]> source.dussan.org Git - jgit.git/commitdiff
Add reset with paths support to ResetCommand 53/3453/3
authorBernard Leach <leachbj@bouncycastle.org>
Thu, 19 May 2011 11:04:20 +0000 (21:04 +1000)
committerChris Aniszczyk <caniszczyk@gmail.com>
Thu, 19 May 2011 14:04:09 +0000 (09:04 -0500)
Bug: 338701
Change-Id: Id7cbce47131b459e632ddc2c9a94628c7d0b75cd
Signed-off-by: Chris Aniszczyk <caniszczyk@gmail.com>
org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ResetCommandTest.java
org.eclipse.jgit/src/org/eclipse/jgit/api/ResetCommand.java

index 578b98170f2b5c52da8ea0dcffbb4e377714b008..f79592f2237851d0fb87c52ec7fdbfbb6dcbf134 100644 (file)
@@ -44,6 +44,7 @@ package org.eclipse.jgit.api;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 
 import java.io.File;
@@ -58,6 +59,7 @@ import org.eclipse.jgit.api.errors.NoHeadException;
 import org.eclipse.jgit.api.errors.NoMessageException;
 import org.eclipse.jgit.api.errors.WrongRepositoryStateException;
 import org.eclipse.jgit.dircache.DirCache;
+import org.eclipse.jgit.dircache.DirCacheEntry;
 import org.eclipse.jgit.errors.AmbiguousObjectException;
 import org.eclipse.jgit.lib.Constants;
 import org.eclipse.jgit.lib.ObjectId;
@@ -66,6 +68,7 @@ import org.eclipse.jgit.revwalk.RevCommit;
 import org.eclipse.jgit.revwalk.RevWalk;
 import org.eclipse.jgit.treewalk.TreeWalk;
 import org.eclipse.jgit.util.FileUtils;
+import org.junit.Assert;
 import org.junit.Test;
 
 public class ResetCommandTest extends RepositoryTestCase {
@@ -74,10 +77,14 @@ public class ResetCommandTest extends RepositoryTestCase {
 
        private RevCommit initialCommit;
 
+       private RevCommit secondCommit;
+
        private File indexFile;
 
        private File untrackedFile;
 
+       private DirCacheEntry prestage;
+
        public void setupRepository() throws IOException, NoFilepatternException,
                        NoHeadException, NoMessageException, ConcurrentRefUpdateException,
                        JGitInternalException, WrongRepositoryStateException {
@@ -95,7 +102,10 @@ public class ResetCommandTest extends RepositoryTestCase {
 
                // add file and commit it
                git.add().addFilepattern("a.txt").call();
-               git.commit().setMessage("adding a.txt").call();
+               secondCommit = git.commit().setMessage("adding a.txt").call();
+
+               prestage = DirCache.read(db.getIndexFile(), db.getFS()).getEntry(
+                               indexFile.getName());
 
                // modify file and add to index
                writer.print("new content");
@@ -178,6 +188,66 @@ public class ResetCommandTest extends RepositoryTestCase {
                assertReflog(prevHead, head);
        }
 
+       @Test
+       public void testPathsReset() throws Exception {
+               setupRepository();
+
+               DirCacheEntry preReset = DirCache.read(db.getIndexFile(), db.getFS())
+                               .getEntry(indexFile.getName());
+               assertNotNull(preReset);
+
+               git.add().addFilepattern(untrackedFile.getName()).call();
+
+               // 'a.txt' has already been modified in setupRepository
+               // 'notAddedToIndex.txt' has been added to repository
+               git.reset().addPath(indexFile.getName())
+                               .addPath(untrackedFile.getName()).call();
+
+               DirCacheEntry postReset = DirCache.read(db.getIndexFile(), db.getFS())
+                               .getEntry(indexFile.getName());
+               assertNotNull(postReset);
+               Assert.assertNotSame(preReset.getObjectId(), postReset.getObjectId());
+               Assert.assertEquals(prestage.getObjectId(), postReset.getObjectId());
+
+               // check that HEAD hasn't moved
+               ObjectId head = db.resolve(Constants.HEAD);
+               assertTrue(head.equals(secondCommit));
+               // check if files still exist
+               assertTrue(untrackedFile.exists());
+               assertTrue(indexFile.exists());
+               assertTrue(inHead(indexFile.getName()));
+               assertTrue(inIndex(indexFile.getName()));
+               assertFalse(inIndex(untrackedFile.getName()));
+       }
+
+       @Test
+       public void testPathsResetWithRef() throws Exception {
+               setupRepository();
+
+               DirCacheEntry preReset = DirCache.read(db.getIndexFile(), db.getFS())
+                               .getEntry(indexFile.getName());
+               assertNotNull(preReset);
+
+               git.add().addFilepattern(untrackedFile.getName()).call();
+
+               // 'a.txt' has already been modified in setupRepository
+               // 'notAddedToIndex.txt' has been added to repository
+               // reset to the inital commit
+               git.reset().setRef(initialCommit.getName())
+                               .addPath(indexFile.getName())
+                               .addPath(untrackedFile.getName()).call();
+
+               // check that HEAD hasn't moved
+               ObjectId head = db.resolve(Constants.HEAD);
+               assertTrue(head.equals(secondCommit));
+               // check if files still exist
+               assertTrue(untrackedFile.exists());
+               assertTrue(indexFile.exists());
+               assertTrue(inHead(indexFile.getName()));
+               assertFalse(inIndex(indexFile.getName()));
+               assertFalse(inIndex(untrackedFile.getName()));
+       }
+
        private void assertReflog(ObjectId prevHead, ObjectId head)
                        throws IOException {
                // Check the reflog for HEAD
@@ -187,9 +257,8 @@ public class ResetCommandTest extends RepositoryTestCase {
                assertEquals(expectedHeadMessage, actualHeadMessage);
                assertEquals(head.getName(), db.getReflogReader(Constants.HEAD)
                                .getLastEntry().getNewId().getName());
-               assertEquals(prevHead.getName(), db
-                               .getReflogReader(Constants.HEAD).getLastEntry().getOldId()
-                               .getName());
+               assertEquals(prevHead.getName(), db.getReflogReader(Constants.HEAD)
+                               .getLastEntry().getOldId().getName());
 
                // The reflog for master contains the same as the one for HEAD
                String actualMasterMessage = db.getReflogReader("refs/heads/master")
@@ -198,9 +267,9 @@ public class ResetCommandTest extends RepositoryTestCase {
                assertEquals(expectedMasterMessage, actualMasterMessage);
                assertEquals(head.getName(), db.getReflogReader(Constants.HEAD)
                                .getLastEntry().getNewId().getName());
-               assertEquals(prevHead.getName(),
-                               db.getReflogReader("refs/heads/master").getLastEntry()
-                                               .getOldId().getName());
+               assertEquals(prevHead.getName(), db
+                               .getReflogReader("refs/heads/master").getLastEntry().getOldId()
+                               .getName());
        }
 
        /**
index 1ddfd6d77a2d7456c839454003f16aadd6570e7a..206d4062b7d8493479bdd142a9ab584887a73087 100644 (file)
@@ -44,12 +44,17 @@ package org.eclipse.jgit.api;
 
 import java.io.IOException;
 import java.text.MessageFormat;
+import java.util.Collection;
+import java.util.LinkedList;
 
 import org.eclipse.jgit.JGitText;
 import org.eclipse.jgit.api.errors.JGitInternalException;
 import org.eclipse.jgit.dircache.DirCache;
 import org.eclipse.jgit.dircache.DirCacheBuilder;
 import org.eclipse.jgit.dircache.DirCacheCheckout;
+import org.eclipse.jgit.dircache.DirCacheEditor;
+import org.eclipse.jgit.dircache.DirCacheEntry;
+import org.eclipse.jgit.dircache.DirCacheIterator;
 import org.eclipse.jgit.lib.Constants;
 import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.lib.Ref;
@@ -58,6 +63,9 @@ import org.eclipse.jgit.lib.Repository;
 import org.eclipse.jgit.lib.RepositoryState;
 import org.eclipse.jgit.revwalk.RevCommit;
 import org.eclipse.jgit.revwalk.RevWalk;
+import org.eclipse.jgit.treewalk.CanonicalTreeParser;
+import org.eclipse.jgit.treewalk.TreeWalk;
+import org.eclipse.jgit.treewalk.filter.PathFilterGroup;
 
 /**
  * A class used to execute a {@code Reset} command. It has setters for all
@@ -103,10 +111,12 @@ public class ResetCommand extends GitCommand<Ref> {
                KEEP // TODO not implemented yet
        }
 
-       private String ref;
+       private String ref = Constants.HEAD;
 
        private ResetType mode;
 
+       private Collection<String> filepaths = new LinkedList<String>();
+
        /**
         *
         * @param repo
@@ -157,6 +167,13 @@ public class ResetCommand extends GitCommand<Ref> {
                                rw.release();
                        }
 
+                       if (!filepaths.isEmpty()) {
+                               // reset [commit] -- paths
+                               resetIndexForPaths(commit);
+                               setCallable(false);
+                               return repo.getRef(Constants.HEAD);
+                       }
+
                        // write the ref
                        final RefUpdate ru = repo.updateRef(Constants.HEAD);
                        ru.setNewObjectId(commitId);
@@ -217,10 +234,70 @@ public class ResetCommand extends GitCommand<Ref> {
         * @return this instance
         */
        public ResetCommand setMode(ResetType mode) {
+               if (!filepaths.isEmpty())
+                       throw new JGitInternalException(MessageFormat.format(
+                                       JGitText.get().illegalCombinationOfArguments,
+                                       "[--mixed | --soft | --hard]", "<paths>..."));
                this.mode = mode;
                return this;
        }
 
+       /**
+        * @param file
+        *            the file to add
+        * @return this instance
+        */
+       public ResetCommand addPath(String file) {
+               if (mode != null)
+                       throw new JGitInternalException(MessageFormat.format(
+                                       JGitText.get().illegalCombinationOfArguments, "<paths>...",
+                                       "[--mixed | --soft | --hard]"));
+               filepaths.add(file);
+               return this;
+       }
+
+       private void resetIndexForPaths(RevCommit commit) {
+               DirCache dc = null;
+               final DirCacheEditor edit;
+               try {
+                       dc = repo.lockDirCache();
+                       edit = dc.editor();
+
+                       final TreeWalk tw = new TreeWalk(repo);
+                       tw.addTree(new DirCacheIterator(dc));
+                       tw.addTree(commit.getTree());
+                       tw.setFilter(PathFilterGroup.createFromStrings(filepaths));
+
+                       while (tw.next()) {
+                               final String path = tw.getPathString();
+                               // DirCacheIterator dci = tw.getTree(0, DirCacheIterator.class);
+                               final CanonicalTreeParser tree = tw.getTree(1,
+                                               CanonicalTreeParser.class);
+                               if (tree == null)
+                                       // file is not in the commit, remove from index
+                                       edit.add(new DirCacheEditor.DeletePath(path));
+                               else {
+                                       // revert index to commit
+                                       edit.add(new DirCacheEditor.PathEdit(path) {
+                                               @Override
+                                               public void apply(DirCacheEntry ent) {
+                                                       ent.setFileMode(tree.getEntryFileMode());
+                                                       ent.setObjectId(tree.getEntryObjectId());
+                                                       ent.setLastModified(0);
+                                               }
+                                       });
+                               }
+                       }
+
+                       edit.commit();
+               } catch (IOException e) {
+                       throw new RuntimeException(e);
+               } finally {
+                       if (dc != null)
+                               dc.unlock();
+               }
+       }
+
        private void resetIndex(RevCommit commit) throws IOException {
                DirCache dc = null;
                try {