rev-parse --disambiguate=<prefix>
authorJunio C Hamano <gitster@pobox.com>
Tue, 3 Jul 2012 21:21:59 +0000 (14:21 -0700)
committerJunio C Hamano <gitster@pobox.com>
Mon, 9 Jul 2012 23:42:23 +0000 (16:42 -0700)
The new option allows you to feed an ambiguous prefix and enumerate
all the objects that share it as a prefix of their object names.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
Documentation/git-rev-parse.txt
builtin/rev-parse.c
cache.h
sha1_name.c
t/t1512-rev-parse-disambiguation.sh

index 8023dc086d044d0ac2cab685ac1c8b050adda95b..8d90863ee3aa43c24170abd3118f4e00e5d4a208 100644 (file)
@@ -101,6 +101,12 @@ OPTIONS
        The option core.warnAmbiguousRefs is used to select the strict
        abbreviation mode.
 
+--disambiguate=<prefix>::
+       Show every object whose name begins with the given prefix.
+       The <prefix> must be at least 4 hexadecimal digits long to
+       avoid listing each and every object in the repository by
+       mistake.
+
 --all::
        Show all refs found in `refs/`.
 
index 16b98b5b903129faa5547f91e39f5ee5a6c98e6f..d85b8a6a6d0c14ac992ef9e3c4aee7490c34e76f 100644 (file)
@@ -195,6 +195,12 @@ static int anti_reference(const char *refname, const unsigned char *sha1, int fl
        return 0;
 }
 
+static int show_abbrev(const unsigned char *sha1, void *cb_data)
+{
+       show_rev(NORMAL, sha1, NULL);
+       return 0;
+}
+
 static void show_datestring(const char *flag, const char *datestr)
 {
        static char buffer[100];
@@ -589,6 +595,10 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
                                for_each_ref(show_reference, NULL);
                                continue;
                        }
+                       if (!prefixcmp(arg, "--disambiguate=")) {
+                               for_each_abbrev(arg + 15, show_abbrev, NULL);
+                               continue;
+                       }
                        if (!strcmp(arg, "--bisect")) {
                                for_each_ref_in("refs/bisect/bad", show_reference, NULL);
                                for_each_ref_in("refs/bisect/good", anti_reference, NULL);
diff --git a/cache.h b/cache.h
index c8d6406bca178d7d203bdf4f7fac19873e6c3bfc..63388780a008236b3888af553007cc4329ec32b1 100644 (file)
--- a/cache.h
+++ b/cache.h
@@ -828,6 +828,9 @@ extern int get_sha1_blob(const char *str, unsigned char *sha1);
 extern void maybe_die_on_misspelt_object_name(const char *name, const char *prefix);
 extern int get_sha1_with_context(const char *str, unsigned flags, unsigned char *sha1, struct object_context *orc);
 
+typedef int each_abbrev_fn(const unsigned char *sha1, void *);
+extern int for_each_abbrev(const char *prefix, each_abbrev_fn, void *);
+
 /*
  * Try to read a SHA1 in hexadecimal format from the 40 characters
  * starting at hex.  Write the 20-byte result to sha1 in binary form.
index 18fac921dd7bb067b2c21d1ad51df3818bcdf261..8bc20c54b17d4f1c08b4c7f8d8f38bb6a9e25011 100644 (file)
@@ -20,10 +20,15 @@ struct disambiguate_state {
        unsigned candidate_ok:1;
        unsigned disambiguate_fn_used:1;
        unsigned ambiguous:1;
+       unsigned always_call_fn:1;
 };
 
 static void update_candidates(struct disambiguate_state *ds, const unsigned char *current)
 {
+       if (ds->always_call_fn) {
+               ds->ambiguous = ds->fn(current, ds->cb_data) ? 1 : 0;
+               return;
+       }
        if (!ds->candidate_exists) {
                /* this is the first candidate */
                hashcpy(ds->candidate, current);
@@ -272,17 +277,12 @@ static int disambiguate_blob_only(const unsigned char *sha1, void *cb_data_unuse
        return kind == OBJ_BLOB;
 }
 
-static int get_short_sha1(const char *name, int len, unsigned char *sha1,
-                         unsigned flags)
+static int prepare_prefixes(const char *name, int len,
+                           unsigned char *bin_pfx,
+                           char *hex_pfx)
 {
-       int i, status;
-       char hex_pfx[40];
-       unsigned char bin_pfx[20];
-       struct disambiguate_state ds;
-       int quietly = !!(flags & GET_SHA1_QUIETLY);
+       int i;
 
-       if (len < MINIMUM_ABBREV || len > 40)
-               return -1;
        hashclr(bin_pfx);
        memset(hex_pfx, 'x', 40);
        for (i = 0; i < len ;i++) {
@@ -303,6 +303,22 @@ static int get_short_sha1(const char *name, int len, unsigned char *sha1,
                        val <<= 4;
                bin_pfx[i >> 1] |= val;
        }
+       return 0;
+}
+
+static int get_short_sha1(const char *name, int len, unsigned char *sha1,
+                         unsigned flags)
+{
+       int status;
+       char hex_pfx[40];
+       unsigned char bin_pfx[20];
+       struct disambiguate_state ds;
+       int quietly = !!(flags & GET_SHA1_QUIETLY);
+
+       if (len < MINIMUM_ABBREV || len > 40)
+               return -1;
+       if (prepare_prefixes(name, len, bin_pfx, hex_pfx) < 0)
+               return -1;
 
        prepare_alt_odb();
 
@@ -327,6 +343,31 @@ static int get_short_sha1(const char *name, int len, unsigned char *sha1,
        return status;
 }
 
+
+int for_each_abbrev(const char *prefix, each_abbrev_fn fn, void *cb_data)
+{
+       char hex_pfx[40];
+       unsigned char bin_pfx[20];
+       struct disambiguate_state ds;
+       int len = strlen(prefix);
+
+       if (len < MINIMUM_ABBREV || len > 40)
+               return -1;
+       if (prepare_prefixes(prefix, len, bin_pfx, hex_pfx) < 0)
+               return -1;
+
+       prepare_alt_odb();
+
+       memset(&ds, 0, sizeof(ds));
+       ds.always_call_fn = 1;
+       ds.cb_data = cb_data;
+       ds.fn = fn;
+
+       find_short_object_filename(len, hex_pfx, &ds);
+       find_short_packed_object(len, bin_pfx, &ds);
+       return ds.ambiguous;
+}
+
 const char *find_unique_abbrev(const unsigned char *sha1, int len)
 {
        int status, exists;
index 6de3cb0c920d8d2943c2e0f1c05eb1af4cd182fe..3ed7558c1ecd074504c6a8699bd599033b1ba84d 100755 (executable)
@@ -252,4 +252,13 @@ test_expect_success 'ambiguous commit-ish' '
        test_must_fail git log 000000000...
 '
 
+test_expect_success 'rev-parse --disambiguate' '
+       # The test creates 16 objects that share the prefix and two
+       # commits created by commit-tree in earlier tests do not share
+       # the prefix.
+       git rev-parse --disambiguate=000000000 >actual &&
+       test "$(wc -l <actual)" = 16 &&
+       test "$(sed -e "s/^\(.........\).*/\1/" actual | sort -u)" = 000000000
+'
+
 test_done