Skip to content

Commit ab48bc0

Browse files
committed
Merge branch 'ab/get-short-oid'
When a short hexadecimal string is used to name an object but there are multiple objects that share the string as the prefix of their names, the code lists these ambiguous candidates in a help message. These object names are now sorted according to their types for easier eyeballing. * ab/get-short-oid: get_short_oid: sort ambiguous objects by type, then SHA-1 sha1-name.c: move around the collect_ambiguous() function git-p4: change "commitish" typo to "committish" sha1-array.h: align function arguments sha1-name.c: remove stray newline
2 parents 54db5c0 + 5cc044e commit ab48bc0

File tree

6 files changed

+101
-21
lines changed

6 files changed

+101
-21
lines changed

Documentation/technical/api-oid-array.txt

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,13 +35,18 @@ Functions
3535
Free all memory associated with the array and return it to the
3636
initial, empty state.
3737

38+
`oid_array_for_each`::
39+
Iterate over each element of the list, executing the callback
40+
function for each one. Does not sort the list, so any custom
41+
hash order is retained. If the callback returns a non-zero
42+
value, the iteration ends immediately and the callback's
43+
return is propagated; otherwise, 0 is returned.
44+
3845
`oid_array_for_each_unique`::
39-
Efficiently iterate over each unique element of the list,
40-
executing the callback function for each one. If the array is
41-
not sorted, this function has the side effect of sorting it. If
42-
the callback returns a non-zero value, the iteration ends
43-
immediately and the callback's return is propagated; otherwise,
44-
0 is returned.
46+
Iterate over each unique element of the list in sorted order,
47+
but otherwise behave like `oid_array_for_each`. If the array
48+
is not sorted, this function has the side effect of sorting
49+
it.
4550

4651
Examples
4752
--------

git-p4.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2099,11 +2099,11 @@ def run(self, args):
20992099

21002100
commits = []
21012101
if self.master:
2102-
commitish = self.master
2102+
committish = self.master
21032103
else:
2104-
commitish = 'HEAD'
2104+
committish = 'HEAD'
21052105

2106-
for line in read_pipe_lines(["git", "rev-list", "--no-merges", "%s..%s" % (self.origin, commitish)]):
2106+
for line in read_pipe_lines(["git", "rev-list", "--no-merges", "%s..%s" % (self.origin, committish)]):
21072107
commits.append(line.strip())
21082108
commits.reverse()
21092109

sha1-array.c

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,26 @@ void oid_array_clear(struct oid_array *array)
4141
array->sorted = 0;
4242
}
4343

44+
45+
int oid_array_for_each(struct oid_array *array,
46+
for_each_oid_fn fn,
47+
void *data)
48+
{
49+
int i;
50+
51+
/* No oid_array_sort() here! See the api-oid-array.txt docs! */
52+
53+
for (i = 0; i < array->nr; i++) {
54+
int ret = fn(array->oid + i, data);
55+
if (ret)
56+
return ret;
57+
}
58+
return 0;
59+
}
60+
4461
int oid_array_for_each_unique(struct oid_array *array,
45-
for_each_oid_fn fn,
46-
void *data)
62+
for_each_oid_fn fn,
63+
void *data)
4764
{
4865
int i;
4966

sha1-array.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,11 @@ void oid_array_clear(struct oid_array *array);
1616

1717
typedef int (*for_each_oid_fn)(const struct object_id *oid,
1818
void *data);
19+
int oid_array_for_each(struct oid_array *array,
20+
for_each_oid_fn fn,
21+
void *data);
1922
int oid_array_for_each_unique(struct oid_array *array,
20-
for_each_oid_fn fn,
21-
void *data);
23+
for_each_oid_fn fn,
24+
void *data);
2225

2326
#endif /* SHA1_ARRAY_H */

sha1-name.c

Lines changed: 42 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -346,7 +346,6 @@ static int show_ambiguous_object(const struct object_id *oid, void *data)
346346
struct strbuf desc = STRBUF_INIT;
347347
int type;
348348

349-
350349
if (ds->fn && !ds->fn(oid, ds->cb_data))
351350
return 0;
352351

@@ -373,6 +372,40 @@ static int show_ambiguous_object(const struct object_id *oid, void *data)
373372
return 0;
374373
}
375374

375+
static int collect_ambiguous(const struct object_id *oid, void *data)
376+
{
377+
oid_array_append(data, oid);
378+
return 0;
379+
}
380+
381+
static int sort_ambiguous(const void *a, const void *b)
382+
{
383+
int a_type = oid_object_info(the_repository, a, NULL);
384+
int b_type = oid_object_info(the_repository, b, NULL);
385+
int a_type_sort;
386+
int b_type_sort;
387+
388+
/*
389+
* Sorts by hash within the same object type, just as
390+
* oid_array_for_each_unique() would do.
391+
*/
392+
if (a_type == b_type)
393+
return oidcmp(a, b);
394+
395+
/*
396+
* Between object types show tags, then commits, and finally
397+
* trees and blobs.
398+
*
399+
* The object_type enum is commit, tree, blob, tag, but we
400+
* want tag, commit, tree blob. Cleverly (perhaps too
401+
* cleverly) do that with modulus, since the enum assigns 1 to
402+
* commit, so tag becomes 0.
403+
*/
404+
a_type_sort = a_type % 4;
405+
b_type_sort = b_type % 4;
406+
return a_type_sort > b_type_sort ? 1 : -1;
407+
}
408+
376409
static int get_short_oid(const char *name, int len, struct object_id *oid,
377410
unsigned flags)
378411
{
@@ -404,6 +437,8 @@ static int get_short_oid(const char *name, int len, struct object_id *oid,
404437
status = finish_object_disambiguation(&ds, oid);
405438

406439
if (!quietly && (status == SHORT_NAME_AMBIGUOUS)) {
440+
struct oid_array collect = OID_ARRAY_INIT;
441+
407442
error(_("short SHA1 %s is ambiguous"), ds.hex_pfx);
408443

409444
/*
@@ -416,18 +451,17 @@ static int get_short_oid(const char *name, int len, struct object_id *oid,
416451
ds.fn = NULL;
417452

418453
advise(_("The candidates are:"));
419-
for_each_abbrev(ds.hex_pfx, show_ambiguous_object, &ds);
454+
for_each_abbrev(ds.hex_pfx, collect_ambiguous, &collect);
455+
QSORT(collect.oid, collect.nr, sort_ambiguous);
456+
457+
if (oid_array_for_each(&collect, show_ambiguous_object, &ds))
458+
BUG("show_ambiguous_object shouldn't return non-zero");
459+
oid_array_clear(&collect);
420460
}
421461

422462
return status;
423463
}
424464

425-
static int collect_ambiguous(const struct object_id *oid, void *data)
426-
{
427-
oid_array_append(data, oid);
428-
return 0;
429-
}
430-
431465
int for_each_abbrev(const char *prefix, each_abbrev_fn fn, void *cb_data)
432466
{
433467
struct oid_array collect = OID_ARRAY_INIT;

t/t1512-rev-parse-disambiguation.sh

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -361,4 +361,25 @@ test_expect_success 'core.disambiguate does not override context' '
361361
git -c core.disambiguate=committish rev-parse $sha1^{tree}
362362
'
363363

364+
test_expect_success C_LOCALE_OUTPUT 'ambiguous commits are printed by type first, then hash order' '
365+
test_must_fail git rev-parse 0000 2>stderr &&
366+
grep ^hint: stderr >hints &&
367+
grep 0000 hints >objects &&
368+
cat >expected <<-\EOF &&
369+
tag
370+
commit
371+
tree
372+
blob
373+
EOF
374+
awk "{print \$3}" <objects >objects.types &&
375+
uniq <objects.types >objects.types.uniq &&
376+
test_cmp expected objects.types.uniq &&
377+
for type in tag commit tree blob
378+
do
379+
grep $type objects >$type.objects &&
380+
sort $type.objects >$type.objects.sorted &&
381+
test_cmp $type.objects.sorted $type.objects
382+
done
383+
'
384+
364385
test_done

0 commit comments

Comments
 (0)