}
@Test
- public void resolveNegativeEntryNumber() throws Exception {
+ public void resolvePreviousBranch() throws Exception {
Git git = new Git(db);
writeTrashFile("file.txt", "content");
git.add().addFilepattern("file.txt").call();
- git.commit().setMessage("create file").call();
+ RevCommit c1 = git.commit().setMessage("create file").call();
+ writeTrashFile("file.txt", "content2");
+ git.add().addFilepattern("file.txt").call();
+ RevCommit c2 = git.commit().setMessage("edit file").call();
+
+ git.checkout().setCreateBranch(true).setName("newbranch")
+ .setStartPoint(c1).call();
+
+ git.checkout().setName(c1.getName()).call();
+
+ git.checkout().setName("master").call();
+
+ assertEquals(c1.getName(), db.simplify("@{-1}"));
+ assertEquals("newbranch", db.simplify("@{-2}"));
+ assertEquals("master", db.simplify("@{-3}"));
+
+ // chained expression
try {
- db.resolve("master@{-12}");
- fail("Exception not thrown");
+ // Cannot refer to reflog of detached head
+ db.resolve("@{-1}@{0}");
+ fail();
} catch (RevisionSyntaxException e) {
- assertNotNull(e);
}
+ assertEquals(c1.getName(), db.resolve("@{-2}@{0}").getName());
+
+ assertEquals(c2.getName(), db.resolve("@{-3}@{0}").getName());
}
@Test
import org.eclipse.jgit.revwalk.RevObject;
import org.eclipse.jgit.revwalk.RevTree;
import org.eclipse.jgit.revwalk.RevWalk;
+import org.eclipse.jgit.storage.file.CheckoutEntry;
import org.eclipse.jgit.storage.file.ReflogEntry;
import org.eclipse.jgit.storage.file.ReflogReader;
import org.eclipse.jgit.treewalk.TreeWalk;
throws AmbiguousObjectException, IOException {
RevWalk rw = new RevWalk(this);
try {
- return resolve(rw, revstr);
+ Object resolved = resolve(rw, revstr);
+ if (resolved instanceof String) {
+ return getRef((String) resolved).getLeaf().getObjectId();
+ } else {
+ return (ObjectId) resolved;
+ }
} finally {
rw.release();
}
}
- private ObjectId resolve(final RevWalk rw, final String revstr) throws IOException {
+ /**
+ * Simplify an expression, but unlike {@link #resolve(String)} it will not
+ * resolve a branch passed or resulting from the expression, such as @{-}.
+ * Thus this method can be used to process an expression to a method that
+ * expects a branch or revision id.
+ *
+ * @param revstr
+ * @return object id or ref name from resolved expression
+ * @throws AmbiguousObjectException
+ * @throws IOException
+ */
+ public String simplify(final String revstr)
+ throws AmbiguousObjectException, IOException {
+ RevWalk rw = new RevWalk(this);
+ try {
+ Object resolved = resolve(rw, revstr);
+ if (resolved != null)
+ if (resolved instanceof String)
+ return (String) resolved;
+ else
+ return ((AnyObjectId) resolved).getName();
+ return null;
+ } finally {
+ rw.release();
+ }
+ }
+
+ private Object resolve(final RevWalk rw, final String revstr)
+ throws IOException {
char[] revChars = revstr.toCharArray();
RevObject rev = null;
+ String name = null;
+ int done = 0;
for (int i = 0; i < revChars.length; ++i) {
switch (revChars[i]) {
case '^':
if (rev == null) {
- rev = parseSimple(rw, new String(revChars, 0, i));
+ if (name == null)
+ name = new String(revChars, done, i);
+ rev = parseSimple(rw, name);
+ name = null;
if (rev == null)
return null;
}
rev = commit.getParent(pnum - 1);
}
i = j - 1;
+ done = i;
break;
case '{':
int k;
throw new RevisionSyntaxException(revstr);
else
throw new RevisionSyntaxException(revstr);
+ done = k;
break;
default:
rev = rw.parseAny(rev);
break;
case '~':
if (rev == null) {
- rev = parseSimple(rw, new String(revChars, 0, i));
+ if (name == null)
+ name = new String(revChars, done, i);
+ rev = parseSimple(rw, name);
if (rev == null)
return null;
}
i = l - 1;
break;
case '@':
+ if (rev != null)
+ throw new RevisionSyntaxException(revstr);
int m;
String time = null;
for (m = i + 2; m < revChars.length; ++m) {
}
}
if (time != null) {
- String refName = new String(revChars, 0, i);
- Ref ref;
- if (refName.equals("")) {
- // Currently checked out branch, HEAD if
- // detached
- ref = getRef(Constants.HEAD);
+ if (time.matches("^-\\d+$")) {
+ if (name != null)
+ throw new RevisionSyntaxException(revstr);
+ else {
+ String previousCheckout = resolveReflogCheckout(-Integer
+ .parseInt(time));
+ if (ObjectId.isId(previousCheckout))
+ rev = parseSimple(rw, previousCheckout);
+ else
+ name = previousCheckout;
+ }
+ } else {
+ if (name == null)
+ name = new String(revChars, done, i);
+ if (name.equals(""))
+ name = Constants.HEAD;
+ Ref ref = getRef(name);
if (ref == null)
return null;
+ // @{n} means current branch, not HEAD@{1} unless
+ // detached
if (ref.isSymbolic())
ref = ref.getLeaf();
- if (ref.getObjectId() == null)
- return null;
- } else
- ref = getRef(refName);
- if (ref == null)
- return null;
- rev = resolveReflog(rw, ref, time);
+ rev = resolveReflog(rw, ref, time);
+ name = null;
+ }
i = m;
} else
- i = m - 1;
+ throw new RevisionSyntaxException(revstr);
break;
case ':': {
RevTree tree;
if (rev == null) {
- // We might not yet have parsed the left hand side.
- ObjectId id;
- try {
- if (i == 0)
- id = resolve(rw, Constants.HEAD);
- else
- id = resolve(rw, new String(revChars, 0, i));
- } catch (RevisionSyntaxException badSyntax) {
- throw new RevisionSyntaxException(revstr);
- }
- if (id == null)
- return null;
- tree = rw.parseTree(id);
- } else {
- tree = rw.parseTree(rev);
+ if (name == null)
+ name = new String(revChars, done, i);
+ if (name.equals(""))
+ name = Constants.HEAD;
+ rev = parseSimple(rw, name);
}
-
+ if (rev == null)
+ return null;
+ tree = rw.parseTree(rev);
if (i == revChars.length - 1)
return tree.copy();
tree);
return tw != null ? tw.getObjectId(0) : null;
}
-
default:
if (rev != null)
throw new RevisionSyntaxException(revstr);
}
}
- return rev != null ? rev.copy() : resolveSimple(revstr);
+ if (rev != null)
+ return rev.copy();
+ if (name != null)
+ return name;
+ name = revstr.substring(done);
+ if (getRef(name) != null)
+ return name;
+ return resolveSimple(name);
}
private static boolean isHex(char c) {
return null;
}
+ private String resolveReflogCheckout(int checkoutNo)
+ throws IOException {
+ List<ReflogEntry> reflogEntries = new ReflogReader(this, Constants.HEAD)
+ .getReverseEntries();
+ for (ReflogEntry entry : reflogEntries) {
+ CheckoutEntry checkout = entry.parseCheckout();
+ if (checkout != null)
+ if (checkoutNo-- == 1)
+ return checkout.getFromBranch();
+ }
+ return null;
+ }
+
private RevCommit resolveReflog(RevWalk rw, Ref ref, String time)
throws IOException {
int number;
throw new RevisionSyntaxException(MessageFormat.format(
JGitText.get().invalidReflogRevision, time));
}
- if (number < 0)
- throw new RevisionSyntaxException(MessageFormat.format(
- JGitText.get().invalidReflogRevision, time));
-
+ assert number >= 0;
ReflogReader reader = new ReflogReader(this, ref.getName());
ReflogEntry entry = reader.getReverseEntry(number);
if (entry == null)