Skip to content

Commit 198342e

Browse files
zeripathKN4CK3R
andauthored
Add setting to disable the git apply step in test patch (#22130) (#22170)
Backport #22130 For a long time Gitea has tested PR patches using a git apply --check method, and in fact prior to the introduction of a read-tree assisted three-way merge in #18004, this was the only way of checking patches. Since #18004, the git apply --check method has been a fallback method, only used when the read-tree three-way merge method has detected a conflict. The read-tree assisted three-way merge method is much faster and less resource intensive method of detecting conflicts. #18004 kept the git apply method around because it was thought possible that this fallback might be able to rectify conflicts that the read-tree three-way merge detected. I am not certain if this could ever be the case. Given the uncertainty here and the now relative stability of the read-tree method - this PR makes using this fallback optional but enables it by default. A `log.Critical` has been added which will alert if the `git apply --check` method was successful at checking a PR that `read-tree` failed on. The hope is that none of these log.Critical messages will be found and there will be no significant difference in conflict detection. Thus we will be able to remove the git apply fallback in future, and/or improve the read-tree three-way merge method to catch any conflicts that git apply method might have been able to fix. An additional benefit for anyone who disables the check method is that patch checking should be significantly less resource intensive and much quicker. (See https://github.com/go-gitea/gitea/issues/22083\#issuecomment-1347961737) Ref #22083 Signed-off-by: Andrew Thornton <art27@cantab.net> <!-- Please check the following: 1. Make sure you are targeting the `main` branch, pull requests on release branches are only allowed for bug fixes. 2. Read contributing guidelines: https://github.com/go-gitea/gitea/blob/main/CONTRIBUTING.md 3. Describe what your pull request does and which issue you're targeting (if any) --> Signed-off-by: Andrew Thornton <art27@cantab.net> Co-authored-by: KN4CK3R <admin@oldschoolhack.me>
1 parent f7258aa commit 198342e

File tree

4 files changed

+27
-4
lines changed

4 files changed

+27
-4
lines changed

custom/conf/app.example.ini

+3
Original file line numberDiff line numberDiff line change
@@ -996,6 +996,9 @@ ROUTER = console
996996
;;
997997
;; Add co-authored-by and co-committed-by trailers if committer does not match author
998998
;ADD_CO_COMMITTER_TRAILERS = true
999+
;;
1000+
;; In addition to testing patches using the three-way merge method, re-test conflicting patches with git apply
1001+
;TEST_CONFLICTING_PATCHES_WITH_GIT_APPLY = true
9991002

10001003
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
10011004
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

docs/content/doc/advanced/config-cheat-sheet.en-us.md

+1
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ Values containing `#` or `;` must be quoted using `` ` `` or `"""`.
101101
- `DEFAULT_MERGE_MESSAGE_OFFICIAL_APPROVERS_ONLY`: **true**: In default merge messages only include approvers who are officially allowed to review.
102102
- `POPULATE_SQUASH_COMMENT_WITH_COMMIT_MESSAGES`: **false**: In default squash-merge messages include the commit message of all commits comprising the pull request.
103103
- `ADD_CO_COMMITTER_TRAILERS`: **true**: Add co-authored-by and co-committed-by trailers to merge commit messages if committer does not match author.
104+
- `TEST_CONFLICTING_PATCHES_WITH_GIT_APPLY`: **true**: PR patches are tested using a three-way merge method to discover if there are conflicts. If this setting is set to **true**, conflicting patches will be retested using `git apply` - This was the previous behaviour in 1.18 (and earlier) but is somewhat inefficient. Please report if you find that this setting is required.
104105

105106
### Repository - Issue (`repository.issue`)
106107

modules/setting/repository.go

+3
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ var (
8383
DefaultMergeMessageOfficialApproversOnly bool
8484
PopulateSquashCommentWithCommitMessages bool
8585
AddCoCommitterTrailers bool
86+
TestConflictingPatchesWithGitApply bool
8687
} `ini:"repository.pull-request"`
8788

8889
// Issue Setting
@@ -205,6 +206,7 @@ var (
205206
DefaultMergeMessageOfficialApproversOnly bool
206207
PopulateSquashCommentWithCommitMessages bool
207208
AddCoCommitterTrailers bool
209+
TestConflictingPatchesWithGitApply bool
208210
}{
209211
WorkInProgressPrefixes: []string{"WIP:", "[WIP]"},
210212
// Same as GitHub. See
@@ -219,6 +221,7 @@ var (
219221
DefaultMergeMessageOfficialApproversOnly: true,
220222
PopulateSquashCommentWithCommitMessages: false,
221223
AddCoCommitterTrailers: true,
224+
TestConflictingPatchesWithGitApply: true,
222225
},
223226

224227
// Issue settings

services/pull/patch.go

+20-4
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323
"code.gitea.io/gitea/modules/log"
2424
"code.gitea.io/gitea/modules/process"
2525
repo_module "code.gitea.io/gitea/modules/repository"
26+
"code.gitea.io/gitea/modules/setting"
2627
"code.gitea.io/gitea/modules/util"
2728

2829
"github.com/gobwas/glob"
@@ -289,13 +290,15 @@ func checkConflicts(ctx context.Context, pr *issues_model.PullRequest, gitRepo *
289290

290291
// 2. AttemptThreeWayMerge first - this is much quicker than plain patch to base
291292
description := fmt.Sprintf("PR[%d] %s/%s#%d", pr.ID, pr.BaseRepo.OwnerName, pr.BaseRepo.Name, pr.Index)
292-
conflict, _, err := AttemptThreeWayMerge(ctx,
293+
conflict, conflictFiles, err := AttemptThreeWayMerge(ctx,
293294
tmpBasePath, gitRepo, pr.MergeBase, "base", "tracking", description)
294295
if err != nil {
295296
return false, err
296297
}
297298

298299
if !conflict {
300+
// No conflicts detected so we need to check if the patch is empty...
301+
// a. Write the newly merged tree and check the new tree-hash
299302
var treeHash string
300303
treeHash, _, err = git.NewCommand(ctx, "write-tree").RunStdString(&git.RunOpts{Dir: tmpBasePath})
301304
if err != nil {
@@ -307,6 +310,8 @@ func checkConflicts(ctx context.Context, pr *issues_model.PullRequest, gitRepo *
307310
if err != nil {
308311
return false, err
309312
}
313+
314+
// b. compare the new tree-hash with the base tree hash
310315
if treeHash == baseTree.ID.String() {
311316
log.Debug("PullRequest[%d]: Patch is empty - ignoring", pr.ID)
312317
pr.Status = issues_model.PullRequestStatusEmpty
@@ -315,9 +320,17 @@ func checkConflicts(ctx context.Context, pr *issues_model.PullRequest, gitRepo *
315320
return false, nil
316321
}
317322

318-
// 3. OK read-tree has failed so we need to try a different thing - this might actually succeed where the above fails due to whitespace handling.
323+
// 3. OK the three-way merge method has detected conflicts
324+
// 3a. Are still testing with GitApply? If not set the conflict status and move on
325+
if !setting.Repository.PullRequest.TestConflictingPatchesWithGitApply {
326+
pr.Status = issues_model.PullRequestStatusConflict
327+
pr.ConflictedFiles = conflictFiles
328+
329+
log.Trace("Found %d files conflicted: %v", len(pr.ConflictedFiles), pr.ConflictedFiles)
330+
return true, nil
331+
}
319332

320-
// 3a. Create a plain patch from head to base
333+
// 3b. Create a plain patch from head to base
321334
tmpPatchFile, err := os.CreateTemp("", "patch")
322335
if err != nil {
323336
log.Error("Unable to create temporary patch file! Error: %v", err)
@@ -340,8 +353,9 @@ func checkConflicts(ctx context.Context, pr *issues_model.PullRequest, gitRepo *
340353
patchPath := tmpPatchFile.Name()
341354
tmpPatchFile.Close()
342355

343-
// 3b. if the size of that patch is 0 - there can be no conflicts!
356+
// 3c. if the size of that patch is 0 - there can be no conflicts!
344357
if stat.Size() == 0 {
358+
log.Critical("git-apply--check patch checker found empty PR when read-tree found conflicts in PR#%d[%d] in %#-v", pr.Index, pr.ID, pr.BaseRepo)
345359
log.Debug("PullRequest[%d]: Patch is empty - ignoring", pr.ID)
346360
pr.Status = issues_model.PullRequestStatusEmpty
347361
return false, nil
@@ -472,6 +486,8 @@ func checkConflicts(ctx context.Context, pr *issues_model.PullRequest, gitRepo *
472486
} else if err != nil {
473487
return false, fmt.Errorf("git apply --check: %w", err)
474488
}
489+
490+
log.Critical("git-apply--check patch checker found no conflicts when read-tree found conflicts in PR#%d[%d] in %#-v", pr.Index, pr.ID, pr.BaseRepo)
475491
return false, nil
476492
}
477493

0 commit comments

Comments
 (0)