summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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 b0c11f868d..9febfb1d52 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 7bb9cadc69..1afa87cd9d 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 838b3bf847..265941fbf4 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 04b0756334..232bf95017 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 cc0028ed19..60d9ef3c7e 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 711704ba5a..2701462041 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