Merge branch 'jk/describe-perf'

"git describe" optimization.

* jk/describe-perf:
  describe: split "found all tags" and max_candidates logic
  describe: stop traversing when we run out of names
  describe: stop digging for max_candidates+1
  t/perf: add tests for git-describe
  t6120: demonstrate weakness in disjoint-root handling
This commit is contained in:
Junio C Hamano
2024-12-15 17:54:25 -08:00
3 changed files with 60 additions and 10 deletions

View File

@ -366,6 +366,13 @@ static void describe_commit(struct object_id *oid, struct strbuf *dst)
struct commit_name **slot; struct commit_name **slot;
seen_commits++; seen_commits++;
if (match_cnt == max_candidates ||
match_cnt == hashmap_get_size(&names)) {
gave_up_on = c;
break;
}
slot = commit_names_peek(&commit_names, c); slot = commit_names_peek(&commit_names, c);
n = slot ? *slot : NULL; n = slot ? *slot : NULL;
if (n) { if (n) {
@ -381,10 +388,6 @@ static void describe_commit(struct object_id *oid, struct strbuf *dst)
if (n->prio == 2) if (n->prio == 2)
annotated_cnt++; annotated_cnt++;
} }
else {
gave_up_on = c;
break;
}
} }
for (cur_match = 0; cur_match < match_cnt; cur_match++) { for (cur_match = 0; cur_match < match_cnt; cur_match++) {
struct possible_tag *t = &all_matches[cur_match]; struct possible_tag *t = &all_matches[cur_match];
@ -470,9 +473,8 @@ static void describe_commit(struct object_id *oid, struct strbuf *dst)
fprintf(stderr, _("traversed %lu commits\n"), seen_commits); fprintf(stderr, _("traversed %lu commits\n"), seen_commits);
if (gave_up_on) { if (gave_up_on) {
fprintf(stderr, fprintf(stderr,
_("more than %i tags found; listed %i most recent\n" _("found %i tags; gave up search at %s\n"),
"gave up search at %s\n"), max_candidates,
max_candidates, max_candidates,
oid_to_hex(&gave_up_on->object.oid)); oid_to_hex(&gave_up_on->object.oid));
} }
} }

30
t/perf/p6100-describe.sh Executable file
View File

@ -0,0 +1,30 @@
#!/bin/sh
test_description='performance of git-describe'
. ./perf-lib.sh
test_perf_default_repo
# clear out old tags and give us a known state
test_expect_success 'set up tags' '
git for-each-ref --format="delete %(refname)" refs/tags >to-delete &&
git update-ref --stdin <to-delete &&
new=$(git rev-list -1000 HEAD | tail -n 1) &&
git tag -m new new $new &&
old=$(git rev-list HEAD | tail -n 1) &&
git tag -m old old $old
'
test_perf 'describe HEAD' '
git describe HEAD
'
test_perf 'describe HEAD with one max candidate' '
git describe --candidates=1 HEAD
'
test_perf 'describe HEAD with one tag' '
git describe --match=new HEAD
'
test_done

View File

@ -18,6 +18,7 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
check_describe () { check_describe () {
indir= && indir= &&
outcome=success &&
while test $# != 0 while test $# != 0
do do
case "$1" in case "$1" in
@ -25,6 +26,9 @@ check_describe () {
indir="$2" indir="$2"
shift shift
;; ;;
--expect-failure)
outcome=failure
;;
*) *)
break break
;; ;;
@ -35,7 +39,7 @@ check_describe () {
expect="$1" expect="$1"
shift shift
describe_opts="$@" describe_opts="$@"
test_expect_success "describe $describe_opts" ' test_expect_${outcome} "describe $describe_opts" '
git ${indir:+ -C "$indir"} describe $describe_opts >raw && git ${indir:+ -C "$indir"} describe $describe_opts >raw &&
sed -e "s/-g[0-9a-f]*\$/-gHASH/" <raw >actual && sed -e "s/-g[0-9a-f]*\$/-gHASH/" <raw >actual &&
echo "$expect" >expect && echo "$expect" >expect &&
@ -616,7 +620,7 @@ test_expect_success 'name-rev --annotate-stdin works with commitGraph' '
# B # B
# o # o
# \ # H \
# o-----o---o----x # o-----o---o----x
# A # A
# #
@ -626,6 +630,7 @@ test_expect_success 'setup: describe commits with disjoint bases' '
cd disjoint1 && cd disjoint1 &&
echo o >> file && git add file && git commit -m o && echo o >> file && git add file && git commit -m o &&
git tag H -a -m H &&
echo A >> file && git add file && git commit -m A && echo A >> file && git add file && git commit -m A &&
git tag A -a -m A && git tag A -a -m A &&
echo o >> file && git add file && git commit -m o && echo o >> file && git add file && git commit -m o &&
@ -638,8 +643,9 @@ test_expect_success 'setup: describe commits with disjoint bases' '
' '
check_describe -C disjoint1 "A-3-gHASH" HEAD check_describe -C disjoint1 "A-3-gHASH" HEAD
check_describe -C disjoint1 --expect-failure "A-3-gHASH" --candidates=2 HEAD
# B # H B
# o---o---o------------. # o---o---o------------.
# \ # \
# o---o---x # o---o---x
@ -657,6 +663,7 @@ test_expect_success 'setup: describe commits with disjoint bases 2' '
git checkout --orphan branch && git checkout --orphan branch &&
echo o >> file2 && git add file2 && GIT_COMMITTER_DATE="2020-01-01 15:00" git commit -m o && echo o >> file2 && git add file2 && GIT_COMMITTER_DATE="2020-01-01 15:00" git commit -m o &&
echo o >> file2 && git add file2 && GIT_COMMITTER_DATE="2020-01-01 15:01" git commit -m o && echo o >> file2 && git add file2 && GIT_COMMITTER_DATE="2020-01-01 15:01" git commit -m o &&
git tag H -a -m H &&
echo B >> file2 && git add file2 && GIT_COMMITTER_DATE="2020-01-01 15:02" git commit -m B && echo B >> file2 && git add file2 && GIT_COMMITTER_DATE="2020-01-01 15:02" git commit -m B &&
git tag B -a -m B && git tag B -a -m B &&
git merge --no-ff --allow-unrelated-histories main -m x git merge --no-ff --allow-unrelated-histories main -m x
@ -664,6 +671,7 @@ test_expect_success 'setup: describe commits with disjoint bases 2' '
' '
check_describe -C disjoint2 "B-3-gHASH" HEAD check_describe -C disjoint2 "B-3-gHASH" HEAD
check_describe -C disjoint2 --expect-failure "B-3-gHASH" --candidates=2 HEAD
test_expect_success 'setup misleading taggerdates' ' test_expect_success 'setup misleading taggerdates' '
GIT_COMMITTER_DATE="2006-12-12 12:31" git tag -a -m "another tag" newer-tag-older-commit unique-file~1 GIT_COMMITTER_DATE="2006-12-12 12:31" git tag -a -m "another tag" newer-tag-older-commit unique-file~1
@ -707,4 +715,14 @@ test_expect_success 'describe --broken --dirty with a file with changed stat' '
) )
' '
test_expect_success '--always with no refs falls back to commit hash' '
git rev-parse HEAD >expect &&
git describe --no-abbrev --always --match=no-such-tag >actual &&
test_cmp expect actual
'
test_expect_success '--exact-match does not show --always fallback' '
test_must_fail git describe --exact-match --always
'
test_done test_done