Remove `git.Command.Run` and `git.Command.RunInDir*` (#19280)

Follows #19266, #8553, Close #18553, now there are only three `Run..(&RunOpts{})` functions.
 * before: `stdout, err := RunInDir(path)`
 * now: `stdout, _, err := RunStdString(&git.RunOpts{Dir:path})`
pull/19288/head^2
wxiaoguang 3 years ago committed by GitHub
parent 3a73645502
commit 124b072f0b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      cmd/hook.go
  2. 4
      integrations/api_repo_git_tags_test.go
  3. 16
      integrations/git_helper_for_declarative_test.go
  4. 22
      integrations/git_test.go
  5. 28
      integrations/pull_merge_test.go
  6. 4
      integrations/repo_tag_test.go
  7. 8
      models/migrations/v128.go
  8. 4
      models/migrations/v134.go
  9. 8
      modules/doctor/mergebase.go
  10. 4
      modules/doctor/misc.go
  11. 29
      modules/git/batch_reader.go
  12. 103
      modules/git/command.go
  13. 4
      modules/git/command_race_test.go
  14. 4
      modules/git/command_test.go
  15. 27
      modules/git/commit.go
  16. 27
      modules/git/diff.go
  17. 9
      modules/git/git.go
  18. 9
      modules/git/log_name_status.go
  19. 31
      modules/git/pipeline/catfile.go
  20. 9
      modules/git/pipeline/lfs_nogogit.go
  21. 11
      modules/git/pipeline/namerev.go
  22. 18
      modules/git/pipeline/revlist.go
  23. 2
      modules/git/remote.go
  24. 29
      modules/git/repo.go
  25. 9
      modules/git/repo_archive.go
  26. 24
      modules/git/repo_attribute.go
  27. 5
      modules/git/repo_blame.go
  28. 19
      modules/git/repo_branch.go
  29. 9
      modules/git/repo_branch_nogogit.go
  30. 67
      modules/git/repo_commit.go
  31. 2
      modules/git/repo_commit_gogit.go
  32. 8
      modules/git/repo_commit_nogogit.go
  33. 2
      modules/git/repo_commitgraph.go
  34. 73
      modules/git/repo_compare.go
  35. 8
      modules/git/repo_gpg.go
  36. 29
      modules/git/repo_index.go
  37. 11
      modules/git/repo_object.go
  38. 9
      modules/git/repo_ref_nogogit.go
  39. 19
      modules/git/repo_stats.go
  40. 12
      modules/git/repo_tag.go
  41. 13
      modules/git/repo_tree.go
  42. 2
      modules/git/repo_tree_gogit.go
  43. 2
      modules/git/tree.go
  44. 17
      modules/git/tree_nogogit.go
  45. 9
      modules/gitgraph/graph.go
  46. 7
      modules/indexer/code/bleve.go
  47. 8
      modules/indexer/code/elastic_search.go
  48. 26
      modules/indexer/code/git.go
  49. 4
      modules/repository/create.go
  50. 8
      modules/repository/generate.go
  51. 16
      modules/repository/init.go
  52. 4
      modules/repository/push.go
  53. 6
      modules/repository/repo.go
  54. 2
      routers/private/hook_pre_receive.go
  55. 18
      routers/private/hook_verification.go
  56. 21
      routers/web/repo/http.go
  57. 2
      routers/web/repo/pull.go
  58. 2
      services/agit/agit.go
  59. 8
      services/asymkey/sign.go
  60. 2
      services/gitdiff/gitdiff.go
  61. 2
      services/migrations/dump.go
  62. 4
      services/migrations/gitea_uploader.go
  63. 6
      services/migrations/gitea_uploader_test.go
  64. 18
      services/mirror/mirror_pull.go
  65. 10
      services/mirror/mirror_push.go
  66. 8
      services/pull/check.go
  67. 156
      services/pull/merge.go
  68. 26
      services/pull/patch.go
  69. 9
      services/pull/patch_unmerged.go
  70. 2
      services/pull/pull.go
  71. 45
      services/pull/temp_repo.go
  72. 4
      services/release/release.go
  73. 4
      services/repository/adopt.go
  74. 2
      services/repository/check.go
  75. 11
      services/repository/files/patch.go
  76. 56
      services/repository/files/temp_repo.go
  77. 6
      services/repository/fork.go
  78. 2
      services/wiki/wiki.go

@ -309,7 +309,7 @@ func runHookPostReceive(c *cli.Context) error {
defer cancel() defer cancel()
// First of all run update-server-info no matter what // First of all run update-server-info no matter what
if _, err := git.NewCommand(ctx, "update-server-info").Run(); err != nil { if _, _, err := git.NewCommand(ctx, "update-server-info").RunStdString(nil); err != nil {
return fmt.Errorf("Failed to call 'git update-server-info': %v", err) return fmt.Errorf("Failed to call 'git update-server-info': %v", err)
} }

@ -28,8 +28,8 @@ func TestAPIGitTags(t *testing.T) {
token := getTokenForLoggedInUser(t, session) token := getTokenForLoggedInUser(t, session)
// Set up git config for the tagger // Set up git config for the tagger
git.NewCommand(git.DefaultContext, "config", "user.name", user.Name).RunInDir(repo.RepoPath()) _ = git.NewCommand(git.DefaultContext, "config", "user.name", user.Name).Run(&git.RunOpts{Dir: repo.RepoPath()})
git.NewCommand(git.DefaultContext, "config", "user.email", user.Email).RunInDir(repo.RepoPath()) _ = git.NewCommand(git.DefaultContext, "config", "user.email", user.Email).Run(&git.RunOpts{Dir: repo.RepoPath()})
gitRepo, _ := git.OpenRepository(git.DefaultContext, repo.RepoPath()) gitRepo, _ := git.OpenRepository(git.DefaultContext, repo.RepoPath())
defer gitRepo.Close() defer gitRepo.Close()

@ -134,7 +134,7 @@ func doGitInitTestRepository(dstPath string) func(*testing.T) {
// Init repository in dstPath // Init repository in dstPath
assert.NoError(t, git.InitRepository(git.DefaultContext, dstPath, false)) assert.NoError(t, git.InitRepository(git.DefaultContext, dstPath, false))
// forcibly set default branch to master // forcibly set default branch to master
_, err := git.NewCommand(git.DefaultContext, "symbolic-ref", "HEAD", git.BranchPrefix+"master").RunInDir(dstPath) _, _, err := git.NewCommand(git.DefaultContext, "symbolic-ref", "HEAD", git.BranchPrefix+"master").RunStdString(&git.RunOpts{Dir: dstPath})
assert.NoError(t, err) assert.NoError(t, err)
assert.NoError(t, os.WriteFile(filepath.Join(dstPath, "README.md"), []byte(fmt.Sprintf("# Testing Repository\n\nOriginally created in: %s", dstPath)), 0o644)) assert.NoError(t, os.WriteFile(filepath.Join(dstPath, "README.md"), []byte(fmt.Sprintf("# Testing Repository\n\nOriginally created in: %s", dstPath)), 0o644))
assert.NoError(t, git.AddChanges(dstPath, true)) assert.NoError(t, git.AddChanges(dstPath, true))
@ -153,49 +153,49 @@ func doGitInitTestRepository(dstPath string) func(*testing.T) {
func doGitAddRemote(dstPath, remoteName string, u *url.URL) func(*testing.T) { func doGitAddRemote(dstPath, remoteName string, u *url.URL) func(*testing.T) {
return func(t *testing.T) { return func(t *testing.T) {
_, err := git.NewCommand(git.DefaultContext, "remote", "add", remoteName, u.String()).RunInDir(dstPath) _, _, err := git.NewCommand(git.DefaultContext, "remote", "add", remoteName, u.String()).RunStdString(&git.RunOpts{Dir: dstPath})
assert.NoError(t, err) assert.NoError(t, err)
} }
} }
func doGitPushTestRepository(dstPath string, args ...string) func(*testing.T) { func doGitPushTestRepository(dstPath string, args ...string) func(*testing.T) {
return func(t *testing.T) { return func(t *testing.T) {
_, err := git.NewCommand(git.DefaultContext, append([]string{"push", "-u"}, args...)...).RunInDir(dstPath) _, _, err := git.NewCommand(git.DefaultContext, append([]string{"push", "-u"}, args...)...).RunStdString(&git.RunOpts{Dir: dstPath})
assert.NoError(t, err) assert.NoError(t, err)
} }
} }
func doGitPushTestRepositoryFail(dstPath string, args ...string) func(*testing.T) { func doGitPushTestRepositoryFail(dstPath string, args ...string) func(*testing.T) {
return func(t *testing.T) { return func(t *testing.T) {
_, err := git.NewCommand(git.DefaultContext, append([]string{"push"}, args...)...).RunInDir(dstPath) _, _, err := git.NewCommand(git.DefaultContext, append([]string{"push"}, args...)...).RunStdString(&git.RunOpts{Dir: dstPath})
assert.Error(t, err) assert.Error(t, err)
} }
} }
func doGitCreateBranch(dstPath, branch string) func(*testing.T) { func doGitCreateBranch(dstPath, branch string) func(*testing.T) {
return func(t *testing.T) { return func(t *testing.T) {
_, err := git.NewCommand(git.DefaultContext, "checkout", "-b", branch).RunInDir(dstPath) _, _, err := git.NewCommand(git.DefaultContext, "checkout", "-b", branch).RunStdString(&git.RunOpts{Dir: dstPath})
assert.NoError(t, err) assert.NoError(t, err)
} }
} }
func doGitCheckoutBranch(dstPath string, args ...string) func(*testing.T) { func doGitCheckoutBranch(dstPath string, args ...string) func(*testing.T) {
return func(t *testing.T) { return func(t *testing.T) {
_, err := git.NewCommandNoGlobals(append(append(git.AllowLFSFiltersArgs(), "checkout"), args...)...).RunInDir(dstPath) _, _, err := git.NewCommandNoGlobals(append(append(git.AllowLFSFiltersArgs(), "checkout"), args...)...).RunStdString(&git.RunOpts{Dir: dstPath})
assert.NoError(t, err) assert.NoError(t, err)
} }
} }
func doGitMerge(dstPath string, args ...string) func(*testing.T) { func doGitMerge(dstPath string, args ...string) func(*testing.T) {
return func(t *testing.T) { return func(t *testing.T) {
_, err := git.NewCommand(git.DefaultContext, append([]string{"merge"}, args...)...).RunInDir(dstPath) _, _, err := git.NewCommand(git.DefaultContext, append([]string{"merge"}, args...)...).RunStdString(&git.RunOpts{Dir: dstPath})
assert.NoError(t, err) assert.NoError(t, err)
} }
} }
func doGitPull(dstPath string, args ...string) func(*testing.T) { func doGitPull(dstPath string, args ...string) func(*testing.T) {
return func(t *testing.T) { return func(t *testing.T) {
_, err := git.NewCommandNoGlobals(append(append(git.AllowLFSFiltersArgs(), "pull"), args...)...).RunInDir(dstPath) _, _, err := git.NewCommandNoGlobals(append(append(git.AllowLFSFiltersArgs(), "pull"), args...)...).RunStdString(&git.RunOpts{Dir: dstPath})
assert.NoError(t, err) assert.NoError(t, err)
} }
} }

@ -160,9 +160,9 @@ func lfsCommitAndPushTest(t *testing.T, dstPath string) (littleLFS, bigLFS strin
return return
} }
prefix := "lfs-data-file-" prefix := "lfs-data-file-"
_, err := git.NewCommand(git.DefaultContext, "lfs").AddArguments("install").RunInDir(dstPath) err := git.NewCommand(git.DefaultContext, "lfs").AddArguments("install").Run(&git.RunOpts{Dir: dstPath})
assert.NoError(t, err) assert.NoError(t, err)
_, err = git.NewCommand(git.DefaultContext, "lfs").AddArguments("track", prefix+"*").RunInDir(dstPath) _, _, err = git.NewCommand(git.DefaultContext, "lfs").AddArguments("track", prefix+"*").RunStdString(&git.RunOpts{Dir: dstPath})
assert.NoError(t, err) assert.NoError(t, err)
err = git.AddChanges(dstPath, false, ".gitattributes") err = git.AddChanges(dstPath, false, ".gitattributes")
assert.NoError(t, err) assert.NoError(t, err)
@ -292,20 +292,20 @@ func lockTest(t *testing.T, repoPath string) {
} }
func lockFileTest(t *testing.T, filename, repoPath string) { func lockFileTest(t *testing.T, filename, repoPath string) {
_, err := git.NewCommand(git.DefaultContext, "lfs").AddArguments("locks").RunInDir(repoPath) _, _, err := git.NewCommand(git.DefaultContext, "lfs").AddArguments("locks").RunStdString(&git.RunOpts{Dir: repoPath})
assert.NoError(t, err) assert.NoError(t, err)
_, err = git.NewCommand(git.DefaultContext, "lfs").AddArguments("lock", filename).RunInDir(repoPath) _, _, err = git.NewCommand(git.DefaultContext, "lfs").AddArguments("lock", filename).RunStdString(&git.RunOpts{Dir: repoPath})
assert.NoError(t, err) assert.NoError(t, err)
_, err = git.NewCommand(git.DefaultContext, "lfs").AddArguments("locks").RunInDir(repoPath) _, _, err = git.NewCommand(git.DefaultContext, "lfs").AddArguments("locks").RunStdString(&git.RunOpts{Dir: repoPath})
assert.NoError(t, err) assert.NoError(t, err)
_, err = git.NewCommand(git.DefaultContext, "lfs").AddArguments("unlock", filename).RunInDir(repoPath) _, _, err = git.NewCommand(git.DefaultContext, "lfs").AddArguments("unlock", filename).RunStdString(&git.RunOpts{Dir: repoPath})
assert.NoError(t, err) assert.NoError(t, err)
} }
func doCommitAndPush(t *testing.T, size int, repoPath, prefix string) string { func doCommitAndPush(t *testing.T, size int, repoPath, prefix string) string {
name, err := generateCommitWithNewData(size, repoPath, "user2@example.com", "User Two", prefix) name, err := generateCommitWithNewData(size, repoPath, "user2@example.com", "User Two", prefix)
assert.NoError(t, err) assert.NoError(t, err)
_, err = git.NewCommand(git.DefaultContext, "push", "origin", "master").RunInDir(repoPath) // Push _, _, err = git.NewCommand(git.DefaultContext, "push", "origin", "master").RunStdString(&git.RunOpts{Dir: repoPath}) // Push
assert.NoError(t, err) assert.NoError(t, err)
return name return name
} }
@ -671,7 +671,7 @@ func doCreateAgitFlowPull(dstPath string, ctx *APITestContext, baseBranch, headB
}) })
t.Run("Push", func(t *testing.T) { t.Run("Push", func(t *testing.T) {
_, err := git.NewCommand(git.DefaultContext, "push", "origin", "HEAD:refs/for/master", "-o", "topic="+headBranch).RunInDir(dstPath) err := git.NewCommand(git.DefaultContext, "push", "origin", "HEAD:refs/for/master", "-o", "topic="+headBranch).Run(&git.RunOpts{Dir: dstPath})
if !assert.NoError(t, err) { if !assert.NoError(t, err) {
return return
} }
@ -692,7 +692,7 @@ func doCreateAgitFlowPull(dstPath string, ctx *APITestContext, baseBranch, headB
assert.Contains(t, "Testing commit 1", prMsg.Body) assert.Contains(t, "Testing commit 1", prMsg.Body)
assert.Equal(t, commit, prMsg.Head.Sha) assert.Equal(t, commit, prMsg.Head.Sha)
_, err = git.NewCommand(git.DefaultContext, "push", "origin", "HEAD:refs/for/master/test/"+headBranch).RunInDir(dstPath) _, _, err = git.NewCommand(git.DefaultContext, "push", "origin", "HEAD:refs/for/master/test/"+headBranch).RunStdString(&git.RunOpts{Dir: dstPath})
if !assert.NoError(t, err) { if !assert.NoError(t, err) {
return return
} }
@ -745,7 +745,7 @@ func doCreateAgitFlowPull(dstPath string, ctx *APITestContext, baseBranch, headB
}) })
t.Run("Push2", func(t *testing.T) { t.Run("Push2", func(t *testing.T) {
_, err := git.NewCommand(git.DefaultContext, "push", "origin", "HEAD:refs/for/master", "-o", "topic="+headBranch).RunInDir(dstPath) err := git.NewCommand(git.DefaultContext, "push", "origin", "HEAD:refs/for/master", "-o", "topic="+headBranch).Run(&git.RunOpts{Dir: dstPath})
if !assert.NoError(t, err) { if !assert.NoError(t, err) {
return return
} }
@ -757,7 +757,7 @@ func doCreateAgitFlowPull(dstPath string, ctx *APITestContext, baseBranch, headB
assert.Equal(t, false, prMsg.HasMerged) assert.Equal(t, false, prMsg.HasMerged)
assert.Equal(t, commit, prMsg.Head.Sha) assert.Equal(t, commit, prMsg.Head.Sha)
_, err = git.NewCommand(git.DefaultContext, "push", "origin", "HEAD:refs/for/master/test/"+headBranch).RunInDir(dstPath) _, _, err = git.NewCommand(git.DefaultContext, "push", "origin", "HEAD:refs/for/master/test/"+headBranch).RunStdString(&git.RunOpts{Dir: dstPath})
if !assert.NoError(t, err) { if !assert.NoError(t, err) {
return return
} }

@ -269,25 +269,24 @@ func TestCantMergeUnrelated(t *testing.T) {
}).(*repo_model.Repository) }).(*repo_model.Repository)
path := repo_model.RepoPath(user1.Name, repo1.Name) path := repo_model.RepoPath(user1.Name, repo1.Name)
_, err := git.NewCommand(git.DefaultContext, "read-tree", "--empty").RunInDir(path) err := git.NewCommand(git.DefaultContext, "read-tree", "--empty").Run(&git.RunOpts{Dir: path})
assert.NoError(t, err) assert.NoError(t, err)
stdin := bytes.NewBufferString("Unrelated File") stdin := bytes.NewBufferString("Unrelated File")
var stdout strings.Builder var stdout strings.Builder
err = git.NewCommand(git.DefaultContext, "hash-object", "-w", "--stdin").RunWithContext(&git.RunContext{ err = git.NewCommand(git.DefaultContext, "hash-object", "-w", "--stdin").Run(&git.RunOpts{
Timeout: -1, Dir: path,
Dir: path, Stdin: stdin,
Stdin: stdin, Stdout: &stdout,
Stdout: &stdout,
}) })
assert.NoError(t, err) assert.NoError(t, err)
sha := strings.TrimSpace(stdout.String()) sha := strings.TrimSpace(stdout.String())
_, err = git.NewCommand(git.DefaultContext, "update-index", "--add", "--replace", "--cacheinfo", "100644", sha, "somewher-over-the-rainbow").RunInDir(path) _, _, err = git.NewCommand(git.DefaultContext, "update-index", "--add", "--replace", "--cacheinfo", "100644", sha, "somewher-over-the-rainbow").RunStdString(&git.RunOpts{Dir: path})
assert.NoError(t, err) assert.NoError(t, err)
treeSha, err := git.NewCommand(git.DefaultContext, "write-tree").RunInDir(path) treeSha, _, err := git.NewCommand(git.DefaultContext, "write-tree").RunStdString(&git.RunOpts{Dir: path})
assert.NoError(t, err) assert.NoError(t, err)
treeSha = strings.TrimSpace(treeSha) treeSha = strings.TrimSpace(treeSha)
@ -308,17 +307,16 @@ func TestCantMergeUnrelated(t *testing.T) {
stdout.Reset() stdout.Reset()
err = git.NewCommand(git.DefaultContext, "commit-tree", treeSha). err = git.NewCommand(git.DefaultContext, "commit-tree", treeSha).
RunWithContext(&git.RunContext{ Run(&git.RunOpts{
Env: env, Env: env,
Timeout: -1, Dir: path,
Dir: path, Stdin: messageBytes,
Stdin: messageBytes, Stdout: &stdout,
Stdout: &stdout,
}) })
assert.NoError(t, err) assert.NoError(t, err)
commitSha := strings.TrimSpace(stdout.String()) commitSha := strings.TrimSpace(stdout.String())
_, err = git.NewCommand(git.DefaultContext, "branch", "unrelated", commitSha).RunInDir(path) _, _, err = git.NewCommand(git.DefaultContext, "branch", "unrelated", commitSha).RunStdString(&git.RunOpts{Dir: path})
assert.NoError(t, err) assert.NoError(t, err)
testEditFileToNewBranch(t, session, "user1", "repo1", "master", "conflict", "README.md", "Hello, World (Edited Once)\n") testEditFileToNewBranch(t, session, "user1", "repo1", "master", "conflict", "README.md", "Hello, World (Edited Once)\n")

@ -66,10 +66,10 @@ func TestCreateNewTagProtected(t *testing.T) {
doGitClone(dstPath, u)(t) doGitClone(dstPath, u)(t)
_, err = git.NewCommand(git.DefaultContext, "tag", "v-2").RunInDir(dstPath) _, _, err = git.NewCommand(git.DefaultContext, "tag", "v-2").RunStdString(&git.RunOpts{Dir: dstPath})
assert.NoError(t, err) assert.NoError(t, err)
_, err = git.NewCommand(git.DefaultContext, "push", "--tags").RunInDir(dstPath) _, _, err = git.NewCommand(git.DefaultContext, "push", "--tags").RunStdString(&git.RunOpts{Dir: dstPath})
assert.Error(t, err) assert.Error(t, err)
assert.Contains(t, err.Error(), "Tag v-2 is protected") assert.Contains(t, err.Error(), "Tag v-2 is protected")
}) })

@ -83,17 +83,17 @@ func fixMergeBase(x *xorm.Engine) error {
if !pr.HasMerged { if !pr.HasMerged {
var err error var err error
pr.MergeBase, err = git.NewCommand(git.DefaultContext, "merge-base", "--", pr.BaseBranch, gitRefName).RunInDir(repoPath) pr.MergeBase, _, err = git.NewCommand(git.DefaultContext, "merge-base", "--", pr.BaseBranch, gitRefName).RunStdString(&git.RunOpts{Dir: repoPath})
if err != nil { if err != nil {
var err2 error var err2 error
pr.MergeBase, err2 = git.NewCommand(git.DefaultContext, "rev-parse", git.BranchPrefix+pr.BaseBranch).RunInDir(repoPath) pr.MergeBase, _, err2 = git.NewCommand(git.DefaultContext, "rev-parse", git.BranchPrefix+pr.BaseBranch).RunStdString(&git.RunOpts{Dir: repoPath})
if err2 != nil { if err2 != nil {
log.Error("Unable to get merge base for PR ID %d, Index %d in %s/%s. Error: %v & %v", pr.ID, pr.Index, baseRepo.OwnerName, baseRepo.Name, err, err2) log.Error("Unable to get merge base for PR ID %d, Index %d in %s/%s. Error: %v & %v", pr.ID, pr.Index, baseRepo.OwnerName, baseRepo.Name, err, err2)
continue continue
} }
} }
} else { } else {
parentsString, err := git.NewCommand(git.DefaultContext, "rev-list", "--parents", "-n", "1", pr.MergedCommitID).RunInDir(repoPath) parentsString, _, err := git.NewCommand(git.DefaultContext, "rev-list", "--parents", "-n", "1", pr.MergedCommitID).RunStdString(&git.RunOpts{Dir: repoPath})
if err != nil { if err != nil {
log.Error("Unable to get parents for merged PR ID %d, Index %d in %s/%s. Error: %v", pr.ID, pr.Index, baseRepo.OwnerName, baseRepo.Name, err) log.Error("Unable to get parents for merged PR ID %d, Index %d in %s/%s. Error: %v", pr.ID, pr.Index, baseRepo.OwnerName, baseRepo.Name, err)
continue continue
@ -106,7 +106,7 @@ func fixMergeBase(x *xorm.Engine) error {
args := append([]string{"merge-base", "--"}, parents[1:]...) args := append([]string{"merge-base", "--"}, parents[1:]...)
args = append(args, gitRefName) args = append(args, gitRefName)
pr.MergeBase, err = git.NewCommand(git.DefaultContext, args...).RunInDir(repoPath) pr.MergeBase, _, err = git.NewCommand(git.DefaultContext, args...).RunStdString(&git.RunOpts{Dir: repoPath})
if err != nil { if err != nil {
log.Error("Unable to get merge base for merged PR ID %d, Index %d in %s/%s. Error: %v", pr.ID, pr.Index, baseRepo.OwnerName, baseRepo.Name, err) log.Error("Unable to get merge base for merged PR ID %d, Index %d in %s/%s. Error: %v", pr.ID, pr.Index, baseRepo.OwnerName, baseRepo.Name, err)
continue continue

@ -80,7 +80,7 @@ func refixMergeBase(x *xorm.Engine) error {
gitRefName := fmt.Sprintf("refs/pull/%d/head", pr.Index) gitRefName := fmt.Sprintf("refs/pull/%d/head", pr.Index)
parentsString, err := git.NewCommand(git.DefaultContext, "rev-list", "--parents", "-n", "1", pr.MergedCommitID).RunInDir(repoPath) parentsString, _, err := git.NewCommand(git.DefaultContext, "rev-list", "--parents", "-n", "1", pr.MergedCommitID).RunStdString(&git.RunOpts{Dir: repoPath})
if err != nil { if err != nil {
log.Error("Unable to get parents for merged PR ID %d, Index %d in %s/%s. Error: %v", pr.ID, pr.Index, baseRepo.OwnerName, baseRepo.Name, err) log.Error("Unable to get parents for merged PR ID %d, Index %d in %s/%s. Error: %v", pr.ID, pr.Index, baseRepo.OwnerName, baseRepo.Name, err)
continue continue
@ -94,7 +94,7 @@ func refixMergeBase(x *xorm.Engine) error {
args := append([]string{"merge-base", "--"}, parents[1:]...) args := append([]string{"merge-base", "--"}, parents[1:]...)
args = append(args, gitRefName) args = append(args, gitRefName)
pr.MergeBase, err = git.NewCommand(git.DefaultContext, args...).RunInDir(repoPath) pr.MergeBase, _, err = git.NewCommand(git.DefaultContext, args...).RunStdString(&git.RunOpts{Dir: repoPath})
if err != nil { if err != nil {
log.Error("Unable to get merge base for merged PR ID %d, Index %d in %s/%s. Error: %v", pr.ID, pr.Index, baseRepo.OwnerName, baseRepo.Name, err) log.Error("Unable to get merge base for merged PR ID %d, Index %d in %s/%s. Error: %v", pr.ID, pr.Index, baseRepo.OwnerName, baseRepo.Name, err)
continue continue

@ -44,17 +44,17 @@ func checkPRMergeBase(ctx context.Context, logger log.Logger, autofix bool) erro
if !pr.HasMerged { if !pr.HasMerged {
var err error var err error
pr.MergeBase, err = git.NewCommand(ctx, "merge-base", "--", pr.BaseBranch, pr.GetGitRefName()).RunInDir(repoPath) pr.MergeBase, _, err = git.NewCommand(ctx, "merge-base", "--", pr.BaseBranch, pr.GetGitRefName()).RunStdString(&git.RunOpts{Dir: repoPath})
if err != nil { if err != nil {
var err2 error var err2 error
pr.MergeBase, err2 = git.NewCommand(ctx, "rev-parse", git.BranchPrefix+pr.BaseBranch).RunInDir(repoPath) pr.MergeBase, _, err2 = git.NewCommand(ctx, "rev-parse", git.BranchPrefix+pr.BaseBranch).RunStdString(&git.RunOpts{Dir: repoPath})
if err2 != nil { if err2 != nil {
logger.Warn("Unable to get merge base for PR ID %d, #%d onto %s in %s/%s. Error: %v & %v", pr.ID, pr.Index, pr.BaseBranch, pr.BaseRepo.OwnerName, pr.BaseRepo.Name, err, err2) logger.Warn("Unable to get merge base for PR ID %d, #%d onto %s in %s/%s. Error: %v & %v", pr.ID, pr.Index, pr.BaseBranch, pr.BaseRepo.OwnerName, pr.BaseRepo.Name, err, err2)
return nil return nil
} }
} }
} else { } else {
parentsString, err := git.NewCommand(ctx, "rev-list", "--parents", "-n", "1", pr.MergedCommitID).RunInDir(repoPath) parentsString, _, err := git.NewCommand(ctx, "rev-list", "--parents", "-n", "1", pr.MergedCommitID).RunStdString(&git.RunOpts{Dir: repoPath})
if err != nil { if err != nil {
logger.Warn("Unable to get parents for merged PR ID %d, #%d onto %s in %s/%s. Error: %v", pr.ID, pr.Index, pr.BaseBranch, pr.BaseRepo.OwnerName, pr.BaseRepo.Name, err) logger.Warn("Unable to get parents for merged PR ID %d, #%d onto %s in %s/%s. Error: %v", pr.ID, pr.Index, pr.BaseBranch, pr.BaseRepo.OwnerName, pr.BaseRepo.Name, err)
return nil return nil
@ -67,7 +67,7 @@ func checkPRMergeBase(ctx context.Context, logger log.Logger, autofix bool) erro
args := append([]string{"merge-base", "--"}, parents[1:]...) args := append([]string{"merge-base", "--"}, parents[1:]...)
args = append(args, pr.GetGitRefName()) args = append(args, pr.GetGitRefName())
pr.MergeBase, err = git.NewCommand(ctx, args...).RunInDir(repoPath) pr.MergeBase, _, err = git.NewCommand(ctx, args...).RunStdString(&git.RunOpts{Dir: repoPath})
if err != nil { if err != nil {
logger.Warn("Unable to get merge base for merged PR ID %d, #%d onto %s in %s/%s. Error: %v", pr.ID, pr.Index, pr.BaseBranch, pr.BaseRepo.OwnerName, pr.BaseRepo.Name, err) logger.Warn("Unable to get merge base for merged PR ID %d, #%d onto %s in %s/%s. Error: %v", pr.ID, pr.Index, pr.BaseBranch, pr.BaseRepo.OwnerName, pr.BaseRepo.Name, err)
return nil return nil

@ -95,11 +95,11 @@ func checkEnablePushOptions(ctx context.Context, logger log.Logger, autofix bool
defer r.Close() defer r.Close()
if autofix { if autofix {
_, err := git.NewCommand(ctx, "config", "receive.advertisePushOptions", "true").RunInDir(r.Path) _, _, err := git.NewCommand(ctx, "config", "receive.advertisePushOptions", "true").RunStdString(&git.RunOpts{Dir: r.Path})
return err return err
} }
value, err := git.NewCommand(ctx, "config", "receive.advertisePushOptions").RunInDir(r.Path) value, _, err := git.NewCommand(ctx, "config", "receive.advertisePushOptions").RunStdString(&git.RunOpts{Dir: r.Path})
if err != nil { if err != nil {
return err return err
} }

@ -34,10 +34,9 @@ func EnsureValidGitRepository(ctx context.Context, repoPath string) error {
stderr := strings.Builder{} stderr := strings.Builder{}
err := NewCommand(ctx, "rev-parse"). err := NewCommand(ctx, "rev-parse").
SetDescription(fmt.Sprintf("%s rev-parse [repo_path: %s]", GitExecutable, repoPath)). SetDescription(fmt.Sprintf("%s rev-parse [repo_path: %s]", GitExecutable, repoPath)).
RunWithContext(&RunContext{ Run(&RunOpts{
Timeout: -1, Dir: repoPath,
Dir: repoPath, Stderr: &stderr,
Stderr: &stderr,
}) })
if err != nil { if err != nil {
return ConcatenateError(err, (&stderr).String()) return ConcatenateError(err, (&stderr).String())
@ -65,12 +64,11 @@ func CatFileBatchCheck(ctx context.Context, repoPath string) (WriteCloserError,
stderr := strings.Builder{} stderr := strings.Builder{}
err := NewCommand(ctx, "cat-file", "--batch-check"). err := NewCommand(ctx, "cat-file", "--batch-check").
SetDescription(fmt.Sprintf("%s cat-file --batch-check [repo_path: %s] (%s:%d)", GitExecutable, repoPath, filename, line)). SetDescription(fmt.Sprintf("%s cat-file --batch-check [repo_path: %s] (%s:%d)", GitExecutable, repoPath, filename, line)).
RunWithContext(&RunContext{ Run(&RunOpts{
Timeout: -1, Dir: repoPath,
Dir: repoPath, Stdin: batchStdinReader,
Stdin: batchStdinReader, Stdout: batchStdoutWriter,
Stdout: batchStdoutWriter, Stderr: &stderr,
Stderr: &stderr,
}) })
if err != nil { if err != nil {
_ = batchStdoutWriter.CloseWithError(ConcatenateError(err, (&stderr).String())) _ = batchStdoutWriter.CloseWithError(ConcatenateError(err, (&stderr).String()))
@ -110,12 +108,11 @@ func CatFileBatch(ctx context.Context, repoPath string) (WriteCloserError, *bufi
stderr := strings.Builder{} stderr := strings.Builder{}
err := NewCommand(ctx, "cat-file", "--batch"). err := NewCommand(ctx, "cat-file", "--batch").
SetDescription(fmt.Sprintf("%s cat-file --batch [repo_path: %s] (%s:%d)", GitExecutable, repoPath, filename, line)). SetDescription(fmt.Sprintf("%s cat-file --batch [repo_path: %s] (%s:%d)", GitExecutable, repoPath, filename, line)).
RunWithContext(&RunContext{ Run(&RunOpts{
Timeout: -1, Dir: repoPath,
Dir: repoPath, Stdin: batchStdinReader,
Stdin: batchStdinReader, Stdout: batchStdoutWriter,
Stdout: batchStdoutWriter, Stderr: &stderr,
Stderr: &stderr,
}) })
if err != nil { if err != nil {
_ = batchStdoutWriter.CloseWithError(ConcatenateError(err, (&stderr).String())) _ = batchStdoutWriter.CloseWithError(ConcatenateError(err, (&stderr).String()))

@ -94,8 +94,8 @@ func (c *Command) AddArguments(args ...string) *Command {
return c return c
} }
// RunContext represents parameters to run the command // RunOpts represents parameters to run the command
type RunContext struct { type RunOpts struct {
Env []string Env []string
Timeout time.Duration Timeout time.Duration
Dir string Dir string
@ -104,16 +104,19 @@ type RunContext struct {
PipelineFunc func(context.Context, context.CancelFunc) error PipelineFunc func(context.Context, context.CancelFunc) error
} }
// RunWithContext run the command with context // Run runs the command with the RunOpts
func (c *Command) RunWithContext(rc *RunContext) error { func (c *Command) Run(opts *RunOpts) error {
if rc.Timeout <= 0 { if opts == nil {
rc.Timeout = defaultCommandExecutionTimeout opts = &RunOpts{}
}
if opts.Timeout <= 0 {
opts.Timeout = defaultCommandExecutionTimeout
} }
if len(rc.Dir) == 0 { if len(opts.Dir) == 0 {
log.Debug("%s", c) log.Debug("%s", c)
} else { } else {
log.Debug("%s: %v", rc.Dir, c) log.Debug("%s: %v", opts.Dir, c)
} }
desc := c.desc desc := c.desc
@ -132,17 +135,17 @@ func (c *Command) RunWithContext(rc *RunContext) error {
args[urlArgIndex] = util.SanitizeCredentialURLs(args[urlArgIndex]) args[urlArgIndex] = util.SanitizeCredentialURLs(args[urlArgIndex])
} }
} }
desc = fmt.Sprintf("%s %s [repo_path: %s]", c.name, strings.Join(args, " "), rc.Dir) desc = fmt.Sprintf("%s %s [repo_path: %s]", c.name, strings.Join(args, " "), opts.Dir)
} }
ctx, cancel, finished := process.GetManager().AddContextTimeout(c.parentContext, rc.Timeout, desc) ctx, cancel, finished := process.GetManager().AddContextTimeout(c.parentContext, opts.Timeout, desc)
defer finished() defer finished()
cmd := exec.CommandContext(ctx, c.name, c.args...) cmd := exec.CommandContext(ctx, c.name, c.args...)
if rc.Env == nil { if opts.Env == nil {
cmd.Env = os.Environ() cmd.Env = os.Environ()
} else { } else {
cmd.Env = rc.Env cmd.Env = opts.Env
} }
cmd.Env = append( cmd.Env = append(
@ -154,16 +157,16 @@ func (c *Command) RunWithContext(rc *RunContext) error {
"GIT_NO_REPLACE_OBJECTS=1", "GIT_NO_REPLACE_OBJECTS=1",
) )
cmd.Dir = rc.Dir cmd.Dir = opts.Dir
cmd.Stdout = rc.Stdout cmd.Stdout = opts.Stdout
cmd.Stderr = rc.Stderr cmd.Stderr = opts.Stderr
cmd.Stdin = rc.Stdin cmd.Stdin = opts.Stdin
if err := cmd.Start(); err != nil { if err := cmd.Start(); err != nil {
return err return err
} }
if rc.PipelineFunc != nil { if opts.PipelineFunc != nil {
err := rc.PipelineFunc(ctx, cancel) err := opts.PipelineFunc(ctx, cancel)
if err != nil { if err != nil {
cancel() cancel()
_ = cmd.Wait() _ = cmd.Wait()
@ -178,18 +181,18 @@ func (c *Command) RunWithContext(rc *RunContext) error {
return ctx.Err() return ctx.Err()
} }
type RunError interface { type RunStdError interface {
error error
Stderr() string Stderr() string
} }
type runError struct { type runStdError struct {
err error err error
stderr string stderr string
errMsg string errMsg string
} }
func (r *runError) Error() string { func (r *runStdError) Error() string {
// the stderr must be in the returned error text, some code only checks `strings.Contains(err.Error(), "git error")` // the stderr must be in the returned error text, some code only checks `strings.Contains(err.Error(), "git error")`
if r.errMsg == "" { if r.errMsg == "" {
r.errMsg = ConcatenateError(r.err, r.stderr).Error() r.errMsg = ConcatenateError(r.err, r.stderr).Error()
@ -197,11 +200,11 @@ func (r *runError) Error() string {
return r.errMsg return r.errMsg
} }
func (r *runError) Unwrap() error { func (r *runStdError) Unwrap() error {
return r.err return r.err
} }
func (r *runError) Stderr() string { func (r *runStdError) Stderr() string {
return r.stderr return r.stderr
} }
@ -209,64 +212,40 @@ func bytesToString(b []byte) string {
return *(*string)(unsafe.Pointer(&b)) // that's what Golang's strings.Builder.String() does (go/src/strings/builder.go) return *(*string)(unsafe.Pointer(&b)) // that's what Golang's strings.Builder.String() does (go/src/strings/builder.go)
} }
// RunWithContextString run the command with context and returns stdout/stderr as string. and store stderr to returned error (err combined with stderr). // RunStdString runs the command with options and returns stdout/stderr as string. and store stderr to returned error (err combined with stderr).
func (c *Command) RunWithContextString(rc *RunContext) (stdout, stderr string, runErr RunError) { func (c *Command) RunStdString(opts *RunOpts) (stdout, stderr string, runErr RunStdError) {
stdoutBytes, stderrBytes, err := c.RunWithContextBytes(rc) stdoutBytes, stderrBytes, err := c.RunStdBytes(opts)
stdout = bytesToString(stdoutBytes) stdout = bytesToString(stdoutBytes)
stderr = bytesToString(stderrBytes) stderr = bytesToString(stderrBytes)
if err != nil { if err != nil {
return stdout, stderr, &runError{err: err, stderr: stderr} return stdout, stderr, &runStdError{err: err, stderr: stderr}
} }
// even if there is no err, there could still be some stderr output, so we just return stdout/stderr as they are // even if there is no err, there could still be some stderr output, so we just return stdout/stderr as they are
return stdout, stderr, nil return stdout, stderr, nil
} }
// RunWithContextBytes run the command with context and returns stdout/stderr as bytes. and store stderr to returned error (err combined with stderr). // RunStdBytes runs the command with options and returns stdout/stderr as bytes. and store stderr to returned error (err combined with stderr).
func (c *Command) RunWithContextBytes(rc *RunContext) (stdout, stderr []byte, runErr RunError) { func (c *Command) RunStdBytes(opts *RunOpts) (stdout, stderr []byte, runErr RunStdError) {
if rc.Stdout != nil || rc.Stderr != nil { if opts == nil {
opts = &RunOpts{}
}
if opts.Stdout != nil || opts.Stderr != nil {
// we must panic here, otherwise there would be bugs if developers set Stdin/Stderr by mistake, and it would be very difficult to debug // we must panic here, otherwise there would be bugs if developers set Stdin/Stderr by mistake, and it would be very difficult to debug
panic("stdout and stderr field must be nil when using RunWithContextBytes") panic("stdout and stderr field must be nil when using RunStdBytes")
} }
stdoutBuf := &bytes.Buffer{} stdoutBuf := &bytes.Buffer{}
stderrBuf := &bytes.Buffer{} stderrBuf := &bytes.Buffer{}
rc.Stdout = stdoutBuf opts.Stdout = stdoutBuf
rc.Stderr = stderrBuf opts.Stderr = stderrBuf
err := c.RunWithContext(rc) err := c.Run(opts)
stderr = stderrBuf.Bytes() stderr = stderrBuf.Bytes()
if err != nil { if err != nil {
return nil, stderr, &runError{err: err, stderr: string(stderr)} return nil, stderr, &runStdError{err: err, stderr: bytesToString(stderr)}
} }
// even if there is no err, there could still be some stderr output // even if there is no err, there could still be some stderr output
return stdoutBuf.Bytes(), stderr, nil return stdoutBuf.Bytes(), stderr, nil
} }
// RunInDirBytes executes the command in given directory
// and returns stdout in []byte and error (combined with stderr).
func (c *Command) RunInDirBytes(dir string) ([]byte, error) {
stdout, _, err := c.RunWithContextBytes(&RunContext{Dir: dir})
return stdout, err
}
// RunInDir executes the command in given directory
// and returns stdout in string and error (combined with stderr).
func (c *Command) RunInDir(dir string) (string, error) {
return c.RunInDirWithEnv(dir, nil)
}
// RunInDirWithEnv executes the command in given directory
// and returns stdout in string and error (combined with stderr).
func (c *Command) RunInDirWithEnv(dir string, env []string) (string, error) {
stdout, _, err := c.RunWithContextString(&RunContext{Env: env, Dir: dir})
return stdout, err
}
// Run executes the command in default working directory
// and returns stdout in string and error (combined with stderr).
func (c *Command) Run() (string, error) {
stdout, _, err := c.RunWithContextString(&RunContext{})
return stdout, err
}
// AllowLFSFiltersArgs return globalCommandArgs with lfs filter, it should only be used for tests // AllowLFSFiltersArgs return globalCommandArgs with lfs filter, it should only be used for tests
func AllowLFSFiltersArgs() []string { func AllowLFSFiltersArgs() []string {
// Now here we should explicitly allow lfs filters to run // Now here we should explicitly allow lfs filters to run

@ -19,7 +19,7 @@ func TestRunWithContextNoTimeout(t *testing.T) {
// 'git --version' does not block so it must be finished before the timeout triggered. // 'git --version' does not block so it must be finished before the timeout triggered.
cmd := NewCommand(context.Background(), "--version") cmd := NewCommand(context.Background(), "--version")
for i := 0; i < maxLoops; i++ { for i := 0; i < maxLoops; i++ {
if err := cmd.RunWithContext(&RunContext{}); err != nil { if err := cmd.Run(&RunOpts{}); err != nil {
t.Fatal(err) t.Fatal(err)
} }
} }
@ -31,7 +31,7 @@ func TestRunWithContextTimeout(t *testing.T) {
// 'git hash-object --stdin' blocks on stdin so we can have the timeout triggered. // 'git hash-object --stdin' blocks on stdin so we can have the timeout triggered.
cmd := NewCommand(context.Background(), "hash-object", "--stdin") cmd := NewCommand(context.Background(), "hash-object", "--stdin")
for i := 0; i < maxLoops; i++ { for i := 0; i < maxLoops; i++ {
if err := cmd.RunWithContext(&RunContext{Timeout: 1 * time.Millisecond}); err != nil { if err := cmd.Run(&RunOpts{Timeout: 1 * time.Millisecond}); err != nil {
if err != context.DeadlineExceeded { if err != context.DeadlineExceeded {
t.Fatalf("Testing %d/%d: %v", i, maxLoops, err) t.Fatalf("Testing %d/%d: %v", i, maxLoops, err)
} }

@ -13,13 +13,13 @@ import (
func TestRunWithContextStd(t *testing.T) { func TestRunWithContextStd(t *testing.T) {
cmd := NewCommand(context.Background(), "--version") cmd := NewCommand(context.Background(), "--version")
stdout, stderr, err := cmd.RunWithContextString(&RunContext{}) stdout, stderr, err := cmd.RunStdString(&RunOpts{})
assert.NoError(t, err) assert.NoError(t, err)
assert.Empty(t, stderr) assert.Empty(t, stderr)
assert.Contains(t, stdout, "git version") assert.Contains(t, stdout, "git version")
cmd = NewCommand(context.Background(), "--no-such-arg") cmd = NewCommand(context.Background(), "--no-such-arg")
stdout, stderr, err = cmd.RunWithContextString(&RunContext{}) stdout, stderr, err = cmd.RunStdString(&RunOpts{})
if assert.Error(t, err) { if assert.Error(t, err) {
assert.Equal(t, stderr, err.Stderr()) assert.Equal(t, stderr, err.Stderr())
assert.Contains(t, err.Stderr(), "unknown option:") assert.Contains(t, err.Stderr(), "unknown option:")

@ -94,7 +94,7 @@ func AddChangesWithArgs(repoPath string, globalArgs []string, all bool, files ..
cmd.AddArguments("--all") cmd.AddArguments("--all")
} }
cmd.AddArguments("--") cmd.AddArguments("--")
_, err := cmd.AddArguments(files...).RunInDir(repoPath) _, _, err := cmd.AddArguments(files...).RunStdString(&RunOpts{Dir: repoPath})
return err return err
} }
@ -130,7 +130,7 @@ func CommitChangesWithArgs(repoPath string, args []string, opts CommitChangesOpt
} }
cmd.AddArguments("-m", opts.Message) cmd.AddArguments("-m", opts.Message)
_, err := cmd.RunInDir(repoPath) _, _, err := cmd.RunStdString(&RunOpts{Dir: repoPath})
// No stderr but exit status 1 means nothing to commit. // No stderr but exit status 1 means nothing to commit.
if err != nil && err.Error() == "exit status 1" { if err != nil && err.Error() == "exit status 1" {
return nil return nil
@ -151,7 +151,7 @@ func AllCommitsCount(ctx context.Context, repoPath string, hidePRRefs bool, file
cmd.AddArguments(files...) cmd.AddArguments(files...)
} }
stdout, err := cmd.RunInDir(repoPath) stdout, _, err := cmd.RunStdString(&RunOpts{Dir: repoPath})
if err != nil { if err != nil {
return 0, err return 0, err
} }
@ -168,7 +168,7 @@ func CommitsCountFiles(ctx context.Context, repoPath string, revision, relpath [
cmd.AddArguments(relpath...) cmd.AddArguments(relpath...)
} }
stdout, err := cmd.RunInDir(repoPath) stdout, _, err := cmd.RunStdString(&RunOpts{Dir: repoPath})
if err != nil { if err != nil {
return 0, err return 0, err
} }
@ -206,7 +206,7 @@ func (c *Commit) HasPreviousCommit(commitHash SHA1) (bool, error) {
} }
if err := CheckGitVersionAtLeast("1.8"); err == nil { if err := CheckGitVersionAtLeast("1.8"); err == nil {
_, err := NewCommand(c.repo.Ctx, "merge-base", "--is-ancestor", that, this).RunInDir(c.repo.Path) _, _, err := NewCommand(c.repo.Ctx, "merge-base", "--is-ancestor", that, this).RunStdString(&RunOpts{Dir: c.repo.Path})
if err == nil { if err == nil {
return true, nil return true, nil
} }
@ -219,7 +219,7 @@ func (c *Commit) HasPreviousCommit(commitHash SHA1) (bool, error) {
return false, err return false, err
} }
result, err := NewCommand(c.repo.Ctx, "rev-list", "--ancestry-path", "-n1", that+".."+this, "--").RunInDir(c.repo.Path) result, _, err := NewCommand(c.repo.Ctx, "rev-list", "--ancestry-path", "-n1", that+".."+this, "--").RunStdString(&RunOpts{Dir: c.repo.Path})
if err != nil { if err != nil {
return false, err return false, err
} }
@ -381,7 +381,7 @@ func (c *Commit) GetBranchName() (string, error) {
} }
args = append(args, "--name-only", "--no-undefined", c.ID.String()) args = append(args, "--name-only", "--no-undefined", c.ID.String())
data, err := NewCommand(c.repo.Ctx, args...).RunInDir(c.repo.Path) data, _, err := NewCommand(c.repo.Ctx, args...).RunStdString(&RunOpts{Dir: c.repo.Path})
if err != nil { if err != nil {
// handle special case where git can not describe commit // handle special case where git can not describe commit
if strings.Contains(err.Error(), "cannot describe") { if strings.Contains(err.Error(), "cannot describe") {
@ -407,7 +407,7 @@ func (c *Commit) LoadBranchName() (err error) {
// GetTagName gets the current tag name for given commit // GetTagName gets the current tag name for given commit
func (c *Commit) GetTagName() (string, error) { func (c *Commit) GetTagName() (string, error) {
data, err := NewCommand(c.repo.Ctx, "describe", "--exact-match", "--tags", "--always", c.ID.String()).RunInDir(c.repo.Path) data, _, err := NewCommand(c.repo.Ctx, "describe", "--exact-match", "--tags", "--always", c.ID.String()).RunStdString(&RunOpts{Dir: c.repo.Path})
if err != nil { if err != nil {
// handle special case where there is no tag for this commit // handle special case where there is no tag for this commit
if strings.Contains(err.Error(), "no tag exactly matches") { if strings.Contains(err.Error(), "no tag exactly matches") {
@ -486,11 +486,10 @@ func GetCommitFileStatus(ctx context.Context, repoPath, commitID string) (*Commi
stderr := new(bytes.Buffer) stderr := new(bytes.Buffer)
args := []string{"log", "--name-status", "-c", "--pretty=format:", "--parents", "--no-renames", "-z", "-1", commitID} args := []string{"log", "--name-status", "-c", "--pretty=format:", "--parents", "--no-renames", "-z", "-1", commitID}
err := NewCommand(ctx, args...).RunWithContext(&RunContext{ err := NewCommand(ctx, args...).Run(&RunOpts{
Timeout: -1, Dir: repoPath,
Dir: repoPath, Stdout: w,
Stdout: w, Stderr: stderr,
Stderr: stderr,
}) })
w.Close() // Close writer to exit parsing goroutine w.Close() // Close writer to exit parsing goroutine
if err != nil { if err != nil {
@ -503,7 +502,7 @@ func GetCommitFileStatus(ctx context.Context, repoPath, commitID string) (*Commi
// GetFullCommitID returns full length (40) of commit ID by given short SHA in a repository. // GetFullCommitID returns full length (40) of commit ID by given short SHA in a repository.
func GetFullCommitID(ctx context.Context, repoPath, shortID string) (string, error) { func GetFullCommitID(ctx context.Context, repoPath, shortID string) (string, error) {
commitID, err := NewCommand(ctx, "rev-parse", shortID).RunInDir(repoPath) commitID, _, err := NewCommand(ctx, "rev-parse", shortID).RunStdString(&RunOpts{Dir: repoPath})
if err != nil { if err != nil {
if strings.Contains(err.Error(), "exit status 128") { if strings.Contains(err.Error(), "exit status 128") {
return "", ErrNotExist{shortID, ""} return "", ErrNotExist{shortID, ""}

@ -36,11 +36,10 @@ func GetRawDiff(ctx context.Context, repoPath, commitID string, diffType RawDiff
func GetReverseRawDiff(ctx context.Context, repoPath, commitID string, writer io.Writer) error { func GetReverseRawDiff(ctx context.Context, repoPath, commitID string, writer io.Writer) error {
stderr := new(bytes.Buffer) stderr := new(bytes.Buffer)
cmd := NewCommand(ctx, "show", "--pretty=format:revert %H%n", "-R", commitID) cmd := NewCommand(ctx, "show", "--pretty=format:revert %H%n", "-R", commitID)
if err := cmd.RunWithContext(&RunContext{ if err := cmd.Run(&RunOpts{
Timeout: -1, Dir: repoPath,
Dir: repoPath, Stdout: writer,
Stdout: writer, Stderr: stderr,
Stderr: stderr,
}); err != nil { }); err != nil {
return fmt.Errorf("Run: %v - %s", err, stderr) return fmt.Errorf("Run: %v - %s", err, stderr)
} }
@ -97,11 +96,10 @@ func GetRepoRawDiffForFile(repo *Repository, startCommit, endCommit string, diff
stderr := new(bytes.Buffer) stderr := new(bytes.Buffer)
cmd := NewCommand(repo.Ctx, args...) cmd := NewCommand(repo.Ctx, args...)
if err = cmd.RunWithContext(&RunContext{ if err = cmd.Run(&RunOpts{
Timeout: -1, Dir: repo.Path,
Dir: repo.Path, Stdout: writer,
Stdout: writer, Stderr: stderr,
Stderr: stderr,
}); err != nil { }); err != nil {
return fmt.Errorf("Run: %v - %s", err, stderr) return fmt.Errorf("Run: %v - %s", err, stderr)
} }
@ -301,11 +299,10 @@ func GetAffectedFiles(repo *Repository, oldCommitID, newCommitID string, env []s
// Run `git diff --name-only` to get the names of the changed files // Run `git diff --name-only` to get the names of the changed files
err = NewCommand(repo.Ctx, "diff", "--name-only", oldCommitID, newCommitID). err = NewCommand(repo.Ctx, "diff", "--name-only", oldCommitID, newCommitID).
RunWithContext(&RunContext{ Run(&RunOpts{
Env: env, Env: env,
Timeout: -1, Dir: repo.Path,
Dir: repo.Path, Stdout: stdoutWriter,
Stdout: stdoutWriter,
PipelineFunc: func(ctx context.Context, cancel context.CancelFunc) error { PipelineFunc: func(ctx context.Context, cancel context.CancelFunc) error {
// Close the writer end of the pipe to begin processing // Close the writer end of the pipe to begin processing
_ = stdoutWriter.Close() _ = stdoutWriter.Close()

@ -54,9 +54,9 @@ func LoadGitVersion() error {
return nil return nil
} }
stdout, err := NewCommand(context.Background(), "version").Run() stdout, _, runErr := NewCommand(context.Background(), "version").RunStdString(nil)
if err != nil { if runErr != nil {
return err return runErr
} }
fields := strings.Fields(stdout) fields := strings.Fields(stdout)
@ -74,6 +74,7 @@ func LoadGitVersion() error {
versionString = fields[2] versionString = fields[2]
} }
var err error
gitVersion, err = version.NewVersion(versionString) gitVersion, err = version.NewVersion(versionString)
return err return err
} }
@ -297,5 +298,5 @@ func checkAndRemoveConfig(key, value string) error {
// Fsck verifies the connectivity and validity of the objects in the database // Fsck verifies the connectivity and validity of the objects in the database
func Fsck(ctx context.Context, repoPath string, timeout time.Duration, args ...string) error { func Fsck(ctx context.Context, repoPath string, timeout time.Duration, args ...string) error {
return NewCommand(ctx, "fsck").AddArguments(args...).RunWithContext(&RunContext{Timeout: timeout, Dir: repoPath}) return NewCommand(ctx, "fsck").AddArguments(args...).Run(&RunOpts{Timeout: timeout, Dir: repoPath})
} }

@ -55,11 +55,10 @@ func LogNameStatusRepo(ctx context.Context, repository, head, treepath string, p
go func() { go func() {
stderr := strings.Builder{} stderr := strings.Builder{}
err := NewCommand(ctx, args...).RunWithContext(&RunContext{ err := NewCommand(ctx, args...).Run(&RunOpts{
Timeout: -1, Dir: repository,
Dir: repository, Stdout: stdoutWriter,
Stdout: stdoutWriter, Stderr: &stderr,
Stderr: &stderr,
}) })
if err != nil { if err != nil {
_ = stdoutWriter.CloseWithError(ConcatenateError(err, (&stderr).String())) _ = stdoutWriter.CloseWithError(ConcatenateError(err, (&stderr).String()))

@ -27,12 +27,11 @@ func CatFileBatchCheck(ctx context.Context, shasToCheckReader *io.PipeReader, ca
stderr := new(bytes.Buffer) stderr := new(bytes.Buffer)
var errbuf strings.Builder var errbuf strings.Builder
cmd := git.NewCommand(ctx, "cat-file", "--batch-check") cmd := git.NewCommand(ctx, "cat-file", "--batch-check")
if err := cmd.RunWithContext(&git.RunContext{ if err := cmd.Run(&git.RunOpts{
Timeout: -1, Dir: tmpBasePath,
Dir: tmpBasePath, Stdin: shasToCheckReader,
Stdin: shasToCheckReader, Stdout: catFileCheckWriter,
Stdout: catFileCheckWriter, Stderr: stderr,
Stderr: stderr,
}); err != nil { }); err != nil {
_ = catFileCheckWriter.CloseWithError(fmt.Errorf("git cat-file --batch-check [%s]: %v - %s", tmpBasePath, err, errbuf.String())) _ = catFileCheckWriter.CloseWithError(fmt.Errorf("git cat-file --batch-check [%s]: %v - %s", tmpBasePath, err, errbuf.String()))
} }
@ -46,11 +45,10 @@ func CatFileBatchCheckAllObjects(ctx context.Context, catFileCheckWriter *io.Pip
stderr := new(bytes.Buffer) stderr := new(bytes.Buffer)
var errbuf strings.Builder var errbuf strings.Builder
cmd := git.NewCommand(ctx, "cat-file", "--batch-check", "--batch-all-objects") cmd := git.NewCommand(ctx, "cat-file", "--batch-check", "--batch-all-objects")
if err := cmd.RunWithContext(&git.RunContext{ if err := cmd.Run(&git.RunOpts{
Timeout: -1, Dir: tmpBasePath,
Dir: tmpBasePath, Stdout: catFileCheckWriter,
Stdout: catFileCheckWriter, Stderr: stderr,
Stderr: stderr,
}); err != nil { }); err != nil {
log.Error("git cat-file --batch-check --batch-all-object [%s]: %v - %s", tmpBasePath, err, errbuf.String()) log.Error("git cat-file --batch-check --batch-all-object [%s]: %v - %s", tmpBasePath, err, errbuf.String())
err = fmt.Errorf("git cat-file --batch-check --batch-all-object [%s]: %v - %s", tmpBasePath, err, errbuf.String()) err = fmt.Errorf("git cat-file --batch-check --batch-all-object [%s]: %v - %s", tmpBasePath, err, errbuf.String())
@ -67,12 +65,11 @@ func CatFileBatch(ctx context.Context, shasToBatchReader *io.PipeReader, catFile
stderr := new(bytes.Buffer) stderr := new(bytes.Buffer)
var errbuf strings.Builder var errbuf strings.Builder
if err := git.NewCommand(ctx, "cat-file", "--batch").RunWithContext(&git.RunContext{ if err := git.NewCommand(ctx, "cat-file", "--batch").Run(&git.RunOpts{
Timeout: -1, Dir: tmpBasePath,
Dir: tmpBasePath, Stdout: catFileBatchWriter,
Stdout: catFileBatchWriter, Stdin: shasToBatchReader,
Stdin: shasToBatchReader, Stderr: stderr,
Stderr: stderr,
}); err != nil { }); err != nil {
_ = shasToBatchReader.CloseWithError(fmt.Errorf("git rev-list [%s]: %v - %s", tmpBasePath, err, errbuf.String())) _ = shasToBatchReader.CloseWithError(fmt.Errorf("git rev-list [%s]: %v - %s", tmpBasePath, err, errbuf.String()))
} }

@ -53,11 +53,10 @@ func FindLFSFile(repo *git.Repository, hash git.SHA1) ([]*LFSResult, error) {
go func() { go func() {
stderr := strings.Builder{} stderr := strings.Builder{}
err := git.NewCommand(repo.Ctx, "rev-list", "--all").RunWithContext(&git.RunContext{ err := git.NewCommand(repo.Ctx, "rev-list", "--all").Run(&git.RunOpts{
Timeout: -1, Dir: repo.Path,
Dir: repo.Path, Stdout: revListWriter,
Stdout: revListWriter, Stderr: &stderr,
Stderr: &stderr,
}) })
if err != nil { if err != nil {
_ = revListWriter.CloseWithError(git.ConcatenateError(err, (&stderr).String())) _ = revListWriter.CloseWithError(git.ConcatenateError(err, (&stderr).String()))

@ -23,12 +23,11 @@ func NameRevStdin(ctx context.Context, shasToNameReader *io.PipeReader, nameRevS
stderr := new(bytes.Buffer) stderr := new(bytes.Buffer)
var errbuf strings.Builder var errbuf strings.Builder
if err := git.NewCommand(ctx, "name-rev", "--stdin", "--name-only", "--always").RunWithContext(&git.RunContext{ if err := git.NewCommand(ctx, "name-rev", "--stdin", "--name-only", "--always").Run(&git.RunOpts{
Timeout: -1, Dir: tmpBasePath,
Dir: tmpBasePath, Stdout: nameRevStdinWriter,
Stdout: nameRevStdinWriter, Stdin: shasToNameReader,
Stdin: shasToNameReader, Stderr: stderr,
Stderr: stderr,
}); err != nil { }); err != nil {
_ = shasToNameReader.CloseWithError(fmt.Errorf("git name-rev [%s]: %v - %s", tmpBasePath, err, errbuf.String())) _ = shasToNameReader.CloseWithError(fmt.Errorf("git name-rev [%s]: %v - %s", tmpBasePath, err, errbuf.String()))
} }

@ -25,11 +25,10 @@ func RevListAllObjects(ctx context.Context, revListWriter *io.PipeWriter, wg *sy
stderr := new(bytes.Buffer) stderr := new(bytes.Buffer)
var errbuf strings.Builder var errbuf strings.Builder
cmd := git.NewCommand(ctx, "rev-list", "--objects", "--all") cmd := git.NewCommand(ctx, "rev-list", "--objects", "--all")
if err := cmd.RunWithContext(&git.RunContext{ if err := cmd.Run(&git.RunOpts{
Timeout: -1, Dir: basePath,
Dir: basePath, Stdout: revListWriter,
Stdout: revListWriter, Stderr: stderr,
Stderr: stderr,
}); err != nil { }); err != nil {
log.Error("git rev-list --objects --all [%s]: %v - %s", basePath, err, errbuf.String()) log.Error("git rev-list --objects --all [%s]: %v - %s", basePath, err, errbuf.String())
err = fmt.Errorf("git rev-list --objects --all [%s]: %v - %s", basePath, err, errbuf.String()) err = fmt.Errorf("git rev-list --objects --all [%s]: %v - %s", basePath, err, errbuf.String())
@ -45,11 +44,10 @@ func RevListObjects(ctx context.Context, revListWriter *io.PipeWriter, wg *sync.
stderr := new(bytes.Buffer) stderr := new(bytes.Buffer)
var errbuf strings.Builder var errbuf strings.Builder
cmd := git.NewCommand(ctx, "rev-list", "--objects", headSHA, "--not", baseSHA) cmd := git.NewCommand(ctx, "rev-list", "--objects", headSHA, "--not", baseSHA)
if err := cmd.RunWithContext(&git.RunContext{ if err := cmd.Run(&git.RunOpts{
Timeout: -1, Dir: tmpBasePath,
Dir: tmpBasePath, Stdout: revListWriter,
Stdout: revListWriter, Stderr: stderr,
Stderr: stderr,
}); err != nil { }); err != nil {
log.Error("git rev-list [%s]: %v - %s", tmpBasePath, err, errbuf.String()) log.Error("git rev-list [%s]: %v - %s", tmpBasePath, err, errbuf.String())
errChan <- fmt.Errorf("git rev-list [%s]: %v - %s", tmpBasePath, err, errbuf.String()) errChan <- fmt.Errorf("git rev-list [%s]: %v - %s", tmpBasePath, err, errbuf.String())

@ -22,7 +22,7 @@ func GetRemoteAddress(ctx context.Context, repoPath, remoteName string) (*url.UR
cmd = NewCommand(ctx, "config", "--get", "remote."+remoteName+".url") cmd = NewCommand(ctx, "config", "--get", "remote."+remoteName+".url")
} }
result, err := cmd.RunInDir(repoPath) result, _, err := cmd.RunStdString(&RunOpts{Dir: repoPath})
if err != nil { if err != nil {
return nil, err return nil, err
} }

@ -59,7 +59,7 @@ func (repo *Repository) parsePrettyFormatLogToList(logs []byte) ([]*Commit, erro
// IsRepoURLAccessible checks if given repository URL is accessible. // IsRepoURLAccessible checks if given repository URL is accessible.
func IsRepoURLAccessible(ctx context.Context, url string) bool { func IsRepoURLAccessible(ctx context.Context, url string) bool {
_, err := NewCommand(ctx, "ls-remote", "-q", "-h", url, "HEAD").Run() _, _, err := NewCommand(ctx, "ls-remote", "-q", "-h", url, "HEAD").RunStdString(nil)
return err == nil return err == nil
} }
@ -74,7 +74,7 @@ func InitRepository(ctx context.Context, repoPath string, bare bool) error {
if bare { if bare {
cmd.AddArguments("--bare") cmd.AddArguments("--bare")
} }
_, err = cmd.RunInDir(repoPath) _, _, err = cmd.RunStdString(&RunOpts{Dir: repoPath})
return err return err
} }
@ -82,11 +82,10 @@ func InitRepository(ctx context.Context, repoPath string, bare bool) error {
func (repo *Repository) IsEmpty() (bool, error) { func (repo *Repository) IsEmpty() (bool, error) {
var errbuf, output strings.Builder var errbuf, output strings.Builder
if err := NewCommand(repo.Ctx, "show-ref", "--head", "^HEAD$"). if err := NewCommand(repo.Ctx, "show-ref", "--head", "^HEAD$").
RunWithContext(&RunContext{ Run(&RunOpts{
Timeout: -1, Dir: repo.Path,
Dir: repo.Path, Stdout: &output,
Stdout: &output, Stderr: &errbuf,
Stderr: &errbuf,
}); err != nil { }); err != nil {
if err.Error() == "exit status 1" && errbuf.String() == "" { if err.Error() == "exit status 1" && errbuf.String() == "" {
return true, nil return true, nil
@ -174,7 +173,7 @@ func CloneWithArgs(ctx context.Context, from, to string, args []string, opts Clo
} }
stderr := new(bytes.Buffer) stderr := new(bytes.Buffer)
if err = cmd.RunWithContext(&RunContext{ if err = cmd.Run(&RunOpts{
Timeout: opts.Timeout, Timeout: opts.Timeout,
Env: envs, Env: envs,
Stdout: io.Discard, Stdout: io.Discard,
@ -219,7 +218,7 @@ func Push(ctx context.Context, repoPath string, opts PushOptions) error {
opts.Timeout = -1 opts.Timeout = -1
} }
err := cmd.RunWithContext(&RunContext{ err := cmd.Run(&RunOpts{
Env: opts.Env, Env: opts.Env,
Timeout: opts.Timeout, Timeout: opts.Timeout,
Dir: repoPath, Dir: repoPath,
@ -261,7 +260,7 @@ func Push(ctx context.Context, repoPath string, opts PushOptions) error {
// GetLatestCommitTime returns time for latest commit in repository (across all branches) // GetLatestCommitTime returns time for latest commit in repository (across all branches)
func GetLatestCommitTime(ctx context.Context, repoPath string) (time.Time, error) { func GetLatestCommitTime(ctx context.Context, repoPath string) (time.Time, error) {
cmd := NewCommand(ctx, "for-each-ref", "--sort=-committerdate", BranchPrefix, "--count", "1", "--format=%(committerdate)") cmd := NewCommand(ctx, "for-each-ref", "--sort=-committerdate", BranchPrefix, "--count", "1", "--format=%(committerdate)")
stdout, err := cmd.RunInDir(repoPath) stdout, _, err := cmd.RunStdString(&RunOpts{Dir: repoPath})
if err != nil { if err != nil {
return time.Time{}, err return time.Time{}, err
} }
@ -278,7 +277,7 @@ type DivergeObject struct {
func checkDivergence(ctx context.Context, repoPath, baseBranch, targetBranch string) (int, error) { func checkDivergence(ctx context.Context, repoPath, baseBranch, targetBranch string) (int, error) {
branches := fmt.Sprintf("%s..%s", baseBranch, targetBranch) branches := fmt.Sprintf("%s..%s", baseBranch, targetBranch)
cmd := NewCommand(ctx, "rev-list", "--count", branches) cmd := NewCommand(ctx, "rev-list", "--count", branches)
stdout, err := cmd.RunInDir(repoPath) stdout, _, err := cmd.RunStdString(&RunOpts{Dir: repoPath})
if err != nil { if err != nil {
return -1, err return -1, err
} }
@ -315,23 +314,23 @@ func (repo *Repository) CreateBundle(ctx context.Context, commit string, out io.
defer os.RemoveAll(tmp) defer os.RemoveAll(tmp)
env := append(os.Environ(), "GIT_OBJECT_DIRECTORY="+filepath.Join(repo.Path, "objects")) env := append(os.Environ(), "GIT_OBJECT_DIRECTORY="+filepath.Join(repo.Path, "objects"))
_, err = NewCommand(ctx, "init", "--bare").RunInDirWithEnv(tmp, env) _, _, err = NewCommand(ctx, "init", "--bare").RunStdString(&RunOpts{Dir: tmp, Env: env})
if err != nil { if err != nil {
return err return err
} }
_, err = NewCommand(ctx, "reset", "--soft", commit).RunInDirWithEnv(tmp, env) _, _, err = NewCommand(ctx, "reset", "--soft", commit).RunStdString(&RunOpts{Dir: tmp, Env: env})
if err != nil { if err != nil {
return err return err
} }
_, err = NewCommand(ctx, "branch", "-m", "bundle").RunInDirWithEnv(tmp, env) _, _, err = NewCommand(ctx, "branch", "-m", "bundle").RunStdString(&RunOpts{Dir: tmp, Env: env})
if err != nil { if err != nil {
return err return err
} }
tmpFile := filepath.Join(tmp, "bundle") tmpFile := filepath.Join(tmp, "bundle")
_, err = NewCommand(ctx, "bundle", "create", tmpFile, "bundle", "HEAD").RunInDirWithEnv(tmp, env) _, _, err = NewCommand(ctx, "bundle", "create", tmpFile, "bundle", "HEAD").RunStdString(&RunOpts{Dir: tmp, Env: env})
if err != nil { if err != nil {
return err return err
} }

@ -57,11 +57,10 @@ func (repo *Repository) CreateArchive(ctx context.Context, format ArchiveType, t
) )
var stderr strings.Builder var stderr strings.Builder
err := NewCommand(ctx, args...).RunWithContext(&RunContext{ err := NewCommand(ctx, args...).Run(&RunOpts{
Timeout: -1, Dir: repo.Path,
Dir: repo.Path, Stdout: target,
Stdout: target, Stderr: &stderr,
Stderr: &stderr,
}) })
if err != nil { if err != nil {
return ConcatenateError(err, stderr.String()) return ConcatenateError(err, stderr.String())

@ -76,12 +76,11 @@ func (repo *Repository) CheckAttribute(opts CheckAttributeOpts) (map[string]map[
cmd := NewCommand(repo.Ctx, cmdArgs...) cmd := NewCommand(repo.Ctx, cmdArgs...)
if err := cmd.RunWithContext(&RunContext{ if err := cmd.Run(&RunOpts{
Env: env, Env: env,
Timeout: -1, Dir: repo.Path,
Dir: repo.Path, Stdout: stdOut,
Stdout: stdOut, Stderr: stdErr,
Stderr: stdErr,
}); err != nil { }); err != nil {
return nil, fmt.Errorf("failed to run check-attr: %v\n%s\n%s", err, stdOut.String(), stdErr.String()) return nil, fmt.Errorf("failed to run check-attr: %v\n%s\n%s", err, stdOut.String(), stdErr.String())
} }
@ -189,13 +188,12 @@ func (c *CheckAttributeReader) Run() error {
_ = c.stdOut.Close() _ = c.stdOut.Close()
}() }()
stdErr := new(bytes.Buffer) stdErr := new(bytes.Buffer)
err := c.cmd.RunWithContext(&RunContext{ err := c.cmd.Run(&RunOpts{
Env: c.env, Env: c.env,
Timeout: -1, Dir: c.Repo.Path,
Dir: c.Repo.Path, Stdin: c.stdinReader,
Stdin: c.stdinReader, Stdout: c.stdOut,
Stdout: c.stdOut, Stderr: stdErr,
Stderr: stdErr,
PipelineFunc: func(_ context.Context, _ context.CancelFunc) error { PipelineFunc: func(_ context.Context, _ context.CancelFunc) error {
select { select {
case <-c.running: case <-c.running:

@ -8,12 +8,13 @@ import "fmt"
// FileBlame return the Blame object of file // FileBlame return the Blame object of file
func (repo *Repository) FileBlame(revision, path, file string) ([]byte, error) { func (repo *Repository) FileBlame(revision, path, file string) ([]byte, error) {
return NewCommand(repo.Ctx, "blame", "--root", "--", file).RunInDirBytes(path) stdout, _, err := NewCommand(repo.Ctx, "blame", "--root", "--", file).RunStdBytes(&RunOpts{Dir: path})
return stdout, err
} }
// LineBlame returns the latest commit at the given line // LineBlame returns the latest commit at the given line
func (repo *Repository) LineBlame(revision, path, file string, line uint) (*Commit, error) { func (repo *Repository) LineBlame(revision, path, file string, line uint) (*Commit, error) {
res, err := NewCommand(repo.Ctx, "blame", fmt.Sprintf("-L %d,%d", line, line), "-p", revision, "--", file).RunInDir(path) res, _, err := NewCommand(repo.Ctx, "blame", fmt.Sprintf("-L %d,%d", line, line), "-p", revision, "--", file).RunStdString(&RunOpts{Dir: path})
if err != nil { if err != nil {
return nil, err return nil, err
} }

@ -24,7 +24,7 @@ const PullRequestPrefix = "refs/for/"
// IsReferenceExist returns true if given reference exists in the repository. // IsReferenceExist returns true if given reference exists in the repository.
func IsReferenceExist(ctx context.Context, repoPath, name string) bool { func IsReferenceExist(ctx context.Context, repoPath, name string) bool {
_, err := NewCommand(ctx, "show-ref", "--verify", "--", name).RunInDir(repoPath) _, _, err := NewCommand(ctx, "show-ref", "--verify", "--", name).RunStdString(&RunOpts{Dir: repoPath})
return err == nil return err == nil
} }
@ -46,7 +46,7 @@ func (repo *Repository) GetHEADBranch() (*Branch, error) {
if repo == nil { if repo == nil {
return nil, fmt.Errorf("nil repo") return nil, fmt.Errorf("nil repo")
} }
stdout, err := NewCommand(repo.Ctx, "symbolic-ref", "HEAD").RunInDir(repo.Path) stdout, _, err := NewCommand(repo.Ctx, "symbolic-ref", "HEAD").RunStdString(&RunOpts{Dir: repo.Path})
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -65,13 +65,14 @@ func (repo *Repository) GetHEADBranch() (*Branch, error) {
// SetDefaultBranch sets default branch of repository. // SetDefaultBranch sets default branch of repository.
func (repo *Repository) SetDefaultBranch(name string) error { func (repo *Repository) SetDefaultBranch(name string) error {
_, err := NewCommand(repo.Ctx, "symbolic-ref", "HEAD", BranchPrefix+name).RunInDir(repo.Path) _, _, err := NewCommand(repo.Ctx, "symbolic-ref", "HEAD", BranchPrefix+name).RunStdString(&RunOpts{Dir: repo.Path})
return err return err
} }
// GetDefaultBranch gets default branch of repository. // GetDefaultBranch gets default branch of repository.
func (repo *Repository) GetDefaultBranch() (string, error) { func (repo *Repository) GetDefaultBranch() (string, error) {
return NewCommand(repo.Ctx, "symbolic-ref", "HEAD").RunInDir(repo.Path) stdout, _, err := NewCommand(repo.Ctx, "symbolic-ref", "HEAD").RunStdString(&RunOpts{Dir: repo.Path})
return stdout, err
} }
// GetBranch returns a branch by it's name // GetBranch returns a branch by it's name
@ -133,7 +134,7 @@ func (repo *Repository) DeleteBranch(name string, opts DeleteBranchOptions) erro
} }
cmd.AddArguments("--", name) cmd.AddArguments("--", name)
_, err := cmd.RunInDir(repo.Path) _, _, err := cmd.RunStdString(&RunOpts{Dir: repo.Path})
return err return err
} }
@ -143,7 +144,7 @@ func (repo *Repository) CreateBranch(branch, oldbranchOrCommit string) error {
cmd := NewCommand(repo.Ctx, "branch") cmd := NewCommand(repo.Ctx, "branch")
cmd.AddArguments("--", branch, oldbranchOrCommit) cmd.AddArguments("--", branch, oldbranchOrCommit)
_, err := cmd.RunInDir(repo.Path) _, _, err := cmd.RunStdString(&RunOpts{Dir: repo.Path})
return err return err
} }
@ -156,13 +157,13 @@ func (repo *Repository) AddRemote(name, url string, fetch bool) error {
} }
cmd.AddArguments(name, url) cmd.AddArguments(name, url)
_, err := cmd.RunInDir(repo.Path) _, _, err := cmd.RunStdString(&RunOpts{Dir: repo.Path})
return err return err
} }
// RemoveRemote removes a remote from repository. // RemoveRemote removes a remote from repository.
func (repo *Repository) RemoveRemote(name string) error { func (repo *Repository) RemoveRemote(name string) error {
_, err := NewCommand(repo.Ctx, "remote", "rm", name).RunInDir(repo.Path) _, _, err := NewCommand(repo.Ctx, "remote", "rm", name).RunStdString(&RunOpts{Dir: repo.Path})
return err return err
} }
@ -173,6 +174,6 @@ func (branch *Branch) GetCommit() (*Commit, error) {
// RenameBranch rename a branch // RenameBranch rename a branch
func (repo *Repository) RenameBranch(from, to string) error { func (repo *Repository) RenameBranch(from, to string) error {
_, err := NewCommand(repo.Ctx, "branch", "-m", from, to).RunInDir(repo.Path) _, _, err := NewCommand(repo.Ctx, "branch", "-m", from, to).RunStdString(&RunOpts{Dir: repo.Path})
return err return err
} }

@ -112,11 +112,10 @@ func walkShowRef(ctx context.Context, repoPath, arg string, skip, limit int, wal
if arg != "" { if arg != "" {
args = append(args, arg) args = append(args, arg)
} }
err := NewCommand(ctx, args...).RunWithContext(&RunContext{ err := NewCommand(ctx, args...).Run(&RunOpts{
Timeout: -1, Dir: repoPath,
Dir: repoPath, Stdout: stdoutWriter,
Stdout: stdoutWriter, Stderr: stderrBuilder,
Stderr: stderrBuilder,
}) })
if err != nil { if err != nil {
if stderrBuilder.Len() == 0 { if stderrBuilder.Len() == 0 {

@ -58,12 +58,12 @@ func (repo *Repository) getCommitByPathWithID(id SHA1, relpath string) (*Commit,
relpath = `\` + relpath relpath = `\` + relpath
} }
stdout, err := NewCommand(repo.Ctx, "log", "-1", prettyLogFormat, id.String(), "--", relpath).RunInDir(repo.Path) stdout, _, runErr := NewCommand(repo.Ctx, "log", "-1", prettyLogFormat, id.String(), "--", relpath).RunStdString(&RunOpts{Dir: repo.Path})
if err != nil { if runErr != nil {
return nil, err return nil, runErr
} }
id, err = NewIDFromString(stdout) id, err := NewIDFromString(stdout)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -73,9 +73,9 @@ func (repo *Repository) getCommitByPathWithID(id SHA1, relpath string) (*Commit,
// GetCommitByPath returns the last commit of relative path. // GetCommitByPath returns the last commit of relative path.
func (repo *Repository) GetCommitByPath(relpath string) (*Commit, error) { func (repo *Repository) GetCommitByPath(relpath string) (*Commit, error) {
stdout, err := NewCommand(repo.Ctx, "log", "-1", prettyLogFormat, "--", relpath).RunInDirBytes(repo.Path) stdout, _, runErr := NewCommand(repo.Ctx, "log", "-1", prettyLogFormat, "--", relpath).RunStdBytes(&RunOpts{Dir: repo.Path})
if err != nil { if runErr != nil {
return nil, err return nil, runErr
} }
commits, err := repo.parsePrettyFormatLogToList(stdout) commits, err := repo.parsePrettyFormatLogToList(stdout)
@ -86,8 +86,8 @@ func (repo *Repository) GetCommitByPath(relpath string) (*Commit, error) {
} }
func (repo *Repository) commitsByRange(id SHA1, page, pageSize int) ([]*Commit, error) { func (repo *Repository) commitsByRange(id SHA1, page, pageSize int) ([]*Commit, error) {
stdout, err := NewCommand(repo.Ctx, "log", id.String(), "--skip="+strconv.Itoa((page-1)*pageSize), stdout, _, err := NewCommand(repo.Ctx, "log", id.String(), "--skip="+strconv.Itoa((page-1)*pageSize),
"--max-count="+strconv.Itoa(pageSize), prettyLogFormat).RunInDirBytes(repo.Path) "--max-count="+strconv.Itoa(pageSize), prettyLogFormat).RunStdBytes(&RunOpts{Dir: repo.Path})
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -139,7 +139,7 @@ func (repo *Repository) searchCommits(id SHA1, opts SearchCommitsOptions) ([]*Co
// search for commits matching given constraints and keywords in commit msg // search for commits matching given constraints and keywords in commit msg
cmd.AddArguments(args...) cmd.AddArguments(args...)
stdout, err := cmd.RunInDirBytes(repo.Path) stdout, _, err := cmd.RunStdBytes(&RunOpts{Dir: repo.Path})
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -161,7 +161,7 @@ func (repo *Repository) searchCommits(id SHA1, opts SearchCommitsOptions) ([]*Co
hashCmd.AddArguments(v) hashCmd.AddArguments(v)
// search with given constraints for commit matching sha hash of v // search with given constraints for commit matching sha hash of v
hashMatching, err := hashCmd.RunInDirBytes(repo.Path) hashMatching, _, err := hashCmd.RunStdBytes(&RunOpts{Dir: repo.Path})
if err != nil || bytes.Contains(stdout, hashMatching) { if err != nil || bytes.Contains(stdout, hashMatching) {
continue continue
} }
@ -175,7 +175,7 @@ func (repo *Repository) searchCommits(id SHA1, opts SearchCommitsOptions) ([]*Co
} }
func (repo *Repository) getFilesChanged(id1, id2 string) ([]string, error) { func (repo *Repository) getFilesChanged(id1, id2 string) ([]string, error) {
stdout, err := NewCommand(repo.Ctx, "diff", "--name-only", id1, id2).RunInDirBytes(repo.Path) stdout, _, err := NewCommand(repo.Ctx, "diff", "--name-only", id1, id2).RunStdBytes(&RunOpts{Dir: repo.Path})
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -185,7 +185,7 @@ func (repo *Repository) getFilesChanged(id1, id2 string) ([]string, error) {
// FileChangedBetweenCommits Returns true if the file changed between commit IDs id1 and id2 // FileChangedBetweenCommits Returns true if the file changed between commit IDs id1 and id2
// You must ensure that id1 and id2 are valid commit ids. // You must ensure that id1 and id2 are valid commit ids.
func (repo *Repository) FileChangedBetweenCommits(filename, id1, id2 string) (bool, error) { func (repo *Repository) FileChangedBetweenCommits(filename, id1, id2 string) (bool, error) {
stdout, err := NewCommand(repo.Ctx, "diff", "--name-only", "-z", id1, id2, "--", filename).RunInDirBytes(repo.Path) stdout, _, err := NewCommand(repo.Ctx, "diff", "--name-only", "-z", id1, id2, "--", filename).RunStdBytes(&RunOpts{Dir: repo.Path})
if err != nil { if err != nil {
return false, err return false, err
} }
@ -211,11 +211,10 @@ func (repo *Repository) CommitsByFileAndRange(revision, file string, page int) (
err := NewCommand(repo.Ctx, "log", revision, "--follow", err := NewCommand(repo.Ctx, "log", revision, "--follow",
"--max-count="+strconv.Itoa(setting.Git.CommitsRangeSize*page), "--max-count="+strconv.Itoa(setting.Git.CommitsRangeSize*page),
prettyLogFormat, "--", file). prettyLogFormat, "--", file).
RunWithContext(&RunContext{ Run(&RunOpts{
Timeout: -1, Dir: repo.Path,
Dir: repo.Path, Stdout: stdoutWriter,
Stdout: stdoutWriter, Stderr: &stderr,
Stderr: &stderr,
}) })
if err != nil { if err != nil {
_ = stdoutWriter.CloseWithError(ConcatenateError(err, (&stderr).String())) _ = stdoutWriter.CloseWithError(ConcatenateError(err, (&stderr).String()))
@ -244,8 +243,8 @@ func (repo *Repository) CommitsByFileAndRange(revision, file string, page int) (
// CommitsByFileAndRangeNoFollow return the commits according revision file and the page // CommitsByFileAndRangeNoFollow return the commits according revision file and the page
func (repo *Repository) CommitsByFileAndRangeNoFollow(revision, file string, page int) ([]*Commit, error) { func (repo *Repository) CommitsByFileAndRangeNoFollow(revision, file string, page int) ([]*Commit, error) {
stdout, err := NewCommand(repo.Ctx, "log", revision, "--skip="+strconv.Itoa((page-1)*50), stdout, _, err := NewCommand(repo.Ctx, "log", revision, "--skip="+strconv.Itoa((page-1)*50),
"--max-count="+strconv.Itoa(setting.Git.CommitsRangeSize), prettyLogFormat, "--", file).RunInDirBytes(repo.Path) "--max-count="+strconv.Itoa(setting.Git.CommitsRangeSize), prettyLogFormat, "--", file).RunStdBytes(&RunOpts{Dir: repo.Path})
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -254,11 +253,11 @@ func (repo *Repository) CommitsByFileAndRangeNoFollow(revision, file string, pag
// FilesCountBetween return the number of files changed between two commits // FilesCountBetween return the number of files changed between two commits
func (repo *Repository) FilesCountBetween(startCommitID, endCommitID string) (int, error) { func (repo *Repository) FilesCountBetween(startCommitID, endCommitID string) (int, error) {
stdout, err := NewCommand(repo.Ctx, "diff", "--name-only", startCommitID+"..."+endCommitID).RunInDir(repo.Path) stdout, _, err := NewCommand(repo.Ctx, "diff", "--name-only", startCommitID+"..."+endCommitID).RunStdString(&RunOpts{Dir: repo.Path})
if err != nil && strings.Contains(err.Error(), "no merge base") { if err != nil && strings.Contains(err.Error(), "no merge base") {
// git >= 2.28 now returns an error if startCommitID and endCommitID have become unrelated. // git >= 2.28 now returns an error if startCommitID and endCommitID have become unrelated.
// previously it would return the results of git diff --name-only startCommitID endCommitID so let's try that... // previously it would return the results of git diff --name-only startCommitID endCommitID so let's try that...
stdout, err = NewCommand(repo.Ctx, "diff", "--name-only", startCommitID, endCommitID).RunInDir(repo.Path) stdout, _, err = NewCommand(repo.Ctx, "diff", "--name-only", startCommitID, endCommitID).RunStdString(&RunOpts{Dir: repo.Path})
} }
if err != nil { if err != nil {
return 0, err return 0, err
@ -272,13 +271,13 @@ func (repo *Repository) CommitsBetween(last, before *Commit) ([]*Commit, error)
var stdout []byte var stdout []byte
var err error var err error
if before == nil { if before == nil {
stdout, err = NewCommand(repo.Ctx, "rev-list", last.ID.String()).RunInDirBytes(repo.Path) stdout, _, err = NewCommand(repo.Ctx, "rev-list", last.ID.String()).RunStdBytes(&RunOpts{Dir: repo.Path})
} else { } else {
stdout, err = NewCommand(repo.Ctx, "rev-list", before.ID.String()+".."+last.ID.String()).RunInDirBytes(repo.Path) stdout, _, err = NewCommand(repo.Ctx, "rev-list", before.ID.String()+".."+last.ID.String()).RunStdBytes(&RunOpts{Dir: repo.Path})
if err != nil && strings.Contains(err.Error(), "no merge base") { if err != nil && strings.Contains(err.Error(), "no merge base") {
// future versions of git >= 2.28 are likely to return an error if before and last have become unrelated. // future versions of git >= 2.28 are likely to return an error if before and last have become unrelated.
// previously it would return the results of git rev-list before last so let's try that... // previously it would return the results of git rev-list before last so let's try that...
stdout, err = NewCommand(repo.Ctx, "rev-list", before.ID.String(), last.ID.String()).RunInDirBytes(repo.Path) stdout, _, err = NewCommand(repo.Ctx, "rev-list", before.ID.String(), last.ID.String()).RunStdBytes(&RunOpts{Dir: repo.Path})
} }
} }
if err != nil { if err != nil {
@ -292,13 +291,13 @@ func (repo *Repository) CommitsBetweenLimit(last, before *Commit, limit, skip in
var stdout []byte var stdout []byte
var err error var err error
if before == nil { if before == nil {
stdout, err = NewCommand(repo.Ctx, "rev-list", "--max-count", strconv.Itoa(limit), "--skip", strconv.Itoa(skip), last.ID.String()).RunInDirBytes(repo.Path) stdout, _, err = NewCommand(repo.Ctx, "rev-list", "--max-count", strconv.Itoa(limit), "--skip", strconv.Itoa(skip), last.ID.String()).RunStdBytes(&RunOpts{Dir: repo.Path})
} else { } else {
stdout, err = NewCommand(repo.Ctx, "rev-list", "--max-count", strconv.Itoa(limit), "--skip", strconv.Itoa(skip), before.ID.String()+".."+last.ID.String()).RunInDirBytes(repo.Path) stdout, _, err = NewCommand(repo.Ctx, "rev-list", "--max-count", strconv.Itoa(limit), "--skip", strconv.Itoa(skip), before.ID.String()+".."+last.ID.String()).RunStdBytes(&RunOpts{Dir: repo.Path})
if err != nil && strings.Contains(err.Error(), "no merge base") { if err != nil && strings.Contains(err.Error(), "no merge base") {
// future versions of git >= 2.28 are likely to return an error if before and last have become unrelated. // future versions of git >= 2.28 are likely to return an error if before and last have become unrelated.
// previously it would return the results of git rev-list --max-count n before last so let's try that... // previously it would return the results of git rev-list --max-count n before last so let's try that...
stdout, err = NewCommand(repo.Ctx, "rev-list", "--max-count", strconv.Itoa(limit), "--skip", strconv.Itoa(skip), before.ID.String(), last.ID.String()).RunInDirBytes(repo.Path) stdout, _, err = NewCommand(repo.Ctx, "rev-list", "--max-count", strconv.Itoa(limit), "--skip", strconv.Itoa(skip), before.ID.String(), last.ID.String()).RunStdBytes(&RunOpts{Dir: repo.Path})
} }
} }
if err != nil { if err != nil {
@ -344,9 +343,9 @@ func (repo *Repository) commitsBefore(id SHA1, limit int) ([]*Commit, error) {
cmd.AddArguments(prettyLogFormat, id.String()) cmd.AddArguments(prettyLogFormat, id.String())
} }
stdout, err := cmd.RunInDirBytes(repo.Path) stdout, _, runErr := cmd.RunStdBytes(&RunOpts{Dir: repo.Path})
if err != nil { if runErr != nil {
return nil, err return nil, runErr
} }
formattedLog, err := repo.parsePrettyFormatLogToList(bytes.TrimSpace(stdout)) formattedLog, err := repo.parsePrettyFormatLogToList(bytes.TrimSpace(stdout))
@ -381,7 +380,7 @@ func (repo *Repository) getCommitsBeforeLimit(id SHA1, num int) ([]*Commit, erro
func (repo *Repository) getBranches(commit *Commit, limit int) ([]string, error) { func (repo *Repository) getBranches(commit *Commit, limit int) ([]string, error) {
if CheckGitVersionAtLeast("2.7.0") == nil { if CheckGitVersionAtLeast("2.7.0") == nil {
stdout, err := NewCommand(repo.Ctx, "for-each-ref", "--count="+strconv.Itoa(limit), "--format=%(refname:strip=2)", "--contains", commit.ID.String(), BranchPrefix).RunInDir(repo.Path) stdout, _, err := NewCommand(repo.Ctx, "for-each-ref", "--count="+strconv.Itoa(limit), "--format=%(refname:strip=2)", "--contains", commit.ID.String(), BranchPrefix).RunStdString(&RunOpts{Dir: repo.Path})
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -390,7 +389,7 @@ func (repo *Repository) getBranches(commit *Commit, limit int) ([]string, error)
return branches, nil return branches, nil
} }
stdout, err := NewCommand(repo.Ctx, "branch", "--contains", commit.ID.String()).RunInDir(repo.Path) stdout, _, err := NewCommand(repo.Ctx, "branch", "--contains", commit.ID.String()).RunStdString(&RunOpts{Dir: repo.Path})
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -429,7 +428,7 @@ func (repo *Repository) GetCommitsFromIDs(commitIDs []string) []*Commit {
// IsCommitInBranch check if the commit is on the branch // IsCommitInBranch check if the commit is on the branch
func (repo *Repository) IsCommitInBranch(commitID, branch string) (r bool, err error) { func (repo *Repository) IsCommitInBranch(commitID, branch string) (r bool, err error) {
stdout, err := NewCommand(repo.Ctx, "branch", "--contains", commitID, branch).RunInDir(repo.Path) stdout, _, err := NewCommand(repo.Ctx, "branch", "--contains", commitID, branch).RunStdString(&RunOpts{Dir: repo.Path})
if err != nil { if err != nil {
return false, err return false, err
} }

@ -50,7 +50,7 @@ func (repo *Repository) ConvertToSHA1(commitID string) (SHA1, error) {
} }
} }
actualCommitID, err := NewCommand(repo.Ctx, "rev-parse", "--verify", commitID).RunInDir(repo.Path) actualCommitID, _, err := NewCommand(repo.Ctx, "rev-parse", "--verify", commitID).RunStdString(&RunOpts{Dir: repo.Path})
if err != nil { if err != nil {
if strings.Contains(err.Error(), "unknown revision or path") || if strings.Contains(err.Error(), "unknown revision or path") ||
strings.Contains(err.Error(), "fatal: Needed a single revision") { strings.Contains(err.Error(), "fatal: Needed a single revision") {

@ -18,7 +18,7 @@ import (
// ResolveReference resolves a name to a reference // ResolveReference resolves a name to a reference
func (repo *Repository) ResolveReference(name string) (string, error) { func (repo *Repository) ResolveReference(name string) (string, error) {
stdout, err := NewCommand(repo.Ctx, "show-ref", "--hash", name).RunInDir(repo.Path) stdout, _, err := NewCommand(repo.Ctx, "show-ref", "--hash", name).RunStdString(&RunOpts{Dir: repo.Path})
if err != nil { if err != nil {
if strings.Contains(err.Error(), "not a valid ref") { if strings.Contains(err.Error(), "not a valid ref") {
return "", ErrNotExist{name, ""} return "", ErrNotExist{name, ""}
@ -51,19 +51,19 @@ func (repo *Repository) GetRefCommitID(name string) (string, error) {
// SetReference sets the commit ID string of given reference (e.g. branch or tag). // SetReference sets the commit ID string of given reference (e.g. branch or tag).
func (repo *Repository) SetReference(name, commitID string) error { func (repo *Repository) SetReference(name, commitID string) error {
_, err := NewCommand(repo.Ctx, "update-ref", name, commitID).RunInDir(repo.Path) _, _, err := NewCommand(repo.Ctx, "update-ref", name, commitID).RunStdString(&RunOpts{Dir: repo.Path})
return err return err
} }
// RemoveReference removes the given reference (e.g. branch or tag). // RemoveReference removes the given reference (e.g. branch or tag).
func (repo *Repository) RemoveReference(name string) error { func (repo *Repository) RemoveReference(name string) error {
_, err := NewCommand(repo.Ctx, "update-ref", "--no-deref", "-d", name).RunInDir(repo.Path) _, _, err := NewCommand(repo.Ctx, "update-ref", "--no-deref", "-d", name).RunStdString(&RunOpts{Dir: repo.Path})
return err return err
} }
// IsCommitExist returns true if given commit exists in current repository. // IsCommitExist returns true if given commit exists in current repository.
func (repo *Repository) IsCommitExist(name string) bool { func (repo *Repository) IsCommitExist(name string) bool {
_, err := NewCommand(repo.Ctx, "cat-file", "-e", name).RunInDir(repo.Path) _, _, err := NewCommand(repo.Ctx, "cat-file", "-e", name).RunStdString(&RunOpts{Dir: repo.Path})
return err == nil return err == nil
} }

@ -13,7 +13,7 @@ import (
// this requires git v2.18 to be installed // this requires git v2.18 to be installed
func WriteCommitGraph(ctx context.Context, repoPath string) error { func WriteCommitGraph(ctx context.Context, repoPath string) error {
if CheckGitVersionAtLeast("2.18") == nil { if CheckGitVersionAtLeast("2.18") == nil {
if _, err := NewCommand(ctx, "commit-graph", "write").RunInDir(repoPath); err != nil { if _, _, err := NewCommand(ctx, "commit-graph", "write").RunStdString(&RunOpts{Dir: repoPath}); err != nil {
return fmt.Errorf("unable to write commit-graph for '%s' : %w", repoPath, err) return fmt.Errorf("unable to write commit-graph for '%s' : %w", repoPath, err)
} }
} }

@ -40,13 +40,13 @@ func (repo *Repository) GetMergeBase(tmpRemote, base, head string) (string, stri
if tmpRemote != "origin" { if tmpRemote != "origin" {
tmpBaseName := RemotePrefix + tmpRemote + "/tmp_" + base tmpBaseName := RemotePrefix + tmpRemote + "/tmp_" + base
// Fetch commit into a temporary branch in order to be able to handle commits and tags // Fetch commit into a temporary branch in order to be able to handle commits and tags
_, err := NewCommand(repo.Ctx, "fetch", tmpRemote, base+":"+tmpBaseName).RunInDir(repo.Path) _, _, err := NewCommand(repo.Ctx, "fetch", tmpRemote, base+":"+tmpBaseName).RunStdString(&RunOpts{Dir: repo.Path})
if err == nil { if err == nil {
base = tmpBaseName base = tmpBaseName
} }
} }
stdout, err := NewCommand(repo.Ctx, "merge-base", "--", base, head).RunInDir(repo.Path) stdout, _, err := NewCommand(repo.Ctx, "merge-base", "--", base, head).RunStdString(&RunOpts{Dir: repo.Path})
return strings.TrimSpace(stdout), base, err return strings.TrimSpace(stdout), base, err
} }
@ -93,7 +93,8 @@ func (repo *Repository) GetCompareInfo(basePath, baseBranch, headBranch string,
// We have a common base - therefore we know that ... should work // We have a common base - therefore we know that ... should work
if !fileOnly { if !fileOnly {
logs, err := NewCommand(repo.Ctx, "log", baseCommitID+separator+headBranch, prettyLogFormat).RunInDirBytes(repo.Path) var logs []byte
logs, _, err = NewCommand(repo.Ctx, "log", baseCommitID+separator+headBranch, prettyLogFormat).RunStdBytes(&RunOpts{Dir: repo.Path})
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -147,22 +148,20 @@ func (repo *Repository) GetDiffNumChangedFiles(base, head string, directComparis
} }
if err := NewCommand(repo.Ctx, "diff", "-z", "--name-only", base+separator+head). if err := NewCommand(repo.Ctx, "diff", "-z", "--name-only", base+separator+head).
RunWithContext(&RunContext{ Run(&RunOpts{
Timeout: -1, Dir: repo.Path,
Dir: repo.Path, Stdout: w,
Stdout: w, Stderr: stderr,
Stderr: stderr,
}); err != nil { }); err != nil {
if strings.Contains(stderr.String(), "no merge base") { if strings.Contains(stderr.String(), "no merge base") {
// git >= 2.28 now returns an error if base and head have become unrelated. // git >= 2.28 now returns an error if base and head have become unrelated.
// previously it would return the results of git diff -z --name-only base head so let's try that... // previously it would return the results of git diff -z --name-only base head so let's try that...
w = &lineCountWriter{} w = &lineCountWriter{}
stderr.Reset() stderr.Reset()
if err = NewCommand(repo.Ctx, "diff", "-z", "--name-only", base, head).RunWithContext(&RunContext{ if err = NewCommand(repo.Ctx, "diff", "-z", "--name-only", base, head).Run(&RunOpts{
Timeout: -1, Dir: repo.Path,
Dir: repo.Path, Stdout: w,
Stdout: w, Stderr: stderr,
Stderr: stderr,
}); err == nil { }); err == nil {
return w.numLines, nil return w.numLines, nil
} }
@ -192,7 +191,7 @@ func GetDiffShortStat(ctx context.Context, repoPath string, args ...string) (num
"--shortstat", "--shortstat",
}, args...) }, args...)
stdout, err := NewCommand(ctx, args...).RunInDir(repoPath) stdout, _, err := NewCommand(ctx, args...).RunStdString(&RunOpts{Dir: repoPath})
if err != nil { if err != nil {
return 0, 0, 0, err return 0, 0, 0, err
} }
@ -248,26 +247,23 @@ func (repo *Repository) GetDiffOrPatch(base, head string, w io.Writer, patch, bi
// GetDiff generates and returns patch data between given revisions, optimized for human readability // GetDiff generates and returns patch data between given revisions, optimized for human readability
func (repo *Repository) GetDiff(base, head string, w io.Writer) error { func (repo *Repository) GetDiff(base, head string, w io.Writer) error {
return NewCommand(repo.Ctx, "diff", "-p", base, head).RunWithContext(&RunContext{ return NewCommand(repo.Ctx, "diff", "-p", base, head).Run(&RunOpts{
Timeout: -1, Dir: repo.Path,
Dir: repo.Path, Stdout: w,
Stdout: w,
}) })
} }
// GetDiffBinary generates and returns patch data between given revisions, including binary diffs. // GetDiffBinary generates and returns patch data between given revisions, including binary diffs.
func (repo *Repository) GetDiffBinary(base, head string, w io.Writer) error { func (repo *Repository) GetDiffBinary(base, head string, w io.Writer) error {
if CheckGitVersionAtLeast("1.7.7") == nil { if CheckGitVersionAtLeast("1.7.7") == nil {
return NewCommand(repo.Ctx, "diff", "-p", "--binary", "--histogram", base, head).RunWithContext(&RunContext{ return NewCommand(repo.Ctx, "diff", "-p", "--binary", "--histogram", base, head).Run(&RunOpts{
Timeout: -1, Dir: repo.Path,
Dir: repo.Path, Stdout: w,
Stdout: w,
}) })
} }
return NewCommand(repo.Ctx, "diff", "-p", "--binary", "--patience", base, head).RunWithContext(&RunContext{ return NewCommand(repo.Ctx, "diff", "-p", "--binary", "--patience", base, head).Run(&RunOpts{
Timeout: -1, Dir: repo.Path,
Dir: repo.Path, Stdout: w,
Stdout: w,
}) })
} }
@ -275,18 +271,16 @@ func (repo *Repository) GetDiffBinary(base, head string, w io.Writer) error {
func (repo *Repository) GetPatch(base, head string, w io.Writer) error { func (repo *Repository) GetPatch(base, head string, w io.Writer) error {
stderr := new(bytes.Buffer) stderr := new(bytes.Buffer)
err := NewCommand(repo.Ctx, "format-patch", "--binary", "--stdout", base+"..."+head). err := NewCommand(repo.Ctx, "format-patch", "--binary", "--stdout", base+"..."+head).
RunWithContext(&RunContext{ Run(&RunOpts{
Timeout: -1, Dir: repo.Path,
Dir: repo.Path, Stdout: w,
Stdout: w, Stderr: stderr,
Stderr: stderr,
}) })
if err != nil && bytes.Contains(stderr.Bytes(), []byte("no merge base")) { if err != nil && bytes.Contains(stderr.Bytes(), []byte("no merge base")) {
return NewCommand(repo.Ctx, "format-patch", "--binary", "--stdout", base, head). return NewCommand(repo.Ctx, "format-patch", "--binary", "--stdout", base, head).
RunWithContext(&RunContext{ Run(&RunOpts{
Timeout: -1, Dir: repo.Path,
Dir: repo.Path, Stdout: w,
Stdout: w,
}) })
} }
return err return err
@ -296,11 +290,10 @@ func (repo *Repository) GetPatch(base, head string, w io.Writer) error {
func (repo *Repository) GetDiffFromMergeBase(base, head string, w io.Writer) error { func (repo *Repository) GetDiffFromMergeBase(base, head string, w io.Writer) error {
stderr := new(bytes.Buffer) stderr := new(bytes.Buffer)
err := NewCommand(repo.Ctx, "diff", "-p", "--binary", base+"..."+head). err := NewCommand(repo.Ctx, "diff", "-p", "--binary", base+"..."+head).
RunWithContext(&RunContext{ Run(&RunOpts{
Timeout: -1, Dir: repo.Path,
Dir: repo.Path, Stdout: w,
Stdout: w, Stderr: stderr,
Stderr: stderr,
}) })
if err != nil && bytes.Contains(stderr.Bytes(), []byte("no merge base")) { if err != nil && bytes.Contains(stderr.Bytes(), []byte("no merge base")) {
return repo.GetDiffBinary(base, head, w) return repo.GetDiffBinary(base, head, w)

@ -34,7 +34,7 @@ func (repo *Repository) GetDefaultPublicGPGKey(forceUpdate bool) (*GPGSettings,
Sign: true, Sign: true,
} }
value, _ := NewCommand(repo.Ctx, "config", "--get", "commit.gpgsign").RunInDir(repo.Path) value, _, _ := NewCommand(repo.Ctx, "config", "--get", "commit.gpgsign").RunStdString(&RunOpts{Dir: repo.Path})
sign, valid := ParseBool(strings.TrimSpace(value)) sign, valid := ParseBool(strings.TrimSpace(value))
if !sign || !valid { if !sign || !valid {
gpgSettings.Sign = false gpgSettings.Sign = false
@ -42,13 +42,13 @@ func (repo *Repository) GetDefaultPublicGPGKey(forceUpdate bool) (*GPGSettings,
return gpgSettings, nil return gpgSettings, nil
} }
signingKey, _ := NewCommand(repo.Ctx, "config", "--get", "user.signingkey").RunInDir(repo.Path) signingKey, _, _ := NewCommand(repo.Ctx, "config", "--get", "user.signingkey").RunStdString(&RunOpts{Dir: repo.Path})
gpgSettings.KeyID = strings.TrimSpace(signingKey) gpgSettings.KeyID = strings.TrimSpace(signingKey)
defaultEmail, _ := NewCommand(repo.Ctx, "config", "--get", "user.email").RunInDir(repo.Path) defaultEmail, _, _ := NewCommand(repo.Ctx, "config", "--get", "user.email").RunStdString(&RunOpts{Dir: repo.Path})
gpgSettings.Email = strings.TrimSpace(defaultEmail) gpgSettings.Email = strings.TrimSpace(defaultEmail)
defaultName, _ := NewCommand(repo.Ctx, "config", "--get", "user.name").RunInDir(repo.Path) defaultName, _, _ := NewCommand(repo.Ctx, "config", "--get", "user.name").RunStdString(&RunOpts{Dir: repo.Path})
gpgSettings.Name = strings.TrimSpace(defaultName) gpgSettings.Name = strings.TrimSpace(defaultName)
if err := gpgSettings.LoadPublicKeyContent(); err != nil { if err := gpgSettings.LoadPublicKeyContent(); err != nil {

@ -18,7 +18,7 @@ import (
// ReadTreeToIndex reads a treeish to the index // ReadTreeToIndex reads a treeish to the index
func (repo *Repository) ReadTreeToIndex(treeish string, indexFilename ...string) error { func (repo *Repository) ReadTreeToIndex(treeish string, indexFilename ...string) error {
if len(treeish) != 40 { if len(treeish) != 40 {
res, err := NewCommand(repo.Ctx, "rev-parse", "--verify", treeish).RunInDir(repo.Path) res, _, err := NewCommand(repo.Ctx, "rev-parse", "--verify", treeish).RunStdString(&RunOpts{Dir: repo.Path})
if err != nil { if err != nil {
return err return err
} }
@ -38,7 +38,7 @@ func (repo *Repository) readTreeToIndex(id SHA1, indexFilename ...string) error
if len(indexFilename) > 0 { if len(indexFilename) > 0 {
env = append(os.Environ(), "GIT_INDEX_FILE="+indexFilename[0]) env = append(os.Environ(), "GIT_INDEX_FILE="+indexFilename[0])
} }
_, err := NewCommand(repo.Ctx, "read-tree", id.String()).RunInDirWithEnv(repo.Path, env) _, _, err := NewCommand(repo.Ctx, "read-tree", id.String()).RunStdString(&RunOpts{Dir: repo.Path, Env: env})
if err != nil { if err != nil {
return err return err
} }
@ -69,7 +69,7 @@ func (repo *Repository) ReadTreeToTemporaryIndex(treeish string) (filename, tmpD
// EmptyIndex empties the index // EmptyIndex empties the index
func (repo *Repository) EmptyIndex() error { func (repo *Repository) EmptyIndex() error {
_, err := NewCommand(repo.Ctx, "read-tree", "--empty").RunInDir(repo.Path) _, _, err := NewCommand(repo.Ctx, "read-tree", "--empty").RunStdString(&RunOpts{Dir: repo.Path})
return err return err
} }
@ -81,7 +81,7 @@ func (repo *Repository) LsFiles(filenames ...string) ([]string, error) {
cmd.AddArguments(arg) cmd.AddArguments(arg)
} }
} }
res, err := cmd.RunInDirBytes(repo.Path) res, _, err := cmd.RunStdBytes(&RunOpts{Dir: repo.Path})
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -106,29 +106,28 @@ func (repo *Repository) RemoveFilesFromIndex(filenames ...string) error {
buffer.WriteByte('\000') buffer.WriteByte('\000')
} }
} }
return cmd.RunWithContext(&RunContext{ return cmd.Run(&RunOpts{
Timeout: -1, Dir: repo.Path,
Dir: repo.Path, Stdin: bytes.NewReader(buffer.Bytes()),
Stdin: bytes.NewReader(buffer.Bytes()), Stdout: stdout,
Stdout: stdout, Stderr: stderr,
Stderr: stderr,
}) })
} }
// AddObjectToIndex adds the provided object hash to the index at the provided filename // AddObjectToIndex adds the provided object hash to the index at the provided filename
func (repo *Repository) AddObjectToIndex(mode string, object SHA1, filename string) error { func (repo *Repository) AddObjectToIndex(mode string, object SHA1, filename string) error {
cmd := NewCommand(repo.Ctx, "update-index", "--add", "--replace", "--cacheinfo", mode, object.String(), filename) cmd := NewCommand(repo.Ctx, "update-index", "--add", "--replace", "--cacheinfo", mode, object.String(), filename)
_, err := cmd.RunInDir(repo.Path) _, _, err := cmd.RunStdString(&RunOpts{Dir: repo.Path})
return err return err
} }
// WriteTree writes the current index as a tree to the object db and returns its hash // WriteTree writes the current index as a tree to the object db and returns its hash
func (repo *Repository) WriteTree() (*Tree, error) { func (repo *Repository) WriteTree() (*Tree, error) {
res, err := NewCommand(repo.Ctx, "write-tree").RunInDir(repo.Path) stdout, _, runErr := NewCommand(repo.Ctx, "write-tree").RunStdString(&RunOpts{Dir: repo.Path})
if err != nil { if runErr != nil {
return nil, err return nil, runErr
} }
id, err := NewIDFromString(strings.TrimSpace(res)) id, err := NewIDFromString(strings.TrimSpace(stdout))
if err != nil { if err != nil {
return nil, err return nil, err
} }

@ -45,12 +45,11 @@ func (repo *Repository) hashObject(reader io.Reader) (string, error) {
cmd := NewCommand(repo.Ctx, "hash-object", "-w", "--stdin") cmd := NewCommand(repo.Ctx, "hash-object", "-w", "--stdin")
stdout := new(bytes.Buffer) stdout := new(bytes.Buffer)
stderr := new(bytes.Buffer) stderr := new(bytes.Buffer)
err := cmd.RunWithContext(&RunContext{ err := cmd.Run(&RunOpts{
Timeout: -1, Dir: repo.Path,
Dir: repo.Path, Stdin: reader,
Stdin: reader, Stdout: stdout,
Stdout: stdout, Stderr: stderr,
Stderr: stderr,
}) })
if err != nil { if err != nil {
return "", err return "", err

@ -23,11 +23,10 @@ func (repo *Repository) GetRefsFiltered(pattern string) ([]*Reference, error) {
go func() { go func() {
stderrBuilder := &strings.Builder{} stderrBuilder := &strings.Builder{}
err := NewCommand(repo.Ctx, "for-each-ref").RunWithContext(&RunContext{ err := NewCommand(repo.Ctx, "for-each-ref").Run(&RunOpts{
Timeout: -1, Dir: repo.Path,
Dir: repo.Path, Stdout: stdoutWriter,
Stdout: stdoutWriter, Stderr: stderrBuilder,
Stderr: stderrBuilder,
}) })
if err != nil { if err != nil {
_ = stdoutWriter.CloseWithError(ConcatenateError(err, stderrBuilder.String())) _ = stdoutWriter.CloseWithError(ConcatenateError(err, stderrBuilder.String()))

@ -39,12 +39,12 @@ func (repo *Repository) GetCodeActivityStats(fromTime time.Time, branch string)
since := fromTime.Format(time.RFC3339) since := fromTime.Format(time.RFC3339)
stdout, err := NewCommand(repo.Ctx, "rev-list", "--count", "--no-merges", "--branches=*", "--date=iso", fmt.Sprintf("--since='%s'", since)).RunInDirBytes(repo.Path) stdout, _, runErr := NewCommand(repo.Ctx, "rev-list", "--count", "--no-merges", "--branches=*", "--date=iso", fmt.Sprintf("--since='%s'", since)).RunStdString(&RunOpts{Dir: repo.Path})
if err != nil { if runErr != nil {
return nil, err return nil, runErr
} }
c, err := strconv.ParseInt(strings.TrimSpace(string(stdout)), 10, 64) c, err := strconv.ParseInt(strings.TrimSpace(stdout), 10, 64)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -67,12 +67,11 @@ func (repo *Repository) GetCodeActivityStats(fromTime time.Time, branch string)
} }
stderr := new(strings.Builder) stderr := new(strings.Builder)
err = NewCommand(repo.Ctx, args...).RunWithContext(&RunContext{ err = NewCommand(repo.Ctx, args...).Run(&RunOpts{
Env: []string{}, Env: []string{},
Timeout: -1, Dir: repo.Path,
Dir: repo.Path, Stdout: stdoutWriter,
Stdout: stdoutWriter, Stderr: stderr,
Stderr: stderr,
PipelineFunc: func(ctx context.Context, cancel context.CancelFunc) error { PipelineFunc: func(ctx context.Context, cancel context.CancelFunc) error {
_ = stdoutWriter.Close() _ = stdoutWriter.Close()
scanner := bufio.NewScanner(stdoutReader) scanner := bufio.NewScanner(stdoutReader)

@ -25,13 +25,13 @@ func IsTagExist(ctx context.Context, repoPath, name string) bool {
// CreateTag create one tag in the repository // CreateTag create one tag in the repository
func (repo *Repository) CreateTag(name, revision string) error { func (repo *Repository) CreateTag(name, revision string) error {
_, err := NewCommand(repo.Ctx, "tag", "--", name, revision).RunInDir(repo.Path) _, _, err := NewCommand(repo.Ctx, "tag", "--", name, revision).RunStdString(&RunOpts{Dir: repo.Path})
return err return err
} }
// CreateAnnotatedTag create one annotated tag in the repository // CreateAnnotatedTag create one annotated tag in the repository
func (repo *Repository) CreateAnnotatedTag(name, message, revision string) error { func (repo *Repository) CreateAnnotatedTag(name, message, revision string) error {
_, err := NewCommand(repo.Ctx, "tag", "-a", "-m", message, "--", name, revision).RunInDir(repo.Path) _, _, err := NewCommand(repo.Ctx, "tag", "-a", "-m", message, "--", name, revision).RunStdString(&RunOpts{Dir: repo.Path})
return err return err
} }
@ -41,7 +41,7 @@ func (repo *Repository) GetTagNameBySHA(sha string) (string, error) {
return "", fmt.Errorf("SHA is too short: %s", sha) return "", fmt.Errorf("SHA is too short: %s", sha)
} }
stdout, err := NewCommand(repo.Ctx, "show-ref", "--tags", "-d").RunInDir(repo.Path) stdout, _, err := NewCommand(repo.Ctx, "show-ref", "--tags", "-d").RunStdString(&RunOpts{Dir: repo.Path})
if err != nil { if err != nil {
return "", err return "", err
} }
@ -64,7 +64,7 @@ func (repo *Repository) GetTagNameBySHA(sha string) (string, error) {
// GetTagID returns the object ID for a tag (annotated tags have both an object SHA AND a commit SHA) // GetTagID returns the object ID for a tag (annotated tags have both an object SHA AND a commit SHA)
func (repo *Repository) GetTagID(name string) (string, error) { func (repo *Repository) GetTagID(name string) (string, error) {
stdout, err := NewCommand(repo.Ctx, "show-ref", "--tags", "--", name).RunInDir(repo.Path) stdout, _, err := NewCommand(repo.Ctx, "show-ref", "--tags", "--", name).RunStdString(&RunOpts{Dir: repo.Path})
if err != nil { if err != nil {
return "", err return "", err
} }
@ -119,10 +119,10 @@ func (repo *Repository) GetTagInfos(page, pageSize int) ([]*Tag, int, error) {
defer stdoutReader.Close() defer stdoutReader.Close()
defer stdoutWriter.Close() defer stdoutWriter.Close()
stderr := strings.Builder{} stderr := strings.Builder{}
rc := &RunContext{Dir: repo.Path, Stdout: stdoutWriter, Stderr: &stderr, Timeout: -1} rc := &RunOpts{Dir: repo.Path, Stdout: stdoutWriter, Stderr: &stderr}
go func() { go func() {
err := NewCommand(repo.Ctx, "for-each-ref", "--format", forEachRefFmt.Flag(), "--sort", "-*creatordate", "refs/tags").RunWithContext(rc) err := NewCommand(repo.Ctx, "for-each-ref", "--format", forEachRefFmt.Flag(), "--sort", "-*creatordate", "refs/tags").Run(rc)
if err != nil { if err != nil {
_ = stdoutWriter.CloseWithError(ConcatenateError(err, stderr.String())) _ = stdoutWriter.CloseWithError(ConcatenateError(err, stderr.String()))
} else { } else {

@ -60,13 +60,12 @@ func (repo *Repository) CommitTree(author, committer *Signature, tree *Tree, opt
stdout := new(bytes.Buffer) stdout := new(bytes.Buffer)
stderr := new(bytes.Buffer) stderr := new(bytes.Buffer)
err = cmd.RunWithContext(&RunContext{ err = cmd.Run(&RunOpts{
Env: env, Env: env,
Timeout: -1, Dir: repo.Path,
Dir: repo.Path, Stdin: messageBytes,
Stdin: messageBytes, Stdout: stdout,
Stdout: stdout, Stderr: stderr,
Stderr: stderr,
}) })
if err != nil { if err != nil {

@ -22,7 +22,7 @@ func (repo *Repository) getTree(id SHA1) (*Tree, error) {
// GetTree find the tree object in the repository. // GetTree find the tree object in the repository.
func (repo *Repository) GetTree(idStr string) (*Tree, error) { func (repo *Repository) GetTree(idStr string) (*Tree, error) {
if len(idStr) != 40 { if len(idStr) != 40 {
res, err := NewCommand(repo.Ctx, "rev-parse", "--verify", idStr).RunInDir(repo.Path) res, _, err := NewCommand(repo.Ctx, "rev-parse", "--verify", idStr).RunStdString(&RunOpts{Dir: repo.Path})
if err != nil { if err != nil {
return nil, err return nil, err
} }

@ -55,7 +55,7 @@ func (repo *Repository) LsTree(ref string, filenames ...string) ([]string, error
cmd.AddArguments(arg) cmd.AddArguments(arg)
} }
} }
res, err := cmd.RunInDirBytes(repo.Path) res, _, err := cmd.RunStdBytes(&RunOpts{Dir: repo.Path})
if err != nil { if err != nil {
return nil, err return nil, err
} }

@ -81,16 +81,17 @@ func (t *Tree) ListEntries() (Entries, error) {
} }
} }
stdout, err := NewCommand(t.repo.Ctx, "ls-tree", "-l", t.ID.String()).RunInDirBytes(t.repo.Path) stdout, _, runErr := NewCommand(t.repo.Ctx, "ls-tree", "-l", t.ID.String()).RunStdBytes(&RunOpts{Dir: t.repo.Path})
if err != nil { if runErr != nil {
if strings.Contains(err.Error(), "fatal: Not a valid object name") || strings.Contains(err.Error(), "fatal: not a tree object") { if strings.Contains(runErr.Error(), "fatal: Not a valid object name") || strings.Contains(runErr.Error(), "fatal: not a tree object") {
return nil, ErrNotExist{ return nil, ErrNotExist{
ID: t.ID.String(), ID: t.ID.String(),
} }
} }
return nil, err return nil, runErr
} }
var err error
t.entries, err = parseTreeEntries(stdout, t) t.entries, err = parseTreeEntries(stdout, t)
if err == nil { if err == nil {
t.entriesParsed = true t.entriesParsed = true
@ -104,11 +105,13 @@ func (t *Tree) ListEntriesRecursive() (Entries, error) {
if t.entriesRecursiveParsed { if t.entriesRecursiveParsed {
return t.entriesRecursive, nil return t.entriesRecursive, nil
} }
stdout, err := NewCommand(t.repo.Ctx, "ls-tree", "-t", "-l", "-r", t.ID.String()).RunInDirBytes(t.repo.Path)
if err != nil { stdout, _, runErr := NewCommand(t.repo.Ctx, "ls-tree", "-t", "-l", "-r", t.ID.String()).RunStdBytes(&RunOpts{Dir: t.repo.Path})
return nil, err if runErr != nil {
return nil, runErr
} }
var err error
t.entriesRecursive, err = parseTreeEntries(stdout, t) t.entriesRecursive, err = parseTreeEntries(stdout, t)
if err == nil { if err == nil {
t.entriesRecursiveParsed = true t.entriesRecursiveParsed = true

@ -64,11 +64,10 @@ func GetCommitGraph(r *git.Repository, page, maxAllowedColors int, hidePRRefs bo
scanner := bufio.NewScanner(stdoutReader) scanner := bufio.NewScanner(stdoutReader)
if err := graphCmd.RunWithContext(&git.RunContext{ if err := graphCmd.Run(&git.RunOpts{
Timeout: -1, Dir: r.Path,
Dir: r.Path, Stdout: stdoutWriter,
Stdout: stdoutWriter, Stderr: stderr,
Stderr: stderr,
PipelineFunc: func(ctx context.Context, cancel context.CancelFunc) error { PipelineFunc: func(ctx context.Context, cancel context.CancelFunc) error {
_ = stdoutWriter.Close() _ = stdoutWriter.Close()
defer stdoutReader.Close() defer stdoutReader.Close()

@ -191,9 +191,10 @@ func (b *BleveIndexer) addUpdate(ctx context.Context, batchWriter git.WriteClose
size := update.Size size := update.Size
var err error
if !update.Sized { if !update.Sized {
stdout, err := git.NewCommand(ctx, "cat-file", "-s", update.BlobSha). var stdout string
RunInDir(repo.RepoPath()) stdout, _, err = git.NewCommand(ctx, "cat-file", "-s", update.BlobSha).RunStdString(&git.RunOpts{Dir: repo.RepoPath()})
if err != nil { if err != nil {
return err return err
} }
@ -210,7 +211,7 @@ func (b *BleveIndexer) addUpdate(ctx context.Context, batchWriter git.WriteClose
return err return err
} }
_, _, size, err := git.ReadBatchLine(batchReader) _, _, size, err = git.ReadBatchLine(batchReader)
if err != nil { if err != nil {
return err return err
} }

@ -220,10 +220,10 @@ func (b *ElasticSearchIndexer) addUpdate(ctx context.Context, batchWriter git.Wr
} }
size := update.Size size := update.Size
var err error
if !update.Sized { if !update.Sized {
stdout, err := git.NewCommand(ctx, "cat-file", "-s", update.BlobSha). var stdout string
RunInDir(repo.RepoPath()) stdout, _, err = git.NewCommand(ctx, "cat-file", "-s", update.BlobSha).RunStdString(&git.RunOpts{Dir: repo.RepoPath()})
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -240,7 +240,7 @@ func (b *ElasticSearchIndexer) addUpdate(ctx context.Context, batchWriter git.Wr
return nil, err return nil, err
} }
_, _, size, err := git.ReadBatchLine(batchReader) _, _, size, err = git.ReadBatchLine(batchReader)
if err != nil { if err != nil {
return nil, err return nil, err
} }

@ -29,7 +29,7 @@ type repoChanges struct {
} }
func getDefaultBranchSha(ctx context.Context, repo *repo_model.Repository) (string, error) { func getDefaultBranchSha(ctx context.Context, repo *repo_model.Repository) (string, error) {
stdout, err := git.NewCommand(ctx, "show-ref", "-s", git.BranchPrefix+repo.DefaultBranch).RunInDir(repo.RepoPath()) stdout, _, err := git.NewCommand(ctx, "show-ref", "-s", git.BranchPrefix+repo.DefaultBranch).RunStdString(&git.RunOpts{Dir: repo.RepoPath()})
if err != nil { if err != nil {
return "", err return "", err
} }
@ -92,30 +92,32 @@ func parseGitLsTreeOutput(stdout []byte) ([]fileUpdate, error) {
// genesisChanges get changes to add repo to the indexer for the first time // genesisChanges get changes to add repo to the indexer for the first time
func genesisChanges(ctx context.Context, repo *repo_model.Repository, revision string) (*repoChanges, error) { func genesisChanges(ctx context.Context, repo *repo_model.Repository, revision string) (*repoChanges, error) {
var changes repoChanges var changes repoChanges
stdout, err := git.NewCommand(ctx, "ls-tree", "--full-tree", "-l", "-r", revision). stdout, _, runErr := git.NewCommand(ctx, "ls-tree", "--full-tree", "-l", "-r", revision).RunStdBytes(&git.RunOpts{Dir: repo.RepoPath()})
RunInDirBytes(repo.RepoPath()) if runErr != nil {
if err != nil { return nil, runErr
return nil, err
} }
var err error
changes.Updates, err = parseGitLsTreeOutput(stdout) changes.Updates, err = parseGitLsTreeOutput(stdout)
return &changes, err return &changes, err
} }
// nonGenesisChanges get changes since the previous indexer update // nonGenesisChanges get changes since the previous indexer update
func nonGenesisChanges(ctx context.Context, repo *repo_model.Repository, revision string) (*repoChanges, error) { func nonGenesisChanges(ctx context.Context, repo *repo_model.Repository, revision string) (*repoChanges, error) {
diffCmd := git.NewCommand(ctx, "diff", "--name-status", diffCmd := git.NewCommand(ctx, "diff", "--name-status", repo.CodeIndexerStatus.CommitSha, revision)
repo.CodeIndexerStatus.CommitSha, revision) stdout, _, runErr := diffCmd.RunStdString(&git.RunOpts{Dir: repo.RepoPath()})
stdout, err := diffCmd.RunInDir(repo.RepoPath()) if runErr != nil {
if err != nil {
// previous commit sha may have been removed by a force push, so // previous commit sha may have been removed by a force push, so
// try rebuilding from scratch // try rebuilding from scratch
log.Warn("git diff: %v", err) log.Warn("git diff: %v", runErr)
if err = indexer.Delete(repo.ID); err != nil { if err := indexer.Delete(repo.ID); err != nil {
return nil, err return nil, err
} }
return genesisChanges(ctx, repo, revision) return genesisChanges(ctx, repo, revision)
} }
var changes repoChanges var changes repoChanges
var err error
updatedFilenames := make([]string, 0, 10) updatedFilenames := make([]string, 0, 10)
for _, line := range strings.Split(stdout, "\n") { for _, line := range strings.Split(stdout, "\n") {
line = strings.TrimSpace(line) line = strings.TrimSpace(line)
@ -169,7 +171,7 @@ func nonGenesisChanges(ctx context.Context, repo *repo_model.Repository, revisio
cmd := git.NewCommand(ctx, "ls-tree", "--full-tree", "-l", revision, "--") cmd := git.NewCommand(ctx, "ls-tree", "--full-tree", "-l", revision, "--")
cmd.AddArguments(updatedFilenames...) cmd.AddArguments(updatedFilenames...)
lsTreeStdout, err := cmd.RunInDirBytes(repo.RepoPath()) lsTreeStdout, _, err := cmd.RunStdBytes(&git.RunOpts{Dir: repo.RepoPath()})
if err != nil { if err != nil {
return nil, err return nil, err
} }

@ -111,9 +111,9 @@ func CreateRepository(doer, u *user_model.User, opts models.CreateRepoOptions) (
return fmt.Errorf("checkDaemonExportOK: %v", err) return fmt.Errorf("checkDaemonExportOK: %v", err)
} }
if stdout, err := git.NewCommand(ctx, "update-server-info"). if stdout, _, err := git.NewCommand(ctx, "update-server-info").
SetDescription(fmt.Sprintf("CreateRepository(git update-server-info): %s", repoPath)). SetDescription(fmt.Sprintf("CreateRepository(git update-server-info): %s", repoPath)).
RunInDir(repoPath); err != nil { RunStdString(&git.RunOpts{Dir: repoPath}); err != nil {
log.Error("CreateRepository(git update-server-info) in %v: Stdout: %s\nError: %v", repo, stdout, err) log.Error("CreateRepository(git update-server-info) in %v: Stdout: %s\nError: %v", repo, stdout, err)
rollbackRepo = repo rollbackRepo = repo
rollbackRepo.OwnerID = u.ID rollbackRepo.OwnerID = u.ID

@ -177,9 +177,9 @@ func generateRepoCommit(ctx context.Context, repo, templateRepo, generateRepo *r
} }
repoPath := repo.RepoPath() repoPath := repo.RepoPath()
if stdout, err := git.NewCommand(ctx, "remote", "add", "origin", repoPath). if stdout, _, err := git.NewCommand(ctx, "remote", "add", "origin", repoPath).
SetDescription(fmt.Sprintf("generateRepoCommit (git remote add): %s to %s", templateRepoPath, tmpDir)). SetDescription(fmt.Sprintf("generateRepoCommit (git remote add): %s to %s", templateRepoPath, tmpDir)).
RunInDirWithEnv(tmpDir, env); err != nil { RunStdString(&git.RunOpts{Dir: tmpDir, Env: env}); err != nil {
log.Error("Unable to add %v as remote origin to temporary repo to %s: stdout %s\nError: %v", repo, tmpDir, stdout, err) log.Error("Unable to add %v as remote origin to temporary repo to %s: stdout %s\nError: %v", repo, tmpDir, stdout, err)
return fmt.Errorf("git remote add: %v", err) return fmt.Errorf("git remote add: %v", err)
} }
@ -292,9 +292,9 @@ func GenerateRepository(ctx context.Context, doer, owner *user_model.User, templ
return generateRepo, fmt.Errorf("checkDaemonExportOK: %v", err) return generateRepo, fmt.Errorf("checkDaemonExportOK: %v", err)
} }
if stdout, err := git.NewCommand(ctx, "update-server-info"). if stdout, _, err := git.NewCommand(ctx, "update-server-info").
SetDescription(fmt.Sprintf("GenerateRepository(git update-server-info): %s", repoPath)). SetDescription(fmt.Sprintf("GenerateRepository(git update-server-info): %s", repoPath)).
RunInDir(repoPath); err != nil { RunStdString(&git.RunOpts{Dir: repoPath}); err != nil {
log.Error("GenerateRepository(git update-server-info) in %v: Stdout: %s\nError: %v", generateRepo, stdout, err) log.Error("GenerateRepository(git update-server-info) in %v: Stdout: %s\nError: %v", generateRepo, stdout, err)
return generateRepo, fmt.Errorf("error in GenerateRepository(git update-server-info): %v", err) return generateRepo, fmt.Errorf("error in GenerateRepository(git update-server-info): %v", err)
} }

@ -229,9 +229,9 @@ func prepareRepoCommit(ctx context.Context, repo *repo_model.Repository, tmpDir,
) )
// Clone to temporary path and do the init commit. // Clone to temporary path and do the init commit.
if stdout, err := git.NewCommand(ctx, "clone", repoPath, tmpDir). if stdout, _, err := git.NewCommand(ctx, "clone", repoPath, tmpDir).
SetDescription(fmt.Sprintf("prepareRepoCommit (git clone): %s to %s", repoPath, tmpDir)). SetDescription(fmt.Sprintf("prepareRepoCommit (git clone): %s to %s", repoPath, tmpDir)).
RunInDirWithEnv("", env); err != nil { RunStdString(&git.RunOpts{Dir: "", Env: env}); err != nil {
log.Error("Failed to clone from %v into %s: stdout: %s\nError: %v", repo, tmpDir, stdout, err) log.Error("Failed to clone from %v into %s: stdout: %s\nError: %v", repo, tmpDir, stdout, err)
return fmt.Errorf("git clone: %v", err) return fmt.Errorf("git clone: %v", err)
} }
@ -306,9 +306,9 @@ func initRepoCommit(ctx context.Context, tmpPath string, repo *repo_model.Reposi
committerName := sig.Name committerName := sig.Name
committerEmail := sig.Email committerEmail := sig.Email
if stdout, err := git.NewCommand(ctx, "add", "--all"). if stdout, _, err := git.NewCommand(ctx, "add", "--all").
SetDescription(fmt.Sprintf("initRepoCommit (git add): %s", tmpPath)). SetDescription(fmt.Sprintf("initRepoCommit (git add): %s", tmpPath)).
RunInDir(tmpPath); err != nil { RunStdString(&git.RunOpts{Dir: tmpPath}); err != nil {
log.Error("git add --all failed: Stdout: %s\nError: %v", stdout, err) log.Error("git add --all failed: Stdout: %s\nError: %v", stdout, err)
return fmt.Errorf("git add --all: %v", err) return fmt.Errorf("git add --all: %v", err)
} }
@ -343,9 +343,9 @@ func initRepoCommit(ctx context.Context, tmpPath string, repo *repo_model.Reposi
"GIT_COMMITTER_EMAIL="+committerEmail, "GIT_COMMITTER_EMAIL="+committerEmail,
) )
if stdout, err := git.NewCommand(ctx, args...). if stdout, _, err := git.NewCommand(ctx, args...).
SetDescription(fmt.Sprintf("initRepoCommit (git commit): %s", tmpPath)). SetDescription(fmt.Sprintf("initRepoCommit (git commit): %s", tmpPath)).
RunInDirWithEnv(tmpPath, env); err != nil { RunStdString(&git.RunOpts{Dir: tmpPath, Env: env}); err != nil {
log.Error("Failed to commit: %v: Stdout: %s\nError: %v", args, stdout, err) log.Error("Failed to commit: %v: Stdout: %s\nError: %v", args, stdout, err)
return fmt.Errorf("git commit: %v", err) return fmt.Errorf("git commit: %v", err)
} }
@ -354,9 +354,9 @@ func initRepoCommit(ctx context.Context, tmpPath string, repo *repo_model.Reposi
defaultBranch = setting.Repository.DefaultBranch defaultBranch = setting.Repository.DefaultBranch
} }
if stdout, err := git.NewCommand(ctx, "push", "origin", "HEAD:"+defaultBranch). if stdout, _, err := git.NewCommand(ctx, "push", "origin", "HEAD:"+defaultBranch).
SetDescription(fmt.Sprintf("initRepoCommit (git push): %s", tmpPath)). SetDescription(fmt.Sprintf("initRepoCommit (git push): %s", tmpPath)).
RunInDirWithEnv(tmpPath, models.InternalPushingEnvironment(u, repo)); err != nil { RunStdString(&git.RunOpts{Dir: tmpPath, Env: models.InternalPushingEnvironment(u, repo)}); err != nil {
log.Error("Failed to push back to HEAD: Stdout: %s\nError: %v", stdout, err) log.Error("Failed to push back to HEAD: Stdout: %s\nError: %v", stdout, err)
return fmt.Errorf("git push: %v", err) return fmt.Errorf("git push: %v", err)
} }

@ -104,8 +104,8 @@ func IsForcePush(ctx context.Context, opts *PushUpdateOptions) (bool, error) {
return false, nil return false, nil
} }
output, err := git.NewCommand(ctx, "rev-list", "--max-count=1", opts.OldCommitID, "^"+opts.NewCommitID). output, _, err := git.NewCommand(ctx, "rev-list", "--max-count=1", opts.OldCommitID, "^"+opts.NewCommitID).
RunInDir(repo_model.RepoPath(opts.RepoUserName, opts.RepoName)) RunStdString(&git.RunOpts{Dir: repo_model.RepoPath(opts.RepoUserName, opts.RepoName)})
if err != nil { if err != nil {
return false, err return false, err
} else if len(output) > 0 { } else if len(output) > 0 {

@ -119,9 +119,9 @@ func MigrateRepositoryGitData(ctx context.Context, u *user_model.User,
return repo, fmt.Errorf("checkDaemonExportOK: %v", err) return repo, fmt.Errorf("checkDaemonExportOK: %v", err)
} }
if stdout, err := git.NewCommand(ctx, "update-server-info"). if stdout, _, err := git.NewCommand(ctx, "update-server-info").
SetDescription(fmt.Sprintf("MigrateRepositoryGitData(git update-server-info): %s", repoPath)). SetDescription(fmt.Sprintf("MigrateRepositoryGitData(git update-server-info): %s", repoPath)).
RunInDir(repoPath); err != nil { RunStdString(&git.RunOpts{Dir: repoPath}); err != nil {
log.Error("MigrateRepositoryGitData(git update-server-info) in %v: Stdout: %s\nError: %v", repo, stdout, err) log.Error("MigrateRepositoryGitData(git update-server-info) in %v: Stdout: %s\nError: %v", repo, stdout, err)
return repo, fmt.Errorf("error in MigrateRepositoryGitData(git update-server-info): %v", err) return repo, fmt.Errorf("error in MigrateRepositoryGitData(git update-server-info): %v", err)
} }
@ -241,7 +241,7 @@ func CleanUpMigrateInfo(ctx context.Context, repo *repo_model.Repository) (*repo
} }
} }
_, err := git.NewCommand(ctx, "remote", "rm", "origin").RunInDir(repoPath) _, _, err := git.NewCommand(ctx, "remote", "rm", "origin").RunStdString(&git.RunOpts{Dir: repoPath})
if err != nil && !strings.HasPrefix(err.Error(), "exit status 128 - fatal: No such remote ") { if err != nil && !strings.HasPrefix(err.Error(), "exit status 128 - fatal: No such remote ") {
return repo, fmt.Errorf("CleanUpMigrateInfo: %v", err) return repo, fmt.Errorf("CleanUpMigrateInfo: %v", err)
} }

@ -179,7 +179,7 @@ func preReceiveBranch(ctx *preReceiveContext, oldCommitID, newCommitID, refFullN
// 2. Disallow force pushes to protected branches // 2. Disallow force pushes to protected branches
if git.EmptySHA != oldCommitID { if git.EmptySHA != oldCommitID {
output, err := git.NewCommand(ctx, "rev-list", "--max-count=1", oldCommitID, "^"+newCommitID).RunInDirWithEnv(repo.RepoPath(), ctx.env) output, _, err := git.NewCommand(ctx, "rev-list", "--max-count=1", oldCommitID, "^"+newCommitID).RunStdString(&git.RunOpts{Dir: repo.RepoPath(), Env: ctx.env})
if err != nil { if err != nil {
log.Error("Unable to detect force push between: %s and %s in %-v Error: %v", oldCommitID, newCommitID, repo, err) log.Error("Unable to detect force push between: %s and %s in %-v Error: %v", oldCommitID, newCommitID, repo, err)
ctx.JSON(http.StatusInternalServerError, private.Response{ ctx.JSON(http.StatusInternalServerError, private.Response{

@ -45,11 +45,10 @@ func verifyCommits(oldCommitID, newCommitID string, repo *git.Repository, env []
// This is safe as force pushes are already forbidden // This is safe as force pushes are already forbidden
err = git.NewCommand(repo.Ctx, "rev-list", oldCommitID+"..."+newCommitID). err = git.NewCommand(repo.Ctx, "rev-list", oldCommitID+"..."+newCommitID).
RunWithContext(&git.RunContext{ Run(&git.RunOpts{
Env: env, Env: env,
Timeout: -1, Dir: repo.Path,
Dir: repo.Path, Stdout: stdoutWriter,
Stdout: stdoutWriter,
PipelineFunc: func(ctx context.Context, cancel context.CancelFunc) error { PipelineFunc: func(ctx context.Context, cancel context.CancelFunc) error {
_ = stdoutWriter.Close() _ = stdoutWriter.Close()
err := readAndVerifyCommitsFromShaReader(stdoutReader, repo, env) err := readAndVerifyCommitsFromShaReader(stdoutReader, repo, env)
@ -93,11 +92,10 @@ func readAndVerifyCommit(sha string, repo *git.Repository, env []string) error {
hash := git.MustIDFromString(sha) hash := git.MustIDFromString(sha)
return git.NewCommand(repo.Ctx, "cat-file", "commit", sha). return git.NewCommand(repo.Ctx, "cat-file", "commit", sha).
RunWithContext(&git.RunContext{ Run(&git.RunOpts{
Env: env, Env: env,
Timeout: -1, Dir: repo.Path,
Dir: repo.Path, Stdout: stdoutWriter,
Stdout: stdoutWriter,
PipelineFunc: func(ctx context.Context, cancel context.CancelFunc) error { PipelineFunc: func(ctx context.Context, cancel context.CancelFunc) error {
_ = stdoutWriter.Close() _ = stdoutWriter.Close()
commit, err := git.CommitFromReader(repo, hash, stdoutReader) commit, err := git.CommitFromReader(repo, hash, stdoutReader)

@ -313,7 +313,7 @@ func dummyInfoRefs(ctx *context.Context) {
return return
} }
refs, err := git.NewCommand(ctx, "receive-pack", "--stateless-rpc", "--advertise-refs", ".").RunInDirBytes(tmpDir) refs, _, err := git.NewCommand(ctx, "receive-pack", "--stateless-rpc", "--advertise-refs", ".").RunStdBytes(&git.RunOpts{Dir: tmpDir})
if err != nil { if err != nil {
log.Error(fmt.Sprintf("%v - %s", err, string(refs))) log.Error(fmt.Sprintf("%v - %s", err, string(refs)))
} }
@ -397,7 +397,7 @@ func (h *serviceHandler) sendFile(contentType, file string) {
var safeGitProtocolHeader = regexp.MustCompile(`^[0-9a-zA-Z]+=[0-9a-zA-Z]+(:[0-9a-zA-Z]+=[0-9a-zA-Z]+)*$`) var safeGitProtocolHeader = regexp.MustCompile(`^[0-9a-zA-Z]+=[0-9a-zA-Z]+(:[0-9a-zA-Z]+=[0-9a-zA-Z]+)*$`)
func getGitConfig(ctx gocontext.Context, option, dir string) string { func getGitConfig(ctx gocontext.Context, option, dir string) string {
out, err := git.NewCommand(ctx, "config", option).RunInDir(dir) out, _, err := git.NewCommand(ctx, "config", option).RunStdString(&git.RunOpts{Dir: dir})
if err != nil { if err != nil {
log.Error("%v - %s", err, out) log.Error("%v - %s", err, out)
} }
@ -472,13 +472,12 @@ func serviceRPC(ctx gocontext.Context, h serviceHandler, service string) {
var stderr bytes.Buffer var stderr bytes.Buffer
cmd := git.NewCommand(h.r.Context(), service, "--stateless-rpc", h.dir) cmd := git.NewCommand(h.r.Context(), service, "--stateless-rpc", h.dir)
cmd.SetDescription(fmt.Sprintf("%s %s %s [repo_path: %s]", git.GitExecutable, service, "--stateless-rpc", h.dir)) cmd.SetDescription(fmt.Sprintf("%s %s %s [repo_path: %s]", git.GitExecutable, service, "--stateless-rpc", h.dir))
if err := cmd.RunWithContext(&git.RunContext{ if err := cmd.Run(&git.RunOpts{
Timeout: -1, Dir: h.dir,
Dir: h.dir, Env: append(os.Environ(), h.environ...),
Env: append(os.Environ(), h.environ...), Stdout: h.w,
Stdout: h.w, Stdin: reqBody,
Stdin: reqBody, Stderr: &stderr,
Stderr: &stderr,
}); err != nil { }); err != nil {
if err.Error() != "signal: killed" { if err.Error() != "signal: killed" {
log.Error("Fail to serve RPC(%s) in %s: %v - %s", service, h.dir, err, stderr.String()) log.Error("Fail to serve RPC(%s) in %s: %v - %s", service, h.dir, err, stderr.String())
@ -512,7 +511,7 @@ func getServiceType(r *http.Request) string {
} }
func updateServerInfo(ctx gocontext.Context, dir string) []byte { func updateServerInfo(ctx gocontext.Context, dir string) []byte {
out, err := git.NewCommand(ctx, "update-server-info").RunInDirBytes(dir) out, _, err := git.NewCommand(ctx, "update-server-info").RunStdBytes(&git.RunOpts{Dir: dir})
if err != nil { if err != nil {
log.Error(fmt.Sprintf("%v - %s", err, string(out))) log.Error(fmt.Sprintf("%v - %s", err, string(out)))
} }
@ -542,7 +541,7 @@ func GetInfoRefs(ctx *context.Context) {
} }
h.environ = append(os.Environ(), h.environ...) h.environ = append(os.Environ(), h.environ...)
refs, _, err := git.NewCommand(ctx, service, "--stateless-rpc", "--advertise-refs", ".").RunWithContextBytes(&git.RunContext{Env: h.environ, Dir: h.dir}) refs, _, err := git.NewCommand(ctx, service, "--stateless-rpc", "--advertise-refs", ".").RunStdBytes(&git.RunOpts{Env: h.environ, Dir: h.dir})
if err != nil { if err != nil {
log.Error(fmt.Sprintf("%v - %s", err, string(refs))) log.Error(fmt.Sprintf("%v - %s", err, string(refs)))
} }

@ -340,7 +340,7 @@ func PrepareMergedViewPullInfo(ctx *context.Context, issue *models.Issue) *git.C
} }
if commitSHA != "" { if commitSHA != "" {
// Get immediate parent of the first commit in the patch, grab history back // Get immediate parent of the first commit in the patch, grab history back
parentCommit, err = git.NewCommand(ctx, "rev-list", "-1", "--skip=1", commitSHA).RunInDir(ctx.Repo.GitRepo.Path) parentCommit, _, err = git.NewCommand(ctx, "rev-list", "-1", "--skip=1", commitSHA).RunStdString(&git.RunOpts{Dir: ctx.Repo.GitRepo.Path})
if err == nil { if err == nil {
parentCommit = strings.TrimSpace(parentCommit) parentCommit = strings.TrimSpace(parentCommit)
} }

@ -205,7 +205,7 @@ func ProcRecive(ctx *context.PrivateContext, opts *private.HookOptions) []privat
} }
if !forcePush { if !forcePush {
output, err := git.NewCommand(ctx, "rev-list", "--max-count=1", oldCommitID, "^"+opts.NewCommitIDs[i]).RunInDirWithEnv(repo.RepoPath(), os.Environ()) output, _, err := git.NewCommand(ctx, "rev-list", "--max-count=1", oldCommitID, "^"+opts.NewCommitIDs[i]).RunStdString(&git.RunOpts{Dir: repo.RepoPath(), Env: os.Environ()})
if err != nil { if err != nil {
log.Error("Unable to detect force push between: %s and %s in %-v Error: %v", oldCommitID, opts.NewCommitIDs[i], repo, err) log.Error("Unable to detect force push between: %s and %s in %-v Error: %v", oldCommitID, opts.NewCommitIDs[i], repo, err)
ctx.JSON(http.StatusInternalServerError, private.Response{ ctx.JSON(http.StatusInternalServerError, private.Response{

@ -90,15 +90,15 @@ func SigningKey(ctx context.Context, repoPath string) (string, *git.Signature) {
if setting.Repository.Signing.SigningKey == "default" || setting.Repository.Signing.SigningKey == "" { if setting.Repository.Signing.SigningKey == "default" || setting.Repository.Signing.SigningKey == "" {
// Can ignore the error here as it means that commit.gpgsign is not set // Can ignore the error here as it means that commit.gpgsign is not set
value, _ := git.NewCommand(ctx, "config", "--get", "commit.gpgsign").RunInDir(repoPath) value, _, _ := git.NewCommand(ctx, "config", "--get", "commit.gpgsign").RunStdString(&git.RunOpts{Dir: repoPath})
sign, valid := git.ParseBool(strings.TrimSpace(value)) sign, valid := git.ParseBool(strings.TrimSpace(value))
if !sign || !valid { if !sign || !valid {
return "", nil return "", nil
} }
signingKey, _ := git.NewCommand(ctx, "config", "--get", "user.signingkey").RunInDir(repoPath) signingKey, _, _ := git.NewCommand(ctx, "config", "--get", "user.signingkey").RunStdString(&git.RunOpts{Dir: repoPath})
signingName, _ := git.NewCommand(ctx, "config", "--get", "user.name").RunInDir(repoPath) signingName, _, _ := git.NewCommand(ctx, "config", "--get", "user.name").RunStdString(&git.RunOpts{Dir: repoPath})
signingEmail, _ := git.NewCommand(ctx, "config", "--get", "user.email").RunInDir(repoPath) signingEmail, _, _ := git.NewCommand(ctx, "config", "--get", "user.email").RunStdString(&git.RunOpts{Dir: repoPath})
return strings.TrimSpace(signingKey), &git.Signature{ return strings.TrimSpace(signingKey), &git.Signature{
Name: strings.TrimSpace(signingName), Name: strings.TrimSpace(signingName),
Email: strings.TrimSpace(signingEmail), Email: strings.TrimSpace(signingEmail),

@ -1378,7 +1378,7 @@ func GetDiff(gitRepo *git.Repository, opts *DiffOptions, files ...string) (*Diff
go func(ctx context.Context, diffArgs []string, repoPath string, writer *io.PipeWriter) { go func(ctx context.Context, diffArgs []string, repoPath string, writer *io.PipeWriter) {
cmd := git.NewCommand(ctx, diffArgs...) cmd := git.NewCommand(ctx, diffArgs...)
cmd.SetDescription(fmt.Sprintf("GetDiffRange [repo_path: %s]", repoPath)) cmd.SetDescription(fmt.Sprintf("GetDiffRange [repo_path: %s]", repoPath))
if err := cmd.RunWithContext(&git.RunContext{ if err := cmd.Run(&git.RunOpts{
Timeout: time.Duration(setting.Git.Timeout.Default) * time.Second, Timeout: time.Duration(setting.Git.Timeout.Default) * time.Second,
Dir: repoPath, Dir: repoPath,
Stderr: os.Stderr, Stderr: os.Stderr,

@ -479,7 +479,7 @@ func (g *RepositoryDumper) CreatePullRequests(prs ...*base.PullRequest) error {
} }
if ok { if ok {
_, err = git.NewCommand(g.ctx, "fetch", remote, pr.Head.Ref).RunInDir(g.gitPath()) _, _, err = git.NewCommand(g.ctx, "fetch", remote, pr.Head.Ref).RunStdString(&git.RunOpts{Dir: g.gitPath()})
if err != nil { if err != nil {
log.Error("Fetch branch from %s failed: %v", pr.Head.CloneURL, err) log.Error("Fetch branch from %s failed: %v", pr.Head.CloneURL, err)
} else { } else {

@ -553,7 +553,7 @@ func (g *GiteaLocalUploader) updateGitForPullRequest(pr *base.PullRequest) (head
} }
if ok { if ok {
_, err = git.NewCommand(g.ctx, "fetch", remote, pr.Head.Ref).RunInDir(g.repo.RepoPath()) _, _, err = git.NewCommand(g.ctx, "fetch", remote, pr.Head.Ref).RunStdString(&git.RunOpts{Dir: g.repo.RepoPath()})
if err != nil { if err != nil {
log.Error("Fetch branch from %s failed: %v", pr.Head.CloneURL, err) log.Error("Fetch branch from %s failed: %v", pr.Head.CloneURL, err)
} else { } else {
@ -577,7 +577,7 @@ func (g *GiteaLocalUploader) updateGitForPullRequest(pr *base.PullRequest) (head
} else { } else {
head = pr.Head.Ref head = pr.Head.Ref
// Ensure the closed PR SHA still points to an existing ref // Ensure the closed PR SHA still points to an existing ref
_, err = git.NewCommand(g.ctx, "rev-list", "--quiet", "-1", pr.Head.SHA).RunInDir(g.repo.RepoPath()) _, _, err = git.NewCommand(g.ctx, "rev-list", "--quiet", "-1", pr.Head.SHA).RunStdString(&git.RunOpts{Dir: g.repo.RepoPath()})
if err != nil { if err != nil {
if pr.Head.SHA != "" { if pr.Head.SHA != "" {
// Git update-ref remove bad references with a relative path // Git update-ref remove bad references with a relative path

@ -233,7 +233,7 @@ func TestGiteaUploadUpdateGitForPullRequest(t *testing.T) {
fromRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) fromRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository)
baseRef := "master" baseRef := "master"
assert.NoError(t, git.InitRepository(git.DefaultContext, fromRepo.RepoPath(), false)) assert.NoError(t, git.InitRepository(git.DefaultContext, fromRepo.RepoPath(), false))
_, err := git.NewCommand(git.DefaultContext, "symbolic-ref", "HEAD", git.BranchPrefix+baseRef).RunInDir(fromRepo.RepoPath()) err := git.NewCommand(git.DefaultContext, "symbolic-ref", "HEAD", git.BranchPrefix+baseRef).Run(&git.RunOpts{Dir: fromRepo.RepoPath()})
assert.NoError(t, err) assert.NoError(t, err)
assert.NoError(t, os.WriteFile(filepath.Join(fromRepo.RepoPath(), "README.md"), []byte(fmt.Sprintf("# Testing Repository\n\nOriginally created in: %s", fromRepo.RepoPath())), 0o644)) assert.NoError(t, os.WriteFile(filepath.Join(fromRepo.RepoPath(), "README.md"), []byte(fmt.Sprintf("# Testing Repository\n\nOriginally created in: %s", fromRepo.RepoPath())), 0o644))
assert.NoError(t, git.AddChanges(fromRepo.RepoPath(), true)) assert.NoError(t, git.AddChanges(fromRepo.RepoPath(), true))
@ -257,7 +257,7 @@ func TestGiteaUploadUpdateGitForPullRequest(t *testing.T) {
// fromRepo branch1 // fromRepo branch1
// //
headRef := "branch1" headRef := "branch1"
_, err = git.NewCommand(git.DefaultContext, "checkout", "-b", headRef).RunInDir(fromRepo.RepoPath()) _, _, err = git.NewCommand(git.DefaultContext, "checkout", "-b", headRef).RunStdString(&git.RunOpts{Dir: fromRepo.RepoPath()})
assert.NoError(t, err) assert.NoError(t, err)
assert.NoError(t, os.WriteFile(filepath.Join(fromRepo.RepoPath(), "README.md"), []byte("SOMETHING"), 0o644)) assert.NoError(t, os.WriteFile(filepath.Join(fromRepo.RepoPath(), "README.md"), []byte("SOMETHING"), 0o644))
assert.NoError(t, git.AddChanges(fromRepo.RepoPath(), true)) assert.NoError(t, git.AddChanges(fromRepo.RepoPath(), true))
@ -281,7 +281,7 @@ func TestGiteaUploadUpdateGitForPullRequest(t *testing.T) {
assert.NoError(t, git.CloneWithArgs(git.DefaultContext, fromRepo.RepoPath(), forkRepo.RepoPath(), []string{}, git.CloneRepoOptions{ assert.NoError(t, git.CloneWithArgs(git.DefaultContext, fromRepo.RepoPath(), forkRepo.RepoPath(), []string{}, git.CloneRepoOptions{
Branch: headRef, Branch: headRef,
})) }))
_, err = git.NewCommand(git.DefaultContext, "checkout", "-b", forkHeadRef).RunInDir(forkRepo.RepoPath()) _, _, err = git.NewCommand(git.DefaultContext, "checkout", "-b", forkHeadRef).RunStdString(&git.RunOpts{Dir: forkRepo.RepoPath()})
assert.NoError(t, err) assert.NoError(t, err)
assert.NoError(t, os.WriteFile(filepath.Join(forkRepo.RepoPath(), "README.md"), []byte(fmt.Sprintf("# branch2 %s", forkRepo.RepoPath())), 0o644)) assert.NoError(t, os.WriteFile(filepath.Join(forkRepo.RepoPath(), "README.md"), []byte(fmt.Sprintf("# branch2 %s", forkRepo.RepoPath())), 0o644))
assert.NoError(t, git.AddChanges(forkRepo.RepoPath(), true)) assert.NoError(t, git.AddChanges(forkRepo.RepoPath(), true))

@ -33,7 +33,7 @@ func UpdateAddress(ctx context.Context, m *repo_model.Mirror, addr string) error
remoteName := m.GetRemoteName() remoteName := m.GetRemoteName()
repoPath := m.Repo.RepoPath() repoPath := m.Repo.RepoPath()
// Remove old remote // Remove old remote
_, err := git.NewCommand(ctx, "remote", "rm", remoteName).RunInDir(repoPath) _, _, err := git.NewCommand(ctx, "remote", "rm", remoteName).RunStdString(&git.RunOpts{Dir: repoPath})
if err != nil && !strings.HasPrefix(err.Error(), "exit status 128 - fatal: No such remote ") { if err != nil && !strings.HasPrefix(err.Error(), "exit status 128 - fatal: No such remote ") {
return err return err
} }
@ -44,7 +44,7 @@ func UpdateAddress(ctx context.Context, m *repo_model.Mirror, addr string) error
} else { } else {
cmd.SetDescription(fmt.Sprintf("remote add %s --mirror=fetch %s [repo_path: %s]", remoteName, addr, repoPath)) cmd.SetDescription(fmt.Sprintf("remote add %s --mirror=fetch %s [repo_path: %s]", remoteName, addr, repoPath))
} }
_, err = cmd.RunInDir(repoPath) _, _, err = cmd.RunStdString(&git.RunOpts{Dir: repoPath})
if err != nil && !strings.HasPrefix(err.Error(), "exit status 128 - fatal: No such remote ") { if err != nil && !strings.HasPrefix(err.Error(), "exit status 128 - fatal: No such remote ") {
return err return err
} }
@ -53,7 +53,7 @@ func UpdateAddress(ctx context.Context, m *repo_model.Mirror, addr string) error
wikiPath := m.Repo.WikiPath() wikiPath := m.Repo.WikiPath()
wikiRemotePath := repo_module.WikiRemoteURL(ctx, addr) wikiRemotePath := repo_module.WikiRemoteURL(ctx, addr)
// Remove old remote of wiki // Remove old remote of wiki
_, err := git.NewCommand(ctx, "remote", "rm", remoteName).RunInDir(wikiPath) _, _, err = git.NewCommand(ctx, "remote", "rm", remoteName).RunStdString(&git.RunOpts{Dir: wikiPath})
if err != nil && !strings.HasPrefix(err.Error(), "exit status 128 - fatal: No such remote ") { if err != nil && !strings.HasPrefix(err.Error(), "exit status 128 - fatal: No such remote ") {
return err return err
} }
@ -64,7 +64,7 @@ func UpdateAddress(ctx context.Context, m *repo_model.Mirror, addr string) error
} else { } else {
cmd.SetDescription(fmt.Sprintf("remote add %s --mirror=fetch %s [repo_path: %s]", remoteName, wikiRemotePath, wikiPath)) cmd.SetDescription(fmt.Sprintf("remote add %s --mirror=fetch %s [repo_path: %s]", remoteName, wikiRemotePath, wikiPath))
} }
_, err = cmd.RunInDir(wikiPath) _, _, err = cmd.RunStdString(&git.RunOpts{Dir: wikiPath})
if err != nil && !strings.HasPrefix(err.Error(), "exit status 128 - fatal: No such remote ") { if err != nil && !strings.HasPrefix(err.Error(), "exit status 128 - fatal: No such remote ") {
return err return err
} }
@ -171,7 +171,7 @@ func pruneBrokenReferences(ctx context.Context,
stdoutBuilder.Reset() stdoutBuilder.Reset()
pruneErr := git.NewCommand(ctx, "remote", "prune", m.GetRemoteName()). pruneErr := git.NewCommand(ctx, "remote", "prune", m.GetRemoteName()).
SetDescription(fmt.Sprintf("Mirror.runSync %ssPrune references: %s ", wiki, m.Repo.FullName())). SetDescription(fmt.Sprintf("Mirror.runSync %ssPrune references: %s ", wiki, m.Repo.FullName())).
RunWithContext(&git.RunContext{ Run(&git.RunOpts{
Timeout: timeout, Timeout: timeout,
Dir: repoPath, Dir: repoPath,
Stdout: stdoutBuilder, Stdout: stdoutBuilder,
@ -219,7 +219,7 @@ func runSync(ctx context.Context, m *repo_model.Mirror) ([]*mirrorSyncResult, bo
stderrBuilder := strings.Builder{} stderrBuilder := strings.Builder{}
if err := git.NewCommand(ctx, gitArgs...). if err := git.NewCommand(ctx, gitArgs...).
SetDescription(fmt.Sprintf("Mirror.runSync: %s", m.Repo.FullName())). SetDescription(fmt.Sprintf("Mirror.runSync: %s", m.Repo.FullName())).
RunWithContext(&git.RunContext{ Run(&git.RunOpts{
Timeout: timeout, Timeout: timeout,
Dir: repoPath, Dir: repoPath,
Stdout: &stdoutBuilder, Stdout: &stdoutBuilder,
@ -245,7 +245,7 @@ func runSync(ctx context.Context, m *repo_model.Mirror) ([]*mirrorSyncResult, bo
stdoutBuilder.Reset() stdoutBuilder.Reset()
if err = git.NewCommand(ctx, gitArgs...). if err = git.NewCommand(ctx, gitArgs...).
SetDescription(fmt.Sprintf("Mirror.runSync: %s", m.Repo.FullName())). SetDescription(fmt.Sprintf("Mirror.runSync: %s", m.Repo.FullName())).
RunWithContext(&git.RunContext{ Run(&git.RunOpts{
Timeout: timeout, Timeout: timeout,
Dir: repoPath, Dir: repoPath,
Stdout: &stdoutBuilder, Stdout: &stdoutBuilder,
@ -310,7 +310,7 @@ func runSync(ctx context.Context, m *repo_model.Mirror) ([]*mirrorSyncResult, bo
stdoutBuilder.Reset() stdoutBuilder.Reset()
if err := git.NewCommand(ctx, "remote", "update", "--prune", m.GetRemoteName()). if err := git.NewCommand(ctx, "remote", "update", "--prune", m.GetRemoteName()).
SetDescription(fmt.Sprintf("Mirror.runSync Wiki: %s ", m.Repo.FullName())). SetDescription(fmt.Sprintf("Mirror.runSync Wiki: %s ", m.Repo.FullName())).
RunWithContext(&git.RunContext{ Run(&git.RunOpts{
Timeout: timeout, Timeout: timeout,
Dir: wikiPath, Dir: wikiPath,
Stdout: &stdoutBuilder, Stdout: &stdoutBuilder,
@ -337,7 +337,7 @@ func runSync(ctx context.Context, m *repo_model.Mirror) ([]*mirrorSyncResult, bo
if err = git.NewCommand(ctx, "remote", "update", "--prune", m.GetRemoteName()). if err = git.NewCommand(ctx, "remote", "update", "--prune", m.GetRemoteName()).
SetDescription(fmt.Sprintf("Mirror.runSync Wiki: %s ", m.Repo.FullName())). SetDescription(fmt.Sprintf("Mirror.runSync Wiki: %s ", m.Repo.FullName())).
RunWithContext(&git.RunContext{ Run(&git.RunOpts{
Timeout: timeout, Timeout: timeout,
Dir: wikiPath, Dir: wikiPath,
Stdout: &stdoutBuilder, Stdout: &stdoutBuilder,

@ -35,13 +35,13 @@ func AddPushMirrorRemote(ctx context.Context, m *repo_model.PushMirror, addr str
} else { } else {
cmd.SetDescription(fmt.Sprintf("remote add %s --mirror=push %s [repo_path: %s]", m.RemoteName, addr, path)) cmd.SetDescription(fmt.Sprintf("remote add %s --mirror=push %s [repo_path: %s]", m.RemoteName, addr, path))
} }
if _, err := cmd.RunInDir(path); err != nil { if _, _, err := cmd.RunStdString(&git.RunOpts{Dir: path}); err != nil {
return err return err
} }
if _, err := git.NewCommand(ctx, "config", "--add", "remote."+m.RemoteName+".push", "+refs/heads/*:refs/heads/*").RunInDir(path); err != nil { if _, _, err := git.NewCommand(ctx, "config", "--add", "remote."+m.RemoteName+".push", "+refs/heads/*:refs/heads/*").RunStdString(&git.RunOpts{Dir: path}); err != nil {
return err return err
} }
if _, err := git.NewCommand(ctx, "config", "--add", "remote."+m.RemoteName+".push", "+refs/tags/*:refs/tags/*").RunInDir(path); err != nil { if _, _, err := git.NewCommand(ctx, "config", "--add", "remote."+m.RemoteName+".push", "+refs/tags/*:refs/tags/*").RunStdString(&git.RunOpts{Dir: path}); err != nil {
return err return err
} }
return nil return nil
@ -67,12 +67,12 @@ func AddPushMirrorRemote(ctx context.Context, m *repo_model.PushMirror, addr str
func RemovePushMirrorRemote(ctx context.Context, m *repo_model.PushMirror) error { func RemovePushMirrorRemote(ctx context.Context, m *repo_model.PushMirror) error {
cmd := git.NewCommand(ctx, "remote", "rm", m.RemoteName) cmd := git.NewCommand(ctx, "remote", "rm", m.RemoteName)
if _, err := cmd.RunInDir(m.Repo.RepoPath()); err != nil { if _, _, err := cmd.RunStdString(&git.RunOpts{Dir: m.Repo.RepoPath()}); err != nil {
return err return err
} }
if m.Repo.HasWiki() { if m.Repo.HasWiki() {
if _, err := cmd.RunInDir(m.Repo.WikiPath()); err != nil { if _, _, err := cmd.RunStdString(&git.RunOpts{Dir: m.Repo.WikiPath()}); err != nil {
// The wiki remote may not exist // The wiki remote may not exist
log.Warn("Wiki Remote[%d] could not be removed: %v", m.ID, err) log.Warn("Wiki Remote[%d] could not be removed: %v", m.ID, err)
} }

@ -175,8 +175,8 @@ func getMergeCommit(ctx context.Context, pr *models.PullRequest) (*git.Commit, e
headFile := pr.GetGitRefName() headFile := pr.GetGitRefName()
// Check if a pull request is merged into BaseBranch // Check if a pull request is merged into BaseBranch
_, err = git.NewCommand(ctx, "merge-base", "--is-ancestor", headFile, pr.BaseBranch). _, _, err = git.NewCommand(ctx, "merge-base", "--is-ancestor", headFile, pr.BaseBranch).
RunInDirWithEnv(pr.BaseRepo.RepoPath(), []string{"GIT_INDEX_FILE=" + indexTmpPath, "GIT_DIR=" + pr.BaseRepo.RepoPath()}) RunStdString(&git.RunOpts{Dir: pr.BaseRepo.RepoPath(), Env: []string{"GIT_INDEX_FILE=" + indexTmpPath, "GIT_DIR=" + pr.BaseRepo.RepoPath()}})
if err != nil { if err != nil {
// Errors are signaled by a non-zero status that is not 1 // Errors are signaled by a non-zero status that is not 1
if strings.Contains(err.Error(), "exit status 1") { if strings.Contains(err.Error(), "exit status 1") {
@ -196,8 +196,8 @@ func getMergeCommit(ctx context.Context, pr *models.PullRequest) (*git.Commit, e
cmd := commitID[:40] + ".." + pr.BaseBranch cmd := commitID[:40] + ".." + pr.BaseBranch
// Get the commit from BaseBranch where the pull request got merged // Get the commit from BaseBranch where the pull request got merged
mergeCommit, err := git.NewCommand(ctx, "rev-list", "--ancestry-path", "--merges", "--reverse", cmd). mergeCommit, _, err := git.NewCommand(ctx, "rev-list", "--ancestry-path", "--merges", "--reverse", cmd).
RunInDirWithEnv("", []string{"GIT_INDEX_FILE=" + indexTmpPath, "GIT_DIR=" + pr.BaseRepo.RepoPath()}) RunStdString(&git.RunOpts{Dir: "", Env: []string{"GIT_INDEX_FILE=" + indexTmpPath, "GIT_DIR=" + pr.BaseRepo.RepoPath()}})
if err != nil { if err != nil {
return nil, fmt.Errorf("git rev-list --ancestry-path --merges --reverse: %v", err) return nil, fmt.Errorf("git rev-list --ancestry-path --merges --reverse: %v", err)
} else if len(mergeCommit) < 40 { } else if len(mergeCommit) < 40 {

@ -141,7 +141,7 @@ func rawMerge(ctx context.Context, pr *models.PullRequest, doer *user_model.User
stagingBranch := "staging" stagingBranch := "staging"
if expectedHeadCommitID != "" { if expectedHeadCommitID != "" {
trackingCommitID, err := git.NewCommand(ctx, "show-ref", "--hash", git.BranchPrefix+trackingBranch).RunInDir(tmpBasePath) trackingCommitID, _, err := git.NewCommand(ctx, "show-ref", "--hash", git.BranchPrefix+trackingBranch).RunStdString(&git.RunOpts{Dir: tmpBasePath})
if err != nil { if err != nil {
log.Error("show-ref[%s] --hash refs/heads/trackingn: %v", tmpBasePath, git.BranchPrefix+trackingBranch, err) log.Error("show-ref[%s] --hash refs/heads/trackingn: %v", tmpBasePath, git.BranchPrefix+trackingBranch, err)
return "", fmt.Errorf("getDiffTree: %v", err) return "", fmt.Errorf("getDiffTree: %v", err)
@ -188,11 +188,10 @@ func rawMerge(ctx context.Context, pr *models.PullRequest, doer *user_model.User
// Switch off LFS process (set required, clean and smudge here also) // Switch off LFS process (set required, clean and smudge here also)
if err := gitConfigCommand().AddArguments("filter.lfs.process", ""). if err := gitConfigCommand().AddArguments("filter.lfs.process", "").
RunWithContext(&git.RunContext{ Run(&git.RunOpts{
Timeout: -1, Dir: tmpBasePath,
Dir: tmpBasePath, Stdout: &outbuf,
Stdout: &outbuf, Stderr: &errbuf,
Stderr: &errbuf,
}); err != nil { }); err != nil {
log.Error("git config [filter.lfs.process -> <> ]: %v\n%s\n%s", err, outbuf.String(), errbuf.String()) log.Error("git config [filter.lfs.process -> <> ]: %v\n%s\n%s", err, outbuf.String(), errbuf.String())
return "", fmt.Errorf("git config [filter.lfs.process -> <> ]: %v\n%s\n%s", err, outbuf.String(), errbuf.String()) return "", fmt.Errorf("git config [filter.lfs.process -> <> ]: %v\n%s\n%s", err, outbuf.String(), errbuf.String())
@ -201,11 +200,10 @@ func rawMerge(ctx context.Context, pr *models.PullRequest, doer *user_model.User
errbuf.Reset() errbuf.Reset()
if err := gitConfigCommand().AddArguments("filter.lfs.required", "false"). if err := gitConfigCommand().AddArguments("filter.lfs.required", "false").
RunWithContext(&git.RunContext{ Run(&git.RunOpts{
Timeout: -1, Dir: tmpBasePath,
Dir: tmpBasePath, Stdout: &outbuf,
Stdout: &outbuf, Stderr: &errbuf,
Stderr: &errbuf,
}); err != nil { }); err != nil {
log.Error("git config [filter.lfs.required -> <false> ]: %v\n%s\n%s", err, outbuf.String(), errbuf.String()) log.Error("git config [filter.lfs.required -> <false> ]: %v\n%s\n%s", err, outbuf.String(), errbuf.String())
return "", fmt.Errorf("git config [filter.lfs.required -> <false> ]: %v\n%s\n%s", err, outbuf.String(), errbuf.String()) return "", fmt.Errorf("git config [filter.lfs.required -> <false> ]: %v\n%s\n%s", err, outbuf.String(), errbuf.String())
@ -214,11 +212,10 @@ func rawMerge(ctx context.Context, pr *models.PullRequest, doer *user_model.User
errbuf.Reset() errbuf.Reset()
if err := gitConfigCommand().AddArguments("filter.lfs.clean", ""). if err := gitConfigCommand().AddArguments("filter.lfs.clean", "").
RunWithContext(&git.RunContext{ Run(&git.RunOpts{
Timeout: -1, Dir: tmpBasePath,
Dir: tmpBasePath, Stdout: &outbuf,
Stdout: &outbuf, Stderr: &errbuf,
Stderr: &errbuf,
}); err != nil { }); err != nil {
log.Error("git config [filter.lfs.clean -> <> ]: %v\n%s\n%s", err, outbuf.String(), errbuf.String()) log.Error("git config [filter.lfs.clean -> <> ]: %v\n%s\n%s", err, outbuf.String(), errbuf.String())
return "", fmt.Errorf("git config [filter.lfs.clean -> <> ]: %v\n%s\n%s", err, outbuf.String(), errbuf.String()) return "", fmt.Errorf("git config [filter.lfs.clean -> <> ]: %v\n%s\n%s", err, outbuf.String(), errbuf.String())
@ -227,11 +224,10 @@ func rawMerge(ctx context.Context, pr *models.PullRequest, doer *user_model.User
errbuf.Reset() errbuf.Reset()
if err := gitConfigCommand().AddArguments("filter.lfs.smudge", ""). if err := gitConfigCommand().AddArguments("filter.lfs.smudge", "").
RunWithContext(&git.RunContext{ Run(&git.RunOpts{
Timeout: -1, Dir: tmpBasePath,
Dir: tmpBasePath, Stdout: &outbuf,
Stdout: &outbuf, Stderr: &errbuf,
Stderr: &errbuf,
}); err != nil { }); err != nil {
log.Error("git config [filter.lfs.smudge -> <> ]: %v\n%s\n%s", err, outbuf.String(), errbuf.String()) log.Error("git config [filter.lfs.smudge -> <> ]: %v\n%s\n%s", err, outbuf.String(), errbuf.String())
return "", fmt.Errorf("git config [filter.lfs.smudge -> <> ]: %v\n%s\n%s", err, outbuf.String(), errbuf.String()) return "", fmt.Errorf("git config [filter.lfs.smudge -> <> ]: %v\n%s\n%s", err, outbuf.String(), errbuf.String())
@ -240,11 +236,10 @@ func rawMerge(ctx context.Context, pr *models.PullRequest, doer *user_model.User
errbuf.Reset() errbuf.Reset()
if err := gitConfigCommand().AddArguments("core.sparseCheckout", "true"). if err := gitConfigCommand().AddArguments("core.sparseCheckout", "true").
RunWithContext(&git.RunContext{ Run(&git.RunOpts{
Timeout: -1, Dir: tmpBasePath,
Dir: tmpBasePath, Stdout: &outbuf,
Stdout: &outbuf, Stderr: &errbuf,
Stderr: &errbuf,
}); err != nil { }); err != nil {
log.Error("git config [core.sparseCheckout -> true ]: %v\n%s\n%s", err, outbuf.String(), errbuf.String()) log.Error("git config [core.sparseCheckout -> true ]: %v\n%s\n%s", err, outbuf.String(), errbuf.String())
return "", fmt.Errorf("git config [core.sparsecheckout -> true]: %v\n%s\n%s", err, outbuf.String(), errbuf.String()) return "", fmt.Errorf("git config [core.sparsecheckout -> true]: %v\n%s\n%s", err, outbuf.String(), errbuf.String())
@ -254,11 +249,10 @@ func rawMerge(ctx context.Context, pr *models.PullRequest, doer *user_model.User
// Read base branch index // Read base branch index
if err := git.NewCommand(ctx, "read-tree", "HEAD"). if err := git.NewCommand(ctx, "read-tree", "HEAD").
RunWithContext(&git.RunContext{ Run(&git.RunOpts{
Timeout: -1, Dir: tmpBasePath,
Dir: tmpBasePath, Stdout: &outbuf,
Stdout: &outbuf, Stderr: &errbuf,
Stderr: &errbuf,
}); err != nil { }); err != nil {
log.Error("git read-tree HEAD: %v\n%s\n%s", err, outbuf.String(), errbuf.String()) log.Error("git read-tree HEAD: %v\n%s\n%s", err, outbuf.String(), errbuf.String())
return "", fmt.Errorf("Unable to read base branch in to the index: %v\n%s\n%s", err, outbuf.String(), errbuf.String()) return "", fmt.Errorf("Unable to read base branch in to the index: %v\n%s\n%s", err, outbuf.String(), errbuf.String())
@ -315,11 +309,10 @@ func rawMerge(ctx context.Context, pr *models.PullRequest, doer *user_model.User
case repo_model.MergeStyleRebaseMerge: case repo_model.MergeStyleRebaseMerge:
// Checkout head branch // Checkout head branch
if err := git.NewCommand(ctx, "checkout", "-b", stagingBranch, trackingBranch). if err := git.NewCommand(ctx, "checkout", "-b", stagingBranch, trackingBranch).
RunWithContext(&git.RunContext{ Run(&git.RunOpts{
Timeout: -1, Dir: tmpBasePath,
Dir: tmpBasePath, Stdout: &outbuf,
Stdout: &outbuf, Stderr: &errbuf,
Stderr: &errbuf,
}); err != nil { }); err != nil {
log.Error("git checkout base prior to merge post staging rebase [%s:%s -> %s:%s]: %v\n%s\n%s", pr.HeadRepo.FullName(), pr.HeadBranch, pr.BaseRepo.FullName(), pr.BaseBranch, err, outbuf.String(), errbuf.String()) log.Error("git checkout base prior to merge post staging rebase [%s:%s -> %s:%s]: %v\n%s\n%s", pr.HeadRepo.FullName(), pr.HeadBranch, pr.BaseRepo.FullName(), pr.BaseBranch, err, outbuf.String(), errbuf.String())
return "", fmt.Errorf("git checkout base prior to merge post staging rebase [%s:%s -> %s:%s]: %v\n%s\n%s", pr.HeadRepo.FullName(), pr.HeadBranch, pr.BaseRepo.FullName(), pr.BaseBranch, err, outbuf.String(), errbuf.String()) return "", fmt.Errorf("git checkout base prior to merge post staging rebase [%s:%s -> %s:%s]: %v\n%s\n%s", pr.HeadRepo.FullName(), pr.HeadBranch, pr.BaseRepo.FullName(), pr.BaseBranch, err, outbuf.String(), errbuf.String())
@ -329,11 +322,10 @@ func rawMerge(ctx context.Context, pr *models.PullRequest, doer *user_model.User
// Rebase before merging // Rebase before merging
if err := git.NewCommand(ctx, "rebase", baseBranch). if err := git.NewCommand(ctx, "rebase", baseBranch).
RunWithContext(&git.RunContext{ Run(&git.RunOpts{
Timeout: -1, Dir: tmpBasePath,
Dir: tmpBasePath, Stdout: &outbuf,
Stdout: &outbuf, Stderr: &errbuf,
Stderr: &errbuf,
}); err != nil { }); err != nil {
// Rebase will leave a REBASE_HEAD file in .git if there is a conflict // Rebase will leave a REBASE_HEAD file in .git if there is a conflict
if _, statErr := os.Stat(filepath.Join(tmpBasePath, ".git", "REBASE_HEAD")); statErr == nil { if _, statErr := os.Stat(filepath.Join(tmpBasePath, ".git", "REBASE_HEAD")); statErr == nil {
@ -383,11 +375,10 @@ func rawMerge(ctx context.Context, pr *models.PullRequest, doer *user_model.User
// Checkout base branch again // Checkout base branch again
if err := git.NewCommand(ctx, "checkout", baseBranch). if err := git.NewCommand(ctx, "checkout", baseBranch).
RunWithContext(&git.RunContext{ Run(&git.RunOpts{
Timeout: -1, Dir: tmpBasePath,
Dir: tmpBasePath, Stdout: &outbuf,
Stdout: &outbuf, Stderr: &errbuf,
Stderr: &errbuf,
}); err != nil { }); err != nil {
log.Error("git checkout base prior to merge post staging rebase [%s:%s -> %s:%s]: %v\n%s\n%s", pr.HeadRepo.FullName(), pr.HeadBranch, pr.BaseRepo.FullName(), pr.BaseBranch, err, outbuf.String(), errbuf.String()) log.Error("git checkout base prior to merge post staging rebase [%s:%s -> %s:%s]: %v\n%s\n%s", pr.HeadRepo.FullName(), pr.HeadBranch, pr.BaseRepo.FullName(), pr.BaseBranch, err, outbuf.String(), errbuf.String())
return "", fmt.Errorf("git checkout base prior to merge post staging rebase [%s:%s -> %s:%s]: %v\n%s\n%s", pr.HeadRepo.FullName(), pr.HeadBranch, pr.BaseRepo.FullName(), pr.BaseBranch, err, outbuf.String(), errbuf.String()) return "", fmt.Errorf("git checkout base prior to merge post staging rebase [%s:%s -> %s:%s]: %v\n%s\n%s", pr.HeadRepo.FullName(), pr.HeadBranch, pr.BaseRepo.FullName(), pr.BaseBranch, err, outbuf.String(), errbuf.String())
@ -429,12 +420,11 @@ func rawMerge(ctx context.Context, pr *models.PullRequest, doer *user_model.User
sig := pr.Issue.Poster.NewGitSig() sig := pr.Issue.Poster.NewGitSig()
if signArg == "" { if signArg == "" {
if err := git.NewCommand(ctx, "commit", fmt.Sprintf("--author='%s <%s>'", sig.Name, sig.Email), "-m", message). if err := git.NewCommand(ctx, "commit", fmt.Sprintf("--author='%s <%s>'", sig.Name, sig.Email), "-m", message).
RunWithContext(&git.RunContext{ Run(&git.RunOpts{
Env: env, Env: env,
Timeout: -1, Dir: tmpBasePath,
Dir: tmpBasePath, Stdout: &outbuf,
Stdout: &outbuf, Stderr: &errbuf,
Stderr: &errbuf,
}); err != nil { }); err != nil {
log.Error("git commit [%s:%s -> %s:%s]: %v\n%s\n%s", pr.HeadRepo.FullName(), pr.HeadBranch, pr.BaseRepo.FullName(), pr.BaseBranch, err, outbuf.String(), errbuf.String()) log.Error("git commit [%s:%s -> %s:%s]: %v\n%s\n%s", pr.HeadRepo.FullName(), pr.HeadBranch, pr.BaseRepo.FullName(), pr.BaseBranch, err, outbuf.String(), errbuf.String())
return "", fmt.Errorf("git commit [%s:%s -> %s:%s]: %v\n%s\n%s", pr.HeadRepo.FullName(), pr.HeadBranch, pr.BaseRepo.FullName(), pr.BaseBranch, err, outbuf.String(), errbuf.String()) return "", fmt.Errorf("git commit [%s:%s -> %s:%s]: %v\n%s\n%s", pr.HeadRepo.FullName(), pr.HeadBranch, pr.BaseRepo.FullName(), pr.BaseBranch, err, outbuf.String(), errbuf.String())
@ -445,12 +435,11 @@ func rawMerge(ctx context.Context, pr *models.PullRequest, doer *user_model.User
message += fmt.Sprintf("\nCo-authored-by: %s\nCo-committed-by: %s\n", sig.String(), sig.String()) message += fmt.Sprintf("\nCo-authored-by: %s\nCo-committed-by: %s\n", sig.String(), sig.String())
} }
if err := git.NewCommand(ctx, "commit", signArg, fmt.Sprintf("--author='%s <%s>'", sig.Name, sig.Email), "-m", message). if err := git.NewCommand(ctx, "commit", signArg, fmt.Sprintf("--author='%s <%s>'", sig.Name, sig.Email), "-m", message).
RunWithContext(&git.RunContext{ Run(&git.RunOpts{
Env: env, Env: env,
Timeout: -1, Dir: tmpBasePath,
Dir: tmpBasePath, Stdout: &outbuf,
Stdout: &outbuf, Stderr: &errbuf,
Stderr: &errbuf,
}); err != nil { }); err != nil {
log.Error("git commit [%s:%s -> %s:%s]: %v\n%s\n%s", pr.HeadRepo.FullName(), pr.HeadBranch, pr.BaseRepo.FullName(), pr.BaseBranch, err, outbuf.String(), errbuf.String()) log.Error("git commit [%s:%s -> %s:%s]: %v\n%s\n%s", pr.HeadRepo.FullName(), pr.HeadBranch, pr.BaseRepo.FullName(), pr.BaseBranch, err, outbuf.String(), errbuf.String())
return "", fmt.Errorf("git commit [%s:%s -> %s:%s]: %v\n%s\n%s", pr.HeadRepo.FullName(), pr.HeadBranch, pr.BaseRepo.FullName(), pr.BaseBranch, err, outbuf.String(), errbuf.String()) return "", fmt.Errorf("git commit [%s:%s -> %s:%s]: %v\n%s\n%s", pr.HeadRepo.FullName(), pr.HeadBranch, pr.BaseRepo.FullName(), pr.BaseBranch, err, outbuf.String(), errbuf.String())
@ -515,12 +504,11 @@ func rawMerge(ctx context.Context, pr *models.PullRequest, doer *user_model.User
} }
// Push back to upstream. // Push back to upstream.
if err := pushCmd.RunWithContext(&git.RunContext{ if err := pushCmd.Run(&git.RunOpts{
Env: env, Env: env,
Timeout: -1, Dir: tmpBasePath,
Dir: tmpBasePath, Stdout: &outbuf,
Stdout: &outbuf, Stderr: &errbuf,
Stderr: &errbuf,
}); err != nil { }); err != nil {
if strings.Contains(errbuf.String(), "non-fast-forward") { if strings.Contains(errbuf.String(), "non-fast-forward") {
return "", &git.ErrPushOutOfDate{ return "", &git.ErrPushOutOfDate{
@ -549,24 +537,22 @@ func commitAndSignNoAuthor(ctx context.Context, pr *models.PullRequest, message,
var outbuf, errbuf strings.Builder var outbuf, errbuf strings.Builder
if signArg == "" { if signArg == "" {
if err := git.NewCommand(ctx, "commit", "-m", message). if err := git.NewCommand(ctx, "commit", "-m", message).
RunWithContext(&git.RunContext{ Run(&git.RunOpts{
Env: env, Env: env,
Timeout: -1, Dir: tmpBasePath,
Dir: tmpBasePath, Stdout: &outbuf,
Stdout: &outbuf, Stderr: &errbuf,
Stderr: &errbuf,
}); err != nil { }); err != nil {
log.Error("git commit [%s:%s -> %s:%s]: %v\n%s\n%s", pr.HeadRepo.FullName(), pr.HeadBranch, pr.BaseRepo.FullName(), pr.BaseBranch, err, outbuf.String(), errbuf.String()) log.Error("git commit [%s:%s -> %s:%s]: %v\n%s\n%s", pr.HeadRepo.FullName(), pr.HeadBranch, pr.BaseRepo.FullName(), pr.BaseBranch, err, outbuf.String(), errbuf.String())
return fmt.Errorf("git commit [%s:%s -> %s:%s]: %v\n%s\n%s", pr.HeadRepo.FullName(), pr.HeadBranch, pr.BaseRepo.FullName(), pr.BaseBranch, err, outbuf.String(), errbuf.String()) return fmt.Errorf("git commit [%s:%s -> %s:%s]: %v\n%s\n%s", pr.HeadRepo.FullName(), pr.HeadBranch, pr.BaseRepo.FullName(), pr.BaseBranch, err, outbuf.String(), errbuf.String())
} }
} else { } else {
if err := git.NewCommand(ctx, "commit", signArg, "-m", message). if err := git.NewCommand(ctx, "commit", signArg, "-m", message).
RunWithContext(&git.RunContext{ Run(&git.RunOpts{
Env: env, Env: env,
Timeout: -1, Dir: tmpBasePath,
Dir: tmpBasePath, Stdout: &outbuf,
Stdout: &outbuf, Stderr: &errbuf,
Stderr: &errbuf,
}); err != nil { }); err != nil {
log.Error("git commit [%s:%s -> %s:%s]: %v\n%s\n%s", pr.HeadRepo.FullName(), pr.HeadBranch, pr.BaseRepo.FullName(), pr.BaseBranch, err, outbuf.String(), errbuf.String()) log.Error("git commit [%s:%s -> %s:%s]: %v\n%s\n%s", pr.HeadRepo.FullName(), pr.HeadBranch, pr.BaseRepo.FullName(), pr.BaseBranch, err, outbuf.String(), errbuf.String())
return fmt.Errorf("git commit [%s:%s -> %s:%s]: %v\n%s\n%s", pr.HeadRepo.FullName(), pr.HeadBranch, pr.BaseRepo.FullName(), pr.BaseBranch, err, outbuf.String(), errbuf.String()) return fmt.Errorf("git commit [%s:%s -> %s:%s]: %v\n%s\n%s", pr.HeadRepo.FullName(), pr.HeadBranch, pr.BaseRepo.FullName(), pr.BaseBranch, err, outbuf.String(), errbuf.String())
@ -577,11 +563,10 @@ func commitAndSignNoAuthor(ctx context.Context, pr *models.PullRequest, message,
func runMergeCommand(pr *models.PullRequest, mergeStyle repo_model.MergeStyle, cmd *git.Command, tmpBasePath string) error { func runMergeCommand(pr *models.PullRequest, mergeStyle repo_model.MergeStyle, cmd *git.Command, tmpBasePath string) error {
var outbuf, errbuf strings.Builder var outbuf, errbuf strings.Builder
if err := cmd.RunWithContext(&git.RunContext{ if err := cmd.Run(&git.RunOpts{
Timeout: -1, Dir: tmpBasePath,
Dir: tmpBasePath, Stdout: &outbuf,
Stdout: &outbuf, Stderr: &errbuf,
Stderr: &errbuf,
}); err != nil { }); err != nil {
// Merge will leave a MERGE_HEAD file in the .git folder if there is a conflict // Merge will leave a MERGE_HEAD file in the .git folder if there is a conflict
if _, statErr := os.Stat(filepath.Join(tmpBasePath, ".git", "MERGE_HEAD")); statErr == nil { if _, statErr := os.Stat(filepath.Join(tmpBasePath, ".git", "MERGE_HEAD")); statErr == nil {
@ -616,11 +601,10 @@ func getDiffTree(ctx context.Context, repoPath, baseBranch, headBranch string) (
var outbuf, errbuf strings.Builder var outbuf, errbuf strings.Builder
// Compute the diff-tree for sparse-checkout // Compute the diff-tree for sparse-checkout
if err := git.NewCommand(ctx, "diff-tree", "--no-commit-id", "--name-only", "-r", "-z", "--root", baseBranch, headBranch, "--"). if err := git.NewCommand(ctx, "diff-tree", "--no-commit-id", "--name-only", "-r", "-z", "--root", baseBranch, headBranch, "--").
RunWithContext(&git.RunContext{ Run(&git.RunOpts{
Timeout: -1, Dir: repoPath,
Dir: repoPath, Stdout: &outbuf,
Stdout: &outbuf, Stderr: &errbuf,
Stderr: &errbuf,
}); err != nil { }); err != nil {
return "", fmt.Errorf("git diff-tree [%s base:%s head:%s]: %s", repoPath, baseBranch, headBranch, errbuf.String()) return "", fmt.Errorf("git diff-tree [%s base:%s head:%s]: %s", repoPath, baseBranch, headBranch, errbuf.String())
} }

@ -76,7 +76,7 @@ func TestPatch(pr *models.PullRequest) error {
defer gitRepo.Close() defer gitRepo.Close()
// 1. update merge base // 1. update merge base
pr.MergeBase, err = git.NewCommand(ctx, "merge-base", "--", "base", "tracking").RunInDir(tmpBasePath) pr.MergeBase, _, err = git.NewCommand(ctx, "merge-base", "--", "base", "tracking").RunStdString(&git.RunOpts{Dir: tmpBasePath})
if err != nil { if err != nil {
var err2 error var err2 error
pr.MergeBase, err2 = gitRepo.GetRefCommitID(git.BranchPrefix + "base") pr.MergeBase, err2 = gitRepo.GetRefCommitID(git.BranchPrefix + "base")
@ -166,7 +166,7 @@ func attemptMerge(ctx context.Context, file *unmergedFile, tmpBasePath string, g
} }
// Need to get the objects from the object db to attempt to merge // Need to get the objects from the object db to attempt to merge
root, err := git.NewCommand(ctx, "unpack-file", file.stage1.sha).RunInDir(tmpBasePath) root, _, err := git.NewCommand(ctx, "unpack-file", file.stage1.sha).RunStdString(&git.RunOpts{Dir: tmpBasePath})
if err != nil { if err != nil {
return fmt.Errorf("unable to get root object: %s at path: %s for merging. Error: %w", file.stage1.sha, file.stage1.path, err) return fmt.Errorf("unable to get root object: %s at path: %s for merging. Error: %w", file.stage1.sha, file.stage1.path, err)
} }
@ -175,7 +175,7 @@ func attemptMerge(ctx context.Context, file *unmergedFile, tmpBasePath string, g
_ = util.Remove(filepath.Join(tmpBasePath, root)) _ = util.Remove(filepath.Join(tmpBasePath, root))
}() }()
base, err := git.NewCommand(ctx, "unpack-file", file.stage2.sha).RunInDir(tmpBasePath) base, _, err := git.NewCommand(ctx, "unpack-file", file.stage2.sha).RunStdString(&git.RunOpts{Dir: tmpBasePath})
if err != nil { if err != nil {
return fmt.Errorf("unable to get base object: %s at path: %s for merging. Error: %w", file.stage2.sha, file.stage2.path, err) return fmt.Errorf("unable to get base object: %s at path: %s for merging. Error: %w", file.stage2.sha, file.stage2.path, err)
} }
@ -183,7 +183,7 @@ func attemptMerge(ctx context.Context, file *unmergedFile, tmpBasePath string, g
defer func() { defer func() {
_ = util.Remove(base) _ = util.Remove(base)
}() }()
head, err := git.NewCommand(ctx, "unpack-file", file.stage3.sha).RunInDir(tmpBasePath) head, _, err := git.NewCommand(ctx, "unpack-file", file.stage3.sha).RunStdString(&git.RunOpts{Dir: tmpBasePath})
if err != nil { if err != nil {
return fmt.Errorf("unable to get head object:%s at path: %s for merging. Error: %w", file.stage3.sha, file.stage3.path, err) return fmt.Errorf("unable to get head object:%s at path: %s for merging. Error: %w", file.stage3.sha, file.stage3.path, err)
} }
@ -193,13 +193,13 @@ func attemptMerge(ctx context.Context, file *unmergedFile, tmpBasePath string, g
}() }()
// now git merge-file annoyingly takes a different order to the merge-tree ... // now git merge-file annoyingly takes a different order to the merge-tree ...
_, conflictErr := git.NewCommand(ctx, "merge-file", base, root, head).RunInDir(tmpBasePath) _, _, conflictErr := git.NewCommand(ctx, "merge-file", base, root, head).RunStdString(&git.RunOpts{Dir: tmpBasePath})
if conflictErr != nil { if conflictErr != nil {
return &errMergeConflict{file.stage2.path} return &errMergeConflict{file.stage2.path}
} }
// base now contains the merged data // base now contains the merged data
hash, err := git.NewCommand(ctx, "hash-object", "-w", "--path", file.stage2.path, base).RunInDir(tmpBasePath) hash, _, err := git.NewCommand(ctx, "hash-object", "-w", "--path", file.stage2.path, base).RunStdString(&git.RunOpts{Dir: tmpBasePath})
if err != nil { if err != nil {
return err return err
} }
@ -223,7 +223,7 @@ func AttemptThreeWayMerge(ctx context.Context, gitPath string, gitRepo *git.Repo
defer cancel() defer cancel()
// First we use read-tree to do a simple three-way merge // First we use read-tree to do a simple three-way merge
if _, err := git.NewCommand(ctx, "read-tree", "-m", base, ours, theirs).RunInDir(gitPath); err != nil { if _, _, err := git.NewCommand(ctx, "read-tree", "-m", base, ours, theirs).RunStdString(&git.RunOpts{Dir: gitPath}); err != nil {
log.Error("Unable to run read-tree -m! Error: %v", err) log.Error("Unable to run read-tree -m! Error: %v", err)
return false, nil, fmt.Errorf("unable to run read-tree -m! Error: %v", err) return false, nil, fmt.Errorf("unable to run read-tree -m! Error: %v", err)
} }
@ -282,7 +282,8 @@ func checkConflicts(ctx context.Context, pr *models.PullRequest, gitRepo *git.Re
} }
if !conflict { if !conflict {
treeHash, err := git.NewCommand(ctx, "write-tree").RunInDir(tmpBasePath) var treeHash string
treeHash, _, err = git.NewCommand(ctx, "write-tree").RunStdString(&git.RunOpts{Dir: tmpBasePath})
if err != nil { if err != nil {
return false, err return false, err
} }
@ -334,7 +335,7 @@ func checkConflicts(ctx context.Context, pr *models.PullRequest, gitRepo *git.Re
log.Trace("PullRequest[%d].testPatch (patchPath): %s", pr.ID, patchPath) log.Trace("PullRequest[%d].testPatch (patchPath): %s", pr.ID, patchPath)
// 4. Read the base branch in to the index of the temporary repository // 4. Read the base branch in to the index of the temporary repository
_, err = git.NewCommand(gitRepo.Ctx, "read-tree", "base").RunInDir(tmpBasePath) _, _, err = git.NewCommand(gitRepo.Ctx, "read-tree", "base").RunStdString(&git.RunOpts{Dir: tmpBasePath})
if err != nil { if err != nil {
return false, fmt.Errorf("git read-tree %s: %v", pr.BaseBranch, err) return false, fmt.Errorf("git read-tree %s: %v", pr.BaseBranch, err)
} }
@ -379,10 +380,9 @@ func checkConflicts(ctx context.Context, pr *models.PullRequest, gitRepo *git.Re
// 8. Run the check command // 8. Run the check command
conflict = false conflict = false
err = git.NewCommand(gitRepo.Ctx, args...). err = git.NewCommand(gitRepo.Ctx, args...).
RunWithContext(&git.RunContext{ Run(&git.RunOpts{
Timeout: -1, Dir: tmpBasePath,
Dir: tmpBasePath, Stderr: stderrWriter,
Stderr: stderrWriter,
PipelineFunc: func(ctx context.Context, cancel context.CancelFunc) error { PipelineFunc: func(ctx context.Context, cancel context.CancelFunc) error {
// Close the writer end of the pipe to begin processing // Close the writer end of the pipe to begin processing
_ = stderrWriter.Close() _ = stderrWriter.Close()

@ -63,11 +63,10 @@ func readUnmergedLsFileLines(ctx context.Context, tmpBasePath string, outputChan
stderr := &strings.Builder{} stderr := &strings.Builder{}
err = git.NewCommand(ctx, "ls-files", "-u", "-z"). err = git.NewCommand(ctx, "ls-files", "-u", "-z").
RunWithContext(&git.RunContext{ Run(&git.RunOpts{
Timeout: -1, Dir: tmpBasePath,
Dir: tmpBasePath, Stdout: lsFilesWriter,
Stdout: lsFilesWriter, Stderr: stderr,
Stderr: stderr,
PipelineFunc: func(_ context.Context, _ context.CancelFunc) error { PipelineFunc: func(_ context.Context, _ context.CancelFunc) error {
_ = lsFilesWriter.Close() _ = lsFilesWriter.Close()
defer func() { defer func() {

@ -479,7 +479,7 @@ func UpdateRef(ctx context.Context, pr *models.PullRequest) (err error) {
return err return err
} }
_, err = git.NewCommand(ctx, "update-ref", pr.GetGitRefName(), pr.HeadCommitID).RunInDir(pr.BaseRepo.RepoPath()) _, _, err = git.NewCommand(ctx, "update-ref", pr.GetGitRefName(), pr.HeadCommitID).RunStdString(&git.RunOpts{Dir: pr.BaseRepo.RepoPath()})
if err != nil { if err != nil {
log.Error("Unable to update ref in base repository for PR[%d] Error: %v", pr.ID, err) log.Error("Unable to update ref in base repository for PR[%d] Error: %v", pr.ID, err)
} }

@ -93,11 +93,10 @@ func createTemporaryRepo(ctx context.Context, pr *models.PullRequest) (string, e
var outbuf, errbuf strings.Builder var outbuf, errbuf strings.Builder
if err := git.NewCommand(ctx, "remote", "add", "-t", pr.BaseBranch, "-m", pr.BaseBranch, "origin", baseRepoPath). if err := git.NewCommand(ctx, "remote", "add", "-t", pr.BaseBranch, "-m", pr.BaseBranch, "origin", baseRepoPath).
RunWithContext(&git.RunContext{ Run(&git.RunOpts{
Timeout: -1, Dir: tmpBasePath,
Dir: tmpBasePath, Stdout: &outbuf,
Stdout: &outbuf, Stderr: &errbuf,
Stderr: &errbuf,
}); err != nil { }); err != nil {
log.Error("Unable to add base repository as origin [%s -> %s]: %v\n%s\n%s", pr.BaseRepo.FullName(), tmpBasePath, err, outbuf.String(), errbuf.String()) log.Error("Unable to add base repository as origin [%s -> %s]: %v\n%s\n%s", pr.BaseRepo.FullName(), tmpBasePath, err, outbuf.String(), errbuf.String())
if err := models.RemoveTemporaryPath(tmpBasePath); err != nil { if err := models.RemoveTemporaryPath(tmpBasePath); err != nil {
@ -109,11 +108,10 @@ func createTemporaryRepo(ctx context.Context, pr *models.PullRequest) (string, e
errbuf.Reset() errbuf.Reset()
if err := git.NewCommand(ctx, "fetch", "origin", "--no-tags", "--", pr.BaseBranch+":"+baseBranch, pr.BaseBranch+":original_"+baseBranch). if err := git.NewCommand(ctx, "fetch", "origin", "--no-tags", "--", pr.BaseBranch+":"+baseBranch, pr.BaseBranch+":original_"+baseBranch).
RunWithContext(&git.RunContext{ Run(&git.RunOpts{
Timeout: -1, Dir: tmpBasePath,
Dir: tmpBasePath, Stdout: &outbuf,
Stdout: &outbuf, Stderr: &errbuf,
Stderr: &errbuf,
}); err != nil { }); err != nil {
log.Error("Unable to fetch origin base branch [%s:%s -> base, original_base in %s]: %v:\n%s\n%s", pr.BaseRepo.FullName(), pr.BaseBranch, tmpBasePath, err, outbuf.String(), errbuf.String()) log.Error("Unable to fetch origin base branch [%s:%s -> base, original_base in %s]: %v:\n%s\n%s", pr.BaseRepo.FullName(), pr.BaseBranch, tmpBasePath, err, outbuf.String(), errbuf.String())
if err := models.RemoveTemporaryPath(tmpBasePath); err != nil { if err := models.RemoveTemporaryPath(tmpBasePath); err != nil {
@ -125,11 +123,10 @@ func createTemporaryRepo(ctx context.Context, pr *models.PullRequest) (string, e
errbuf.Reset() errbuf.Reset()
if err := git.NewCommand(ctx, "symbolic-ref", "HEAD", git.BranchPrefix+baseBranch). if err := git.NewCommand(ctx, "symbolic-ref", "HEAD", git.BranchPrefix+baseBranch).
RunWithContext(&git.RunContext{ Run(&git.RunOpts{
Timeout: -1, Dir: tmpBasePath,
Dir: tmpBasePath, Stdout: &outbuf,
Stdout: &outbuf, Stderr: &errbuf,
Stderr: &errbuf,
}); err != nil { }); err != nil {
log.Error("Unable to set HEAD as base branch [%s]: %v\n%s\n%s", tmpBasePath, err, outbuf.String(), errbuf.String()) log.Error("Unable to set HEAD as base branch [%s]: %v\n%s\n%s", tmpBasePath, err, outbuf.String(), errbuf.String())
if err := models.RemoveTemporaryPath(tmpBasePath); err != nil { if err := models.RemoveTemporaryPath(tmpBasePath); err != nil {
@ -149,11 +146,10 @@ func createTemporaryRepo(ctx context.Context, pr *models.PullRequest) (string, e
} }
if err := git.NewCommand(ctx, "remote", "add", remoteRepoName, headRepoPath). if err := git.NewCommand(ctx, "remote", "add", remoteRepoName, headRepoPath).
RunWithContext(&git.RunContext{ Run(&git.RunOpts{
Timeout: -1, Dir: tmpBasePath,
Dir: tmpBasePath, Stdout: &outbuf,
Stdout: &outbuf, Stderr: &errbuf,
Stderr: &errbuf,
}); err != nil { }); err != nil {
log.Error("Unable to add head repository as head_repo [%s -> %s]: %v\n%s\n%s", pr.HeadRepo.FullName(), tmpBasePath, err, outbuf.String(), errbuf.String()) log.Error("Unable to add head repository as head_repo [%s -> %s]: %v\n%s\n%s", pr.HeadRepo.FullName(), tmpBasePath, err, outbuf.String(), errbuf.String())
if err := models.RemoveTemporaryPath(tmpBasePath); err != nil { if err := models.RemoveTemporaryPath(tmpBasePath); err != nil {
@ -175,11 +171,10 @@ func createTemporaryRepo(ctx context.Context, pr *models.PullRequest) (string, e
headBranch = pr.GetGitRefName() headBranch = pr.GetGitRefName()
} }
if err := git.NewCommand(ctx, "fetch", "--no-tags", remoteRepoName, headBranch+":"+trackingBranch). if err := git.NewCommand(ctx, "fetch", "--no-tags", remoteRepoName, headBranch+":"+trackingBranch).
RunWithContext(&git.RunContext{ Run(&git.RunOpts{
Timeout: -1, Dir: tmpBasePath,
Dir: tmpBasePath, Stdout: &outbuf,
Stdout: &outbuf, Stderr: &errbuf,
Stderr: &errbuf,
}); err != nil { }); err != nil {
if err := models.RemoveTemporaryPath(tmpBasePath); err != nil { if err := models.RemoveTemporaryPath(tmpBasePath); err != nil {
log.Error("CreateTempRepo: RemoveTemporaryPath: %s", err) log.Error("CreateTempRepo: RemoveTemporaryPath: %s", err)

@ -297,9 +297,9 @@ func DeleteReleaseByID(ctx context.Context, id int64, doer *user_model.User, del
} }
if delTag { if delTag {
if stdout, err := git.NewCommand(ctx, "tag", "-d", rel.TagName). if stdout, _, err := git.NewCommand(ctx, "tag", "-d", rel.TagName).
SetDescription(fmt.Sprintf("DeleteReleaseByID (git tag -d): %d", rel.ID)). SetDescription(fmt.Sprintf("DeleteReleaseByID (git tag -d): %d", rel.ID)).
RunInDir(repo.RepoPath()); err != nil && !strings.Contains(err.Error(), "not found") { RunStdString(&git.RunOpts{Dir: repo.RepoPath()}); err != nil && !strings.Contains(err.Error(), "not found") {
log.Error("DeleteReleaseByID (git tag -d): %d in %v Failed:\nStdout: %s\nError: %v", rel.ID, repo, stdout, err) log.Error("DeleteReleaseByID (git tag -d): %d in %v Failed:\nStdout: %s\nError: %v", rel.ID, repo, stdout, err)
return fmt.Errorf("git tag -d: %v", err) return fmt.Errorf("git tag -d: %v", err)
} }

@ -84,9 +84,9 @@ func AdoptRepository(doer, u *user_model.User, opts models.CreateRepoOptions) (*
} }
} }
if stdout, err := git.NewCommand(ctx, "update-server-info"). if stdout, _, err := git.NewCommand(ctx, "update-server-info").
SetDescription(fmt.Sprintf("CreateRepository(git update-server-info): %s", repoPath)). SetDescription(fmt.Sprintf("CreateRepository(git update-server-info): %s", repoPath)).
RunInDir(repoPath); err != nil { RunStdString(&git.RunOpts{Dir: repoPath}); err != nil {
log.Error("CreateRepository(git update-server-info) in %v: Stdout: %s\nError: %v", repo, stdout, err) log.Error("CreateRepository(git update-server-info) in %v: Stdout: %s\nError: %v", repo, stdout, err)
return fmt.Errorf("CreateRepository(git update-server-info): %v", err) return fmt.Errorf("CreateRepository(git update-server-info): %v", err)
} }

@ -77,7 +77,7 @@ func GitGcRepos(ctx context.Context, timeout time.Duration, args ...string) erro
SetDescription(fmt.Sprintf("Repository Garbage Collection: %s", repo.FullName())) SetDescription(fmt.Sprintf("Repository Garbage Collection: %s", repo.FullName()))
var stdout string var stdout string
var err error var err error
stdout, _, err = command.RunWithContextString(&git.RunContext{Timeout: timeout, Dir: repo.RepoPath()}) stdout, _, err = command.RunStdString(&git.RunOpts{Timeout: timeout, Dir: repo.RepoPath()})
if err != nil { if err != nil {
log.Error("Repository garbage collection failed for %v. Stdout: %s\nError: %v", repo, stdout, err) log.Error("Repository garbage collection failed for %v. Stdout: %s\nError: %v", repo, stdout, err)

@ -145,12 +145,11 @@ func ApplyDiffPatch(ctx context.Context, repo *repo_model.Repository, doer *user
} }
cmd := git.NewCommand(ctx, args...) cmd := git.NewCommand(ctx, args...)
if err := cmd.RunWithContext(&git.RunContext{ if err := cmd.Run(&git.RunOpts{
Timeout: -1, Dir: t.basePath,
Dir: t.basePath, Stdout: stdout,
Stdout: stdout, Stderr: stderr,
Stderr: stderr, Stdin: strings.NewReader(opts.Content),
Stdin: strings.NewReader(opts.Content),
}); err != nil { }); err != nil {
return nil, fmt.Errorf("Error: Stdout: %s\nStderr: %s\nErr: %v", stdout.String(), stderr.String(), err) return nil, fmt.Errorf("Error: Stdout: %s\nStderr: %s\nErr: %v", stdout.String(), stderr.String(), err)
} }

@ -52,7 +52,7 @@ func (t *TemporaryUploadRepository) Close() {
// Clone the base repository to our path and set branch as the HEAD // Clone the base repository to our path and set branch as the HEAD
func (t *TemporaryUploadRepository) Clone(branch string) error { func (t *TemporaryUploadRepository) Clone(branch string) error {
if _, err := git.NewCommand(t.ctx, "clone", "-s", "--bare", "-b", branch, t.repo.RepoPath(), t.basePath).Run(); err != nil { if _, _, err := git.NewCommand(t.ctx, "clone", "-s", "--bare", "-b", branch, t.repo.RepoPath(), t.basePath).RunStdString(nil); err != nil {
stderr := err.Error() stderr := err.Error()
if matched, _ := regexp.MatchString(".*Remote branch .* not found in upstream origin.*", stderr); matched { if matched, _ := regexp.MatchString(".*Remote branch .* not found in upstream origin.*", stderr); matched {
return git.ErrBranchNotExist{ return git.ErrBranchNotExist{
@ -92,7 +92,7 @@ func (t *TemporaryUploadRepository) Init() error {
// SetDefaultIndex sets the git index to our HEAD // SetDefaultIndex sets the git index to our HEAD
func (t *TemporaryUploadRepository) SetDefaultIndex() error { func (t *TemporaryUploadRepository) SetDefaultIndex() error {
if _, err := git.NewCommand(t.ctx, "read-tree", "HEAD").RunInDir(t.basePath); err != nil { if _, _, err := git.NewCommand(t.ctx, "read-tree", "HEAD").RunStdString(&git.RunOpts{Dir: t.basePath}); err != nil {
return fmt.Errorf("SetDefaultIndex: %v", err) return fmt.Errorf("SetDefaultIndex: %v", err)
} }
return nil return nil
@ -111,11 +111,10 @@ func (t *TemporaryUploadRepository) LsFiles(filenames ...string) ([]string, erro
} }
if err := git.NewCommand(t.ctx, cmdArgs...). if err := git.NewCommand(t.ctx, cmdArgs...).
RunWithContext(&git.RunContext{ Run(&git.RunOpts{
Timeout: -1, Dir: t.basePath,
Dir: t.basePath, Stdout: stdOut,
Stdout: stdOut, Stderr: stdErr,
Stderr: stdErr,
}); err != nil { }); err != nil {
log.Error("Unable to run git ls-files for temporary repo: %s (%s) Error: %v\nstdout: %s\nstderr: %s", t.repo.FullName(), t.basePath, err, stdOut.String(), stdErr.String()) log.Error("Unable to run git ls-files for temporary repo: %s (%s) Error: %v\nstdout: %s\nstderr: %s", t.repo.FullName(), t.basePath, err, stdOut.String(), stdErr.String())
err = fmt.Errorf("Unable to run git ls-files for temporary repo of: %s Error: %v\nstdout: %s\nstderr: %s", t.repo.FullName(), err, stdOut.String(), stdErr.String()) err = fmt.Errorf("Unable to run git ls-files for temporary repo of: %s Error: %v\nstdout: %s\nstderr: %s", t.repo.FullName(), err, stdOut.String(), stdErr.String())
@ -144,12 +143,11 @@ func (t *TemporaryUploadRepository) RemoveFilesFromIndex(filenames ...string) er
} }
if err := git.NewCommand(t.ctx, "update-index", "--remove", "-z", "--index-info"). if err := git.NewCommand(t.ctx, "update-index", "--remove", "-z", "--index-info").
RunWithContext(&git.RunContext{ Run(&git.RunOpts{
Timeout: -1, Dir: t.basePath,
Dir: t.basePath, Stdin: stdIn,
Stdin: stdIn, Stdout: stdOut,
Stdout: stdOut, Stderr: stdErr,
Stderr: stdErr,
}); err != nil { }); err != nil {
log.Error("Unable to update-index for temporary repo: %s (%s) Error: %v\nstdout: %s\nstderr: %s", t.repo.FullName(), t.basePath, err, stdOut.String(), stdErr.String()) log.Error("Unable to update-index for temporary repo: %s (%s) Error: %v\nstdout: %s\nstderr: %s", t.repo.FullName(), t.basePath, err, stdOut.String(), stdErr.String())
return fmt.Errorf("Unable to update-index for temporary repo: %s Error: %v\nstdout: %s\nstderr: %s", t.repo.FullName(), err, stdOut.String(), stdErr.String()) return fmt.Errorf("Unable to update-index for temporary repo: %s Error: %v\nstdout: %s\nstderr: %s", t.repo.FullName(), err, stdOut.String(), stdErr.String())
@ -163,12 +161,11 @@ func (t *TemporaryUploadRepository) HashObject(content io.Reader) (string, error
stdErr := new(bytes.Buffer) stdErr := new(bytes.Buffer)
if err := git.NewCommand(t.ctx, "hash-object", "-w", "--stdin"). if err := git.NewCommand(t.ctx, "hash-object", "-w", "--stdin").
RunWithContext(&git.RunContext{ Run(&git.RunOpts{
Timeout: -1, Dir: t.basePath,
Dir: t.basePath, Stdin: content,
Stdin: content, Stdout: stdOut,
Stdout: stdOut, Stderr: stdErr,
Stderr: stdErr,
}); err != nil { }); err != nil {
log.Error("Unable to hash-object to temporary repo: %s (%s) Error: %v\nstdout: %s\nstderr: %s", t.repo.FullName(), t.basePath, err, stdOut.String(), stdErr.String()) log.Error("Unable to hash-object to temporary repo: %s (%s) Error: %v\nstdout: %s\nstderr: %s", t.repo.FullName(), t.basePath, err, stdOut.String(), stdErr.String())
return "", fmt.Errorf("Unable to hash-object to temporary repo: %s Error: %v\nstdout: %s\nstderr: %s", t.repo.FullName(), err, stdOut.String(), stdErr.String()) return "", fmt.Errorf("Unable to hash-object to temporary repo: %s Error: %v\nstdout: %s\nstderr: %s", t.repo.FullName(), err, stdOut.String(), stdErr.String())
@ -179,7 +176,7 @@ func (t *TemporaryUploadRepository) HashObject(content io.Reader) (string, error
// AddObjectToIndex adds the provided object hash to the index with the provided mode and path // AddObjectToIndex adds the provided object hash to the index with the provided mode and path
func (t *TemporaryUploadRepository) AddObjectToIndex(mode, objectHash, objectPath string) error { func (t *TemporaryUploadRepository) AddObjectToIndex(mode, objectHash, objectPath string) error {
if _, err := git.NewCommand(t.ctx, "update-index", "--add", "--replace", "--cacheinfo", mode, objectHash, objectPath).RunInDir(t.basePath); err != nil { if _, _, err := git.NewCommand(t.ctx, "update-index", "--add", "--replace", "--cacheinfo", mode, objectHash, objectPath).RunStdString(&git.RunOpts{Dir: t.basePath}); err != nil {
stderr := err.Error() stderr := err.Error()
if matched, _ := regexp.MatchString(".*Invalid path '.*", stderr); matched { if matched, _ := regexp.MatchString(".*Invalid path '.*", stderr); matched {
return models.ErrFilePathInvalid{ return models.ErrFilePathInvalid{
@ -195,7 +192,7 @@ func (t *TemporaryUploadRepository) AddObjectToIndex(mode, objectHash, objectPat
// WriteTree writes the current index as a tree to the object db and returns its hash // WriteTree writes the current index as a tree to the object db and returns its hash
func (t *TemporaryUploadRepository) WriteTree() (string, error) { func (t *TemporaryUploadRepository) WriteTree() (string, error) {
stdout, err := git.NewCommand(t.ctx, "write-tree").RunInDir(t.basePath) stdout, _, err := git.NewCommand(t.ctx, "write-tree").RunStdString(&git.RunOpts{Dir: t.basePath})
if err != nil { if err != nil {
log.Error("Unable to write tree in temporary repo: %s(%s): Error: %v", t.repo.FullName(), t.basePath, err) log.Error("Unable to write tree in temporary repo: %s(%s): Error: %v", t.repo.FullName(), t.basePath, err)
return "", fmt.Errorf("Unable to write-tree in temporary repo for: %s Error: %v", t.repo.FullName(), err) return "", fmt.Errorf("Unable to write-tree in temporary repo for: %s Error: %v", t.repo.FullName(), err)
@ -213,7 +210,7 @@ func (t *TemporaryUploadRepository) GetLastCommitByRef(ref string) (string, erro
if ref == "" { if ref == "" {
ref = "HEAD" ref = "HEAD"
} }
stdout, err := git.NewCommand(t.ctx, "rev-parse", ref).RunInDir(t.basePath) stdout, _, err := git.NewCommand(t.ctx, "rev-parse", ref).RunStdString(&git.RunOpts{Dir: t.basePath})
if err != nil { if err != nil {
log.Error("Unable to get last ref for %s in temporary repo: %s(%s): Error: %v", ref, t.repo.FullName(), t.basePath, err) log.Error("Unable to get last ref for %s in temporary repo: %s(%s): Error: %v", ref, t.repo.FullName(), t.basePath, err)
return "", fmt.Errorf("Unable to rev-parse %s in temporary repo for: %s Error: %v", ref, t.repo.FullName(), err) return "", fmt.Errorf("Unable to rev-parse %s in temporary repo for: %s Error: %v", ref, t.repo.FullName(), err)
@ -300,13 +297,12 @@ func (t *TemporaryUploadRepository) CommitTreeWithDate(parent string, author, co
stdout := new(bytes.Buffer) stdout := new(bytes.Buffer)
stderr := new(bytes.Buffer) stderr := new(bytes.Buffer)
if err := git.NewCommand(t.ctx, args...). if err := git.NewCommand(t.ctx, args...).
RunWithContext(&git.RunContext{ Run(&git.RunOpts{
Env: env, Env: env,
Timeout: -1, Dir: t.basePath,
Dir: t.basePath, Stdin: messageBytes,
Stdin: messageBytes, Stdout: stdout,
Stdout: stdout, Stderr: stderr,
Stderr: stderr,
}); err != nil { }); err != nil {
log.Error("Unable to commit-tree in temporary repo: %s (%s) Error: %v\nStdout: %s\nStderr: %s", log.Error("Unable to commit-tree in temporary repo: %s (%s) Error: %v\nStdout: %s\nStderr: %s",
t.repo.FullName(), t.basePath, err, stdout, stderr) t.repo.FullName(), t.basePath, err, stdout, stderr)
@ -357,7 +353,7 @@ func (t *TemporaryUploadRepository) DiffIndex() (*gitdiff.Diff, error) {
var finalErr error var finalErr error
if err := git.NewCommand(t.ctx, "diff-index", "--src-prefix=\\a/", "--dst-prefix=\\b/", "--cached", "-p", "HEAD"). if err := git.NewCommand(t.ctx, "diff-index", "--src-prefix=\\a/", "--dst-prefix=\\b/", "--cached", "-p", "HEAD").
RunWithContext(&git.RunContext{ Run(&git.RunOpts{
Timeout: 30 * time.Second, Timeout: 30 * time.Second,
Dir: t.basePath, Dir: t.basePath,
Stdout: stdoutWriter, Stdout: stdoutWriter,

@ -111,7 +111,7 @@ func ForkRepository(ctx context.Context, doer, owner *user_model.User, opts Fork
if stdout, _, err := git.NewCommand(txCtx, if stdout, _, err := git.NewCommand(txCtx,
"clone", "--bare", oldRepoPath, repoPath). "clone", "--bare", oldRepoPath, repoPath).
SetDescription(fmt.Sprintf("ForkRepository(git clone): %s to %s", opts.BaseRepo.FullName(), repo.FullName())). SetDescription(fmt.Sprintf("ForkRepository(git clone): %s to %s", opts.BaseRepo.FullName(), repo.FullName())).
RunWithContextBytes(&git.RunContext{Timeout: 10 * time.Minute}); err != nil { RunStdBytes(&git.RunOpts{Timeout: 10 * time.Minute}); err != nil {
log.Error("Fork Repository (git clone) Failed for %v (from %v):\nStdout: %s\nError: %v", repo, opts.BaseRepo, stdout, err) log.Error("Fork Repository (git clone) Failed for %v (from %v):\nStdout: %s\nError: %v", repo, opts.BaseRepo, stdout, err)
return fmt.Errorf("git clone: %v", err) return fmt.Errorf("git clone: %v", err)
} }
@ -120,9 +120,9 @@ func ForkRepository(ctx context.Context, doer, owner *user_model.User, opts Fork
return fmt.Errorf("checkDaemonExportOK: %v", err) return fmt.Errorf("checkDaemonExportOK: %v", err)
} }
if stdout, err := git.NewCommand(txCtx, "update-server-info"). if stdout, _, err := git.NewCommand(txCtx, "update-server-info").
SetDescription(fmt.Sprintf("ForkRepository(git update-server-info): %s", repo.FullName())). SetDescription(fmt.Sprintf("ForkRepository(git update-server-info): %s", repo.FullName())).
RunInDir(repoPath); err != nil { RunStdString(&git.RunOpts{Dir: repoPath}); err != nil {
log.Error("Fork Repository (git update-server-info) failed for %v:\nStdout: %s\nError: %v", repo, stdout, err) log.Error("Fork Repository (git update-server-info) failed for %v:\nStdout: %s\nError: %v", repo, stdout, err)
return fmt.Errorf("git update-server-info: %v", err) return fmt.Errorf("git update-server-info: %v", err)
} }

@ -81,7 +81,7 @@ func InitWiki(ctx context.Context, repo *repo_model.Repository) error {
return fmt.Errorf("InitRepository: %v", err) return fmt.Errorf("InitRepository: %v", err)
} else if err = repo_module.CreateDelegateHooks(repo.WikiPath()); err != nil { } else if err = repo_module.CreateDelegateHooks(repo.WikiPath()); err != nil {
return fmt.Errorf("createDelegateHooks: %v", err) return fmt.Errorf("createDelegateHooks: %v", err)
} else if _, err = git.NewCommand(ctx, "symbolic-ref", "HEAD", git.BranchPrefix+"master").RunInDir(repo.WikiPath()); err != nil { } else if _, _, err = git.NewCommand(ctx, "symbolic-ref", "HEAD", git.BranchPrefix+"master").RunStdString(&git.RunOpts{Dir: repo.WikiPath()}); err != nil {
return fmt.Errorf("unable to set default wiki branch to master: %v", err) return fmt.Errorf("unable to set default wiki branch to master: %v", err)
} }
return nil return nil

Loading…
Cancel
Save