indexState(CONTENT));
}
+ /**
+ * Merging two commits when files have equal content, but conflicting file mode
+ * in the virtual ancestor.
+ *
+ * <p>
+ * This test has the same set up as
+ * {@code checkFileDirMergeConflictInVirtualAncestor_NoConflictInChildren}, only
+ * with the mode conflict in A1 and A2.
+ */
+ @Theory
+ public void checkModeMergeConflictInVirtualAncestor(MergeStrategy strategy) throws Exception {
+ if (!strategy.equals(MergeStrategy.RECURSIVE)) {
+ return;
+ }
+
+ Git git = Git.wrap(db);
+
+ // master
+ writeTrashFile("c", "initial file");
+ git.add().addFilepattern("c").call();
+ RevCommit commitI = git.commit().setMessage("Initial commit").call();
+
+ File a = writeTrashFile("a", "content in Ancestor");
+ git.add().addFilepattern("a").call();
+ RevCommit commitA1 = git.commit().setMessage("Ancestor 1").call();
+
+ a = writeTrashFile("a", "content in Child 1 (commited on master)");
+ git.add().addFilepattern("a").call();
+ // commit C1M
+ git.commit().setMessage("Child 1 on master").call();
+
+ git.checkout().setCreateBranch(true).setStartPoint(commitI).setName("branch-to-merge").call();
+ // "a" becomes executable in A2
+ a = writeTrashFile("a", "content in Ancestor");
+ a.setExecutable(true);
+ git.add().addFilepattern("a").call();
+ RevCommit commitA2 = git.commit().setMessage("Ancestor 2").call();
+
+ // second branch
+ git.checkout().setCreateBranch(true).setStartPoint(commitA1).setName("second-branch").call();
+ a = writeTrashFile("a", "content in Child 2 (commited on second-branch)");
+ git.add().addFilepattern("a").call();
+ // commit C2S
+ git.commit().setMessage("Child 2 on second-branch").call();
+
+ // Merge branch-to-merge into second-branch
+ MergeResult mergeResult = git.merge().include(commitA2).setStrategy(strategy).call();
+ assertEquals(mergeResult.getNewHead(), null);
+ assertEquals(mergeResult.getMergeStatus(), MergeStatus.CONFLICTING);
+ // Resolve the conflict manually, merge "a" as non-executable
+ a = writeTrashFile("a", "merge conflict resolution");
+ a.setExecutable(false);
+ git.add().addFilepattern("a").call();
+ RevCommit commitC3S = git.commit().setMessage("Child 3 on second bug - resolve merge conflict").call();
+
+ // Merge branch-to-merge into master
+ git.checkout().setName("master").call();
+ mergeResult = git.merge().include(commitA2).setStrategy(strategy).call();
+ assertEquals(mergeResult.getNewHead(), null);
+ assertEquals(mergeResult.getMergeStatus(), MergeStatus.CONFLICTING);
+
+ // Resolve the conflict manually - merge "a" as non-executable
+ a = writeTrashFile("a", "merge conflict resolution");
+ a.setExecutable(false);
+ git.add().addFilepattern("a").call();
+ // commit C4M
+ git.commit().setMessage("Child 4 on master - resolve merge conflict").call();
+
+ // Merge C4M (second-branch) into master (C3S)
+ // Conflict in virtual base should be here, but there are no conflicts in
+ // children
+ mergeResult = git.merge().include(commitC3S).call();
+ assertEquals(mergeResult.getMergeStatus(), MergeStatus.MERGED);
+
+ }
+
private void writeSubmodule(String path, ObjectId commit)
throws IOException, ConfigInvalidException {
addSubmoduleToIndex(path, commit);
}
return true;
}
- // FileModes are not mergeable. We found a conflict on modes.
- // For conflicting entries we don't know lastModified and
- // length.
- add(tw.getRawPath(), base, DirCacheEntry.STAGE_1, EPOCH, 0);
- add(tw.getRawPath(), ours, DirCacheEntry.STAGE_2, EPOCH, 0);
- add(tw.getRawPath(), theirs, DirCacheEntry.STAGE_3, EPOCH, 0);
- unmergedPaths.add(tw.getPathString());
- mergeResults.put(tw.getPathString(),
- new MergeResult<>(Collections.<RawText> emptyList()));
+ if (!ignoreConflicts) {
+ // FileModes are not mergeable. We found a conflict on modes.
+ // For conflicting entries we don't know lastModified and
+ // length.
+ // This path can be skipped on ignoreConflicts, so the caller
+ // could use virtual commit.
+ add(tw.getRawPath(), base, DirCacheEntry.STAGE_1, EPOCH, 0);
+ add(tw.getRawPath(), ours, DirCacheEntry.STAGE_2, EPOCH, 0);
+ add(tw.getRawPath(), theirs, DirCacheEntry.STAGE_3, EPOCH, 0);
+ unmergedPaths.add(tw.getPathString());
+ mergeResults.put(tw.getPathString(), new MergeResult<>(Collections.<RawText>emptyList()));
+ }
return true;
}