mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-10-27 00:23:41 +09:00 
			
		
		
		
	Support changing git config through app.ini, use diff.algorithm=histogram by default (#24860)
				
					
				
			Close #13454 , Close #23255, Close #14697 (and maybe more related issues) Many users have the requirement to customize the git config. This PR introduces an easy way: put the options in Gitea's app.ini `[git.config]`, then the config options will be applied to git config. And it can support more flexible default config values, eg: now `diff.algorithm=histogram` by default. According to: https://stackoverflow.com/a/32367597/4754037 , `histogram diff` is efficient and doesn't like to cause server-side problems. --------- Co-authored-by: silverwind <me@silverwind.io> Co-authored-by: KN4CK3R <admin@oldschoolhack.me> Co-authored-by: Giteabot <teabot@gitea.io>
This commit is contained in:
		| @@ -682,6 +682,28 @@ LEVEL = Info | ||||
| ;; Disable the usage of using partial clones for git. | ||||
| ;DISABLE_PARTIAL_CLONE = false | ||||
|  | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Git Operation timeout in seconds | ||||
| ;[git.timeout] | ||||
| ;DEFAULT = 360 | ||||
| ;MIGRATE = 600 | ||||
| ;MIRROR = 300 | ||||
| ;CLONE = 300 | ||||
| ;PULL = 300 | ||||
| ;GC = 60 | ||||
|  | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Git Reflog timeout in days | ||||
| ;[git.reflog] | ||||
| ;ENABLED = true | ||||
| ;EXPIRATION = 90 | ||||
|  | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Git config options | ||||
| ;; This section only does "set" config, a removed config key from this section won't be removed from git config automatically. The format is `some.configKey = value`. | ||||
| ;[git.config] | ||||
| ;diff.algorithm = histogram | ||||
|  | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| [service] | ||||
| @@ -2176,32 +2198,6 @@ LEVEL = Info | ||||
| ;Check at least this proportion of LFSMetaObjects per repo. (This may cause all stale LFSMetaObjects to be checked.) | ||||
| ;PROPORTION_TO_CHECK_PER_REPO = 0.6 | ||||
|  | ||||
|  | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Git Operation timeout in seconds | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;[git.timeout] | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;DEFAULT = 360 | ||||
| ;MIGRATE = 600 | ||||
| ;MIRROR = 300 | ||||
| ;CLONE = 300 | ||||
| ;PULL = 300 | ||||
| ;GC = 60 | ||||
|  | ||||
|  | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Git Reflog timeout in days | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;[git.reflog] | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;ENABLED = true | ||||
| ;EXPIRATION = 90 | ||||
|  | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;[mirror] | ||||
|   | ||||
| @@ -1054,12 +1054,7 @@ Default templates for project boards: | ||||
| - `DISABLE_CORE_PROTECT_NTFS`: **false** Set to true to forcibly set `core.protectNTFS` to false. | ||||
| - `DISABLE_PARTIAL_CLONE`: **false** Disable the usage of using partial clones for git. | ||||
|  | ||||
| ## Git - Reflog settings (`git.reflog`) | ||||
|  | ||||
| - `ENABLED`: **true** Set to true to enable Git to write changes to reflogs in each repo. | ||||
| - `EXPIRATION`: **90** Reflog entry lifetime, in days. Entries are removed opportunistically by Git. | ||||
|  | ||||
| ## Git - Timeout settings (`git.timeout`) | ||||
| ### Git - Timeout settings (`git.timeout`) | ||||
|  | ||||
| - `DEFAULT`: **360**: Git operations default timeout seconds. | ||||
| - `MIGRATE`: **600**: Migrate external repositories timeout seconds. | ||||
| @@ -1068,6 +1063,18 @@ Default templates for project boards: | ||||
| - `PULL`: **300**: Git pull from internal repositories timeout seconds. | ||||
| - `GC`: **60**: Git repository GC timeout seconds. | ||||
|  | ||||
| ### Git - Reflog settings (`git.reflog`) | ||||
|  | ||||
| - `ENABLED`: **true** Set to true to enable Git to write changes to reflogs in each repo. | ||||
| - `EXPIRATION`: **90** Reflog entry lifetime, in days. Entries are removed opportunistically by Git. | ||||
|  | ||||
| ### Git - Config options (`git.config`) | ||||
|  | ||||
| The key/value pairs in this section will be used as git config. | ||||
| This section only does "set" config, a removed config key from this section won't be removed from git config automatically. The format is `some.configKey = value`. | ||||
|  | ||||
| - `diff.algorithm`: **histogram** | ||||
|  | ||||
| ## Metrics (`metrics`) | ||||
|  | ||||
| - `ENABLED`: **false**: Enables /metrics endpoint for prometheus. | ||||
|   | ||||
| @@ -282,6 +282,22 @@ Place custom files in corresponding sub-folder under `custom/options`. | ||||
|  | ||||
| To add custom .gitignore, add a file with existing [.gitignore rules](https://git-scm.com/docs/gitignore) in it to `$GITEA_CUSTOM/options/gitignore` | ||||
|  | ||||
| ## Customizing the git configuration | ||||
|  | ||||
| Starting with Gitea 1.20, you can customize the git configuration via the `git.config` section. | ||||
|  | ||||
| ### Enabling signed git pushes | ||||
|  | ||||
| To enable signed git pushes, set these two options: | ||||
|  | ||||
| ```ini | ||||
| [git.config] | ||||
| receive.advertisePushOptions = true | ||||
| receive.certNonceSeed = <randomstring> | ||||
| ``` | ||||
|  | ||||
| `certNonceSeed` should be set to a random string and be kept secret. | ||||
|  | ||||
| ### Labels | ||||
|  | ||||
| Starting with Gitea 1.19, you can add a file that follows the [YAML label format](https://github.com/go-gitea/gitea/blob/main/options/label/Advanced.yaml) to `$GITEA_CUSTOM/options/label`: | ||||
|   | ||||
| @@ -224,6 +224,14 @@ func syncGitConfig() (err error) { | ||||
| 		return fmt.Errorf("unable to prepare git home directory %s, err: %w", HomeDir(), err) | ||||
| 	} | ||||
|  | ||||
| 	// first, write user's git config options to git config file | ||||
| 	// user config options could be overwritten by builtin values later, because if a value is builtin, it must have some special purposes | ||||
| 	for k, v := range setting.GitConfig.Options { | ||||
| 		if err = configSet(strings.ToLower(k), v); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// 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. | ||||
|   | ||||
| @@ -42,14 +42,14 @@ func TestMain(m *testing.M) { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestGitConfig(t *testing.T) { | ||||
| 	gitConfigContains := func(sub string) bool { | ||||
| func gitConfigContains(sub string) bool { | ||||
| 	if b, err := os.ReadFile(HomeDir() + "/.gitconfig"); err == nil { | ||||
| 		return strings.Contains(string(b), sub) | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| func TestGitConfig(t *testing.T) { | ||||
| 	assert.False(t, gitConfigContains("key-a")) | ||||
|  | ||||
| 	assert.NoError(t, configSetNonExist("test.key-a", "val-a")) | ||||
| @@ -81,3 +81,15 @@ func TestGitConfig(t *testing.T) { | ||||
| 	assert.NoError(t, configUnsetAll("test.key-x", "*")) | ||||
| 	assert.False(t, gitConfigContains("key-x = *")) | ||||
| } | ||||
|  | ||||
| func TestSyncConfig(t *testing.T) { | ||||
| 	oldGitConfig := setting.GitConfig | ||||
| 	defer func() { | ||||
| 		setting.GitConfig = oldGitConfig | ||||
| 	}() | ||||
|  | ||||
| 	setting.GitConfig.Options["sync-test.cfg-key-a"] = "CfgValA" | ||||
| 	assert.NoError(t, syncGitConfig()) | ||||
| 	assert.True(t, gitConfigContains("[sync-test]")) | ||||
| 	assert.True(t, gitConfigContains("cfg-key-a = CfgValA")) | ||||
| } | ||||
|   | ||||
| @@ -5,6 +5,7 @@ package setting | ||||
|  | ||||
| import ( | ||||
| 	"path/filepath" | ||||
| 	"strings" | ||||
| 	"time" | ||||
|  | ||||
| 	"code.gitea.io/gitea/modules/log" | ||||
| @@ -78,12 +79,28 @@ var Git = struct { | ||||
| 	}, | ||||
| } | ||||
|  | ||||
| var GitConfig = struct { | ||||
| 	Options map[string]string | ||||
| }{ | ||||
| 	Options: make(map[string]string), | ||||
| } | ||||
|  | ||||
| func loadGitFrom(rootCfg ConfigProvider) { | ||||
| 	sec := rootCfg.Section("git") | ||||
| 	if err := sec.MapTo(&Git); err != nil { | ||||
| 		log.Fatal("Failed to map Git settings: %v", err) | ||||
| 	} | ||||
|  | ||||
| 	secGitConfig := rootCfg.Section("git.config") | ||||
| 	GitConfig.Options = make(map[string]string) | ||||
| 	for _, key := range secGitConfig.Keys() { | ||||
| 		// git config key is case-insensitive, so always use lower-case | ||||
| 		GitConfig.Options[strings.ToLower(key.Name())] = key.String() | ||||
| 	} | ||||
| 	if _, ok := GitConfig.Options["diff.algorithm"]; !ok { | ||||
| 		GitConfig.Options["diff.algorithm"] = "histogram" | ||||
| 	} | ||||
|  | ||||
| 	Git.HomePath = sec.Key("HOME_PATH").MustString("home") | ||||
| 	if !filepath.IsAbs(Git.HomePath) { | ||||
| 		Git.HomePath = filepath.Join(AppDataPath, Git.HomePath) | ||||
|   | ||||
							
								
								
									
										40
									
								
								modules/setting/git_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								modules/setting/git_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,40 @@ | ||||
| // Copyright 2019 The Gitea Authors. All rights reserved. | ||||
| // SPDX-License-Identifier: MIT | ||||
|  | ||||
| package setting | ||||
|  | ||||
| import ( | ||||
| 	"testing" | ||||
|  | ||||
| 	"github.com/stretchr/testify/assert" | ||||
| ) | ||||
|  | ||||
| func TestGitConfig(t *testing.T) { | ||||
| 	oldGit := Git | ||||
| 	oldGitConfig := GitConfig | ||||
| 	defer func() { | ||||
| 		Git = oldGit | ||||
| 		GitConfig = oldGitConfig | ||||
| 	}() | ||||
|  | ||||
| 	cfg, err := NewConfigProviderFromData(` | ||||
| [git.config] | ||||
| a.b = 1 | ||||
| `) | ||||
| 	assert.NoError(t, err) | ||||
| 	loadGitFrom(cfg) | ||||
|  | ||||
| 	assert.Len(t, GitConfig.Options, 2) | ||||
| 	assert.EqualValues(t, "1", GitConfig.Options["a.b"]) | ||||
| 	assert.EqualValues(t, "histogram", GitConfig.Options["diff.algorithm"]) | ||||
|  | ||||
| 	cfg, err = NewConfigProviderFromData(` | ||||
| [git.config] | ||||
| diff.algorithm = other | ||||
| `) | ||||
| 	assert.NoError(t, err) | ||||
| 	loadGitFrom(cfg) | ||||
|  | ||||
| 	assert.Len(t, GitConfig.Options, 1) | ||||
| 	assert.EqualValues(t, "other", GitConfig.Options["diff.algorithm"]) | ||||
| } | ||||
		Reference in New Issue
	
	Block a user