rev-parse --disambiguate=<prefix>
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>
Junio C Hamano committed
Jul 3, 2012 at 14:21 UTC
957d74062c1f0e92368aeda335e27d2d61f584f6
5 files changed
+78
-9
Documentation/git-rev-parse.txt
+6
@@ -101,6 +101,12 @@ OPTIONS
101
The option core.warnAmbiguousRefs is used to select the strict
102
abbreviation mode.
103
104
+--disambiguate=<prefix>::
105
+ Show every object whose name begins with the given prefix.
106
+ The <prefix> must be at least 4 hexadecimal digits long to
107
+ avoid listing each and every object in the repository by
108
+ mistake.
109
+
110
--all::
111
Show all refs found in `refs/`.
112
builtin/rev-parse.c
+10
@@ -195,6 +195,12 @@ static int anti_reference(const char *refname, const unsigned char *sha1, int fl
195
return 0;
196
}
197
198
+static int show_abbrev(const unsigned char *sha1, void *cb_data)
199
+{
200
+ show_rev(NORMAL, sha1, NULL);
201
+ return 0;
202
+}
203
+
204
static void show_datestring(const char *flag, const char *datestr)
205
{
206
static char buffer[100];
@@ -589,6 +595,10 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
595
for_each_ref(show_reference, NULL);
596
continue;
597
}
598
+ if (!prefixcmp(arg, "--disambiguate=")) {
599
+ for_each_abbrev(arg + 15, show_abbrev, NULL);
600
+ continue;
601
+ }
602
if (!strcmp(arg, "--bisect")) {
603
for_each_ref_in("refs/bisect/bad", show_reference, NULL);
604
for_each_ref_in("refs/bisect/good", anti_reference, NULL);
cache.h
+3
@@ -828,6 +828,9 @@ extern int get_sha1_blob(const char *str, unsigned char *sha1);
828
extern void maybe_die_on_misspelt_object_name(const char *name, const char *prefix);
829
extern int get_sha1_with_context(const char *str, unsigned flags, unsigned char *sha1, struct object_context *orc);
830
831
+typedef int each_abbrev_fn(const unsigned char *sha1, void *);
832
+extern int for_each_abbrev(const char *prefix, each_abbrev_fn, void *);
833
+
834
/*
835
* Try to read a SHA1 in hexadecimal format from the 40 characters
836
* starting at hex. Write the 20-byte result to sha1 in binary form.
sha1_name.c
+50
-9
@@ -20,10 +20,15 @@ struct disambiguate_state {
20
unsigned candidate_ok:1;
21
unsigned disambiguate_fn_used:1;
22
unsigned ambiguous:1;
23
+ unsigned always_call_fn:1;
24
};
25
26
static void update_candidates(struct disambiguate_state *ds, const unsigned char *current)
27
{
28
+ if (ds->always_call_fn) {
29
+ ds->ambiguous = ds->fn(current, ds->cb_data) ? 1 : 0;
30
+ return;
31
+ }
32
if (!ds->candidate_exists) {
33
/* this is the first candidate */
34
hashcpy(ds->candidate, current);
@@ -272,17 +277,12 @@ static int disambiguate_blob_only(const unsigned char *sha1, void *cb_data_unuse
277
return kind == OBJ_BLOB;
278
}
279
275
-static int get_short_sha1(const char *name, int len, unsigned char *sha1,
276
- unsigned flags)
280
+static int prepare_prefixes(const char *name, int len,
281
+ unsigned char *bin_pfx,
282
+ char *hex_pfx)
283
{
278
- int i, status;
279
- char hex_pfx[40];
280
- unsigned char bin_pfx[20];
281
- struct disambiguate_state ds;
282
- int quietly = !!(flags & GET_SHA1_QUIETLY);
284
+ int i;
285
284
- if (len < MINIMUM_ABBREV || len > 40)
285
- return -1;
286
hashclr(bin_pfx);
287
memset(hex_pfx, 'x', 40);
288
for (i = 0; i < len ;i++) {
@@ -303,6 +303,22 @@ static int get_short_sha1(const char *name, int len, unsigned char *sha1,
303
val <<= 4;
304
bin_pfx[i >> 1] |= val;
305
}
306
+ return 0;
307
+}
308
+
309
+static int get_short_sha1(const char *name, int len, unsigned char *sha1,
310
+ unsigned flags)
311
+{
312
+ int status;
313
+ char hex_pfx[40];
314
+ unsigned char bin_pfx[20];
315
+ struct disambiguate_state ds;
316
+ int quietly = !!(flags & GET_SHA1_QUIETLY);
317
+
318
+ if (len < MINIMUM_ABBREV || len > 40)
319
+ return -1;
320
+ if (prepare_prefixes(name, len, bin_pfx, hex_pfx) < 0)
321
+ return -1;
322
323
prepare_alt_odb();
324
@@ -327,6 +343,31 @@ static int get_short_sha1(const char *name, int len, unsigned char *sha1,
343
return status;
344
}
345
346
+
347
+int for_each_abbrev(const char *prefix, each_abbrev_fn fn, void *cb_data)
348
+{
349
+ char hex_pfx[40];
350
+ unsigned char bin_pfx[20];
351
+ struct disambiguate_state ds;
352
+ int len = strlen(prefix);
353
+
354
+ if (len < MINIMUM_ABBREV || len > 40)
355
+ return -1;
356
+ if (prepare_prefixes(prefix, len, bin_pfx, hex_pfx) < 0)
357
+ return -1;
358
+
359
+ prepare_alt_odb();
360
+
361
+ memset(&ds, 0, sizeof(ds));
362
+ ds.always_call_fn = 1;
363
+ ds.cb_data = cb_data;
364
+ ds.fn = fn;
365
+
366
+ find_short_object_filename(len, hex_pfx, &ds);
367
+ find_short_packed_object(len, bin_pfx, &ds);
368
+ return ds.ambiguous;
369
+}
370
+
371
const char *find_unique_abbrev(const unsigned char *sha1, int len)
372
{
373
int status, exists;
t/t1512-rev-parse-disambiguation.sh
+9
@@ -252,4 +252,13 @@ test_expect_success 'ambiguous commit-ish' '
252
test_must_fail git log 000000000...
253
'
254
255
+test_expect_success 'rev-parse --disambiguate' '
256
+ # The test creates 16 objects that share the prefix and two
257
+ # commits created by commit-tree in earlier tests do not share
258
+ # the prefix.
259
+ git rev-parse --disambiguate=000000000 >actual &&
260
+ test "$(wc -l <actual)" = 16 &&
261
+ test "$(sed -e "s/^\(.........\).*/\1/" actual | sort -u)" = 000000000
262
+'
263
+
264
test_done