]> source.dussan.org Git - jgit.git/commitdiff
Abort merge when file to be checked out is dirty 33/2733/3
authorPhilipp Thun <philipp.thun@sap.com>
Thu, 17 Mar 2011 09:48:44 +0000 (10:48 +0100)
committerChristian Halstrick <christian.halstrick@sap.com>
Fri, 18 Mar 2011 16:04:50 +0000 (17:04 +0100)
In case a file needs to be checked out (from THEIRS) during a merge
operation, it has to be checked if the worktree version of this file
is dirty. If this is true, merge shall fail.

Change-Id: I17c24845584700aad953c3d4f2bea77a0d665ec4
Signed-off-by: Philipp Thun <philipp.thun@sap.com>
org.eclipse.jgit.test/tst/org/eclipse/jgit/api/MergeCommandTest.java
org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java

index 987e64731e4926166613ab9ebf7f0c3549943b1a..2761989c717cc817773b9cbb42dc78cb74cabba5 100644 (file)
@@ -638,6 +638,164 @@ public class MergeCommandTest extends RepositoryTestCase {
                assertEquals(RepositoryState.MERGING, db.getRepositoryState());
        }
 
+       @Test
+       public void testSuccessfulMergeFailsDueToDirtyIndex() throws Exception {
+               Git git = new Git(db);
+
+               File fileA = writeTrashFile("a", "a");
+               RevCommit initialCommit = addAllAndCommit(git);
+
+               // switch branch
+               createBranch(initialCommit, "refs/heads/side");
+               checkoutBranch("refs/heads/side");
+               // modify file a
+               write(fileA, "a(side)");
+               writeTrashFile("b", "b");
+               RevCommit sideCommit = addAllAndCommit(git);
+
+               // switch branch
+               checkoutBranch("refs/heads/master");
+               writeTrashFile("c", "c");
+               addAllAndCommit(git);
+
+               // modify and add file a
+               write(fileA, "a(modified)");
+               git.add().addFilepattern("a").call();
+               // do not commit
+
+               // get current index state
+               String indexState = indexState(CONTENT);
+
+               // merge
+               MergeResult result = git.merge().include(sideCommit.getId())
+                               .setStrategy(MergeStrategy.RESOLVE).call();
+
+               checkMergeFailedResult(result, indexState, fileA);
+       }
+
+       @Test
+       public void testConflictingMergeFailsDueToDirtyIndex() throws Exception {
+               Git git = new Git(db);
+
+               File fileA = writeTrashFile("a", "a");
+               RevCommit initialCommit = addAllAndCommit(git);
+
+               // switch branch
+               createBranch(initialCommit, "refs/heads/side");
+               checkoutBranch("refs/heads/side");
+               // modify file a
+               write(fileA, "a(side)");
+               writeTrashFile("b", "b");
+               RevCommit sideCommit = addAllAndCommit(git);
+
+               // switch branch
+               checkoutBranch("refs/heads/master");
+               // modify file a - this will cause a conflict during merge
+               write(fileA, "a(master)");
+               writeTrashFile("c", "c");
+               addAllAndCommit(git);
+
+               // modify and add file a
+               write(fileA, "a(modified)");
+               git.add().addFilepattern("a").call();
+               // do not commit
+
+               // get current index state
+               String indexState = indexState(CONTENT);
+
+               // merge
+               MergeResult result = git.merge().include(sideCommit.getId())
+                               .setStrategy(MergeStrategy.RESOLVE).call();
+
+               checkMergeFailedResult(result, indexState, fileA);
+       }
+
+       @Test
+       public void testSuccessfulMergeFailsDueToDirtyWorktree() throws Exception {
+               Git git = new Git(db);
+
+               File fileA = writeTrashFile("a", "a");
+               RevCommit initialCommit = addAllAndCommit(git);
+
+               // switch branch
+               createBranch(initialCommit, "refs/heads/side");
+               checkoutBranch("refs/heads/side");
+               // modify file a
+               write(fileA, "a(side)");
+               writeTrashFile("b", "b");
+               RevCommit sideCommit = addAllAndCommit(git);
+
+               // switch branch
+               checkoutBranch("refs/heads/master");
+               writeTrashFile("c", "c");
+               addAllAndCommit(git);
+
+               // modify file a
+               write(fileA, "a(modified)");
+               // do not add and commit
+
+               // get current index state
+               String indexState = indexState(CONTENT);
+
+               // merge
+               MergeResult result = git.merge().include(sideCommit.getId())
+                               .setStrategy(MergeStrategy.RESOLVE).call();
+
+               checkMergeFailedResult(result, indexState, fileA);
+       }
+
+       @Test
+       public void testConflictingMergeFailsDueToDirtyWorktree() throws Exception {
+               Git git = new Git(db);
+
+               File fileA = writeTrashFile("a", "a");
+               RevCommit initialCommit = addAllAndCommit(git);
+
+               // switch branch
+               createBranch(initialCommit, "refs/heads/side");
+               checkoutBranch("refs/heads/side");
+               // modify file a
+               write(fileA, "a(side)");
+               writeTrashFile("b", "b");
+               RevCommit sideCommit = addAllAndCommit(git);
+
+               // switch branch
+               checkoutBranch("refs/heads/master");
+               // modify file a - this will cause a conflict during merge
+               write(fileA, "a(master)");
+               writeTrashFile("c", "c");
+               addAllAndCommit(git);
+
+               // modify file a
+               write(fileA, "a(modified)");
+               // do not add and commit
+
+               // get current index state
+               String indexState = indexState(CONTENT);
+
+               // merge
+               MergeResult result = git.merge().include(sideCommit.getId())
+                               .setStrategy(MergeStrategy.RESOLVE).call();
+
+               checkMergeFailedResult(result, indexState, fileA);
+       }
+
+       private RevCommit addAllAndCommit(final Git git) throws Exception {
+               git.add().addFilepattern(".").call();
+               return git.commit().setMessage("message").call();
+       }
+
+       private void checkMergeFailedResult(final MergeResult result,
+                       final String indexState, final File fileA) throws Exception {
+               assertEquals(MergeStatus.FAILED, result.getMergeStatus());
+               assertEquals("a(modified)", read(fileA));
+               assertFalse(new File(db.getWorkTree(), "b").exists());
+               assertEquals("c", read(new File(db.getWorkTree(), "c")));
+               assertEquals(indexState, indexState(CONTENT));
+               assertEquals(null, result.getConflicts());
+               assertEquals(RepositoryState.SAFE, db.getRepositoryState());
+       }
+
        private void createBranch(ObjectId objectId, String branchName) throws IOException {
                RefUpdate updateRef = db.updateRef(branchName);
                updateRef.setNewObjectId(objectId);
index a055131d61c0989ea2230f54830f7b4b8aa96ffd..5e99fc00f168e2ab3d69146801423af107432a63 100644 (file)
@@ -393,6 +393,10 @@ public class ResolveMerger extends ThreeWayMerger {
                if (modeB == modeO && tw.idEqual(T_BASE, T_OURS)) {
                        // OURS was not changed compared to BASE. All changes must be in
                        // THEIRS. THEIRS is chosen.
+
+                       // Check worktree before checking out THEIRS
+                       if (isWorktreeDirty())
+                               return false;
                        if (nonTree(modeT)) {
                                DirCacheEntry e = add(tw.getRawPath(), theirs,
                                                DirCacheEntry.STAGE_0);