Before this commit, a force checkout would fail if there were any conflicting files. After this commit, a force checkout will overwrite the conflicting files, as expected. Making this work required fixing a bug in DirCacheCheckout. Before this commit, when DirCacheCheckout had failOnConflict=false, it would delete all conflicting files from the working copy and just leave them missing. After this commit, DirCacheCheckout overwrites conflicting files with the merge tree. This change in DirCacheCheckout causes "reset --hard" and "revert --abort" to behave as expected (previously they would simply delete conflicting files, now they will be overwritten from the merge tree). Change-Id: If7e328ee792ef6511ab7d9c26d8d77c39210ec9f Signed-off-by: Ned Twigg <ned.twigg@diffplug.com>tags/v5.2.0.201811281532-m3
@@ -154,7 +154,7 @@ public class CheckoutCommandTest extends RepositoryTestCase { | |||
} | |||
@Test | |||
public void testCheckoutWithConflict() { | |||
public void testCheckoutWithConflict() throws Exception { | |||
CheckoutCommand co = git.checkout(); | |||
try { | |||
writeTrashFile("Test.txt", "Another change"); | |||
@@ -165,6 +165,8 @@ public class CheckoutCommandTest extends RepositoryTestCase { | |||
assertEquals(Status.CONFLICTS, co.getResult().getStatus()); | |||
assertTrue(co.getResult().getConflictList().contains("Test.txt")); | |||
} | |||
git.checkout().setName("master").setForce(true).call(); | |||
assertThat(read("Test.txt"), is("Hello world")); | |||
} | |||
@Test |
@@ -269,7 +269,7 @@ public class CheckoutCommand extends GitCommand<Ref> { | |||
try { | |||
dco = new DirCacheCheckout(repo, headTree, dc, | |||
newCommit.getTree()); | |||
dco.setFailOnConflict(true); | |||
dco.setFailOnConflict(!force); | |||
dco.setProgressMonitor(monitor); | |||
try { | |||
dco.checkout(); |
@@ -522,7 +522,7 @@ public class DirCacheCheckout { | |||
builder.finish(); | |||
// init progress reporting | |||
int numTotal = removed.size() + updated.size(); | |||
int numTotal = removed.size() + updated.size() + conflicts.size(); | |||
monitor.beginTask(JGitText.get().checkingOutFiles, numTotal); | |||
performingCheckout = true; | |||
@@ -597,6 +597,33 @@ public class DirCacheCheckout { | |||
} | |||
throw ex; | |||
} | |||
for (String conflict : conflicts) { | |||
// the conflicts are likely to have multiple entries in the | |||
// dircache, we only want to check out the one for the "theirs" | |||
// tree | |||
int entryIdx = dc.findEntry(conflict); | |||
if (entryIdx >= 0) { | |||
while (entryIdx < dc.getEntryCount()) { | |||
DirCacheEntry entry = dc.getEntry(entryIdx); | |||
if (!entry.getPathString().equals(conflict)) { | |||
break; | |||
} | |||
if (entry.getStage() == DirCacheEntry.STAGE_3) { | |||
checkoutEntry(repo, entry, objectReader, false, | |||
null); | |||
break; | |||
} | |||
++entryIdx; | |||
} | |||
} | |||
monitor.update(1); | |||
if (monitor.isCancelled()) { | |||
throw new CanceledException(MessageFormat.format( | |||
JGitText.get().operationCanceled, | |||
JGitText.get().checkingOutFiles)); | |||
} | |||
} | |||
monitor.endTask(); | |||
// commit the index builder - a new index is persisted |