Skip to content

Commit

Permalink
Merge branch 'ks/combine-diff'
Browse files Browse the repository at this point in the history
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
  • Loading branch information
gitster committed Mar 5, 2014
2 parents 2de3478 + fce135c commit 6376463
Show file tree
Hide file tree
Showing 7 changed files with 246 additions and 65 deletions.
116 changes: 73 additions & 43 deletions combine-diff.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,10 @@
static struct combine_diff_path *intersect_paths(struct combine_diff_path *curr, int n, int num_parent)
{
struct diff_queue_struct *q = &diff_queued_diff;
struct combine_diff_path *p;
int i;
struct combine_diff_path *p, **tail = &curr;
int i, cmp;

if (!n) {
struct combine_diff_path *list = NULL, **tail = &list;
for (i = 0; i < q->nr; i++) {
int len;
const char *path;
Expand All @@ -31,7 +30,6 @@ static struct combine_diff_path *intersect_paths(struct combine_diff_path *curr,
p->path = (char *) &(p->parent[num_parent]);
memcpy(p->path, path, len);
p->path[len] = 0;
p->len = len;
p->next = NULL;
memset(p->parent, 0,
sizeof(p->parent[0]) * num_parent);
Expand All @@ -44,31 +42,37 @@ static struct combine_diff_path *intersect_paths(struct combine_diff_path *curr,
*tail = p;
tail = &p->next;
}
return list;
return curr;
}

for (p = curr; p; p = p->next) {
int found = 0;
if (!p->len)
/*
* paths in curr (linked list) and q->queue[] (array) are
* both sorted in the tree order.
*/
i = 0;
while ((p = *tail) != NULL) {
cmp = ((i >= q->nr)
? -1 : strcmp(p->path, q->queue[i]->two->path));

if (cmp < 0) {
/* p->path not in q->queue[]; drop it */
*tail = p->next;
free(p);
continue;
for (i = 0; i < q->nr; i++) {
const char *path;
int len;
}

if (diff_unmodified_pair(q->queue[i]))
continue;
path = q->queue[i]->two->path;
len = strlen(path);
if (len == p->len && !memcmp(path, p->path, len)) {
found = 1;
hashcpy(p->parent[n].sha1, q->queue[i]->one->sha1);
p->parent[n].mode = q->queue[i]->one->mode;
p->parent[n].status = q->queue[i]->status;
break;
}
if (cmp > 0) {
/* q->queue[i] not in p->path; skip it */
i++;
continue;
}
if (!found)
p->len = 0;

hashcpy(p->parent[n].sha1, q->queue[i]->one->sha1);
p->parent[n].mode = q->queue[i]->one->mode;
p->parent[n].status = q->queue[i]->status;

tail = &p->next;
i++;
}
return curr;
}
Expand Down Expand Up @@ -1219,8 +1223,6 @@ void show_combined_diff(struct combine_diff_path *p,
{
struct diff_options *opt = &rev->diffopt;

if (!p->len)
return;
if (opt->output_format & (DIFF_FORMAT_RAW |
DIFF_FORMAT_NAME |
DIFF_FORMAT_NAME_STATUS))
Expand Down Expand Up @@ -1284,17 +1286,21 @@ static void handle_combined_callback(struct diff_options *opt,
q.queue = xcalloc(num_paths, sizeof(struct diff_filepair *));
q.alloc = num_paths;
q.nr = num_paths;
for (i = 0, p = paths; p; p = p->next) {
if (!p->len)
continue;
for (i = 0, p = paths; p; p = p->next)
q.queue[i++] = combined_pair(p, num_parent);
}
opt->format_callback(&q, opt, opt->format_callback_data);
for (i = 0; i < num_paths; i++)
free_combined_pair(q.queue[i]);
free(q.queue);
}

static const char *path_path(void *obj)
{
struct combine_diff_path *path = (struct combine_diff_path *)obj;

return path->path;
}

void diff_tree_combined(const unsigned char *sha1,
const struct sha1_array *parents,
int dense,
Expand All @@ -1310,6 +1316,8 @@ void diff_tree_combined(const unsigned char *sha1,
diffopts.output_format = DIFF_FORMAT_NO_OUTPUT;
DIFF_OPT_SET(&diffopts, RECURSIVE);
DIFF_OPT_CLR(&diffopts, ALLOW_EXTERNAL);
/* tell diff_tree to emit paths in sorted (=tree) order */
diffopts.orderfile = NULL;

show_log_first = !!rev->loginfo && !rev->no_commit_id;
needsep = 0;
Expand All @@ -1335,22 +1343,46 @@ void diff_tree_combined(const unsigned char *sha1,
printf("%s%c", diff_line_prefix(opt),
opt->line_termination);
}

/* if showing diff, show it in requested order */
if (diffopts.output_format != DIFF_FORMAT_NO_OUTPUT &&
opt->orderfile) {
diffcore_order(opt->orderfile);
}

diff_flush(&diffopts);
}

/* find out surviving paths */
for (num_paths = 0, p = paths; p; p = p->next) {
if (p->len)
num_paths++;
/* find out number of surviving paths */
for (num_paths = 0, p = paths; p; p = p->next)
num_paths++;

/* order paths according to diffcore_order */
if (opt->orderfile && num_paths) {
struct obj_order *o;

o = xmalloc(sizeof(*o) * num_paths);
for (i = 0, p = paths; p; p = p->next, i++)
o[i].obj = p;
order_objects(opt->orderfile, path_path, o, num_paths);
for (i = 0; i < num_paths - 1; i++) {
p = o[i].obj;
p->next = o[i+1].obj;
}

p = o[num_paths-1].obj;
p->next = NULL;
paths = o[0].obj;
free(o);
}


if (num_paths) {
if (opt->output_format & (DIFF_FORMAT_RAW |
DIFF_FORMAT_NAME |
DIFF_FORMAT_NAME_STATUS)) {
for (p = paths; p; p = p->next) {
if (p->len)
show_raw_diff(p, num_parent, rev);
}
for (p = paths; p; p = p->next)
show_raw_diff(p, num_parent, rev);
needsep = 1;
}
else if (opt->output_format &
Expand All @@ -1363,11 +1395,9 @@ void diff_tree_combined(const unsigned char *sha1,
if (needsep)
printf("%s%c", diff_line_prefix(opt),
opt->line_termination);
for (p = paths; p; p = p->next) {
if (p->len)
show_patch_diff(p, num_parent, dense,
0, rev);
}
for (p = paths; p; p = p->next)
show_patch_diff(p, num_parent, dense,
0, rev);
}
}

Expand Down
2 changes: 0 additions & 2 deletions diff-lib.c
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,6 @@ int run_diff_files(struct rev_info *revs, unsigned int option)
dpath->path = (char *) &(dpath->parent[5]);

dpath->next = NULL;
dpath->len = path_len;
memcpy(dpath->path, ce->name, path_len);
dpath->path[path_len] = '\0';
hashclr(dpath->sha1);
Expand Down Expand Up @@ -327,7 +326,6 @@ static int show_modified(struct rev_info *revs,
p = xmalloc(combine_diff_path_size(2, pathlen));
p->path = (char *) &p->parent[2];
p->next = NULL;
p->len = pathlen;
memcpy(p->path, new->name, pathlen);
p->path[pathlen] = 0;
p->mode = mode;
Expand Down
1 change: 0 additions & 1 deletion diff.h
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,6 @@ extern int diff_root_tree_sha1(const unsigned char *new, const char *base,

struct combine_diff_path {
struct combine_diff_path *next;
int len;
char *path;
unsigned int mode;
unsigned char sha1[20];
Expand Down
51 changes: 32 additions & 19 deletions diffcore-order.c
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,6 @@ static void prepare_order(const char *orderfile)
}
}

struct pair_order {
struct diff_filepair *pair;
int orig_order;
int order;
};

static int match_order(const char *path)
{
int i;
Expand All @@ -84,35 +78,54 @@ static int match_order(const char *path)
return order_cnt;
}

static int compare_pair_order(const void *a_, const void *b_)
static int compare_objs_order(const void *a_, const void *b_)
{
struct pair_order const *a, *b;
a = (struct pair_order const *)a_;
b = (struct pair_order const *)b_;
struct obj_order const *a, *b;
a = (struct obj_order const *)a_;
b = (struct obj_order const *)b_;
if (a->order != b->order)
return a->order - b->order;
return a->orig_order - b->orig_order;
}

void order_objects(const char *orderfile, obj_path_fn_t obj_path,
struct obj_order *objs, int nr)
{
int i;

if (!nr)
return;

prepare_order(orderfile);
for (i = 0; i < nr; i++) {
objs[i].orig_order = i;
objs[i].order = match_order(obj_path(objs[i].obj));
}
qsort(objs, nr, sizeof(*objs), compare_objs_order);
}

static const char *pair_pathtwo(void *obj)
{
struct diff_filepair *pair = (struct diff_filepair *)obj;

return pair->two->path;
}

void diffcore_order(const char *orderfile)
{
struct diff_queue_struct *q = &diff_queued_diff;
struct pair_order *o;
struct obj_order *o;
int i;

if (!q->nr)
return;

o = xmalloc(sizeof(*o) * q->nr);
prepare_order(orderfile);
for (i = 0; i < q->nr; i++) {
o[i].pair = q->queue[i];
o[i].orig_order = i;
o[i].order = match_order(o[i].pair->two->path);
}
qsort(o, q->nr, sizeof(*o), compare_pair_order);
for (i = 0; i < q->nr; i++)
q->queue[i] = o[i].pair;
o[i].obj = q->queue[i];
order_objects(orderfile, pair_pathtwo, o, q->nr);
for (i = 0; i < q->nr; i++)
q->queue[i] = o[i].obj;
free(o);
return;
}
14 changes: 14 additions & 0 deletions diffcore.h
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,20 @@ extern void diffcore_merge_broken(void);
extern void diffcore_pickaxe(struct diff_options *);
extern void diffcore_order(const char *orderfile);

/* low-level interface to diffcore_order */
struct obj_order {
void *obj; /* setup by caller */

/* setup/used by order_objects() */
int orig_order;
int order;
};

typedef const char *(*obj_path_fn_t)(void *obj);

void order_objects(const char *orderfile, obj_path_fn_t obj_path,
struct obj_order *objs, int nr);

#define DIFF_DEBUG 0
#if DIFF_DEBUG
void diff_debug_filespec(struct diff_filespec *, int, const char *);
Expand Down
21 changes: 21 additions & 0 deletions t/t4056-diff-order.sh
Original file line number Diff line number Diff line change
Expand Up @@ -97,4 +97,25 @@ do
'
done

test_expect_success 'setup for testing combine-diff order' '
git checkout -b tmp HEAD~ &&
create_files 3 &&
git checkout master &&
git merge --no-commit -s ours tmp &&
create_files 5
'

test_expect_success "combine-diff: no order (=tree object order)" '
git diff --name-only HEAD HEAD^ HEAD^2 >actual &&
test_cmp expect_none actual
'

for i in 1 2
do
test_expect_success "combine-diff: orderfile using option ($i)" '
git diff -Oorder_file_$i --name-only HEAD HEAD^ HEAD^2 >actual &&
test_cmp expect_$i actual
'
done

test_done
Loading

0 comments on commit 6376463

Please sign in to comment.