Skip to content

Commit 752b7b2

Browse files
committed
merge-base: mark bases that are on first-parent chain
In a workflow where topic branches are first merged to the 'next' integration branch to be tested before getting merged down to the 'master' integration branch to be consumed by the end users, merging the 'master' branch back to the 'next' happens after topics graduate to 'master' and release notes entries are written for them. Git finds many merge bases between 'master' and 'next' while creating this merge. In addition to the tip of 'master' back when we made such a merge back from 'master' to 'next' was made the last time, which is the most reasonable merge base to explain the histories of both branches, all the tips of topic branches that graduated recently are merge bases. Because these tips of topic branches were already in 'next', the tip of 'next' reaches them, and because they just graduated to 'master', the tip of 'master' reaches them, too. And these topics are independent most of the time (that is the point of employing the topic-branch workflow), so they cannot be reduced. The merge-recursive machinery is very inefficient to compute this merge, because it needs to create pointless virtual merge-base commits across these many merge bases. Conceptually, the point where the histories of 'master' and 'next' diverged was the tip of 'master' back when we created such a merge back from 'master' to 'next' the last time, and in practice that is the only merge base that matters. Update the logic in paint_down_to_common() so that it can mark if a merge-base commit was reached by following the first-parent chain of either side of the merge to find such commit, and give an option to get_merge_bases_opt() to return only merge-base commits that are on the first-parent chain, so that a later step of this series can introduce a command line option to enable it and avoid feeding useless merge bases to the merge machinery. Signed-off-by: Junio C Hamano <[email protected]>
1 parent b702eff commit 752b7b2

File tree

3 files changed

+17
-3
lines changed

3 files changed

+17
-3
lines changed

commit.c

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -765,8 +765,9 @@ void sort_in_topological_order(struct commit_list **list, enum rev_sort_order so
765765
#define PARENT2 (1u<<17)
766766
#define STALE (1u<<18)
767767
#define RESULT (1u<<19)
768+
#define FPCHAIN (1u<<20)
768769

769-
static const unsigned all_flags = (PARENT1 | PARENT2 | STALE | RESULT);
770+
static const unsigned all_flags = (PARENT1 | PARENT2 | STALE | RESULT | FPCHAIN);
770771

771772
static int queue_has_nonstale(struct prio_queue *queue)
772773
{
@@ -802,6 +803,7 @@ static struct commit_list *paint_down_to_common(struct commit *one, int n, struc
802803
struct commit *commit = prio_queue_get(&queue);
803804
struct commit_list *parents;
804805
int flags;
806+
int nth_parent = 0;
805807

806808
flags = commit->object.flags & (PARENT1 | PARENT2 | STALE);
807809
if (flags == (PARENT1 | PARENT2)) {
@@ -816,11 +818,14 @@ static struct commit_list *paint_down_to_common(struct commit *one, int n, struc
816818
while (parents) {
817819
struct commit *p = parents->item;
818820
parents = parents->next;
821+
nth_parent++;
819822
if ((p->object.flags & flags) == flags)
820823
continue;
821824
if (parse_commit(p))
822825
return NULL;
823826
p->object.flags |= flags;
827+
if (nth_parent == 1)
828+
p->object.flags |= FPCHAIN;
824829
prio_queue_put(&queue, p);
825830
}
826831
}
@@ -951,6 +956,8 @@ struct commit_list *get_merge_bases_opt(struct commit *one,
951956
struct commit_list *result;
952957
int cnt, i;
953958
int cleanup = !!(flags & MB_POSTCLEAN);
959+
int fpchain = !!(flags & MB_FPCHAIN);
960+
char *on_fpchain;
954961

955962
result = merge_bases_many(one, n, twos);
956963

@@ -975,21 +982,27 @@ struct commit_list *get_merge_bases_opt(struct commit *one,
975982
/* There are more than one */
976983
cnt = commit_list_count(result);
977984
rslt = xcalloc(cnt, sizeof(*rslt));
985+
on_fpchain = xcalloc(cnt, sizeof(*on_fpchain));
978986
for (list = result, i = 0; list; list = list->next)
979987
rslt[i++] = list->item;
980988
free_commit_list(result);
981989

990+
for (i = 0; i < cnt; i++)
991+
on_fpchain[i] = !!(rslt[i]->object.flags & FPCHAIN);
992+
982993
clear_commit_marks(one, all_flags);
983994
clear_commit_marks_many(n, twos, all_flags);
984995

985996
mark_redundant(rslt, cnt);
986997
result = NULL;
987998
for (i = 0; i < cnt; i++)
988-
if (!(rslt[i]->object.flags & STALE))
999+
if (!(rslt[i]->object.flags & STALE) &&
1000+
(!fpchain || on_fpchain[i]))
9891001
commit_list_insert_by_date(rslt[i], &result);
9901002
else
9911003
rslt[i]->object.flags &= ~STALE;
9921004
free(rslt);
1005+
free(on_fpchain);
9931006
return result;
9941007
}
9951008

commit.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,7 @@ extern struct commit_list *get_merge_bases_many(struct commit *one, int n, struc
254254
extern struct commit_list *get_octopus_merge_bases(struct commit_list *in);
255255

256256
#define MB_POSTCLEAN 01
257+
#define MB_FPCHAIN 02
257258
extern struct commit_list *get_merge_bases_opt(struct commit *one, int n, struct commit **twos, unsigned flags);
258259

259260
#define get_merge_bases_many_dirty(one, n, twos) get_merge_bases_opt((one),(n),(twos),MB_POSTCLEAN)

object.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ struct object_array {
3636
* bisect.c: 16
3737
* bundle.c: 16
3838
* http-push.c: 16-----19
39-
* commit.c: 16-----19
39+
* commit.c: 16-------20
4040
*/
4141
#define FLAG_BITS 27
4242

0 commit comments

Comments
 (0)