From f7dd7fe2634133b01e837646622507afa7bb9729 Mon Sep 17 00:00:00 2001 From: silverwind Date: Mon, 15 Dec 2025 10:37:59 +0100 Subject: [PATCH 1/9] Add git.DIFF_RENAME_THRESHOLD option --- custom/conf/app.example.ini | 2 ++ modules/setting/git.go | 2 ++ services/gitdiff/git_diff_tree.go | 4 +++- services/gitdiff/gitdiff.go | 4 +++- 4 files changed, 10 insertions(+), 2 deletions(-) diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini index 2ade8455909a9..00b83a9ba2193 100644 --- a/custom/conf/app.example.ini +++ b/custom/conf/app.example.ini @@ -733,6 +733,8 @@ LEVEL = Info ;DISABLE_CORE_PROTECT_NTFS=false ;; Disable the usage of using partial clones for git. ;DISABLE_PARTIAL_CLONE = false +;; Set the similarity threshold passed to git rename detection via `--find-renames=` +;DIFF_RENAME_THRESHOLD = 50% ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Git Operation timeout in seconds diff --git a/modules/setting/git.go b/modules/setting/git.go index 48a4e7f30deb5..4f2abe5c23b3c 100644 --- a/modules/setting/git.go +++ b/modules/setting/git.go @@ -30,6 +30,7 @@ var Git = struct { LargeObjectThreshold int64 DisableCoreProtectNTFS bool DisablePartialClone bool + DiffRenameThreshold string Timeout struct { Default int Migrate int @@ -52,6 +53,7 @@ var Git = struct { PullRequestPushMessage: true, LargeObjectThreshold: 1024 * 1024, DisablePartialClone: false, + DiffRenameThreshold: "50%", Timeout: struct { Default int Migrate int diff --git a/services/gitdiff/git_diff_tree.go b/services/gitdiff/git_diff_tree.go index 4649c24af311b..ca69675b306f7 100644 --- a/services/gitdiff/git_diff_tree.go +++ b/services/gitdiff/git_diff_tree.go @@ -15,6 +15,7 @@ import ( "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/git/gitcmd" "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/setting" ) type DiffTree struct { @@ -56,7 +57,8 @@ func runGitDiffTree(ctx context.Context, gitRepo *git.Repository, useMergeBase b return nil, err } - cmd := gitcmd.NewCommand("diff-tree", "--raw", "-r", "--find-renames", "--root") + cmd := gitcmd.NewCommand("diff-tree", "--raw", "-r", "--root") + cmd.AddOptionFormat("--find-renames=%s", setting.Git.DiffRenameThreshold) if useMergeBase { cmd.AddArguments("--merge-base") } diff --git a/services/gitdiff/gitdiff.go b/services/gitdiff/gitdiff.go index 34e94671a2523..06ecf833bfa1f 100644 --- a/services/gitdiff/gitdiff.go +++ b/services/gitdiff/gitdiff.go @@ -1225,9 +1225,11 @@ func getDiffBasic(ctx context.Context, gitRepo *git.Repository, opts *DiffOption } cmdDiff := gitcmd.NewCommand(). - AddArguments("diff", "--src-prefix=\\a/", "--dst-prefix=\\b/", "-M"). + AddArguments("diff", "--src-prefix=\\a/", "--dst-prefix=\\b/"). AddArguments(opts.WhitespaceBehavior...) + cmdDiff.AddOptionFormat("--find-renames=%s", setting.Git.DiffRenameThreshold) + // In git 2.31, git diff learned --skip-to which we can use to shortcut skip to file // so if we are using at least this version of git we don't have to tell ParsePatch to do // the skipping for us From 44a7d1a9f560dc5a7b708b4822ef52b4701230bc Mon Sep 17 00:00:00 2001 From: silverwind Date: Mon, 15 Dec 2025 10:55:56 +0100 Subject: [PATCH 2/9] rename to DIFF_RENAME_SIMILARITY_THRESHOLD and change to 25% --- modules/setting/git.go | 58 +++++++++++++++---------------- services/gitdiff/git_diff_tree.go | 2 +- services/gitdiff/gitdiff.go | 2 +- 3 files changed, 31 insertions(+), 31 deletions(-) diff --git a/modules/setting/git.go b/modules/setting/git.go index 4f2abe5c23b3c..f8227ab2c948c 100644 --- a/modules/setting/git.go +++ b/modules/setting/git.go @@ -17,21 +17,21 @@ var Git = struct { HomePath string DisableDiffHighlight bool - MaxGitDiffLines int - MaxGitDiffLineCharacters int - MaxGitDiffFiles int - CommitsRangeSize int // CommitsRangeSize the default commits range size - BranchesRangeSize int // BranchesRangeSize the default branches range size - VerbosePush bool - VerbosePushDelay time.Duration - GCArgs []string `ini:"GC_ARGS" delim:" "` - EnableAutoGitWireProtocol bool - PullRequestPushMessage bool - LargeObjectThreshold int64 - DisableCoreProtectNTFS bool - DisablePartialClone bool - DiffRenameThreshold string - Timeout struct { + MaxGitDiffLines int + MaxGitDiffLineCharacters int + MaxGitDiffFiles int + CommitsRangeSize int // CommitsRangeSize the default commits range size + BranchesRangeSize int // BranchesRangeSize the default branches range size + VerbosePush bool + VerbosePushDelay time.Duration + GCArgs []string `ini:"GC_ARGS" delim:" "` + EnableAutoGitWireProtocol bool + PullRequestPushMessage bool + LargeObjectThreshold int64 + DisableCoreProtectNTFS bool + DisablePartialClone bool + DiffRenameSimilarityThreshold string + Timeout struct { Default int Migrate int Mirror int @@ -40,20 +40,20 @@ var Git = struct { GC int `ini:"GC"` } `ini:"git.timeout"` }{ - DisableDiffHighlight: false, - MaxGitDiffLines: 1000, - MaxGitDiffLineCharacters: 5000, - MaxGitDiffFiles: 100, - CommitsRangeSize: 50, - BranchesRangeSize: 20, - VerbosePush: true, - VerbosePushDelay: 5 * time.Second, - GCArgs: []string{}, - EnableAutoGitWireProtocol: true, - PullRequestPushMessage: true, - LargeObjectThreshold: 1024 * 1024, - DisablePartialClone: false, - DiffRenameThreshold: "50%", + DisableDiffHighlight: false, + MaxGitDiffLines: 1000, + MaxGitDiffLineCharacters: 5000, + MaxGitDiffFiles: 100, + CommitsRangeSize: 50, + BranchesRangeSize: 20, + VerbosePush: true, + VerbosePushDelay: 5 * time.Second, + GCArgs: []string{}, + EnableAutoGitWireProtocol: true, + PullRequestPushMessage: true, + LargeObjectThreshold: 1024 * 1024, + DisablePartialClone: false, + DiffRenameSimilarityThreshold: "25%", Timeout: struct { Default int Migrate int diff --git a/services/gitdiff/git_diff_tree.go b/services/gitdiff/git_diff_tree.go index ca69675b306f7..5a1fa2098f42c 100644 --- a/services/gitdiff/git_diff_tree.go +++ b/services/gitdiff/git_diff_tree.go @@ -58,7 +58,7 @@ func runGitDiffTree(ctx context.Context, gitRepo *git.Repository, useMergeBase b } cmd := gitcmd.NewCommand("diff-tree", "--raw", "-r", "--root") - cmd.AddOptionFormat("--find-renames=%s", setting.Git.DiffRenameThreshold) + cmd.AddOptionFormat("--find-renames=%s", setting.Git.DiffRenameSimilarityThreshold) if useMergeBase { cmd.AddArguments("--merge-base") } diff --git a/services/gitdiff/gitdiff.go b/services/gitdiff/gitdiff.go index 06ecf833bfa1f..34afae41d6bd0 100644 --- a/services/gitdiff/gitdiff.go +++ b/services/gitdiff/gitdiff.go @@ -1228,7 +1228,7 @@ func getDiffBasic(ctx context.Context, gitRepo *git.Repository, opts *DiffOption AddArguments("diff", "--src-prefix=\\a/", "--dst-prefix=\\b/"). AddArguments(opts.WhitespaceBehavior...) - cmdDiff.AddOptionFormat("--find-renames=%s", setting.Git.DiffRenameThreshold) + cmdDiff.AddOptionFormat("--find-renames=%s", setting.Git.DiffRenameSimilarityThreshold) // In git 2.31, git diff learned --skip-to which we can use to shortcut skip to file // so if we are using at least this version of git we don't have to tell ParsePatch to do From ee2c98ebeeb1bc833fd6b7ddff640c3b0a194bf3 Mon Sep 17 00:00:00 2001 From: silverwind Date: Mon, 15 Dec 2025 10:57:45 +0100 Subject: [PATCH 3/9] doc --- custom/conf/app.example.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini index 00b83a9ba2193..80985af2282e0 100644 --- a/custom/conf/app.example.ini +++ b/custom/conf/app.example.ini @@ -734,7 +734,7 @@ LEVEL = Info ;; Disable the usage of using partial clones for git. ;DISABLE_PARTIAL_CLONE = false ;; Set the similarity threshold passed to git rename detection via `--find-renames=` -;DIFF_RENAME_THRESHOLD = 50% +;DIFF_RENAME_SIMILARITY_THRESHOLD = 50% ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Git Operation timeout in seconds From fc255f186c2bf0628d1af4370cd090286fe149b0 Mon Sep 17 00:00:00 2001 From: silverwind Date: Mon, 15 Dec 2025 10:58:53 +0100 Subject: [PATCH 4/9] doc --- custom/conf/app.example.ini | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini index 80985af2282e0..5f0b93a0d4f8f 100644 --- a/custom/conf/app.example.ini +++ b/custom/conf/app.example.ini @@ -733,8 +733,8 @@ LEVEL = Info ;DISABLE_CORE_PROTECT_NTFS=false ;; Disable the usage of using partial clones for git. ;DISABLE_PARTIAL_CLONE = false -;; Set the similarity threshold passed to git rename detection via `--find-renames=` -;DIFF_RENAME_SIMILARITY_THRESHOLD = 50% +;; Set the similarity threshold passed to git rename detection via `--find-renames=`. Default is 25%, git's default is 50%. +;DIFF_RENAME_SIMILARITY_THRESHOLD = 25% ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Git Operation timeout in seconds From a6ee2c402a6ebeac7215fc41e07916af05b6af19 Mon Sep 17 00:00:00 2001 From: silverwind Date: Mon, 15 Dec 2025 19:44:36 +0100 Subject: [PATCH 5/9] revert to 50% --- custom/conf/app.example.ini | 4 ++-- modules/setting/git.go | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini index 5f0b93a0d4f8f..14de7269ab58b 100644 --- a/custom/conf/app.example.ini +++ b/custom/conf/app.example.ini @@ -733,8 +733,8 @@ LEVEL = Info ;DISABLE_CORE_PROTECT_NTFS=false ;; Disable the usage of using partial clones for git. ;DISABLE_PARTIAL_CLONE = false -;; Set the similarity threshold passed to git rename detection via `--find-renames=`. Default is 25%, git's default is 50%. -;DIFF_RENAME_SIMILARITY_THRESHOLD = 25% +;; Set the similarity threshold passed to git rename detection via `--find-renames=`. Default is 50%, the same as git. +;DIFF_RENAME_SIMILARITY_THRESHOLD = 50% ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Git Operation timeout in seconds diff --git a/modules/setting/git.go b/modules/setting/git.go index f8227ab2c948c..75b8c4196609b 100644 --- a/modules/setting/git.go +++ b/modules/setting/git.go @@ -53,7 +53,7 @@ var Git = struct { PullRequestPushMessage: true, LargeObjectThreshold: 1024 * 1024, DisablePartialClone: false, - DiffRenameSimilarityThreshold: "25%", + DiffRenameSimilarityThreshold: "50%", Timeout: struct { Default int Migrate int From 2963dfce741963a71193187d9636f2ccd9903729 Mon Sep 17 00:00:00 2001 From: silverwind Date: Mon, 15 Dec 2025 19:50:34 +0100 Subject: [PATCH 6/9] use in more places --- modules/git/diff.go | 9 +++++++-- services/gitdiff/gitdiff.go | 5 ++--- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/modules/git/diff.go b/modules/git/diff.go index c97a2141bf794..309d8f4615a49 100644 --- a/modules/git/diff.go +++ b/modules/git/diff.go @@ -16,6 +16,7 @@ import ( "code.gitea.io/gitea/modules/git/gitcmd" "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/setting" ) // RawDiffType type of a raw diff. @@ -47,7 +48,9 @@ func GetRepoRawDiffForFile(repo *Repository, startCommit, endCommit string, diff switch diffType { case RawDiffNormal: if len(startCommit) != 0 { - cmd.AddArguments("diff", "-M").AddDynamicArguments(startCommit, endCommit).AddDashesAndList(files...) + cmd.AddArguments("diff"). + AddOptionFormat("--find-renames=%s", setting.Git.DiffRenameSimilarityThreshold). + AddDynamicArguments(startCommit, endCommit).AddDashesAndList(files...) } else if commit.ParentCount() == 0 { cmd.AddArguments("show").AddDynamicArguments(endCommit).AddDashesAndList(files...) } else { @@ -55,7 +58,9 @@ func GetRepoRawDiffForFile(repo *Repository, startCommit, endCommit string, diff if err != nil { return err } - cmd.AddArguments("diff", "-M").AddDynamicArguments(c.ID.String(), endCommit).AddDashesAndList(files...) + cmd.AddArguments("diff"). + AddOptionFormat("--find-renames=%s", setting.Git.DiffRenameSimilarityThreshold). + AddDynamicArguments(c.ID.String(), endCommit).AddDashesAndList(files...) } case RawDiffPatch: if len(startCommit) != 0 { diff --git a/services/gitdiff/gitdiff.go b/services/gitdiff/gitdiff.go index 34afae41d6bd0..17eb3d4280319 100644 --- a/services/gitdiff/gitdiff.go +++ b/services/gitdiff/gitdiff.go @@ -1226,9 +1226,8 @@ func getDiffBasic(ctx context.Context, gitRepo *git.Repository, opts *DiffOption cmdDiff := gitcmd.NewCommand(). AddArguments("diff", "--src-prefix=\\a/", "--dst-prefix=\\b/"). - AddArguments(opts.WhitespaceBehavior...) - - cmdDiff.AddOptionFormat("--find-renames=%s", setting.Git.DiffRenameSimilarityThreshold) + AddArguments(opts.WhitespaceBehavior...). + AddOptionFormat("--find-renames=%s", setting.Git.DiffRenameSimilarityThreshold) // In git 2.31, git diff learned --skip-to which we can use to shortcut skip to file // so if we are using at least this version of git we don't have to tell ParsePatch to do From b2715ca10be08c562e521883b607ecbb9490f463 Mon Sep 17 00:00:00 2001 From: silverwind Date: Mon, 15 Dec 2025 19:53:01 +0100 Subject: [PATCH 7/9] use chaining --- services/gitdiff/git_diff_tree.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/services/gitdiff/git_diff_tree.go b/services/gitdiff/git_diff_tree.go index 5a1fa2098f42c..2a3c7c944504f 100644 --- a/services/gitdiff/git_diff_tree.go +++ b/services/gitdiff/git_diff_tree.go @@ -57,8 +57,9 @@ func runGitDiffTree(ctx context.Context, gitRepo *git.Repository, useMergeBase b return nil, err } - cmd := gitcmd.NewCommand("diff-tree", "--raw", "-r", "--root") - cmd.AddOptionFormat("--find-renames=%s", setting.Git.DiffRenameSimilarityThreshold) + cmd := gitcmd.NewCommand("diff-tree", "--raw", "-r", "--root"). + AddOptionFormat("--find-renames=%s", setting.Git.DiffRenameSimilarityThreshold) + if useMergeBase { cmd.AddArguments("--merge-base") } From c094b03a94b6435f34455ce83fd690d884ef8867 Mon Sep 17 00:00:00 2001 From: silverwind Date: Mon, 15 Dec 2025 20:56:31 +0100 Subject: [PATCH 8/9] validate the value --- custom/conf/app.example.ini | 3 ++- modules/setting/git.go | 6 ++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini index 14de7269ab58b..fe2e404a6d770 100644 --- a/custom/conf/app.example.ini +++ b/custom/conf/app.example.ini @@ -733,7 +733,8 @@ LEVEL = Info ;DISABLE_CORE_PROTECT_NTFS=false ;; Disable the usage of using partial clones for git. ;DISABLE_PARTIAL_CLONE = false -;; Set the similarity threshold passed to git rename detection via `--find-renames=`. Default is 50%, the same as git. +;; Set the similarity threshold passed to git rename detection via `--find-renames=`. +;; Default is 50%, the same as git. Must be a integer percentage between 0% and 100%. ;DIFF_RENAME_SIMILARITY_THRESHOLD = 50% ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; diff --git a/modules/setting/git.go b/modules/setting/git.go index 75b8c4196609b..318f2c0cacc6f 100644 --- a/modules/setting/git.go +++ b/modules/setting/git.go @@ -5,6 +5,7 @@ package setting import ( "path/filepath" + "regexp" "strings" "time" @@ -119,4 +120,9 @@ func loadGitFrom(rootCfg ConfigProvider) { } else { Git.HomePath = filepath.Clean(Git.HomePath) } + + // validate for a integer percentage between 0% and 100% + if !regexp.MustCompile(`^([0-9]|[1-9][0-9]|100)%$`).MatchString(Git.DiffRenameSimilarityThreshold) { + log.Fatal("Invalid git.DIFF_RENAME_SIMILARITY_THRESHOLD: %s", Git.DiffRenameSimilarityThreshold) + } } From ef6927aebc0b7c3bbe0ad163bd0cf291cad67750 Mon Sep 17 00:00:00 2001 From: silverwind Date: Mon, 15 Dec 2025 21:00:50 +0100 Subject: [PATCH 9/9] tweak doc --- custom/conf/app.example.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini index fe2e404a6d770..475c62ab6c423 100644 --- a/custom/conf/app.example.ini +++ b/custom/conf/app.example.ini @@ -733,7 +733,7 @@ LEVEL = Info ;DISABLE_CORE_PROTECT_NTFS=false ;; Disable the usage of using partial clones for git. ;DISABLE_PARTIAL_CLONE = false -;; Set the similarity threshold passed to git rename detection via `--find-renames=`. +;; Set the similarity threshold passed to git commands via `--find-renames=`. ;; Default is 50%, the same as git. Must be a integer percentage between 0% and 100%. ;DIFF_RENAME_SIMILARITY_THRESHOLD = 50%