Skip to content

Commit 6376463

Browse files
committed
Merge branch 'ks/combine-diff'
Teach combine-diff to honour the path-output-order imposed by diffcore-order, and optimize how matching paths are found in the N-way diffs made with parents. * ks/combine-diff: tests: add checking that combine-diff emits only correct paths combine-diff: simplify intersect_paths() further combine-diff: combine_diff_path.len is not needed anymore combine-diff: optimize combine_diff_path sets intersection diff test: add tests for combine-diff with orderfile diffcore-order: export generic ordering interface
2 parents 2de3478 + fce135c commit 6376463

File tree

7 files changed

+246
-65
lines changed

7 files changed

+246
-65
lines changed

combine-diff.c

Lines changed: 73 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,10 @@
1515
static struct combine_diff_path *intersect_paths(struct combine_diff_path *curr, int n, int num_parent)
1616
{
1717
struct diff_queue_struct *q = &diff_queued_diff;
18-
struct combine_diff_path *p;
19-
int i;
18+
struct combine_diff_path *p, **tail = &curr;
19+
int i, cmp;
2020

2121
if (!n) {
22-
struct combine_diff_path *list = NULL, **tail = &list;
2322
for (i = 0; i < q->nr; i++) {
2423
int len;
2524
const char *path;
@@ -31,7 +30,6 @@ static struct combine_diff_path *intersect_paths(struct combine_diff_path *curr,
3130
p->path = (char *) &(p->parent[num_parent]);
3231
memcpy(p->path, path, len);
3332
p->path[len] = 0;
34-
p->len = len;
3533
p->next = NULL;
3634
memset(p->parent, 0,
3735
sizeof(p->parent[0]) * num_parent);
@@ -44,31 +42,37 @@ static struct combine_diff_path *intersect_paths(struct combine_diff_path *curr,
4442
*tail = p;
4543
tail = &p->next;
4644
}
47-
return list;
45+
return curr;
4846
}
4947

50-
for (p = curr; p; p = p->next) {
51-
int found = 0;
52-
if (!p->len)
48+
/*
49+
* paths in curr (linked list) and q->queue[] (array) are
50+
* both sorted in the tree order.
51+
*/
52+
i = 0;
53+
while ((p = *tail) != NULL) {
54+
cmp = ((i >= q->nr)
55+
? -1 : strcmp(p->path, q->queue[i]->two->path));
56+
57+
if (cmp < 0) {
58+
/* p->path not in q->queue[]; drop it */
59+
*tail = p->next;
60+
free(p);
5361
continue;
54-
for (i = 0; i < q->nr; i++) {
55-
const char *path;
56-
int len;
62+
}
5763

58-
if (diff_unmodified_pair(q->queue[i]))
59-
continue;
60-
path = q->queue[i]->two->path;
61-
len = strlen(path);
62-
if (len == p->len && !memcmp(path, p->path, len)) {
63-
found = 1;
64-
hashcpy(p->parent[n].sha1, q->queue[i]->one->sha1);
65-
p->parent[n].mode = q->queue[i]->one->mode;
66-
p->parent[n].status = q->queue[i]->status;
67-
break;
68-
}
64+
if (cmp > 0) {
65+
/* q->queue[i] not in p->path; skip it */
66+
i++;
67+
continue;
6968
}
70-
if (!found)
71-
p->len = 0;
69+
70+
hashcpy(p->parent[n].sha1, q->queue[i]->one->sha1);
71+
p->parent[n].mode = q->queue[i]->one->mode;
72+
p->parent[n].status = q->queue[i]->status;
73+
74+
tail = &p->next;
75+
i++;
7276
}
7377
return curr;
7478
}
@@ -1219,8 +1223,6 @@ void show_combined_diff(struct combine_diff_path *p,
12191223
{
12201224
struct diff_options *opt = &rev->diffopt;
12211225

1222-
if (!p->len)
1223-
return;
12241226
if (opt->output_format & (DIFF_FORMAT_RAW |
12251227
DIFF_FORMAT_NAME |
12261228
DIFF_FORMAT_NAME_STATUS))
@@ -1284,17 +1286,21 @@ static void handle_combined_callback(struct diff_options *opt,
12841286
q.queue = xcalloc(num_paths, sizeof(struct diff_filepair *));
12851287
q.alloc = num_paths;
12861288
q.nr = num_paths;
1287-
for (i = 0, p = paths; p; p = p->next) {
1288-
if (!p->len)
1289-
continue;
1289+
for (i = 0, p = paths; p; p = p->next)
12901290
q.queue[i++] = combined_pair(p, num_parent);
1291-
}
12921291
opt->format_callback(&q, opt, opt->format_callback_data);
12931292
for (i = 0; i < num_paths; i++)
12941293
free_combined_pair(q.queue[i]);
12951294
free(q.queue);
12961295
}
12971296

1297+
static const char *path_path(void *obj)
1298+
{
1299+
struct combine_diff_path *path = (struct combine_diff_path *)obj;
1300+
1301+
return path->path;
1302+
}
1303+
12981304
void diff_tree_combined(const unsigned char *sha1,
12991305
const struct sha1_array *parents,
13001306
int dense,
@@ -1310,6 +1316,8 @@ void diff_tree_combined(const unsigned char *sha1,
13101316
diffopts.output_format = DIFF_FORMAT_NO_OUTPUT;
13111317
DIFF_OPT_SET(&diffopts, RECURSIVE);
13121318
DIFF_OPT_CLR(&diffopts, ALLOW_EXTERNAL);
1319+
/* tell diff_tree to emit paths in sorted (=tree) order */
1320+
diffopts.orderfile = NULL;
13131321

13141322
show_log_first = !!rev->loginfo && !rev->no_commit_id;
13151323
needsep = 0;
@@ -1335,22 +1343,46 @@ void diff_tree_combined(const unsigned char *sha1,
13351343
printf("%s%c", diff_line_prefix(opt),
13361344
opt->line_termination);
13371345
}
1346+
1347+
/* if showing diff, show it in requested order */
1348+
if (diffopts.output_format != DIFF_FORMAT_NO_OUTPUT &&
1349+
opt->orderfile) {
1350+
diffcore_order(opt->orderfile);
1351+
}
1352+
13381353
diff_flush(&diffopts);
13391354
}
13401355

1341-
/* find out surviving paths */
1342-
for (num_paths = 0, p = paths; p; p = p->next) {
1343-
if (p->len)
1344-
num_paths++;
1356+
/* find out number of surviving paths */
1357+
for (num_paths = 0, p = paths; p; p = p->next)
1358+
num_paths++;
1359+
1360+
/* order paths according to diffcore_order */
1361+
if (opt->orderfile && num_paths) {
1362+
struct obj_order *o;
1363+
1364+
o = xmalloc(sizeof(*o) * num_paths);
1365+
for (i = 0, p = paths; p; p = p->next, i++)
1366+
o[i].obj = p;
1367+
order_objects(opt->orderfile, path_path, o, num_paths);
1368+
for (i = 0; i < num_paths - 1; i++) {
1369+
p = o[i].obj;
1370+
p->next = o[i+1].obj;
1371+
}
1372+
1373+
p = o[num_paths-1].obj;
1374+
p->next = NULL;
1375+
paths = o[0].obj;
1376+
free(o);
13451377
}
1378+
1379+
13461380
if (num_paths) {
13471381
if (opt->output_format & (DIFF_FORMAT_RAW |
13481382
DIFF_FORMAT_NAME |
13491383
DIFF_FORMAT_NAME_STATUS)) {
1350-
for (p = paths; p; p = p->next) {
1351-
if (p->len)
1352-
show_raw_diff(p, num_parent, rev);
1353-
}
1384+
for (p = paths; p; p = p->next)
1385+
show_raw_diff(p, num_parent, rev);
13541386
needsep = 1;
13551387
}
13561388
else if (opt->output_format &
@@ -1363,11 +1395,9 @@ void diff_tree_combined(const unsigned char *sha1,
13631395
if (needsep)
13641396
printf("%s%c", diff_line_prefix(opt),
13651397
opt->line_termination);
1366-
for (p = paths; p; p = p->next) {
1367-
if (p->len)
1368-
show_patch_diff(p, num_parent, dense,
1369-
0, rev);
1370-
}
1398+
for (p = paths; p; p = p->next)
1399+
show_patch_diff(p, num_parent, dense,
1400+
0, rev);
13711401
}
13721402
}
13731403

diff-lib.c

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,6 @@ int run_diff_files(struct rev_info *revs, unsigned int option)
125125
dpath->path = (char *) &(dpath->parent[5]);
126126

127127
dpath->next = NULL;
128-
dpath->len = path_len;
129128
memcpy(dpath->path, ce->name, path_len);
130129
dpath->path[path_len] = '\0';
131130
hashclr(dpath->sha1);
@@ -327,7 +326,6 @@ static int show_modified(struct rev_info *revs,
327326
p = xmalloc(combine_diff_path_size(2, pathlen));
328327
p->path = (char *) &p->parent[2];
329328
p->next = NULL;
330-
p->len = pathlen;
331329
memcpy(p->path, new->name, pathlen);
332330
p->path[pathlen] = 0;
333331
p->mode = mode;

diff.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,6 @@ extern int diff_root_tree_sha1(const unsigned char *new, const char *base,
198198

199199
struct combine_diff_path {
200200
struct combine_diff_path *next;
201-
int len;
202201
char *path;
203202
unsigned int mode;
204203
unsigned char sha1[20];

diffcore-order.c

Lines changed: 32 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -57,12 +57,6 @@ static void prepare_order(const char *orderfile)
5757
}
5858
}
5959

60-
struct pair_order {
61-
struct diff_filepair *pair;
62-
int orig_order;
63-
int order;
64-
};
65-
6660
static int match_order(const char *path)
6761
{
6862
int i;
@@ -84,35 +78,54 @@ static int match_order(const char *path)
8478
return order_cnt;
8579
}
8680

87-
static int compare_pair_order(const void *a_, const void *b_)
81+
static int compare_objs_order(const void *a_, const void *b_)
8882
{
89-
struct pair_order const *a, *b;
90-
a = (struct pair_order const *)a_;
91-
b = (struct pair_order const *)b_;
83+
struct obj_order const *a, *b;
84+
a = (struct obj_order const *)a_;
85+
b = (struct obj_order const *)b_;
9286
if (a->order != b->order)
9387
return a->order - b->order;
9488
return a->orig_order - b->orig_order;
9589
}
9690

91+
void order_objects(const char *orderfile, obj_path_fn_t obj_path,
92+
struct obj_order *objs, int nr)
93+
{
94+
int i;
95+
96+
if (!nr)
97+
return;
98+
99+
prepare_order(orderfile);
100+
for (i = 0; i < nr; i++) {
101+
objs[i].orig_order = i;
102+
objs[i].order = match_order(obj_path(objs[i].obj));
103+
}
104+
qsort(objs, nr, sizeof(*objs), compare_objs_order);
105+
}
106+
107+
static const char *pair_pathtwo(void *obj)
108+
{
109+
struct diff_filepair *pair = (struct diff_filepair *)obj;
110+
111+
return pair->two->path;
112+
}
113+
97114
void diffcore_order(const char *orderfile)
98115
{
99116
struct diff_queue_struct *q = &diff_queued_diff;
100-
struct pair_order *o;
117+
struct obj_order *o;
101118
int i;
102119

103120
if (!q->nr)
104121
return;
105122

106123
o = xmalloc(sizeof(*o) * q->nr);
107-
prepare_order(orderfile);
108-
for (i = 0; i < q->nr; i++) {
109-
o[i].pair = q->queue[i];
110-
o[i].orig_order = i;
111-
o[i].order = match_order(o[i].pair->two->path);
112-
}
113-
qsort(o, q->nr, sizeof(*o), compare_pair_order);
114124
for (i = 0; i < q->nr; i++)
115-
q->queue[i] = o[i].pair;
125+
o[i].obj = q->queue[i];
126+
order_objects(orderfile, pair_pathtwo, o, q->nr);
127+
for (i = 0; i < q->nr; i++)
128+
q->queue[i] = o[i].obj;
116129
free(o);
117130
return;
118131
}

diffcore.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,20 @@ extern void diffcore_merge_broken(void);
111111
extern void diffcore_pickaxe(struct diff_options *);
112112
extern void diffcore_order(const char *orderfile);
113113

114+
/* low-level interface to diffcore_order */
115+
struct obj_order {
116+
void *obj; /* setup by caller */
117+
118+
/* setup/used by order_objects() */
119+
int orig_order;
120+
int order;
121+
};
122+
123+
typedef const char *(*obj_path_fn_t)(void *obj);
124+
125+
void order_objects(const char *orderfile, obj_path_fn_t obj_path,
126+
struct obj_order *objs, int nr);
127+
114128
#define DIFF_DEBUG 0
115129
#if DIFF_DEBUG
116130
void diff_debug_filespec(struct diff_filespec *, int, const char *);

t/t4056-diff-order.sh

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,4 +97,25 @@ do
9797
'
9898
done
9999

100+
test_expect_success 'setup for testing combine-diff order' '
101+
git checkout -b tmp HEAD~ &&
102+
create_files 3 &&
103+
git checkout master &&
104+
git merge --no-commit -s ours tmp &&
105+
create_files 5
106+
'
107+
108+
test_expect_success "combine-diff: no order (=tree object order)" '
109+
git diff --name-only HEAD HEAD^ HEAD^2 >actual &&
110+
test_cmp expect_none actual
111+
'
112+
113+
for i in 1 2
114+
do
115+
test_expect_success "combine-diff: orderfile using option ($i)" '
116+
git diff -Oorder_file_$i --name-only HEAD HEAD^ HEAD^2 >actual &&
117+
test_cmp expect_$i actual
118+
'
119+
done
120+
100121
test_done

0 commit comments

Comments
 (0)