diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/NameConflictTreeWalkTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/NameConflictTreeWalkTest.java index 675331baf..e59b7c18d 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/NameConflictTreeWalkTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/NameConflictTreeWalkTest.java @@ -120,11 +120,15 @@ public class NameConflictTreeWalkTest extends RepositoryTestCase { tw.addTree(new DirCacheIterator(tree1)); assertModes("a", REGULAR_FILE, TREE, tw); + assertTrue(tw.isDirectoryFileConflict()); assertTrue(tw.isSubtree()); tw.enterSubtree(); assertModes("a/b", MISSING, REGULAR_FILE, tw); + assertTrue(tw.isDirectoryFileConflict()); assertModes("a.b", EXECUTABLE_FILE, MISSING, tw); + assertFalse(tw.isDirectoryFileConflict()); assertModes("a0b", SYMLINK, MISSING, tw); + assertFalse(tw.isDirectoryFileConflict()); } public void testDF_GapByOne() throws Exception { @@ -153,10 +157,14 @@ public class NameConflictTreeWalkTest extends RepositoryTestCase { assertModes("a", REGULAR_FILE, TREE, tw); assertTrue(tw.isSubtree()); + assertTrue(tw.isDirectoryFileConflict()); tw.enterSubtree(); assertModes("a/b", MISSING, REGULAR_FILE, tw); + assertTrue(tw.isDirectoryFileConflict()); assertModes("a.b", EXECUTABLE_FILE, EXECUTABLE_FILE, tw); + assertFalse(tw.isDirectoryFileConflict()); assertModes("a0b", SYMLINK, MISSING, tw); + assertFalse(tw.isDirectoryFileConflict()); } public void testDF_SkipsSeenSubtree() throws Exception { @@ -185,10 +193,57 @@ public class NameConflictTreeWalkTest extends RepositoryTestCase { assertModes("a", REGULAR_FILE, TREE, tw); assertTrue(tw.isSubtree()); + assertTrue(tw.isDirectoryFileConflict()); tw.enterSubtree(); assertModes("a/b", MISSING, REGULAR_FILE, tw); + assertTrue(tw.isDirectoryFileConflict()); assertModes("a.b", MISSING, EXECUTABLE_FILE, tw); + assertFalse(tw.isDirectoryFileConflict()); assertModes("a0b", SYMLINK, SYMLINK, tw); + assertFalse(tw.isDirectoryFileConflict()); + } + + public void testDF_DetectConflict() throws Exception { + final DirCache tree0 = db.readDirCache(); + final DirCache tree1 = db.readDirCache(); + { + final DirCacheBuilder b0 = tree0.builder(); + final DirCacheBuilder b1 = tree1.builder(); + + b0.add(makeEntry("0", REGULAR_FILE)); + b0.add(makeEntry("a", REGULAR_FILE)); + b1.add(makeEntry("0", REGULAR_FILE)); + b1.add(makeEntry("a.b", REGULAR_FILE)); + b1.add(makeEntry("a/b", REGULAR_FILE)); + b1.add(makeEntry("a/c/e", REGULAR_FILE)); + + b0.finish(); + b1.finish(); + assertEquals(2, tree0.getEntryCount()); + assertEquals(4, tree1.getEntryCount()); + } + + final NameConflictTreeWalk tw = new NameConflictTreeWalk(db); + tw.reset(); + tw.addTree(new DirCacheIterator(tree0)); + tw.addTree(new DirCacheIterator(tree1)); + + assertModes("0", REGULAR_FILE, REGULAR_FILE, tw); + assertFalse(tw.isDirectoryFileConflict()); + assertModes("a", REGULAR_FILE, TREE, tw); + assertTrue(tw.isSubtree()); + assertTrue(tw.isDirectoryFileConflict()); + tw.enterSubtree(); + assertModes("a/b", MISSING, REGULAR_FILE, tw); + assertTrue(tw.isDirectoryFileConflict()); + assertModes("a/c", MISSING, TREE, tw); + assertTrue(tw.isDirectoryFileConflict()); + tw.enterSubtree(); + assertModes("a/c/e", MISSING, REGULAR_FILE, tw); + assertTrue(tw.isDirectoryFileConflict()); + + assertModes("a.b", MISSING, REGULAR_FILE, tw); + assertFalse(tw.isDirectoryFileConflict()); } private DirCacheEntry makeEntry(final String path, final FileMode mode) diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/NameConflictTreeWalk.java b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/NameConflictTreeWalk.java index 99126e861..2d6acbddf 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/NameConflictTreeWalk.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/NameConflictTreeWalk.java @@ -87,6 +87,8 @@ public class NameConflictTreeWalk extends TreeWalk { private boolean fastMinHasMatch; + private AbstractTreeIterator dfConflict; + /** * Create a new tree walker for a given repository. * @@ -141,6 +143,7 @@ public class NameConflictTreeWalk extends TreeWalk { if (minRef.eof()) return minRef; + boolean hasConflict = false; minRef.matches = minRef; while (++i < trees.length) { final AbstractTreeIterator t = trees[i]; @@ -156,6 +159,7 @@ public class NameConflictTreeWalk extends TreeWalk { // tree anyway. // t.matches = minRef; + hasConflict = true; } else { fastMinHasMatch = false; t.matches = t; @@ -182,10 +186,13 @@ public class NameConflictTreeWalk extends TreeWalk { } t.matches = t; minRef = t; + hasConflict = true; } else fastMinHasMatch = false; } + if (hasConflict && fastMinHasMatch && dfConflict == null) + dfConflict = minRef; return minRef; } @@ -281,6 +288,10 @@ public class NameConflictTreeWalk extends TreeWalk { for (final AbstractTreeIterator t : trees) if (t.matches == minRef) t.matches = treeMatch; + + if (dfConflict == null) + dfConflict = treeMatch; + return treeMatch; } @@ -302,6 +313,9 @@ public class NameConflictTreeWalk extends TreeWalk { t.matches = null; } } + + if (ch == dfConflict) + dfConflict = null; } @Override @@ -319,5 +333,26 @@ public class NameConflictTreeWalk extends TreeWalk { t.matches = null; } } + + if (ch == dfConflict) + dfConflict = null; + } + + /** + * True if the current entry is covered by a directory/file conflict. + * + * This means that for some prefix of the current entry's path, this walk + * has detected a directory/file conflict. Also true if the current entry + * itself is a directory/file conflict. + * + * Example: If this TreeWalk points to foo/bar/a.txt and this method returns + * true then you know that either for path foo or for path foo/bar files and + * folders were detected. + * + * @return true if the current entry is covered by a + * directory/file conflict, false otherwise + */ + public boolean isDirectoryFileConflict() { + return dfConflict != null; } }