describe: fix --exclude, --match with --contains and --all

git describe --contains acts as a wrapper around git name-rev. When
operating with --contains and --all, the --match and --exclude patterns
are not properly forwarded to name-rev as --exclude and --refs options.

This results in the command silently discarding match and exclude
requests from the user when operating in --all mode.

We could check and die() if the user provides --contains, --all, and
--match/--exclude. However, its also straight forward to just pass the
filters down to git name-rev.

Notice that the documentation for --match and --exclude mention the
--all mode. It explains that they operate on refs with the prefix
refs/tags, and additionally refs/heads and refs/remotes when using
--all.

Fix the describe logic to pass the patterns down with the appropriate
prefixes when --all is provided. This fixes the support to match the
documented behavior.

Add tests to check that this works as expected.

Reported-by: Tuomas Ahola <taahol@utu.fi>
Signed-off-by: Jacob Keller <jacob.keller@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Jacob Keller
2026-06-01 16:36:08 -07:00
committed by Junio C Hamano
parent a89346e34a
commit 1891707d1b
2 changed files with 37 additions and 3 deletions

View File

@@ -712,13 +712,25 @@ int cmd_describe(int argc,
NULL);
if (always)
strvec_push(&args, "--always");
if (!all) {
if (!all)
strvec_push(&args, "--tags");
for_each_string_list_item(item, &patterns)
strvec_pushf(&args, "--refs=refs/tags/%s", item->string);
for_each_string_list_item(item, &exclude_patterns)
strvec_pushf(&args, "--exclude=refs/tags/%s", item->string);
if (all) {
for_each_string_list_item(item, &patterns)
strvec_pushf(&args, "--refs=refs/tags/%s", item->string);
strvec_pushf(&args, "--refs=refs/heads/%s", item->string);
for_each_string_list_item(item, &exclude_patterns)
strvec_pushf(&args, "--exclude=refs/tags/%s", item->string);
strvec_pushf(&args, "--exclude=refs/heads/%s", item->string);
for_each_string_list_item(item, &patterns)
strvec_pushf(&args, "--refs=refs/remotes/%s", item->string);
for_each_string_list_item(item, &exclude_patterns)
strvec_pushf(&args, "--exclude=refs/remotes/%s", item->string);
}
if (argc)
strvec_pushv(&args, argv);
else

View File

@@ -345,6 +345,28 @@ test_expect_success 'describe --contains and --no-match' '
test_cmp expect actual
'
test_expect_success 'describe --contains --all --match no matching commit' '
echo "tags/A^0" >expect &&
tagged_commit=$(git rev-parse "refs/tags/A^0") &&
test_must_fail git describe --contains --all --match="B" $tagged_commit
'
check_describe "tags/A^0" --contains --all --match="A" $(git rev-parse "refs/tags/A^0")
check_describe "branch_A" --contains --all --match="branch*" $(git rev-parse "refs/tags/A^0")
check_describe "branch_C~1" --contains --all --match="branch*" --exclude="branch_A" $(git rev-parse "refs/tags/A^0")
check_describe "branch_A" --contains --all \
--exclude="A" --exclude="c" --exclude="test*" --exclude="origin/remote_branch_A" \
$(git rev-parse "refs/tags/A^0")
check_describe "remotes/origin/remote_branch_A" --contains --all --match="origin/remote*" $(git rev-parse "refs/tags/A^0")
check_describe "remotes/origin/remote_branch_C~1" --contains --all \
--match="origin/remote*" --exclude="origin/remote_branch_A" \
$(git rev-parse "refs/tags/A^0")
test_expect_success 'setup and absorb a submodule' '
test_create_repo sub1 &&
test_commit -C sub1 initial &&