Browse Source

Add reset with paths support to ResetCommand

Bug: 338701
Change-Id: Id7cbce47131b459e632ddc2c9a94628c7d0b75cd
Signed-off-by: Chris Aniszczyk <caniszczyk@gmail.com>
stable-1.0
Bernard Leach 14 years ago committed by Chris Aniszczyk
parent
commit
37fe0988b2
  1. 83
      org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ResetCommandTest.java
  2. 79
      org.eclipse.jgit/src/org/eclipse/jgit/api/ResetCommand.java

83
org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ResetCommandTest.java

@ -44,6 +44,7 @@ package org.eclipse.jgit.api;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import java.io.File; 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.NoMessageException;
import org.eclipse.jgit.api.errors.WrongRepositoryStateException; import org.eclipse.jgit.api.errors.WrongRepositoryStateException;
import org.eclipse.jgit.dircache.DirCache; import org.eclipse.jgit.dircache.DirCache;
import org.eclipse.jgit.dircache.DirCacheEntry;
import org.eclipse.jgit.errors.AmbiguousObjectException; import org.eclipse.jgit.errors.AmbiguousObjectException;
import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.ObjectId; 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.revwalk.RevWalk;
import org.eclipse.jgit.treewalk.TreeWalk; import org.eclipse.jgit.treewalk.TreeWalk;
import org.eclipse.jgit.util.FileUtils; import org.eclipse.jgit.util.FileUtils;
import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
public class ResetCommandTest extends RepositoryTestCase { public class ResetCommandTest extends RepositoryTestCase {
@ -74,10 +77,14 @@ public class ResetCommandTest extends RepositoryTestCase {
private RevCommit initialCommit; private RevCommit initialCommit;
private RevCommit secondCommit;
private File indexFile; private File indexFile;
private File untrackedFile; private File untrackedFile;
private DirCacheEntry prestage;
public void setupRepository() throws IOException, NoFilepatternException, public void setupRepository() throws IOException, NoFilepatternException,
NoHeadException, NoMessageException, ConcurrentRefUpdateException, NoHeadException, NoMessageException, ConcurrentRefUpdateException,
JGitInternalException, WrongRepositoryStateException { JGitInternalException, WrongRepositoryStateException {
@ -95,7 +102,10 @@ public class ResetCommandTest extends RepositoryTestCase {
// add file and commit it // add file and commit it
git.add().addFilepattern("a.txt").call(); 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 // modify file and add to index
writer.print("new content"); writer.print("new content");
@ -178,6 +188,66 @@ public class ResetCommandTest extends RepositoryTestCase {
assertReflog(prevHead, head); 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) private void assertReflog(ObjectId prevHead, ObjectId head)
throws IOException { throws IOException {
// Check the reflog for HEAD // Check the reflog for HEAD
@ -187,9 +257,8 @@ public class ResetCommandTest extends RepositoryTestCase {
assertEquals(expectedHeadMessage, actualHeadMessage); assertEquals(expectedHeadMessage, actualHeadMessage);
assertEquals(head.getName(), db.getReflogReader(Constants.HEAD) assertEquals(head.getName(), db.getReflogReader(Constants.HEAD)
.getLastEntry().getNewId().getName()); .getLastEntry().getNewId().getName());
assertEquals(prevHead.getName(), db assertEquals(prevHead.getName(), db.getReflogReader(Constants.HEAD)
.getReflogReader(Constants.HEAD).getLastEntry().getOldId() .getLastEntry().getOldId().getName());
.getName());
// The reflog for master contains the same as the one for HEAD // The reflog for master contains the same as the one for HEAD
String actualMasterMessage = db.getReflogReader("refs/heads/master") String actualMasterMessage = db.getReflogReader("refs/heads/master")
@ -198,9 +267,9 @@ public class ResetCommandTest extends RepositoryTestCase {
assertEquals(expectedMasterMessage, actualMasterMessage); assertEquals(expectedMasterMessage, actualMasterMessage);
assertEquals(head.getName(), db.getReflogReader(Constants.HEAD) assertEquals(head.getName(), db.getReflogReader(Constants.HEAD)
.getLastEntry().getNewId().getName()); .getLastEntry().getNewId().getName());
assertEquals(prevHead.getName(), assertEquals(prevHead.getName(), db
db.getReflogReader("refs/heads/master").getLastEntry() .getReflogReader("refs/heads/master").getLastEntry().getOldId()
.getOldId().getName()); .getName());
} }
/** /**

79
org.eclipse.jgit/src/org/eclipse/jgit/api/ResetCommand.java

@ -44,12 +44,17 @@ package org.eclipse.jgit.api;
import java.io.IOException; import java.io.IOException;
import java.text.MessageFormat; import java.text.MessageFormat;
import java.util.Collection;
import java.util.LinkedList;
import org.eclipse.jgit.JGitText; import org.eclipse.jgit.JGitText;
import org.eclipse.jgit.api.errors.JGitInternalException; import org.eclipse.jgit.api.errors.JGitInternalException;
import org.eclipse.jgit.dircache.DirCache; import org.eclipse.jgit.dircache.DirCache;
import org.eclipse.jgit.dircache.DirCacheBuilder; import org.eclipse.jgit.dircache.DirCacheBuilder;
import org.eclipse.jgit.dircache.DirCacheCheckout; 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.Constants;
import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Ref; 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.lib.RepositoryState;
import org.eclipse.jgit.revwalk.RevCommit; import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevWalk; 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 * 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 KEEP // TODO not implemented yet
} }
private String ref; private String ref = Constants.HEAD;
private ResetType mode; private ResetType mode;
private Collection<String> filepaths = new LinkedList<String>();
/** /**
* *
* @param repo * @param repo
@ -157,6 +167,13 @@ public class ResetCommand extends GitCommand<Ref> {
rw.release(); rw.release();
} }
if (!filepaths.isEmpty()) {
// reset [commit] -- paths
resetIndexForPaths(commit);
setCallable(false);
return repo.getRef(Constants.HEAD);
}
// write the ref // write the ref
final RefUpdate ru = repo.updateRef(Constants.HEAD); final RefUpdate ru = repo.updateRef(Constants.HEAD);
ru.setNewObjectId(commitId); ru.setNewObjectId(commitId);
@ -217,10 +234,70 @@ public class ResetCommand extends GitCommand<Ref> {
* @return this instance * @return this instance
*/ */
public ResetCommand setMode(ResetType mode) { public ResetCommand setMode(ResetType mode) {
if (!filepaths.isEmpty())
throw new JGitInternalException(MessageFormat.format(
JGitText.get().illegalCombinationOfArguments,
"[--mixed | --soft | --hard]", "<paths>..."));
this.mode = mode; this.mode = mode;
return this; 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 { private void resetIndex(RevCommit commit) throws IOException {
DirCache dc = null; DirCache dc = null;
try { try {

Loading…
Cancel
Save