diff options
author | wxiaoguang <wxiaoguang@gmail.com> | 2022-06-10 09:57:49 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-06-10 09:57:49 +0800 |
commit | a0051634b982608d94399033a8b76e7e3b1537ac (patch) | |
tree | 174bf860eb23c80bff16dc0e94f8d7d1a3437f0a /modules/git | |
parent | e26f84a9b75f250f951e0efa5c5c62860b3c8370 (diff) | |
download | gitea-a0051634b982608d94399033a8b76e7e3b1537ac.tar.gz gitea-a0051634b982608d94399033a8b76e7e3b1537ac.zip |
Refactor git module, make Gitea use internal git config (#19732)
* Refactor git module, make Gitea use internal git config, add safe.directory config
* introduce git.InitSimple and git.InitWithConfigSync, make serv cmd use gitconfig
* use HOME instead of GIT_CONFIG_GLOBAL, because git always needs a correct HOME
* fix cmd env in cmd/serv.go
* fine tune error message
* Fix a incorrect test case
* fix configAddNonExist
* fix configAddNonExist logic, add `--fixed-value` flag, add tests
* add configSetNonExist function in case it's needed.
* use configSetNonExist for `user.name` and `user.email`
* add some comments
* Update cmd/serv.go
Co-authored-by: zeripath <art27@cantab.net>
* Update cmd/serv.go
Co-authored-by: zeripath <art27@cantab.net>
* Update modules/git/git.go
Co-authored-by: zeripath <art27@cantab.net>
* Update modules/setting/setting.go
Co-authored-by: zeripath <art27@cantab.net>
* Update modules/git/repo_attribute.go
Co-authored-by: zeripath <art27@cantab.net>
* fix spaces in messages
* use `configSet("core.protectNTFS", ...)` instead of `globalCommandArgs`
* remove GIT_CONFIG_NOSYSTEM, continue to use system's git config
* Update cmd/serv.go
Co-authored-by: zeripath <art27@cantab.net>
* fix merge
* remove code for safe.directory
* separate git.CommonEnvs to CommonGitCmdEnvs and CommonCmdServEnvs
* avoid Golang's data race error
Co-authored-by: zeripath <art27@cantab.net>
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Diffstat (limited to 'modules/git')
-rw-r--r-- | modules/git/command.go | 40 | ||||
-rw-r--r-- | modules/git/commit.go | 5 | ||||
-rw-r--r-- | modules/git/git.go | 229 | ||||
-rw-r--r-- | modules/git/git_test.go | 67 | ||||
-rw-r--r-- | modules/git/lfs.go | 6 | ||||
-rw-r--r-- | modules/git/remote.go | 4 | ||||
-rw-r--r-- | modules/git/repo_attribute.go | 7 | ||||
-rw-r--r-- | modules/git/repo_tree.go | 8 |
8 files changed, 229 insertions, 137 deletions
diff --git a/modules/git/command.go b/modules/git/command.go index f6344dbfd1..d71497f1d7 100644 --- a/modules/git/command.go +++ b/modules/git/command.go @@ -8,6 +8,7 @@ package git import ( "bytes" "context" + "errors" "fmt" "io" "os" @@ -104,6 +105,25 @@ type RunOpts struct { PipelineFunc func(context.Context, context.CancelFunc) error } +// CommonGitCmdEnvs returns the common environment variables for a "git" command. +func CommonGitCmdEnvs() []string { + // at the moment, do not set "GIT_CONFIG_NOSYSTEM", users may have put some configs like "receive.certNonceSeed" in it + return []string{ + fmt.Sprintf("LC_ALL=%s", DefaultLocale), + "GIT_TERMINAL_PROMPT=0", // avoid prompting for credentials interactively, supported since git v2.3 + "GIT_NO_REPLACE_OBJECTS=1", // ignore replace references (https://git-scm.com/docs/git-replace) + "HOME=" + HomeDir(), // make Gitea use internal git config only, to prevent conflicts with user's git config + } +} + +// CommonCmdServEnvs is like CommonGitCmdEnvs but it only returns minimal required environment variables for the "gitea serv" command +func CommonCmdServEnvs() []string { + return []string{ + "GIT_NO_REPLACE_OBJECTS=1", // ignore replace references (https://git-scm.com/docs/git-replace) + "HOME=" + HomeDir(), // make Gitea use internal git config only, to prevent conflicts with user's git config + } +} + // Run runs the command with the RunOpts func (c *Command) Run(opts *RunOpts) error { if opts == nil { @@ -148,16 +168,8 @@ func (c *Command) Run(opts *RunOpts) error { cmd.Env = opts.Env } - cmd.Env = append( - cmd.Env, - fmt.Sprintf("LC_ALL=%s", DefaultLocale), - // avoid prompting for credentials interactively, supported since git v2.3 - "GIT_TERMINAL_PROMPT=0", - // ignore replace references (https://git-scm.com/docs/git-replace) - "GIT_NO_REPLACE_OBJECTS=1", - ) - process.SetSysProcAttribute(cmd) + cmd.Env = append(cmd.Env, CommonGitCmdEnvs()...) cmd.Dir = opts.Dir cmd.Stdout = opts.Stdout cmd.Stderr = opts.Stderr @@ -184,7 +196,9 @@ func (c *Command) Run(opts *RunOpts) error { type RunStdError interface { error + Unwrap() error Stderr() string + IsExitCode(code int) bool } type runStdError struct { @@ -209,6 +223,14 @@ func (r *runStdError) Stderr() string { return r.stderr } +func (r *runStdError) IsExitCode(code int) bool { + var exitError *exec.ExitError + if errors.As(r.err, &exitError) { + return exitError.ExitCode() == code + } + return false +} + func bytesToString(b []byte) string { return *(*string)(unsafe.Pointer(&b)) // that's what Golang's strings.Builder.String() does (go/src/strings/builder.go) } diff --git a/modules/git/commit.go b/modules/git/commit.go index 8c194ef502..99fbbd0cfc 100644 --- a/modules/git/commit.go +++ b/modules/git/commit.go @@ -398,11 +398,6 @@ func (c *Commit) GetSubModule(entryname string) (*SubModule, error) { // GetBranchName gets the closest branch name (as returned by 'git name-rev --name-only') func (c *Commit) GetBranchName() (string, error) { - err := LoadGitVersion() - if err != nil { - return "", fmt.Errorf("Git version missing: %v", err) - } - args := []string{ "name-rev", } diff --git a/modules/git/git.go b/modules/git/git.go index 8fad070330..5817bd2c7f 100644 --- a/modules/git/git.go +++ b/modules/git/git.go @@ -10,11 +10,13 @@ import ( "fmt" "os" "os/exec" + "path/filepath" "runtime" "strings" + "sync" "time" - "code.gitea.io/gitea/modules/process" + "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" "github.com/hashicorp/go-version" @@ -32,38 +34,33 @@ var ( GitExecutable = "git" // DefaultContext is the default context to run git commands in - // will be overwritten by Init with HammerContext + // will be overwritten by InitWithConfigSync with HammerContext DefaultContext = context.Background() - gitVersion *version.Version - // SupportProcReceive version >= 2.29.0 SupportProcReceive bool -) -// LocalVersion returns current Git version from shell. -func LocalVersion() (*version.Version, error) { - if err := LoadGitVersion(); err != nil { - return nil, err - } - return gitVersion, nil -} + // initMutex is used to avoid Golang's data race error. see the comments below. + initMutex sync.Mutex + + gitVersion *version.Version +) -// LoadGitVersion returns current Git version from shell. -func LoadGitVersion() error { +// loadGitVersion returns current Git version from shell. Internal usage only. +func loadGitVersion() (*version.Version, error) { // doesn't need RWMutex because its exec by Init() if gitVersion != nil { - return nil + return gitVersion, nil } - stdout, _, runErr := NewCommand(context.Background(), "version").RunStdString(nil) + stdout, _, runErr := NewCommand(DefaultContext, "version").RunStdString(nil) if runErr != nil { - return runErr + return nil, runErr } fields := strings.Fields(stdout) if len(fields) < 3 { - return fmt.Errorf("not enough output: %s", stdout) + return nil, fmt.Errorf("invalid git version output: %s", stdout) } var versionString string @@ -78,7 +75,7 @@ func LoadGitVersion() error { var err error gitVersion, err = version.NewVersion(versionString) - return err + return gitVersion, err } // SetExecutablePath changes the path of git executable and checks the file permission and version. @@ -93,7 +90,7 @@ func SetExecutablePath(path string) error { } GitExecutable = absPath - err = LoadGitVersion() + _, err = loadGitVersion() if err != nil { return fmt.Errorf("unable to load git version: %w", err) } @@ -120,7 +117,10 @@ func SetExecutablePath(path string) error { // VersionInfo returns git version information func VersionInfo() string { - format := "Git Version: %s" + if gitVersion == nil { + return "(git not found)" + } + format := "%s" args := []interface{}{gitVersion.Original()} // Since git wire protocol has been released from git v2.18 if setting.Git.EnableAutoGitWireProtocol && CheckGitVersionAtLeast("2.18") == nil { @@ -131,8 +131,33 @@ func VersionInfo() string { return fmt.Sprintf(format, args...) } -// Init initializes git module -func Init(ctx context.Context) error { +// InitSimple initializes git module with a very simple step, no config changes, no global command arguments. +// This method doesn't change anything to filesystem +func InitSimple(ctx context.Context) error { + initMutex.Lock() + defer initMutex.Unlock() + + return initSimpleInternal(ctx) +} + +// HomeDir is the home dir for git to store the global config file used by Gitea internally +func HomeDir() string { + if setting.RepoRootPath == "" { + // TODO: now, some unit test code call the git module directly without initialization, which is incorrect. + // at the moment, we just use a temp HomeDir to prevent from conflicting with user's git config + // in the future, the git module should be initialized first before use. + tmpHomeDir := filepath.Join(os.TempDir(), "gitea-temp-home") + log.Error("Git's HomeDir is empty (RepoRootPath is empty), the git module is not initialized correctly, using a temp HomeDir (%s) temporarily", tmpHomeDir) + return tmpHomeDir + } + return setting.RepoRootPath +} + +func initSimpleInternal(ctx context.Context) error { + // at the moment, when running integration tests, the git.InitXxx would be called twice. + // one is called by the GlobalInitInstalled, one is called by TestMain. + // so the init functions should be protected by a mutex to avoid Golang's data race error. + DefaultContext = ctx if setting.Git.Timeout.Default > 0 { @@ -146,6 +171,23 @@ func Init(ctx context.Context) error { // force cleanup args globalCommandArgs = []string{} + return nil +} + +// InitWithConfigSync initializes git module. This method may create directories or write files into filesystem +func InitWithConfigSync(ctx context.Context) error { + initMutex.Lock() + defer initMutex.Unlock() + + err := initSimpleInternal(ctx) + if err != nil { + return err + } + + if err = os.MkdirAll(setting.RepoRootPath, os.ModePerm); err != nil { + return fmt.Errorf("unable to create directory %s, err: %w", setting.RepoRootPath, err) + } + if CheckGitVersionAtLeast("2.9") == nil { // Explicitly disable credential helper, otherwise Git credentials might leak globalCommandArgs = append(globalCommandArgs, "-c", "credential.helper=") @@ -161,68 +203,71 @@ func Init(ctx context.Context) error { globalCommandArgs = append(globalCommandArgs, "-c", "uploadpack.allowfilter=true", "-c", "uploadpack.allowAnySHA1InWant=true") } - // Save current git version on init to gitVersion otherwise it would require an RWMutex - if err := LoadGitVersion(); err != nil { - return err - } - - // Git requires setting user.name and user.email in order to commit changes - if they're not set just add some defaults - for configKey, defaultValue := range map[string]string{"user.name": "Gitea", "user.email": "gitea@fake.local"} { - if err := checkAndSetConfig(configKey, defaultValue, false); err != nil { + // Git requires setting user.name and user.email in order to commit changes - old comment: "if they're not set just add some defaults" + // TODO: need to confirm whether users really need to change these values manually. It seems that these values are dummy only and not really used. + // If these values are not really used, then they can be set (overwritten) directly without considering about existence. + for configKey, defaultValue := range map[string]string{ + "user.name": "Gitea", + "user.email": "gitea@fake.local", + } { + if err := configSetNonExist(configKey, defaultValue); err != nil { return err } } // Set git some configurations - these must be set to these values for gitea to work correctly - if err := checkAndSetConfig("core.quotePath", "false", true); err != nil { + if err := configSet("core.quotePath", "false"); err != nil { return err } if CheckGitVersionAtLeast("2.10") == nil { - if err := checkAndSetConfig("receive.advertisePushOptions", "true", true); err != nil { + if err := configSet("receive.advertisePushOptions", "true"); err != nil { return err } } if CheckGitVersionAtLeast("2.18") == nil { - if err := checkAndSetConfig("core.commitGraph", "true", true); err != nil { + if err := configSet("core.commitGraph", "true"); err != nil { return err } - if err := checkAndSetConfig("gc.writeCommitGraph", "true", true); err != nil { + if err := configSet("gc.writeCommitGraph", "true"); err != nil { return err } } if CheckGitVersionAtLeast("2.29") == nil { // set support for AGit flow - if err := checkAndAddConfig("receive.procReceiveRefs", "refs/for"); err != nil { + if err := configAddNonExist("receive.procReceiveRefs", "refs/for"); err != nil { return err } SupportProcReceive = true } else { - if err := checkAndRemoveConfig("receive.procReceiveRefs", "refs/for"); err != nil { + if err := configUnsetAll("receive.procReceiveRefs", "refs/for"); err != nil { return err } SupportProcReceive = false } if runtime.GOOS == "windows" { - if err := checkAndSetConfig("core.longpaths", "true", true); err != nil { + if err := configSet("core.longpaths", "true"); err != nil { return err } - } - if setting.Git.DisableCoreProtectNTFS { - if err := checkAndSetConfig("core.protectntfs", "false", true); err != nil { + if setting.Git.DisableCoreProtectNTFS { + err = configSet("core.protectNTFS", "false") + } else { + err = configUnsetAll("core.protectNTFS", "false") + } + if err != nil { return err } - globalCommandArgs = append(globalCommandArgs, "-c", "core.protectntfs=false") } + return nil } // CheckGitVersionAtLeast check git version is at least the constraint version func CheckGitVersionAtLeast(atLeast string) error { - if err := LoadGitVersion(); err != nil { + if _, err := loadGitVersion(); err != nil { return err } atLeastVersion, err := version.NewVersion(atLeast) @@ -235,75 +280,75 @@ func CheckGitVersionAtLeast(atLeast string) error { return nil } -func checkAndSetConfig(key, defaultValue string, forceToDefault bool) error { - stdout, stderr, err := process.GetManager().Exec("git.Init(get setting)", GitExecutable, "config", "--get", key) - if err != nil { - perr, ok := err.(*process.Error) - if !ok { - return fmt.Errorf("Failed to get git %s(%v) errType %T: %s", key, err, err, stderr) - } - eerr, ok := perr.Err.(*exec.ExitError) - if !ok || eerr.ExitCode() != 1 { - return fmt.Errorf("Failed to get git %s(%v) errType %T: %s", key, err, err, stderr) - } +func configSet(key, value string) error { + stdout, _, err := NewCommand(DefaultContext, "config", "--get", key).RunStdString(nil) + if err != nil && !err.IsExitCode(1) { + return fmt.Errorf("failed to get git config %s, err: %w", key, err) } currValue := strings.TrimSpace(stdout) - - if currValue == defaultValue || (!forceToDefault && len(currValue) > 0) { + if currValue == value { return nil } - if _, stderr, err = process.GetManager().Exec(fmt.Sprintf("git.Init(set %s)", key), "git", "config", "--global", key, defaultValue); err != nil { - return fmt.Errorf("Failed to set git %s(%s): %s", key, err, stderr) + _, _, err = NewCommand(DefaultContext, "config", "--global", key, value).RunStdString(nil) + if err != nil { + return fmt.Errorf("failed to set git global config %s, err: %w", key, err) } return nil } -func checkAndAddConfig(key, value string) error { - _, stderr, err := process.GetManager().Exec("git.Init(get setting)", GitExecutable, "config", "--get", key, value) - if err != nil { - perr, ok := err.(*process.Error) - if !ok { - return fmt.Errorf("Failed to get git %s(%v) errType %T: %s", key, err, err, stderr) - } - eerr, ok := perr.Err.(*exec.ExitError) - if !ok || eerr.ExitCode() != 1 { - return fmt.Errorf("Failed to get git %s(%v) errType %T: %s", key, err, err, stderr) - } - if eerr.ExitCode() == 1 { - if _, stderr, err = process.GetManager().Exec(fmt.Sprintf("git.Init(set %s)", key), "git", "config", "--global", "--add", key, value); err != nil { - return fmt.Errorf("Failed to set git %s(%s): %s", key, err, stderr) - } - return nil +func configSetNonExist(key, value string) error { + _, _, err := NewCommand(DefaultContext, "config", "--get", key).RunStdString(nil) + if err == nil { + // already exist + return nil + } + if err.IsExitCode(1) { + // not exist, set new config + _, _, err = NewCommand(DefaultContext, "config", "--global", key, value).RunStdString(nil) + if err != nil { + return fmt.Errorf("failed to set git global config %s, err: %w", key, err) } + return nil } - return nil + return fmt.Errorf("failed to get git config %s, err: %w", key, err) } -func checkAndRemoveConfig(key, value string) error { - _, stderr, err := process.GetManager().Exec("git.Init(get setting)", GitExecutable, "config", "--get", key, value) - if err != nil { - perr, ok := err.(*process.Error) - if !ok { - return fmt.Errorf("Failed to get git %s(%v) errType %T: %s", key, err, err, stderr) - } - eerr, ok := perr.Err.(*exec.ExitError) - if !ok || eerr.ExitCode() != 1 { - return fmt.Errorf("Failed to get git %s(%v) errType %T: %s", key, err, err, stderr) - } - if eerr.ExitCode() == 1 { - return nil +func configAddNonExist(key, value string) error { + _, _, err := NewCommand(DefaultContext, "config", "--fixed-value", "--get", key, value).RunStdString(nil) + if err == nil { + // already exist + return nil + } + if err.IsExitCode(1) { + // not exist, add new config + _, _, err = NewCommand(DefaultContext, "config", "--global", "--add", key, value).RunStdString(nil) + if err != nil { + return fmt.Errorf("failed to add git global config %s, err: %w", key, err) } + return nil } + return fmt.Errorf("failed to get git config %s, err: %w", key, err) +} - if _, stderr, err = process.GetManager().Exec(fmt.Sprintf("git.Init(set %s)", key), "git", "config", "--global", "--unset-all", key, value); err != nil { - return fmt.Errorf("Failed to set git %s(%s): %s", key, err, stderr) +func configUnsetAll(key, value string) error { + _, _, err := NewCommand(DefaultContext, "config", "--get", key).RunStdString(nil) + if err == nil { + // exist, need to remove + _, _, err = NewCommand(DefaultContext, "config", "--global", "--fixed-value", "--unset-all", key, value).RunStdString(nil) + if err != nil { + return fmt.Errorf("failed to unset git global config %s, err: %w", key, err) + } + return nil } - - return nil + if err.IsExitCode(1) { + // not exist + return nil + } + return fmt.Errorf("failed to get git config %s, err: %w", key, err) } // Fsck verifies the connectivity and validity of the objects in the database diff --git a/modules/git/git_test.go b/modules/git/git_test.go index c62a55badc..5b1cd820e8 100644 --- a/modules/git/git_test.go +++ b/modules/git/git_test.go @@ -8,23 +8,74 @@ import ( "context" "fmt" "os" + "strings" "testing" "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/util" + + "github.com/stretchr/testify/assert" ) -func fatalTestError(fmtStr string, args ...interface{}) { - fmt.Fprintf(os.Stderr, fmtStr, args...) - os.Exit(1) +func testRun(m *testing.M) error { + _ = log.NewLogger(1000, "console", "console", `{"level":"trace","stacktracelevel":"NONE","stderr":true}`) + + repoRootPath, err := os.MkdirTemp(os.TempDir(), "repos") + if err != nil { + return fmt.Errorf("unable to create temp dir: %w", err) + } + defer util.RemoveAll(repoRootPath) + setting.RepoRootPath = repoRootPath + + if err = InitWithConfigSync(context.Background()); err != nil { + return fmt.Errorf("failed to call Init: %w", err) + } + + exitCode := m.Run() + if exitCode != 0 { + return fmt.Errorf("run test failed, ExitCode=%d", exitCode) + } + return nil } func TestMain(m *testing.M) { - _ = log.NewLogger(1000, "console", "console", `{"level":"trace","stacktracelevel":"NONE","stderr":true}`) + if err := testRun(m); err != nil { + _, _ = fmt.Fprintf(os.Stderr, "Test failed: %v", err) + os.Exit(1) + } +} - if err := Init(context.Background()); err != nil { - fatalTestError("Init failed: %v", err) +func TestGitConfig(t *testing.T) { + gitConfigContains := func(sub string) bool { + if b, err := os.ReadFile(HomeDir() + "/.gitconfig"); err == nil { + return strings.Contains(string(b), sub) + } + return false } - exitStatus := m.Run() - os.Exit(exitStatus) + assert.False(t, gitConfigContains("key-a")) + + assert.NoError(t, configSetNonExist("test.key-a", "val-a")) + assert.True(t, gitConfigContains("key-a = val-a")) + + assert.NoError(t, configSetNonExist("test.key-a", "val-a-changed")) + assert.False(t, gitConfigContains("key-a = val-a-changed")) + + assert.NoError(t, configSet("test.key-a", "val-a-changed")) + assert.True(t, gitConfigContains("key-a = val-a-changed")) + + assert.NoError(t, configAddNonExist("test.key-b", "val-b")) + assert.True(t, gitConfigContains("key-b = val-b")) + + assert.NoError(t, configAddNonExist("test.key-b", "val-2b")) + assert.True(t, gitConfigContains("key-b = val-b")) + assert.True(t, gitConfigContains("key-b = val-2b")) + + assert.NoError(t, configUnsetAll("test.key-b", "val-b")) + assert.False(t, gitConfigContains("key-b = val-b")) + assert.True(t, gitConfigContains("key-b = val-2b")) + + assert.NoError(t, configUnsetAll("test.key-b", "val-2b")) + assert.False(t, gitConfigContains("key-b = val-2b")) } diff --git a/modules/git/lfs.go b/modules/git/lfs.go index cdd9d15b2e..c5d8354b6d 100644 --- a/modules/git/lfs.go +++ b/modules/git/lfs.go @@ -18,12 +18,6 @@ func CheckLFSVersion() { if setting.LFS.StartServer { // Disable LFS client hooks if installed for the current OS user // Needs at least git v2.1.2 - - err := LoadGitVersion() - if err != nil { - logger.Fatal("Error retrieving git version: %v", err) - } - if CheckGitVersionAtLeast("2.1.2") != nil { setting.LFS.StartServer = false logger.Error("LFS server support needs at least Git v2.1.2") diff --git a/modules/git/remote.go b/modules/git/remote.go index 536b1681ce..b2a2e6d7ab 100644 --- a/modules/git/remote.go +++ b/modules/git/remote.go @@ -11,10 +11,6 @@ import ( // GetRemoteAddress returns the url of a specific remote of the repository. func GetRemoteAddress(ctx context.Context, repoPath, remoteName string) (*url.URL, error) { - err := LoadGitVersion() - if err != nil { - return nil, err - } var cmd *Command if CheckGitVersionAtLeast("2.7") == nil { cmd = NewCommand(ctx, "remote", "get-url", remoteName) diff --git a/modules/git/repo_attribute.go b/modules/git/repo_attribute.go index a18c80c3f1..38818788f3 100644 --- a/modules/git/repo_attribute.go +++ b/modules/git/repo_attribute.go @@ -28,11 +28,6 @@ type CheckAttributeOpts struct { // CheckAttribute return the Blame object of file func (repo *Repository) CheckAttribute(opts CheckAttributeOpts) (map[string]map[string]string, error) { - err := LoadGitVersion() - if err != nil { - return nil, fmt.Errorf("git version missing: %v", err) - } - env := []string{} if len(opts.IndexFile) > 0 && CheckGitVersionAtLeast("1.7.8") == nil { @@ -126,7 +121,7 @@ type CheckAttributeReader struct { cancel context.CancelFunc } -// Init initializes the cmd +// Init initializes the CheckAttributeReader func (c *CheckAttributeReader) Init(ctx context.Context) error { cmdArgs := []string{"check-attr", "--stdin", "-z"} diff --git a/modules/git/repo_tree.go b/modules/git/repo_tree.go index 3e7a9c2cfb..2e139daddf 100644 --- a/modules/git/repo_tree.go +++ b/modules/git/repo_tree.go @@ -24,11 +24,6 @@ type CommitTreeOpts struct { // CommitTree creates a commit from a given tree id for the user with provided message func (repo *Repository) CommitTree(author, committer *Signature, tree *Tree, opts CommitTreeOpts) (SHA1, error) { - err := LoadGitVersion() - if err != nil { - return SHA1{}, err - } - commitTimeStr := time.Now().Format(time.RFC3339) // Because this may call hooks we should pass in the environment @@ -60,14 +55,13 @@ func (repo *Repository) CommitTree(author, committer *Signature, tree *Tree, opt stdout := new(bytes.Buffer) stderr := new(bytes.Buffer) - err = cmd.Run(&RunOpts{ + err := cmd.Run(&RunOpts{ Env: env, Dir: repo.Path, Stdin: messageBytes, Stdout: stdout, Stderr: stderr, }) - if err != nil { return SHA1{}, ConcatenateError(err, stderr.String()) } |