Browse Source

Make sure not to overwrite untracked not-ignored files

When DirCacheCheckout was checking out it was silently
overwriting untracked files. This is only ok if the
files are also ignored. Untracked and not ignored files
should not be overwritten. This fix adds checks for
this situation.
Because this change in the behaviour also broke tests
which expected that a checkout will overwrite untracked
files (PullCommandTest) these tests have to be modified
also.

Bug: 333093
Change-Id: I26806d2108ceb64c51abaa877e11b584bf527fc9
Signed-off-by: Christian Halstrick <christian.halstrick@sap.com>
Signed-off-by: Chris Aniszczyk <caniszczyk@gmail.com>
stable-0.11
Christian Halstrick 14 years ago committed by Chris Aniszczyk
parent
commit
0d7dd6625a
  1. 12
      org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PullCommandTest.java
  2. 29
      org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ReadTreeTest.java
  3. 27
      org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java

12
org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PullCommandTest.java

@ -56,10 +56,8 @@ import java.io.IOException;
import org.eclipse.jgit.api.CreateBranchCommand.SetupUpstreamMode; import org.eclipse.jgit.api.CreateBranchCommand.SetupUpstreamMode;
import org.eclipse.jgit.api.MergeResult.MergeStatus; import org.eclipse.jgit.api.MergeResult.MergeStatus;
import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.RefUpdate;
import org.eclipse.jgit.lib.RepositoryTestCase; import org.eclipse.jgit.lib.RepositoryTestCase;
import org.eclipse.jgit.lib.StoredConfig; import org.eclipse.jgit.lib.StoredConfig;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.storage.file.FileRepository; import org.eclipse.jgit.storage.file.FileRepository;
import org.eclipse.jgit.transport.RefSpec; import org.eclipse.jgit.transport.RefSpec;
import org.eclipse.jgit.transport.RemoteConfig; import org.eclipse.jgit.transport.RemoteConfig;
@ -190,13 +188,7 @@ public class PullCommandTest extends RepositoryTestCase {
writeToFile(sourceFile, "Hello world"); writeToFile(sourceFile, "Hello world");
// and commit it // and commit it
source.add().addFilepattern("SomeFile.txt").call(); source.add().addFilepattern("SomeFile.txt").call();
RevCommit commit = source.commit().setMessage( source.commit().setMessage("Initial commit for source").call();
"Initial commit for source").call();
// point the master branch to the new commit
RefUpdate upd = dbTarget.updateRef("refs/heads/master");
upd.setNewObjectId(commit.getId());
upd.update();
// configure the target repo to connect to the source via "origin" // configure the target repo to connect to the source via "origin"
StoredConfig targetConfig = dbTarget.getConfig(); StoredConfig targetConfig = dbTarget.getConfig();
@ -214,9 +206,9 @@ public class PullCommandTest extends RepositoryTestCase {
targetConfig.save(); targetConfig.save();
targetFile = new File(dbTarget.getWorkTree(), "SomeFile.txt"); targetFile = new File(dbTarget.getWorkTree(), "SomeFile.txt");
writeToFile(targetFile, "Hello world");
// make sure we have the same content // make sure we have the same content
target.pull().call(); target.pull().call();
assertFileContentsEqual(targetFile, "Hello world");
} }
private void writeToFile(File actFile, String string) throws IOException { private void writeToFile(File actFile, String string) throws IOException {

29
org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ReadTreeTest.java

@ -571,6 +571,34 @@ public abstract class ReadTreeTest extends RepositoryTestCase {
writeTrashFile("foo", "foo"); writeTrashFile("foo", "foo");
go(); go();
// test that we don't overwrite untracked files when there is a HEAD
recursiveDelete(new File(trash, "foo"));
setupCase(mk("other"), mkmap("other", "other", "foo", "foo"),
mk("other"));
writeTrashFile("foo", "bar");
try {
checkout();
fail("didn't get the expected exception");
} catch (CheckoutConflictException e) {
assertConflict("foo");
assertWorkDir(mkmap("foo", "bar", "other", "other"));
assertIndex(mk("other"));
}
// test that we don't overwrite untracked files when there is no HEAD
recursiveDelete(new File(trash, "other"));
recursiveDelete(new File(trash, "foo"));
setupCase(null, mk("foo"), null);
writeTrashFile("foo", "bar");
try {
checkout();
fail("didn't get the expected exception");
} catch (CheckoutConflictException e) {
assertConflict("foo");
assertWorkDir(mkmap("foo", "bar"));
assertIndex(mkmap());
}
// TODO: Why should we expect conflicts here? // TODO: Why should we expect conflicts here?
// H and M are emtpy and according to rule #5 of // H and M are emtpy and according to rule #5 of
// the carry-over rules a dirty index is no reason // the carry-over rules a dirty index is no reason
@ -581,6 +609,7 @@ public abstract class ReadTreeTest extends RepositoryTestCase {
// assertConflict("foo"); // assertConflict("foo");
recursiveDelete(new File(trash, "foo")); recursiveDelete(new File(trash, "foo"));
recursiveDelete(new File(trash, "other"));
setupCase(null, mk("foo"), null); setupCase(null, mk("foo"), null);
writeTrashFile("foo/bar/baz", ""); writeTrashFile("foo/bar/baz", "");
writeTrashFile("foo/blahblah", ""); writeTrashFile("foo/blahblah", "");

27
org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java vendored

@ -300,15 +300,21 @@ public class DirCacheCheckout {
* @param m the tree to merge * @param m the tree to merge
* @param i the index * @param i the index
* @param f the working tree * @param f the working tree
* @throws IOException
*/ */
void processEntry(CanonicalTreeParser m, DirCacheBuildIterator i, void processEntry(CanonicalTreeParser m, DirCacheBuildIterator i,
WorkingTreeIterator f) { WorkingTreeIterator f) throws IOException {
if (m != null) { if (m != null) {
// There is an entry in the merge commit. Means: we want to update // There is an entry in the merge commit. Means: we want to update
// what's currently in the index and working-tree to that one // what's currently in the index and working-tree to that one
if (i == null) { if (i == null) {
// The index entry is missing // The index entry is missing
update(m.getEntryPathString(), m.getEntryObjectId(), if (f != null && !FileMode.TREE.equals(f.getEntryFileMode())
&& !f.isEntryIgnored()) {
// don't overwrite an untracked and not ignored file
conflicts.add(walk.getPathString());
} else
update(m.getEntryPathString(), m.getEntryObjectId(),
m.getEntryFileMode()); m.getEntryFileMode());
} else if (f == null || !m.idEqual(i)) { } else if (f == null || !m.idEqual(i)) {
// The working tree file is missing or the merge content differs // The working tree file is missing or the merge content differs
@ -344,6 +350,13 @@ public class DirCacheCheckout {
// conflicts set // conflicts set
remove(i.getEntryPathString()); remove(i.getEntryPathString());
conflicts.remove(i.getEntryPathString()); conflicts.remove(i.getEntryPathString());
} else {
// We are about to remove an untracked file. Check that
// it is ignored - otherwise that's an conflict
if (!f.isEntryIgnored())
conflicts.add(walk.getPathString());
else
remove(f.getEntryPathString());
} }
} }
} else { } else {
@ -626,6 +639,16 @@ public class DirCacheCheckout {
} }
if (i == null) { if (i == null) {
// make sure not to overwrite untracked files
if (f != null) {
// a dirty worktree: the index is empty but we have a
// workingtree-file
if (mId == null || !mId.equals(f.getEntryObjectId())) {
conflict(name, null, h, m);
return;
}
}
/** /**
* <pre> * <pre>
* I (index) H M Result * I (index) H M Result

Loading…
Cancel
Save