RebaseCommand: return correct status on stash apply conflicts

Ensure that also the fast-forward cases return status
STASH_APPLY_CONFLICTS when applying the stash produces conflicts.

Bug: 582526
Change-Id: Ib989ff431dca6e301eb05156ca054a7115fa6ad5
Signed-off-by: Thomas Wolf <twolf@apache.org>
This commit is contained in:
Thomas Wolf 2023-10-13 20:00:06 +02:00 committed by Matthias Sohn
parent e4779dab99
commit f93ccb7fd4
2 changed files with 71 additions and 13 deletions

View File

@ -2221,7 +2221,7 @@ public void testFastForwardRebaseWithAutoStash() throws Exception {
checkoutBranch("refs/heads/master"); checkoutBranch("refs/heads/master");
writeTrashFile(FILE1, "modified file1"); writeTrashFile(FILE1, "modified file1");
git.add().addFilepattern(FILE1).call(); git.add().addFilepattern(FILE1).call();
git.commit().setMessage("commit3").call(); git.commit().setMessage("commit2").call();
// checkout topic branch / modify file0 // checkout topic branch / modify file0
checkoutBranch("refs/heads/topic"); checkoutBranch("refs/heads/topic");
@ -2240,6 +2240,57 @@ public void testFastForwardRebaseWithAutoStash() throws Exception {
assertEquals(RepositoryState.SAFE, db.getRepositoryState()); assertEquals(RepositoryState.SAFE, db.getRepositoryState());
} }
@Test
public void testFastForwardRebaseWithAutoStashConflict() throws Exception {
// create file0, add and commit
db.getConfig().setBoolean(ConfigConstants.CONFIG_REBASE_SECTION, null,
ConfigConstants.CONFIG_KEY_AUTOSTASH, true);
writeTrashFile("file0", "file0");
git.add().addFilepattern("file0").call();
git.commit().setMessage("commit0").call();
// create file1, add and commit
writeTrashFile(FILE1, "file1");
git.add().addFilepattern(FILE1).call();
RevCommit commit = git.commit().setMessage("commit1").call();
// create topic branch
createBranch(commit, "refs/heads/topic");
// checkout master branch / modify file1, add and commit
checkoutBranch("refs/heads/master");
writeTrashFile(FILE1, "modified file1");
git.add().addFilepattern(FILE1).call();
RevCommit master = git.commit().setMessage("commit2").call();
// checkout topic branch / modify file0 and file1
checkoutBranch("refs/heads/topic");
writeTrashFile("file0", "unstaged modified file0");
writeTrashFile(FILE1, "unstaged modified file1");
// rebase
assertEquals(Status.STASH_APPLY_CONFLICTS,
git.rebase().setUpstream("refs/heads/master").call()
.getStatus());
checkFile(new File(db.getWorkTree(), "file0"),
"unstaged modified file0");
checkFile(new File(db.getWorkTree(), FILE1),
"<<<<<<< HEAD\n"
+ "modified file1\n"
+ "=======\n"
+ "unstaged modified file1\n"
+ ">>>>>>> stash\n");
// If there is a merge conflict, the index is not reset, and thus file0
// is staged here. This is the same behavior as in C git.
String expected = "[file0, mode:100644, content:unstaged modified file0]"
+ "[file1, mode:100644, stage:1, content:file1]"
+ "[file1, mode:100644, stage:2, content:modified file1]"
+ "[file1, mode:100644, stage:3, content:unstaged modified file1]";
assertEquals(expected, indexState(CONTENT));
assertEquals(RepositoryState.SAFE, db.getRepositoryState());
assertEquals(master, db.resolve(Constants.HEAD));
assertEquals(master, db.resolve("refs/heads/topic"));
}
private List<DiffEntry> getStashedDiff() throws AmbiguousObjectException, private List<DiffEntry> getStashedDiff() throws AmbiguousObjectException,
IncorrectObjectTypeException, IOException, MissingObjectException { IncorrectObjectTypeException, IOException, MissingObjectException {
ObjectId stashId = db.resolve("stash@{0}"); ObjectId stashId = db.resolve("stash@{0}");

View File

@ -289,13 +289,17 @@ public RebaseResult call() throws GitAPIException, NoHeadException,
} }
} }
RebaseResult res = initFilesAndRewind(); RebaseResult res = initFilesAndRewind();
if (stopAfterInitialization) if (stopAfterInitialization) {
return RebaseResult.INTERACTIVE_PREPARED_RESULT; return RebaseResult.INTERACTIVE_PREPARED_RESULT;
}
if (res != null) { if (res != null) {
autoStashApply(); if (!autoStashApply()) {
if (rebaseState.getDir().exists()) res = RebaseResult.STASH_APPLY_CONFLICTS_RESULT;
}
if (rebaseState.getDir().exists()) {
FileUtils.delete(rebaseState.getDir(), FileUtils.delete(rebaseState.getDir(),
FileUtils.RECURSIVE); FileUtils.RECURSIVE);
}
return res; return res;
} }
} }
@ -381,7 +385,7 @@ private void autoStash() throws GitAPIException, IOException {
} }
private boolean autoStashApply() throws IOException, GitAPIException { private boolean autoStashApply() throws IOException, GitAPIException {
boolean conflicts = false; boolean success = true;
if (rebaseState.getFile(AUTOSTASH).exists()) { if (rebaseState.getFile(AUTOSTASH).exists()) {
String stash = rebaseState.readFile(AUTOSTASH); String stash = rebaseState.readFile(AUTOSTASH);
try (Git git = Git.wrap(repo)) { try (Git git = Git.wrap(repo)) {
@ -389,7 +393,7 @@ private boolean autoStashApply() throws IOException, GitAPIException {
.ignoreRepositoryState(true).setStrategy(strategy) .ignoreRepositoryState(true).setStrategy(strategy)
.call(); .call();
} catch (StashApplyFailureException e) { } catch (StashApplyFailureException e) {
conflicts = true; success = false;
try (RevWalk rw = new RevWalk(repo)) { try (RevWalk rw = new RevWalk(repo)) {
ObjectId stashId = repo.resolve(stash); ObjectId stashId = repo.resolve(stash);
RevCommit commit = rw.parseCommit(stashId); RevCommit commit = rw.parseCommit(stashId);
@ -398,7 +402,7 @@ private boolean autoStashApply() throws IOException, GitAPIException {
} }
} }
} }
return conflicts; return success;
} }
private void updateStashRef(ObjectId commitId, PersonIdent refLogIdent, private void updateStashRef(ObjectId commitId, PersonIdent refLogIdent,
@ -723,13 +727,15 @@ private RebaseResult finishRebase(RevCommit finalHead,
boolean lastStepIsForward) throws IOException, GitAPIException { boolean lastStepIsForward) throws IOException, GitAPIException {
String headName = rebaseState.readFile(HEAD_NAME); String headName = rebaseState.readFile(HEAD_NAME);
updateHead(headName, finalHead, upstreamCommit); updateHead(headName, finalHead, upstreamCommit);
boolean stashConflicts = autoStashApply(); boolean unstashSuccessful = autoStashApply();
getRepository().autoGC(monitor); getRepository().autoGC(monitor);
FileUtils.delete(rebaseState.getDir(), FileUtils.RECURSIVE); FileUtils.delete(rebaseState.getDir(), FileUtils.RECURSIVE);
if (stashConflicts) if (!unstashSuccessful) {
return RebaseResult.STASH_APPLY_CONFLICTS_RESULT; return RebaseResult.STASH_APPLY_CONFLICTS_RESULT;
if (lastStepIsForward || finalHead == null) }
if (lastStepIsForward || finalHead == null) {
return RebaseResult.FAST_FORWARD_RESULT; return RebaseResult.FAST_FORWARD_RESULT;
}
return RebaseResult.OK_RESULT; return RebaseResult.OK_RESULT;
} }
@ -1149,7 +1155,7 @@ private RebaseResult initFilesAndRewind() throws IOException,
if (!isInteractive() && walk.isMergedInto(upstream, headCommit)) if (!isInteractive() && walk.isMergedInto(upstream, headCommit))
return RebaseResult.UP_TO_DATE_RESULT; return RebaseResult.UP_TO_DATE_RESULT;
else if (!isInteractive() && walk.isMergedInto(headCommit, upstream)) { else if (!isInteractive() && walk.isMergedInto(headCommit, upstream)) {
// head is already merged into upstream, fast-foward // head is already merged into upstream, fast-forward
monitor.beginTask(MessageFormat.format( monitor.beginTask(MessageFormat.format(
JGitText.get().resettingHead, JGitText.get().resettingHead,
upstreamCommit.getShortMessage()), ProgressMonitor.UNKNOWN); upstreamCommit.getShortMessage()), ProgressMonitor.UNKNOWN);
@ -1447,13 +1453,14 @@ private RebaseResult abort(RebaseResult result) throws IOException,
throw new JGitInternalException( throw new JGitInternalException(
JGitText.get().abortingRebaseFailed); JGitText.get().abortingRebaseFailed);
} }
boolean stashConflicts = autoStashApply(); boolean unstashSuccessful = autoStashApply();
// cleanup the files // cleanup the files
FileUtils.delete(rebaseState.getDir(), FileUtils.RECURSIVE); FileUtils.delete(rebaseState.getDir(), FileUtils.RECURSIVE);
repo.writeCherryPickHead(null); repo.writeCherryPickHead(null);
repo.writeMergeHeads(null); repo.writeMergeHeads(null);
if (stashConflicts) if (!unstashSuccessful) {
return RebaseResult.STASH_APPLY_CONFLICTS_RESULT; return RebaseResult.STASH_APPLY_CONFLICTS_RESULT;
}
return result; return result;
} finally { } finally {