Skip to content

Commit

Permalink
Faster git.GetDivergingCommits (#24482)
Browse files Browse the repository at this point in the history
Using `git rev-list --left-right` is almost 2x faster than calling `git
rev-list` twice.

Co-authored-by: silverwind <[email protected]>
  • Loading branch information
oliverpool and silverwind authored May 4, 2023
1 parent 377a0a2 commit 75ea0d5
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 22 deletions.
37 changes: 15 additions & 22 deletions modules/git/repo.go
Original file line number Diff line number Diff line change
Expand Up @@ -244,35 +244,28 @@ type DivergeObject struct {
Behind int
}

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

// GetDivergingCommits returns the number of commits a targetBranch is ahead or behind a baseBranch
func GetDivergingCommits(ctx context.Context, repoPath, baseBranch, targetBranch string) (DivergeObject, error) {
// $(git rev-list --count master..feature) commits ahead of master
ahead, errorAhead := checkDivergence(ctx, repoPath, baseBranch, targetBranch)
if errorAhead != nil {
return DivergeObject{}, errorAhead
do.Behind, err = strconv.Atoi(left)
if err != nil {
return do, err
}

// $(git rev-list --count feature..master) commits behind master
behind, errorBehind := checkDivergence(ctx, repoPath, targetBranch, baseBranch)
if errorBehind != nil {
return DivergeObject{}, errorBehind
do.Ahead, err = strconv.Atoi(right)
if err != nil {
return do, err
}

return DivergeObject{ahead, behind}, nil
return do, nil
}

// CreateBundle create bundle content to the target path
Expand Down
25 changes: 25 additions & 0 deletions modules/git/repo_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
package git

import (
"context"
"path/filepath"
"testing"

Expand All @@ -29,3 +30,27 @@ func TestRepoIsEmpty(t *testing.T) {
assert.NoError(t, err)
assert.True(t, isEmpty)
}

func TestRepoGetDivergingCommits(t *testing.T) {
bareRepo1Path := filepath.Join(testReposDir, "repo1_bare")
do, err := GetDivergingCommits(context.Background(), bareRepo1Path, "master", "branch2")
assert.NoError(t, err)
assert.Equal(t, DivergeObject{
Ahead: 1,
Behind: 5,
}, do)

do, err = GetDivergingCommits(context.Background(), bareRepo1Path, "master", "master")
assert.NoError(t, err)
assert.Equal(t, DivergeObject{
Ahead: 0,
Behind: 0,
}, do)

do, err = GetDivergingCommits(context.Background(), bareRepo1Path, "master", "test")
assert.NoError(t, err)
assert.Equal(t, DivergeObject{
Ahead: 0,
Behind: 2,
}, do)
}

0 comments on commit 75ea0d5

Please sign in to comment.