Skip to content

Commit 75ea0d5

Browse files
Faster git.GetDivergingCommits (#24482)
Using `git rev-list --left-right` is almost 2x faster than calling `git rev-list` twice. Co-authored-by: silverwind <[email protected]>
1 parent 377a0a2 commit 75ea0d5

File tree

2 files changed

+40
-22
lines changed

2 files changed

+40
-22
lines changed

modules/git/repo.go

Lines changed: 15 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -244,35 +244,28 @@ type DivergeObject struct {
244244
Behind int
245245
}
246246

247-
func checkDivergence(ctx context.Context, repoPath, baseBranch, targetBranch string) (int, error) {
248-
branches := fmt.Sprintf("%s..%s", baseBranch, targetBranch)
249-
cmd := NewCommand(ctx, "rev-list", "--count").AddDynamicArguments(branches)
247+
// GetDivergingCommits returns the number of commits a targetBranch is ahead or behind a baseBranch
248+
func GetDivergingCommits(ctx context.Context, repoPath, baseBranch, targetBranch string) (do DivergeObject, err error) {
249+
cmd := NewCommand(ctx, "rev-list", "--count", "--left-right").
250+
AddDynamicArguments(baseBranch + "..." + targetBranch)
250251
stdout, _, err := cmd.RunStdString(&RunOpts{Dir: repoPath})
251252
if err != nil {
252-
return -1, err
253+
return do, err
253254
}
254-
outInteger, errInteger := strconv.Atoi(strings.Trim(stdout, "\n"))
255-
if errInteger != nil {
256-
return -1, errInteger
255+
left, right, found := strings.Cut(strings.Trim(stdout, "\n"), "\t")
256+
if !found {
257+
return do, fmt.Errorf("git rev-list output is missing a tab: %q", stdout)
257258
}
258-
return outInteger, nil
259-
}
260259

261-
// GetDivergingCommits returns the number of commits a targetBranch is ahead or behind a baseBranch
262-
func GetDivergingCommits(ctx context.Context, repoPath, baseBranch, targetBranch string) (DivergeObject, error) {
263-
// $(git rev-list --count master..feature) commits ahead of master
264-
ahead, errorAhead := checkDivergence(ctx, repoPath, baseBranch, targetBranch)
265-
if errorAhead != nil {
266-
return DivergeObject{}, errorAhead
260+
do.Behind, err = strconv.Atoi(left)
261+
if err != nil {
262+
return do, err
267263
}
268-
269-
// $(git rev-list --count feature..master) commits behind master
270-
behind, errorBehind := checkDivergence(ctx, repoPath, targetBranch, baseBranch)
271-
if errorBehind != nil {
272-
return DivergeObject{}, errorBehind
264+
do.Ahead, err = strconv.Atoi(right)
265+
if err != nil {
266+
return do, err
273267
}
274-
275-
return DivergeObject{ahead, behind}, nil
268+
return do, nil
276269
}
277270

278271
// CreateBundle create bundle content to the target path

modules/git/repo_test.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
package git
55

66
import (
7+
"context"
78
"path/filepath"
89
"testing"
910

@@ -29,3 +30,27 @@ func TestRepoIsEmpty(t *testing.T) {
2930
assert.NoError(t, err)
3031
assert.True(t, isEmpty)
3132
}
33+
34+
func TestRepoGetDivergingCommits(t *testing.T) {
35+
bareRepo1Path := filepath.Join(testReposDir, "repo1_bare")
36+
do, err := GetDivergingCommits(context.Background(), bareRepo1Path, "master", "branch2")
37+
assert.NoError(t, err)
38+
assert.Equal(t, DivergeObject{
39+
Ahead: 1,
40+
Behind: 5,
41+
}, do)
42+
43+
do, err = GetDivergingCommits(context.Background(), bareRepo1Path, "master", "master")
44+
assert.NoError(t, err)
45+
assert.Equal(t, DivergeObject{
46+
Ahead: 0,
47+
Behind: 0,
48+
}, do)
49+
50+
do, err = GetDivergingCommits(context.Background(), bareRepo1Path, "master", "test")
51+
assert.NoError(t, err)
52+
assert.Equal(t, DivergeObject{
53+
Ahead: 0,
54+
Behind: 2,
55+
}, do)
56+
}

0 commit comments

Comments
 (0)