abbrev: prepare for new world order
[gitweb.git] / sha1_name.c
index f7e388490a3647172ddb8f1bb21db56d67c61e66..3b647fd7cf79127cfa6f684836e387568a87c310 100644 (file)
@@ -283,6 +283,36 @@ static int disambiguate_blob_only(const unsigned char *sha1, void *cb_data_unuse
        return kind == OBJ_BLOB;
 }
 
+static disambiguate_hint_fn default_disambiguate_hint;
+
+int set_disambiguate_hint_config(const char *var, const char *value)
+{
+       static const struct {
+               const char *name;
+               disambiguate_hint_fn fn;
+       } hints[] = {
+               { "none", NULL },
+               { "commit", disambiguate_commit_only },
+               { "committish", disambiguate_committish_only },
+               { "tree", disambiguate_tree_only },
+               { "treeish", disambiguate_treeish_only },
+               { "blob", disambiguate_blob_only }
+       };
+       int i;
+
+       if (!value)
+               return config_error_nonbool(var);
+
+       for (i = 0; i < ARRAY_SIZE(hints); i++) {
+               if (!strcasecmp(value, hints[i].name)) {
+                       default_disambiguate_hint = hints[i].fn;
+                       return 0;
+               }
+       }
+
+       return error("unknown hint type for '%s': %s", var, value);
+}
+
 static int init_object_disambiguation(const char *name, int len,
                                      struct disambiguate_state *ds)
 {
@@ -318,6 +348,38 @@ static int init_object_disambiguation(const char *name, int len,
        return 0;
 }
 
+static int show_ambiguous_object(const unsigned char *sha1, void *data)
+{
+       const struct disambiguate_state *ds = data;
+       struct strbuf desc = STRBUF_INIT;
+       int type;
+
+       if (ds->fn && !ds->fn(sha1, ds->cb_data))
+               return 0;
+
+       type = sha1_object_info(sha1, NULL);
+       if (type == OBJ_COMMIT) {
+               struct commit *commit = lookup_commit(sha1);
+               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(sha1);
+               if (!parse_tag(tag) && tag->tag)
+                       strbuf_addf(&desc, " %s", tag->tag);
+       }
+
+       advise("  %s %s%s",
+              find_unique_abbrev(sha1, DEFAULT_ABBREV),
+              typename(type) ? typename(type) : "unknown type",
+              desc.buf);
+
+       strbuf_release(&desc);
+       return 0;
+}
+
 static int get_short_sha1(const char *name, int len, unsigned char *sha1,
                          unsigned flags)
 {
@@ -341,13 +403,29 @@ static int get_short_sha1(const char *name, int len, unsigned char *sha1,
                ds.fn = disambiguate_treeish_only;
        else if (flags & GET_SHA1_BLOB)
                ds.fn = disambiguate_blob_only;
+       else
+               ds.fn = default_disambiguate_hint;
 
        find_short_object_filename(&ds);
        find_short_packed_object(&ds);
        status = finish_object_disambiguation(&ds, sha1);
 
-       if (!quietly && (status == SHORT_NAME_AMBIGUOUS))
-               return error(_("short SHA1 %s is ambiguous"), ds.hex_pfx);
+       if (!quietly && (status == SHORT_NAME_AMBIGUOUS)) {
+               error(_("short SHA1 %s is ambiguous"), ds.hex_pfx);
+
+               /*
+                * We may still have ambiguity if we simply saw a series of
+                * candidates that did not satisfy our hint function. In
+                * that case, we still want to show them, so disable the hint
+                * function entirely.
+                */
+               if (!ds.ambiguous)
+                       ds.fn = NULL;
+
+               advise(_("The candidates are:"));
+               for_each_abbrev(ds.hex_pfx, show_ambiguous_object, &ds);
+       }
+
        return status;
 }