OSDN Git Service

refs: extract a function peel_entry()
authorMichael Haggerty <mhagger@alum.mit.edu>
Mon, 22 Apr 2013 19:52:22 +0000 (21:52 +0200)
committerJunio C Hamano <gitster@pobox.com>
Wed, 1 May 2013 22:33:10 +0000 (15:33 -0700)
Peel the entry, and as a side effect store the peeled value in the
entry.  Use this function from two places in peel_ref(); a third
caller will be added soon.

Please note that this change can lead to ref_entries for unpacked refs
being peeled.  This has no practical benefit but is harmless.

Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
refs.c

diff --git a/refs.c b/refs.c
index 787db21..689b55d 100644 (file)
--- a/refs.c
+++ b/refs.c
@@ -1286,7 +1286,17 @@ enum peel_status {
        PEEL_INVALID = -1,
 
        /* object cannot be peeled because it is not a tag: */
-       PEEL_NON_TAG = -2
+       PEEL_NON_TAG = -2,
+
+       /* ref_entry contains no peeled value because it is a symref: */
+       PEEL_IS_SYMREF = -3,
+
+       /*
+        * ref_entry cannot be peeled because it is broken (i.e., the
+        * symbolic reference cannot even be resolved to an object
+        * name):
+        */
+       PEEL_BROKEN = -4
 };
 
 /*
@@ -1318,31 +1328,56 @@ static enum peel_status peel_object(const unsigned char *name, unsigned char *sh
        return PEEL_PEELED;
 }
 
+/*
+ * Peel the entry (if possible) and return its new peel_status.
+ */
+static enum peel_status peel_entry(struct ref_entry *entry)
+{
+       enum peel_status status;
+
+       if (entry->flag & REF_KNOWS_PEELED)
+               return is_null_sha1(entry->u.value.peeled) ?
+                       PEEL_NON_TAG : PEEL_PEELED;
+       if (entry->flag & REF_ISBROKEN)
+               return PEEL_BROKEN;
+       if (entry->flag & REF_ISSYMREF)
+               return PEEL_IS_SYMREF;
+
+       status = peel_object(entry->u.value.sha1, entry->u.value.peeled);
+       if (status == PEEL_PEELED || status == PEEL_NON_TAG)
+               entry->flag |= REF_KNOWS_PEELED;
+       return status;
+}
+
 int peel_ref(const char *refname, unsigned char *sha1)
 {
        int flag;
        unsigned char base[20];
 
        if (current_ref && (current_ref->name == refname
-               || !strcmp(current_ref->name, refname))) {
-               if (current_ref->flag & REF_KNOWS_PEELED) {
-                       if (is_null_sha1(current_ref->u.value.peeled))
-                           return -1;
-                       hashcpy(sha1, current_ref->u.value.peeled);
-                       return 0;
-               }
-               return peel_object(current_ref->u.value.sha1, sha1);
+                           || !strcmp(current_ref->name, refname))) {
+               if (peel_entry(current_ref))
+                       return -1;
+               hashcpy(sha1, current_ref->u.value.peeled);
+               return 0;
        }
 
        if (read_ref_full(refname, base, 1, &flag))
                return -1;
 
-       if ((flag & REF_ISPACKED)) {
+       /*
+        * If the reference is packed, read its ref_entry from the
+        * cache in the hope that we already know its peeled value.
+        * We only try this optimization on packed references because
+        * (a) forcing the filling of the loose reference cache could
+        * be expensive and (b) loose references anyway usually do not
+        * have REF_KNOWS_PEELED.
+        */
+       if (flag & REF_ISPACKED) {
                struct ref_entry *r = get_packed_ref(refname);
-
-               if (r && (r->flag & REF_KNOWS_PEELED)) {
-                       if (is_null_sha1(r->u.value.peeled))
-                           return -1;
+               if (r) {
+                       if (peel_entry(r))
+                               return -1;
                        hashcpy(sha1, r->u.value.peeled);
                        return 0;
                }