diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitCommandTest.java index 3e73c7598..45f312f38 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitCommandTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitCommandTest.java @@ -55,6 +55,8 @@ import java.util.TimeZone; import org.eclipse.jgit.api.errors.WrongRepositoryStateException; import org.eclipse.jgit.diff.DiffEntry; import org.eclipse.jgit.dircache.DirCache; +import org.eclipse.jgit.dircache.DirCacheBuilder; +import org.eclipse.jgit.dircache.DirCacheEntry; import org.eclipse.jgit.lib.ConfigConstants; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.FileMode; @@ -471,4 +473,56 @@ public class CommitCommandTest extends RepositoryTestCase { assertEquals("New Author", amendedAuthor.getName()); assertEquals("newauthor@example.org", amendedAuthor.getEmailAddress()); } + + @Test + public void commitOnlyShouldCommitUnmergedPathAndNotAffectOthers() + throws Exception { + DirCache index = db.lockDirCache(); + DirCacheBuilder builder = index.builder(); + addUnmergedEntry("unmerged1", builder); + addUnmergedEntry("unmerged2", builder); + DirCacheEntry other = new DirCacheEntry("other"); + other.setFileMode(FileMode.REGULAR_FILE); + builder.add(other); + builder.commit(); + + writeTrashFile("unmerged1", "unmerged1 data"); + writeTrashFile("unmerged2", "unmerged2 data"); + writeTrashFile("other", "other data"); + + assertEquals("[other, mode:100644]" + + "[unmerged1, mode:100644, stage:1]" + + "[unmerged1, mode:100644, stage:2]" + + "[unmerged1, mode:100644, stage:3]" + + "[unmerged2, mode:100644, stage:1]" + + "[unmerged2, mode:100644, stage:2]" + + "[unmerged2, mode:100644, stage:3]", + indexState(0)); + + Git git = new Git(db); + RevCommit commit = git.commit().setOnly("unmerged1") + .setMessage("Only one file").call(); + + assertEquals("[other, mode:100644]" + "[unmerged1, mode:100644]" + + "[unmerged2, mode:100644, stage:1]" + + "[unmerged2, mode:100644, stage:2]" + + "[unmerged2, mode:100644, stage:3]", + indexState(0)); + + TreeWalk walk = TreeWalk.forPath(db, "unmerged1", commit.getTree()); + assertEquals(FileMode.REGULAR_FILE, walk.getFileMode(0)); + walk.release(); + } + + private static void addUnmergedEntry(String file, DirCacheBuilder builder) { + DirCacheEntry stage1 = new DirCacheEntry(file, DirCacheEntry.STAGE_1); + DirCacheEntry stage2 = new DirCacheEntry(file, DirCacheEntry.STAGE_2); + DirCacheEntry stage3 = new DirCacheEntry(file, DirCacheEntry.STAGE_3); + stage1.setFileMode(FileMode.REGULAR_FILE); + stage2.setFileMode(FileMode.REGULAR_FILE); + stage3.setFileMode(FileMode.REGULAR_FILE); + builder.add(stage1); + builder.add(stage2); + builder.add(stage3); + } } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/CommitCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/CommitCommand.java index ee9208317..eab2e8d4b 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/CommitCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/CommitCommand.java @@ -58,10 +58,8 @@ import org.eclipse.jgit.api.errors.NoMessageException; import org.eclipse.jgit.api.errors.UnmergedPathsException; import org.eclipse.jgit.api.errors.WrongRepositoryStateException; import org.eclipse.jgit.dircache.DirCache; +import org.eclipse.jgit.dircache.DirCacheBuildIterator; import org.eclipse.jgit.dircache.DirCacheBuilder; -import org.eclipse.jgit.dircache.DirCacheEditor; -import org.eclipse.jgit.dircache.DirCacheEditor.DeletePath; -import org.eclipse.jgit.dircache.DirCacheEditor.PathEdit; import org.eclipse.jgit.dircache.DirCacheEntry; import org.eclipse.jgit.dircache.DirCacheIterator; import org.eclipse.jgit.errors.UnmergedPathException; @@ -298,25 +296,26 @@ public class CommitCommand extends GitCommand { throws IOException { ObjectInserter inserter = null; - // get DirCacheEditor to modify the index if required - DirCacheEditor dcEditor = index.editor(); + // get DirCacheBuilder for existing index + DirCacheBuilder existingBuilder = index.builder(); // get DirCacheBuilder for newly created in-core index to build a // temporary index for this commit DirCache inCoreIndex = DirCache.newInCore(); - DirCacheBuilder dcBuilder = inCoreIndex.builder(); + DirCacheBuilder tempBuilder = inCoreIndex.builder(); onlyProcessed = new boolean[only.size()]; boolean emptyCommit = true; TreeWalk treeWalk = new TreeWalk(repo); - int dcIdx = treeWalk.addTree(new DirCacheIterator(index)); + int dcIdx = treeWalk.addTree(new DirCacheBuildIterator(existingBuilder)); int fIdx = treeWalk.addTree(new FileTreeIterator(repo)); int hIdx = -1; if (headId != null) hIdx = treeWalk.addTree(new RevWalk(repo).parseTree(headId)); treeWalk.setRecursive(true); + String lastAddedFile = null; while (treeWalk.next()) { String path = treeWalk.getPathString(); // check if current entry's path matches a specified path @@ -326,11 +325,12 @@ public class CommitCommand extends GitCommand { if (hIdx != -1) hTree = treeWalk.getTree(hIdx, CanonicalTreeParser.class); + DirCacheIterator dcTree = treeWalk.getTree(dcIdx, + DirCacheIterator.class); + if (pos >= 0) { // include entry in commit - DirCacheIterator dcTree = treeWalk.getTree(dcIdx, - DirCacheIterator.class); FileTreeIterator fTree = treeWalk.getTree(fIdx, FileTreeIterator.class); @@ -339,6 +339,13 @@ public class CommitCommand extends GitCommand { if (!tracked) break; + // for an unmerged path, DirCacheBuildIterator will yield 3 + // entries, we only want to add one + if (path.equals(lastAddedFile)) + continue; + + lastAddedFile = path; + if (fTree != null) { // create a new DirCacheEntry with data retrieved from disk final DirCacheEntry dcEntry = new DirCacheEntry(path); @@ -371,15 +378,10 @@ public class CommitCommand extends GitCommand { } } - // update index - dcEditor.add(new PathEdit(path) { - @Override - public void apply(DirCacheEntry ent) { - ent.copyMetaData(dcEntry); - } - }); + // add to existing index + existingBuilder.add(dcEntry); // add to temporary in-core index - dcBuilder.add(dcEntry); + tempBuilder.add(dcEntry); if (emptyCommit && (hTree == null || !hTree.idEqual(fTree) || hTree @@ -388,9 +390,8 @@ public class CommitCommand extends GitCommand { // this is a change emptyCommit = false; } else { - // if no file exists on disk, remove entry from index and - // don't add it to temporary in-core index - dcEditor.add(new DeletePath(path)); + // if no file exists on disk, neither add it to + // index nor to temporary in-core index if (emptyCommit && hTree != null) // this is a change @@ -408,8 +409,12 @@ public class CommitCommand extends GitCommand { dcEntry.setFileMode(hTree.getEntryFileMode()); // add to temporary in-core index - dcBuilder.add(dcEntry); + tempBuilder.add(dcEntry); } + + // preserve existing entry in index + if (dcTree != null) + existingBuilder.add(dcTree.getDirCacheEntry()); } } @@ -425,9 +430,9 @@ public class CommitCommand extends GitCommand { throw new JGitInternalException(JGitText.get().emptyCommit); // update index - dcEditor.commit(); + existingBuilder.commit(); // finish temporary in-core index used for this commit - dcBuilder.finish(); + tempBuilder.finish(); return inCoreIndex; }