Skip to content

Commit 69a4e6a

Browse files
committed
fix
1 parent 8e8ca6c commit 69a4e6a

28 files changed

+115
-143
lines changed

cmd/hook.go

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -220,10 +220,7 @@ Gitea or set your environment appropriately.`, "")
220220
}
221221
}
222222

223-
supportProcReceive := false
224-
if git.CheckGitVersionAtLeast("2.29") == nil {
225-
supportProcReceive = true
226-
}
223+
supportProcReceive := git.DefaultFeatures().SupportProcReceive
227224

228225
for scanner.Scan() {
229226
// TODO: support news feeds for wiki
@@ -497,7 +494,7 @@ Gitea or set your environment appropriately.`, "")
497494
return nil
498495
}
499496

500-
if git.CheckGitVersionAtLeast("2.29") != nil {
497+
if !git.DefaultFeatures().SupportProcReceive {
501498
return fail(ctx, "No proc-receive support", "current git version doesn't support proc-receive.")
502499
}
503500

cmd/serv.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ func runServ(c *cli.Context) error {
178178
}
179179

180180
if len(words) < 2 {
181-
if git.CheckGitVersionAtLeast("2.29") == nil {
181+
if git.DefaultFeatures().SupportProcReceive {
182182
// for AGit Flow
183183
if cmd == "ssh_info" {
184184
fmt.Print(`{"type":"gitea","version":1}`)

modules/git/blame.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ func (r *BlameReader) Close() error {
132132
// CreateBlameReader creates reader for given repository, commit and file
133133
func CreateBlameReader(ctx context.Context, objectFormat ObjectFormat, repoPath string, commit *Commit, file string, bypassBlameIgnore bool) (*BlameReader, error) {
134134
var ignoreRevsFile *string
135-
if CheckGitVersionAtLeast("2.23") == nil && !bypassBlameIgnore {
135+
if DefaultFeatures().CheckVersionAtLeast("2.23") && !bypassBlameIgnore {
136136
ignoreRevsFile = tryCreateBlameIgnoreRevsFile(commit)
137137
}
138138

modules/git/commit.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -423,7 +423,7 @@ func (c *Commit) GetSubModule(entryname string) (*SubModule, error) {
423423
// GetBranchName gets the closest branch name (as returned by 'git name-rev --name-only')
424424
func (c *Commit) GetBranchName() (string, error) {
425425
cmd := NewCommand(c.repo.Ctx, "name-rev")
426-
if CheckGitVersionAtLeast("2.13.0") == nil {
426+
if DefaultFeatures().CheckVersionAtLeast("2.13.0") {
427427
cmd.AddArguments("--exclude", "refs/tags/*")
428428
}
429429
cmd.AddArguments("--name-only", "--no-undefined").AddDynamicArguments(c.ID.String())

modules/git/git.go

Lines changed: 84 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -22,42 +22,65 @@ import (
2222
"github.com/hashicorp/go-version"
2323
)
2424

25-
// RequiredVersion is the minimum Git version required
26-
const RequiredVersion = "2.0.0"
25+
const RequiredVersion = "2.0.0" // the minimum Git version required
26+
27+
type Features struct {
28+
gitVersion *version.Version
29+
30+
UsingGogit bool
31+
SupportProcReceive bool // >= 2.29
32+
SupportHashSha256 bool // >= 2.42, SHA-256 repositories no longer an ‘experimental curiosity’
33+
SupportedObjectFormats []ObjectFormat // sha1, sha256
34+
}
2735

2836
var (
29-
// GitExecutable is the command name of git
30-
// Could be updated to an absolute path while initialization
31-
GitExecutable = "git"
37+
GitExecutable = "git" // the command name of git, will be updated to an absolute path during initialization
38+
DefaultContext context.Context // the default context to run git commands in, must be initialized by git.InitXxx
39+
defaultFeatures *Features
40+
)
3241

33-
// DefaultContext is the default context to run git commands in, must be initialized by git.InitXxx
34-
DefaultContext context.Context
42+
func (f *Features) CheckVersionAtLeast(atLeast string) bool {
43+
return f.gitVersion.Compare(version.Must(version.NewVersion(atLeast))) >= 0
44+
}
3545

36-
DefaultFeatures struct {
37-
GitVersion *version.Version
46+
// VersionInfo returns git version information
47+
func (f *Features) VersionInfo() string {
48+
return f.gitVersion.Original()
49+
}
3850

39-
SupportProcReceive bool // >= 2.29
40-
SupportHashSha256 bool // >= 2.42, SHA-256 repositories no longer an ‘experimental curiosity’
51+
func DefaultFeatures() *Features {
52+
if defaultFeatures == nil {
53+
if !setting.IsProd || setting.IsInTesting {
54+
log.Warn("git.DefaultFeatures is called before git.InitXxx, initializing with default values")
55+
}
56+
if err := InitSimple(context.Background()); err != nil {
57+
log.Fatal("git.InitSimple failed: %v", err)
58+
}
4159
}
42-
)
60+
return defaultFeatures
61+
}
4362

4463
// loadGitVersion tries to get the current git version and stores it into a global variable
45-
func loadGitVersion() error {
46-
// doesn't need RWMutex because it's executed by Init()
47-
if DefaultFeatures.GitVersion != nil {
48-
return nil
49-
}
50-
64+
func loadGitVersionFeatures() (*Features, error) {
5165
stdout, _, runErr := NewCommand(DefaultContext, "version").RunStdString(nil)
5266
if runErr != nil {
53-
return runErr
67+
return nil, runErr
5468
}
5569

5670
ver, err := parseGitVersionLine(strings.TrimSpace(stdout))
57-
if err == nil {
58-
DefaultFeatures.GitVersion = ver
71+
if err != nil {
72+
return nil, err
5973
}
60-
return err
74+
75+
features := &Features{gitVersion: ver, UsingGogit: isGogit}
76+
features.SupportProcReceive = features.CheckVersionAtLeast("2.29")
77+
features.SupportHashSha256 = features.CheckVersionAtLeast("2.42") && !isGogit
78+
79+
features.SupportedObjectFormats = append(features.SupportedObjectFormats, Sha1ObjectFormat)
80+
if features.SupportHashSha256 {
81+
features.SupportedObjectFormats = append(features.SupportedObjectFormats, Sha256ObjectFormat)
82+
}
83+
return features, nil
6184
}
6285

6386
func parseGitVersionLine(s string) (*version.Version, error) {
@@ -85,56 +108,24 @@ func SetExecutablePath(path string) error {
85108
return fmt.Errorf("git not found: %w", err)
86109
}
87110
GitExecutable = absPath
111+
return nil
112+
}
88113

89-
if err = loadGitVersion(); err != nil {
90-
return fmt.Errorf("unable to load git version: %w", err)
91-
}
92-
93-
versionRequired, err := version.NewVersion(RequiredVersion)
94-
if err != nil {
95-
return err
96-
}
97-
98-
if DefaultFeatures.GitVersion.LessThan(versionRequired) {
114+
func ensureGitVersion() error {
115+
if !DefaultFeatures().CheckVersionAtLeast(RequiredVersion) {
99116
moreHint := "get git: https://git-scm.com/download/"
100117
if runtime.GOOS == "linux" {
101118
// there are a lot of CentOS/RHEL users using old git, so we add a special hint for them
102-
if _, err = os.Stat("/etc/redhat-release"); err == nil {
119+
if _, err := os.Stat("/etc/redhat-release"); err == nil {
103120
// ius.io is the recommended official(git-scm.com) method to install git
104121
moreHint = "get git: https://git-scm.com/download/linux and https://ius.io"
105122
}
106123
}
107-
return fmt.Errorf("installed git version %q is not supported, Gitea requires git version >= %q, %s", DefaultFeatures.GitVersion.Original(), RequiredVersion, moreHint)
108-
}
109-
110-
if err = checkGitVersionCompatibility(DefaultFeatures.GitVersion); err != nil {
111-
return fmt.Errorf("installed git version %s has a known compatibility issue with Gitea: %w, please upgrade (or downgrade) git", DefaultFeatures.GitVersion.String(), err)
124+
return fmt.Errorf("installed git version %q is not supported, Gitea requires git version >= %q, %s", DefaultFeatures().gitVersion.Original(), RequiredVersion, moreHint)
112125
}
113-
return nil
114-
}
115-
116-
// VersionInfo returns git version information
117-
func VersionInfo() string {
118-
if DefaultFeatures.GitVersion == nil {
119-
return "(git not found)"
120-
}
121-
format := "%s"
122-
args := []any{DefaultFeatures.GitVersion.Original()}
123-
// Since git wire protocol has been released from git v2.18
124-
if setting.Git.EnableAutoGitWireProtocol && CheckGitVersionAtLeast("2.18") == nil {
125-
format += ", Wire Protocol %s Enabled"
126-
args = append(args, "Version 2") // for focus color
127-
}
128-
129-
return fmt.Sprintf(format, args...)
130-
}
131126

132-
func checkInit() error {
133-
if setting.Git.HomePath == "" {
134-
return errors.New("unable to init Git's HomeDir, incorrect initialization of the setting and git modules")
135-
}
136-
if DefaultContext != nil {
137-
log.Warn("git module has been initialized already, duplicate init may work but it's better to fix it")
127+
if err := checkGitVersionCompatibility(DefaultFeatures().gitVersion); err != nil {
128+
return fmt.Errorf("installed git version %s has a known compatibility issue with Gitea: %w, please upgrade (or downgrade) git", DefaultFeatures().gitVersion.String(), err)
138129
}
139130
return nil
140131
}
@@ -154,8 +145,12 @@ func HomeDir() string {
154145
// InitSimple initializes git module with a very simple step, no config changes, no global command arguments.
155146
// This method doesn't change anything to filesystem. At the moment, it is only used by some Gitea sub-commands.
156147
func InitSimple(ctx context.Context) error {
157-
if err := checkInit(); err != nil {
158-
return err
148+
if setting.Git.HomePath == "" {
149+
return errors.New("unable to init Git's HomeDir, incorrect initialization of the setting and git modules")
150+
}
151+
152+
if DefaultContext != nil && (!setting.IsProd || setting.IsInTesting) {
153+
log.Warn("git module has been initialized already, duplicate init may work but it's better to fix it")
159154
}
160155

161156
DefaultContext = ctx
@@ -165,40 +160,45 @@ func InitSimple(ctx context.Context) error {
165160
defaultCommandExecutionTimeout = time.Duration(setting.Git.Timeout.Default) * time.Second
166161
}
167162

168-
return SetExecutablePath(setting.Git.Path)
169-
}
163+
if err := SetExecutablePath(setting.Git.Path); err != nil {
164+
return err
165+
}
170166

171-
// InitFull initializes git module with version check and change global variables, sync gitconfig.
172-
// It should only be called once at the beginning of the program initialization (TestMain/GlobalInitInstalled) as this code makes unsynchronized changes to variables.
173-
func InitFull(ctx context.Context) (err error) {
174-
if err = InitSimple(ctx); err != nil {
167+
var err error
168+
defaultFeatures, err = loadGitVersionFeatures()
169+
if err != nil {
170+
return err
171+
}
172+
if err = ensureGitVersion(); err != nil {
175173
return err
176174
}
177175

178176
// when git works with gnupg (commit signing), there should be a stable home for gnupg commands
179177
if _, ok := os.LookupEnv("GNUPGHOME"); !ok {
180178
_ = os.Setenv("GNUPGHOME", filepath.Join(HomeDir(), ".gnupg"))
181179
}
180+
return nil
181+
}
182+
183+
// InitFull initializes git module with version check and change global variables, sync gitconfig.
184+
// It should only be called once at the beginning of the program initialization (TestMain/GlobalInitInstalled) as this code makes unsynchronized changes to variables.
185+
func InitFull(ctx context.Context) (err error) {
186+
if err = InitSimple(ctx); err != nil {
187+
return err
188+
}
182189

183190
// Since git wire protocol has been released from git v2.18
184-
if setting.Git.EnableAutoGitWireProtocol && CheckGitVersionAtLeast("2.18") == nil {
191+
if setting.Git.EnableAutoGitWireProtocol && DefaultFeatures().CheckVersionAtLeast("2.18") {
185192
globalCommandArgs = append(globalCommandArgs, "-c", "protocol.version=2")
186193
}
187194

188195
// Explicitly disable credential helper, otherwise Git credentials might leak
189-
if CheckGitVersionAtLeast("2.9") == nil {
196+
if DefaultFeatures().CheckVersionAtLeast("2.9") {
190197
globalCommandArgs = append(globalCommandArgs, "-c", "credential.helper=")
191198
}
192-
DefaultFeatures.SupportProcReceive = CheckGitVersionAtLeast("2.29") == nil
193-
DefaultFeatures.SupportHashSha256 = CheckGitVersionAtLeast("2.42") == nil && !isGogit
194-
if DefaultFeatures.SupportHashSha256 {
195-
SupportedObjectFormats = append(SupportedObjectFormats, Sha256ObjectFormat)
196-
} else {
197-
log.Warn("sha256 hash support is disabled - requires Git >= 2.42. Gogit is currently unsupported")
198-
}
199199

200200
if setting.LFS.StartServer {
201-
if CheckGitVersionAtLeast("2.1.2") != nil {
201+
if !DefaultFeatures().CheckVersionAtLeast("2.1.2") {
202202
return errors.New("LFS server support requires Git >= 2.1.2")
203203
}
204204
globalCommandArgs = append(globalCommandArgs, "-c", "filter.lfs.required=", "-c", "filter.lfs.smudge=", "-c", "filter.lfs.clean=")
@@ -238,13 +238,13 @@ func syncGitConfig() (err error) {
238238
return err
239239
}
240240

241-
if CheckGitVersionAtLeast("2.10") == nil {
241+
if DefaultFeatures().CheckVersionAtLeast("2.10") {
242242
if err := configSet("receive.advertisePushOptions", "true"); err != nil {
243243
return err
244244
}
245245
}
246246

247-
if CheckGitVersionAtLeast("2.18") == nil {
247+
if DefaultFeatures().CheckVersionAtLeast("2.18") {
248248
if err := configSet("core.commitGraph", "true"); err != nil {
249249
return err
250250
}
@@ -256,7 +256,7 @@ func syncGitConfig() (err error) {
256256
}
257257
}
258258

259-
if DefaultFeatures.SupportProcReceive {
259+
if DefaultFeatures().SupportProcReceive {
260260
// set support for AGit flow
261261
if err := configAddNonExist("receive.procReceiveRefs", "refs/for"); err != nil {
262262
return err
@@ -294,7 +294,7 @@ func syncGitConfig() (err error) {
294294
}
295295

296296
// By default partial clones are disabled, enable them from git v2.22
297-
if !setting.Git.DisablePartialClone && CheckGitVersionAtLeast("2.22") == nil {
297+
if !setting.Git.DisablePartialClone && DefaultFeatures().CheckVersionAtLeast("2.22") {
298298
if err = configSet("uploadpack.allowfilter", "true"); err != nil {
299299
return err
300300
}
@@ -309,21 +309,6 @@ func syncGitConfig() (err error) {
309309
return err
310310
}
311311

312-
// CheckGitVersionAtLeast check git version is at least the constraint version
313-
func CheckGitVersionAtLeast(atLeast string) error {
314-
if DefaultFeatures.GitVersion == nil {
315-
panic("git module is not initialized") // it shouldn't happen
316-
}
317-
atLeastVersion, err := version.NewVersion(atLeast)
318-
if err != nil {
319-
return err
320-
}
321-
if DefaultFeatures.GitVersion.Compare(atLeastVersion) < 0 {
322-
return fmt.Errorf("installed git binary version %s is not at least %s", DefaultFeatures.GitVersion.Original(), atLeast)
323-
}
324-
return nil
325-
}
326-
327312
func checkGitVersionCompatibility(gitVer *version.Version) error {
328313
badVersions := []struct {
329314
Version *version.Version

modules/git/object_format.go

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -120,12 +120,8 @@ var (
120120
Sha256ObjectFormat ObjectFormat = Sha256ObjectFormatImpl{}
121121
)
122122

123-
var SupportedObjectFormats = []ObjectFormat{
124-
Sha1ObjectFormat,
125-
}
126-
127123
func ObjectFormatFromName(name string) ObjectFormat {
128-
for _, objectFormat := range SupportedObjectFormats {
124+
for _, objectFormat := range DefaultFeatures().SupportedObjectFormats {
129125
if name == objectFormat.Name() {
130126
return objectFormat
131127
}

modules/git/object_id.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ func (*Sha256Hash) Type() ObjectFormat { return Sha256ObjectFormat }
5454

5555
func NewIDFromString(hexHash string) (ObjectID, error) {
5656
var theObjectFormat ObjectFormat
57-
for _, objectFormat := range SupportedObjectFormats {
57+
for _, objectFormat := range DefaultFeatures().SupportedObjectFormats {
5858
if len(hexHash) == objectFormat.FullLength() {
5959
theObjectFormat = objectFormat
6060
break

modules/git/remote.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import (
1212
// GetRemoteAddress returns remote url of git repository in the repoPath with special remote name
1313
func GetRemoteAddress(ctx context.Context, repoPath, remoteName string) (string, error) {
1414
var cmd *Command
15-
if CheckGitVersionAtLeast("2.7") == nil {
15+
if DefaultFeatures().CheckVersionAtLeast("2.7") {
1616
cmd = NewCommand(ctx, "remote", "get-url").AddDynamicArguments(remoteName)
1717
} else {
1818
cmd = NewCommand(ctx, "config", "--get").AddDynamicArguments("remote." + remoteName + ".url")

modules/git/repo.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ func InitRepository(ctx context.Context, repoPath string, bare bool, objectForma
101101
if !IsValidObjectFormat(objectFormatName) {
102102
return fmt.Errorf("invalid object format: %s", objectFormatName)
103103
}
104-
if DefaultFeatures.SupportHashSha256 {
104+
if DefaultFeatures().SupportHashSha256 {
105105
cmd.AddOptionValues("--object-format", objectFormatName)
106106
}
107107

modules/git/repo_base.go

Lines changed: 0 additions & 6 deletions
This file was deleted.

modules/git/repo_base_gogit.go

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,7 @@ import (
2222
"github.com/go-git/go-git/v5/storage/filesystem"
2323
)
2424

25-
func init() {
26-
isGogit = true
27-
}
25+
const isGogit = true
2826

2927
// Repository represents a Git repository.
3028
type Repository struct {

0 commit comments

Comments
 (0)