From 55088ac8a480d94ccf37bc53b6b2ddc7475b269b Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Wed, 10 Jun 2026 11:50:01 -0700 Subject: [PATCH] describe: limit default ref iteration to tags Without --all, git describe ignores refs outside refs/tags/. Commit 8a5a1884e9 (Avoid accessing non-tag refs in git-describe unless --all is requested, 2008-02-24) moved this check ahead of object lookup. That avoided loading objects for irrelevant refs, but the backend still has to yield every ref before get_name() can reject it. Pass refs/tags/ to the iterator so the backend can avoid visiting those refs in the first place. The new perf test creates 10,000 unrelated packed refs. It measures: git describe --exact-match HEAD The runtime drops from 0.03(0.01+0.01) to 0.02(0.00+0.00). In a repository with 120,532 refs but only 330 tags, the same command went from 171.7 ms to 9.9 ms. Signed-off-by: Tamir Duberstein Signed-off-by: Junio C Hamano --- builtin/describe.c | 3 +++ t/perf/p6100-describe.sh | 12 ++++++++++++ 2 files changed, 15 insertions(+) diff --git a/builtin/describe.c b/builtin/describe.c index bffeed13a3..e93c3720ec 100644 --- a/builtin/describe.c +++ b/builtin/describe.c @@ -740,6 +740,9 @@ int cmd_describe(int argc, return ret; } + if (!all) + for_each_ref_opts.prefix = "refs/tags/"; + hashmap_init(&names, commit_name_neq, NULL, 0); refs_for_each_ref_ext(get_main_ref_store(the_repository), get_name, NULL, &for_each_ref_opts); diff --git a/t/perf/p6100-describe.sh b/t/perf/p6100-describe.sh index 069f91ce49..b1c61529bb 100755 --- a/t/perf/p6100-describe.sh +++ b/t/perf/p6100-describe.sh @@ -27,4 +27,16 @@ test_perf 'describe HEAD with one tag' ' git describe --match=new HEAD ' +test_expect_success 'set up many unrelated refs' ' + ref_count=10000 && + git tag -m tip tip HEAD && + test_seq -f "create refs/heads/describe-perf/%05d HEAD" $ref_count | + git update-ref --stdin && + git pack-refs --all +' + +test_perf 'describe exact tag with many unrelated refs' ' + git describe --exact-match HEAD +' + test_done