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
					
				
					 2 changed files with 41 additions and 23 deletions
				
			
		| 
						 | 
				
			
			@ -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
 | 
			
		||||
	}
 | 
			
		||||
	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
 | 
			
		||||
	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)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// $(git rev-list --count feature..master) commits behind master
 | 
			
		||||
	behind, errorBehind := checkDivergence(ctx, repoPath, targetBranch, baseBranch)
 | 
			
		||||
	if errorBehind != nil {
 | 
			
		||||
		return DivergeObject{}, errorBehind
 | 
			
		||||
	do.Behind, err = strconv.Atoi(left)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return do, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return DivergeObject{ahead, behind}, nil
 | 
			
		||||
	do.Ahead, err = strconv.Atoi(right)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return do, err
 | 
			
		||||
	}
 | 
			
		||||
	return do, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CreateBundle create bundle content to the target path
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,6 +4,7 @@
 | 
			
		|||
package git
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -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)
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue