Skip to content

Commit edf1412

Browse files
committed
Merge branch 'jc/merge-reduce-parents-early' into maint
Octopus merge strategy did not reduce heads that are recorded in the final commit correctly. By Junio C Hamano (4) and Michał Kiedrowicz (1) * jc/merge-reduce-parents-early: fmt-merge-msg: discard needless merge parents builtin/merge.c: reduce parents early builtin/merge.c: collect other parents early builtin/merge.c: remove "remoteheads" global variable merge tests: octopus with redundant parents
2 parents c4da6c0 + 5802f81 commit edf1412

File tree

5 files changed

+276
-71
lines changed

5 files changed

+276
-71
lines changed

builtin/fmt-merge-msg.c

Lines changed: 119 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -53,14 +53,56 @@ static void init_src_data(struct src_data *data)
5353
static struct string_list srcs = STRING_LIST_INIT_DUP;
5454
static struct string_list origins = STRING_LIST_INIT_DUP;
5555

56-
static int handle_line(char *line)
56+
struct merge_parents {
57+
int alloc, nr;
58+
struct merge_parent {
59+
unsigned char given[20];
60+
unsigned char commit[20];
61+
unsigned char used;
62+
} *item;
63+
};
64+
65+
/*
66+
* I know, I know, this is inefficient, but you won't be pulling and merging
67+
* hundreds of heads at a time anyway.
68+
*/
69+
static struct merge_parent *find_merge_parent(struct merge_parents *table,
70+
unsigned char *given,
71+
unsigned char *commit)
72+
{
73+
int i;
74+
for (i = 0; i < table->nr; i++) {
75+
if (given && hashcmp(table->item[i].given, given))
76+
continue;
77+
if (commit && hashcmp(table->item[i].commit, commit))
78+
continue;
79+
return &table->item[i];
80+
}
81+
return NULL;
82+
}
83+
84+
static void add_merge_parent(struct merge_parents *table,
85+
unsigned char *given,
86+
unsigned char *commit)
87+
{
88+
if (table->nr && find_merge_parent(table, given, commit))
89+
return;
90+
ALLOC_GROW(table->item, table->nr + 1, table->alloc);
91+
hashcpy(table->item[table->nr].given, given);
92+
hashcpy(table->item[table->nr].commit, commit);
93+
table->item[table->nr].used = 0;
94+
table->nr++;
95+
}
96+
97+
static int handle_line(char *line, struct merge_parents *merge_parents)
5798
{
5899
int i, len = strlen(line);
59100
struct origin_data *origin_data;
60101
char *src, *origin;
61102
struct src_data *src_data;
62103
struct string_list_item *item;
63104
int pulling_head = 0;
105+
unsigned char sha1[20];
64106

65107
if (len < 43 || line[40] != '\t')
66108
return 1;
@@ -71,14 +113,15 @@ static int handle_line(char *line)
71113
if (line[41] != '\t')
72114
return 2;
73115

74-
line[40] = 0;
75-
origin_data = xcalloc(1, sizeof(struct origin_data));
76-
i = get_sha1(line, origin_data->sha1);
77-
line[40] = '\t';
78-
if (i) {
79-
free(origin_data);
116+
i = get_sha1_hex(line, sha1);
117+
if (i)
80118
return 3;
81-
}
119+
120+
if (!find_merge_parent(merge_parents, sha1, NULL))
121+
return 0; /* subsumed by other parents */
122+
123+
origin_data = xcalloc(1, sizeof(struct origin_data));
124+
hashcpy(origin_data->sha1, sha1);
82125

83126
if (line[len - 1] == '\n')
84127
line[len - 1] = 0;
@@ -366,13 +409,77 @@ static void fmt_merge_msg_sigs(struct strbuf *out)
366409
strbuf_release(&tagbuf);
367410
}
368411

412+
static void find_merge_parents(struct merge_parents *result,
413+
struct strbuf *in, unsigned char *head)
414+
{
415+
struct commit_list *parents, *next;
416+
struct commit *head_commit;
417+
int pos = 0, i, j;
418+
419+
parents = NULL;
420+
while (pos < in->len) {
421+
int len;
422+
char *p = in->buf + pos;
423+
char *newline = strchr(p, '\n');
424+
unsigned char sha1[20];
425+
struct commit *parent;
426+
struct object *obj;
427+
428+
len = newline ? newline - p : strlen(p);
429+
pos += len + !!newline;
430+
431+
if (len < 43 ||
432+
get_sha1_hex(p, sha1) ||
433+
p[40] != '\t' ||
434+
p[41] != '\t')
435+
continue; /* skip not-for-merge */
436+
/*
437+
* Do not use get_merge_parent() here; we do not have
438+
* "name" here and we do not want to contaminate its
439+
* util field yet.
440+
*/
441+
obj = parse_object(sha1);
442+
parent = (struct commit *)peel_to_type(NULL, 0, obj, OBJ_COMMIT);
443+
if (!parent)
444+
continue;
445+
commit_list_insert(parent, &parents);
446+
add_merge_parent(result, obj->sha1, parent->object.sha1);
447+
}
448+
head_commit = lookup_commit(head);
449+
if (head_commit)
450+
commit_list_insert(head_commit, &parents);
451+
parents = reduce_heads(parents);
452+
453+
while (parents) {
454+
for (i = 0; i < result->nr; i++)
455+
if (!hashcmp(result->item[i].commit,
456+
parents->item->object.sha1))
457+
result->item[i].used = 1;
458+
next = parents->next;
459+
free(parents);
460+
parents = next;
461+
}
462+
463+
for (i = j = 0; i < result->nr; i++) {
464+
if (result->item[i].used) {
465+
if (i != j)
466+
result->item[j] = result->item[i];
467+
j++;
468+
}
469+
}
470+
result->nr = j;
471+
}
472+
369473
int fmt_merge_msg(struct strbuf *in, struct strbuf *out,
370474
struct fmt_merge_msg_opts *opts)
371475
{
372476
int i = 0, pos = 0;
373477
unsigned char head_sha1[20];
374478
const char *current_branch;
375479
void *current_branch_to_free;
480+
struct merge_parents merge_parents;
481+
482+
memset(&merge_parents, 0, sizeof(merge_parents));
376483

377484
/* get current branch */
378485
current_branch = current_branch_to_free =
@@ -382,6 +489,8 @@ int fmt_merge_msg(struct strbuf *in, struct strbuf *out,
382489
if (!prefixcmp(current_branch, "refs/heads/"))
383490
current_branch += 11;
384491

492+
find_merge_parents(&merge_parents, in, head_sha1);
493+
385494
/* get a line */
386495
while (pos < in->len) {
387496
int len;
@@ -392,7 +501,7 @@ int fmt_merge_msg(struct strbuf *in, struct strbuf *out,
392501
pos += len + !!newline;
393502
i++;
394503
p[len] = 0;
395-
if (handle_line(p))
504+
if (handle_line(p, &merge_parents))
396505
die ("Error in line %d: %.*s", i, len, p);
397506
}
398507

@@ -423,6 +532,7 @@ int fmt_merge_msg(struct strbuf *in, struct strbuf *out,
423532

424533
strbuf_complete_line(out);
425534
free(current_branch_to_free);
535+
free(merge_parents.item);
426536
return 0;
427537
}
428538

0 commit comments

Comments
 (0)