Faster git.GetDivergingCommits (#24482)
Using `git rev-list --left-right` is almost 2x faster than calling `git rev-list` twice. Co-authored-by: silverwind <me@silverwind.io>
This commit is contained in:
parent
377a0a20f0
commit
75ea0d5dba
|
@ -244,35 +244,28 @@ type DivergeObject struct {
|
||||||
Behind int
|
Behind int
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkDivergence(ctx context.Context, repoPath, baseBranch, targetBranch string) (int, error) {
|
// GetDivergingCommits returns the number of commits a targetBranch is ahead or behind a baseBranch
|
||||||
branches := fmt.Sprintf("%s..%s", baseBranch, targetBranch)
|
func GetDivergingCommits(ctx context.Context, repoPath, baseBranch, targetBranch string) (do DivergeObject, err error) {
|
||||||
cmd := NewCommand(ctx, "rev-list", "--count").AddDynamicArguments(branches)
|
cmd := NewCommand(ctx, "rev-list", "--count", "--left-right").
|
||||||
|
AddDynamicArguments(baseBranch + "..." + targetBranch)
|
||||||
stdout, _, err := cmd.RunStdString(&RunOpts{Dir: repoPath})
|
stdout, _, err := cmd.RunStdString(&RunOpts{Dir: repoPath})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return -1, err
|
return do, err
|
||||||
}
|
}
|
||||||
outInteger, errInteger := strconv.Atoi(strings.Trim(stdout, "\n"))
|
left, right, found := strings.Cut(strings.Trim(stdout, "\n"), "\t")
|
||||||
if errInteger != nil {
|
if !found {
|
||||||
return -1, errInteger
|
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// $(git rev-list --count feature..master) commits behind master
|
do.Behind, err = strconv.Atoi(left)
|
||||||
behind, errorBehind := checkDivergence(ctx, repoPath, targetBranch, baseBranch)
|
if err != nil {
|
||||||
if errorBehind != nil {
|
return do, err
|
||||||
return DivergeObject{}, errorBehind
|
|
||||||
}
|
}
|
||||||
|
do.Ahead, err = strconv.Atoi(right)
|
||||||
return DivergeObject{ahead, behind}, nil
|
if err != nil {
|
||||||
|
return do, err
|
||||||
|
}
|
||||||
|
return do, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateBundle create bundle content to the target path
|
// CreateBundle create bundle content to the target path
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
package git
|
package git
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
@ -29,3 +30,27 @@ func TestRepoIsEmpty(t *testing.T) {
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.True(t, isEmpty)
|
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)
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue