From 97eb37e823f103c74c79da2b5e070d753a920403 Mon Sep 17 00:00:00 2001
From: zeripath <art27@cantab.net>
Date: Fri, 3 Apr 2020 17:00:41 +0100
Subject: [PATCH] Fix rebase conflict detection in git 2.26 (#10929)

* Fix rebase conflict detection in git 2.26

Git changed the technique used in rebase from
simple apply-patches to use merge. This breaks
our conflict detection code.

Signed-off-by: Andrew Thornton <art27@cantab.net>

* As per @techknowlogick reduce copying

Signed-off-by: Andrew Thornton <art27@cantab.net>
---
 services/pull/merge.go | 29 +++++++++++++++++++++++------
 1 file changed, 23 insertions(+), 6 deletions(-)

diff --git a/services/pull/merge.go b/services/pull/merge.go
index 90b90b9c16..511f3dbfc4 100644
--- a/services/pull/merge.go
+++ b/services/pull/merge.go
@@ -263,17 +263,34 @@ func rawMerge(pr *models.PullRequest, doer *models.User, mergeStyle models.Merge
 		if err := git.NewCommand("rebase", baseBranch).RunInDirPipeline(tmpBasePath, &outbuf, &errbuf); err != nil {
 			// Rebase will leave a REBASE_HEAD file in .git if there is a conflict
 			if _, statErr := os.Stat(filepath.Join(tmpBasePath, ".git", "REBASE_HEAD")); statErr == nil {
-				// The original commit SHA1 that is failing will be in .git/rebase-apply/original-commit
-				commitShaBytes, readErr := ioutil.ReadFile(filepath.Join(tmpBasePath, ".git", "rebase-apply", "original-commit"))
-				if readErr != nil {
-					// Abandon this attempt to handle the error
+				var commitSha string
+				ok := false
+				failingCommitPaths := []string{
+					filepath.Join(tmpBasePath, ".git", "rebase-apply", "original-commit"), // Git < 2.26
+					filepath.Join(tmpBasePath, ".git", "rebase-merge", "stopped-sha"),     // Git >= 2.26
+				}
+				for _, failingCommitPath := range failingCommitPaths {
+					if _, statErr := os.Stat(filepath.Join(failingCommitPath)); statErr == nil {
+						commitShaBytes, readErr := ioutil.ReadFile(filepath.Join(failingCommitPath))
+						if readErr != nil {
+							// Abandon this attempt to handle the error
+							log.Error("git rebase staging on to base [%s:%s -> %s:%s]: %v\n%s\n%s", pr.HeadRepo.FullName(), pr.HeadBranch, pr.BaseRepo.FullName(), pr.BaseBranch, err, outbuf.String(), errbuf.String())
+							return "", fmt.Errorf("git rebase staging on to base [%s:%s -> %s:%s]: %v\n%s\n%s", pr.HeadRepo.FullName(), pr.HeadBranch, pr.BaseRepo.FullName(), pr.BaseBranch, err, outbuf.String(), errbuf.String())
+						}
+						commitSha = strings.TrimSpace(string(commitShaBytes))
+						ok = true
+						break
+					}
+				}
+				if !ok {
+					log.Error("Unable to determine failing commit sha for this rebase message. Cannot cast as models.ErrRebaseConflicts.")
 					log.Error("git rebase staging on to base [%s:%s -> %s:%s]: %v\n%s\n%s", pr.HeadRepo.FullName(), pr.HeadBranch, pr.BaseRepo.FullName(), pr.BaseBranch, err, outbuf.String(), errbuf.String())
 					return "", fmt.Errorf("git rebase staging on to base [%s:%s -> %s:%s]: %v\n%s\n%s", pr.HeadRepo.FullName(), pr.HeadBranch, pr.BaseRepo.FullName(), pr.BaseBranch, err, outbuf.String(), errbuf.String())
 				}
-				log.Debug("RebaseConflict at %s [%s:%s -> %s:%s]: %v\n%s\n%s", strings.TrimSpace(string(commitShaBytes)), pr.HeadRepo.FullName(), pr.HeadBranch, pr.BaseRepo.FullName(), pr.BaseBranch, err, outbuf.String(), errbuf.String())
+				log.Debug("RebaseConflict at %s [%s:%s -> %s:%s]: %v\n%s\n%s", commitSha, pr.HeadRepo.FullName(), pr.HeadBranch, pr.BaseRepo.FullName(), pr.BaseBranch, err, outbuf.String(), errbuf.String())
 				return "", models.ErrRebaseConflicts{
 					Style:     mergeStyle,
-					CommitSHA: strings.TrimSpace(string(commitShaBytes)),
+					CommitSHA: commitSha,
 					StdOut:    outbuf.String(),
 					StdErr:    errbuf.String(),
 					Err:       err,