summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJunio C Hamano <gitster@pobox.com>2018-05-30 05:04:11 (GMT)
committerJunio C Hamano <gitster@pobox.com>2018-05-30 05:04:11 (GMT)
commitab48bc0aeadd7f6b661bc125a913e1c7d145cd5e (patch)
tree98bbbcf8dd2e210de83c71b2aecc508e9e7ba395
parent54db5c0e1edf0d92bd474f515fab349b98c18a24 (diff)
parent5cc044e02571e93048160d94e64fe6d8dd96597e (diff)
downloadgit-ab48bc0aeadd7f6b661bc125a913e1c7d145cd5e.zip
git-ab48bc0aeadd7f6b661bc125a913e1c7d145cd5e.tar.gz
git-ab48bc0aeadd7f6b661bc125a913e1c7d145cd5e.tar.bz2
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
-rw-r--r--Documentation/technical/api-oid-array.txt17
-rwxr-xr-xgit-p4.py6
-rw-r--r--sha1-array.c21
-rw-r--r--sha1-array.h7
-rw-r--r--sha1-name.c50
-rwxr-xr-xt/t1512-rev-parse-disambiguation.sh21
6 files changed, 101 insertions, 21 deletions
diff --git a/Documentation/technical/api-oid-array.txt b/Documentation/technical/api-oid-array.txt
index b0c11f8..9febfb1 100644
--- a/Documentation/technical/api-oid-array.txt
+++ b/Documentation/technical/api-oid-array.txt
@@ -35,13 +35,18 @@ Functions
Free all memory associated with the array and return it to the
initial, empty state.
+`oid_array_for_each`::
+ Iterate over each element of the list, executing the callback
+ function for each one. Does not sort the list, so any custom
+ hash order is retained. If the callback returns a non-zero
+ value, the iteration ends immediately and the callback's
+ return is propagated; otherwise, 0 is returned.
+
`oid_array_for_each_unique`::
- Efficiently iterate over each unique element of the list,
- executing the callback function for each one. If the array is
- not sorted, this function has the side effect of sorting it. If
- the callback returns a non-zero value, the iteration ends
- immediately and the callback's return is propagated; otherwise,
- 0 is returned.
+ Iterate over each unique element of the list in sorted order,
+ but otherwise behave like `oid_array_for_each`. If the array
+ is not sorted, this function has the side effect of sorting
+ it.
Examples
--------
diff --git a/git-p4.py b/git-p4.py
index 7bb9cad..1afa87c 100755
--- a/git-p4.py
+++ b/git-p4.py
@@ -2099,11 +2099,11 @@ class P4Submit(Command, P4UserMap):
commits = []
if self.master:
- commitish = self.master
+ committish = self.master
else:
- commitish = 'HEAD'
+ committish = 'HEAD'
- for line in read_pipe_lines(["git", "rev-list", "--no-merges", "%s..%s" % (self.origin, commitish)]):
+ for line in read_pipe_lines(["git", "rev-list", "--no-merges", "%s..%s" % (self.origin, committish)]):
commits.append(line.strip())
commits.reverse()
diff --git a/sha1-array.c b/sha1-array.c
index 838b3bf..265941f 100644
--- a/sha1-array.c
+++ b/sha1-array.c
@@ -41,9 +41,26 @@ void oid_array_clear(struct oid_array *array)
array->sorted = 0;
}
+
+int oid_array_for_each(struct oid_array *array,
+ for_each_oid_fn fn,
+ void *data)
+{
+ int i;
+
+ /* No oid_array_sort() here! See the api-oid-array.txt docs! */
+
+ for (i = 0; i < array->nr; i++) {
+ int ret = fn(array->oid + i, data);
+ if (ret)
+ return ret;
+ }
+ return 0;
+}
+
int oid_array_for_each_unique(struct oid_array *array,
- for_each_oid_fn fn,
- void *data)
+ for_each_oid_fn fn,
+ void *data)
{
int i;
diff --git a/sha1-array.h b/sha1-array.h
index 04b0756..232bf95 100644
--- a/sha1-array.h
+++ b/sha1-array.h
@@ -16,8 +16,11 @@ void oid_array_clear(struct oid_array *array);
typedef int (*for_each_oid_fn)(const struct object_id *oid,
void *data);
+int oid_array_for_each(struct oid_array *array,
+ for_each_oid_fn fn,
+ void *data);
int oid_array_for_each_unique(struct oid_array *array,
- for_each_oid_fn fn,
- void *data);
+ for_each_oid_fn fn,
+ void *data);
#endif /* SHA1_ARRAY_H */
diff --git a/sha1-name.c b/sha1-name.c
index cc0028e..60d9ef3 100644
--- a/sha1-name.c
+++ b/sha1-name.c
@@ -346,7 +346,6 @@ static int show_ambiguous_object(const struct object_id *oid, void *data)
struct strbuf desc = STRBUF_INIT;
int type;
-
if (ds->fn && !ds->fn(oid, ds->cb_data))
return 0;
@@ -373,6 +372,40 @@ static int show_ambiguous_object(const struct object_id *oid, void *data)
return 0;
}
+static int collect_ambiguous(const struct object_id *oid, void *data)
+{
+ oid_array_append(data, oid);
+ return 0;
+}
+
+static int sort_ambiguous(const void *a, const void *b)
+{
+ int a_type = oid_object_info(the_repository, a, NULL);
+ int b_type = oid_object_info(the_repository, b, NULL);
+ int a_type_sort;
+ int b_type_sort;
+
+ /*
+ * Sorts by hash within the same object type, just as
+ * oid_array_for_each_unique() would do.
+ */
+ if (a_type == b_type)
+ return oidcmp(a, b);
+
+ /*
+ * Between object types show tags, then commits, and finally
+ * trees and blobs.
+ *
+ * The object_type enum is commit, tree, blob, tag, but we
+ * want tag, commit, tree blob. Cleverly (perhaps too
+ * cleverly) do that with modulus, since the enum assigns 1 to
+ * commit, so tag becomes 0.
+ */
+ a_type_sort = a_type % 4;
+ b_type_sort = b_type % 4;
+ return a_type_sort > b_type_sort ? 1 : -1;
+}
+
static int get_short_oid(const char *name, int len, struct object_id *oid,
unsigned flags)
{
@@ -404,6 +437,8 @@ static int get_short_oid(const char *name, int len, struct object_id *oid,
status = finish_object_disambiguation(&ds, oid);
if (!quietly && (status == SHORT_NAME_AMBIGUOUS)) {
+ struct oid_array collect = OID_ARRAY_INIT;
+
error(_("short SHA1 %s is ambiguous"), ds.hex_pfx);
/*
@@ -416,18 +451,17 @@ static int get_short_oid(const char *name, int len, struct object_id *oid,
ds.fn = NULL;
advise(_("The candidates are:"));
- for_each_abbrev(ds.hex_pfx, show_ambiguous_object, &ds);
+ for_each_abbrev(ds.hex_pfx, collect_ambiguous, &collect);
+ QSORT(collect.oid, collect.nr, sort_ambiguous);
+
+ if (oid_array_for_each(&collect, show_ambiguous_object, &ds))
+ BUG("show_ambiguous_object shouldn't return non-zero");
+ oid_array_clear(&collect);
}
return status;
}
-static int collect_ambiguous(const struct object_id *oid, void *data)
-{
- oid_array_append(data, oid);
- return 0;
-}
-
int for_each_abbrev(const char *prefix, each_abbrev_fn fn, void *cb_data)
{
struct oid_array collect = OID_ARRAY_INIT;
diff --git a/t/t1512-rev-parse-disambiguation.sh b/t/t1512-rev-parse-disambiguation.sh
index 711704b..2701462 100755
--- a/t/t1512-rev-parse-disambiguation.sh
+++ b/t/t1512-rev-parse-disambiguation.sh
@@ -361,4 +361,25 @@ test_expect_success 'core.disambiguate does not override context' '
git -c core.disambiguate=committish rev-parse $sha1^{tree}
'
+test_expect_success C_LOCALE_OUTPUT 'ambiguous commits are printed by type first, then hash order' '
+ test_must_fail git rev-parse 0000 2>stderr &&
+ grep ^hint: stderr >hints &&
+ grep 0000 hints >objects &&
+ cat >expected <<-\EOF &&
+ tag
+ commit
+ tree
+ blob
+ EOF
+ awk "{print \$3}" <objects >objects.types &&
+ uniq <objects.types >objects.types.uniq &&
+ test_cmp expected objects.types.uniq &&
+ for type in tag commit tree blob
+ do
+ grep $type objects >$type.objects &&
+ sort $type.objects >$type.objects.sorted &&
+ test_cmp $type.objects.sorted $type.objects
+ done
+'
+
test_done