Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support changing git config through app.ini, use diff.algorithm=histogram by default #24860

Merged
merged 11 commits into from
May 23, 2023
48 changes: 22 additions & 26 deletions custom/conf/app.example.ini
Original file line number Diff line number Diff line change
Expand Up @@ -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
delvh marked this conversation as resolved.
Show resolved Hide resolved

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; 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]
Expand Down Expand Up @@ -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]
Expand Down
19 changes: 13 additions & 6 deletions docs/content/doc/administration/config-cheat-sheet.en-us.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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.
Expand Down
16 changes: 16 additions & 0 deletions docs/content/doc/administration/customizing-gitea.en-us.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`:
Expand Down
8 changes: 8 additions & 0 deletions modules/git/git.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
24 changes: 18 additions & 6 deletions modules/git/git_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,14 @@ func TestMain(m *testing.M) {
}
}

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
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"))
Expand Down Expand Up @@ -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"))
}
17 changes: 17 additions & 0 deletions modules/setting/git.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ package setting

import (
"path/filepath"
"strings"
"time"

"code.gitea.io/gitea/modules/log"
Expand Down Expand Up @@ -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)
Expand Down
40 changes: 40 additions & 0 deletions modules/setting/git_test.go
Original file line number Diff line number Diff line change
@@ -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"])
}