Skip to content

Commit 06f33c1

Browse files
committed
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 <[email protected]>
1 parent 924189d commit 06f33c1

File tree

3 files changed

+64
-18
lines changed

3 files changed

+64
-18
lines changed

attr.c

Lines changed: 55 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#define NO_THE_INDEX_COMPATIBILITY_MACROS
12
#include "cache.h"
23
#include "attr.h"
34

@@ -318,6 +319,9 @@ static struct attr_stack *read_attr_from_array(const char **list)
318319
return res;
319320
}
320321

322+
static enum git_attr_direction direction;
323+
static struct index_state *use_index;
324+
321325
static struct attr_stack *read_attr_from_file(const char *path, int macro_ok)
322326
{
323327
FILE *fp = fopen(path, "r");
@@ -340,53 +344,44 @@ static void *read_index_data(const char *path)
340344
unsigned long sz;
341345
enum object_type type;
342346
void *data;
347+
struct index_state *istate = use_index ? use_index : &the_index;
343348

344349
len = strlen(path);
345-
pos = cache_name_pos(path, len);
350+
pos = index_name_pos(istate, path, len);
346351
if (pos < 0) {
347352
/*
348353
* We might be in the middle of a merge, in which
349354
* case we would read stage #2 (ours).
350355
*/
351356
int i;
352357
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));
355360
i++)
356-
if (ce_stage(active_cache[i]) == 2)
361+
if (ce_stage(istate->cache[i]) == 2)
357362
pos = i;
358363
}
359364
if (pos < 0)
360365
return NULL;
361-
data = read_sha1_file(active_cache[pos]->sha1, &type, &sz);
366+
data = read_sha1_file(istate->cache[pos]->sha1, &type, &sz);
362367
if (!data || type != OBJ_BLOB) {
363368
free(data);
364369
return NULL;
365370
}
366371
return data;
367372
}
368373

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)
370375
{
371376
struct attr_stack *res;
372377
char *buf, *sp;
373378
int lineno = 0;
374379

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-
*/
386380
buf = read_index_data(path);
387381
if (!buf)
388-
return res;
382+
return NULL;
389383

384+
res = xcalloc(1, sizeof(*res));
390385
for (sp = buf; *sp; ) {
391386
char *ep;
392387
int more;
@@ -401,6 +396,30 @@ static struct attr_stack *read_attr(const char *path, int macro_ok)
401396
return res;
402397
}
403398

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+
404423
#if DEBUG_ATTR
405424
static void debug_info(const char *what, struct attr_stack *elem)
406425
{
@@ -428,6 +447,15 @@ static void debug_set(const char *what, const char *match, struct git_attr *attr
428447
#define debug_set(a,b,c,d) do { ; } while (0)
429448
#endif
430449

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+
431459
static void bootstrap_attr_stack(void)
432460
{
433461
if (!attr_stack) {
@@ -642,3 +670,12 @@ int git_checkattr(const char *path, int num, struct git_attr_check *check)
642670

643671
return 0;
644672
}
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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,10 @@ struct git_attr_check {
3131

3232
int git_checkattr(const char *path, int, struct git_attr_check *);
3333

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+
3440
#endif /* ATTR_H */

unpack-trees.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include "unpack-trees.h"
88
#include "progress.h"
99
#include "refs.h"
10+
#include "attr.h"
1011

1112
/*
1213
* Error messages expected by scripts out of plumbing commands such as
@@ -105,6 +106,7 @@ static int check_updates(struct unpack_trees_options *o)
105106
cnt = 0;
106107
}
107108

109+
git_attr_set_direction(GIT_ATTR_CHECKOUT, &o->result);
108110
for (i = 0; i < index->cache_nr; i++) {
109111
struct cache_entry *ce = index->cache[i];
110112

@@ -130,6 +132,7 @@ static int check_updates(struct unpack_trees_options *o)
130132
}
131133
}
132134
stop_progress(&progress);
135+
git_attr_set_direction(GIT_ATTR_CHECKIN, NULL);
133136
return errs != 0;
134137
}
135138

0 commit comments

Comments
 (0)