]> source.dussan.org Git - jgit.git/commitdiff
Fixed ResolveMerger regarding handling of deletions 46/1846/2
authorChristian Halstrick <christian.halstrick@sap.com>
Wed, 3 Nov 2010 13:13:56 +0000 (14:13 +0100)
committerChristian Halstrick <christian.halstrick@sap.com>
Sun, 7 Nov 2010 13:59:01 +0000 (14:59 +0100)
There was a bug in ResolveMerger which is one reason for
bug 328841. If a merge was failing because of conflicts
deletions where not handled correctly. Files which have
to be deleted (because there was a non-conflicting deletion
coming in from THEIRS) are not deleted. In the
non-conflicting case we also forgot to delete the file but
in this case we explicitly checkout in the end these files
get deleted during that checkout.

This is fixed by handling incoming deletions explicitly.

Bug: 328841
Change-Id: I7f4c94ab54138e1b2f3fcdf34fb803d68e209ad0
Signed-off-by: Christian Halstrick <christian.halstrick@sap.com>
org.eclipse.jgit.test/tst/org/eclipse/jgit/api/MergeCommandTest.java
org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java

index 7efe7c948deb165df63359a6902d15ce0af6b9f6..dbf3ba015e621c586303798afe609315211dfe1d 100644 (file)
@@ -365,6 +365,48 @@ public class MergeCommandTest extends RepositoryTestCase {
                                read(new File(db.getWorkTree(), "c/c/c")));
        }
 
+       public void testDeletionAndConflict() throws Exception {
+               Git git = new Git(db);
+
+               writeTrashFile("a", "1\na\n3\n");
+               writeTrashFile("b", "1\nb\n3\n");
+               writeTrashFile("d", "1\nd\n3\n");
+               writeTrashFile("c/c/c", "1\nc\n3\n");
+               git.add().addFilepattern("a").addFilepattern("b")
+                               .addFilepattern("c/c/c").addFilepattern("d").call();
+               RevCommit initialCommit = git.commit().setMessage("initial").call();
+
+               createBranch(initialCommit, "refs/heads/side");
+               checkoutBranch("refs/heads/side");
+
+               assertTrue(new File(db.getWorkTree(), "b").delete());
+               writeTrashFile("a", "1\na\n3(side)\n");
+               git.add().addFilepattern("b").setUpdate(true).call();
+               git.add().addFilepattern("a").setUpdate(true).call();
+               RevCommit secondCommit = git.commit().setMessage("side").call();
+
+               assertFalse(new File(db.getWorkTree(), "b").exists());
+               checkoutBranch("refs/heads/master");
+               assertTrue(new File(db.getWorkTree(), "b").exists());
+
+               writeTrashFile("a", "1\na\n3(main)\n");
+               writeTrashFile("c/c/c", "1\nc(main)\n3\n");
+               git.add().addFilepattern("a").addFilepattern("c/c/c").call();
+               git.commit().setMessage("main").call();
+
+               // We are merging a deletion into our branch
+               MergeResult result = git.merge().include(secondCommit.getId())
+                               .setStrategy(MergeStrategy.RESOLVE).call();
+               assertEquals(MergeStatus.CONFLICTING, result.getMergeStatus());
+
+               assertEquals(
+                               "1\na\n<<<<<<< HEAD\n3(main)\n=======\n3(side)\n>>>>>>> 54ffed45d62d252715fc20e41da92d44c48fb0ff\n",
+                               read(new File(db.getWorkTree(), "a")));
+               assertFalse(new File(db.getWorkTree(), "b").exists());
+               assertEquals("1\nc(main)\n3\n",
+                               read(new File(db.getWorkTree(), "c/c/c")));
+       }
+
        public void testMergeFailingWithDirtyWorkingTree() throws Exception {
                Git git = new Git(db);
 
index a8ab433fb526df14ca93f6790af25a458be86e16..1b6ec23baee72817608f24d238a27488a5da1256 100644 (file)
@@ -93,7 +93,9 @@ public class ResolveMerger extends ThreeWayMerger {
                /** the merge failed because of a dirty index */
                DIRTY_INDEX,
                /** the merge failed because of a dirty workingtree */
-               DIRTY_WORKTREE
+               DIRTY_WORKTREE,
+               /** the merge failed because of a file could not be deleted */
+               COULD_NOT_DELETE
        }
 
        private NameConflictTreeWalk tw;
@@ -229,10 +231,16 @@ public class ResolveMerger extends ThreeWayMerger {
        private void checkout() throws NoWorkTreeException, IOException {
                for (Map.Entry<String, DirCacheEntry> entry : toBeCheckedOut.entrySet()) {
                        File f = new File(db.getWorkTree(), entry.getKey());
-                       createDir(f.getParentFile());
-                       DirCacheCheckout.checkoutEntry(db,
-                                       f,
-                                       entry.getValue(), true);
+                       if (entry.getValue() != null) {
+                               createDir(f.getParentFile());
+                               DirCacheCheckout.checkoutEntry(db,
+                                               f,
+                                               entry.getValue(), true);
+                       } else {
+                               if (!f.delete())
+                                       failingPathes.put(entry.getKey(),
+                                                       MergeFailureReason.COULD_NOT_DELETE);
+                       }
                        modifiedFiles.add(entry.getKey());
                }
        }
@@ -373,13 +381,21 @@ public class ResolveMerger extends ThreeWayMerger {
                        return true;
                }
 
-               if (nonTree(modeT) && modeB == modeO && tw.idEqual(T_BASE, T_OURS)) {
+               if (modeB == modeO && tw.idEqual(T_BASE, T_OURS)) {
                        // OURS was not changed compared to base. All changes must be in
                        // THEIRS. Choose THEIRS.
-                       DirCacheEntry e=add(tw.getRawPath(), theirs, DirCacheEntry.STAGE_0);
-                       if (e!=null)
-                               toBeCheckedOut.put(tw.getPathString(), e);
-                       return true;
+                       if (nonTree(modeT)) {
+                               DirCacheEntry e = add(tw.getRawPath(), theirs,
+                                               DirCacheEntry.STAGE_0);
+                               if (e != null)
+                                       toBeCheckedOut.put(tw.getPathString(), e);
+                               return true;
+                       } else if (modeT == 0) {
+                               // we want THEIRS ... but THEIRS contains the deletion of the
+                               // file
+                               toBeCheckedOut.put(tw.getPathString(), null);
+                               return true;
+                       }
                }
 
                if (tw.isSubtree()) {