From 0afd62efa868791895eb1f563bb08f6511fe9a79 Mon Sep 17 00:00:00 2001 From: Christian Halstrick Date: Fri, 9 Oct 2015 16:14:10 +0200 Subject: [PATCH] Make sure to overwrite files when "reset --hard" detects conflicts When performing a "reset --hard" a checkout is done. The pathes are checked for potential checkout conflicts. But in the end for all remaining conflicts these files are simply deleted from the working tree. That's not the right strategy to handle checkout conflicts during "reset --hard". Instead for every conflict we should simply checkout the merge commit's content. This is different from native gits behavior which reports errors when during a "checkout --hard" a file shows up where a folder was expected. "warning: unable to unlink d/c.txt: Not a directory" Why it is like that in native git was asked in http://permalink.gmane.org/gmane.comp.version-control.git/279482. Unless it is explained why native git why this error is reported JGit should overwrite the files. Bug: 474842 Change-Id: I08e23822a577aaf22120c5137eb169b6bd08447b Signed-off-by: Matthias Sohn --- .../eclipse/jgit/api/ResetCommandTest.java | 28 +++++++++++++++++++ .../jgit/dircache/DirCacheCheckout.java | 15 ++++++++-- 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ResetCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ResetCommandTest.java index 40d8458ef..725ebc0d2 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ResetCommandTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ResetCommandTest.java @@ -156,6 +156,34 @@ public void testHardReset() throws JGitInternalException, assertEquals(prevHead, db.readOrigHead()); } + @Test + public void testHardResetWithConflicts_DoOverWriteUntrackedFile() + throws JGitInternalException, + AmbiguousObjectException, IOException, GitAPIException { + setupRepository(); + git.rm().setCached(true).addFilepattern("a.txt").call(); + assertTrue(new File(db.getWorkTree(), "a.txt").exists()); + git.reset().setMode(ResetType.HARD).setRef(Constants.HEAD) + .call(); + assertTrue(new File(db.getWorkTree(), "a.txt").exists()); + assertEquals("content", read(new File(db.getWorkTree(), "a.txt"))); + } + + @Test + public void testHardResetWithConflicts_DoDeleteFileFolderConflicts() + throws JGitInternalException, + AmbiguousObjectException, IOException, GitAPIException { + setupRepository(); + writeTrashFile("d/c.txt", "x"); + git.add().addFilepattern("d/c.txt").call(); + FileUtils.delete(new File(db.getWorkTree(), "d"), FileUtils.RECURSIVE); + writeTrashFile("d", "y"); + + git.reset().setMode(ResetType.HARD).setRef(Constants.HEAD) + .call(); + assertFalse(new File(db.getWorkTree(), "d").exists()); + } + @Test public void testResetToNonexistingHEAD() throws JGitInternalException, AmbiguousObjectException, IOException, GitAPIException { diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java index fc4cc9093..12ceb74ab 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java @@ -354,8 +354,16 @@ void processEntry(CanonicalTreeParser m, DirCacheBuildIterator i, // The index entry is missing if (f != null && !FileMode.TREE.equals(f.getEntryFileMode()) && !f.isEntryIgnored()) { - // don't overwrite an untracked and not ignored file - conflicts.add(walk.getPathString()); + if (failOnConflict) { + // don't overwrite an untracked and not ignored file + conflicts.add(walk.getPathString()); + } else { + // failOnConflict is false. Putting something to conflicts + // would mean we delete it. Instead we want the mergeCommit + // content to be checked out. + update(m.getEntryPathString(), m.getEntryObjectId(), + m.getEntryFileMode()); + } } else update(m.getEntryPathString(), m.getEntryObjectId(), m.getEntryFileMode()); @@ -390,6 +398,9 @@ void processEntry(CanonicalTreeParser m, DirCacheBuildIterator i, if (f != null) { // There is a file/folder for that path in the working tree if (walk.isDirectoryFileConflict()) { + // We put it in conflicts. Even if failOnConflict is false + // this would cause the path to be deleted. Thats exactly what + // we want in this situation conflicts.add(walk.getPathString()); } else { // No file/folder conflict exists. All entries are files or