Browse Source

Rebase: fix wrong update if original HEAD after Merge+Skip

Rebase would update the original HEAD to the wrong commit when
"skipping" the last commit after a merged commit.

Includes a test for the specific situation.

Change-Id: I087314b1834a3f11a4561f04ca5c21411d54d993
Signed-off-by: Mathias Kinzler <mathias.kinzler@sap.com>
stable-0.10
Mathias Kinzler 14 years ago
parent
commit
2a7cd0086b
  1. 38
      org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RebaseCommandTest.java
  2. 44
      org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseCommand.java

38
org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RebaseCommandTest.java

@ -499,6 +499,44 @@ public class RebaseCommandTest extends RepositoryTestCase {
assertEquals(RepositoryState.SAFE, db.getRepositoryState()); assertEquals(RepositoryState.SAFE, db.getRepositoryState());
} }
public void testMergeFirstStopOnLastConflictAndSkip() throws Exception {
// create file1 on master
RevCommit firstInMaster = writeFileAndCommit(FILE1, "Add file1", "1",
"2", "3");
// change in master
writeFileAndCommit(FILE1, "change file1 in master", "1master", "2", "3");
checkFile(FILE1, "1master", "2", "3");
// create a topic branch based on the first commit
createBranch(firstInMaster, "refs/heads/topic");
checkoutBranch("refs/heads/topic");
// we have the old content again
checkFile(FILE1, "1", "2", "3");
// add a line (conflicting)
writeFileAndCommit(FILE1, "add a line to file1 in topic", "1topic",
"2", "3", "4topic");
// change first line (conflicting again)
writeFileAndCommit(FILE1,
"change file1 in topic\n\nThis is conflicting", "1topicagain",
"2", "3", "4topic");
RebaseResult res = git.rebase().setUpstream("refs/heads/master").call();
assertEquals(Status.STOPPED, res.getStatus());
writeFileAndAdd(FILE1, "merged");
res = git.rebase().setOperation(Operation.CONTINUE).call();
assertEquals(Status.STOPPED, res.getStatus());
res = git.rebase().setOperation(Operation.SKIP).call();
assertNotNull(res);
assertEquals(Status.OK, res.getStatus());
assertEquals(RepositoryState.SAFE, db.getRepositoryState());
checkFile(FILE1, "merged");
}
public void testStopOnConflictAndSkipNoConflict() throws Exception { public void testStopOnConflictAndSkipNoConflict() throws Exception {
// create file1 on master // create file1 on master
RevCommit firstInMaster = writeFileAndCommit(FILE1, "Add file1", "1", RevCommit firstInMaster = writeFileAndCommit(FILE1, "Add file1", "1",

44
org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseCommand.java

@ -218,14 +218,12 @@ public class RebaseCommand extends GitCommand<RebaseResult> {
if (this.operation == Operation.CONTINUE) if (this.operation == Operation.CONTINUE)
newHead = continueRebase(); newHead = continueRebase();
List<Step> steps = loadSteps(); if (this.operation == Operation.SKIP)
newHead = checkoutCurrentHead();
if (this.operation == Operation.SKIP && !steps.isEmpty())
checkoutCurrentHead();
ObjectReader or = repo.newObjectReader(); ObjectReader or = repo.newObjectReader();
int stepsToPop = 0;
List<Step> steps = loadSteps();
for (Step step : steps) { for (Step step : steps) {
if (step.action != Action.PICK) if (step.action != Action.PICK)
continue; continue;
@ -250,22 +248,32 @@ public class RebaseCommand extends GitCommand<RebaseResult> {
if (newHead == null) { if (newHead == null) {
return stop(commitToPick); return stop(commitToPick);
} }
stepsToPop++;
} }
if (newHead != null || steps.isEmpty()) { if (newHead != null) {
// point the previous head (if any) to the new commit // point the previous head (if any) to the new commit
String headName = readFile(rebaseDir, HEAD_NAME); String headName = readFile(rebaseDir, HEAD_NAME);
if (headName.startsWith(Constants.R_REFS)) { if (headName.startsWith(Constants.R_REFS)) {
RefUpdate rup = repo.updateRef(headName); RefUpdate rup = repo.updateRef(headName);
if (newHead != null) { rup.setNewObjectId(newHead);
rup.setNewObjectId(newHead); Result res = rup.forceUpdate();
rup.forceUpdate(); switch (res) {
case FAST_FORWARD:
case FORCED:
case NO_CHANGE:
break;
default:
throw new JGitInternalException("Updating HEAD failed");
} }
rup = repo.updateRef(Constants.HEAD); rup = repo.updateRef(Constants.HEAD);
rup.link(headName); res = rup.link(headName);
} switch (res) {
if (this.operation == Operation.SKIP && steps.isEmpty()) { case FAST_FORWARD:
checkoutCurrentHead(); case FORCED:
case NO_CHANGE:
break;
default:
throw new JGitInternalException("Updating HEAD failed");
}
} }
FileUtils.delete(rebaseDir, FileUtils.RECURSIVE); FileUtils.delete(rebaseDir, FileUtils.RECURSIVE);
return new RebaseResult(Status.OK); return new RebaseResult(Status.OK);
@ -276,8 +284,8 @@ public class RebaseCommand extends GitCommand<RebaseResult> {
} }
} }
private void checkoutCurrentHead() throws IOException, NoHeadException, private RevCommit checkoutCurrentHead() throws IOException,
JGitInternalException { NoHeadException, JGitInternalException {
ObjectId headTree = repo.resolve(Constants.HEAD + "^{tree}"); ObjectId headTree = repo.resolve(Constants.HEAD + "^{tree}");
if (headTree == null) if (headTree == null)
throw new NoHeadException( throw new NoHeadException(
@ -299,6 +307,10 @@ public class RebaseCommand extends GitCommand<RebaseResult> {
} finally { } finally {
dc.unlock(); dc.unlock();
} }
RevWalk rw = new RevWalk(repo);
RevCommit commit = rw.parseCommit(repo.resolve(Constants.HEAD));
rw.release();
return commit;
} }
/** /**

Loading…
Cancel
Save