pack-refs: rename handle_one_ref() to pack_one_ref()
[gitweb.git] / sha1_name.c
index 18fac921dd7bb067b2c21d1ad51df3818bcdf261..c50630a3ea793e0cfd2510b8813129a1685428f4 100644 (file)
@@ -20,10 +20,15 @@ struct disambiguate_state {
        unsigned candidate_ok:1;
        unsigned disambiguate_fn_used:1;
        unsigned ambiguous:1;
+       unsigned always_call_fn:1;
 };
 
 static void update_candidates(struct disambiguate_state *ds, const unsigned char *current)
 {
+       if (ds->always_call_fn) {
+               ds->ambiguous = ds->fn(current, ds->cb_data) ? 1 : 0;
+               return;
+       }
        if (!ds->candidate_exists) {
                /* this is the first candidate */
                hashcpy(ds->candidate, current);
@@ -272,17 +277,12 @@ static int disambiguate_blob_only(const unsigned char *sha1, void *cb_data_unuse
        return kind == OBJ_BLOB;
 }
 
-static int get_short_sha1(const char *name, int len, unsigned char *sha1,
-                         unsigned flags)
+static int prepare_prefixes(const char *name, int len,
+                           unsigned char *bin_pfx,
+                           char *hex_pfx)
 {
-       int i, status;
-       char hex_pfx[40];
-       unsigned char bin_pfx[20];
-       struct disambiguate_state ds;
-       int quietly = !!(flags & GET_SHA1_QUIETLY);
+       int i;
 
-       if (len < MINIMUM_ABBREV || len > 40)
-               return -1;
        hashclr(bin_pfx);
        memset(hex_pfx, 'x', 40);
        for (i = 0; i < len ;i++) {
@@ -303,6 +303,22 @@ static int get_short_sha1(const char *name, int len, unsigned char *sha1,
                        val <<= 4;
                bin_pfx[i >> 1] |= val;
        }
+       return 0;
+}
+
+static int get_short_sha1(const char *name, int len, unsigned char *sha1,
+                         unsigned flags)
+{
+       int status;
+       char hex_pfx[40];
+       unsigned char bin_pfx[20];
+       struct disambiguate_state ds;
+       int quietly = !!(flags & GET_SHA1_QUIETLY);
+
+       if (len < MINIMUM_ABBREV || len > 40)
+               return -1;
+       if (prepare_prefixes(name, len, bin_pfx, hex_pfx) < 0)
+               return -1;
 
        prepare_alt_odb();
 
@@ -327,6 +343,31 @@ static int get_short_sha1(const char *name, int len, unsigned char *sha1,
        return status;
 }
 
+
+int for_each_abbrev(const char *prefix, each_abbrev_fn fn, void *cb_data)
+{
+       char hex_pfx[40];
+       unsigned char bin_pfx[20];
+       struct disambiguate_state ds;
+       int len = strlen(prefix);
+
+       if (len < MINIMUM_ABBREV || len > 40)
+               return -1;
+       if (prepare_prefixes(prefix, len, bin_pfx, hex_pfx) < 0)
+               return -1;
+
+       prepare_alt_odb();
+
+       memset(&ds, 0, sizeof(ds));
+       ds.always_call_fn = 1;
+       ds.cb_data = cb_data;
+       ds.fn = fn;
+
+       find_short_object_filename(len, hex_pfx, &ds);
+       find_short_packed_object(len, bin_pfx, &ds);
+       return ds.ambiguous;
+}
+
 const char *find_unique_abbrev(const unsigned char *sha1, int len)
 {
        int status, exists;
@@ -995,10 +1036,22 @@ int interpret_branch_name(const char *name, struct strbuf *buf)
        len = cp + tmp_len - name;
        cp = xstrndup(name, cp - name);
        upstream = branch_get(*cp ? cp : NULL);
-       if (!upstream
-           || !upstream->merge
-           || !upstream->merge[0]->dst)
-               return error("No upstream branch found for '%s'", cp);
+       /*
+        * Upstream can be NULL only if cp refers to HEAD and HEAD
+        * points to something different than a branch.
+        */
+       if (!upstream)
+               return error(_("HEAD does not point to a branch"));
+       if (!upstream->merge || !upstream->merge[0]->dst) {
+               if (!ref_exists(upstream->refname))
+                       return error(_("No such branch: '%s'"), cp);
+               if (!upstream->merge)
+                       return error(_("No upstream configured for branch '%s'"),
+                                    upstream->name);
+               return error(
+                       _("Upstream branch '%s' not stored as a remote-tracking branch"),
+                       upstream->merge[0]->src);
+       }
        free(cp);
        cp = shorten_unambiguous_ref(upstream->merge[0]->dst, 0);
        strbuf_reset(buf);
@@ -1084,7 +1137,8 @@ int get_sha1_blob(const char *name, unsigned char *sha1)
 static void diagnose_invalid_sha1_path(const char *prefix,
                                       const char *filename,
                                       const unsigned char *tree_sha1,
-                                      const char *object_name)
+                                      const char *object_name,
+                                      int object_name_len)
 {
        struct stat st;
        unsigned char sha1[20];
@@ -1094,8 +1148,8 @@ static void diagnose_invalid_sha1_path(const char *prefix,
                prefix = "";
 
        if (!lstat(filename, &st))
-               die("Path '%s' exists on disk, but not in '%s'.",
-                   filename, object_name);
+               die("Path '%s' exists on disk, but not in '%.*s'.",
+                   filename, object_name_len, object_name);
        if (errno == ENOENT || errno == ENOTDIR) {
                char *fullname = xmalloc(strlen(filename)
                                             + strlen(prefix) + 1);
@@ -1105,16 +1159,16 @@ static void diagnose_invalid_sha1_path(const char *prefix,
                if (!get_tree_entry(tree_sha1, fullname,
                                    sha1, &mode)) {
                        die("Path '%s' exists, but not '%s'.\n"
-                           "Did you mean '%s:%s' aka '%s:./%s'?",
+                           "Did you mean '%.*s:%s' aka '%.*s:./%s'?",
                            fullname,
                            filename,
-                           object_name,
+                           object_name_len, object_name,
                            fullname,
-                           object_name,
+                           object_name_len, object_name,
                            filename);
                }
-               die("Path '%s' does not exist in '%s'",
-                   filename, object_name);
+               die("Path '%s' does not exist in '%.*s'",
+                   filename, object_name_len, object_name);
        }
 }
 
@@ -1279,13 +1333,8 @@ static int get_sha1_with_context_1(const char *name,
        }
        if (*cp == ':') {
                unsigned char tree_sha1[20];
-               char *object_name = NULL;
-               if (only_to_die) {
-                       object_name = xmalloc(cp-name+1);
-                       strncpy(object_name, name, cp-name);
-                       object_name[cp-name] = '\0';
-               }
-               if (!get_sha1_1(name, cp-name, tree_sha1, GET_SHA1_TREEISH)) {
+               int len = cp - name;
+               if (!get_sha1_1(name, len, tree_sha1, GET_SHA1_TREEISH)) {
                        const char *filename = cp+1;
                        char *new_filename = NULL;
 
@@ -1293,10 +1342,10 @@ static int get_sha1_with_context_1(const char *name,
                        if (new_filename)
                                filename = new_filename;
                        ret = get_tree_entry(tree_sha1, filename, sha1, &oc->mode);
-                       if (only_to_die) {
+                       if (ret && only_to_die) {
                                diagnose_invalid_sha1_path(prefix, filename,
-                                                          tree_sha1, object_name);
-                               free(object_name);
+                                                          tree_sha1,
+                                                          name, len);
                        }
                        hashcpy(oc->tree, tree_sha1);
                        strncpy(oc->path, filename,
@@ -1307,7 +1356,7 @@ static int get_sha1_with_context_1(const char *name,
                        return ret;
                } else {
                        if (only_to_die)
-                               die("Invalid object name '%s'.", object_name);
+                               die("Invalid object name '%.*s'.", len, name);
                }
        }
        return ret;