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;
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;
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 {
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 {
// 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");
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
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")
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());
}
/**
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;
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
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
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);
* @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 {