Skip to content

Commit 026680f

Browse files
committed
Merge branch 'jc/fix-tree-walk'
* jc/fix-tree-walk: read-tree --debug-unpack unpack-trees.c: look ahead in the index unpack-trees.c: prepare for looking ahead in the index Aggressive three-way merge: fix D/F case traverse_trees(): handle D/F conflict case sanely more D/F conflict tests tests: move convenience regexp to match object names to test-lib.sh Conflicts: builtin-read-tree.c unpack-trees.c unpack-trees.h
2 parents eca9388 + ba655da commit 026680f

19 files changed

+734
-140
lines changed

builtin-read-tree.c

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,34 @@ static int exclude_per_directory_cb(const struct option *opt, const char *arg,
6565
return 0;
6666
}
6767

68+
static void debug_stage(const char *label, struct cache_entry *ce,
69+
struct unpack_trees_options *o)
70+
{
71+
printf("%s ", label);
72+
if (!ce)
73+
printf("(missing)\n");
74+
else if (ce == o->df_conflict_entry)
75+
printf("(conflict)\n");
76+
else
77+
printf("%06o #%d %s %.8s\n",
78+
ce->ce_mode, ce_stage(ce), ce->name,
79+
sha1_to_hex(ce->sha1));
80+
}
81+
82+
static int debug_merge(struct cache_entry **stages, struct unpack_trees_options *o)
83+
{
84+
int i;
85+
86+
printf("* %d-way merge\n", o->merge_size);
87+
debug_stage("index", stages[0], o);
88+
for (i = 1; i <= o->merge_size; i++) {
89+
char buf[24];
90+
sprintf(buf, "ent#%d", i);
91+
debug_stage(buf, stages[i], o);
92+
}
93+
return 0;
94+
}
95+
6896
static struct lock_file lock_file;
6997

7098
int cmd_read_tree(int argc, const char **argv, const char *unused_prefix)
@@ -101,6 +129,8 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix)
101129
"don't check the working tree after merging", 1),
102130
OPT_SET_INT(0, "no-sparse-checkout", &opts.skip_sparse_checkout,
103131
"skip applying sparse checkout filter", 1),
132+
OPT_SET_INT(0, "debug-unpack", &opts.debug_unpack,
133+
"debug unpack-trees", 1),
104134
OPT_END()
105135
};
106136

@@ -169,6 +199,9 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix)
169199
opts.head_idx = 1;
170200
}
171201

202+
if (opts.debug_unpack)
203+
opts.fn = debug_merge;
204+
172205
cache_tree_free(&active_cache_tree);
173206
for (i = 0; i < nr_trees; i++) {
174207
struct tree *tree = trees[i];
@@ -178,6 +211,9 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix)
178211
if (unpack_trees(nr_trees, t, &opts))
179212
return 128;
180213

214+
if (opts.debug_unpack)
215+
return 0; /* do not write the index out */
216+
181217
/*
182218
* When reading only one tree (either the most basic form,
183219
* "-m ent" or "--reset ent" form), we can obtain a fully

cache.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,8 @@ struct cache_entry {
182182
/* Only remove in work directory, not index */
183183
#define CE_WT_REMOVE (0x400000)
184184

185+
#define CE_UNPACKED (0x1000000)
186+
185187
/*
186188
* Extended on-disk flags
187189
*/

diff-lib.c

Lines changed: 1 addition & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -380,21 +380,6 @@ static void do_oneway_diff(struct unpack_trees_options *o,
380380
show_modified(revs, tree, idx, 1, cached, match_missing);
381381
}
382382

383-
static inline void skip_same_name(struct cache_entry *ce, struct unpack_trees_options *o)
384-
{
385-
int len = ce_namelen(ce);
386-
const struct index_state *index = o->src_index;
387-
388-
while (o->pos < index->cache_nr) {
389-
struct cache_entry *next = index->cache[o->pos];
390-
if (len != ce_namelen(next))
391-
break;
392-
if (memcmp(ce->name, next->name, len))
393-
break;
394-
o->pos++;
395-
}
396-
}
397-
398383
/*
399384
* The unpack_trees() interface is designed for merging, so
400385
* the different source entries are designed primarily for
@@ -416,9 +401,6 @@ static int oneway_diff(struct cache_entry **src, struct unpack_trees_options *o)
416401
struct cache_entry *tree = src[1];
417402
struct rev_info *revs = o->unpack_data;
418403

419-
if (idx && ce_stage(idx))
420-
skip_same_name(idx, o);
421-
422404
/*
423405
* Unpack-trees generates a DF/conflict entry if
424406
* there was a directory in the index and a tree
@@ -464,6 +446,7 @@ int run_diff_index(struct rev_info *revs, int cached)
464446
exit(128);
465447

466448
diff_set_mnemonic_prefix(&revs->diffopt, "c/", cached ? "i/" : "w/");
449+
diffcore_fix_diff_index(&revs->diffopt);
467450
diffcore_std(&revs->diffopt);
468451
diff_flush(&revs->diffopt);
469452
return 0;

diff.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3678,6 +3678,23 @@ static void diffcore_skip_stat_unmatch(struct diff_options *diffopt)
36783678
*q = outq;
36793679
}
36803680

3681+
static int diffnamecmp(const void *a_, const void *b_)
3682+
{
3683+
const struct diff_filepair *a = *((const struct diff_filepair **)a_);
3684+
const struct diff_filepair *b = *((const struct diff_filepair **)b_);
3685+
const char *name_a, *name_b;
3686+
3687+
name_a = a->one ? a->one->path : a->two->path;
3688+
name_b = b->one ? b->one->path : b->two->path;
3689+
return strcmp(name_a, name_b);
3690+
}
3691+
3692+
void diffcore_fix_diff_index(struct diff_options *options)
3693+
{
3694+
struct diff_queue_struct *q = &diff_queued_diff;
3695+
qsort(q->queue, q->nr, sizeof(q->queue[0]), diffnamecmp);
3696+
}
3697+
36813698
void diffcore_std(struct diff_options *options)
36823699
{
36833700
if (options->skip_stat_unmatch)

diff.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,7 @@ extern int diff_setup_done(struct diff_options *);
210210
#define DIFF_PICKAXE_REGEX 2
211211

212212
extern void diffcore_std(struct diff_options *);
213+
extern void diffcore_fix_diff_index(struct diff_options *);
213214

214215
#define COMMON_DIFF_OPTIONS_HELP \
215216
"\ncommon diff options:\n" \

t/diff-lib.sh

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
:
22

3-
_x40='[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]'
4-
_x40="$_x40$_x40$_x40$_x40$_x40$_x40$_x40$_x40"
53
sanitize_diff_raw='/^:/s/ '"$_x40"' '"$_x40"' \([A-Z]\)[0-9]* / X X \1# /'
64
compare_diff_raw () {
75
# When heuristics are improved, the score numbers would change.

t/t1000-read-tree-m-3way.sh

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -126,9 +126,6 @@ cat >expected <<\EOF
126126
100644 X 0 Z/NN
127127
EOF
128128

129-
_x40='[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]'
130-
_x40="$_x40$_x40$_x40$_x40$_x40$_x40$_x40$_x40"
131-
132129
check_result () {
133130
git ls-files --stage | sed -e 's/ '"$_x40"' / X /' >current &&
134131
test_cmp expected current

t/t1001-read-tree-m-2way.sh

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,6 @@ read_tree_twoway () {
2626
git read-tree -m "$1" "$2" && git ls-files --stage
2727
}
2828

29-
_x40='[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]'
30-
_x40="$_x40$_x40$_x40$_x40$_x40$_x40$_x40$_x40"
3129
compare_change () {
3230
sed -n >current \
3331
-e '/^--- /d; /^+++ /d; /^@@ /d;' \

t/t1002-read-tree-m-u-2way.sh

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,6 @@ This is identical to t1001, but uses -u to update the work tree as well.
1010
'
1111
. ./test-lib.sh
1212

13-
_x40='[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]'
14-
_x40="$_x40$_x40$_x40$_x40$_x40$_x40$_x40$_x40"
1513
compare_change () {
1614
sed >current \
1715
-e '1{/^diff --git /d;}' \

t/t1012-read-tree-df.sh

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
#!/bin/sh
2+
3+
test_description='read-tree D/F conflict corner cases'
4+
5+
. ./test-lib.sh
6+
7+
maketree () {
8+
(
9+
rm -f .git/index .git/index.lock &&
10+
git clean -d -f -f -q -x &&
11+
name="$1" &&
12+
shift &&
13+
for it
14+
do
15+
path=$(expr "$it" : '\([^:]*\)') &&
16+
mkdir -p $(dirname "$path") &&
17+
echo "$it" >"$path" &&
18+
git update-index --add "$path" || exit
19+
done &&
20+
git tag "$name" $(git write-tree)
21+
)
22+
}
23+
24+
settree () {
25+
rm -f .git/index .git/index.lock &&
26+
git clean -d -f -f -q -x &&
27+
git read-tree "$1" &&
28+
git checkout-index -f -q -u -a &&
29+
git update-index --refresh
30+
}
31+
32+
checkindex () {
33+
git ls-files -s |
34+
sed "s|^[0-7][0-7]* $_x40 \([0-3]\) |\1 |" >current &&
35+
cat >expect &&
36+
test_cmp expect current
37+
}
38+
39+
test_expect_success setup '
40+
maketree O-000 a/b-2/c/d a/b/c/d a/x &&
41+
maketree A-000 a/b-2/c/d a/b/c/d a/x &&
42+
maketree A-001 a/b-2/c/d a/b/c/d a/b/c/e a/x &&
43+
maketree B-000 a/b-2/c/d a/b a/x &&
44+
45+
maketree O-010 t-0 t/1 t/2 t=3 &&
46+
maketree A-010 t-0 t t=3 &&
47+
maketree B-010 t/1: t=3: &&
48+
49+
maketree O-020 ds/dma/ioat.c ds/dma/ioat_dca.c &&
50+
maketree A-020 ds/dma/ioat/Makefile ds/dma/ioat/registers.h &&
51+
:
52+
'
53+
54+
test_expect_success '3-way (1)' '
55+
settree A-000 &&
56+
git read-tree -m -u O-000 A-000 B-000 &&
57+
checkindex <<-EOF
58+
3 a/b
59+
0 a/b-2/c/d
60+
1 a/b/c/d
61+
2 a/b/c/d
62+
0 a/x
63+
EOF
64+
'
65+
66+
test_expect_success '3-way (2)' '
67+
settree A-001 &&
68+
git read-tree -m -u O-000 A-001 B-000 &&
69+
checkindex <<-EOF
70+
3 a/b
71+
0 a/b-2/c/d
72+
1 a/b/c/d
73+
2 a/b/c/d
74+
2 a/b/c/e
75+
0 a/x
76+
EOF
77+
'
78+
79+
test_expect_success '3-way (3)' '
80+
settree A-010 &&
81+
git read-tree -m -u O-010 A-010 B-010 &&
82+
checkindex <<-EOF
83+
2 t
84+
1 t-0
85+
2 t-0
86+
1 t/1
87+
3 t/1
88+
1 t/2
89+
0 t=3
90+
EOF
91+
'
92+
93+
test_expect_success '2-way (1)' '
94+
settree O-020 &&
95+
git read-tree -m -u O-020 A-020 &&
96+
checkindex <<-EOF
97+
0 ds/dma/ioat/Makefile
98+
0 ds/dma/ioat/registers.h
99+
EOF
100+
'
101+
102+
test_done

0 commit comments

Comments
 (0)