Skip to content

Commit 6ba8b07

Browse files
committed
Merge branch 'jc/attributes-checkout'
* jc/attributes-checkout: Add a test for checking whether gitattributes is honored by checkout. Read attributes from the index that is being checked out
2 parents b71fdc5 + b997045 commit 6ba8b07

File tree

4 files changed

+95
-18
lines changed

4 files changed

+95
-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 */

t/t0020-crlf.sh

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,37 @@ test_expect_success 'in-tree .gitattributes (4)' '
429429
}
430430
'
431431

432+
test_expect_success 'checkout with existing .gitattributes' '
433+
434+
git config core.autocrlf true &&
435+
git config --unset core.safecrlf &&
436+
echo ".file2 -crlfQ" | q_to_cr >> .gitattributes &&
437+
git add .gitattributes &&
438+
git commit -m initial &&
439+
echo ".file -crlfQ" | q_to_cr >> .gitattributes &&
440+
echo "contents" > .file &&
441+
git add .gitattributes .file &&
442+
git commit -m second &&
443+
444+
git checkout master~1 &&
445+
git checkout master &&
446+
test "$(git diff-files --raw)" = ""
447+
448+
'
449+
450+
test_expect_success 'checkout when deleting .gitattributes' '
451+
452+
git rm .gitattributes &&
453+
echo "contentsQ" | q_to_cr > .file2 &&
454+
git add .file2 &&
455+
git commit -m third
456+
457+
git checkout master~1 &&
458+
git checkout master &&
459+
remove_cr .file2 >/dev/null
460+
461+
'
462+
432463
test_expect_success 'invalid .gitattributes (must not crash)' '
433464
434465
echo "three +crlf" >>.gitattributes &&

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
@@ -86,6 +87,7 @@ static int check_updates(struct unpack_trees_options *o)
8687
cnt = 0;
8788
}
8889

90+
git_attr_set_direction(GIT_ATTR_CHECKOUT, &o->result);
8991
for (i = 0; i < index->cache_nr; i++) {
9092
struct cache_entry *ce = index->cache[i];
9193

@@ -110,6 +112,7 @@ static int check_updates(struct unpack_trees_options *o)
110112
}
111113
}
112114
stop_progress(&progress);
115+
git_attr_set_direction(GIT_ATTR_CHECKIN, NULL);
113116
return errs != 0;
114117
}
115118

0 commit comments

Comments
 (0)