Code

Added missing completions for show-branch and merge-base.
[git.git] / sha1_name.c
index ec5cd2c9ea42cfdd07a1fcac1f2c05072aa26193..6d7cd78381414aa2fef31d31d46fbb24b0aaab1d 100644 (file)
@@ -4,6 +4,7 @@
 #include "tree.h"
 #include "blob.h"
 #include "tree-walk.h"
+#include "refs.h"
 
 static int find_short_object_filename(int len, const char *name, unsigned char *sha1)
 {
@@ -83,7 +84,7 @@ static int find_short_packed_object(int len, const unsigned char *match, unsigne
                        int cmp;
 
                        nth_packed_object_sha1(p, mid, now);
-                       cmp = memcmp(match, now, 20);
+                       cmp = hashcmp(match, now);
                        if (!cmp) {
                                first = mid;
                                break;
@@ -102,10 +103,10 @@ static int find_short_packed_object(int len, const unsigned char *match, unsigne
                                    !match_sha(len, match, next)) {
                                        /* unique within this pack */
                                        if (!found) {
-                                               memcpy(found_sha1, now, 20);
+                                               hashcpy(found_sha1, now);
                                                found++;
                                        }
-                                       else if (memcmp(found_sha1, now, 20)) {
+                                       else if (hashcmp(found_sha1, now)) {
                                                found = 2;
                                                break;
                                        }
@@ -119,7 +120,7 @@ static int find_short_packed_object(int len, const unsigned char *match, unsigne
                }
        }
        if (found == 1)
-               memcpy(sha1, found_sha1, 20);
+               hashcpy(sha1, found_sha1);
        return found;
 }
 
@@ -139,13 +140,13 @@ static int find_unique_short_object(int len, char *canonical,
        if (1 < has_unpacked || 1 < has_packed)
                return SHORT_NAME_AMBIGUOUS;
        if (has_unpacked != has_packed) {
-               memcpy(sha1, (has_packed ? packed_sha1 : unpacked_sha1), 20);
+               hashcpy(sha1, (has_packed ? packed_sha1 : unpacked_sha1));
                return 0;
        }
        /* Both have unique ones -- do they match? */
-       if (memcmp(packed_sha1, unpacked_sha1, 20))
+       if (hashcmp(packed_sha1, unpacked_sha1))
                return SHORT_NAME_AMBIGUOUS;
-       memcpy(sha1, packed_sha1, 20);
+       hashcpy(sha1, packed_sha1);
        return 0;
 }
 
@@ -156,9 +157,9 @@ static int get_short_sha1(const char *name, int len, unsigned char *sha1,
        char canonical[40];
        unsigned char res[20];
 
-       if (len < MINIMUM_ABBREV)
+       if (len < MINIMUM_ABBREV || len > 40)
                return -1;
-       memset(res, 0, 20);
+       hashclr(res);
        memset(canonical, 'x', 40);
        for (i = 0; i < len ;i++) {
                unsigned char c = name[i];
@@ -190,9 +191,9 @@ const char *find_unique_abbrev(const unsigned char *sha1, int len)
        int status, is_null;
        static char hex[41];
 
-       is_null = !memcmp(sha1, null_sha1, 20);
+       is_null = is_null_sha1(sha1);
        memcpy(hex, sha1_to_hex(sha1), 40);
-       if (len == 40)
+       if (len == 40 || !len)
                return hex;
        while (len < 40) {
                unsigned char sha1_ret[20];
@@ -245,36 +246,70 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1)
                "refs/remotes/%.*s/HEAD",
                NULL
        };
-       const char **p;
-       const char *warning = "warning: refname '%.*s' is ambiguous.\n";
-       char *pathname;
-       int already_found = 0;
+       static const char *warning = "warning: refname '%.*s' is ambiguous.\n";
+       const char **p, *ref;
+       char *real_ref = NULL;
+       int refs_found = 0;
+       int at, reflog_len;
        unsigned char *this_result;
        unsigned char sha1_from_ref[20];
 
        if (len == 40 && !get_sha1_hex(str, sha1))
                return 0;
 
+       /* basic@{time or number} format to query ref-log */
+       reflog_len = at = 0;
+       if (str[len-1] == '}') {
+               for (at = 1; at < len - 1; at++) {
+                       if (str[at] == '@' && str[at+1] == '{') {
+                               reflog_len = (len-1) - (at+2);
+                               len = at;
+                               break;
+                       }
+               }
+       }
+
        /* Accept only unambiguous ref paths. */
        if (ambiguous_path(str, len))
                return -1;
 
        for (p = fmt; *p; p++) {
-               this_result = already_found ? sha1_from_ref : sha1;
-               pathname = git_path(*p, len, str);
-               if (!read_ref(pathname, this_result)) {
-                       if (warn_ambiguous_refs) {
-                               if (already_found)
-                                       fprintf(stderr, warning, len, str);
-                               already_found++;
-                       }
+               this_result = refs_found ? sha1_from_ref : sha1;
+               ref = resolve_ref(mkpath(*p, len, str), this_result, 1, NULL);
+               if (ref) {
+                       if (!refs_found++)
+                               real_ref = xstrdup(ref);
+                       if (!warn_ambiguous_refs)
+                               break;
+               }
+       }
+
+       if (!refs_found)
+               return -1;
+
+       if (warn_ambiguous_refs && refs_found > 1)
+               fprintf(stderr, warning, len, str);
+
+       if (reflog_len) {
+               /* Is it asking for N-th entry, or approxidate? */
+               int nth, i;
+               unsigned long at_time;
+               for (i = nth = 0; 0 <= nth && i < reflog_len; i++) {
+                       char ch = str[at+2+i];
+                       if ('0' <= ch && ch <= '9')
+                               nth = nth * 10 + ch - '0';
                        else
-                               return 0;
+                               nth = -1;
                }
+               if (0 <= nth)
+                       at_time = 0;
+               else
+                       at_time = approxidate(str + at + 2);
+               read_ref_at(real_ref, at_time, nth, sha1);
        }
-       if (already_found)
-               return 0;
-       return -1;
+
+       free(real_ref);
+       return 0;
 }
 
 static int get_sha1_1(const char *name, int len, unsigned char *sha1);
@@ -295,13 +330,13 @@ static int get_parent(const char *name, int len,
        if (parse_commit(commit))
                return -1;
        if (!idx) {
-               memcpy(result, commit->object.sha1, 20);
+               hashcpy(result, commit->object.sha1);
                return 0;
        }
        p = commit->parents;
        while (p) {
                if (!--idx) {
-                       memcpy(result, p->item->object.sha1, 20);
+                       hashcpy(result, p->item->object.sha1);
                        return 0;
                }
                p = p->next;
@@ -322,9 +357,9 @@ static int get_nth_ancestor(const char *name, int len,
 
                if (!commit || parse_commit(commit) || !commit->parents)
                        return -1;
-               memcpy(sha1, commit->parents->item->object.sha1, 20);
+               hashcpy(sha1, commit->parents->item->object.sha1);
        }
-       memcpy(result, sha1, 20);
+       hashcpy(result, sha1);
        return 0;
 }
 
@@ -332,7 +367,7 @@ static int peel_onion(const char *name, int len, unsigned char *sha1)
 {
        unsigned char outer[20];
        const char *sp;
-       const char *type_string = NULL;
+       unsigned int expected_type = 0;
        struct object *o;
 
        /*
@@ -356,13 +391,13 @@ static int peel_onion(const char *name, int len, unsigned char *sha1)
 
        sp++; /* beginning of type name, or closing brace for empty */
        if (!strncmp(commit_type, sp, 6) && sp[6] == '}')
-               type_string = commit_type;
+               expected_type = OBJ_COMMIT;
        else if (!strncmp(tree_type, sp, 4) && sp[4] == '}')
-               type_string = tree_type;
+               expected_type = OBJ_TREE;
        else if (!strncmp(blob_type, sp, 4) && sp[4] == '}')
-               type_string = blob_type;
+               expected_type = OBJ_BLOB;
        else if (sp[0] == '}')
-               type_string = NULL;
+               expected_type = OBJ_NONE;
        else
                return -1;
 
@@ -372,11 +407,11 @@ static int peel_onion(const char *name, int len, unsigned char *sha1)
        o = parse_object(outer);
        if (!o)
                return -1;
-       if (!type_string) {
+       if (!expected_type) {
                o = deref_tag(o, name, sp - name - 2);
                if (!o || (!o->parsed && !parse_object(o->sha1)))
                        return -1;
-               memcpy(sha1, o->sha1, 20);
+               hashcpy(sha1, o->sha1);
        }
        else {
                /* At this point, the syntax look correct, so
@@ -387,18 +422,18 @@ static int peel_onion(const char *name, int len, unsigned char *sha1)
                while (1) {
                        if (!o || (!o->parsed && !parse_object(o->sha1)))
                                return -1;
-                       if (o->type == type_string) {
-                               memcpy(sha1, o->sha1, 20);
+                       if (o->type == expected_type) {
+                               hashcpy(sha1, o->sha1);
                                return 0;
                        }
-                       if (o->type == tag_type)
+                       if (o->type == OBJ_TAG)
                                o = ((struct tag*) o)->tagged;
-                       else if (o->type == commit_type)
+                       else if (o->type == OBJ_COMMIT)
                                o = &(((struct commit *) o)->tree->object);
                        else
                                return error("%.*s: expected %s type, but the object dereferences to %s type",
-                                            len, name, type_string,
-                                            o->type);
+                                            len, name, typename(expected_type),
+                                            typename(o->type));
                        if (!o->parsed)
                                parse_object(o->sha1);
                }
@@ -406,6 +441,26 @@ static int peel_onion(const char *name, int len, unsigned char *sha1)
        return 0;
 }
 
+static int get_describe_name(const char *name, int len, unsigned char *sha1)
+{
+       const char *cp;
+
+       for (cp = name + len - 1; name + 2 <= cp; cp--) {
+               char ch = *cp;
+               if (hexval(ch) & ~0377) {
+                       /* We must be looking at g in "SOMETHING-g"
+                        * for it to be describe output.
+                        */
+                       if (ch == 'g' && cp[-1] == '-') {
+                               cp++;
+                               len -= cp - name;
+                               return get_short_sha1(cp, len, sha1, 1);
+                       }
+               }
+       }
+       return -1;
+}
+
 static int get_sha1_1(const char *name, int len, unsigned char *sha1)
 {
        int ret, has_suffix;
@@ -447,6 +502,12 @@ static int get_sha1_1(const char *name, int len, unsigned char *sha1)
        ret = get_sha1_basic(name, len, sha1);
        if (!ret)
                return 0;
+
+       /* It could be describe output that is "SOMETHING-gXXXX" */
+       ret = get_describe_name(name, len, sha1);
+       if (!ret)
+               return 0;
+
        return get_short_sha1(name, len, sha1, 0);
 }
 
@@ -456,7 +517,7 @@ static int get_sha1_1(const char *name, int len, unsigned char *sha1)
  */
 int get_sha1(const char *name, unsigned char *sha1)
 {
-       int ret;
+       int ret, bracket_depth;
        unsigned unused;
        int namelen = strlen(name);
        const char *cp;
@@ -495,14 +556,22 @@ int get_sha1(const char *name, unsigned char *sha1)
                            memcmp(ce->name, cp, namelen))
                                break;
                        if (ce_stage(ce) == stage) {
-                               memcpy(sha1, ce->sha1, 20);
+                               hashcpy(sha1, ce->sha1);
                                return 0;
                        }
+                       pos++;
                }
                return -1;
        }
-       cp = strchr(name, ':');
-       if (cp) {
+       for (cp = name, bracket_depth = 0; *cp; cp++) {
+               if (*cp == '{')
+                       bracket_depth++;
+               else if (bracket_depth && *cp == '}')
+                       bracket_depth--;
+               else if (!bracket_depth && *cp == ':')
+                       break;
+       }
+       if (*cp == ':') {
                unsigned char tree_sha1[20];
                if (!get_sha1_1(name, cp-name, tree_sha1))
                        return get_tree_entry(tree_sha1, cp+1, sha1,