Fix a number of failing conflict situations

Adds further tests where the working tree is dirty (differs from
index) and where we have staged but uncommitted changes.

Fixed the test case 9 for file/directory conflicts.

Bug: 428819
Change-Id: Ie44a288b052abe936ebb74272d0fefef3b218a7a
Signed-off-by: Axel Richard <axel.richard@obeo.fr>
Signed-off-by: Robin Rosenberg <robin.rosenberg@dewire.com>
Signed-off-by: Christian Halstrick <christian.halstrick@sap.com>
This commit is contained in:
Robin Rosenberg 2014-03-30 22:04:53 +02:00
parent f7ac527ca7
commit 1a9f122773
5 changed files with 486 additions and 46 deletions

View File

@ -8,6 +8,8 @@ Bundle-Localization: plugin
Bundle-ActivationPolicy: lazy Bundle-ActivationPolicy: lazy
Bundle-RequiredExecutionEnvironment: J2SE-1.5 Bundle-RequiredExecutionEnvironment: J2SE-1.5
Import-Package: org.eclipse.jgit.api;version="[3.4.0,3.5.0)", Import-Package: org.eclipse.jgit.api;version="[3.4.0,3.5.0)",
org.eclipse.jgit.api.errors;version="[3.4.0,3.5.0)",
org.eclipse.jgit.diff;version="[3.4.0,3.5.0)",
org.eclipse.jgit.dircache;version="[3.4.0,3.5.0)", org.eclipse.jgit.dircache;version="[3.4.0,3.5.0)",
org.eclipse.jgit.junit;version="[3.4.0,3.5.0)", org.eclipse.jgit.junit;version="[3.4.0,3.5.0)",
org.eclipse.jgit.lib;version="[3.4.0,3.5.0)", org.eclipse.jgit.lib;version="[3.4.0,3.5.0)",

View File

@ -43,15 +43,21 @@
package org.eclipse.jgit.pgm; package org.eclipse.jgit.pgm;
import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertNotNull;
import java.io.File; import java.io.File;
import java.util.List;
import org.eclipse.jgit.api.Git; import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.errors.CheckoutConflictException;
import org.eclipse.jgit.diff.DiffEntry;
import org.eclipse.jgit.lib.CLIRepositoryTestCase; import org.eclipse.jgit.lib.CLIRepositoryTestCase;
import org.eclipse.jgit.lib.FileMode; import org.eclipse.jgit.lib.FileMode;
import org.eclipse.jgit.lib.Ref; import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.treewalk.FileTreeIterator; import org.eclipse.jgit.treewalk.FileTreeIterator;
import org.eclipse.jgit.treewalk.FileTreeIterator.FileEntry; import org.eclipse.jgit.treewalk.FileTreeIterator.FileEntry;
import org.eclipse.jgit.treewalk.TreeWalk;
import org.eclipse.jgit.util.FileUtils; import org.eclipse.jgit.util.FileUtils;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
@ -150,6 +156,7 @@ public void testCheckoutExistingBranchWithConflict() throws Exception {
* <li>Delete file 'a' in the working tree * <li>Delete file 'a' in the working tree
* <li>Checkout branch '1' * <li>Checkout branch '1'
* </ol> * </ol>
* <p>
* The working tree should contain 'a' with FileMode.REGULAR_FILE after the * The working tree should contain 'a' with FileMode.REGULAR_FILE after the
* checkout. * checkout.
* *
@ -181,6 +188,359 @@ public void testCheckoutWithMissingWorkingTreeFile() throws Exception {
assertEquals("Hello world a", read(fileA)); assertEquals("Hello world a", read(fileA));
} }
/**
* Steps:
* <ol>
* <li>Add file 'b'
* <li>Commit
* <li>Create branch '1'
* <li>Add folder 'a'
* <li>Commit
* <li>Replace folder 'a' by file 'a' in the working tree
* <li>Checkout branch '1'
* </ol>
* <p>
* The working tree should contain 'a' with FileMode.REGULAR_FILE after the
* checkout.
*
* @throws Exception
*/
@Test
public void fileModeTestMissingThenFolderWithFileInWorkingTree()
throws Exception {
Git git = new Git(db);
writeTrashFile("b", "Hello world b");
git.add().addFilepattern(".").call();
git.commit().setMessage("add file b").call();
Ref branch_1 = git.branchCreate().setName("branch_1").call();
File folderA = new File(db.getWorkTree(), "a");
FileUtils.mkdirs(folderA);
writeTrashFile("a/c", "Hello world c");
git.add().addFilepattern(".").call();
git.commit().setMessage("add folder a").call();
FileEntry entry = new FileTreeIterator.FileEntry(new File(
db.getWorkTree(), "a"), db.getFS());
assertEquals(FileMode.TREE, entry.getMode());
FileUtils.delete(folderA, FileUtils.RECURSIVE);
writeTrashFile("a", "b");
entry = new FileTreeIterator.FileEntry(new File(db.getWorkTree(), "a"),
db.getFS());
assertEquals(FileMode.REGULAR_FILE, entry.getMode());
git.checkout().setName(branch_1.getName()).call();
entry = new FileTreeIterator.FileEntry(new File(db.getWorkTree(), "a"),
db.getFS());
assertEquals(FileMode.REGULAR_FILE, entry.getMode());
}
/**
* Steps:
* <ol>
* <li>Add file 'a'
* <li>Commit
* <li>Create branch '1'
* <li>Replace file 'a' by folder 'a'
* <li>Commit
* <li>Delete folder 'a' in the working tree
* <li>Checkout branch '1'
* </ol>
* <p>
* The working tree should contain 'a' with FileMode.REGULAR_FILE after the
* checkout.
*
* @throws Exception
*/
@Test
public void fileModeTestFolderWithMissingInWorkingTree() throws Exception {
Git git = new Git(db);
writeTrashFile("b", "Hello world b");
writeTrashFile("a", "b");
git.add().addFilepattern(".").call();
git.commit().setMessage("add file b & file a").call();
Ref branch_1 = git.branchCreate().setName("branch_1").call();
git.rm().addFilepattern("a").call();
File folderA = new File(db.getWorkTree(), "a");
FileUtils.mkdirs(folderA);
writeTrashFile("a/c", "Hello world c");
git.add().addFilepattern(".").call();
git.commit().setMessage("add folder a").call();
FileEntry entry = new FileTreeIterator.FileEntry(new File(
db.getWorkTree(), "a"), db.getFS());
assertEquals(FileMode.TREE, entry.getMode());
FileUtils.delete(folderA, FileUtils.RECURSIVE);
git.checkout().setName(branch_1.getName()).call();
entry = new FileTreeIterator.FileEntry(new File(db.getWorkTree(), "a"),
db.getFS());
assertEquals(FileMode.REGULAR_FILE, entry.getMode());
}
/**
* Steps:
* <ol>
* <li>Add file 'a'
* <li>Commit
* <li>Create branch '1'
* <li>Delete file 'a'
* <li>Commit
* <li>Add folder 'a' in the working tree
* <li>Checkout branch '1'
* </ol>
* <p>
* The checkout command should raise an error. The conflicting paths are 'a'
* and 'a/c'.
*
* @throws Exception
*/
@Test
public void fileModeTestMissingWithFolderInWorkingTree() throws Exception {
Git git = new Git(db);
writeTrashFile("b", "Hello world b");
writeTrashFile("a", "b");
git.add().addFilepattern(".").call();
git.commit().setMessage("add file b & file a").call();
Ref branch_1 = git.branchCreate().setName("branch_1").call();
git.rm().addFilepattern("a").call();
git.commit().setMessage("delete file a").call();
FileUtils.mkdirs(new File(db.getWorkTree(), "a"));
writeTrashFile("a/c", "Hello world c");
FileEntry entry = new FileTreeIterator.FileEntry(new File(
db.getWorkTree(), "a"), db.getFS());
assertEquals(FileMode.TREE, entry.getMode());
CheckoutConflictException exception = null;
try {
git.checkout().setName(branch_1.getName()).call();
} catch (CheckoutConflictException e) {
exception = e;
}
assertNotNull(exception);
assertEquals(2, exception.getConflictingPaths().size());
assertEquals("a", exception.getConflictingPaths().get(0));
assertEquals("a/c", exception.getConflictingPaths().get(1));
}
/**
* Steps:
* <ol>
* <li>Add folder 'a'
* <li>Commit
* <li>Create branch '1'
* <li>Delete folder 'a'
* <li>Commit
* <li>Add file 'a' in the working tree
* <li>Checkout branch '1'
* </ol>
* <p>
* The checkout command should raise an error. The conflicting path is 'a'.
*
* @throws Exception
*/
@Test
public void fileModeTestFolderThenMissingWithFileInWorkingTree()
throws Exception {
Git git = new Git(db);
FileUtils.mkdirs(new File(db.getWorkTree(), "a"));
writeTrashFile("a/c", "Hello world c");
writeTrashFile("b", "Hello world b");
git.add().addFilepattern(".").call();
RevCommit commit1 = git.commit().setMessage("add folder a & file b")
.call();
Ref branch_1 = git.branchCreate().setName("branch_1").call();
git.rm().addFilepattern("a").call();
RevCommit commit2 = git.commit().setMessage("delete folder a").call();
TreeWalk tw = new TreeWalk(db);
tw.addTree(commit1.getTree());
tw.addTree(commit2.getTree());
List<DiffEntry> scan = DiffEntry.scan(tw);
assertEquals(1, scan.size());
assertEquals(FileMode.MISSING, scan.get(0).getNewMode());
assertEquals(FileMode.TREE, scan.get(0).getOldMode());
writeTrashFile("a", "b");
FileEntry entry = new FileTreeIterator.FileEntry(new File(
db.getWorkTree(), "a"), db.getFS());
assertEquals(FileMode.REGULAR_FILE, entry.getMode());
CheckoutConflictException exception = null;
try {
git.checkout().setName(branch_1.getName()).call();
} catch (CheckoutConflictException e) {
exception = e;
}
assertNotNull(exception);
assertEquals(1, exception.getConflictingPaths().size());
assertEquals("a", exception.getConflictingPaths().get(0));
}
/**
* Steps:
* <ol>
* <li>Add folder 'a'
* <li>Commit
* <li>Create branch '1'
* <li>Replace folder 'a'by file 'a'
* <li>Commit
* <li>Delete file 'a' in the working tree
* <li>Checkout branch '1'
* </ol>
* <p>
* The working tree should contain 'a' with FileMode.TREE after the
* checkout.
*
* @throws Exception
*/
@Test
public void fileModeTestFolderThenFileWithMissingInWorkingTree()
throws Exception {
Git git = new Git(db);
FileUtils.mkdirs(new File(db.getWorkTree(), "a"));
writeTrashFile("a/c", "Hello world c");
writeTrashFile("b", "Hello world b");
git.add().addFilepattern(".").call();
git.commit().setMessage("add folder a & file b").call();
Ref branch_1 = git.branchCreate().setName("branch_1").call();
git.rm().addFilepattern("a").call();
File fileA = new File(db.getWorkTree(), "a");
writeTrashFile("a", "b");
git.add().addFilepattern("a").call();
git.commit().setMessage("add file a").call();
FileEntry entry = new FileTreeIterator.FileEntry(new File(
db.getWorkTree(), "a"), db.getFS());
assertEquals(FileMode.REGULAR_FILE, entry.getMode());
FileUtils.delete(fileA);
git.checkout().setName(branch_1.getName()).call();
entry = new FileTreeIterator.FileEntry(new File(db.getWorkTree(), "a"),
db.getFS());
assertEquals(FileMode.TREE, entry.getMode());
}
/**
* Steps:
* <ol>
* <li>Add file 'a'
* <li>Commit
* <li>Create branch '1'
* <li>Modify file 'a'
* <li>Commit
* <li>Delete file 'a' & replace by folder 'a' in the working tree & index
* <li>Checkout branch '1'
* </ol>
* <p>
* The checkout command should raise an error. The conflicting path is 'a'.
*
* @throws Exception
*/
@Test
public void fileModeTestFileThenFileWithFolderInIndex() throws Exception {
Git git = new Git(db);
writeTrashFile("a", "Hello world a");
writeTrashFile("b", "Hello world b");
git.add().addFilepattern(".").call();
git.commit().setMessage("add files a & b").call();
Ref branch_1 = git.branchCreate().setName("branch_1").call();
writeTrashFile("a", "b");
git.add().addFilepattern("a").call();
git.commit().setMessage("add file a").call();
FileEntry entry = new FileTreeIterator.FileEntry(new File(
db.getWorkTree(), "a"), db.getFS());
assertEquals(FileMode.REGULAR_FILE, entry.getMode());
git.rm().addFilepattern("a").call();
FileUtils.mkdirs(new File(db.getWorkTree(), "a"));
writeTrashFile("a/c", "Hello world c");
git.add().addFilepattern(".").call();
entry = new FileTreeIterator.FileEntry(new File(db.getWorkTree(), "a"),
db.getFS());
assertEquals(FileMode.TREE, entry.getMode());
CheckoutConflictException exception = null;
try {
git.checkout().setName(branch_1.getName()).call();
} catch (CheckoutConflictException e) {
exception = e;
}
assertNotNull(exception);
assertEquals(1, exception.getConflictingPaths().size());
assertEquals("a", exception.getConflictingPaths().get(0));
}
/**
* Steps:
* <ol>
* <li>Add file 'a'
* <li>Commit
* <li>Create branch '1'
* <li>Modify file 'a'
* <li>Commit
* <li>Delete file 'a' & replace by folder 'a' in the working tree & index
* <li>Checkout branch '1'
* </ol>
* <p>
* The checkout command should raise an error. The conflicting paths are 'a'
* and 'a/c'.
*
* @throws Exception
*/
@Test
public void fileModeTestFileWithFolderInIndex() throws Exception {
Git git = new Git(db);
writeTrashFile("b", "Hello world b");
writeTrashFile("a", "b");
git.add().addFilepattern(".").call();
git.commit().setMessage("add file b & file a").call();
Ref branch_1 = git.branchCreate().setName("branch_1").call();
git.rm().addFilepattern("a").call();
writeTrashFile("a", "Hello world a");
git.add().addFilepattern("a").call();
git.commit().setMessage("add file a").call();
FileEntry entry = new FileTreeIterator.FileEntry(new File(
db.getWorkTree(), "a"), db.getFS());
assertEquals(FileMode.REGULAR_FILE, entry.getMode());
git.rm().addFilepattern("a").call();
FileUtils.mkdirs(new File(db.getWorkTree(), "a"));
writeTrashFile("a/c", "Hello world c");
git.add().addFilepattern(".").call();
entry = new FileTreeIterator.FileEntry(new File(db.getWorkTree(), "a"),
db.getFS());
assertEquals(FileMode.TREE, entry.getMode());
CheckoutConflictException exception = null;
try {
git.checkout().setName(branch_1.getName()).call();
} catch (CheckoutConflictException e) {
exception = e;
}
assertNotNull(exception);
assertEquals(1, exception.getConflictingPaths().size());
assertEquals("a", exception.getConflictingPaths().get(0));
// TODO: ideally we'd like to get two paths from this exception
// assertEquals(2, exception.getConflictingPaths().size());
// assertEquals("a", exception.getConflictingPaths().get(0));
// assertEquals("a/c", exception.getConflictingPaths().get(1));
}
static private void assertEquals(Object expected, Object actual) { static private void assertEquals(Object expected, Object actual) {
Assert.assertEquals(expected, actual); Assert.assertEquals(expected, actual);
} }

View File

@ -619,7 +619,7 @@ public void testDirectoryFileConflicts_8() throws Exception {
@Test @Test
public void testDirectoryFileConflicts_9() throws Exception { public void testDirectoryFileConflicts_9() throws Exception {
// 9 // 9
doit(mk("DF"), mkmap("DF", "QP"), mk("DF/DF")); doit(mkmap("DF", "QP"), mkmap("DF", "QP"), mkmap("DF/DF", "DF/DF"));
assertRemoved("DF/DF"); assertRemoved("DF/DF");
assertUpdated("DF"); assertUpdated("DF");
} }

View File

@ -562,7 +562,7 @@ void processEntry(CanonicalTreeParser h, CanonicalTreeParser m,
* 6b D F F N N N N Conflict * 6b D F F N N N N Conflict
* 7 F D F Y Y N N Update * 7 F D F Y Y N N Update
* 8 F D F N Y N N Conflict * 8 F D F N Y N N Conflict
* 9 F D F Y N N N Update * 9 F D F N N N Conflict
* 10 F D D N N Y Keep * 10 F D D N N Y Keep
* 11 F D D N N N Conflict * 11 F D D N N N Conflict
* 12 F F D Y N Y N Update * 12 F F D Y N Y N Update
@ -610,7 +610,7 @@ void processEntry(CanonicalTreeParser h, CanonicalTreeParser m,
// switch processes all relevant cases. // switch processes all relevant cases.
switch (ffMask) { switch (ffMask) {
case 0xDDF: // 1 2 case 0xDDF: // 1 2
if (isModified(name)) { if (f != null && isModifiedSubtree_IndexWorkingtree(name)) {
conflict(name, dce, h, m); // 1 conflict(name, dce, h, m); // 1
} else { } else {
update(name, mId, mMode); // 2 update(name, mId, mMode); // 2
@ -647,32 +647,29 @@ void processEntry(CanonicalTreeParser h, CanonicalTreeParser m,
break; break;
case 0xFDF: // 7 8 9 case 0xFDF: // 7 8 9
if (equalIdAndMode(hId, hMode, mId, mMode)) { if (equalIdAndMode(hId, hMode, mId, mMode)) {
if (isModified(name)) if (isModifiedSubtree_IndexWorkingtree(name))
conflict(name, dce, h, m); // 8 conflict(name, dce, h, m); // 8
else else
update(name, mId, mMode); // 7 update(name, mId, mMode); // 7
} else if (!isModified(name)) } else
update(name, mId, mMode); // 9 conflict(name, dce, h, m); // 9
else
// To be confirmed - this case is not in the table.
conflict(name, dce, h, m);
break; break;
case 0xFD0: // keep without a rule case 0xFD0: // keep without a rule
keep(dce); keep(dce);
break; break;
case 0xFFD: // 12 13 14 case 0xFFD: // 12 13 14
if (equalIdAndMode(hId, hMode, iId, iMode)) if (equalIdAndMode(hId, hMode, iId, iMode))
if (f == null if (f != null
|| f.isModified(dce, true, && f.isModified(dce, true,
this.walk.getObjectReader())) this.walk.getObjectReader()))
conflict(name, dce, h, m); conflict(name, dce, h, m); // 13
else else
remove(name); remove(name); // 12
else else
conflict(name, dce, h, m); conflict(name, dce, h, m); // 14
break; break;
case 0x0DF: // 16 17 case 0x0DF: // 16 17
if (!isModified(name)) if (!isModifiedSubtree_IndexWorkingtree(name))
update(name, mId, mMode); update(name, mId, mMode);
else else
conflict(name, dce, h, m); conflict(name, dce, h, m);
@ -684,12 +681,14 @@ void processEntry(CanonicalTreeParser h, CanonicalTreeParser m,
} }
// if we have no file at all then there is nothing to do // if we have no file at all then there is nothing to do
if ((ffMask & 0x222) == 0) if ((ffMask & 0x222) == 0
&& (f == null || FileMode.TREE.equals(f.getEntryFileMode())))
return; return;
if ((ffMask == 0x00F) && f != null && FileMode.TREE.equals(f.getEntryFileMode())) { if ((ffMask == 0x00F) && f != null && FileMode.TREE.equals(f.getEntryFileMode())) {
// File/Directory conflict case #20 // File/Directory conflict case #20
conflict(name, null, h, m); conflict(name, null, h, m);
return;
} }
if (i == null) { if (i == null) {
@ -768,7 +767,9 @@ else if (m == null)
* </pre> * </pre>
*/ */
if (m == null || equalIdAndMode(mId, mMode, iId, iMode)) { if (m == null
|| !isModified_IndexTree(name, iId, iMode, mId, mMode,
mergeCommitTree)) {
// Merge contains nothing or the same as Index // Merge contains nothing or the same as Index
// Nothing in Head // Nothing in Head
// Something in Index // Something in Index
@ -824,7 +825,7 @@ else if (m == null)
* clean I==H I==M H M Result * clean I==H I==M H M Result
* ----------------------------------------------------- * -----------------------------------------------------
* 10 yes yes N/A exists nothing remove path from index * 10 yes yes N/A exists nothing remove path from index
* 11 no yes N/A exists nothing fail * 11 no yes N/A exists nothing keep file
* 12 yes no N/A exists nothing fail * 12 yes no N/A exists nothing fail
* 13 no no N/A exists nothing fail * 13 no no N/A exists nothing fail
* </pre> * </pre>
@ -841,23 +842,31 @@ else if (m == null)
// Something different from a submodule in Index // Something different from a submodule in Index
// Nothing in Merge // Nothing in Merge
// Something in Head // Something in Head
if (equalIdAndMode(hId, hMode, iId, iMode)) { if (!isModified_IndexTree(name, iId, iMode, hId, hMode,
headCommitTree)) {
// Index contains the same as Head // Index contains the same as Head
// Something different from a submodule in Index // Something different from a submodule in Index
// Nothing in Merge // Nothing in Merge
// Something in Head // Something in Head
if (f == null if (f != null
|| f.isModified(dce, true, && f.isModified(dce, true,
this.walk.getObjectReader())) this.walk.getObjectReader())) {
// file is dirty // file is dirty
// Index contains the same as Head // Index contains the same as Head
// Something different from a submodule in Index // Something different from a submodule in Index
// Nothing in Merge // Nothing in Merge
// Something in Head // Something in Head
// -> file is dirty but is should be removed. That's
// a conflict if (!FileMode.TREE.equals(f.getEntryFileMode())
conflict(name, dce, h, m); && FileMode.TREE.equals(iMode))
else // The workingtree contains a file and the index semantically contains a folder.
// Git considers the workingtree file as untracked. Just keep the untracked file.
return;
else
// -> file is dirty and tracked but is should be
// removed. That's a conflict
conflict(name, dce, h, m);
} else
// file doesn't exist or is clean // file doesn't exist or is clean
// Index contains the same as Head // Index contains the same as Head
// Something different from a submodule in Index // Something different from a submodule in Index
@ -880,8 +889,10 @@ else if (m == null)
// Something in Head // Something in Head
// Something in Index // Something in Index
if (!equalIdAndMode(hId, hMode, mId, mMode) if (!equalIdAndMode(hId, hMode, mId, mMode)
&& !equalIdAndMode(hId, hMode, iId, iMode) && isModified_IndexTree(name, iId, iMode, hId, hMode,
&& !equalIdAndMode(mId, mMode, iId, iMode)) headCommitTree)
&& isModified_IndexTree(name, iId, iMode, mId, mMode,
mergeCommitTree))
// All three contents in Head, Merge, Index differ from each // All three contents in Head, Merge, Index differ from each
// other // other
// -> All contents differ. Report a conflict. // -> All contents differ. Report a conflict.
@ -893,8 +904,10 @@ else if (m == null)
// Something in Head // Something in Head
// Something in Index // Something in Index
if (equalIdAndMode(hId, hMode, iId, iMode) if (!isModified_IndexTree(name, iId, iMode, hId, hMode,
&& !equalIdAndMode(mId, mMode, iId, iMode)) { headCommitTree)
&& isModified_IndexTree(name, iId, iMode, mId, mMode,
mergeCommitTree)) {
// Head contains the same as Index. Merge differs // Head contains the same as Index. Merge differs
// Something in Merge // Something in Merge
@ -1036,25 +1049,88 @@ private void cleanUpConflicts() throws CheckoutConflictException {
} }
} }
private boolean isModified(String path) throws CorruptObjectException, IOException { /**
* Checks whether the subtree starting at a given path differs between Index and
* workingtree.
*
* @param path
* @return true if the subtrees differ
* @throws CorruptObjectException
* @throws IOException
*/
private boolean isModifiedSubtree_IndexWorkingtree(String path)
throws CorruptObjectException, IOException {
NameConflictTreeWalk tw = new NameConflictTreeWalk(repo); NameConflictTreeWalk tw = new NameConflictTreeWalk(repo);
tw.addTree(new DirCacheIterator(dc)); try {
tw.addTree(new FileTreeIterator(repo)); tw.addTree(new DirCacheIterator(dc));
tw.setRecursive(true); tw.addTree(new FileTreeIterator(repo));
tw.setFilter(PathFilter.create(path)); tw.setRecursive(true);
DirCacheIterator dcIt; tw.setFilter(PathFilter.create(path));
WorkingTreeIterator wtIt; DirCacheIterator dcIt;
while(tw.next()) { WorkingTreeIterator wtIt;
dcIt = tw.getTree(0, DirCacheIterator.class); while (tw.next()) {
wtIt = tw.getTree(1, WorkingTreeIterator.class); dcIt = tw.getTree(0, DirCacheIterator.class);
if (dcIt == null || wtIt == null) wtIt = tw.getTree(1, WorkingTreeIterator.class);
return true; if (dcIt == null || wtIt == null)
if (wtIt.isModified(dcIt.getDirCacheEntry(), true, return true;
this.walk.getObjectReader())) { if (wtIt.isModified(dcIt.getDirCacheEntry(), true,
return true; this.walk.getObjectReader())) {
return true;
}
} }
return false;
} finally {
tw.release();
}
}
private boolean isModified_IndexTree(String path, ObjectId iId,
FileMode iMode, ObjectId tId, FileMode tMode, ObjectId rootTree)
throws CorruptObjectException, IOException {
if (iMode != tMode)
return true;
if (FileMode.TREE.equals(iMode)
&& (iId == null || ObjectId.zeroId().equals(iId)))
return isModifiedSubtree_IndexTree(path, rootTree);
else
return !equalIdAndMode(iId, iMode, tId, tMode);
}
/**
* Checks whether the subtree starting at a given path differs between Index and
* some tree.
*
* @param path
* @param tree
* the tree to compare
* @return true if the subtrees differ
* @throws CorruptObjectException
* @throws IOException
*/
private boolean isModifiedSubtree_IndexTree(String path, ObjectId tree)
throws CorruptObjectException, IOException {
NameConflictTreeWalk tw = new NameConflictTreeWalk(repo);
try {
tw.addTree(new DirCacheIterator(dc));
tw.addTree(tree);
tw.setRecursive(true);
tw.setFilter(PathFilter.create(path));
while (tw.next()) {
AbstractTreeIterator dcIt = tw.getTree(0,
DirCacheIterator.class);
AbstractTreeIterator treeIt = tw.getTree(1,
AbstractTreeIterator.class);
if (dcIt == null || treeIt == null)
return true;
if (dcIt.getEntryRawMode() != treeIt.getEntryRawMode())
return true;
if (!dcIt.getEntryObjectId().equals(treeIt.getEntryObjectId()))
return true;
}
return false;
} finally {
tw.release();
} }
return false;
} }
/** /**

View File

@ -832,6 +832,8 @@ public boolean isModified(DirCacheEntry entry, boolean forceContentCheck) {
*/ */
public boolean isModified(DirCacheEntry entry, boolean forceContentCheck, public boolean isModified(DirCacheEntry entry, boolean forceContentCheck,
ObjectReader reader) throws IOException { ObjectReader reader) throws IOException {
if (entry == null)
return !FileMode.MISSING.equals(getEntryFileMode());
MetadataDiff diff = compareMetadata(entry); MetadataDiff diff = compareMetadata(entry);
switch (diff) { switch (diff) {
case DIFFER_BY_TIMESTAMP: case DIFFER_BY_TIMESTAMP: