]> source.dussan.org Git - jgit.git/commitdiff
Support parsing previous checkout as a revision expresion. 76/6776/6
authorRobin Rosenberg <robin.rosenberg@dewire.com>
Thu, 12 Jul 2012 06:04:35 +0000 (08:04 +0200)
committerRobin Rosenberg <robin.rosenberg@dewire.com>
Fri, 20 Jul 2012 06:20:48 +0000 (08:20 +0200)
Repository.resolve can only return an ObjectId and will
continue to do so, but another method, simplify(), will
be able to return a branch name for some cases.

Previous checkouts can be specified as @{-n}, where n is an
integer speifying the n:th previous branch. The result
is the branch name, unless the checkout was a detached head,
in which case the object id is returned. Since the result
is a branch it may be followed by a references to the reflog,
such as @{-1}@{1} if necessary.

A simple expression like "master" is resolved to master in
simplify, but anything starting with refs gets resolved to
its object id, even if it is a branch.

A symbolic ref is resolved to its leaf ref, e.g. "HEAD" might
be resolved to "master".

Change-Id: Ifb815a1247ba2a3e2d9c46249c09be9d47f2b693

org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ReflogResolveTest.java
org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RepositoryResolveTest.java
org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java

index 15cbbcbdf0613c6196fc543211389d05cfb0f37d..fe28b47bbaf367dba02c90ae36846d7a34645e3c 100644 (file)
@@ -126,17 +126,36 @@ public class ReflogResolveTest extends RepositoryTestCase {
        }
 
        @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
index f975a87736bd9fb99b7d6bb75aedf21ba5c09703..1c6a547729cea652cb79ab3e199c8af070f3fbe6 100644 (file)
@@ -53,6 +53,7 @@ import static org.junit.Assert.fail;
 
 import java.io.IOException;
 
+import org.eclipse.jgit.api.Git;
 import org.eclipse.jgit.errors.IncorrectObjectTypeException;
 import org.junit.Test;
 
@@ -231,6 +232,17 @@ public class RepositoryResolveTest extends SampleDataRepositoryTestCase {
                assertNull("no not-a-branch:", db.resolve("not-a-branch:"));
        }
 
+       @Test
+       public void resolveExprSimple() throws Exception {
+               Git git = new Git(db);
+               writeTrashFile("file.txt", "content");
+               git.add().addFilepattern("file.txt").call();
+               git.commit().setMessage("create file").call();
+               assertEquals("master", db.simplify("master"));
+               assertEquals("refs/heads/master", db.simplify("refs/heads/master"));
+               assertEquals("HEAD", db.simplify("HEAD"));
+       }
+
        private static ObjectId id(String name) {
                return ObjectId.fromString(name);
        }
index 2916c29b644024f12cd960bd8804c77ea4e37704..db030952a008a7c7a683a294b2de3e6a45d5b868 100644 (file)
@@ -79,6 +79,7 @@ import org.eclipse.jgit.revwalk.RevCommit;
 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;
@@ -376,20 +377,58 @@ public abstract class Repository {
                        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;
                                }
@@ -429,6 +468,7 @@ public abstract class Repository {
                                                                rev = commit.getParent(pnum - 1);
                                                }
                                                i = j - 1;
+                                               done = i;
                                                break;
                                        case '{':
                                                int k;
@@ -456,6 +496,7 @@ public abstract class Repository {
                                                                throw new RevisionSyntaxException(revstr);
                                                else
                                                        throw new RevisionSyntaxException(revstr);
+                                               done = k;
                                                break;
                                        default:
                                                rev = rw.parseAny(rev);
@@ -485,7 +526,9 @@ public abstract class Repository {
                                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;
                                }
@@ -523,6 +566,8 @@ public abstract class Repository {
                                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) {
@@ -532,47 +577,48 @@ public abstract class Repository {
                                        }
                                }
                                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();
 
@@ -581,13 +627,19 @@ public abstract class Repository {
                                                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) {
@@ -634,6 +686,19 @@ public abstract class Repository {
                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;
@@ -643,10 +708,7 @@ public abstract class Repository {
                        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)