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>
			
			
This commit is contained in:
		
							parent
							
								
									e26f84a9b7
								
							
						
					
					
						commit
						a0051634b9
					
				
					 21 changed files with 286 additions and 193 deletions
				
			
		
							
								
								
									
										60
									
								
								cmd/serv.go
									
										
									
									
									
								
							
							
						
						
									
										60
									
								
								cmd/serv.go
									
										
									
									
									
								
							| 
						 | 
					@ -6,6 +6,7 @@
 | 
				
			||||||
package cmd
 | 
					package cmd
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
 | 
						"context"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"net/http"
 | 
						"net/http"
 | 
				
			||||||
	"net/url"
 | 
						"net/url"
 | 
				
			||||||
| 
						 | 
					@ -65,6 +66,21 @@ func setup(logPath string, debug bool) {
 | 
				
			||||||
	if debug {
 | 
						if debug {
 | 
				
			||||||
		setting.RunMode = "dev"
 | 
							setting.RunMode = "dev"
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Check if setting.RepoRootPath exists. It could be the case that it doesn't exist, this can happen when
 | 
				
			||||||
 | 
						// `[repository]` `ROOT` is a relative path and $GITEA_WORK_DIR isn't passed to the SSH connection.
 | 
				
			||||||
 | 
						if _, err := os.Stat(setting.RepoRootPath); err != nil {
 | 
				
			||||||
 | 
							if os.IsNotExist(err) {
 | 
				
			||||||
 | 
								_ = fail("Incorrect configuration, no repository directory.", "Directory `[repository].ROOT` %q was not found, please check if $GITEA_WORK_DIR is passed to the SSH connection or make `[repository].ROOT` an absolute value.", setting.RepoRootPath)
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								_ = fail("Incorrect configuration, repository directory is inaccessible", "Directory `[repository].ROOT` %q is inaccessible. err: %v", setting.RepoRootPath, err)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if err := git.InitSimple(context.Background()); err != nil {
 | 
				
			||||||
 | 
							_ = fail("Failed to init git", "Failed to init git, err: %v", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var (
 | 
					var (
 | 
				
			||||||
| 
						 | 
					@ -80,12 +96,12 @@ var (
 | 
				
			||||||
func fail(userMessage, logMessage string, args ...interface{}) error {
 | 
					func fail(userMessage, logMessage string, args ...interface{}) error {
 | 
				
			||||||
	// There appears to be a chance to cause a zombie process and failure to read the Exit status
 | 
						// There appears to be a chance to cause a zombie process and failure to read the Exit status
 | 
				
			||||||
	// if nothing is outputted on stdout.
 | 
						// if nothing is outputted on stdout.
 | 
				
			||||||
	fmt.Fprintln(os.Stdout, "")
 | 
						_, _ = fmt.Fprintln(os.Stdout, "")
 | 
				
			||||||
	fmt.Fprintln(os.Stderr, "Gitea:", userMessage)
 | 
						_, _ = fmt.Fprintln(os.Stderr, "Gitea:", userMessage)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if len(logMessage) > 0 {
 | 
						if len(logMessage) > 0 {
 | 
				
			||||||
		if !setting.IsProd {
 | 
							if !setting.IsProd {
 | 
				
			||||||
			fmt.Fprintf(os.Stderr, logMessage+"\n", args...)
 | 
								_, _ = fmt.Fprintf(os.Stderr, logMessage+"\n", args...)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	ctx, cancel := installSignals()
 | 
						ctx, cancel := installSignals()
 | 
				
			||||||
| 
						 | 
					@ -237,17 +253,6 @@ func runServ(c *cli.Context) error {
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		return fail("Internal Server Error", "%s", err.Error())
 | 
							return fail("Internal Server Error", "%s", err.Error())
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	os.Setenv(repo_module.EnvRepoIsWiki, strconv.FormatBool(results.IsWiki))
 | 
					 | 
				
			||||||
	os.Setenv(repo_module.EnvRepoName, results.RepoName)
 | 
					 | 
				
			||||||
	os.Setenv(repo_module.EnvRepoUsername, results.OwnerName)
 | 
					 | 
				
			||||||
	os.Setenv(repo_module.EnvPusherName, results.UserName)
 | 
					 | 
				
			||||||
	os.Setenv(repo_module.EnvPusherEmail, results.UserEmail)
 | 
					 | 
				
			||||||
	os.Setenv(repo_module.EnvPusherID, strconv.FormatInt(results.UserID, 10))
 | 
					 | 
				
			||||||
	os.Setenv(repo_module.EnvRepoID, strconv.FormatInt(results.RepoID, 10))
 | 
					 | 
				
			||||||
	os.Setenv(repo_module.EnvPRID, fmt.Sprintf("%d", 0))
 | 
					 | 
				
			||||||
	os.Setenv(repo_module.EnvDeployKeyID, fmt.Sprintf("%d", results.DeployKeyID))
 | 
					 | 
				
			||||||
	os.Setenv(repo_module.EnvKeyID, fmt.Sprintf("%d", results.KeyID))
 | 
					 | 
				
			||||||
	os.Setenv(repo_module.EnvAppURL, setting.AppURL)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// LFS token authentication
 | 
						// LFS token authentication
 | 
				
			||||||
	if verb == lfsAuthenticateVerb {
 | 
						if verb == lfsAuthenticateVerb {
 | 
				
			||||||
| 
						 | 
					@ -298,20 +303,29 @@ func runServ(c *cli.Context) error {
 | 
				
			||||||
		gitcmd = exec.CommandContext(ctx, verb, repoPath)
 | 
							gitcmd = exec.CommandContext(ctx, verb, repoPath)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Check if setting.RepoRootPath exists. It could be the case that it doesn't exist, this can happen when
 | 
					 | 
				
			||||||
	// `[repository]` `ROOT` is a relative path and $GITEA_WORK_DIR isn't passed to the SSH connection.
 | 
					 | 
				
			||||||
	if _, err := os.Stat(setting.RepoRootPath); err != nil {
 | 
					 | 
				
			||||||
		if os.IsNotExist(err) {
 | 
					 | 
				
			||||||
			return fail("Incorrect configuration.",
 | 
					 | 
				
			||||||
				"Directory `[repository]` `ROOT` %s was not found, please check if $GITEA_WORK_DIR is passed to the SSH connection or make `[repository]` `ROOT` an absolute value.", setting.RepoRootPath)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	process.SetSysProcAttribute(gitcmd)
 | 
						process.SetSysProcAttribute(gitcmd)
 | 
				
			||||||
	gitcmd.Dir = setting.RepoRootPath
 | 
						gitcmd.Dir = setting.RepoRootPath
 | 
				
			||||||
	gitcmd.Stdout = os.Stdout
 | 
						gitcmd.Stdout = os.Stdout
 | 
				
			||||||
	gitcmd.Stdin = os.Stdin
 | 
						gitcmd.Stdin = os.Stdin
 | 
				
			||||||
	gitcmd.Stderr = os.Stderr
 | 
						gitcmd.Stderr = os.Stderr
 | 
				
			||||||
 | 
						gitcmd.Env = append(gitcmd.Env, os.Environ()...)
 | 
				
			||||||
 | 
						gitcmd.Env = append(gitcmd.Env,
 | 
				
			||||||
 | 
							repo_module.EnvRepoIsWiki+"="+strconv.FormatBool(results.IsWiki),
 | 
				
			||||||
 | 
							repo_module.EnvRepoName+"="+results.RepoName,
 | 
				
			||||||
 | 
							repo_module.EnvRepoUsername+"="+results.OwnerName,
 | 
				
			||||||
 | 
							repo_module.EnvPusherName+"="+results.UserName,
 | 
				
			||||||
 | 
							repo_module.EnvPusherEmail+"="+results.UserEmail,
 | 
				
			||||||
 | 
							repo_module.EnvPusherID+"="+strconv.FormatInt(results.UserID, 10),
 | 
				
			||||||
 | 
							repo_module.EnvRepoID+"="+strconv.FormatInt(results.RepoID, 10),
 | 
				
			||||||
 | 
							repo_module.EnvPRID+"="+fmt.Sprintf("%d", 0),
 | 
				
			||||||
 | 
							repo_module.EnvDeployKeyID+"="+fmt.Sprintf("%d", results.DeployKeyID),
 | 
				
			||||||
 | 
							repo_module.EnvKeyID+"="+fmt.Sprintf("%d", results.KeyID),
 | 
				
			||||||
 | 
							repo_module.EnvAppURL+"="+setting.AppURL,
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
						// to avoid breaking, here only use the minimal environment variables for the "gitea serv" command.
 | 
				
			||||||
 | 
						// it could be re-considered whether to use the same git.CommonGitCmdEnvs() as "git" command later.
 | 
				
			||||||
 | 
						gitcmd.Env = append(gitcmd.Env, git.CommonCmdServEnvs()...)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err = gitcmd.Run(); err != nil {
 | 
						if err = gitcmd.Run(); err != nil {
 | 
				
			||||||
		return fail("Internal error", "Failed to execute git command: %v", err)
 | 
							return fail("Internal error", "Failed to execute git command: %v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -274,8 +274,8 @@ func prepareTestEnv(t testing.TB, skip ...int) func() {
 | 
				
			||||||
	deferFn := PrintCurrentTest(t, ourSkip)
 | 
						deferFn := PrintCurrentTest(t, ourSkip)
 | 
				
			||||||
	assert.NoError(t, unittest.LoadFixtures())
 | 
						assert.NoError(t, unittest.LoadFixtures())
 | 
				
			||||||
	assert.NoError(t, util.RemoveAll(setting.RepoRootPath))
 | 
						assert.NoError(t, util.RemoveAll(setting.RepoRootPath))
 | 
				
			||||||
 | 
					 | 
				
			||||||
	assert.NoError(t, unittest.CopyDir(path.Join(filepath.Dir(setting.AppPath), "integrations/gitea-repositories-meta"), setting.RepoRootPath))
 | 
						assert.NoError(t, unittest.CopyDir(path.Join(filepath.Dir(setting.AppPath), "integrations/gitea-repositories-meta"), setting.RepoRootPath))
 | 
				
			||||||
 | 
						assert.NoError(t, git.InitWithConfigSync(context.Background()))
 | 
				
			||||||
	ownerDirs, err := os.ReadDir(setting.RepoRootPath)
 | 
						ownerDirs, err := os.ReadDir(setting.RepoRootPath)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		assert.NoError(t, err, "unable to read the new repo root: %v\n", err)
 | 
							assert.NoError(t, err, "unable to read the new repo root: %v\n", err)
 | 
				
			||||||
| 
						 | 
					@ -576,6 +576,7 @@ func resetFixtures(t *testing.T) {
 | 
				
			||||||
	assert.NoError(t, unittest.LoadFixtures())
 | 
						assert.NoError(t, unittest.LoadFixtures())
 | 
				
			||||||
	assert.NoError(t, util.RemoveAll(setting.RepoRootPath))
 | 
						assert.NoError(t, util.RemoveAll(setting.RepoRootPath))
 | 
				
			||||||
	assert.NoError(t, unittest.CopyDir(path.Join(filepath.Dir(setting.AppPath), "integrations/gitea-repositories-meta"), setting.RepoRootPath))
 | 
						assert.NoError(t, unittest.CopyDir(path.Join(filepath.Dir(setting.AppPath), "integrations/gitea-repositories-meta"), setting.RepoRootPath))
 | 
				
			||||||
 | 
						assert.NoError(t, git.InitWithConfigSync(context.Background()))
 | 
				
			||||||
	ownerDirs, err := os.ReadDir(setting.RepoRootPath)
 | 
						ownerDirs, err := os.ReadDir(setting.RepoRootPath)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		assert.NoError(t, err, "unable to read the new repo root: %v\n", err)
 | 
							assert.NoError(t, err, "unable to read the new repo root: %v\n", err)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -62,6 +62,7 @@ func initMigrationTest(t *testing.T) func() {
 | 
				
			||||||
	assert.True(t, len(setting.RepoRootPath) != 0)
 | 
						assert.True(t, len(setting.RepoRootPath) != 0)
 | 
				
			||||||
	assert.NoError(t, util.RemoveAll(setting.RepoRootPath))
 | 
						assert.NoError(t, util.RemoveAll(setting.RepoRootPath))
 | 
				
			||||||
	assert.NoError(t, unittest.CopyDir(path.Join(filepath.Dir(setting.AppPath), "integrations/gitea-repositories-meta"), setting.RepoRootPath))
 | 
						assert.NoError(t, unittest.CopyDir(path.Join(filepath.Dir(setting.AppPath), "integrations/gitea-repositories-meta"), setting.RepoRootPath))
 | 
				
			||||||
 | 
						assert.NoError(t, git.InitWithConfigSync(context.Background()))
 | 
				
			||||||
	ownerDirs, err := os.ReadDir(setting.RepoRootPath)
 | 
						ownerDirs, err := os.ReadDir(setting.RepoRootPath)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		assert.NoError(t, err, "unable to read the new repo root: %v\n", err)
 | 
							assert.NoError(t, err, "unable to read the new repo root: %v\n", err)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -202,9 +202,8 @@ func prepareTestEnv(t *testing.T, skip int, syncModels ...interface{}) (*xorm.En
 | 
				
			||||||
	ourSkip += skip
 | 
						ourSkip += skip
 | 
				
			||||||
	deferFn := PrintCurrentTest(t, ourSkip)
 | 
						deferFn := PrintCurrentTest(t, ourSkip)
 | 
				
			||||||
	assert.NoError(t, os.RemoveAll(setting.RepoRootPath))
 | 
						assert.NoError(t, os.RemoveAll(setting.RepoRootPath))
 | 
				
			||||||
 | 
						assert.NoError(t, unittest.CopyDir(path.Join(filepath.Dir(setting.AppPath), "integrations/gitea-repositories-meta"), setting.RepoRootPath))
 | 
				
			||||||
	assert.NoError(t, unittest.CopyDir(path.Join(filepath.Dir(setting.AppPath), "integrations/gitea-repositories-meta"),
 | 
						assert.NoError(t, git.InitWithConfigSync(context.Background()))
 | 
				
			||||||
		setting.RepoRootPath))
 | 
					 | 
				
			||||||
	ownerDirs, err := os.ReadDir(setting.RepoRootPath)
 | 
						ownerDirs, err := os.ReadDir(setting.RepoRootPath)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		assert.NoError(t, err, "unable to read the new repo root: %v\n", err)
 | 
							assert.NoError(t, err, "unable to read the new repo root: %v\n", err)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -14,6 +14,7 @@ import (
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"code.gitea.io/gitea/models/db"
 | 
						"code.gitea.io/gitea/models/db"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/base"
 | 
						"code.gitea.io/gitea/modules/base"
 | 
				
			||||||
 | 
						"code.gitea.io/gitea/modules/git"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/setting"
 | 
						"code.gitea.io/gitea/modules/setting"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/storage"
 | 
						"code.gitea.io/gitea/modules/storage"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/util"
 | 
						"code.gitea.io/gitea/modules/util"
 | 
				
			||||||
| 
						 | 
					@ -116,6 +117,9 @@ func MainTest(m *testing.M, testOpts *TestOptions) {
 | 
				
			||||||
	if err = CopyDir(filepath.Join(testOpts.GiteaRootPath, "integrations", "gitea-repositories-meta"), setting.RepoRootPath); err != nil {
 | 
						if err = CopyDir(filepath.Join(testOpts.GiteaRootPath, "integrations", "gitea-repositories-meta"), setting.RepoRootPath); err != nil {
 | 
				
			||||||
		fatalTestError("util.CopyDir: %v\n", err)
 | 
							fatalTestError("util.CopyDir: %v\n", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						if err = git.InitWithConfigSync(context.Background()); err != nil {
 | 
				
			||||||
 | 
							fatalTestError("git.Init: %v\n", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ownerDirs, err := os.ReadDir(setting.RepoRootPath)
 | 
						ownerDirs, err := os.ReadDir(setting.RepoRootPath)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
| 
						 | 
					@ -198,6 +202,7 @@ func PrepareTestEnv(t testing.TB) {
 | 
				
			||||||
	assert.NoError(t, util.RemoveAll(setting.RepoRootPath))
 | 
						assert.NoError(t, util.RemoveAll(setting.RepoRootPath))
 | 
				
			||||||
	metaPath := filepath.Join(giteaRoot, "integrations", "gitea-repositories-meta")
 | 
						metaPath := filepath.Join(giteaRoot, "integrations", "gitea-repositories-meta")
 | 
				
			||||||
	assert.NoError(t, CopyDir(metaPath, setting.RepoRootPath))
 | 
						assert.NoError(t, CopyDir(metaPath, setting.RepoRootPath))
 | 
				
			||||||
 | 
						assert.NoError(t, git.InitWithConfigSync(context.Background()))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ownerDirs, err := os.ReadDir(setting.RepoRootPath)
 | 
						ownerDirs, err := os.ReadDir(setting.RepoRootPath)
 | 
				
			||||||
	assert.NoError(t, err)
 | 
						assert.NoError(t, err)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -8,6 +8,7 @@ package git
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"bytes"
 | 
						"bytes"
 | 
				
			||||||
	"context"
 | 
						"context"
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"io"
 | 
						"io"
 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
| 
						 | 
					@ -104,6 +105,25 @@ type RunOpts struct {
 | 
				
			||||||
	PipelineFunc   func(context.Context, context.CancelFunc) error
 | 
						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
 | 
					// Run runs the command with the RunOpts
 | 
				
			||||||
func (c *Command) Run(opts *RunOpts) error {
 | 
					func (c *Command) Run(opts *RunOpts) error {
 | 
				
			||||||
	if opts == nil {
 | 
						if opts == nil {
 | 
				
			||||||
| 
						 | 
					@ -148,16 +168,8 @@ func (c *Command) Run(opts *RunOpts) error {
 | 
				
			||||||
		cmd.Env = opts.Env
 | 
							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)
 | 
						process.SetSysProcAttribute(cmd)
 | 
				
			||||||
 | 
						cmd.Env = append(cmd.Env, CommonGitCmdEnvs()...)
 | 
				
			||||||
	cmd.Dir = opts.Dir
 | 
						cmd.Dir = opts.Dir
 | 
				
			||||||
	cmd.Stdout = opts.Stdout
 | 
						cmd.Stdout = opts.Stdout
 | 
				
			||||||
	cmd.Stderr = opts.Stderr
 | 
						cmd.Stderr = opts.Stderr
 | 
				
			||||||
| 
						 | 
					@ -184,7 +196,9 @@ func (c *Command) Run(opts *RunOpts) error {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type RunStdError interface {
 | 
					type RunStdError interface {
 | 
				
			||||||
	error
 | 
						error
 | 
				
			||||||
 | 
						Unwrap() error
 | 
				
			||||||
	Stderr() string
 | 
						Stderr() string
 | 
				
			||||||
 | 
						IsExitCode(code int) bool
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type runStdError struct {
 | 
					type runStdError struct {
 | 
				
			||||||
| 
						 | 
					@ -209,6 +223,14 @@ func (r *runStdError) Stderr() string {
 | 
				
			||||||
	return r.stderr
 | 
						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 {
 | 
					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)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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')
 | 
					// GetBranchName gets the closest branch name (as returned by 'git name-rev --name-only')
 | 
				
			||||||
func (c *Commit) GetBranchName() (string, error) {
 | 
					func (c *Commit) GetBranchName() (string, error) {
 | 
				
			||||||
	err := LoadGitVersion()
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return "", fmt.Errorf("Git version missing: %v", err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	args := []string{
 | 
						args := []string{
 | 
				
			||||||
		"name-rev",
 | 
							"name-rev",
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -10,11 +10,13 @@ import (
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
	"os/exec"
 | 
						"os/exec"
 | 
				
			||||||
 | 
						"path/filepath"
 | 
				
			||||||
	"runtime"
 | 
						"runtime"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
 | 
						"sync"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"code.gitea.io/gitea/modules/process"
 | 
						"code.gitea.io/gitea/modules/log"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/setting"
 | 
						"code.gitea.io/gitea/modules/setting"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/hashicorp/go-version"
 | 
						"github.com/hashicorp/go-version"
 | 
				
			||||||
| 
						 | 
					@ -32,38 +34,33 @@ var (
 | 
				
			||||||
	GitExecutable = "git"
 | 
						GitExecutable = "git"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// DefaultContext is the default context to run git commands in
 | 
						// 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()
 | 
						DefaultContext = context.Background()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	gitVersion *version.Version
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// SupportProcReceive version >= 2.29.0
 | 
						// SupportProcReceive version >= 2.29.0
 | 
				
			||||||
	SupportProcReceive bool
 | 
						SupportProcReceive bool
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// initMutex is used to avoid Golang's data race error. see the comments below.
 | 
				
			||||||
 | 
						initMutex sync.Mutex
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						gitVersion *version.Version
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// LocalVersion returns current Git version from shell.
 | 
					// loadGitVersion returns current Git version from shell. Internal usage only.
 | 
				
			||||||
func LocalVersion() (*version.Version, error) {
 | 
					func loadGitVersion() (*version.Version, error) {
 | 
				
			||||||
	if err := LoadGitVersion(); err != nil {
 | 
					 | 
				
			||||||
		return nil, err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return gitVersion, nil
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// LoadGitVersion returns current Git version from shell.
 | 
					 | 
				
			||||||
func LoadGitVersion() error {
 | 
					 | 
				
			||||||
	// doesn't need RWMutex because its exec by Init()
 | 
						// doesn't need RWMutex because its exec by Init()
 | 
				
			||||||
	if gitVersion != nil {
 | 
						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 {
 | 
						if runErr != nil {
 | 
				
			||||||
		return runErr
 | 
							return nil, runErr
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	fields := strings.Fields(stdout)
 | 
						fields := strings.Fields(stdout)
 | 
				
			||||||
	if len(fields) < 3 {
 | 
						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
 | 
						var versionString string
 | 
				
			||||||
| 
						 | 
					@ -78,7 +75,7 @@ func LoadGitVersion() error {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var err error
 | 
						var err error
 | 
				
			||||||
	gitVersion, err = version.NewVersion(versionString)
 | 
						gitVersion, err = version.NewVersion(versionString)
 | 
				
			||||||
	return err
 | 
						return gitVersion, err
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// SetExecutablePath changes the path of git executable and checks the file permission and version.
 | 
					// 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
 | 
						GitExecutable = absPath
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err = LoadGitVersion()
 | 
						_, err = loadGitVersion()
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return fmt.Errorf("unable to load git version: %w", err)
 | 
							return fmt.Errorf("unable to load git version: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -120,7 +117,10 @@ func SetExecutablePath(path string) error {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// VersionInfo returns git version information
 | 
					// VersionInfo returns git version information
 | 
				
			||||||
func VersionInfo() string {
 | 
					func VersionInfo() string {
 | 
				
			||||||
	format := "Git Version: %s"
 | 
						if gitVersion == nil {
 | 
				
			||||||
 | 
							return "(git not found)"
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						format := "%s"
 | 
				
			||||||
	args := []interface{}{gitVersion.Original()}
 | 
						args := []interface{}{gitVersion.Original()}
 | 
				
			||||||
	// Since git wire protocol has been released from git v2.18
 | 
						// Since git wire protocol has been released from git v2.18
 | 
				
			||||||
	if setting.Git.EnableAutoGitWireProtocol && CheckGitVersionAtLeast("2.18") == nil {
 | 
						if setting.Git.EnableAutoGitWireProtocol && CheckGitVersionAtLeast("2.18") == nil {
 | 
				
			||||||
| 
						 | 
					@ -131,8 +131,33 @@ func VersionInfo() string {
 | 
				
			||||||
	return fmt.Sprintf(format, args...)
 | 
						return fmt.Sprintf(format, args...)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Init initializes git module
 | 
					// InitSimple initializes git module with a very simple step, no config changes, no global command arguments.
 | 
				
			||||||
func Init(ctx context.Context) error {
 | 
					// 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
 | 
						DefaultContext = ctx
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if setting.Git.Timeout.Default > 0 {
 | 
						if setting.Git.Timeout.Default > 0 {
 | 
				
			||||||
| 
						 | 
					@ -146,6 +171,23 @@ func Init(ctx context.Context) error {
 | 
				
			||||||
	// force cleanup args
 | 
						// force cleanup args
 | 
				
			||||||
	globalCommandArgs = []string{}
 | 
						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 {
 | 
						if CheckGitVersionAtLeast("2.9") == nil {
 | 
				
			||||||
		// Explicitly disable credential helper, otherwise Git credentials might leak
 | 
							// Explicitly disable credential helper, otherwise Git credentials might leak
 | 
				
			||||||
		globalCommandArgs = append(globalCommandArgs, "-c", "credential.helper=")
 | 
							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")
 | 
							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
 | 
						// Git requires setting user.name and user.email in order to commit changes - old comment: "if they're not set just add some defaults"
 | 
				
			||||||
	if err := LoadGitVersion(); err != nil {
 | 
						// 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.
 | 
				
			||||||
		return err
 | 
						// 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",
 | 
				
			||||||
	// Git requires setting user.name and user.email in order to commit changes - if they're not set just add some defaults
 | 
							"user.email": "gitea@fake.local",
 | 
				
			||||||
	for configKey, defaultValue := range map[string]string{"user.name": "Gitea", "user.email": "gitea@fake.local"} {
 | 
						} {
 | 
				
			||||||
		if err := checkAndSetConfig(configKey, defaultValue, false); err != nil {
 | 
							if err := configSetNonExist(configKey, defaultValue); err != nil {
 | 
				
			||||||
			return err
 | 
								return err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Set git some configurations - these must be set to these values for gitea to work correctly
 | 
						// 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
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if CheckGitVersionAtLeast("2.10") == nil {
 | 
						if CheckGitVersionAtLeast("2.10") == nil {
 | 
				
			||||||
		if err := checkAndSetConfig("receive.advertisePushOptions", "true", true); err != nil {
 | 
							if err := configSet("receive.advertisePushOptions", "true"); err != nil {
 | 
				
			||||||
			return err
 | 
								return err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if CheckGitVersionAtLeast("2.18") == nil {
 | 
						if CheckGitVersionAtLeast("2.18") == nil {
 | 
				
			||||||
		if err := checkAndSetConfig("core.commitGraph", "true", true); err != nil {
 | 
							if err := configSet("core.commitGraph", "true"); err != nil {
 | 
				
			||||||
			return err
 | 
								return err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if err := checkAndSetConfig("gc.writeCommitGraph", "true", true); err != nil {
 | 
							if err := configSet("gc.writeCommitGraph", "true"); err != nil {
 | 
				
			||||||
			return err
 | 
								return err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if CheckGitVersionAtLeast("2.29") == nil {
 | 
						if CheckGitVersionAtLeast("2.29") == nil {
 | 
				
			||||||
		// set support for AGit flow
 | 
							// 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
 | 
								return err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		SupportProcReceive = true
 | 
							SupportProcReceive = true
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		if err := checkAndRemoveConfig("receive.procReceiveRefs", "refs/for"); err != nil {
 | 
							if err := configUnsetAll("receive.procReceiveRefs", "refs/for"); err != nil {
 | 
				
			||||||
			return err
 | 
								return err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		SupportProcReceive = false
 | 
							SupportProcReceive = false
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if runtime.GOOS == "windows" {
 | 
						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 {
 | 
				
			||||||
 | 
								err = configSet("core.protectNTFS", "false")
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								err = configUnsetAll("core.protectNTFS", "false")
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
			return err
 | 
								return err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if setting.Git.DisableCoreProtectNTFS {
 | 
					
 | 
				
			||||||
		if err := checkAndSetConfig("core.protectntfs", "false", true); err != nil {
 | 
					 | 
				
			||||||
			return err
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		globalCommandArgs = append(globalCommandArgs, "-c", "core.protectntfs=false")
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// CheckGitVersionAtLeast check git version is at least the constraint version
 | 
					// CheckGitVersionAtLeast check git version is at least the constraint version
 | 
				
			||||||
func CheckGitVersionAtLeast(atLeast string) error {
 | 
					func CheckGitVersionAtLeast(atLeast string) error {
 | 
				
			||||||
	if err := LoadGitVersion(); err != nil {
 | 
						if _, err := loadGitVersion(); err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	atLeastVersion, err := version.NewVersion(atLeast)
 | 
						atLeastVersion, err := version.NewVersion(atLeast)
 | 
				
			||||||
| 
						 | 
					@ -235,75 +280,75 @@ func CheckGitVersionAtLeast(atLeast string) error {
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func checkAndSetConfig(key, defaultValue string, forceToDefault bool) error {
 | 
					func configSet(key, value string) error {
 | 
				
			||||||
	stdout, stderr, err := process.GetManager().Exec("git.Init(get setting)", GitExecutable, "config", "--get", key)
 | 
						stdout, _, err := NewCommand(DefaultContext, "config", "--get", key).RunStdString(nil)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil && !err.IsExitCode(1) {
 | 
				
			||||||
		perr, ok := err.(*process.Error)
 | 
							return fmt.Errorf("failed to get git config %s, err: %w", key, err)
 | 
				
			||||||
		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)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	currValue := strings.TrimSpace(stdout)
 | 
						currValue := strings.TrimSpace(stdout)
 | 
				
			||||||
 | 
						if currValue == value {
 | 
				
			||||||
	if currValue == defaultValue || (!forceToDefault && len(currValue) > 0) {
 | 
					 | 
				
			||||||
		return nil
 | 
							return nil
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if _, stderr, err = process.GetManager().Exec(fmt.Sprintf("git.Init(set %s)", key), "git", "config", "--global", key, defaultValue); err != nil {
 | 
						_, _, err = NewCommand(DefaultContext, "config", "--global", key, value).RunStdString(nil)
 | 
				
			||||||
		return fmt.Errorf("Failed to set git %s(%s): %s", key, err, stderr)
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return fmt.Errorf("failed to set git global config %s, err: %w", key, err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func checkAndAddConfig(key, value string) error {
 | 
					func configSetNonExist(key, value string) error {
 | 
				
			||||||
	_, stderr, err := process.GetManager().Exec("git.Init(get setting)", GitExecutable, "config", "--get", key, value)
 | 
						_, _, err := NewCommand(DefaultContext, "config", "--get", key).RunStdString(nil)
 | 
				
			||||||
	if err != nil {
 | 
						if err == nil {
 | 
				
			||||||
		perr, ok := err.(*process.Error)
 | 
							// already exist
 | 
				
			||||||
		if !ok {
 | 
							return nil
 | 
				
			||||||
			return fmt.Errorf("Failed to get git %s(%v) errType %T: %s", key, err, err, stderr)
 | 
						}
 | 
				
			||||||
		}
 | 
						if err.IsExitCode(1) {
 | 
				
			||||||
		eerr, ok := perr.Err.(*exec.ExitError)
 | 
							// not exist, set new config
 | 
				
			||||||
		if !ok || eerr.ExitCode() != 1 {
 | 
							_, _, err = NewCommand(DefaultContext, "config", "--global", key, value).RunStdString(nil)
 | 
				
			||||||
			return fmt.Errorf("Failed to get git %s(%v) errType %T: %s", key, err, err, stderr)
 | 
							if err != nil {
 | 
				
			||||||
		}
 | 
								return fmt.Errorf("failed to set git global config %s, err: %w", key, err)
 | 
				
			||||||
		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
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							return nil
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return nil
 | 
						return fmt.Errorf("failed to get git config %s, err: %w", key, err)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func checkAndRemoveConfig(key, value string) error {
 | 
					func configAddNonExist(key, value string) error {
 | 
				
			||||||
	_, stderr, err := process.GetManager().Exec("git.Init(get setting)", GitExecutable, "config", "--get", key, value)
 | 
						_, _, err := NewCommand(DefaultContext, "config", "--fixed-value", "--get", key, value).RunStdString(nil)
 | 
				
			||||||
	if err != nil {
 | 
						if err == nil {
 | 
				
			||||||
		perr, ok := err.(*process.Error)
 | 
							// already exist
 | 
				
			||||||
		if !ok {
 | 
							return nil
 | 
				
			||||||
			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
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						if err.IsExitCode(1) {
 | 
				
			||||||
	if _, stderr, err = process.GetManager().Exec(fmt.Sprintf("git.Init(set %s)", key), "git", "config", "--global", "--unset-all", key, value); err != nil {
 | 
							// not exist, add new config
 | 
				
			||||||
		return fmt.Errorf("Failed to set git %s(%s): %s", key, err, stderr)
 | 
							_, _, 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)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return nil
 | 
					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
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						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
 | 
					// Fsck verifies the connectivity and validity of the objects in the database
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -8,23 +8,74 @@ import (
 | 
				
			||||||
	"context"
 | 
						"context"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
 | 
						"strings"
 | 
				
			||||||
	"testing"
 | 
						"testing"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"code.gitea.io/gitea/modules/log"
 | 
						"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{}) {
 | 
					func testRun(m *testing.M) error {
 | 
				
			||||||
	fmt.Fprintf(os.Stderr, fmtStr, args...)
 | 
						_ = log.NewLogger(1000, "console", "console", `{"level":"trace","stacktracelevel":"NONE","stderr":true}`)
 | 
				
			||||||
	os.Exit(1)
 | 
					
 | 
				
			||||||
 | 
						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) {
 | 
					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 {
 | 
					func TestGitConfig(t *testing.T) {
 | 
				
			||||||
		fatalTestError("Init failed: %v", err)
 | 
						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()
 | 
						assert.False(t, gitConfigContains("key-a"))
 | 
				
			||||||
	os.Exit(exitStatus)
 | 
					
 | 
				
			||||||
 | 
						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"))
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -18,12 +18,6 @@ func CheckLFSVersion() {
 | 
				
			||||||
	if setting.LFS.StartServer {
 | 
						if setting.LFS.StartServer {
 | 
				
			||||||
		// Disable LFS client hooks if installed for the current OS user
 | 
							// Disable LFS client hooks if installed for the current OS user
 | 
				
			||||||
		// Needs at least git v2.1.2
 | 
							// 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 {
 | 
							if CheckGitVersionAtLeast("2.1.2") != nil {
 | 
				
			||||||
			setting.LFS.StartServer = false
 | 
								setting.LFS.StartServer = false
 | 
				
			||||||
			logger.Error("LFS server support needs at least Git v2.1.2")
 | 
								logger.Error("LFS server support needs at least Git v2.1.2")
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -11,10 +11,6 @@ import (
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// GetRemoteAddress returns the url of a specific remote of the repository.
 | 
					// GetRemoteAddress returns the url of a specific remote of the repository.
 | 
				
			||||||
func GetRemoteAddress(ctx context.Context, repoPath, remoteName string) (*url.URL, error) {
 | 
					func GetRemoteAddress(ctx context.Context, repoPath, remoteName string) (*url.URL, error) {
 | 
				
			||||||
	err := LoadGitVersion()
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return nil, err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	var cmd *Command
 | 
						var cmd *Command
 | 
				
			||||||
	if CheckGitVersionAtLeast("2.7") == nil {
 | 
						if CheckGitVersionAtLeast("2.7") == nil {
 | 
				
			||||||
		cmd = NewCommand(ctx, "remote", "get-url", remoteName)
 | 
							cmd = NewCommand(ctx, "remote", "get-url", remoteName)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -28,11 +28,6 @@ type CheckAttributeOpts struct {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// CheckAttribute return the Blame object of file
 | 
					// CheckAttribute return the Blame object of file
 | 
				
			||||||
func (repo *Repository) CheckAttribute(opts CheckAttributeOpts) (map[string]map[string]string, error) {
 | 
					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{}
 | 
						env := []string{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if len(opts.IndexFile) > 0 && CheckGitVersionAtLeast("1.7.8") == nil {
 | 
						if len(opts.IndexFile) > 0 && CheckGitVersionAtLeast("1.7.8") == nil {
 | 
				
			||||||
| 
						 | 
					@ -126,7 +121,7 @@ type CheckAttributeReader struct {
 | 
				
			||||||
	cancel      context.CancelFunc
 | 
						cancel      context.CancelFunc
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Init initializes the cmd
 | 
					// Init initializes the CheckAttributeReader
 | 
				
			||||||
func (c *CheckAttributeReader) Init(ctx context.Context) error {
 | 
					func (c *CheckAttributeReader) Init(ctx context.Context) error {
 | 
				
			||||||
	cmdArgs := []string{"check-attr", "--stdin", "-z"}
 | 
						cmdArgs := []string{"check-attr", "--stdin", "-z"}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -24,11 +24,6 @@ type CommitTreeOpts struct {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// CommitTree creates a commit from a given tree id for the user with provided message
 | 
					// 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) {
 | 
					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)
 | 
						commitTimeStr := time.Now().Format(time.RFC3339)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Because this may call hooks we should pass in the environment
 | 
						// 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)
 | 
						stdout := new(bytes.Buffer)
 | 
				
			||||||
	stderr := new(bytes.Buffer)
 | 
						stderr := new(bytes.Buffer)
 | 
				
			||||||
	err = cmd.Run(&RunOpts{
 | 
						err := cmd.Run(&RunOpts{
 | 
				
			||||||
		Env:    env,
 | 
							Env:    env,
 | 
				
			||||||
		Dir:    repo.Path,
 | 
							Dir:    repo.Path,
 | 
				
			||||||
		Stdin:  messageBytes,
 | 
							Stdin:  messageBytes,
 | 
				
			||||||
		Stdout: stdout,
 | 
							Stdout: stdout,
 | 
				
			||||||
		Stderr: stderr,
 | 
							Stderr: stderr,
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
 | 
					 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return SHA1{}, ConcatenateError(err, stderr.String())
 | 
							return SHA1{}, ConcatenateError(err, stderr.String())
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -30,7 +30,7 @@ func TestMain(m *testing.M) {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestRepoStatsIndex(t *testing.T) {
 | 
					func TestRepoStatsIndex(t *testing.T) {
 | 
				
			||||||
	if err := git.Init(context.Background()); !assert.NoError(t, err) {
 | 
						if err := git.InitWithConfigSync(context.Background()); !assert.NoError(t, err) {
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -317,11 +317,6 @@ func initRepoCommit(ctx context.Context, tmpPath string, repo *repo_model.Reposi
 | 
				
			||||||
		return fmt.Errorf("git add --all: %v", err)
 | 
							return fmt.Errorf("git add --all: %v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err = git.LoadGitVersion()
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return fmt.Errorf("Unable to get git version: %v", err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	args := []string{
 | 
						args := []string{
 | 
				
			||||||
		"commit", fmt.Sprintf("--author='%s <%s>'", sig.Name, sig.Email),
 | 
							"commit", fmt.Sprintf("--author='%s <%s>'", sig.Name, sig.Email),
 | 
				
			||||||
		"-m", "Initial commit",
 | 
							"-m", "Initial commit",
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -182,6 +182,7 @@ func FileURLToPath(u *url.URL) (string, error) {
 | 
				
			||||||
// it returns error when the variable does not exist.
 | 
					// it returns error when the variable does not exist.
 | 
				
			||||||
func HomeDir() (home string, err error) {
 | 
					func HomeDir() (home string, err error) {
 | 
				
			||||||
	// TODO: some users run Gitea with mismatched uid  and "HOME=xxx" (they set HOME=xxx by environment manually)
 | 
						// TODO: some users run Gitea with mismatched uid  and "HOME=xxx" (they set HOME=xxx by environment manually)
 | 
				
			||||||
 | 
						// TODO: when running gitea as a sub command inside git, the HOME directory is not the user's home directory
 | 
				
			||||||
	// so at the moment we can not use `user.Current().HomeDir`
 | 
						// so at the moment we can not use `user.Current().HomeDir`
 | 
				
			||||||
	if isOSWindows() {
 | 
						if isOSWindows() {
 | 
				
			||||||
		home = os.Getenv("USERPROFILE")
 | 
							home = os.Getenv("USERPROFILE")
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -102,8 +102,8 @@ func GlobalInitInstalled(ctx context.Context) {
 | 
				
			||||||
		log.Fatal("Gitea is not installed")
 | 
							log.Fatal("Gitea is not installed")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mustInitCtx(ctx, git.Init)
 | 
						mustInitCtx(ctx, git.InitWithConfigSync)
 | 
				
			||||||
	log.Info(git.VersionInfo())
 | 
						log.Info("Git Version: %s (home: %s)", git.VersionInfo(), git.HomeDir())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	git.CheckLFSVersion()
 | 
						git.CheckLFSVersion()
 | 
				
			||||||
	log.Info("AppPath: %s", setting.AppPath)
 | 
						log.Info("AppPath: %s", setting.AppPath)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -247,9 +247,8 @@ func Config(ctx *context.Context) {
 | 
				
			||||||
	ctx.Data["DisableRouterLog"] = setting.DisableRouterLog
 | 
						ctx.Data["DisableRouterLog"] = setting.DisableRouterLog
 | 
				
			||||||
	ctx.Data["RunUser"] = setting.RunUser
 | 
						ctx.Data["RunUser"] = setting.RunUser
 | 
				
			||||||
	ctx.Data["RunMode"] = util.ToTitleCase(setting.RunMode)
 | 
						ctx.Data["RunMode"] = util.ToTitleCase(setting.RunMode)
 | 
				
			||||||
	if version, err := git.LocalVersion(); err == nil {
 | 
						ctx.Data["GitVersion"] = git.VersionInfo()
 | 
				
			||||||
		ctx.Data["GitVersion"] = version.Original()
 | 
					
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	ctx.Data["RepoRootPath"] = setting.RepoRootPath
 | 
						ctx.Data["RepoRootPath"] = setting.RepoRootPath
 | 
				
			||||||
	ctx.Data["CustomRootPath"] = setting.CustomPath
 | 
						ctx.Data["CustomRootPath"] = setting.CustomPath
 | 
				
			||||||
	ctx.Data["StaticRootPath"] = setting.StaticRootPath
 | 
						ctx.Data["StaticRootPath"] = setting.StaticRootPath
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -421,12 +421,9 @@ func LFSPointerFiles(ctx *context.Context) {
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	ctx.Data["PageIsSettingsLFS"] = true
 | 
						ctx.Data["PageIsSettingsLFS"] = true
 | 
				
			||||||
	err := git.LoadGitVersion()
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		log.Fatal("Error retrieving git version: %v", err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	ctx.Data["LFSFilesLink"] = ctx.Repo.RepoLink + "/settings/lfs"
 | 
						ctx.Data["LFSFilesLink"] = ctx.Repo.RepoLink + "/settings/lfs"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var err error
 | 
				
			||||||
	err = func() error {
 | 
						err = func() error {
 | 
				
			||||||
		pointerChan := make(chan lfs.PointerBlob)
 | 
							pointerChan := make(chan lfs.PointerBlob)
 | 
				
			||||||
		errChan := make(chan error, 1)
 | 
							errChan := make(chan error, 1)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -223,12 +223,6 @@ func Merge(ctx context.Context, pr *models.PullRequest, doer *user_model.User, b
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// rawMerge perform the merge operation without changing any pull information in database
 | 
					// rawMerge perform the merge operation without changing any pull information in database
 | 
				
			||||||
func rawMerge(ctx context.Context, pr *models.PullRequest, doer *user_model.User, mergeStyle repo_model.MergeStyle, expectedHeadCommitID, message string) (string, error) {
 | 
					func rawMerge(ctx context.Context, pr *models.PullRequest, doer *user_model.User, mergeStyle repo_model.MergeStyle, expectedHeadCommitID, message string) (string, error) {
 | 
				
			||||||
	err := git.LoadGitVersion()
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		log.Error("git.LoadGitVersion: %v", err)
 | 
					 | 
				
			||||||
		return "", fmt.Errorf("Unable to get git version: %v", err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Clone base repo.
 | 
						// Clone base repo.
 | 
				
			||||||
	tmpBasePath, err := createTemporaryRepo(ctx, pr)
 | 
						tmpBasePath, err := createTemporaryRepo(ctx, pr)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -229,11 +229,6 @@ func (t *TemporaryUploadRepository) CommitTreeWithDate(parent string, author, co
 | 
				
			||||||
	authorSig := author.NewGitSig()
 | 
						authorSig := author.NewGitSig()
 | 
				
			||||||
	committerSig := committer.NewGitSig()
 | 
						committerSig := committer.NewGitSig()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err := git.LoadGitVersion()
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return "", fmt.Errorf("Unable to get git version: %v", err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Because this may call hooks we should pass in the environment
 | 
						// Because this may call hooks we should pass in the environment
 | 
				
			||||||
	env := append(os.Environ(),
 | 
						env := append(os.Environ(),
 | 
				
			||||||
		"GIT_AUTHOR_NAME="+authorSig.Name,
 | 
							"GIT_AUTHOR_NAME="+authorSig.Name,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue