Read attributes from the index that is being checked out
Traditionally we used .gitattributes file from the work tree if exists, and otherwise read from the index as a fallback. When switching to a branch that has an updated .gitattributes file, and entries in it give different attributes to other paths being checked out, we should instead read from the .gitattributes in the index. This breaks a use case of fixing incorrect entries in the .gitattributes in the work tree (without adding it to the index) and checking other paths out, though. $ edit .gitattributes ;# mark foo.dat as binary $ rm foo.dat $ git checkout foo.dat Signed-off-by: Junio C Hamano <gitster@pobox.com>
Junio C Hamano committed
Mar 13, 2009 at 21:24 UTC
06f33c1735bf76e02f3e2601cde5161e969872a7
3 files changed
+64
-18
attr.c
+55
-18
@@ -1,3 +1,4 @@
1
+#define NO_THE_INDEX_COMPATIBILITY_MACROS
2
#include "cache.h"
3
#include "attr.h"
4
@@ -318,6 +319,9 @@ static struct attr_stack *read_attr_from_array(const char **list)
319
return res;
320
}
321
322
+static enum git_attr_direction direction;
323
+static struct index_state *use_index;
324
+
325
static struct attr_stack *read_attr_from_file(const char *path, int macro_ok)
326
{
327
FILE *fp = fopen(path, "r");
@@ -340,9 +344,10 @@ static void *read_index_data(const char *path)
344
unsigned long sz;
345
enum object_type type;
346
void *data;
347
+ struct index_state *istate = use_index ? use_index : &the_index;
348
349
len = strlen(path);
345
- pos = cache_name_pos(path, len);
350
+ pos = index_name_pos(istate, path, len);
351
if (pos < 0) {
352
/*
353
* We might be in the middle of a merge, in which
@@ -350,15 +355,15 @@ static void *read_index_data(const char *path)
355
*/
356
int i;
357
for (i = -pos - 1;
353
- (pos < 0 && i < active_nr &&
354
- !strcmp(active_cache[i]->name, path));
358
+ (pos < 0 && i < istate->cache_nr &&
359
+ !strcmp(istate->cache[i]->name, path));
360
i++)
356
- if (ce_stage(active_cache[i]) == 2)
361
+ if (ce_stage(istate->cache[i]) == 2)
362
pos = i;
363
}
364
if (pos < 0)
365
return NULL;
361
- data = read_sha1_file(active_cache[pos]->sha1, &type, &sz);
366
+ data = read_sha1_file(istate->cache[pos]->sha1, &type, &sz);
367
if (!data || type != OBJ_BLOB) {
368
free(data);
369
return NULL;
@@ -366,27 +371,17 @@ static void *read_index_data(const char *path)
371
return data;
372
}
373
369
-static struct attr_stack *read_attr(const char *path, int macro_ok)
374
+static struct attr_stack *read_attr_from_index(const char *path, int macro_ok)
375
{
376
struct attr_stack *res;
377
char *buf, *sp;
378
int lineno = 0;
379
375
- res = read_attr_from_file(path, macro_ok);
376
- if (res)
377
- return res;
378
-
379
- res = xcalloc(1, sizeof(*res));
380
-
381
- /*
382
- * There is no checked out .gitattributes file there, but
383
- * we might have it in the index. We allow operation in a
384
- * sparsely checked out work tree, so read from it.
385
- */
380
buf = read_index_data(path);
381
if (!buf)
388
- return res;
382
+ return NULL;
383
384
+ res = xcalloc(1, sizeof(*res));
385
for (sp = buf; *sp; ) {
386
char *ep;
387
int more;
@@ -401,6 +396,30 @@ static struct attr_stack *read_attr(const char *path, int macro_ok)
396
return res;
397
}
398
399
+static struct attr_stack *read_attr(const char *path, int macro_ok)
400
+{
401
+ struct attr_stack *res;
402
+
403
+ if (direction == GIT_ATTR_CHECKOUT) {
404
+ res = read_attr_from_index(path, macro_ok);
405
+ if (!res)
406
+ res = read_attr_from_file(path, macro_ok);
407
+ }
408
+ else {
409
+ res = read_attr_from_file(path, macro_ok);
410
+ if (!res)
411
+ /*
412
+ * There is no checked out .gitattributes file there, but
413
+ * we might have it in the index. We allow operation in a
414
+ * sparsely checked out work tree, so read from it.
415
+ */
416
+ res = read_attr_from_index(path, macro_ok);
417
+ }
418
+ if (!res)
419
+ res = xcalloc(1, sizeof(*res));
420
+ return res;
421
+}
422
+
423
#if DEBUG_ATTR
424
static void debug_info(const char *what, struct attr_stack *elem)
425
{
@@ -428,6 +447,15 @@ static void debug_set(const char *what, const char *match, struct git_attr *attr
447
#define debug_set(a,b,c,d) do { ; } while (0)
448
#endif
449
450
+static void drop_attr_stack(void)
451
+{
452
+ while (attr_stack) {
453
+ struct attr_stack *elem = attr_stack;
454
+ attr_stack = elem->prev;
455
+ free_attr_elem(elem);
456
+ }
457
+}
458
+
459
static void bootstrap_attr_stack(void)
460
{
461
if (!attr_stack) {
@@ -642,3 +670,12 @@ int git_checkattr(const char *path, int num, struct git_attr_check *check)
670
671
return 0;
672
}
673
+
674
+void git_attr_set_direction(enum git_attr_direction new, struct index_state *istate)
675
+{
676
+ enum git_attr_direction old = direction;
677
+ direction = new;
678
+ if (new != old)
679
+ drop_attr_stack();
680
+ use_index = istate;
681
+}
attr.h
+6
@@ -31,4 +31,10 @@ struct git_attr_check {
31
32
int git_checkattr(const char *path, int, struct git_attr_check *);
33
34
+enum git_attr_direction {
35
+ GIT_ATTR_CHECKIN,
36
+ GIT_ATTR_CHECKOUT
37
+};
38
+void git_attr_set_direction(enum git_attr_direction, struct index_state *);
39
+
40
#endif /* ATTR_H */
unpack-trees.c
+3
@@ -7,6 +7,7 @@
7
#include "unpack-trees.h"
8
#include "progress.h"
9
#include "refs.h"
10
+#include "attr.h"
11
12
/*
13
* Error messages expected by scripts out of plumbing commands such as
@@ -105,6 +106,7 @@ static int check_updates(struct unpack_trees_options *o)
106
cnt = 0;
107
}
108
109
+ git_attr_set_direction(GIT_ATTR_CHECKOUT, &o->result);
110
for (i = 0; i < index->cache_nr; i++) {
111
struct cache_entry *ce = index->cache[i];
112
@@ -130,6 +132,7 @@ static int check_updates(struct unpack_trees_options *o)
132
}
133
}
134
stop_progress(&progress);
135
+ git_attr_set_direction(GIT_ATTR_CHECKIN, NULL);
136
return errs != 0;
137
}
138