Skip to content

Commit 283097e

Browse files
committed
Merge branch 'jc/merge-reduce-parents-early'
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 7b864ab + 5802f81 commit 283097e

File tree

5 files changed

+275
-70
lines changed

5 files changed

+275
-70
lines changed

builtin/fmt-merge-msg.c

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

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

67109
if (len < 43 || line[40] != '\t')
68110
return 1;
@@ -73,14 +115,15 @@ static int handle_line(char *line)
73115
if (line[41] != '\t')
74116
return 2;
75117

76-
line[40] = 0;
77-
origin_data = xcalloc(1, sizeof(struct origin_data));
78-
i = get_sha1(line, origin_data->sha1);
79-
line[40] = '\t';
80-
if (i) {
81-
free(origin_data);
118+
i = get_sha1_hex(line, sha1);
119+
if (i)
82120
return 3;
83-
}
121+
122+
if (!find_merge_parent(merge_parents, sha1, NULL))
123+
return 0; /* subsumed by other parents */
124+
125+
origin_data = xcalloc(1, sizeof(struct origin_data));
126+
hashcpy(origin_data->sha1, sha1);
84127

85128
if (line[len - 1] == '\n')
86129
line[len - 1] = 0;
@@ -472,13 +515,77 @@ static void fmt_merge_msg_sigs(struct strbuf *out)
472515
strbuf_release(&tagbuf);
473516
}
474517

518+
static void find_merge_parents(struct merge_parents *result,
519+
struct strbuf *in, unsigned char *head)
520+
{
521+
struct commit_list *parents, *next;
522+
struct commit *head_commit;
523+
int pos = 0, i, j;
524+
525+
parents = NULL;
526+
while (pos < in->len) {
527+
int len;
528+
char *p = in->buf + pos;
529+
char *newline = strchr(p, '\n');
530+
unsigned char sha1[20];
531+
struct commit *parent;
532+
struct object *obj;
533+
534+
len = newline ? newline - p : strlen(p);
535+
pos += len + !!newline;
536+
537+
if (len < 43 ||
538+
get_sha1_hex(p, sha1) ||
539+
p[40] != '\t' ||
540+
p[41] != '\t')
541+
continue; /* skip not-for-merge */
542+
/*
543+
* Do not use get_merge_parent() here; we do not have
544+
* "name" here and we do not want to contaminate its
545+
* util field yet.
546+
*/
547+
obj = parse_object(sha1);
548+
parent = (struct commit *)peel_to_type(NULL, 0, obj, OBJ_COMMIT);
549+
if (!parent)
550+
continue;
551+
commit_list_insert(parent, &parents);
552+
add_merge_parent(result, obj->sha1, parent->object.sha1);
553+
}
554+
head_commit = lookup_commit(head);
555+
if (head_commit)
556+
commit_list_insert(head_commit, &parents);
557+
parents = reduce_heads(parents);
558+
559+
while (parents) {
560+
for (i = 0; i < result->nr; i++)
561+
if (!hashcmp(result->item[i].commit,
562+
parents->item->object.sha1))
563+
result->item[i].used = 1;
564+
next = parents->next;
565+
free(parents);
566+
parents = next;
567+
}
568+
569+
for (i = j = 0; i < result->nr; i++) {
570+
if (result->item[i].used) {
571+
if (i != j)
572+
result->item[j] = result->item[i];
573+
j++;
574+
}
575+
}
576+
result->nr = j;
577+
}
578+
475579
int fmt_merge_msg(struct strbuf *in, struct strbuf *out,
476580
struct fmt_merge_msg_opts *opts)
477581
{
478582
int i = 0, pos = 0;
479583
unsigned char head_sha1[20];
480584
const char *current_branch;
481585
void *current_branch_to_free;
586+
struct merge_parents merge_parents;
587+
588+
memset(&merge_parents, 0, sizeof(merge_parents));
482589

483590
/* get current branch */
484591
current_branch = current_branch_to_free =
@@ -488,6 +595,8 @@ int fmt_merge_msg(struct strbuf *in, struct strbuf *out,
488595
if (!prefixcmp(current_branch, "refs/heads/"))
489596
current_branch += 11;
490597

598+
find_merge_parents(&merge_parents, in, head_sha1);
599+
491600
/* get a line */
492601
while (pos < in->len) {
493602
int len;
@@ -498,7 +607,7 @@ int fmt_merge_msg(struct strbuf *in, struct strbuf *out,
498607
pos += len + !!newline;
499608
i++;
500609
p[len] = 0;
501-
if (handle_line(p))
610+
if (handle_line(p, &merge_parents))
502611
die ("Error in line %d: %.*s", i, len, p);
503612
}
504613

@@ -529,6 +638,7 @@ int fmt_merge_msg(struct strbuf *in, struct strbuf *out,
529638

530639
strbuf_complete_line(out);
531640
free(current_branch_to_free);
641+
free(merge_parents.item);
532642
return 0;
533643
}
534644

0 commit comments

Comments
 (0)