]> source.dussan.org Git - jgit.git/commitdiff
Introduce exactRef to read a ref whose exact name is known 48/49548/4
authorJonathan Nieder <jrn@google.com>
Fri, 5 Jun 2015 21:14:55 +0000 (14:14 -0700)
committerJonathan Nieder <jrn@google.com>
Fri, 5 Jun 2015 21:14:55 +0000 (14:14 -0700)
Unlike getRef(name), the new exactRef method does not walk the search
path.  This should produce a less confusing result than getRef when the
exact ref name is known: it will not try to resolve refs/foo/bar to
refs/heads/refs/foo/bar even when refs/foo/bar does not exist.

It can be faster than both getRefs(ALL).get(name) and getRef(name)
because it only needs to examine a single ref.

A follow-up change will introduce a findRef synonym to getRef and
deprecate getRef to make the choice a caller is making more obvious
(exactRef or findRef, with the same semantics as getRefs(ALL).get and
getRefs(ALL).findRef).

Change-Id: If1bd09bcfc9919e7976a4d77f13184ea58dcda52
Signed-off-by: Jonathan Nieder <jrn@google.com>
org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/RefDirectoryTest.java
org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RefTest.java
org.eclipse.jgit/src/org/eclipse/jgit/lib/RefDatabase.java

index 8dbe64478e9af754731e3a129001a1489922d4a0..292e50447e499a10c2128293bb0362c23c0745f7 100644 (file)
@@ -999,6 +999,23 @@ public class RefDirectoryTest extends LocalDiskRepositoryTestCase {
                assertNull(r.getPeeledObjectId());
        }
 
+       @Test
+       public void testExactRef_FetchHead() throws IOException {
+               // This is an odd special case where we need to make sure we read
+               // exactly the first 40 bytes of the file and nothing further on
+               // that line, or the remainder of the file.
+               write(new File(diskRepo.getDirectory(), "FETCH_HEAD"), A.name()
+                               + "\tnot-for-merge"
+                               + "\tbranch 'master' of git://egit.eclipse.org/jgit\n");
+
+               Ref r = refdir.exactRef("FETCH_HEAD");
+               assertFalse(r.isSymbolic());
+               assertEquals(A, r.getObjectId());
+               assertEquals("FETCH_HEAD", r.getName());
+               assertFalse(r.isPeeled());
+               assertNull(r.getPeeledObjectId());
+       }
+
        @Test
        public void testGetRef_AnyHeadWithGarbage() throws IOException {
                write(new File(diskRepo.getDirectory(), "refs/heads/A"), A.name()
index f2ed684511c4c4d0c70afadfb58a7e7014d45c0d..109f401898a252ede8a73542815cccfc6bce3452 100644 (file)
@@ -84,6 +84,12 @@ public class RefTest extends SampleDataRepositoryTestCase {
                }
        }
 
+       private void writeNewRef(String name, ObjectId value) throws IOException {
+               RefUpdate updateRef = db.updateRef(name);
+               updateRef.setNewObjectId(value);
+               assertEquals(RefUpdate.Result.NEW, updateRef.update());
+       }
+
        @Test
        public void testRemoteNames() throws Exception {
                FileBasedConfig config = db.getConfig();
@@ -192,6 +198,50 @@ public class RefTest extends SampleDataRepositoryTestCase {
                assertEquals(Storage.LOOSE, ref.getStorage());
        }
 
+       @Test
+       public void testGetShortRef() throws IOException {
+               Ref ref = db.getRef("master");
+               assertEquals("refs/heads/master", ref.getName());
+               assertEquals(db.resolve("refs/heads/master"), ref.getObjectId());
+       }
+
+       @Test
+       public void testGetShortExactRef() throws IOException {
+               assertNull(db.getRefDatabase().exactRef("master"));
+
+               Ref ref = db.getRefDatabase().exactRef("HEAD");
+               assertEquals("HEAD", ref.getName());
+               assertEquals("refs/heads/master", ref.getTarget().getName());
+               assertEquals(db.resolve("refs/heads/master"), ref.getObjectId());
+       }
+
+       @Test
+       public void testRefsUnderRefs() throws IOException {
+               ObjectId masterId = db.resolve("refs/heads/master");
+               writeNewRef("refs/heads/refs/foo/bar", masterId);
+
+               assertNull(db.getRefDatabase().exactRef("refs/foo/bar"));
+
+               Ref ref = db.getRef("refs/foo/bar");
+               assertEquals("refs/heads/refs/foo/bar", ref.getName());
+               assertEquals(db.resolve("refs/heads/master"), ref.getObjectId());
+       }
+
+       @Test
+       public void testAmbiguousRefsUnderRefs() throws IOException {
+               ObjectId masterId = db.resolve("refs/heads/master");
+               writeNewRef("refs/foo/bar", masterId);
+               writeNewRef("refs/heads/refs/foo/bar", masterId);
+
+               Ref exactRef = db.getRefDatabase().exactRef("refs/foo/bar");
+               assertEquals("refs/foo/bar", exactRef.getName());
+               assertEquals(masterId, exactRef.getObjectId());
+
+               Ref ref = db.getRef("refs/foo/bar");
+               assertEquals("refs/foo/bar", ref.getName());
+               assertEquals(masterId, ref.getObjectId());
+       }
+
        /**
         * Let an "outsider" create a loose ref with the same name as a packed one
         *
index 7fea880612c28373a00c1b0e8beb8c43a80c36a8..1a58c5138233113b4e1f19c3ad0b08db275f3e43 100644 (file)
@@ -211,6 +211,9 @@ public abstract class RefDatabase {
         * Aside from taking advantage of {@link #SEARCH_PATH}, this method may be
         * able to more quickly resolve a single reference name than obtaining the
         * complete namespace by {@code getRefs(ALL).get(name)}.
+        * <p>
+        * To read a specific reference without using @{link #SEARCH_PATH}, see
+        * {@link #exactRef(String)}.
         *
         * @param name
         *            the name of the reference. May be a short name which must be
@@ -221,6 +224,36 @@ public abstract class RefDatabase {
         */
        public abstract Ref getRef(String name) throws IOException;
 
+       /**
+        * Read a single reference.
+        * <p>
+        * Unlike {@link #getRef}, this method expects an unshortened reference
+        * name and does not search using the standard {@link #SEARCH_PATH}.
+        *
+        * @param name
+        *             the unabbreviated name of the reference.
+        * @return the reference (if it exists); else {@code null}.
+        * @throws IOException
+        *             the reference space cannot be accessed.
+        * @since 4.1
+        */
+       public Ref exactRef(String name) throws IOException {
+               int slash = name.lastIndexOf('/');
+               String prefix = name.substring(0, slash + 1);
+               String rest = name.substring(slash + 1);
+               Ref result = getRefs(prefix).get(rest);
+               if (result != null || slash != -1) {
+                       return result;
+               }
+
+               for (Ref ref : getAdditionalRefs()) {
+                       if (name.equals(ref.getName())) {
+                               return ref;
+                       }
+               }
+               return null;
+       }
+
        /**
         * Get a section of the reference namespace.
         *
@@ -242,6 +275,7 @@ public abstract class RefDatabase {
         * The result list includes non-ref items such as MERGE_HEAD and
         * FETCH_RESULT cast to be refs. The names of these refs are not returned by
         * <code>getRefs(ALL)</code> but are accepted by {@link #getRef(String)}
+        * and {@link exactRef(String)}.
         *
         * @return a list of additional refs
         * @throws IOException