Refactor git command stderr handling (#36402)

And clean up legacy fragile & incorrect logic
This commit is contained in:
wxiaoguang
2026-01-19 07:10:33 +08:00
committed by GitHub
parent fafd1db19e
commit 72be55f7d3
69 changed files with 345 additions and 627 deletions

View File

@@ -36,12 +36,7 @@ func CreateArchive(ctx context.Context, repo Repository, format string, target i
paths[i] = path.Clean(paths[i])
}
cmd.AddDynamicArguments(paths...)
var stderr strings.Builder
if err := RunCmd(ctx, repo, cmd.WithStdout(target).WithStderr(&stderr)); err != nil {
return gitcmd.ConcatenateError(err, stderr.String())
}
return nil
return RunCmdWithStderr(ctx, repo, cmd.WithStdout(target))
}
// CreateBundle create bundle content to the target path

View File

@@ -12,16 +12,16 @@ import (
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/git/gitcmd"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
)
func LineBlame(ctx context.Context, repo Repository, revision, file string, line uint) (string, error) {
return RunCmdString(ctx, repo,
stdout, _, err := RunCmdString(ctx, repo,
gitcmd.NewCommand("blame").
AddOptionFormat("-L %d,%d", line, line).
AddOptionValues("-p", revision).
AddDashesAndList(file))
return stdout, err
}
// BlamePart represents block of blame - continuous lines with one sha
@@ -173,17 +173,10 @@ func CreateBlameReader(ctx context.Context, objectFormat git.ObjectFormat, repo
return nil, err
}
go func() {
stderr := bytes.Buffer{}
// TODO: it doesn't work for directories (the directories shouldn't be "blamed"), and the "err" should be returned by "Read" but not by "Close"
err := RunCmd(ctx, repo, cmd.WithUseContextTimeout(true).
WithStdout(stdout).
WithStderr(&stderr),
)
err := RunCmdWithStderr(ctx, repo, cmd.WithUseContextTimeout(true).WithStdout(stdout))
done <- err
_ = stdout.Close()
if err != nil {
log.Error("Error running git blame (dir: %v): %v, stderr: %v", repoPath, err, stderr.String())
}
}()
bufferedReader := bufio.NewReader(reader)

View File

@@ -36,14 +36,14 @@ func GetBranchCommitID(ctx context.Context, repo Repository, branch string) (str
// SetDefaultBranch sets default branch of repository.
func SetDefaultBranch(ctx context.Context, repo Repository, name string) error {
_, err := RunCmdString(ctx, repo, gitcmd.NewCommand("symbolic-ref", "HEAD").
_, _, err := RunCmdString(ctx, repo, gitcmd.NewCommand("symbolic-ref", "HEAD").
AddDynamicArguments(git.BranchPrefix+name))
return err
}
// GetDefaultBranch gets default branch of repository.
func GetDefaultBranch(ctx context.Context, repo Repository) (string, error) {
stdout, err := RunCmdString(ctx, repo, gitcmd.NewCommand("symbolic-ref", "HEAD"))
stdout, _, err := RunCmdString(ctx, repo, gitcmd.NewCommand("symbolic-ref", "HEAD"))
if err != nil {
return "", err
}
@@ -56,7 +56,7 @@ func GetDefaultBranch(ctx context.Context, repo Repository) (string, error) {
// IsReferenceExist returns true if given reference exists in the repository.
func IsReferenceExist(ctx context.Context, repo Repository, name string) bool {
_, err := RunCmdString(ctx, repo, gitcmd.NewCommand("show-ref", "--verify").AddDashesAndList(name))
_, _, err := RunCmdString(ctx, repo, gitcmd.NewCommand("show-ref", "--verify").AddDashesAndList(name))
return err == nil
}
@@ -76,7 +76,7 @@ func DeleteBranch(ctx context.Context, repo Repository, name string, force bool)
}
cmd.AddDashesAndList(name)
_, err := RunCmdString(ctx, repo, cmd)
_, _, err := RunCmdString(ctx, repo, cmd)
return err
}
@@ -85,12 +85,12 @@ func CreateBranch(ctx context.Context, repo Repository, branch, oldbranchOrCommi
cmd := gitcmd.NewCommand("branch")
cmd.AddDashesAndList(branch, oldbranchOrCommit)
_, err := RunCmdString(ctx, repo, cmd)
_, _, err := RunCmdString(ctx, repo, cmd)
return err
}
// RenameBranch rename a branch
func RenameBranch(ctx context.Context, repo Repository, from, to string) error {
_, err := RunCmdString(ctx, repo, gitcmd.NewCommand("branch", "-m").AddDynamicArguments(from, to))
_, _, err := RunCmdString(ctx, repo, gitcmd.NewCommand("branch", "-m").AddDynamicArguments(from, to))
return err
}

View File

@@ -13,11 +13,14 @@ func RunCmd(ctx context.Context, repo Repository, cmd *gitcmd.Command) error {
return cmd.WithDir(repoPath(repo)).WithParentCallerInfo().Run(ctx)
}
func RunCmdString(ctx context.Context, repo Repository, cmd *gitcmd.Command) (string, error) {
res, _, err := cmd.WithDir(repoPath(repo)).WithParentCallerInfo().RunStdString(ctx)
return res, err
func RunCmdString(ctx context.Context, repo Repository, cmd *gitcmd.Command) (string, string, gitcmd.RunStdError) {
return cmd.WithDir(repoPath(repo)).WithParentCallerInfo().RunStdString(ctx)
}
func RunCmdBytes(ctx context.Context, repo Repository, cmd *gitcmd.Command) ([]byte, []byte, error) {
func RunCmdBytes(ctx context.Context, repo Repository, cmd *gitcmd.Command) ([]byte, []byte, gitcmd.RunStdError) {
return cmd.WithDir(repoPath(repo)).WithParentCallerInfo().RunStdBytes(ctx)
}
func RunCmdWithStderr(ctx context.Context, repo Repository, cmd *gitcmd.Command) gitcmd.RunStdError {
return cmd.WithDir(repoPath(repo)).WithParentCallerInfo().RunWithStderr(ctx)
}

View File

@@ -88,7 +88,7 @@ func AllCommitsCount(ctx context.Context, repo Repository, hidePRRefs bool, file
cmd.AddDashesAndList(files...)
}
stdout, err := RunCmdString(ctx, repo, cmd)
stdout, _, err := RunCmdString(ctx, repo, cmd)
if err != nil {
return 0, err
}
@@ -102,7 +102,7 @@ func GetFullCommitID(ctx context.Context, repo Repository, shortID string) (stri
// GetLatestCommitTime returns time for latest commit in repository (across all branches)
func GetLatestCommitTime(ctx context.Context, repo Repository) (time.Time, error) {
stdout, err := RunCmdString(ctx, repo,
stdout, _, err := RunCmdString(ctx, repo,
gitcmd.NewCommand("for-each-ref", "--sort=-committerdate", git.BranchPrefix, "--count", "1", "--format=%(committerdate)"))
if err != nil {
return time.Time{}, err

View File

@@ -5,7 +5,6 @@ package gitrepo
import (
"bufio"
"bytes"
"context"
"io"
@@ -76,16 +75,14 @@ func GetCommitFileStatus(ctx context.Context, repo Repository, commitID string)
close(done)
}()
stderr := new(bytes.Buffer)
err := gitcmd.NewCommand("log", "--name-status", "-m", "--pretty=format:", "--first-parent", "--no-renames", "-z", "-1").
AddDynamicArguments(commitID).
WithDir(repoPath(repo)).
WithStdout(w).
WithStderr(stderr).
Run(ctx)
w.Close() // Close writer to exit parsing goroutine
RunWithStderr(ctx)
_ = w.Close() // Close writer to exit parsing goroutine
if err != nil {
return nil, gitcmd.ConcatenateError(err, stderr.String())
return nil, err
}
<-done

View File

@@ -22,7 +22,7 @@ type DivergeObject struct {
func GetDivergingCommits(ctx context.Context, repo Repository, baseBranch, targetBranch string) (*DivergeObject, error) {
cmd := gitcmd.NewCommand("rev-list", "--count", "--left-right").
AddDynamicArguments(baseBranch + "..." + targetBranch).AddArguments("--")
stdout, err1 := RunCmdString(ctx, repo, cmd)
stdout, _, err1 := RunCmdString(ctx, repo, cmd)
if err1 != nil {
return nil, err1
}

View File

@@ -12,7 +12,7 @@ import (
)
func GitConfigGet(ctx context.Context, repo Repository, key string) (string, error) {
result, err := RunCmdString(ctx, repo, gitcmd.NewCommand("config", "--get").
result, _, err := RunCmdString(ctx, repo, gitcmd.NewCommand("config", "--get").
AddDynamicArguments(key))
if err != nil {
return "", err
@@ -27,7 +27,7 @@ func getRepoConfigLockKey(repoStoragePath string) string {
// GitConfigAdd add a git configuration key to a specific value for the given repository.
func GitConfigAdd(ctx context.Context, repo Repository, key, value string) error {
return globallock.LockAndDo(ctx, getRepoConfigLockKey(repo.RelativePath()), func(ctx context.Context) error {
_, err := RunCmdString(ctx, repo, gitcmd.NewCommand("config", "--add").
_, _, err := RunCmdString(ctx, repo, gitcmd.NewCommand("config", "--add").
AddDynamicArguments(key, value))
return err
})
@@ -38,7 +38,7 @@ func GitConfigAdd(ctx context.Context, repo Repository, key, value string) error
// If the key exists, it will be updated to the new value.
func GitConfigSet(ctx context.Context, repo Repository, key, value string) error {
return globallock.LockAndDo(ctx, getRepoConfigLockKey(repo.RelativePath()), func(ctx context.Context) error {
_, err := RunCmdString(ctx, repo, gitcmd.NewCommand("config").
_, _, err := RunCmdString(ctx, repo, gitcmd.NewCommand("config").
AddDynamicArguments(key, value))
return err
})

View File

@@ -4,7 +4,6 @@
package gitrepo
import (
"bytes"
"context"
"fmt"
"io"
@@ -22,7 +21,7 @@ func GetDiffShortStatByCmdArgs(ctx context.Context, repo Repository, trustedArgs
// we get:
// " 9902 files changed, 2034198 insertions(+), 298800 deletions(-)\n"
cmd := gitcmd.NewCommand("diff", "--shortstat").AddArguments(trustedArgs...).AddDynamicArguments(dynamicArgs...)
stdout, err := RunCmdString(ctx, repo, cmd)
stdout, _, err := RunCmdString(ctx, repo, cmd)
if err != nil {
return 0, 0, 0, err
}
@@ -65,12 +64,8 @@ func parseDiffStat(stdout string) (numFiles, totalAdditions, totalDeletions int,
// GetReverseRawDiff dumps the reverse diff results of repository in given commit ID to io.Writer.
func GetReverseRawDiff(ctx context.Context, repo Repository, commitID string, writer io.Writer) error {
stderr := new(bytes.Buffer)
if err := RunCmd(ctx, repo, gitcmd.NewCommand("show", "--pretty=format:revert %H%n", "-R").
return RunCmdWithStderr(ctx, repo, gitcmd.NewCommand("show", "--pretty=format:revert %H%n", "-R").
AddDynamicArguments(commitID).
WithStdout(writer).
WithStderr(stderr)); err != nil {
return fmt.Errorf("GetReverseRawDiff: %w - %s", err, stderr)
}
return nil
WithStdout(writer),
)
}

View File

@@ -13,7 +13,7 @@ import (
// MergeBase checks and returns merge base of two commits.
func MergeBase(ctx context.Context, repo Repository, baseCommitID, headCommitID string) (string, error) {
mergeBase, err := RunCmdString(ctx, repo, gitcmd.NewCommand("merge-base").
mergeBase, _, err := RunCmdString(ctx, repo, gitcmd.NewCommand("merge-base").
AddDashesAndList(baseCommitID, headCommitID))
if err != nil {
return "", fmt.Errorf("get merge-base of %s and %s failed: %w", baseCommitID, headCommitID, err)

View File

@@ -6,8 +6,6 @@ package gitrepo
import (
"context"
"errors"
"io"
"time"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/git/gitcmd"
@@ -36,7 +34,7 @@ func GitRemoteAdd(ctx context.Context, repo Repository, remoteName, remoteURL st
return errors.New("unknown remote option: " + string(options[0]))
}
}
_, err := RunCmdString(ctx, repo, cmd.AddDynamicArguments(remoteName, remoteURL))
_, _, err := RunCmdString(ctx, repo, cmd.AddDynamicArguments(remoteName, remoteURL))
return err
})
}
@@ -44,7 +42,7 @@ func GitRemoteAdd(ctx context.Context, repo Repository, remoteName, remoteURL st
func GitRemoteRemove(ctx context.Context, repo Repository, remoteName string) error {
return globallock.LockAndDo(ctx, getRepoConfigLockKey(repo.RelativePath()), func(ctx context.Context) error {
cmd := gitcmd.NewCommand("remote", "rm").AddDynamicArguments(remoteName)
_, err := RunCmdString(ctx, repo, cmd)
_, _, err := RunCmdString(ctx, repo, cmd)
return err
})
}
@@ -60,21 +58,3 @@ func GitRemoteGetURL(ctx context.Context, repo Repository, remoteName string) (*
}
return giturl.ParseGitURL(addr)
}
// GitRemotePrune prunes the remote branches that no longer exist in the remote repository.
func GitRemotePrune(ctx context.Context, repo Repository, remoteName string, timeout time.Duration, stdout, stderr io.Writer) error {
return RunCmd(ctx, repo, gitcmd.NewCommand("remote", "prune").
AddDynamicArguments(remoteName).
WithTimeout(timeout).
WithStdout(stdout).
WithStderr(stderr))
}
// GitRemoteUpdatePrune updates the remote branches and prunes the ones that no longer exist in the remote repository.
func GitRemoteUpdatePrune(ctx context.Context, repo Repository, remoteName string, timeout time.Duration, stdout, stderr io.Writer) error {
return RunCmd(ctx, repo, gitcmd.NewCommand("remote", "update", "--prune").
AddDynamicArguments(remoteName).
WithTimeout(timeout).
WithStdout(stdout).
WithStderr(stderr))
}