Skip to content

Commit ed9a540

Browse files
author
Junio C Hamano
committed
merge-base: fully contaminate the well.
The discussion on the list demonstrated a pathological case where an ancestor of a merge-base can be left interesting. This commit introduces a postprocessing phase to fix it. Signed-off-by: Junio C Hamano <junkio@cox.net>
1 parent 592ee97 commit ed9a540

File tree

1 file changed

+77
-1
lines changed

1 file changed

+77
-1
lines changed

merge-base.c

Lines changed: 77 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,45 @@ static struct commit *interesting(struct commit_list *list)
8080
* Now, list does not have any interesting commit. So we find the newest
8181
* commit from the result list that is not marked uninteresting. Which is
8282
* commit B.
83+
*
84+
*
85+
* Another pathological example how this thing can fail to mark an ancestor
86+
* of a merge base as UNINTERESTING without the postprocessing phase.
87+
*
88+
* 2
89+
* H
90+
* 1 / \
91+
* G A \
92+
* |\ / \
93+
* | B \
94+
* | \ \
95+
* \ C F
96+
* \ \ /
97+
* \ D /
98+
* \ | /
99+
* \| /
100+
* E
101+
*
102+
* list A B C D E F G H
103+
* G1 H2 - - - - - - 1 2
104+
* H2 E1 B1 - 1 - - 1 - 1 2
105+
* F2 E1 B1 A2 2 1 - - 1 2 1 2
106+
* E3 B1 A2 2 1 - - 3 2 1 2
107+
* B1 A2 2 1 - - 3 2 1 2
108+
* C1 A2 2 1 1 - 3 2 1 2
109+
* D1 A2 2 1 1 1 3 2 1 2
110+
* A2 2 1 1 1 3 2 1 2
111+
* B3 2 3 1 1 3 2 1 2
112+
* C7 2 3 7 1 3 2 1 2
113+
*
114+
* At this point, unfortunately, everybody in the list is
115+
* uninteresting, so we fail to complete the following two
116+
* steps to fully marking uninteresting commits.
117+
*
118+
* D7 2 3 7 7 3 2 1 2
119+
* E7 2 3 7 7 7 2 1 2
120+
*
121+
* and we end up showing E as an interesting merge base.
83122
*/
84123

85124
static int show_all = 0;
@@ -88,6 +127,7 @@ static int merge_base(struct commit *rev1, struct commit *rev2)
88127
{
89128
struct commit_list *list = NULL;
90129
struct commit_list *result = NULL;
130+
struct commit_list *tmp = NULL;
91131

92132
if (rev1 == rev2) {
93133
printf("%s\n", sha1_to_hex(rev1->object.sha1));
@@ -104,9 +144,10 @@ static int merge_base(struct commit *rev1, struct commit *rev2)
104144

105145
while (interesting(list)) {
106146
struct commit *commit = list->item;
107-
struct commit_list *tmp = list, *parents;
147+
struct commit_list *parents;
108148
int flags = commit->object.flags & 7;
109149

150+
tmp = list;
110151
list = list->next;
111152
free(tmp);
112153
if (flags == 3) {
@@ -130,6 +171,41 @@ static int merge_base(struct commit *rev1, struct commit *rev2)
130171
if (!result)
131172
return 1;
132173

174+
/*
175+
* Postprocess to fully contaminate the well.
176+
*/
177+
for (tmp = result; tmp; tmp = tmp->next) {
178+
struct commit *c = tmp->item;
179+
/* Reinject uninteresting ones to list,
180+
* so we can scan their parents.
181+
*/
182+
if (c->object.flags & UNINTERESTING)
183+
commit_list_insert(c, &list);
184+
}
185+
while (list) {
186+
struct commit *c = list->item;
187+
struct commit_list *parents;
188+
189+
tmp = list;
190+
list = list->next;
191+
free(tmp);
192+
193+
/* Anything taken out of the list is uninteresting, so
194+
* mark all its parents uninteresting. We do not
195+
* parse new ones (we already parsed all the relevant
196+
* ones).
197+
*/
198+
parents = c->parents;
199+
while (parents) {
200+
struct commit *p = parents->item;
201+
parents = parents->next;
202+
if (!(p->object.flags & UNINTERESTING)) {
203+
p->object.flags |= UNINTERESTING;
204+
commit_list_insert(p, &list);
205+
}
206+
}
207+
}
208+
133209
while (result) {
134210
struct commit *commit = result->item;
135211
result = result->next;

0 commit comments

Comments
 (0)