mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-10-31 21:28:11 +09:00 
			
		
		
		
	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:
		| @@ -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) | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user