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:
parent
f7ac527ca7
commit
1a9f122773
|
@ -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)",
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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");
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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:
|
||||||
|
|
Loading…
Reference in New Issue