Eric Blake <ebb9@xxxxxxx> writes: > What is really needed is a method in git where once a SHA1 prefix becomes > ambiguous, you can still easily choose to resolve the ambiguity in favor > of the oldest commit that matches the prefix. "Oldest commit" does not make much sense in a distributed environment. In git.git, I tend to have many objects in my primary repository that nobody else has, and other people would probably have many objects that I do not have. "Oldest among the ones reachable from these heads" and specifying only the ones that are publicly available may have some value, though. I agree that we would want a reverse operation of find_unique_abbrev(); here is a quick and dirty one. $ git rev-parse --disamb=aba1 | git name-rev --stdin aba14750f47700b8923b411a9348fb251b788967 tree aba15f7f592c302196401d17a42c772d744555b4 (tags/gitgui-0.9.3~5) commit aba16b190c54a107521801ad77ab66586553ba69 blob aba170cdb4874b72dd619e6f7bbc13c33295f831 (tags/v1.5.2^0) commit It is very tempting to say that we should favor commits over other types, but at the "extended sha1 expression" level, we traditionally haven't favored one type over others, so it has to wait until 1.6.0 at least. --- builtin-rev-parse.c | 13 +++++++++++++ cache.h | 3 +++ sha1_name.c | 37 +++++++++++++++++++++++++++++++++++++ 3 files changed, 53 insertions(+), 0 deletions(-) diff --git a/builtin-rev-parse.c b/builtin-rev-parse.c index 0351d54..c64b43e 100644 --- a/builtin-rev-parse.c +++ b/builtin-rev-parse.c @@ -365,6 +365,15 @@ static int cmd_parseopt(int argc, const char **argv, const char *prefix) return 0; } +static void disamb_show(const unsigned char *sha1, void *cb_data) +{ + char *orig = cb_data; + enum object_type type; + + type = sha1_object_info(sha1, NULL); + printf("%s %s %s\n", sha1_to_hex(sha1), typename(type), orig); +} + int cmd_rev_parse(int argc, const char **argv, const char *prefix) { int i, as_is = 0, verify = 0; @@ -548,6 +557,10 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix) show_datestring("--min-age=", arg+8); continue; } + if (!prefixcmp(arg, "--disamb=")) { + for_each_sha1(arg + 9, disamb_show, NULL); + continue; + } if (show_flag(arg) && verify) die("Needed a single revision"); continue; diff --git a/cache.h b/cache.h index 2a1e7ec..fa15140 100644 --- a/cache.h +++ b/cache.h @@ -454,6 +454,9 @@ extern char *sha1_file_name(const unsigned char *sha1); extern char *sha1_pack_name(const unsigned char *sha1); extern char *sha1_pack_index_name(const unsigned char *sha1); extern const char *find_unique_abbrev(const unsigned char *sha1, int); +typedef void for_each_sha1_fn(const unsigned char *sha1, void *); +int for_each_sha1(const char *prefix, for_each_sha1_fn fn, void *cb_data); + extern const unsigned char null_sha1[20]; static inline int is_null_sha1(const unsigned char *sha1) { diff --git a/sha1_name.c b/sha1_name.c index 8b6c76f..2703831 100644 --- a/sha1_name.c +++ b/sha1_name.c @@ -213,6 +213,43 @@ const char *find_unique_abbrev(const unsigned char *sha1, int len) return hex; } +static int for_each_sha1_rec(char *prefix, int len, for_each_sha1_fn fn, void *cb_data) +{ + unsigned char sha1[20]; + int status, i, found; + + if (40 <= len) + return 0; + status = get_short_sha1(prefix, len, sha1, 1); + if (status == SHORT_NAME_NOT_FOUND) + return 0; + if (!status) { + fn(sha1, cb_data); + return 1; + } + /* Ambiguous */ + found = 0; + for (i = 0; i < 16; i++) { + prefix[len] = "0123456789abcdef"[i]; + prefix[len+1] = '\0'; + found += for_each_sha1_rec(prefix, len + 1, fn, cb_data); + } + return found; +} + +int for_each_sha1(const char *prefix, for_each_sha1_fn fn, void *cb_data) +{ + int len; + char hex[41]; + + len = strlen(prefix); + if (40 <= len) + return 0; + memcpy(hex, prefix, len+1); + + return for_each_sha1_rec(hex, len, fn, cb_data); +} + static int ambiguous_path(const char *path, int len) { int slash = 1; -- 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