{"thread":{"id":"65730","subject":"[PATCH v2] describe: fix --exclude, --match with --contains and --all","startedAt":"2026-06-01T23:37:41Z","lastAt":"2026-06-01T23:37:41Z","messageCount":1,"participants":["Jacob Keller"],"isPatch":true,"patchVersion":2,"patchTotal":null},"messages":[{"id":"544444","messageId":"20260601233727.43558-1-jacob.e.keller@intel.com","threadId":"65730","inReplyTo":null,"subject":"[PATCH v2] describe: fix --exclude, --match with --contains and --all","fromName":"Jacob Keller","fromEmail":"jacob.e.keller@intel.com","sentAt":"2026-06-01T23:36:08Z","receivedAt":"2026-06-01T23:37:41Z","isPatch":true,"body":"From: Jacob Keller <jacob.keller@gmail.com>\n\ngit describe --contains acts as a wrapper around git name-rev. When\noperating with --contains and --all, the --match and --exclude patterns\nare not properly forwarded to name-rev as --exclude and --refs options.\n\nThis results in the command silently discarding match and exclude\nrequests from the user when operating in --all mode.\n\nWe could check and die() if the user provides --contains, --all, and\n--match/--exclude. However, its also straight forward to just pass the\nfilters down to git name-rev.\n\nNotice that the documentation for --match and --exclude mention the\n--all mode. It explains that they operate on refs with the prefix\nrefs/tags, and additionally refs/heads and refs/remotes when using\n--all.\n\nFix the describe logic to pass the patterns down with the appropriate\nprefixes when --all is provided. This fixes the support to match the\ndocumented behavior.\n\nAdd tests to check that this works as expected.\n\nReported-by: Tuomas Ahola <taahol@utu.fi>\nSigned-off-by: Jacob Keller <jacob.keller@gmail.com>\n---\nChanges in v2:\n* Use check_describe for tests.\n* Fix test which could return multiple answers by adding an additional\n  exclude.\n* Add a few additional tests around origin remote.\n\n builtin/describe.c  | 18 +++++++++++++++---\n t/t6120-describe.sh | 22 ++++++++++++++++++++++\n 2 files changed, 37 insertions(+), 3 deletions(-)\n\ndiff --git a/builtin/describe.c b/builtin/describe.c\nindex 1c47d7c0b7c3..faaf44cec573 100644\n--- a/builtin/describe.c\n+++ b/builtin/describe.c\n@@ -712,13 +712,25 @@ int cmd_describe(int argc,\n \t\t\t     NULL);\n \t\tif (always)\n \t\t\tstrvec_push(&args, \"--always\");\n-\t\tif (!all) {\n+\t\tif (!all)\n \t\t\tstrvec_push(&args, \"--tags\");\n+\n+\t\tfor_each_string_list_item(item, &patterns)\n+\t\t\tstrvec_pushf(&args, \"--refs=refs/tags/%s\", item->string);\n+\t\tfor_each_string_list_item(item, &exclude_patterns)\n+\t\t\tstrvec_pushf(&args, \"--exclude=refs/tags/%s\", item->string);\n+\n+\t\tif (all) {\n \t\t\tfor_each_string_list_item(item, &patterns)\n-\t\t\t\tstrvec_pushf(&args, \"--refs=refs/tags/%s\", item->string);\n+\t\t\t\tstrvec_pushf(&args, \"--refs=refs/heads/%s\", item->string);\n \t\t\tfor_each_string_list_item(item, &exclude_patterns)\n-\t\t\t\tstrvec_pushf(&args, \"--exclude=refs/tags/%s\", item->string);\n+\t\t\t\tstrvec_pushf(&args, \"--exclude=refs/heads/%s\", item->string);\n+\t\t\tfor_each_string_list_item(item, &patterns)\n+\t\t\t\tstrvec_pushf(&args, \"--refs=refs/remotes/%s\", item->string);\n+\t\t\tfor_each_string_list_item(item, &exclude_patterns)\n+\t\t\t\tstrvec_pushf(&args, \"--exclude=refs/remotes/%s\", item->string);\n \t\t}\n+\n \t\tif (argc)\n \t\t\tstrvec_pushv(&args, argv);\n \t\telse\ndiff --git a/t/t6120-describe.sh b/t/t6120-describe.sh\nindex 8ee3d2c37d02..4d72033e391d 100755\n--- a/t/t6120-describe.sh\n+++ b/t/t6120-describe.sh\n@@ -359,6 +359,28 @@ test_expect_success 'describe --contains and --no-match' '\n \ttest_cmp expect actual\n '\n \n+test_expect_success 'describe --contains --all --match no matching commit' '\n+\techo \"tags/A^0\" >expect &&\n+\ttagged_commit=$(git rev-parse \"refs/tags/A^0\") &&\n+\ttest_must_fail git describe --contains --all --match=\"B\" $tagged_commit\n+'\n+\n+check_describe \"tags/A^0\" --contains --all --match=\"A\" $(git rev-parse \"refs/tags/A^0\")\n+\n+check_describe \"branch_A\" --contains --all --match=\"branch*\" $(git rev-parse \"refs/tags/A^0\")\n+\n+check_describe \"branch_C~1\" --contains --all --match=\"branch*\" --exclude=\"branch_A\" $(git rev-parse \"refs/tags/A^0\")\n+\n+check_describe \"branch_A\" --contains --all \\\n+\t--exclude=\"A\" --exclude=\"c\" --exclude=\"test*\" --exclude=\"origin/remote_branch_A\" \\\n+\t$(git rev-parse \"refs/tags/A^0\")\n+\n+check_describe \"remotes/origin/remote_branch_A\" --contains --all --match=\"origin/remote*\" $(git rev-parse \"refs/tags/A^0\")\n+\n+check_describe \"remotes/origin/remote_branch_C~1\" --contains --all \\\n+\t--match=\"origin/remote*\" --exclude=\"origin/remote_branch_A\" \\\n+\t$(git rev-parse \"refs/tags/A^0\")\n+\n test_expect_success 'setup and absorb a submodule' '\n \ttest_create_repo sub1 &&\n \ttest_commit -C sub1 initial &&\n-- \n2.54.0.633.g0ded84c31b89\n\n"}]}