From cf9b01b09a320de4afb8da8f2ec5002fd0441831 Mon Sep 17 00:00:00 2001 From: Christian Halstrick Date: Wed, 23 Jul 2014 15:30:06 +0200 Subject: [PATCH] Handle initial checkout correctly As described in native gits file "git-read-tree.txt" git has in a special mode when doing the "initial" checkout. "Initial" means that the index is empty before the checkout. This was not handled correctly in JGit and is fixed in this commit. Also see https://github.com/git/git/blob/master/Documentation/git-read-tree.txt#L181 Change-Id: I9b9d1bd9ebf349cfca420c891c7b099a18d07ba4 --- .../jgit/lib/DirCacheCheckoutTest.java | 19 +++++++++++++++++++ .../jgit/dircache/DirCacheCheckout.java | 15 +++++++++++---- 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/DirCacheCheckoutTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/DirCacheCheckoutTest.java index afbad6ab2..f7e6fa9b7 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/DirCacheCheckoutTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/DirCacheCheckoutTest.java @@ -72,6 +72,8 @@ import org.eclipse.jgit.errors.CorruptObjectException; import org.eclipse.jgit.errors.NoWorkTreeException; import org.eclipse.jgit.junit.RepositoryTestCase; +import org.eclipse.jgit.junit.TestRepository; +import org.eclipse.jgit.junit.TestRepository.BranchBuilder; import org.eclipse.jgit.revwalk.RevCommit; import org.eclipse.jgit.treewalk.FileTreeIterator; import org.eclipse.jgit.treewalk.TreeWalk; @@ -213,6 +215,23 @@ public void testResetHardFromIndexEntryWithoutFileToTreeWithoutFile() assertIndex(mkmap("x", "x")); } + /** + * Test first checkout in a repo + * + * @throws Exception + */ + @Test + public void testInitialCheckout() throws Exception { + Git git = new Git(db); + + TestRepository db_t = new TestRepository(db); + BranchBuilder master = db_t.branch("master"); + master.commit().add("f", "1").message("m0").create(); + assertFalse(new File(db.getWorkTree(), "f").exists()); + git.checkout().setName("master").call(); + assertTrue(new File(db.getWorkTree(), "f").exists()); + } + private DirCacheCheckout resetHard(RevCommit commit) throws NoWorkTreeException, CorruptObjectException, IOException { 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 80dda8eb8..4b0d58600 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java @@ -110,6 +110,8 @@ public class DirCacheCheckout { private ArrayList toBeDeleted = new ArrayList(); + private boolean emptyDirCache; + /** * @return a list of updated paths and objectIds */ @@ -168,6 +170,7 @@ public DirCacheCheckout(Repository repo, ObjectId headCommitTree, DirCache dc, this.headCommitTree = headCommitTree; this.mergeCommitTree = mergeCommitTree; this.workingTree = workingTree; + this.emptyDirCache = (dc == null) || (dc.getEntryCount() == 0); } /** @@ -716,7 +719,8 @@ void processEntry(CanonicalTreeParser h, CanonicalTreeParser m, * 0 nothing nothing nothing (does not happen) * 1 nothing nothing exists use M * 2 nothing exists nothing remove path from index - * 3 nothing exists exists yes keep index + * 3 nothing exists exists yes keep index if not in initial checkout + * , otherwise use M * nothing exists exists no fail * */ @@ -743,9 +747,12 @@ else if (m == null) // in the index there is nothing (e.g. 'git rm ...' was // called before). Ignore the cached deletion and use what we // find in Merge. Potentially updates the file. - if (equalIdAndMode(hId, hMode, mId, mMode)) - keep(dce); - else + if (equalIdAndMode(hId, hMode, mId, mMode)) { + if (emptyDirCache) + update(name, mId, mMode); + else + keep(dce); + } else conflict(name, dce, h, m); } } else {