[JGIT PATCH 2/2] Fix merges involving clean subtrees with StrategySimpleTwoWayInCore

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



If a both sides modify files in the same subtree, but do so in a
non-conflicting way, we should still be able to merge them by an
automated merge strategy.  Recursing into the subtree permits us
to do this merge.

Signed-off-by: Shawn O. Pearce <spearce@xxxxxxxxxxx>
---
 .../org/spearce/jgit/merge/SimpleMergeTest.java    |  204 ++++++++++++++++++++
 .../jgit/merge/StrategySimpleTwoWayInCore.java     |   32 ++-
 2 files changed, 225 insertions(+), 11 deletions(-)

diff --git a/org.spearce.jgit.test/tst/org/spearce/jgit/merge/SimpleMergeTest.java b/org.spearce.jgit.test/tst/org/spearce/jgit/merge/SimpleMergeTest.java
index e99f017..c5755a8 100644
--- a/org.spearce.jgit.test/tst/org/spearce/jgit/merge/SimpleMergeTest.java
+++ b/org.spearce.jgit.test/tst/org/spearce/jgit/merge/SimpleMergeTest.java
@@ -146,6 +146,210 @@ public void testTrivialTwoWay_validSubtreeSort() throws Exception {
 		assertFalse(tw.next());
 	}
 
+	public void testTrivialTwoWay_concurrentSubtreeChange() throws Exception {
+		final DirCache treeB = DirCache.read(db);
+		final DirCache treeO = DirCache.read(db);
+		final DirCache treeT = DirCache.read(db);
+		{
+			final DirCacheBuilder b = treeB.builder();
+			final DirCacheBuilder o = treeO.builder();
+			final DirCacheBuilder t = treeT.builder();
+
+			b.add(makeEntry("d/o", FileMode.REGULAR_FILE));
+			b.add(makeEntry("d/t", FileMode.REGULAR_FILE));
+
+			o.add(makeEntry("d/o", FileMode.REGULAR_FILE, "o !"));
+			o.add(makeEntry("d/t", FileMode.REGULAR_FILE));
+
+			t.add(makeEntry("d/o", FileMode.REGULAR_FILE));
+			t.add(makeEntry("d/t", FileMode.REGULAR_FILE, "t !"));
+
+			b.finish();
+			o.finish();
+			t.finish();
+		}
+
+		final ObjectWriter ow = new ObjectWriter(db);
+		final ObjectId b = commit(ow, treeB, new ObjectId[] {});
+		final ObjectId o = commit(ow, treeO, new ObjectId[] { b });
+		final ObjectId t = commit(ow, treeT, new ObjectId[] { b });
+
+		Merger ourMerger = MergeStrategy.SIMPLE_TWO_WAY_IN_CORE.newMerger(db);
+		boolean merge = ourMerger.merge(new ObjectId[] { o, t });
+		assertTrue(merge);
+
+		final TreeWalk tw = new TreeWalk(db);
+		tw.setRecursive(true);
+		tw.reset(ourMerger.getResultTreeId());
+
+		assertTrue(tw.next());
+		assertEquals("d/o", tw.getPathString());
+		assertCorrectId(treeO, tw);
+
+		assertTrue(tw.next());
+		assertEquals("d/t", tw.getPathString());
+		assertCorrectId(treeT, tw);
+
+		assertFalse(tw.next());
+	}
+	
+	public void testTrivialTwoWay_conflictSubtreeChange() throws Exception {
+		final DirCache treeB = DirCache.read(db);
+		final DirCache treeO = DirCache.read(db);
+		final DirCache treeT = DirCache.read(db);
+		{
+			final DirCacheBuilder b = treeB.builder();
+			final DirCacheBuilder o = treeO.builder();
+			final DirCacheBuilder t = treeT.builder();
+
+			b.add(makeEntry("d/o", FileMode.REGULAR_FILE));
+			b.add(makeEntry("d/t", FileMode.REGULAR_FILE));
+
+			o.add(makeEntry("d/o", FileMode.REGULAR_FILE));
+			o.add(makeEntry("d/t", FileMode.REGULAR_FILE, "o !"));
+
+			t.add(makeEntry("d/o", FileMode.REGULAR_FILE, "t !"));
+			t.add(makeEntry("d/t", FileMode.REGULAR_FILE, "t !"));
+
+			b.finish();
+			o.finish();
+			t.finish();
+		}
+
+		final ObjectWriter ow = new ObjectWriter(db);
+		final ObjectId b = commit(ow, treeB, new ObjectId[] {});
+		final ObjectId o = commit(ow, treeO, new ObjectId[] { b });
+		final ObjectId t = commit(ow, treeT, new ObjectId[] { b });
+
+		Merger ourMerger = MergeStrategy.SIMPLE_TWO_WAY_IN_CORE.newMerger(db);
+		boolean merge = ourMerger.merge(new ObjectId[] { o, t });
+		assertFalse(merge);
+	}
+
+	public void testTrivialTwoWay_leftDFconflict1() throws Exception {
+		final DirCache treeB = DirCache.read(db);
+		final DirCache treeO = DirCache.read(db);
+		final DirCache treeT = DirCache.read(db);
+		{
+			final DirCacheBuilder b = treeB.builder();
+			final DirCacheBuilder o = treeO.builder();
+			final DirCacheBuilder t = treeT.builder();
+
+			b.add(makeEntry("d/o", FileMode.REGULAR_FILE));
+			b.add(makeEntry("d/t", FileMode.REGULAR_FILE));
+
+			o.add(makeEntry("d", FileMode.REGULAR_FILE));
+
+			t.add(makeEntry("d/o", FileMode.REGULAR_FILE));
+			t.add(makeEntry("d/t", FileMode.REGULAR_FILE, "t !"));
+
+			b.finish();
+			o.finish();
+			t.finish();
+		}
+
+		final ObjectWriter ow = new ObjectWriter(db);
+		final ObjectId b = commit(ow, treeB, new ObjectId[] {});
+		final ObjectId o = commit(ow, treeO, new ObjectId[] { b });
+		final ObjectId t = commit(ow, treeT, new ObjectId[] { b });
+
+		Merger ourMerger = MergeStrategy.SIMPLE_TWO_WAY_IN_CORE.newMerger(db);
+		boolean merge = ourMerger.merge(new ObjectId[] { o, t });
+		assertFalse(merge);
+	}
+
+	public void testTrivialTwoWay_rightDFconflict1() throws Exception {
+		final DirCache treeB = DirCache.read(db);
+		final DirCache treeO = DirCache.read(db);
+		final DirCache treeT = DirCache.read(db);
+		{
+			final DirCacheBuilder b = treeB.builder();
+			final DirCacheBuilder o = treeO.builder();
+			final DirCacheBuilder t = treeT.builder();
+
+			b.add(makeEntry("d/o", FileMode.REGULAR_FILE));
+			b.add(makeEntry("d/t", FileMode.REGULAR_FILE));
+
+			o.add(makeEntry("d/o", FileMode.REGULAR_FILE));
+			o.add(makeEntry("d/t", FileMode.REGULAR_FILE, "o !"));
+
+			t.add(makeEntry("d", FileMode.REGULAR_FILE));
+
+			b.finish();
+			o.finish();
+			t.finish();
+		}
+
+		final ObjectWriter ow = new ObjectWriter(db);
+		final ObjectId b = commit(ow, treeB, new ObjectId[] {});
+		final ObjectId o = commit(ow, treeO, new ObjectId[] { b });
+		final ObjectId t = commit(ow, treeT, new ObjectId[] { b });
+
+		Merger ourMerger = MergeStrategy.SIMPLE_TWO_WAY_IN_CORE.newMerger(db);
+		boolean merge = ourMerger.merge(new ObjectId[] { o, t });
+		assertFalse(merge);
+	}
+
+	public void testTrivialTwoWay_leftDFconflict2() throws Exception {
+		final DirCache treeB = DirCache.read(db);
+		final DirCache treeO = DirCache.read(db);
+		final DirCache treeT = DirCache.read(db);
+		{
+			final DirCacheBuilder b = treeB.builder();
+			final DirCacheBuilder o = treeO.builder();
+			final DirCacheBuilder t = treeT.builder();
+
+			b.add(makeEntry("d", FileMode.REGULAR_FILE));
+
+			o.add(makeEntry("d", FileMode.REGULAR_FILE, "o !"));
+
+			t.add(makeEntry("d/o", FileMode.REGULAR_FILE));
+
+			b.finish();
+			o.finish();
+			t.finish();
+		}
+
+		final ObjectWriter ow = new ObjectWriter(db);
+		final ObjectId b = commit(ow, treeB, new ObjectId[] {});
+		final ObjectId o = commit(ow, treeO, new ObjectId[] { b });
+		final ObjectId t = commit(ow, treeT, new ObjectId[] { b });
+
+		Merger ourMerger = MergeStrategy.SIMPLE_TWO_WAY_IN_CORE.newMerger(db);
+		boolean merge = ourMerger.merge(new ObjectId[] { o, t });
+		assertFalse(merge);
+	}
+
+	public void testTrivialTwoWay_rightDFconflict2() throws Exception {
+		final DirCache treeB = DirCache.read(db);
+		final DirCache treeO = DirCache.read(db);
+		final DirCache treeT = DirCache.read(db);
+		{
+			final DirCacheBuilder b = treeB.builder();
+			final DirCacheBuilder o = treeO.builder();
+			final DirCacheBuilder t = treeT.builder();
+
+			b.add(makeEntry("d", FileMode.REGULAR_FILE));
+
+			o.add(makeEntry("d/o", FileMode.REGULAR_FILE));
+
+			t.add(makeEntry("d", FileMode.REGULAR_FILE, "t !"));
+
+			b.finish();
+			o.finish();
+			t.finish();
+		}
+
+		final ObjectWriter ow = new ObjectWriter(db);
+		final ObjectId b = commit(ow, treeB, new ObjectId[] {});
+		final ObjectId o = commit(ow, treeO, new ObjectId[] { b });
+		final ObjectId t = commit(ow, treeT, new ObjectId[] { b });
+
+		Merger ourMerger = MergeStrategy.SIMPLE_TWO_WAY_IN_CORE.newMerger(db);
+		boolean merge = ourMerger.merge(new ObjectId[] { o, t });
+		assertFalse(merge);
+	}
+
 	private void assertCorrectId(final DirCache treeT, final TreeWalk tw) {
 		assertEquals(treeT.getEntry(tw.getPathString()).getObjectId(), tw
 				.getObjectId(0));
diff --git a/org.spearce.jgit/src/org/spearce/jgit/merge/StrategySimpleTwoWayInCore.java b/org.spearce.jgit/src/org/spearce/jgit/merge/StrategySimpleTwoWayInCore.java
index 0f8b4e1..3ebe397 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/merge/StrategySimpleTwoWayInCore.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/merge/StrategySimpleTwoWayInCore.java
@@ -115,7 +115,7 @@ protected boolean mergeImpl() throws IOException {
 				final int modeO = tw.getRawMode(T_OURS);
 				final int modeT = tw.getRawMode(T_THEIRS);
 				if (modeO == modeT && tw.idEqual(T_OURS, T_THEIRS)) {
-					same();
+					add(T_OURS, DirCacheEntry.STAGE_0);
 					continue;
 				}
 
@@ -124,8 +124,24 @@ protected boolean mergeImpl() throws IOException {
 					add(T_THEIRS, DirCacheEntry.STAGE_0);
 				else if (modeB == modeT && tw.idEqual(T_BASE, T_THEIRS))
 					add(T_OURS, DirCacheEntry.STAGE_0);
-				else {
-					conflict();
+				else if (tw.isSubtree()) {
+					if (nonTree(modeB)) {
+						add(T_BASE, DirCacheEntry.STAGE_1);
+						hasConflict = true;
+					}
+					if (nonTree(modeO)) {
+						add(T_OURS, DirCacheEntry.STAGE_2);
+						hasConflict = true;
+					}
+					if (nonTree(modeT)) {
+						add(T_THEIRS, DirCacheEntry.STAGE_3);
+						hasConflict = true;
+					}
+					tw.enterSubtree();
+				} else {
+					add(T_BASE, DirCacheEntry.STAGE_1);
+					add(T_OURS, DirCacheEntry.STAGE_2);
+					add(T_THEIRS, DirCacheEntry.STAGE_3);
 					hasConflict = true;
 				}
 			}
@@ -143,14 +159,8 @@ else if (modeB == modeT && tw.idEqual(T_BASE, T_THEIRS))
 			}
 		}
 
-		private void same() throws IOException {
-			add(T_OURS, DirCacheEntry.STAGE_0);
-		}
-
-		private void conflict() throws IOException {
-			add(T_BASE, DirCacheEntry.STAGE_1);
-			add(T_OURS, DirCacheEntry.STAGE_2);
-			add(T_THEIRS, DirCacheEntry.STAGE_3);
+		private static boolean nonTree(final int mode) {
+			return mode != 0 && !FileMode.TREE.equals(mode);
 		}
 
 		private void add(final int tree, final int stage) throws IOException {
-- 
1.6.2.96.gc65e7

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]

  Powered by Linux