}
}
+ /**
+ * The test reproduces https://bugs.eclipse.org/bugs/show_bug.cgi?id=535919.
+ */
+ @Test
+ public void tesdDF_LastItemsInTreeHasDFConflictAndSpecialNames()
+ throws Exception {
+
+ final DirCache tree0 = db.readDirCache();
+ final DirCache tree1 = db.readDirCache();
+
+ final DirCacheBuilder b0 = tree0.builder();
+ final DirCacheBuilder b1 = tree1.builder();
+ // The tree0 has the following order in git:
+ // subtree, subtree-0
+ b0.add(createEntry("subtree", REGULAR_FILE));
+ b0.add(createEntry("subtree-0", REGULAR_FILE));
+ // The tree1 has the following order in git:
+ // subtree-0, subtree/file
+ b1.add(createEntry("subtree/file", REGULAR_FILE));
+ b1.add(createEntry("subtree-0", REGULAR_FILE));
+
+ b0.finish();
+ b1.finish();
+
+ try (NameConflictTreeWalk tw = new NameConflictTreeWalk(db)) {
+ tw.addTree(new DirCacheIterator(tree0));
+ tw.addTree(new DirCacheIterator(tree1));
+
+ assertModes("subtree", REGULAR_FILE, TREE, tw);
+ assertTrue(tw.isSubtree());
+ assertTrue(tw.isDirectoryFileConflict());
+ tw.enterSubtree();
+ assertModes("subtree/file", MISSING, REGULAR_FILE, tw);
+ assertFalse(tw.isSubtree());
+ // isDirectoryFileConflict is true, because the conflict is detected
+ // on parent.
+ assertTrue(tw.isDirectoryFileConflict());
+ assertModes("subtree-0", REGULAR_FILE, REGULAR_FILE, tw);
+ assertFalse(tw.isSubtree());
+ assertFalse(tw.isDirectoryFileConflict());
+ assertFalse(tw.next());
+ }
+ }
+
+ /**
+ * The test reproduces https://bugs.eclipse.org/bugs/show_bug.cgi?id=535919.
+ */
+ @Test
+ public void tesdDF_LastItemsInTreeHasDFConflictAndSpecialNames2()
+ throws Exception {
+
+ final DirCache tree0 = db.readDirCache();
+ final DirCache tree1 = db.readDirCache();
+
+ final DirCacheBuilder b0 = tree0.builder();
+ final DirCacheBuilder b1 = tree1.builder();
+ // The tree0 has the following order in git:
+ // subtree-0, subtree/file
+ b0.add(createEntry("subtree/file", REGULAR_FILE));
+ b0.add(createEntry("subtree-0", REGULAR_FILE));
+ // The tree1 has the following order in git:
+ // subtree, subtree-0
+ b1.add(createEntry("subtree", REGULAR_FILE));
+ b1.add(createEntry("subtree-0", REGULAR_FILE));
+
+ b0.finish();
+ b1.finish();
+
+ try (NameConflictTreeWalk tw = new NameConflictTreeWalk(db)) {
+ tw.addTree(new DirCacheIterator(tree0));
+ tw.addTree(new DirCacheIterator(tree1));
+
+ assertModes("subtree", TREE, REGULAR_FILE, tw);
+ assertTrue(tw.isSubtree());
+ assertTrue(tw.isDirectoryFileConflict());
+ tw.enterSubtree();
+ assertModes("subtree/file", REGULAR_FILE, MISSING, tw);
+ assertFalse(tw.isSubtree());
+ // isDirectoryFileConflict is true, because the conflict is detected
+ // on parent.
+ assertTrue(tw.isDirectoryFileConflict());
+ assertModes("subtree-0", REGULAR_FILE, REGULAR_FILE, tw);
+ assertFalse(tw.isSubtree());
+ assertFalse(tw.isDirectoryFileConflict());
+ assertFalse(tw.next());
+ }
+ }
+
+ @Test
+ public void tesdDF_NonLastItemsInTreeHasDFConflictAndSpecialNames()
+ throws Exception {
+ final DirCache tree0 = db.readDirCache();
+ final DirCache tree1 = db.readDirCache();
+
+ final DirCacheBuilder b0 = tree0.builder();
+ final DirCacheBuilder b1 = tree1.builder();
+ b0.add(createEntry("subtree", REGULAR_FILE));
+ b0.add(createEntry("subtree-0", REGULAR_FILE));
+ b0.add(createEntry("x", REGULAR_FILE));
+
+ b1.add(createEntry("subtree/file", REGULAR_FILE));
+ b1.add(createEntry("subtree-0", REGULAR_FILE));
+ b1.add(createEntry("x", REGULAR_FILE));
+
+ b0.finish();
+ b1.finish();
+
+ try (NameConflictTreeWalk tw = new NameConflictTreeWalk(db)) {
+ tw.addTree(new DirCacheIterator(tree0));
+ tw.addTree(new DirCacheIterator(tree1));
+
+ assertModes("subtree", REGULAR_FILE, TREE, tw);
+ assertTrue(tw.isSubtree());
+ assertTrue(tw.isDirectoryFileConflict());
+ tw.enterSubtree();
+ assertModes("subtree/file", MISSING, REGULAR_FILE, tw);
+ assertFalse(tw.isSubtree());
+ // isDirectoryFileConflict is true, because the conflict is detected
+ // on parent.
+ // see JavaDoc for isDirectoryFileConflict for details
+ assertTrue(tw.isDirectoryFileConflict());
+ assertModes("subtree-0", REGULAR_FILE, REGULAR_FILE, tw);
+ assertFalse(tw.isSubtree());
+ assertFalse(tw.isDirectoryFileConflict());
+ assertModes("x", REGULAR_FILE, REGULAR_FILE, tw);
+ assertFalse(tw.isSubtree());
+ assertFalse(tw.isDirectoryFileConflict());
+ assertFalse(tw.next());
+ }
+ }
+
+ @Test
+ public void tesdDF_NoSpecialNames() throws Exception {
+ final DirCache tree0 = db.readDirCache();
+ final DirCache tree1 = db.readDirCache();
+
+ final DirCacheBuilder b0 = tree0.builder();
+ final DirCacheBuilder b1 = tree1.builder();
+ // In this test both trees (tree0 and tree1) have exactly the same order
+ // of entries:
+ // subtree, xubtree-0
+ b0.add(createEntry("subtree", REGULAR_FILE));
+ b0.add(createEntry("xubtree-0", REGULAR_FILE));
+
+ b1.add(createEntry("subtree/file", REGULAR_FILE));
+ b1.add(createEntry("xubtree-0", REGULAR_FILE));
+
+ b0.finish();
+ b1.finish();
+
+ try (NameConflictTreeWalk tw = new NameConflictTreeWalk(db)) {
+ tw.addTree(new DirCacheIterator(tree0));
+ tw.addTree(new DirCacheIterator(tree1));
+
+ assertModes("subtree", REGULAR_FILE, TREE, tw);
+ assertTrue(tw.isSubtree());
+ assertTrue(tw.isDirectoryFileConflict());
+ tw.enterSubtree();
+ assertModes("subtree/file", MISSING, REGULAR_FILE, tw);
+ assertFalse(tw.isSubtree());
+ // isDirectoryFileConflict is true, because the conflict is detected
+ // on parent.
+ // see JavaDoc for isDirectoryFileConflict for details
+ assertTrue(tw.isDirectoryFileConflict());
+ assertModes("xubtree-0", REGULAR_FILE, REGULAR_FILE, tw);
+ assertFalse(tw.isSubtree());
+ assertFalse(tw.isDirectoryFileConflict());
+ assertFalse(tw.next());
+ }
+ }
+
@Test
public void testDF_specialFileNames() throws Exception {
final DirCache tree0 = db.readDirCache();
public class NameConflictTreeWalk extends TreeWalk {
private static final int TREE_MODE = FileMode.TREE.getBits();
+ /**
+ * True if all {@link #trees} point to entries with equal names.
+ *
+ * If at least one tree iterator point to a different name or
+ * reached end of the tree, the value is false.
+ * Note: if all iterators reached end of trees, the value is true.
+ */
private boolean allTreesNamesMatchFastMinRef;
private AbstractTreeIterator dfConflict;
return trees[trees.length - 1];
}
AbstractTreeIterator minRef = trees[i];
- allTreesNamesMatchFastMinRef = true;
+ // if i > 0 then we already know that only some trees reached the end
+ // (but not all), so it is impossible that ALL trees points to the
+ // minRef entry.
+ // Only if i == 0 it is still possible that all trees points to the same
+ // minRef entry.
+ allTreesNamesMatchFastMinRef = i == 0;
boolean hasConflict = false;
minRef.matches = minRef;
while (++i < trees.length) {
final AbstractTreeIterator t = trees[i];
- if (t.eof())
+ if (t.eof()) {
+ allTreesNamesMatchFastMinRef = false;
continue;
+ }
final int cmp = t.pathCompare(minRef);
if (cmp < 0) {
// Exact name/mode match is best.
//
t.matches = minRef;
- } else if (allTreesNamesMatchFastMinRef && isTree(t) && !isTree(minRef)
- && !isGitlink(minRef) && nameEqual(t, minRef)) {
+ } else if (allTreesNamesMatchFastMinRef && isTree(t)
+ && !isTree(minRef) && !isGitlink(minRef)
+ && nameEqual(t, minRef)) {
// The minimum is a file (non-tree) but the next entry
// of this iterator is a tree whose name matches our file.
// This is a classic D/F conflict and commonly occurs like