Skip to content

Commit 0feb4dc

Browse files
committed
Add setting to disable the git apply step in test patch
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 go-gitea#18004, this was the only way of checking patches. Since go-gitea#18004, the git apply --check method has been a fallback method, only used when the read-tree method has detected a conflict. The read-tree assisted three-way merge method is much faster and less resource intensive method of detecting conflicts. go-gitea#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 and disables it by default. The hope is that users will not mention any significant difference in conflict detection and 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 incorrectly detecting. (See https://github.com/go-gitea/gitea/issues/22083\#issuecomment-1347961737) Ref go-gitea#22083 Signed-off-by: Andrew Thornton <art27@cantab.net>
1 parent a95247b commit 0feb4dc

File tree

4 files changed

+23
-4
lines changed

4 files changed

+23
-4
lines changed

custom/conf/app.example.ini

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1036,6 +1036,9 @@ ROUTER = console
10361036
;;
10371037
;; Add co-authored-by and co-committed-by trailers if committer does not match author
10381038
;ADD_CO_COMMITTER_TRAILERS = true
1039+
;;
1040+
;; In addition to testing patches using the three-way merge method, re-test conflicting patches with git apply
1041+
;TEST_CONFLICTING_PATCHES_WITH_GIT_APPLY = false
10391042

10401043
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
10411044
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@ In addition there is _`StaticRootPath`_ which can be set as a built-in at build
134134
- `DEFAULT_MERGE_MESSAGE_OFFICIAL_APPROVERS_ONLY`: **true**: In default merge messages only include approvers who are officially allowed to review.
135135
- `POPULATE_SQUASH_COMMENT_WITH_COMMIT_MESSAGES`: **false**: In default squash-merge messages include the commit message of all commits comprising the pull request.
136136
- `ADD_CO_COMMITTER_TRAILERS`: **true**: Add co-authored-by and co-committed-by trailers to merge commit messages if committer does not match author.
137+
- `TEST_CONFLICTING_PATCHES_WITH_GIT_APPLY`: **false**: 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.
137138

138139
### Repository - Issue (`repository.issue`)
139140

modules/setting/repository.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ var (
8282
DefaultMergeMessageOfficialApproversOnly bool
8383
PopulateSquashCommentWithCommitMessages bool
8484
AddCoCommitterTrailers bool
85+
TestConflictingPatchesWithGitApply bool
8586
} `ini:"repository.pull-request"`
8687

8788
// Issue Setting
@@ -204,6 +205,7 @@ var (
204205
DefaultMergeMessageOfficialApproversOnly bool
205206
PopulateSquashCommentWithCommitMessages bool
206207
AddCoCommitterTrailers bool
208+
TestConflictingPatchesWithGitApply bool
207209
}{
208210
WorkInProgressPrefixes: []string{"WIP:", "[WIP]"},
209211
// Same as GitHub. See

services/pull/patch.go

Lines changed: 17 additions & 4 deletions
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"
@@ -287,13 +288,15 @@ func checkConflicts(ctx context.Context, pr *issues_model.PullRequest, gitRepo *
287288

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

296297
if !conflict {
298+
// No conflicts detected so we need to check if the patch is empty...
299+
// a. Write the newly merged tree and check the new tree-hash
297300
var treeHash string
298301
treeHash, _, err = git.NewCommand(ctx, "write-tree").RunStdString(&git.RunOpts{Dir: tmpBasePath})
299302
if err != nil {
@@ -305,6 +308,8 @@ func checkConflicts(ctx context.Context, pr *issues_model.PullRequest, gitRepo *
305308
if err != nil {
306309
return false, err
307310
}
311+
312+
// b. compare the new tree-hash with the base tree hash
308313
if treeHash == baseTree.ID.String() {
309314
log.Debug("PullRequest[%d]: Patch is empty - ignoring", pr.ID)
310315
pr.Status = issues_model.PullRequestStatusEmpty
@@ -313,9 +318,17 @@ func checkConflicts(ctx context.Context, pr *issues_model.PullRequest, gitRepo *
313318
return false, nil
314319
}
315320

316-
// 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.
321+
// 3. OK the three-way merge method has detected conflicts
322+
// 3a. Are still testing with GitApply? If not set the conflict status and move on
323+
if !setting.Repository.PullRequest.TestConflictingPatchesWithGitApply {
324+
pr.Status = issues_model.PullRequestStatusConflict
325+
pr.ConflictedFiles = conflictFiles
326+
327+
log.Trace("Found %d files conflicted: %v", len(pr.ConflictedFiles), pr.ConflictedFiles)
328+
return true, nil
329+
}
317330

318-
// 3a. Create a plain patch from head to base
331+
// 3b. Create a plain patch from head to base
319332
tmpPatchFile, err := os.CreateTemp("", "patch")
320333
if err != nil {
321334
log.Error("Unable to create temporary patch file! Error: %v", err)
@@ -338,7 +351,7 @@ func checkConflicts(ctx context.Context, pr *issues_model.PullRequest, gitRepo *
338351
patchPath := tmpPatchFile.Name()
339352
tmpPatchFile.Close()
340353

341-
// 3b. if the size of that patch is 0 - there can be no conflicts!
354+
// 3c. if the size of that patch is 0 - there can be no conflicts!
342355
if stat.Size() == 0 {
343356
log.Debug("PullRequest[%d]: Patch is empty - ignoring", pr.ID)
344357
pr.Status = issues_model.PullRequestStatusEmpty

0 commit comments

Comments
 (0)