On Mon, Apr 13, 2009 at 12:51:21PM -0700, Junio C Hamano wrote: > That is one possibility. Another is: > > git reset --hard mester > > (and you have ./mester file in the work tree) and in that case the user > definitely didn't want to do any checkout. > > I wonder if you can tell these cases apart, and also if this (not just > telling these apart, but what your patch adds) is worth additional You could always guess based on the existing refs: --- diff --git a/builtin-reset.c b/builtin-reset.c index c0cb915..803957d 100644 --- a/builtin-reset.c +++ b/builtin-reset.c @@ -243,8 +243,11 @@ int cmd_reset(int argc, const char **argv, const char *prefix) } } - if (get_sha1(rev, sha1)) - die("Failed to resolve '%s' as a valid ref.", rev); + if (get_sha1(rev, sha1)) { + error("Failed to resolve '%s' as a valid ref.", rev); + probable_refs_print(rev); + return 1; + } commit = lookup_commit_reference(sha1); if (!commit) @@ -257,6 +260,11 @@ int cmd_reset(int argc, const char **argv, const char *prefix) if (i < argc) { if (reset_type == MIXED) warning("--mixed option is deprecated with paths."); + else if (reset_type == HARD) { + error("Cannot do hard reset with paths."); + probable_refs_print(argv[i]); + return 1; + } else if (reset_type != NONE) die("Cannot do %s reset with paths.", reset_type_names[reset_type]); diff --git a/refs.c b/refs.c index 82afb87..bad7e2f 100644 --- a/refs.c +++ b/refs.c @@ -3,6 +3,8 @@ #include "object.h" #include "tag.h" #include "dir.h" +#include "levenshtein.h" +#include "string-list.h" /* ISSYMREF=01 and ISPACKED=02 are public interfaces */ #define REF_KNOWS_PEELED 04 @@ -750,9 +752,8 @@ int check_ref_format(const char *ref) } } -const char *prettify_ref(const struct ref *ref) +static const char *prettify_refname(const char *name) { - const char *name = ref->name; return name + ( !prefixcmp(name, "refs/heads/") ? 11 : !prefixcmp(name, "refs/tags/") ? 10 : @@ -760,6 +761,11 @@ const char *prettify_ref(const struct ref *ref) 0); } +const char *prettify_ref(const struct ref *ref) +{ + return prettify_refname(ref->name); +} + const char *ref_rev_parse_rules[] = { "%.*s", "refs/%.*s", @@ -1756,3 +1762,74 @@ char *shorten_unambiguous_ref(const char *ref) free(short_name); return xstrdup(ref); } + +struct probable_refs_data { + const char *s; + struct string_list *out; +}; + +static void probable_refs_append(struct probable_refs_data *d, const char *s) +{ + struct string_list_item *i = string_list_append(s, d->out); + i->util = (void *)levenshtein(d->s, s, 0, 2, 1, 4); +} + +static int probable_refs_cb(const char *refname, const unsigned char *sha1, + int flag, void *data) +{ + const char *p = prettify_refname(refname); + probable_refs_append(data, refname); + if (p != refname) + probable_refs_append(data, p); + return 1; +} + +static int util_compare(const void *va, const void *vb) +{ + const struct string_list_item *a = va, *b = vb; + return a->util - b->util; +} + +void probable_refs(const char *s, struct string_list *out) +{ + struct probable_refs_data d; + int i, j; + + memset(out, 0, sizeof(*out)); + out->strdup_strings = 1; + d.s = s; + d.out = out; + for_each_ref(probable_refs_cb, &d); + + if (!out->nr) + return; + + qsort(out->items, out->nr, sizeof(*out->items), util_compare); + /* Arbitrary cutoff at distance '5'. The first is the best match, but + * there may be others which are equally good */ + for (i = 0; i < out->nr; i++) + if ((int)out->items[i].util > 5 || + out->items[i].util > out->items[0].util) + break; + /* truncate the list to i items */ + for (j = i; j < out->nr; j++) + free(out->items[j].string); + out->nr = i; +} + +void probable_refs_print(const char *name) +{ + struct string_list s; + int i; + + probable_refs(name, &s); + if (!s.nr) + return; + + fprintf(stderr, "\nDid you mean %s?\n", + s.nr < 2 ? "this" : "one of these"); + for (i = 0; i < s.nr; i++) + fprintf(stderr, "\t%s\n", s.items[i].string); + + string_list_clear(&s, 0); +} diff --git a/refs.h b/refs.h index 50abbbb..586bfab 100644 --- a/refs.h +++ b/refs.h @@ -95,4 +95,6 @@ int update_ref(const char *action, const char *refname, const unsigned char *sha1, const unsigned char *oldval, int flags, enum action_on_err onerr); +void probable_refs_print(const char *name); + #endif /* REFS_H */ And yes, I am joking. -Peff -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html