Browse Source

Allow file mode conflicts in virtual base commit on recursive merge.

Similar to https://git.eclipse.org/r/c/jgit/jgit/+/175166, ignore
path that have conflicts on attributes, so that the virtual base could
be used by RecursiveMerger.

Change-Id: I99c95445a305558d55bbb9c9e97446caaf61c154
Signed-off-by: Marija Savtchouk <mariasavtchouk@google.com>
tags/v5.12.0.202105051250-m2
Marija Savtchouk 3 years ago
parent
commit
7ceb61494b

+ 76
- 0
org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/MergerTest.java View File

@@ -1648,6 +1648,82 @@ public class MergerTest extends RepositoryTestCase {
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);

+ 12
- 9
org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java View File

@@ -644,15 +644,18 @@ public class ResolveMerger extends ThreeWayMerger {
}
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;
}


Loading…
Cancel
Save