Skip to content

Commit 0b9442d

Browse files
Linus TorvaldsJunio C Hamano
authored andcommitted
[PATCH] Speed up git-merge-base a lot
In commit 4f7eb2e I fixed git-merge-base getting confused by datestamps that caused it to traverse things in a non-obvious order. However, my fix was a very brute-force one, and it had some really horrible implications for more complex trees with lots of parallell development. It might end up traversing all the way to the root commit. Now, normally that isn't that horrible: it's used mainly for merging, and the bad cases really tend to happen fairly rarely, so if it takes a few seconds, we're not in too bad shape. However, gitk will also do the git-merge-base for every merge it shows, because it basically re-does the trivial merge in order to show the "interesting" parts. And there we'd really like the result to be instantaneous. This patch does that by walking the tree more completely, and using the same heuristic as git-rev-list to decide "ok, the rest is uninteresting". In one - hopefully fairly extreme - case, it made a git-merge-base go from just under five seconds(!) to a tenth of a second on my machine. Signed-off-by: Linus Torvalds <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 2b64f88 commit 0b9442d

File tree

1 file changed

+22
-7
lines changed

1 file changed

+22
-7
lines changed

merge-base.c

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,22 @@
22
#include "cache.h"
33
#include "commit.h"
44

5+
#define PARENT1 1
6+
#define PARENT2 2
7+
#define UNINTERESTING 4
8+
9+
static int interesting(struct commit_list *list)
10+
{
11+
while (list) {
12+
struct commit *commit = list->item;
13+
list = list->next;
14+
if (commit->object.flags & UNINTERESTING)
15+
continue;
16+
return 1;
17+
}
18+
return 0;
19+
}
20+
521
static struct commit *common_ancestor(struct commit *rev1, struct commit *rev2)
622
{
723
struct commit_list *list = NULL;
@@ -18,19 +34,18 @@ static struct commit *common_ancestor(struct commit *rev1, struct commit *rev2)
1834
insert_by_date(rev1, &list);
1935
insert_by_date(rev2, &list);
2036

21-
while (list) {
37+
while (interesting(list)) {
2238
struct commit *commit = list->item;
2339
struct commit_list *tmp = list, *parents;
24-
int flags = commit->object.flags & 3;
40+
int flags = commit->object.flags & 7;
2541

2642
list = list->next;
2743
free(tmp);
28-
switch (flags) {
29-
case 3:
44+
if (flags == 3) {
3045
insert_by_date(commit, &result);
31-
continue;
32-
case 0:
33-
die("git-merge-base: commit without either parent?");
46+
47+
/* Mark children of a found merge uninteresting */
48+
flags |= UNINTERESTING;
3449
}
3550
parents = commit->parents;
3651
while (parents) {

0 commit comments

Comments
 (0)