@@ -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
85124static 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