Merge branch 'ab/get-short-oid'
authorJunio C Hamano <gitster@pobox.com>
Wed, 30 May 2018 05:04:11 +0000 (14:04 +0900)
committerJunio C Hamano <gitster@pobox.com>
Wed, 30 May 2018 05:04:11 +0000 (14:04 +0900)
When a short hexadecimal string is used to name an object but there
are multiple objects that share the string as the prefix of their
names, the code lists these ambiguous candidates in a help message.
These object names are now sorted according to their types for
easier eyeballing.

* ab/get-short-oid:
get_short_oid: sort ambiguous objects by type, then SHA-1
sha1-name.c: move around the collect_ambiguous() function
git-p4: change "commitish" typo to "committish"
sha1-array.h: align function arguments
sha1-name.c: remove stray newline

1  2 
sha1-name.c
diff --combined sha1-name.c
index cc0028ed19d13da0162c42c44bb2dc58c675e30e,46d8b1afa65f174132dffeea1c24abae37f580df..60d9ef3c7e7108c859647656972c171cce4e7d7f
@@@ -223,7 -223,7 +223,7 @@@ static int finish_object_disambiguation
  
  static int disambiguate_commit_only(const struct object_id *oid, void *cb_data_unused)
  {
 -      int kind = oid_object_info(oid, NULL);
 +      int kind = oid_object_info(the_repository, oid, NULL);
        return kind == OBJ_COMMIT;
  }
  
@@@ -232,7 -232,7 +232,7 @@@ static int disambiguate_committish_only
        struct object *obj;
        int kind;
  
 -      kind = oid_object_info(oid, NULL);
 +      kind = oid_object_info(the_repository, oid, NULL);
        if (kind == OBJ_COMMIT)
                return 1;
        if (kind != OBJ_TAG)
  
  static int disambiguate_tree_only(const struct object_id *oid, void *cb_data_unused)
  {
 -      int kind = oid_object_info(oid, NULL);
 +      int kind = oid_object_info(the_repository, oid, NULL);
        return kind == OBJ_TREE;
  }
  
@@@ -256,7 -256,7 +256,7 @@@ static int disambiguate_treeish_only(co
        struct object *obj;
        int kind;
  
 -      kind = oid_object_info(oid, NULL);
 +      kind = oid_object_info(the_repository, oid, NULL);
        if (kind == OBJ_TREE || kind == OBJ_COMMIT)
                return 1;
        if (kind != OBJ_TAG)
  
  static int disambiguate_blob_only(const struct object_id *oid, void *cb_data_unused)
  {
 -      int kind = oid_object_info(oid, NULL);
 +      int kind = oid_object_info(the_repository, oid, NULL);
        return kind == OBJ_BLOB;
  }
  
@@@ -346,11 -346,10 +346,10 @@@ static int show_ambiguous_object(const 
        struct strbuf desc = STRBUF_INIT;
        int type;
  
        if (ds->fn && !ds->fn(oid, ds->cb_data))
                return 0;
  
 -      type = oid_object_info(oid, NULL);
 +      type = oid_object_info(the_repository, oid, NULL);
        if (type == OBJ_COMMIT) {
                struct commit *commit = lookup_commit(oid);
                if (commit) {
        return 0;
  }
  
 -      int a_type = oid_object_info(a, NULL);
 -      int b_type = oid_object_info(b, NULL);
+ static int collect_ambiguous(const struct object_id *oid, void *data)
+ {
+       oid_array_append(data, oid);
+       return 0;
+ }
+ static int sort_ambiguous(const void *a, const void *b)
+ {
++      int a_type = oid_object_info(the_repository, a, NULL);
++      int b_type = oid_object_info(the_repository, b, NULL);
+       int a_type_sort;
+       int b_type_sort;
+       /*
+        * Sorts by hash within the same object type, just as
+        * oid_array_for_each_unique() would do.
+        */
+       if (a_type == b_type)
+               return oidcmp(a, b);
+       /*
+        * Between object types show tags, then commits, and finally
+        * trees and blobs.
+        *
+        * The object_type enum is commit, tree, blob, tag, but we
+        * want tag, commit, tree blob. Cleverly (perhaps too
+        * cleverly) do that with modulus, since the enum assigns 1 to
+        * commit, so tag becomes 0.
+        */
+       a_type_sort = a_type % 4;
+       b_type_sort = b_type % 4;
+       return a_type_sort > b_type_sort ? 1 : -1;
+ }
  static int get_short_oid(const char *name, int len, struct object_id *oid,
                          unsigned flags)
  {
                return -1;
  
        if (HAS_MULTI_BITS(flags & GET_OID_DISAMBIGUATORS))
 -              die("BUG: multiple get_short_oid disambiguator flags");
 +              BUG("multiple get_short_oid disambiguator flags");
  
        if (flags & GET_OID_COMMIT)
                ds.fn = disambiguate_commit_only;
        status = finish_object_disambiguation(&ds, oid);
  
        if (!quietly && (status == SHORT_NAME_AMBIGUOUS)) {
+               struct oid_array collect = OID_ARRAY_INIT;
                error(_("short SHA1 %s is ambiguous"), ds.hex_pfx);
  
                /*
                        ds.fn = NULL;
  
                advise(_("The candidates are:"));
-               for_each_abbrev(ds.hex_pfx, show_ambiguous_object, &ds);
+               for_each_abbrev(ds.hex_pfx, collect_ambiguous, &collect);
+               QSORT(collect.oid, collect.nr, sort_ambiguous);
+               if (oid_array_for_each(&collect, show_ambiguous_object, &ds))
+                       BUG("show_ambiguous_object shouldn't return non-zero");
+               oid_array_clear(&collect);
        }
  
        return status;
  }
  
- static int collect_ambiguous(const struct object_id *oid, void *data)
- {
-       oid_array_append(data, oid);
-       return 0;
- }
  int for_each_abbrev(const char *prefix, each_abbrev_fn fn, void *cb_data)
  {
        struct oid_array collect = OID_ARRAY_INIT;
@@@ -864,7 -898,7 +898,7 @@@ struct object *peel_to_type(const char 
                if (o->type == OBJ_TAG)
                        o = ((struct tag*) o)->tagged;
                else if (o->type == OBJ_COMMIT)
 -                      o = &(((struct commit *) o)->tree->object);
 +                      o = &(get_commit_tree(((struct commit *)o))->object);
                else {
                        if (name)
                                error("%.*s: expected %s type, but the object "
@@@ -1685,8 -1719,8 +1719,8 @@@ static int get_oid_with_context_1(cons
                        if (new_filename)
                                filename = new_filename;
                        if (flags & GET_OID_FOLLOW_SYMLINKS) {
 -                              ret = get_tree_entry_follow_symlinks(tree_oid.hash,
 -                                      filename, oid->hash, &oc->symlink_path,
 +                              ret = get_tree_entry_follow_symlinks(&tree_oid,
 +                                      filename, oid, &oc->symlink_path,
                                        &oc->mode);
                        } else {
                                ret = get_tree_entry(&tree_oid, filename, oid,
                                                                   name, len);
                                }
                        }
 -                      hashcpy(oc->tree, tree_oid.hash);
                        if (flags & GET_OID_RECORD_PATH)
                                oc->path = xstrdup(filename);
  
@@@ -1728,6 -1763,6 +1762,6 @@@ void maybe_die_on_misspelt_object_name(
  int get_oid_with_context(const char *str, unsigned flags, struct object_id *oid, struct object_context *oc)
  {
        if (flags & GET_OID_FOLLOW_SYMLINKS && flags & GET_OID_ONLY_TO_DIE)
 -              die("BUG: incompatible flags for get_sha1_with_context");
 +              BUG("incompatible flags for get_sha1_with_context");
        return get_oid_with_context_1(str, flags, NULL, oid, oc);
  }