diff options
author | Tobias Pfeifer <to.pfeifer@web.de> | 2013-08-07 14:18:23 +0200 |
---|---|---|
committer | Matthias Sohn <matthias.sohn@sap.com> | 2013-11-05 18:05:02 +0100 |
commit | 765896febb4b63cfe2c37dc0a73c90c79dd1591b (patch) | |
tree | f6c13b3c779d5d64a99a294fd960fb460cf20a6c /org.eclipse.jgit.test | |
parent | 01b5b999a567691fa9602792f365ba0dd5ae061f (diff) | |
download | jgit-765896febb4b63cfe2c37dc0a73c90c79dd1591b.tar.gz jgit-765896febb4b63cfe2c37dc0a73c90c79dd1591b.zip |
Add Squash/Fixup support for rebase interactive in RebaseCommand
The rebase command now supports squash and fixup. Both actions are not
allowed as the first step of the rebase.
In JGit, before any rebase step is performed, the next commit is
already cherry-picked. This commit keeps that behaviour. In case of
squash or fixup a soft reset to the parent is perfomed afterwards.
CQ: 7684
Bug: 396510
Change-Id: I3c4190940b4d7f19860e223d647fc78705e57203
Signed-off-by: Tobias Pfeifer <to.pfeifer@web.de>
Signed-off-by: Stefan Lay <stefan.lay@sap.com>
Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
Diffstat (limited to 'org.eclipse.jgit.test')
-rw-r--r-- | org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RebaseCommandTest.java | 339 |
1 files changed, 338 insertions, 1 deletions
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RebaseCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RebaseCommandTest.java index b9f5bc95ea..63ef21d8d3 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RebaseCommandTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RebaseCommandTest.java @@ -42,9 +42,9 @@ */ package org.eclipse.jgit.api; -import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.CoreMatchers.not; +import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; @@ -63,6 +63,7 @@ import org.eclipse.jgit.api.MergeResult.MergeStatus; import org.eclipse.jgit.api.RebaseCommand.InteractiveHandler; import org.eclipse.jgit.api.RebaseCommand.Operation; import org.eclipse.jgit.api.RebaseResult.Status; +import org.eclipse.jgit.api.errors.InvalidRebaseStepException; import org.eclipse.jgit.api.errors.JGitInternalException; import org.eclipse.jgit.api.errors.RefNotFoundException; import org.eclipse.jgit.api.errors.UnmergedPathsException; @@ -83,6 +84,8 @@ import org.eclipse.jgit.merge.ResolveMerger.MergeFailureReason; import org.eclipse.jgit.revwalk.RevCommit; import org.eclipse.jgit.revwalk.RevWalk; import org.eclipse.jgit.util.FileUtils; +import org.eclipse.jgit.util.IO; +import org.eclipse.jgit.util.RawParseUtils; import org.junit.Before; import org.junit.Test; @@ -1957,6 +1960,340 @@ public class RebaseCommandTest extends RepositoryTestCase { assertEquals("edited commit message", actualCommitMag); } + @Test + public void testParseSquashFixupSequenceCount() { + int count = RebaseCommand + .parseSquashFixupSequenceCount("# This is a combination of 3 commits.\n# newline"); + assertEquals(3, count); + } + + @Test + public void testRebaseInteractiveSingleSquashAndModifyMessage() throws Exception { + // create file1 on master + writeTrashFile(FILE1, FILE1); + git.add().addFilepattern(FILE1).call(); + git.commit().setMessage("Add file1\nnew line").call(); + assertTrue(new File(db.getWorkTree(), FILE1).exists()); + + // create file2 on master + writeTrashFile("file2", "file2"); + git.add().addFilepattern("file2").call(); + git.commit().setMessage("Add file2\nnew line").call(); + assertTrue(new File(db.getWorkTree(), "file2").exists()); + + // update FILE1 on master + writeTrashFile(FILE1, "blah"); + git.add().addFilepattern(FILE1).call(); + git.commit().setMessage("updated file1 on master\nnew line").call(); + + writeTrashFile("file2", "more change"); + git.add().addFilepattern("file2").call(); + git.commit().setMessage("update file2 on master\nnew line").call(); + + git.rebase().setUpstream("HEAD~3") + .runInteractively(new InteractiveHandler() { + + public void prepareSteps(List<RebaseTodoLine> steps) { + steps.get(1).setAction(Action.SQUASH); + } + + public String modifyCommitMessage(String commit) { + final File messageSquashFile = new File(db + .getDirectory(), "rebase-merge/message-squash"); + final File messageFixupFile = new File(db + .getDirectory(), "rebase-merge/message-fixup"); + + assertFalse(messageFixupFile.exists()); + assertTrue(messageSquashFile.exists()); + assertEquals( + "# This is a combination of 2 commits.\n# This is the 2nd commit message:\nupdated file1 on master\nnew line\n# The first commit's message is:\nAdd file2\nnew line", + commit); + + try { + byte[] messageSquashBytes = IO + .readFully(messageSquashFile); + int end = RawParseUtils.prevLF(messageSquashBytes, + messageSquashBytes.length); + String messageSquashContent = RawParseUtils.decode( + messageSquashBytes, 0, end + 1); + assertEquals(messageSquashContent, commit); + } catch (Throwable t) { + fail(t.getMessage()); + } + + return "changed"; + } + }).call(); + + RevWalk walk = new RevWalk(db); + ObjectId headId = db.resolve(Constants.HEAD); + RevCommit headCommit = walk.parseCommit(headId); + assertEquals(headCommit.getFullMessage(), + "update file2 on master\nnew line"); + + ObjectId head2Id = db.resolve(Constants.HEAD + "^1"); + RevCommit head1Commit = walk.parseCommit(head2Id); + assertEquals("changed", head1Commit.getFullMessage()); + } + + @Test + public void testRebaseInteractiveMultipleSquash() throws Exception { + // create file0 on master + writeTrashFile("file0", "file0"); + git.add().addFilepattern("file0").call(); + git.commit().setMessage("Add file0\nnew line").call(); + assertTrue(new File(db.getWorkTree(), "file0").exists()); + + // create file1 on master + writeTrashFile(FILE1, FILE1); + git.add().addFilepattern(FILE1).call(); + git.commit().setMessage("Add file1\nnew line").call(); + assertTrue(new File(db.getWorkTree(), FILE1).exists()); + + // create file2 on master + writeTrashFile("file2", "file2"); + git.add().addFilepattern("file2").call(); + git.commit().setMessage("Add file2\nnew line").call(); + assertTrue(new File(db.getWorkTree(), "file2").exists()); + + // update FILE1 on master + writeTrashFile(FILE1, "blah"); + git.add().addFilepattern(FILE1).call(); + git.commit().setMessage("updated file1 on master\nnew line").call(); + + writeTrashFile("file2", "more change"); + git.add().addFilepattern("file2").call(); + git.commit().setMessage("update file2 on master\nnew line").call(); + + git.rebase().setUpstream("HEAD~4") + .runInteractively(new InteractiveHandler() { + + public void prepareSteps(List<RebaseTodoLine> steps) { + steps.get(1).setAction(Action.SQUASH); + steps.get(2).setAction(Action.SQUASH); + } + + public String modifyCommitMessage(String commit) { + final File messageSquashFile = new File(db.getDirectory(), + "rebase-merge/message-squash"); + final File messageFixupFile = new File(db.getDirectory(), + "rebase-merge/message-fixup"); + assertFalse(messageFixupFile.exists()); + assertTrue(messageSquashFile.exists()); + assertEquals( + "# This is a combination of 3 commits.\n# This is the 3rd commit message:\nupdated file1 on master\nnew line\n# This is the 2nd commit message:\nAdd file2\nnew line\n# The first commit's message is:\nAdd file1\nnew line", + commit); + + try { + byte[] messageSquashBytes = IO + .readFully(messageSquashFile); + int end = RawParseUtils.prevLF(messageSquashBytes, + messageSquashBytes.length); + String messageSquashContend = RawParseUtils.decode( + messageSquashBytes, 0, end + 1); + assertEquals(messageSquashContend, commit); + } catch (Throwable t) { + fail(t.getMessage()); + } + + return "# This is a combination of 3 commits.\n# This is the 3rd commit message:\nupdated file1 on master\nnew line\n# This is the 2nd commit message:\nAdd file2\nnew line\n# The first commit's message is:\nAdd file1\nnew line"; + } + }).call(); + + RevWalk walk = new RevWalk(db); + ObjectId headId = db.resolve(Constants.HEAD); + RevCommit headCommit = walk.parseCommit(headId); + assertEquals(headCommit.getFullMessage(), + "update file2 on master\nnew line"); + + ObjectId head2Id = db.resolve(Constants.HEAD + "^1"); + RevCommit head1Commit = walk.parseCommit(head2Id); + assertEquals( + "updated file1 on master\nnew line\nAdd file2\nnew line\nAdd file1\nnew line", + head1Commit.getFullMessage()); + } + + @Test + public void testRebaseInteractiveMixedSquashAndFixup() throws Exception { + // create file0 on master + writeTrashFile("file0", "file0"); + git.add().addFilepattern("file0").call(); + git.commit().setMessage("Add file0\nnew line").call(); + assertTrue(new File(db.getWorkTree(), "file0").exists()); + + // create file1 on master + writeTrashFile(FILE1, FILE1); + git.add().addFilepattern(FILE1).call(); + git.commit().setMessage("Add file1\nnew line").call(); + assertTrue(new File(db.getWorkTree(), FILE1).exists()); + + // create file2 on master + writeTrashFile("file2", "file2"); + git.add().addFilepattern("file2").call(); + git.commit().setMessage("Add file2\nnew line").call(); + assertTrue(new File(db.getWorkTree(), "file2").exists()); + + // update FILE1 on master + writeTrashFile(FILE1, "blah"); + git.add().addFilepattern(FILE1).call(); + git.commit().setMessage("updated file1 on master\nnew line").call(); + + writeTrashFile("file2", "more change"); + git.add().addFilepattern("file2").call(); + git.commit().setMessage("update file2 on master\nnew line").call(); + + git.rebase().setUpstream("HEAD~4") + .runInteractively(new InteractiveHandler() { + + public void prepareSteps(List<RebaseTodoLine> steps) { + steps.get(1).setAction(Action.FIXUP); + steps.get(2).setAction(Action.SQUASH); + } + + public String modifyCommitMessage(String commit) { + final File messageSquashFile = new File(db + .getDirectory(), "rebase-merge/message-squash"); + final File messageFixupFile = new File(db + .getDirectory(), "rebase-merge/message-fixup"); + + assertFalse(messageFixupFile.exists()); + assertTrue(messageSquashFile.exists()); + assertEquals( + "# This is a combination of 3 commits.\n# This is the 3rd commit message:\nupdated file1 on master\nnew line\n# The 2nd commit message will be skipped:\n# Add file2\n# new line\n# The first commit's message is:\nAdd file1\nnew line", + commit); + + try { + byte[] messageSquashBytes = IO + .readFully(messageSquashFile); + int end = RawParseUtils.prevLF(messageSquashBytes, + messageSquashBytes.length); + String messageSquashContend = RawParseUtils.decode( + messageSquashBytes, 0, end + 1); + assertEquals(messageSquashContend, commit); + } catch (Throwable t) { + fail(t.getMessage()); + } + + return "changed"; + } + }).call(); + + RevWalk walk = new RevWalk(db); + ObjectId headId = db.resolve(Constants.HEAD); + RevCommit headCommit = walk.parseCommit(headId); + assertEquals(headCommit.getFullMessage(), + "update file2 on master\nnew line"); + + ObjectId head2Id = db.resolve(Constants.HEAD + "^1"); + RevCommit head1Commit = walk.parseCommit(head2Id); + assertEquals("changed", head1Commit.getFullMessage()); + } + + @Test + public void testRebaseInteractiveSingleFixup() throws Exception { + // create file1 on master + writeTrashFile(FILE1, FILE1); + git.add().addFilepattern(FILE1).call(); + git.commit().setMessage("Add file1\nnew line").call(); + assertTrue(new File(db.getWorkTree(), FILE1).exists()); + + // create file2 on master + writeTrashFile("file2", "file2"); + git.add().addFilepattern("file2").call(); + git.commit().setMessage("Add file2\nnew line").call(); + assertTrue(new File(db.getWorkTree(), "file2").exists()); + + // update FILE1 on master + writeTrashFile(FILE1, "blah"); + git.add().addFilepattern(FILE1).call(); + git.commit().setMessage("updated file1 on master\nnew line").call(); + + writeTrashFile("file2", "more change"); + git.add().addFilepattern("file2").call(); + git.commit().setMessage("update file2 on master\nnew line").call(); + + git.rebase().setUpstream("HEAD~3") + .runInteractively(new InteractiveHandler() { + + public void prepareSteps(List<RebaseTodoLine> steps) { + steps.get(1).setAction(Action.FIXUP); + } + + public String modifyCommitMessage(String commit) { + fail("No callback to modify commit message expected for single fixup"); + return commit; + } + }).call(); + + RevWalk walk = new RevWalk(db); + ObjectId headId = db.resolve(Constants.HEAD); + RevCommit headCommit = walk.parseCommit(headId); + assertEquals("update file2 on master\nnew line", + headCommit.getFullMessage()); + + ObjectId head1Id = db.resolve(Constants.HEAD + "^1"); + RevCommit head1Commit = walk.parseCommit(head1Id); + assertEquals("Add file2\nnew line", + head1Commit.getFullMessage()); + } + + + @Test(expected = InvalidRebaseStepException.class) + public void testRebaseInteractiveFixupFirstCommitShouldFail() + throws Exception { + // create file1 on master + writeTrashFile(FILE1, FILE1); + git.add().addFilepattern(FILE1).call(); + git.commit().setMessage("Add file1\nnew line").call(); + assertTrue(new File(db.getWorkTree(), FILE1).exists()); + + // create file2 on master + writeTrashFile("file2", "file2"); + git.add().addFilepattern("file2").call(); + git.commit().setMessage("Add file2\nnew line").call(); + assertTrue(new File(db.getWorkTree(), "file2").exists()); + + git.rebase().setUpstream("HEAD~1") + .runInteractively(new InteractiveHandler() { + + public void prepareSteps(List<RebaseTodoLine> steps) { + steps.get(0).setAction(Action.FIXUP); + } + + public String modifyCommitMessage(String commit) { + return commit; + } + }).call(); + } + + @Test(expected = InvalidRebaseStepException.class) + public void testRebaseInteractiveSquashFirstCommitShouldFail() + throws Exception { + // create file1 on master + writeTrashFile(FILE1, FILE1); + git.add().addFilepattern(FILE1).call(); + git.commit().setMessage("Add file1\nnew line").call(); + assertTrue(new File(db.getWorkTree(), FILE1).exists()); + + // create file2 on master + writeTrashFile("file2", "file2"); + git.add().addFilepattern("file2").call(); + git.commit().setMessage("Add file2\nnew line").call(); + assertTrue(new File(db.getWorkTree(), "file2").exists()); + + git.rebase().setUpstream("HEAD~1") + .runInteractively(new InteractiveHandler() { + + public void prepareSteps(List<RebaseTodoLine> steps) { + steps.get(0).setAction(Action.SQUASH); + } + + public String modifyCommitMessage(String commit) { + return commit; + } + }).call(); + } + private File getTodoFile() { File todoFile = new File(db.getDirectory(), GIT_REBASE_TODO); return todoFile; |