Merge branch 'ma/t7005-bash-workaround'
[gitweb.git] / sha1-name.c
index 60d9ef3c7e7108c859647656972c171cce4e7d7f..faa60f69e311f5f09cd5b91a8fbbaf3e3e744ab0 100644 (file)
@@ -12,6 +12,8 @@
 #include "packfile.h"
 #include "object-store.h"
 #include "repository.h"
+#include "midx.h"
+#include "commit-reach.h"
 
 static int get_oid_oneline(const char *, struct object_id *, struct commit_list *);
 
@@ -44,7 +46,7 @@ static void update_candidates(struct disambiguate_state *ds, const struct object
                oidcpy(&ds->candidate, current);
                ds->candidate_exists = 1;
                return;
-       } else if (!oidcmp(&ds->candidate, current)) {
+       } else if (oideq(&ds->candidate, current)) {
                /* the same as what we already have seen */
                return;
        }
@@ -149,6 +151,32 @@ static int match_sha(unsigned len, const unsigned char *a, const unsigned char *
        return 1;
 }
 
+static void unique_in_midx(struct multi_pack_index *m,
+                          struct disambiguate_state *ds)
+{
+       uint32_t num, i, first = 0;
+       const struct object_id *current = NULL;
+       num = m->num_objects;
+
+       if (!num)
+               return;
+
+       bsearch_midx(&ds->bin_pfx, m, &first);
+
+       /*
+        * At this point, "first" is the location of the lowest object
+        * with an object name that could match "bin_pfx".  See if we have
+        * 0, 1 or more objects that actually match(es).
+        */
+       for (i = first; i < num && !ds->ambiguous; i++) {
+               struct object_id oid;
+               current = nth_midxed_object_oid(&oid, m, i);
+               if (!match_sha(ds->len, ds->bin_pfx.hash, current->hash))
+                       break;
+               update_candidates(ds, current);
+       }
+}
+
 static void unique_in_pack(struct packed_git *p,
                           struct disambiguate_state *ds)
 {
@@ -177,8 +205,12 @@ static void unique_in_pack(struct packed_git *p,
 
 static void find_short_packed_object(struct disambiguate_state *ds)
 {
+       struct multi_pack_index *m;
        struct packed_git *p;
 
+       for (m = get_multi_pack_index(the_repository); m && !ds->ambiguous;
+            m = m->next)
+               unique_in_midx(m, ds);
        for (p = get_packed_git(the_repository); p && !ds->ambiguous;
             p = p->next)
                unique_in_pack(p, ds);
@@ -239,7 +271,8 @@ static int disambiguate_committish_only(const struct object_id *oid, void *cb_da
                return 0;
 
        /* We need to do this the hard way... */
-       obj = deref_tag(parse_object(oid), NULL, 0);
+       obj = deref_tag(the_repository, parse_object(the_repository, oid),
+                       NULL, 0);
        if (obj && obj->type == OBJ_COMMIT)
                return 1;
        return 0;
@@ -263,7 +296,8 @@ static int disambiguate_treeish_only(const struct object_id *oid, void *cb_data_
                return 0;
 
        /* We need to do this the hard way... */
-       obj = deref_tag(parse_object(oid), NULL, 0);
+       obj = deref_tag(the_repository, parse_object(the_repository, oid),
+                       NULL, 0);
        if (obj && (obj->type == OBJ_TREE || obj->type == OBJ_COMMIT))
                return 1;
        return 0;
@@ -310,7 +344,7 @@ static int init_object_disambiguation(const char *name, int len,
 {
        int i;
 
-       if (len < MINIMUM_ABBREV || len > GIT_SHA1_HEXSZ)
+       if (len < MINIMUM_ABBREV || len > the_hash_algo->hexsz)
                return -1;
 
        memset(ds, 0, sizeof(*ds));
@@ -351,14 +385,14 @@ static int show_ambiguous_object(const struct object_id *oid, void *data)
 
        type = oid_object_info(the_repository, oid, NULL);
        if (type == OBJ_COMMIT) {
-               struct commit *commit = lookup_commit(oid);
+               struct commit *commit = lookup_commit(the_repository, oid);
                if (commit) {
                        struct pretty_print_context pp = {0};
                        pp.date_mode.type = DATE_SHORT;
                        format_commit_message(commit, " %ad - %s", &desc, &pp);
                }
        } else if (type == OBJ_TAG) {
-               struct tag *tag = lookup_tag(oid);
+               struct tag *tag = lookup_tag(the_repository, oid);
                if (!parse_tag(tag) && tag->tag)
                        strbuf_addf(&desc, " %s", tag->tag);
        }
@@ -527,6 +561,42 @@ static int extend_abbrev_len(const struct object_id *oid, void *cb_data)
        return 0;
 }
 
+static void find_abbrev_len_for_midx(struct multi_pack_index *m,
+                                    struct min_abbrev_data *mad)
+{
+       int match = 0;
+       uint32_t num, first = 0;
+       struct object_id oid;
+       const struct object_id *mad_oid;
+
+       if (!m->num_objects)
+               return;
+
+       num = m->num_objects;
+       mad_oid = mad->oid;
+       match = bsearch_midx(mad_oid, m, &first);
+
+       /*
+        * first is now the position in the packfile where we would insert
+        * mad->hash if it does not exist (or the position of mad->hash if
+        * it does exist). Hence, we consider a maximum of two objects
+        * nearby for the abbreviation length.
+        */
+       mad->init_len = 0;
+       if (!match) {
+               if (nth_midxed_object_oid(&oid, m, first))
+                       extend_abbrev_len(&oid, mad);
+       } else if (first < num - 1) {
+               if (nth_midxed_object_oid(&oid, m, first + 1))
+                       extend_abbrev_len(&oid, mad);
+       }
+       if (first > 0) {
+               if (nth_midxed_object_oid(&oid, m, first - 1))
+                       extend_abbrev_len(&oid, mad);
+       }
+       mad->init_len = mad->cur_len;
+}
+
 static void find_abbrev_len_for_pack(struct packed_git *p,
                                     struct min_abbrev_data *mad)
 {
@@ -565,8 +635,11 @@ static void find_abbrev_len_for_pack(struct packed_git *p,
 
 static void find_abbrev_len_packed(struct min_abbrev_data *mad)
 {
+       struct multi_pack_index *m;
        struct packed_git *p;
 
+       for (m = get_multi_pack_index(the_repository); m; m = m->next)
+               find_abbrev_len_for_midx(m, mad);
        for (p = get_packed_git(the_repository); p; p = p->next)
                find_abbrev_len_for_pack(p, mad);
 }
@@ -576,6 +649,8 @@ int find_unique_abbrev_r(char *hex, const struct object_id *oid, int len)
        struct disambiguate_state ds;
        struct min_abbrev_data mad;
        struct object_id oid_ret;
+       const unsigned hexsz = the_hash_algo->hexsz;
+
        if (len < 0) {
                unsigned long count = approximate_object_count();
                /*
@@ -599,8 +674,8 @@ int find_unique_abbrev_r(char *hex, const struct object_id *oid, int len)
        }
 
        oid_to_hex_r(hex, oid);
-       if (len == GIT_SHA1_HEXSZ || !len)
-               return GIT_SHA1_HEXSZ;
+       if (len == hexsz || !len)
+               return hexsz;
 
        mad.init_len = len;
        mad.cur_len = len;
@@ -706,7 +781,7 @@ static int get_oid_basic(const char *str, int len, struct object_id *oid,
        int refs_found = 0;
        int at, reflog_len, nth_prior = 0;
 
-       if (len == GIT_SHA1_HEXSZ && !get_oid_hex(str, oid)) {
+       if (len == the_hash_algo->hexsz && !get_oid_hex(str, oid)) {
                if (warn_ambiguous_refs && warn_on_object_refname_ambiguity) {
                        refs_found = dwim_ref(str, len, &tmp_oid, &real_ref);
                        if (refs_found > 0) {
@@ -750,7 +825,7 @@ static int get_oid_basic(const char *str, int len, struct object_id *oid,
                int detached;
 
                if (interpret_nth_prior_checkout(str, len, &buf) > 0) {
-                       detached = (buf.len == GIT_SHA1_HEXSZ && !get_oid_hex(buf.buf, oid));
+                       detached = (buf.len == the_hash_algo->hexsz && !get_oid_hex(buf.buf, oid));
                        strbuf_release(&buf);
                        if (detached)
                                return 0;
@@ -844,7 +919,7 @@ static int get_parent(const char *name, int len,
 
        if (ret)
                return ret;
-       commit = lookup_commit_reference(&oid);
+       commit = lookup_commit_reference(the_repository, &oid);
        if (parse_commit(commit))
                return -1;
        if (!idx) {
@@ -872,7 +947,7 @@ static int get_nth_ancestor(const char *name, int len,
        ret = get_oid_1(name, len, &oid, GET_OID_COMMITTISH);
        if (ret)
                return ret;
-       commit = lookup_commit_reference(&oid);
+       commit = lookup_commit_reference(the_repository, &oid);
        if (!commit)
                return -1;
 
@@ -891,7 +966,7 @@ struct object *peel_to_type(const char *name, int namelen,
        if (name && !namelen)
                namelen = strlen(name);
        while (1) {
-               if (!o || (!o->parsed && !parse_object(&o->oid)))
+               if (!o || (!o->parsed && !parse_object(the_repository, &o->oid)))
                        return NULL;
                if (expected_type == OBJ_ANY || o->type == expected_type)
                        return o;
@@ -964,12 +1039,12 @@ static int peel_onion(const char *name, int len, struct object_id *oid,
        if (get_oid_1(name, sp - name - 2, &outer, lookup_flags))
                return -1;
 
-       o = parse_object(&outer);
+       o = parse_object(the_repository, &outer);
        if (!o)
                return -1;
        if (!expected_type) {
-               o = deref_tag(o, name, sp - name - 2);
-               if (!o || (!o->parsed && !parse_object(&o->oid)))
+               o = deref_tag(the_repository, o, name, sp - name - 2);
+               if (!o || (!o->parsed && !parse_object(the_repository, &o->oid)))
                        return -1;
                oidcpy(oid, &o->oid);
                return 0;
@@ -1096,11 +1171,12 @@ static int handle_one_ref(const char *path, const struct object_id *oid,
                          int flag, void *cb_data)
 {
        struct commit_list **list = cb_data;
-       struct object *object = parse_object(oid);
+       struct object *object = parse_object(the_repository, oid);
        if (!object)
                return 0;
        if (object->type == OBJ_TAG) {
-               object = deref_tag(object, path, strlen(path));
+               object = deref_tag(the_repository, object, path,
+                                  strlen(path));
                if (!object)
                        return 0;
        }
@@ -1142,7 +1218,7 @@ static int get_oid_oneline(const char *prefix, struct object_id *oid,
                int matches;
 
                commit = pop_most_recent_commit(&list, ONELINE_SEEN);
-               if (!parse_object(&commit->object.oid))
+               if (!parse_object(the_repository, &commit->object.oid))
                        continue;
                buf = get_commit_buffer(commit, NULL);
                p = strstr(buf, "\n\n");
@@ -1251,13 +1327,13 @@ int get_oid_mb(const char *name, struct object_id *oid)
        }
        if (st)
                return st;
-       one = lookup_commit_reference_gently(&oid_tmp, 0);
+       one = lookup_commit_reference_gently(the_repository, &oid_tmp, 0);
        if (!one)
                return -1;
 
        if (get_oid_committish(dots[3] ? (dots + 3) : "HEAD", &oid_tmp))
                return -1;
-       two = lookup_commit_reference_gently(&oid_tmp, 0);
+       two = lookup_commit_reference_gently(the_repository, &oid_tmp, 0);
        if (!two)
                return -1;
        mbs = get_merge_bases(one, two);
@@ -1650,6 +1726,7 @@ static int get_oid_with_context_1(const char *name,
                        struct commit_list *list = NULL;
 
                        for_each_ref(handle_one_ref, &list);
+                       head_ref(handle_one_ref, &list);
                        commit_list_sort_by_date(&list);
                        return get_oid_oneline(name + 2, oid, list);
                }