{"thread":{"id":"45453","subject":"[PATCH v2 01/16] tag doc: move the description of --[no-]merged earlier","startedAt":"2017-03-21T13:01:00Z","lastAt":"2017-03-23T00:46:20Z","messageCount":45,"participants":["Ævar Arnfjörð Bjarmason","Junio C Hamano","Jeff King"],"isPatch":true,"patchVersion":2,"patchTotal":16},"messages":[{"id":"314791","messageId":"20170321125901.10652-2-avarab@gmail.com","threadId":"45453","inReplyTo":"20170321125901.10652-1-avarab@gmail.com","subject":"[PATCH v2 01/16] tag doc: move the description of --[no-]merged earlier","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2017-03-21T12:58:46Z","receivedAt":"2017-03-21T13:01:00Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Move the documentation for the --merged & --no-merged options earlier\nin the documentation, to sit along the other switches, and right next\nto the similar --contains and --points-at switches.\n\nIt makes more sense to group the options together, not have some\noptions after the like of <tagname>, <object>, <format> etc.\n\nThis was originally put there when the --merged & --no-merged options\nwere introduced in 5242860f54 (\"tag.c: implement '--merged' and\n'--no-merged' options\", 2015-09-10). It's not apparent from that\ncommit that the documentation is being placed apart from other\noptions, rather than along with them, so this was likely missed in the\ninitial review.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n Documentation/git-tag.txt | 10 +++++-----\n 1 file changed, 5 insertions(+), 5 deletions(-)\n\ndiff --git a/Documentation/git-tag.txt b/Documentation/git-tag.txt\nindex 525737a5d8..33f18ea5fb 100644\n--- a/Documentation/git-tag.txt\n+++ b/Documentation/git-tag.txt\n@@ -124,6 +124,11 @@ This option is only applicable when listing tags without annotation lines.\n \tOnly list tags which contain the specified commit (HEAD if not\n \tspecified).\n \n+--[no-]merged [<commit>]::\n+\tOnly list tags whose tips are reachable, or not reachable\n+\tif `--no-merged` is used, from the specified commit (`HEAD`\n+\tif not specified).\n+\n --points-at <object>::\n \tOnly list tags of the given object.\n \n@@ -173,11 +178,6 @@ This option is only applicable when listing tags without annotation lines.\n \tthat of linkgit:git-for-each-ref[1].  When unspecified,\n \tdefaults to `%(refname:strip=2)`.\n \n---[no-]merged [<commit>]::\n-\tOnly list tags whose tips are reachable, or not reachable\n-\tif `--no-merged` is used, from the specified commit (`HEAD`\n-\tif not specified).\n-\n CONFIGURATION\n -------------\n By default, 'git tag' in sign-with-default mode (-s) will use your\n-- \n2.11.0\n\n"},{"id":"314792","messageId":"20170321125901.10652-4-avarab@gmail.com","threadId":"45453","inReplyTo":"20170321125901.10652-1-avarab@gmail.com","subject":"[PATCH v2 03/16] tag doc: reword --[no-]merged to talk about commits, not tips","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2017-03-21T12:58:48Z","receivedAt":"2017-03-21T13:01:01Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change the wording for the --merged and --no-merged options to talk\nabout \"commits\" instead of \"tips\".\n\nThis phrasing was copied from the \"branch\" documentation in commit\n5242860f54 (\"tag.c: implement '--merged' and '--no-merged' options\",\n2015-09-10). Talking about the \"tip\" is branch nomenclature, not\nsomething usually associated with tags.\n\nThis phrasing might lead the reader to believe that these options\nmight find tags pointing to trees or blobs, let's instead be explicit\nand only talk about commits.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n Documentation/git-tag.txt | 6 +++---\n 1 file changed, 3 insertions(+), 3 deletions(-)\n\ndiff --git a/Documentation/git-tag.txt b/Documentation/git-tag.txt\nindex 68b0ab2410..3abf912782 100644\n--- a/Documentation/git-tag.txt\n+++ b/Documentation/git-tag.txt\n@@ -125,11 +125,11 @@ This option is only applicable when listing tags without annotation lines.\n \tspecified).\n \n --merged [<commit>]::\n-\tOnly list tags whose tips are reachable from the specified commit\n-\t(`HEAD` if not specified).\n+\tOnly list tags whose commits are reachable from the specified\n+\tcommit (`HEAD` if not specified).\n \n --no-merged [<commit>]::\n-\tOnly list tags whose tips are not reachable from the specified\n+\tOnly list tags whose commits are not reachable from the specified\n \tcommit (`HEAD` if not specified).\n \n --points-at <object>::\n-- \n2.11.0\n\n"},{"id":"314793","messageId":"20170321125901.10652-15-avarab@gmail.com","threadId":"45453","inReplyTo":"20170321125901.10652-1-avarab@gmail.com","subject":"[PATCH v2 14/16] ref-filter: reflow recently changed branch/tag/for-each-ref docs","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2017-03-21T12:58:59Z","receivedAt":"2017-03-21T13:01:03Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Reflow the recently changed branch/tag-for-each-ref\ndocumentation. This change shows no changes under --word-diff, except\nthe innocuous change of moving git-tag.txt's \"[--sort=<key>]\" around\nslightly.\n---\n Documentation/git-branch.txt | 15 ++++++++-------\n Documentation/git-tag.txt    |  7 ++++---\n 2 files changed, 12 insertions(+), 10 deletions(-)\n\ndiff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt\nindex e4b5d5c3e1..5e175ec339 100644\n--- a/Documentation/git-branch.txt\n+++ b/Documentation/git-branch.txt\n@@ -10,9 +10,9 @@ SYNOPSIS\n [verse]\n 'git branch' [--color[=<when>] | --no-color] [-r | -a]\n \t[--list] [-v [--abbrev=<length> | --no-abbrev]]\n-\t[--column[=<options>] | --no-column]\n+\t[--column[=<options>] | --no-column] [--sort=<key>]\n \t[(--merged | --no-merged) [<commit>]]\n-\t[--contains [<commit]] [--no-contains [<commit>]] [--sort=<key>]\n+\t[--contains [<commit]] [--no-contains [<commit>]]\n \t[--points-at <object>] [--format=<format>] [<pattern>...]\n 'git branch' [--set-upstream | --track | --no-track] [-l] [-f] <branchname> [<start-point>]\n 'git branch' (--set-upstream-to=<upstream> | -u <upstream>) [<branchname>]\n@@ -36,11 +36,12 @@ as branch creation.\n \n With `--contains`, shows only the branches that contain the named commit\n (in other words, the branches whose tip commits are descendants of the\n-named commit), `--no-contains` inverts it. With `--merged`, only branches merged into the named\n-commit (i.e. the branches whose tip commits are reachable from the named\n-commit) will be listed.  With `--no-merged` only branches not merged into\n-the named commit will be listed.  If the <commit> argument is missing it\n-defaults to `HEAD` (i.e. the tip of the current branch).\n+named commit), `--no-contains` inverts it. With `--merged`, only branches\n+merged into the named commit (i.e. the branches whose tip commits are\n+reachable from the named commit) will be listed.  With `--no-merged` only\n+branches not merged into the named commit will be listed.  If the <commit>\n+argument is missing it defaults to `HEAD` (i.e. the tip of the current\n+branch).\n \n The command's second form creates a new branch head named <branchname>\n which points to the current `HEAD`, or <start-point> if given.\ndiff --git a/Documentation/git-tag.txt b/Documentation/git-tag.txt\nindex b399b91931..c249072001 100644\n--- a/Documentation/git-tag.txt\n+++ b/Documentation/git-tag.txt\n@@ -12,9 +12,10 @@ SYNOPSIS\n 'git tag' [-a | -s | -u <keyid>] [-f] [-m <msg> | -F <file>]\n \t<tagname> [<commit> | <object>]\n 'git tag' -d <tagname>...\n-'git tag' [-n[<num>]] -l [--contains <commit>] [--contains <commit>] [--points-at <object>]\n-\t[--column[=<options>] | --no-column] [--create-reflog] [--sort=<key>]\n-\t[--format=<format>] [--[no-]merged [<commit>]] [<pattern>...]\n+'git tag' [-n[<num>]] -l [--contains <commit>] [--contains <commit>]\n+\t[--points-at <object>] [--column[=<options>] | --no-column]\n+\t[--create-reflog] [--sort=<key>] [--format=<format>]\n+\t[--[no-]merged [<commit>]] [<pattern>...]\n 'git tag' -v [--format=<format>] <tagname>...\n \n DESCRIPTION\n-- \n2.11.0\n\n"},{"id":"314794","messageId":"20170321125901.10652-16-avarab@gmail.com","threadId":"45453","inReplyTo":"20170321125901.10652-1-avarab@gmail.com","subject":"[PATCH v2 15/16] tag: implicitly supply --list given the -n option","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2017-03-21T12:59:00Z","receivedAt":"2017-03-21T13:01:07Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change the \"tag\" command to treat the \"-n\" invocation as a list-like\noption in addition to --contains, --points-at etc.\n\nMost of the work for this was done in my earlier \"tag: Implicitly\nsupply --list given another list-like option\" commit, but I've split\noff this patch since it's more contentious. Now these will be\nsynonymous:\n\n    git tag -n 100\n    git tag -n --list 100\n\nWhereas before the former would die. This doesn't technically\nintroduce any more ambiguity than the aforementioned change applied to\nth other list-like options, but it does introduce the possibility for\nmore confusion, since instead of the latter of these dying:\n\n    git tag -n100\n    git tag -n 100\n\nIt now works entirely differently, i.e. invokes list mode with a\nfilter for \"100\" as a pattern. I.e. it's synonymous with:\n\n    git tag -n --list 100\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n Documentation/git-tag.txt |  9 +++++----\n builtin/tag.c             |  3 ++-\n t/t7004-tag.sh            | 17 ++++++++++++++++-\n 3 files changed, 23 insertions(+), 6 deletions(-)\n\ndiff --git a/Documentation/git-tag.txt b/Documentation/git-tag.txt\nindex c249072001..6694b7d33f 100644\n--- a/Documentation/git-tag.txt\n+++ b/Documentation/git-tag.txt\n@@ -83,10 +83,11 @@ OPTIONS\n \n -n<num>::\n \t<num> specifies how many lines from the annotation, if any,\n-\tare printed when using -l.\n-\tThe default is not to print any annotation lines.\n-\tIf no number is given to `-n`, only the first line is printed.\n-\tIf the tag is not annotated, the commit message is displayed instead.\n+\tare printed when using -l. Implies `--list`.\n++\n+The default is not to print any annotation lines.\n+If no number is given to `-n`, only the first line is printed.\n+If the tag is not annotated, the commit message is displayed instead.\n \n -l::\n --list::\ndiff --git a/builtin/tag.c b/builtin/tag.c\nindex 67d63b2095..dbc6f5b74b 100644\n--- a/builtin/tag.c\n+++ b/builtin/tag.c\n@@ -461,7 +461,8 @@ int cmd_tag(int argc, const char **argv, const char *prefix)\n \t\tif (argc == 0)\n \t\t\tcmdmode = 'l';\n \t\telse if (filter.with_commit || filter.no_commit ||\n-\t\t\t filter.points_at.nr || filter.merge_commit)\n+\t\t\t filter.points_at.nr || filter.merge_commit ||\n+\t\t\t filter.lines != -1)\n \t\t\tcmdmode = 'l';\n \t}\n \ndiff --git a/t/t7004-tag.sh b/t/t7004-tag.sh\nindex 7984d1b495..60b5cd8751 100755\n--- a/t/t7004-tag.sh\n+++ b/t/t7004-tag.sh\n@@ -639,6 +639,11 @@ test_expect_success \\\n \tgit tag -n0 -l tag-one-line >actual &&\n \ttest_cmp expect actual &&\n \n+\tgit tag -n0 | grep \"^tag-one-line\" >actual &&\n+\ttest_cmp expect actual &&\n+\tgit tag -n0 tag-one-line >actual &&\n+\ttest_cmp expect actual &&\n+\n \techo \"tag-one-line    A msg\" >expect &&\n \tgit tag -n1 -l | grep \"^tag-one-line\" >actual &&\n \ttest_cmp expect actual &&\n@@ -652,6 +657,17 @@ test_expect_success \\\n \ttest_cmp expect actual\n '\n \n+test_expect_success 'The -n 100 invocation means -n --list 100, not -n100' '\n+\t>expect &&\n+\tgit tag -n 100 >actual &&\n+\ttest_cmp expect actual &&\n+\n+\tgit tag -m \"A msg\" 100 &&\n+\techo \"100             A msg\" >expect &&\n+\tgit tag -n 100 >actual &&\n+\ttest_cmp expect actual\n+'\n+\n test_expect_success \\\n \t'listing the zero-lines message of a non-signed tag should succeed' '\n \tgit tag -m \"\" tag-zero-lines &&\n@@ -1569,7 +1585,6 @@ test_expect_success 'mixing incompatibles modes and options is forbidden' '\n \ttest_must_fail git tag -a -s -m -F &&\n \ttest_must_fail git tag -a -s -m -F -l &&\n \ttest_must_fail git tag -l -v &&\n-\ttest_must_fail git tag -n 100 &&\n \ttest_must_fail git tag -n 100 -v &&\n \ttest_must_fail git tag -l -m msg &&\n \ttest_must_fail git tag -l -F some file &&\n-- \n2.11.0\n\n"},{"id":"314795","messageId":"20170321125901.10652-14-avarab@gmail.com","threadId":"45453","inReplyTo":"20170321125901.10652-1-avarab@gmail.com","subject":"[PATCH v2 13/16] ref-filter: add --no-contains option to tag/branch/for-each-ref","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2017-03-21T12:58:58Z","receivedAt":"2017-03-21T13:01:11Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change the tag, branch & for-each-ref commands to have a --no-contains\noption in addition to their longstanding --contains options.\n\nThis allows for finding the last-good rollout tag given a known-bad\n<commit>. Given a hypothetically bad commit cf5c7253e0, the git\nversion to revert to can be found with this hacky two-liner:\n\n    (git tag -l 'v[0-9]*'; git tag -l --contains cf5c7253e0 'v[0-9]*') |\n        sort | uniq -c | grep -E '^ *1 ' | awk '{print $2}' | tail -n 10\n\nWith this new --no-contains option the same can be achieved with:\n\n    git tag -l --no-contains cf5c7253e0 'v[0-9]*' | sort | tail -n 10\n\nAs the filtering machinery is shared between the tag, branch &\nfor-each-ref commands, implement this for those commands too. A\npractical use for this with \"branch\" is e.g. finding branches which\nwere branched off between v2.8.0 and v2.10.0:\n\n    git branch --contains v2.8.0 --no-contains v2.10.0\n\nThe \"describe\" command also has a --contains option, but its semantics\nare unrelated to what tag/branch/for-each-ref use --contains for. A\n--no-contains option for \"describe\" wouldn't make any sense, other\nthan being exactly equivalent to not supplying --contains at all,\nwhich would be confusing at best.\n\nAdd a --without option to \"tag\" as an alias for --no-contains, for\nconsistency with --with and --contains.  The --with option is\nundocumented, and possibly the only user of it is\nJunio (<xmqqefy71iej.fsf@gitster.mtv.corp.google.com>). But it's\ntrivial to support, so let's do that.\n\nThe additions to the the test suite are inverse copies of the\ncorresponding --contains tests. With this change --no-contains for\ntag, branch & for-each-ref is just as well tested as the existing\n--contains option.\n\nIn addition to those tests, add a test for \"tag\" which asserts that\n--no-contains won't find tree/blob tags, which is slightly\nunintuitive, but consistent with how --contains works & is documented.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n Documentation/git-branch.txt           |  16 +++-\n Documentation/git-for-each-ref.txt     |   6 +-\n Documentation/git-tag.txt              |   6 +-\n builtin/branch.c                       |   5 +-\n builtin/for-each-ref.c                 |   3 +-\n builtin/tag.c                          |   8 +-\n contrib/completion/git-completion.bash |   4 +-\n parse-options.h                        |   4 +-\n ref-filter.c                           |  19 +++--\n ref-filter.h                           |   1 +\n t/t3201-branch-contains.sh             |  54 +++++++++++++-\n t/t6302-for-each-ref-filter.sh         |  16 ++++\n t/t7004-tag.sh                         | 130 ++++++++++++++++++++++++++++++++-\n 13 files changed, 246 insertions(+), 26 deletions(-)\n\ndiff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt\nindex e465298571..e4b5d5c3e1 100644\n--- a/Documentation/git-branch.txt\n+++ b/Documentation/git-branch.txt\n@@ -11,7 +11,8 @@ SYNOPSIS\n 'git branch' [--color[=<when>] | --no-color] [-r | -a]\n \t[--list] [-v [--abbrev=<length> | --no-abbrev]]\n \t[--column[=<options>] | --no-column]\n-\t[(--merged | --no-merged | --contains) [<commit>]] [--sort=<key>]\n+\t[(--merged | --no-merged) [<commit>]]\n+\t[--contains [<commit]] [--no-contains [<commit>]] [--sort=<key>]\n \t[--points-at <object>] [--format=<format>] [<pattern>...]\n 'git branch' [--set-upstream | --track | --no-track] [-l] [-f] <branchname> [<start-point>]\n 'git branch' (--set-upstream-to=<upstream> | -u <upstream>) [<branchname>]\n@@ -35,7 +36,7 @@ as branch creation.\n \n With `--contains`, shows only the branches that contain the named commit\n (in other words, the branches whose tip commits are descendants of the\n-named commit).  With `--merged`, only branches merged into the named\n+named commit), `--no-contains` inverts it. With `--merged`, only branches merged into the named\n commit (i.e. the branches whose tip commits are reachable from the named\n commit) will be listed.  With `--no-merged` only branches not merged into\n the named commit will be listed.  If the <commit> argument is missing it\n@@ -213,6 +214,10 @@ start-point is either a local or remote-tracking branch.\n \tOnly list branches which contain the specified commit (HEAD\n \tif not specified). Implies `--list`.\n \n+--no-contains [<commit>]::\n+\tOnly list branches which don't contain the specified commit\n+\t(HEAD if not specified). Implies `--list`.\n+\n --merged [<commit>]::\n \tOnly list branches whose tips are reachable from the\n \tspecified commit (HEAD if not specified). Implies `--list`,\n@@ -298,13 +303,16 @@ If you are creating a branch that you want to checkout immediately, it is\n easier to use the git checkout command with its `-b` option to create\n a branch and check it out with a single command.\n \n-The options `--contains`, `--merged` and `--no-merged` serve three related\n-but different purposes:\n+The options `--contains`, `--no-contains`, `--merged` and `--no-merged`\n+serve four related but different purposes:\n \n - `--contains <commit>` is used to find all branches which will need\n   special attention if <commit> were to be rebased or amended, since those\n   branches contain the specified <commit>.\n \n+- `--no-contains <commit>` is the inverse of that, i.e. branches that don't\n+  contain the specified <commit>.\n+\n - `--merged` is used to find all branches which can be safely deleted,\n   since those branches are fully contained by HEAD.\n \ndiff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt\nindex 4d55893712..03e187a105 100644\n--- a/Documentation/git-for-each-ref.txt\n+++ b/Documentation/git-for-each-ref.txt\n@@ -11,7 +11,7 @@ SYNOPSIS\n 'git for-each-ref' [--count=<count>] [--shell|--perl|--python|--tcl]\n \t\t   [(--sort=<key>)...] [--format=<format>] [<pattern>...]\n \t\t   [--points-at <object>] [(--merged | --no-merged) [<object>]]\n-\t\t   [--contains [<object>]]\n+\t\t   [--contains [<object>]] [--no-contains [<object>]]\n \n DESCRIPTION\n -----------\n@@ -81,6 +81,10 @@ OPTIONS\n \tOnly list refs which contain the specified commit (HEAD if not\n \tspecified).\n \n+--no-contains [<object>]::\n+\tOnly list refs which don't contain the specified commit (HEAD\n+\tif not specified).\n+\n --ignore-case::\n \tSorting and filtering refs are case insensitive.\n \ndiff --git a/Documentation/git-tag.txt b/Documentation/git-tag.txt\nindex baf96944ae..b399b91931 100644\n--- a/Documentation/git-tag.txt\n+++ b/Documentation/git-tag.txt\n@@ -12,7 +12,7 @@ SYNOPSIS\n 'git tag' [-a | -s | -u <keyid>] [-f] [-m <msg> | -F <file>]\n \t<tagname> [<commit> | <object>]\n 'git tag' -d <tagname>...\n-'git tag' [-n[<num>]] -l [--contains <commit>] [--points-at <object>]\n+'git tag' [-n[<num>]] -l [--contains <commit>] [--contains <commit>] [--points-at <object>]\n \t[--column[=<options>] | --no-column] [--create-reflog] [--sort=<key>]\n \t[--format=<format>] [--[no-]merged [<commit>]] [<pattern>...]\n 'git tag' -v [--format=<format>] <tagname>...\n@@ -130,6 +130,10 @@ This option is only applicable when listing tags without annotation lines.\n \tOnly list tags which contain the specified commit (HEAD if not\n \tspecified). Implies `--list`.\n \n+--no-contains [<commit>]::\n+\tOnly list tags which don't contain the specified commit (HEAD if\n+\tnot specified). Implies `--list`.\n+\n --merged [<commit>]::\n \tOnly list tags whose commits are reachable from the specified\n \tcommit (`HEAD` if not specified), incompatible with `--no-merged`.\ndiff --git a/builtin/branch.c b/builtin/branch.c\nindex 52688f2e1b..0552c42ad1 100644\n--- a/builtin/branch.c\n+++ b/builtin/branch.c\n@@ -562,7 +562,9 @@ int cmd_branch(int argc, const char **argv, const char *prefix)\n \t\tOPT_SET_INT('r', \"remotes\",     &filter.kind, N_(\"act on remote-tracking branches\"),\n \t\t\tFILTER_REFS_REMOTES),\n \t\tOPT_CONTAINS(&filter.with_commit, N_(\"print only branches that contain the commit\")),\n+\t\tOPT_NO_CONTAINS(&filter.no_commit, N_(\"print only branches that don't contain the commit\")),\n \t\tOPT_WITH(&filter.with_commit, N_(\"print only branches that contain the commit\")),\n+\t\tOPT_WITHOUT(&filter.no_commit, N_(\"print only branches that don't contain the commit\")),\n \t\tOPT__ABBREV(&filter.abbrev),\n \n \t\tOPT_GROUP(N_(\"Specific git-branch actions:\")),\n@@ -618,7 +620,8 @@ int cmd_branch(int argc, const char **argv, const char *prefix)\n \tif (!delete && !rename && !edit_description && !new_upstream && !unset_upstream && argc == 0)\n \t\tlist = 1;\n \n-\tif (filter.with_commit || filter.merge != REF_FILTER_MERGED_NONE || filter.points_at.nr)\n+\tif (filter.with_commit || filter.merge != REF_FILTER_MERGED_NONE || filter.points_at.nr ||\n+\t    filter.no_commit)\n \t\tlist = 1;\n \n \tif (!!delete + !!rename + !!new_upstream +\ndiff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c\nindex 1a5ed20f59..eca365bf89 100644\n--- a/builtin/for-each-ref.c\n+++ b/builtin/for-each-ref.c\n@@ -9,7 +9,7 @@ static char const * const for_each_ref_usage[] = {\n \tN_(\"git for-each-ref [<options>] [<pattern>]\"),\n \tN_(\"git for-each-ref [--points-at <object>]\"),\n \tN_(\"git for-each-ref [(--merged | --no-merged) [<commit>]]\"),\n-\tN_(\"git for-each-ref [--contains [<commit>]]\"),\n+\tN_(\"git for-each-ref [--contains [<commit>]] [--no-contains [<commit>]]\"),\n \tNULL\n };\n \n@@ -43,6 +43,7 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix)\n \t\tOPT_MERGED(&filter, N_(\"print only refs that are merged\")),\n \t\tOPT_NO_MERGED(&filter, N_(\"print only refs that are not merged\")),\n \t\tOPT_CONTAINS(&filter.with_commit, N_(\"print only refs which contain the commit\")),\n+\t\tOPT_NO_CONTAINS(&filter.no_commit, N_(\"print only refs which don't contain the commit\")),\n \t\tOPT_BOOL(0, \"ignore-case\", &icase, N_(\"sorting and filtering are case insensitive\")),\n \t\tOPT_END(),\n \t};\ndiff --git a/builtin/tag.c b/builtin/tag.c\nindex dde05beb31..67d63b2095 100644\n--- a/builtin/tag.c\n+++ b/builtin/tag.c\n@@ -22,7 +22,7 @@\n static const char * const git_tag_usage[] = {\n \tN_(\"git tag [-a | -s | -u <key-id>] [-f] [-m <msg> | -F <file>] <tagname> [<head>]\"),\n \tN_(\"git tag -d <tagname>...\"),\n-\tN_(\"git tag -l [-n[<num>]] [--contains <commit>] [--points-at <object>]\"\n+\tN_(\"git tag -l [-n[<num>]] [--contains <commit>] [--no-contains <commit>] [--points-at <object>]\"\n \t\t\"\\n\\t\\t[--format=<format>] [--[no-]merged [<commit>]] [<pattern>...]\"),\n \tN_(\"git tag -v [--format=<format>] <tagname>...\"),\n \tNULL\n@@ -424,7 +424,9 @@ int cmd_tag(int argc, const char **argv, const char *prefix)\n \t\tOPT_GROUP(N_(\"Tag listing options\")),\n \t\tOPT_COLUMN(0, \"column\", &colopts, N_(\"show tag list in columns\")),\n \t\tOPT_CONTAINS(&filter.with_commit, N_(\"print only tags that contain the commit\")),\n+\t\tOPT_NO_CONTAINS(&filter.no_commit, N_(\"print only tags that don't contain the commit\")),\n \t\tOPT_WITH(&filter.with_commit, N_(\"print only tags that contain the commit\")),\n+\t\tOPT_WITHOUT(&filter.no_commit, N_(\"print only tags that don't contain the commit\")),\n \t\tOPT_MERGED(&filter, N_(\"print only tags that are merged\")),\n \t\tOPT_NO_MERGED(&filter, N_(\"print only tags that are not merged\")),\n \t\tOPT_CALLBACK(0 , \"sort\", sorting_tail, N_(\"key\"),\n@@ -458,7 +460,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix)\n \tif (!cmdmode) {\n \t\tif (argc == 0)\n \t\t\tcmdmode = 'l';\n-\t\telse if (filter.with_commit ||\n+\t\telse if (filter.with_commit || filter.no_commit ||\n \t\t\t filter.points_at.nr || filter.merge_commit)\n \t\t\tcmdmode = 'l';\n \t}\n@@ -494,6 +496,8 @@ int cmd_tag(int argc, const char **argv, const char *prefix)\n \t\tdie(_(\"-n option is only allowed in list mode\"));\n \tif (filter.with_commit)\n \t\tdie(_(\"--contains option is only allowed in list mode\"));\n+\tif (filter.no_commit)\n+\t\tdie(_(\"--no-contains option is only allowed in list mode\"));\n \tif (filter.points_at.nr)\n \t\tdie(_(\"--points-at option is only allowed in list mode\"));\n \tif (filter.merge_commit)\ndiff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\nindex fc32286a43..ec8fce5820 100644\n--- a/contrib/completion/git-completion.bash\n+++ b/contrib/completion/git-completion.bash\n@@ -1093,7 +1093,7 @@ _git_branch ()\n \t--*)\n \t\t__gitcomp \"\n \t\t\t--color --no-color --verbose --abbrev= --no-abbrev\n-\t\t\t--track --no-track --contains --merged --no-merged\n+\t\t\t--track --no-track --contains --no-contains --merged --no-merged\n \t\t\t--set-upstream-to= --edit-description --list\n \t\t\t--unset-upstream --delete --move --remotes\n \t\t\t--column --no-column --sort= --points-at\n@@ -2862,7 +2862,7 @@ _git_tag ()\n \t\t__gitcomp \"\n \t\t\t--list --delete --verify --annotate --message --file\n \t\t\t--sign --cleanup --local-user --force --column --sort=\n-\t\t\t--contains --points-at --merged --no-merged --create-reflog\n+\t\t\t--contains --no-contains --points-at --merged --no-merged --create-reflog\n \t\t\t\"\n \t\t;;\n \tesac\ndiff --git a/parse-options.h b/parse-options.h\nindex dcd8a0926c..0eac90b510 100644\n--- a/parse-options.h\n+++ b/parse-options.h\n@@ -258,7 +258,9 @@ extern int parse_opt_passthru_argv(const struct option *, const char *, int);\n \t  PARSE_OPT_LASTARG_DEFAULT | flag, \\\n \t  parse_opt_commits, (intptr_t) \"HEAD\" \\\n \t}\n-#define OPT_CONTAINS(v, h) _OPT_CONTAINS_OR_WITH(\"contains\", v, h, 0)\n+#define OPT_CONTAINS(v, h) _OPT_CONTAINS_OR_WITH(\"contains\", v, h, PARSE_OPT_NONEG)\n+#define OPT_NO_CONTAINS(v, h) _OPT_CONTAINS_OR_WITH(\"no-contains\", v, h, PARSE_OPT_NONEG)\n #define OPT_WITH(v, h) _OPT_CONTAINS_OR_WITH(\"with\", v, h, PARSE_OPT_HIDDEN)\n+#define OPT_WITHOUT(v, h) _OPT_CONTAINS_OR_WITH(\"without\", v, h, PARSE_OPT_HIDDEN)\n \n #endif\ndiff --git a/ref-filter.c b/ref-filter.c\nindex d7efae7b53..1e39273005 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -1487,6 +1487,7 @@ struct ref_filter_cbdata {\n \tstruct ref_array *array;\n \tstruct ref_filter *filter;\n \tstruct contains_cache contains_cache;\n+\tstruct contains_cache no_contains_cache;\n };\n \n /*\n@@ -1586,11 +1587,11 @@ static enum contains_result contains_tag_algo(struct commit *candidate,\n }\n \n static int commit_contains(struct ref_filter *filter, struct commit *commit,\n-\t\t\t   struct contains_cache *cache)\n+\t\t\t   struct commit_list *list, struct contains_cache *cache)\n {\n \tif (filter->with_commit_tag_algo)\n-\t\treturn contains_tag_algo(commit, filter->with_commit, cache) == CONTAINS_YES;\n-\treturn is_descendant_of(commit, filter->with_commit);\n+\t\treturn contains_tag_algo(commit, list, cache) == CONTAINS_YES;\n+\treturn is_descendant_of(commit, list);\n }\n \n /*\n@@ -1780,13 +1781,17 @@ static int ref_filter_handler(const char *refname, const struct object_id *oid,\n \t * obtain the commit using the 'oid' available and discard all\n \t * non-commits early. The actual filtering is done later.\n \t */\n-\tif (filter->merge_commit || filter->with_commit || filter->verbose) {\n+\tif (filter->merge_commit || filter->with_commit || filter->no_commit || filter->verbose) {\n \t\tcommit = lookup_commit_reference_gently(oid->hash, 1);\n \t\tif (!commit)\n \t\t\treturn 0;\n-\t\t/* We perform the filtering for the '--contains' option */\n+\t\t/* We perform the filtering for the '--contains' option... */\n \t\tif (filter->with_commit &&\n-\t\t    !commit_contains(filter, commit, &ref_cbdata->contains_cache))\n+\t\t    !commit_contains(filter, commit, filter->with_commit, &ref_cbdata->contains_cache))\n+\t\t\treturn 0;\n+\t\t/* ...or for the `--no-contains' option */\n+\t\tif (filter->no_commit &&\n+\t\t    commit_contains(filter, commit, filter->no_commit, &ref_cbdata->no_contains_cache))\n \t\t\treturn 0;\n \t}\n \n@@ -1887,6 +1892,7 @@ int filter_refs(struct ref_array *array, struct ref_filter *filter, unsigned int\n \tfilter->kind = type & FILTER_REFS_KIND_MASK;\n \n \tinit_contains_cache(&ref_cbdata.contains_cache);\n+\tinit_contains_cache(&ref_cbdata.no_contains_cache);\n \n \t/*  Simple per-ref filtering */\n \tif (!filter->kind)\n@@ -1911,6 +1917,7 @@ int filter_refs(struct ref_array *array, struct ref_filter *filter, unsigned int\n \t}\n \n \tclear_contains_cache(&ref_cbdata.contains_cache);\n+\tclear_contains_cache(&ref_cbdata.no_contains_cache);\n \n \t/*  Filters that need revision walking */\n \tif (filter->merge_commit)\ndiff --git a/ref-filter.h b/ref-filter.h\nindex e738c5dfd3..dde40f6849 100644\n--- a/ref-filter.h\n+++ b/ref-filter.h\n@@ -53,6 +53,7 @@ struct ref_filter {\n \tconst char **name_patterns;\n \tstruct sha1_array points_at;\n \tstruct commit_list *with_commit;\n+\tstruct commit_list *no_commit;\n \n \tenum {\n \t\tREF_FILTER_MERGED_NONE = 0,\ndiff --git a/t/t3201-branch-contains.sh b/t/t3201-branch-contains.sh\nindex daa3ae82b7..0ef1b6fdcc 100755\n--- a/t/t3201-branch-contains.sh\n+++ b/t/t3201-branch-contains.sh\n@@ -1,6 +1,6 @@\n #!/bin/sh\n \n-test_description='branch --contains <commit>, --merged, and --no-merged'\n+test_description='branch --contains <commit>, --no-contains <commit> --merged, and --no-merged'\n \n . ./test-lib.sh\n \n@@ -45,6 +45,22 @@ test_expect_success 'branch --contains master' '\n \n '\n \n+test_expect_success 'branch --no-contains=master' '\n+\n+\tgit branch --no-contains=master >actual &&\n+\t>expect &&\n+\ttest_cmp expect actual\n+\n+'\n+\n+test_expect_success 'branch --no-contains master' '\n+\n+\tgit branch --no-contains master >actual &&\n+\t>expect &&\n+\ttest_cmp expect actual\n+\n+'\n+\n test_expect_success 'branch --contains=side' '\n \n \tgit branch --contains=side >actual &&\n@@ -55,6 +71,16 @@ test_expect_success 'branch --contains=side' '\n \n '\n \n+test_expect_success 'branch --no-contains=side' '\n+\n+\tgit branch --no-contains=side >actual &&\n+\t{\n+\t\techo \"  master\"\n+\t} >expect &&\n+\ttest_cmp expect actual\n+\n+'\n+\n test_expect_success 'branch --contains with pattern implies --list' '\n \n \tgit branch --contains=master master >actual &&\n@@ -65,6 +91,14 @@ test_expect_success 'branch --contains with pattern implies --list' '\n \n '\n \n+test_expect_success 'branch --no-contains with pattern implies --list' '\n+\n+\tgit branch --no-contains=master master >actual &&\n+\t>expect &&\n+\ttest_cmp expect actual\n+\n+'\n+\n test_expect_success 'side: branch --merged' '\n \n \tgit branch --merged >actual &&\n@@ -126,7 +160,9 @@ test_expect_success 'branch --no-merged with pattern implies --list' '\n test_expect_success 'implicit --list conflicts with modification options' '\n \n \ttest_must_fail git branch --contains=master -d &&\n-\ttest_must_fail git branch --contains=master -m foo\n+\ttest_must_fail git branch --contains=master -m foo &&\n+\ttest_must_fail git branch --no-contains=master -d &&\n+\ttest_must_fail git branch --no-contains=master -m foo\n \n '\n \n@@ -136,7 +172,8 @@ test_expect_success 'Assert that --contains only works on commits, not trees & b\n \tSome blob\n \tEOF\n \t) &&\n-\ttest_must_fail git branch --contains $blob\n+\ttest_must_fail git branch --contains $blob &&\n+\ttest_must_fail git branch --no-contains $blob\n '\n \n # We want to set up a case where the walk for the tracking info\n@@ -168,4 +205,15 @@ test_expect_success 'branch --merged with --verbose' '\n \ttest_i18ncmp expect actual\n '\n \n+test_expect_success 'branch --contains combined with --no-contains' '\n+\tgit branch --contains zzz --no-contains topic >actual &&\n+\tcat >expect <<-\\EOF &&\n+\t  master\n+\t  side\n+\t  zzz\n+\tEOF\n+\ttest_cmp expect actual\n+\n+'\n+\n test_done\ndiff --git a/t/t6302-for-each-ref-filter.sh b/t/t6302-for-each-ref-filter.sh\nindex d36d5dc124..fc067ed672 100755\n--- a/t/t6302-for-each-ref-filter.sh\n+++ b/t/t6302-for-each-ref-filter.sh\n@@ -93,6 +93,22 @@ test_expect_success 'filtering with --contains' '\n \ttest_cmp expect actual\n '\n \n+test_expect_success 'filtering with --no-contains' '\n+\tcat >expect <<-\\EOF &&\n+\trefs/tags/one\n+\tEOF\n+\tgit for-each-ref --format=\"%(refname)\" --no-contains=two >actual &&\n+\ttest_cmp expect actual\n+'\n+\n+test_expect_success 'filtering with --contains and --no-contains' '\n+\tcat >expect <<-\\EOF &&\n+\trefs/tags/two\n+\tEOF\n+\tgit for-each-ref --format=\"%(refname)\" --contains=two --no-contains=three >actual &&\n+\ttest_cmp expect actual\n+'\n+\n test_expect_success '%(color) must fail' '\n \ttest_must_fail git for-each-ref --format=\"%(color)%(refname)\"\n '\ndiff --git a/t/t7004-tag.sh b/t/t7004-tag.sh\nindex b45ea8f5ac..7984d1b495 100755\n--- a/t/t7004-tag.sh\n+++ b/t/t7004-tag.sh\n@@ -1404,6 +1404,23 @@ test_expect_success 'checking that first commit is in all tags (relative)' \"\n \ttest_cmp expected actual\n \"\n \n+# All the --contains tests above, but with --no-contains\n+test_expect_success 'checking that first commit is not listed in any tag with --no-contains  (hash)' \"\n+\t>expected &&\n+\tgit tag -l --no-contains $hash1 v* >actual &&\n+\ttest_cmp expected actual\n+\"\n+\n+test_expect_success 'checking that first commit is in all tags (tag)' \"\n+\tgit tag -l --no-contains v1.0 v* >actual &&\n+\ttest_cmp expected actual\n+\"\n+\n+test_expect_success 'checking that first commit is in all tags (relative)' \"\n+\tgit tag -l --no-contains HEAD~2 v* >actual &&\n+\ttest_cmp expected actual\n+\"\n+\n cat > expected <<EOF\n v2.0\n EOF\n@@ -1413,6 +1430,17 @@ test_expect_success 'checking that second commit only has one tag' \"\n \ttest_cmp expected actual\n \"\n \n+cat > expected <<EOF\n+v0.2.1\n+v1.0\n+v1.0.1\n+v1.1.3\n+EOF\n+\n+test_expect_success 'inverse of the last test, with --no-contains' \"\n+\tgit tag -l --no-contains $hash2 v* >actual &&\n+\ttest_cmp expected actual\n+\"\n \n cat > expected <<EOF\n EOF\n@@ -1422,6 +1450,19 @@ test_expect_success 'checking that third commit has no tags' \"\n \ttest_cmp expected actual\n \"\n \n+cat > expected <<EOF\n+v0.2.1\n+v1.0\n+v1.0.1\n+v1.1.3\n+v2.0\n+EOF\n+\n+test_expect_success 'conversely --no-contains on the third commit lists all tags' \"\n+\tgit tag -l --no-contains $hash3 v* >actual &&\n+\ttest_cmp expected actual\n+\"\n+\n # how about a simple merge?\n \n test_expect_success 'creating simple branch' '\n@@ -1443,6 +1484,19 @@ test_expect_success 'checking that branch head only has one tag' \"\n \ttest_cmp expected actual\n \"\n \n+cat > expected <<EOF\n+v0.2.1\n+v1.0\n+v1.0.1\n+v1.1.3\n+v2.0\n+EOF\n+\n+test_expect_success 'checking that branch head with --no-contains lists all but one tag' \"\n+\tgit tag -l --no-contains $hash4 v* >actual &&\n+\ttest_cmp expected actual\n+\"\n+\n test_expect_success 'merging original branch into this branch' '\n \tgit merge --strategy=ours master &&\n         git tag v4.0\n@@ -1464,6 +1518,20 @@ v1.0.1\n v1.1.3\n v2.0\n v3.0\n+EOF\n+\n+test_expect_success 'checking that original branch head with --no-contains lists all but one tag now' \"\n+\tgit tag -l --no-contains $hash3 v* >actual &&\n+\ttest_cmp expected actual\n+\"\n+\n+cat > expected <<EOF\n+v0.2.1\n+v1.0\n+v1.0.1\n+v1.1.3\n+v2.0\n+v3.0\n v4.0\n EOF\n \n@@ -1477,6 +1545,12 @@ test_expect_success 'checking that --contains can be used in non-list mode' '\n \ttest_cmp expected actual\n '\n \n+test_expect_success 'checking that initial commit is in all tags with --no-contains' \"\n+\t>expected &&\n+\tgit tag -l --no-contains $hash1 v* >actual &&\n+\ttest_cmp expected actual\n+\"\n+\n # mixing modes and options:\n \n test_expect_success 'mixing incompatibles modes and options is forbidden' '\n@@ -1501,10 +1575,13 @@ test_expect_success 'mixing incompatibles modes and options is forbidden' '\n \ttest_must_fail git tag -l -F some file &&\n \ttest_must_fail git tag -v -s &&\n \ttest_must_fail git tag --contains tag-tree &&\n-\ttest_must_fail git tag --contains tag-blob\n+\ttest_must_fail git tag --contains tag-blob &&\n+\ttest_must_fail git tag --no-contains tag-tree &&\n+\ttest_must_fail git tag --no-contains tag-blob &&\n+\ttest_must_fail git tag --contains --no-contains\n '\n \n-for option in --contains --merged --no-merged --points-at\n+for option in --contains --no-contains --merged --no-merged --points-at\n do\n \ttest_expect_success \"mixing incompatible modes with $option is forbidden\" \"\n \t\ttest_must_fail git tag -d $option HEAD &&\n@@ -1771,7 +1848,7 @@ run_with_limited_stack () {\n test_lazy_prereq ULIMIT_STACK_SIZE 'run_with_limited_stack true'\n \n # we require ulimit, this excludes Windows\n-test_expect_success ULIMIT_STACK_SIZE '--contains works in a deep repo' '\n+test_expect_success ULIMIT_STACK_SIZE '--contains and --no-contains work in a deep repo' '\n \t>expect &&\n \ti=1 &&\n \twhile test $i -lt 8000\n@@ -1787,7 +1864,9 @@ EOF\"\n \tgit checkout master &&\n \tgit tag far-far-away HEAD^ &&\n \trun_with_limited_stack git tag --contains HEAD >actual &&\n-\ttest_cmp expect actual\n+\ttest_cmp expect actual &&\n+\trun_with_limited_stack git tag --no-contains HEAD >actual &&\n+\ttest_line_count \">\" 10 actual\n '\n \n test_expect_success '--format should list tags as per format given' '\n@@ -1849,4 +1928,47 @@ test_expect_success 'ambiguous branch/tags not marked' '\n \ttest_cmp expect actual\n '\n \n+test_expect_success '--contains combined with --no-contains' '\n+\t(\n+\t\tgit init no-contains &&\n+\t\tcd no-contains &&\n+\t\ttest_commit v0.1 &&\n+\t\ttest_commit v0.2 &&\n+\t\ttest_commit v0.3 &&\n+\t\ttest_commit v0.4 &&\n+\t\ttest_commit v0.5 &&\n+\t\tcat >expected <<-\\EOF &&\n+\t\tv0.2\n+\t\tv0.3\n+\t\tv0.4\n+\t\tEOF\n+\t\tgit tag --contains v0.2 --no-contains v0.5 >actual &&\n+\t\ttest_cmp expected actual\n+\t)\n+'\n+\n+# As the docs say, list tags which contain a specified *commit*. We\n+# don't recurse down to tags for trees or blobs pointed to by *those*\n+# commits.\n+test_expect_success 'Does --[no-]contains stop at commits? Yes!' '\n+\tcd no-contains &&\n+\tblob=$(git rev-parse v0.3:v0.3.t) &&\n+\ttree=$(git rev-parse v0.3^{tree}) &&\n+\tgit tag tag-blob $blob &&\n+\tgit tag tag-tree $tree &&\n+\tgit tag --contains v0.3 >actual &&\n+\tcat >expected <<-\\EOF &&\n+\tv0.3\n+\tv0.4\n+\tv0.5\n+\tEOF\n+\ttest_cmp expected actual &&\n+\tgit tag --no-contains v0.3 >actual &&\n+\tcat >expected <<-\\EOF &&\n+\tv0.1\n+\tv0.2\n+\tEOF\n+\ttest_cmp expected actual\n+'\n+\n test_done\n-- \n2.11.0\n\n"},{"id":"314796","messageId":"20170321125901.10652-3-avarab@gmail.com","threadId":"45453","inReplyTo":"20170321125901.10652-1-avarab@gmail.com","subject":"[PATCH v2 02/16] tag doc: split up the --[no-]merged documentation","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2017-03-21T12:58:47Z","receivedAt":"2017-03-21T13:01:12Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Split up the --[no-]merged documentation into documentation that\ndocuments each option independently. This is in line with how \"branch\"\nand \"for-each-ref\" are documented, and makes subsequent changes to\ndiscuss the limits & caveats of each option easier to read.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n Documentation/git-tag.txt | 11 +++++++----\n 1 file changed, 7 insertions(+), 4 deletions(-)\n\ndiff --git a/Documentation/git-tag.txt b/Documentation/git-tag.txt\nindex 33f18ea5fb..68b0ab2410 100644\n--- a/Documentation/git-tag.txt\n+++ b/Documentation/git-tag.txt\n@@ -124,10 +124,13 @@ This option is only applicable when listing tags without annotation lines.\n \tOnly list tags which contain the specified commit (HEAD if not\n \tspecified).\n \n---[no-]merged [<commit>]::\n-\tOnly list tags whose tips are reachable, or not reachable\n-\tif `--no-merged` is used, from the specified commit (`HEAD`\n-\tif not specified).\n+--merged [<commit>]::\n+\tOnly list tags whose tips are reachable from the specified commit\n+\t(`HEAD` if not specified).\n+\n+--no-merged [<commit>]::\n+\tOnly list tags whose tips are not reachable from the specified\n+\tcommit (`HEAD` if not specified).\n \n --points-at <object>::\n \tOnly list tags of the given object.\n-- \n2.11.0\n\n"},{"id":"314797","messageId":"20170321125901.10652-13-avarab@gmail.com","threadId":"45453","inReplyTo":"20170321125901.10652-1-avarab@gmail.com","subject":"[PATCH v2 12/16] tag: change --point-at to default to HEAD","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2017-03-21T12:58:57Z","receivedAt":"2017-03-21T13:01:16Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change the --points-at option to default to HEAD for consistency with\nits siblings --contains, --merged etc. which default to\nHEAD. Previously we'd get:\n\n    $ git tag --points-at 2>&1 | head -n 1\n    error: option `points-at' requires a value\n\nThis changes behavior added in commit ae7706b9ac (tag: add --points-at\nlist option, 2012-02-08).\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n Documentation/git-tag.txt | 3 ++-\n builtin/tag.c             | 3 ++-\n t/t7004-tag.sh            | 9 ++++++++-\n 3 files changed, 12 insertions(+), 3 deletions(-)\n\ndiff --git a/Documentation/git-tag.txt b/Documentation/git-tag.txt\nindex b9dffc4128..baf96944ae 100644\n--- a/Documentation/git-tag.txt\n+++ b/Documentation/git-tag.txt\n@@ -139,7 +139,8 @@ This option is only applicable when listing tags without annotation lines.\n \tcommit (`HEAD` if not specified), incompatible with `--merged`.\n \n --points-at <object>::\n-\tOnly list tags of the given object. Implies `--list`.\n+\tOnly list tags of the given object (HEAD if not\n+\tspecified). Implies `--list`.\n \n -m <msg>::\n --message=<msg>::\ndiff --git a/builtin/tag.c b/builtin/tag.c\nindex ec987ae3c7..dde05beb31 100644\n--- a/builtin/tag.c\n+++ b/builtin/tag.c\n@@ -431,7 +431,8 @@ int cmd_tag(int argc, const char **argv, const char *prefix)\n \t\t\t     N_(\"field name to sort on\"), &parse_opt_ref_sorting),\n \t\t{\n \t\t\tOPTION_CALLBACK, 0, \"points-at\", &filter.points_at, N_(\"object\"),\n-\t\t\tN_(\"print only tags of the object\"), 0, parse_opt_object_name\n+\t\t\tN_(\"print only tags of the object\"), PARSE_OPT_LASTARG_DEFAULT,\n+\t\t\tparse_opt_object_name, (intptr_t) \"HEAD\"\n \t\t},\n \t\tOPT_STRING(  0 , \"format\", &format, N_(\"format\"), N_(\"format to use for the output\")),\n \t\tOPT_BOOL('i', \"ignore-case\", &icase, N_(\"sorting and filtering are case insensitive\")),\ndiff --git a/t/t7004-tag.sh b/t/t7004-tag.sh\nindex dd793e43aa..b45ea8f5ac 100755\n--- a/t/t7004-tag.sh\n+++ b/t/t7004-tag.sh\n@@ -1513,7 +1513,8 @@ do\n \t\"\n \ttest_expect_success \"Doing 'git tag --list-like $option <commit> <pattern> is permitted\" \"\n \t\tgit tag -n $option HEAD HEAD &&\n-\t\tgit tag $option HEAD HEAD\n+\t\tgit tag $option HEAD HEAD &&\n+\t\tgit tag $option\n \t\"\n done\n \n@@ -1525,6 +1526,12 @@ test_expect_success '--points-at can be used in non-list mode' '\n \ttest_cmp expect actual\n '\n \n+test_expect_success '--points-at is a synonym for --points-at HEAD' '\n+\techo v4.0 >expect &&\n+\tgit tag --points-at >actual &&\n+\ttest_cmp expect actual\n+'\n+\n test_expect_success '--points-at finds lightweight tags' '\n \techo v4.0 >expect &&\n \tgit tag --points-at v4.0 >actual &&\n-- \n2.11.0\n\n"},{"id":"314798","messageId":"20170321125901.10652-7-avarab@gmail.com","threadId":"45453","inReplyTo":"20170321125901.10652-1-avarab@gmail.com","subject":"[PATCH v2 06/16] tag: remove a TODO item from the test suite","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2017-03-21T12:58:51Z","receivedAt":"2017-03-21T13:01:22Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change the test for \"git tag -l\" to not have an associated TODO\ncomment saying that it should return non-zero if there's no tags.\n\nThis was added in commit ef5a6fb597 (\"Add test-script for git-tag\",\n2007-06-28) when the tests for \"tag\" were initially added, but at this\npoint changing this would be inconsistent with how \"git tag\" is a\nsynonym for \"git tag -l\", and would needlessly break external code\nthat relies on this porcelain command.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t7004-tag.sh | 2 --\n 1 file changed, 2 deletions(-)\n\ndiff --git a/t/t7004-tag.sh b/t/t7004-tag.sh\nindex 3439913488..830eff948e 100755\n--- a/t/t7004-tag.sh\n+++ b/t/t7004-tag.sh\n@@ -16,7 +16,6 @@ tag_exists () {\n \tgit show-ref --quiet --verify refs/tags/\"$1\"\n }\n \n-# todo: git tag -l now returns always zero, when fixed, change this test\n test_expect_success 'listing all tags in an empty tree should succeed' '\n \tgit tag -l &&\n \tgit tag\n@@ -136,7 +135,6 @@ test_expect_success \\\n \t'listing a tag using a matching pattern should output that tag' \\\n \t'test $(git tag -l mytag) = mytag'\n \n-# todo: git tag -l now returns always zero, when fixed, change this test\n test_expect_success \\\n \t'listing tags using a non-matching pattern should suceed' \\\n \t'git tag -l xxx'\n-- \n2.11.0\n\n"},{"id":"314799","messageId":"20170321125901.10652-5-avarab@gmail.com","threadId":"45453","inReplyTo":"20170321125901.10652-1-avarab@gmail.com","subject":"[PATCH v2 04/16] ref-filter: make combining --merged & --no-merged an error","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2017-03-21T12:58:49Z","receivedAt":"2017-03-21T13:01:23Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change the behavior of specifying --merged & --no-merged to be an\nerror, instead of silently picking the option that was provided last.\n\nSubsequent changes of mine add a --no-contains option in addition to\nthe existing --contains. Providing both of those isn't an error, and\nhas actual meaning.\n\nMaking its cousins have different behavior in this regard would be\nconfusing to the user, especially since we'd be silently disregarding\nsome of their command-line input.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n Documentation/git-branch.txt       |  6 ++++--\n Documentation/git-for-each-ref.txt |  6 ++++--\n Documentation/git-tag.txt          |  4 ++--\n ref-filter.c                       | 11 ++++++++++-\n t/t3200-branch.sh                  |  4 ++++\n t/t6302-for-each-ref-filter.sh     |  4 ++++\n t/t7004-tag.sh                     |  4 ++++\n 7 files changed, 32 insertions(+), 7 deletions(-)\n\ndiff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt\nindex 092f1bcf9f..e465298571 100644\n--- a/Documentation/git-branch.txt\n+++ b/Documentation/git-branch.txt\n@@ -215,11 +215,13 @@ start-point is either a local or remote-tracking branch.\n \n --merged [<commit>]::\n \tOnly list branches whose tips are reachable from the\n-\tspecified commit (HEAD if not specified). Implies `--list`.\n+\tspecified commit (HEAD if not specified). Implies `--list`,\n+\tincompatible with `--no-merged`.\n \n --no-merged [<commit>]::\n \tOnly list branches whose tips are not reachable from the\n-\tspecified commit (HEAD if not specified). Implies `--list`.\n+\tspecified commit (HEAD if not specified). Implies `--list`,\n+\tincompatible with `--merged`.\n \n <branchname>::\n \tThe name of the branch to create or delete.\ndiff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt\nindex 111e1be6f5..4d55893712 100644\n--- a/Documentation/git-for-each-ref.txt\n+++ b/Documentation/git-for-each-ref.txt\n@@ -69,11 +69,13 @@ OPTIONS\n \n --merged [<object>]::\n \tOnly list refs whose tips are reachable from the\n-\tspecified commit (HEAD if not specified).\n+\tspecified commit (HEAD if not specified),\n+\tincompatible with `--no-merged`.\n \n --no-merged [<object>]::\n \tOnly list refs whose tips are not reachable from the\n-\tspecified commit (HEAD if not specified).\n+\tspecified commit (HEAD if not specified),\n+\tincompatible with `--merged`.\n \n --contains [<object>]::\n \tOnly list refs which contain the specified commit (HEAD if not\ndiff --git a/Documentation/git-tag.txt b/Documentation/git-tag.txt\nindex 3abf912782..448fdf3743 100644\n--- a/Documentation/git-tag.txt\n+++ b/Documentation/git-tag.txt\n@@ -126,11 +126,11 @@ This option is only applicable when listing tags without annotation lines.\n \n --merged [<commit>]::\n \tOnly list tags whose commits are reachable from the specified\n-\tcommit (`HEAD` if not specified).\n+\tcommit (`HEAD` if not specified), incompatible with `--no-merged`.\n \n --no-merged [<commit>]::\n \tOnly list tags whose commits are not reachable from the specified\n-\tcommit (`HEAD` if not specified).\n+\tcommit (`HEAD` if not specified), incompatible with `--merged`.\n \n --points-at <object>::\n \tOnly list tags of the given object.\ndiff --git a/ref-filter.c b/ref-filter.c\nindex 9c82b5b9d6..d7efae7b53 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -2084,8 +2084,17 @@ int parse_opt_merge_filter(const struct option *opt, const char *arg, int unset)\n {\n \tstruct ref_filter *rf = opt->value;\n \tunsigned char sha1[20];\n+\tint no_merged = starts_with(opt->long_name, \"no\");\n \n-\trf->merge = starts_with(opt->long_name, \"no\")\n+\tif (rf->merge) {\n+\t\tif (no_merged) {\n+\t\t\treturn opterror(opt, \"is incompatible with --merged\", 0);\n+\t\t} else {\n+\t\t\treturn opterror(opt, \"is incompatible with --no-merged\", 0);\n+\t\t}\n+\t}\n+\n+\trf->merge = no_merged\n \t\t? REF_FILTER_MERGED_OMIT\n \t\t: REF_FILTER_MERGED_INCLUDE;\n \ndiff --git a/t/t3200-branch.sh b/t/t3200-branch.sh\nindex 9f353c0efc..fe62e7c775 100755\n--- a/t/t3200-branch.sh\n+++ b/t/t3200-branch.sh\n@@ -978,6 +978,10 @@ test_expect_success '--merged catches invalid object names' '\n \ttest_must_fail git branch --merged 0000000000000000000000000000000000000000\n '\n \n+test_expect_success '--merged is incompatible with --no-merged' '\n+\ttest_must_fail git branch --merged HEAD --no-merged HEAD\n+'\n+\n test_expect_success 'tracking with unexpected .fetch refspec' '\n \trm -rf a b c d &&\n \tgit init a &&\ndiff --git a/t/t6302-for-each-ref-filter.sh b/t/t6302-for-each-ref-filter.sh\nindex a09a1a46ef..d36d5dc124 100755\n--- a/t/t6302-for-each-ref-filter.sh\n+++ b/t/t6302-for-each-ref-filter.sh\n@@ -421,4 +421,8 @@ test_expect_success 'check %(if:notequals=<string>)' '\n \ttest_cmp expect actual\n '\n \n+test_expect_success '--merged is incompatible with --no-merged' '\n+\ttest_must_fail git for-each-ref --merged HEAD --no-merged HEAD\n+'\n+\n test_done\ndiff --git a/t/t7004-tag.sh b/t/t7004-tag.sh\nindex b4698ab5f5..45790664c1 100755\n--- a/t/t7004-tag.sh\n+++ b/t/t7004-tag.sh\n@@ -1748,6 +1748,10 @@ test_expect_success '--merged cannot be used in non-list mode' '\n \ttest_must_fail git tag --merged=mergetest-2 foo\n '\n \n+test_expect_success '--merged is incompatible with --no-merged' '\n+\ttest_must_fail git tag --merged HEAD --no-merged HEAD\n+'\n+\n test_expect_success '--merged shows merged tags' '\n \tcat >expect <<-\\EOF &&\n \tmergetest-1\n-- \n2.11.0\n\n"},{"id":"314800","messageId":"20170321125901.10652-6-avarab@gmail.com","threadId":"45453","inReplyTo":"20170321125901.10652-1-avarab@gmail.com","subject":"[PATCH v2 05/16] ref-filter: add test for --contains on a non-commit","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2017-03-21T12:58:50Z","receivedAt":"2017-03-21T13:01:24Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change the tag test suite to test for --contains on a tree & blob, it\nonly accepts commits and will spew out \"<object> is a tree, not a\ncommit\".\n\nIt's sufficient to test this just for the \"tag\" and \"branch\" commands,\nbecause it covers all the machinery is shared between \"branch\" and\n\"for-each-ref\".\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t3201-branch-contains.sh | 9 +++++++++\n t/t7004-tag.sh             | 4 +++-\n 2 files changed, 12 insertions(+), 1 deletion(-)\n\ndiff --git a/t/t3201-branch-contains.sh b/t/t3201-branch-contains.sh\nindex 7f3ec47241..daa3ae82b7 100755\n--- a/t/t3201-branch-contains.sh\n+++ b/t/t3201-branch-contains.sh\n@@ -130,6 +130,15 @@ test_expect_success 'implicit --list conflicts with modification options' '\n \n '\n \n+test_expect_success 'Assert that --contains only works on commits, not trees & blobs' '\n+\ttest_must_fail git branch --contains master^{tree} &&\n+\tblob=$(git hash-object -w --stdin <<-\\EOF\n+\tSome blob\n+\tEOF\n+\t) &&\n+\ttest_must_fail git branch --contains $blob\n+'\n+\n # We want to set up a case where the walk for the tracking info\n # of one branch crosses the tip of another branch (and make sure\n # that the latter walk does not mess up our flag to see if it was\ndiff --git a/t/t7004-tag.sh b/t/t7004-tag.sh\nindex 45790664c1..3439913488 100755\n--- a/t/t7004-tag.sh\n+++ b/t/t7004-tag.sh\n@@ -1461,7 +1461,9 @@ test_expect_success 'mixing incompatibles modes and options is forbidden' '\n \ttest_must_fail git tag -n 100 &&\n \ttest_must_fail git tag -l -m msg &&\n \ttest_must_fail git tag -l -F some file &&\n-\ttest_must_fail git tag -v -s\n+\ttest_must_fail git tag -v -s &&\n+\ttest_must_fail git tag --contains tag-tree &&\n+\ttest_must_fail git tag --contains tag-blob\n '\n \n # check points-at\n-- \n2.11.0\n\n"},{"id":"314801","messageId":"20170321125901.10652-8-avarab@gmail.com","threadId":"45453","inReplyTo":"20170321125901.10652-1-avarab@gmail.com","subject":"[PATCH v2 07/16] tag tests: fix a typo in a test description","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2017-03-21T12:58:52Z","receivedAt":"2017-03-21T13:01:26Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change \"suceed\" to \"succeed\" in a test description. The typo has been\nhere since the code was originally added in commit ef5a6fb597 (\"Add\ntest-script for git-tag\", 2007-06-28).\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t7004-tag.sh | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/t/t7004-tag.sh b/t/t7004-tag.sh\nindex 830eff948e..63ee2cf727 100755\n--- a/t/t7004-tag.sh\n+++ b/t/t7004-tag.sh\n@@ -136,7 +136,7 @@ test_expect_success \\\n \t'test $(git tag -l mytag) = mytag'\n \n test_expect_success \\\n-\t'listing tags using a non-matching pattern should suceed' \\\n+\t'listing tags using a non-matching pattern should succeed' \\\n \t'git tag -l xxx'\n \n test_expect_success \\\n-- \n2.11.0\n\n"},{"id":"314802","messageId":"20170321125901.10652-9-avarab@gmail.com","threadId":"45453","inReplyTo":"20170321125901.10652-1-avarab@gmail.com","subject":"[PATCH v2 08/16] for-each-ref: partly change <object> to <commit> in help","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2017-03-21T12:58:53Z","receivedAt":"2017-03-21T13:01:28Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change mentions of <object> to <commit> in the help output of\nfor-each-ref as appropriate.\n\nBoth --[no-]merged and --contains only take commits, but --points-at\ncan take any object, such as a tag pointing to a tree or blob.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/for-each-ref.c | 4 ++--\n 1 file changed, 2 insertions(+), 2 deletions(-)\n\ndiff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c\nindex df41fa0350..1a5ed20f59 100644\n--- a/builtin/for-each-ref.c\n+++ b/builtin/for-each-ref.c\n@@ -8,8 +8,8 @@\n static char const * const for_each_ref_usage[] = {\n \tN_(\"git for-each-ref [<options>] [<pattern>]\"),\n \tN_(\"git for-each-ref [--points-at <object>]\"),\n-\tN_(\"git for-each-ref [(--merged | --no-merged) [<object>]]\"),\n-\tN_(\"git for-each-ref [--contains [<object>]]\"),\n+\tN_(\"git for-each-ref [(--merged | --no-merged) [<commit>]]\"),\n+\tN_(\"git for-each-ref [--contains [<commit>]]\"),\n \tNULL\n };\n \n-- \n2.11.0\n\n"},{"id":"314803","messageId":"20170321125901.10652-10-avarab@gmail.com","threadId":"45453","inReplyTo":"20170321125901.10652-1-avarab@gmail.com","subject":"[PATCH v2 09/16] tag: add more incompatibles mode tests","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2017-03-21T12:58:54Z","receivedAt":"2017-03-21T13:01:31Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Amend the test suite to test for more invalid uses like \"-l -a\"\netc. This mainly tests the `(argc == 0 && !cmdmode)` ->\n`((create_tag_object || force) && (cmdmode != 0))` code path in\nbuiltin/tag.c.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t7004-tag.sh | 13 +++++++++++++\n 1 file changed, 13 insertions(+)\n\ndiff --git a/t/t7004-tag.sh b/t/t7004-tag.sh\nindex 63ee2cf727..958c77ab86 100755\n--- a/t/t7004-tag.sh\n+++ b/t/t7004-tag.sh\n@@ -1455,6 +1455,19 @@ test_expect_success 'checking that initial commit is in all tags' \"\n \n test_expect_success 'mixing incompatibles modes and options is forbidden' '\n \ttest_must_fail git tag -a &&\n+\ttest_must_fail git tag -a -l &&\n+\ttest_must_fail git tag -s &&\n+\ttest_must_fail git tag -s -l &&\n+\ttest_must_fail git tag -m &&\n+\ttest_must_fail git tag -m -l &&\n+\ttest_must_fail git tag -m \"hlagh\" &&\n+\ttest_must_fail git tag -m \"hlagh\" -l &&\n+\ttest_must_fail git tag -F &&\n+\ttest_must_fail git tag -F -l &&\n+\ttest_must_fail git tag -f &&\n+\ttest_must_fail git tag -f -l &&\n+\ttest_must_fail git tag -a -s -m -F &&\n+\ttest_must_fail git tag -a -s -m -F -l &&\n \ttest_must_fail git tag -l -v &&\n \ttest_must_fail git tag -n 100 &&\n \ttest_must_fail git tag -l -m msg &&\n-- \n2.11.0\n\n"},{"id":"314804","messageId":"20170321125901.10652-17-avarab@gmail.com","threadId":"45453","inReplyTo":"20170321125901.10652-1-avarab@gmail.com","subject":"[PATCH v2 16/16] tag: add tests for --with and --without","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2017-03-21T12:59:01Z","receivedAt":"2017-03-21T13:01:34Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change the test suite to test for these synonyms for --contains and\n--no-contains, respectively.\n\nBefore this change there were no tests for them at all. This doesn't\nexhaustively test for them as well as their --contains and\n--no-contains synonyms, but at least it's something.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t7004-tag.sh | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/t/t7004-tag.sh b/t/t7004-tag.sh\nindex 60b5cd8751..8cd611344f 100755\n--- a/t/t7004-tag.sh\n+++ b/t/t7004-tag.sh\n@@ -1596,7 +1596,7 @@ test_expect_success 'mixing incompatibles modes and options is forbidden' '\n \ttest_must_fail git tag --contains --no-contains\n '\n \n-for option in --contains --no-contains --merged --no-merged --points-at\n+for option in --contains --with --no-contains --without --merged --no-merged --points-at\n do\n \ttest_expect_success \"mixing incompatible modes with $option is forbidden\" \"\n \t\ttest_must_fail git tag -d $option HEAD &&\n-- \n2.11.0\n\n"},{"id":"314805","messageId":"20170321125901.10652-11-avarab@gmail.com","threadId":"45453","inReplyTo":"20170321125901.10652-1-avarab@gmail.com","subject":"[PATCH v2 10/16] tag: change misleading --list <pattern> documentation","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2017-03-21T12:58:55Z","receivedAt":"2017-03-21T13:01:39Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change the documentation for --list so that it's described as a\ntoggle, not as an option that takes a <pattern> as an argument.\n\nJunio initially documented this in b867c7c23a (\"git-tag: -l to list\ntags (usability).\", 2006-02-17), but later Jeff King changed \"tag\" to\naccept multiple patterns in 588d0e834b (\"tag: accept multiple patterns\nfor --list\", 2011-06-20).\n\nHowever, documenting this as \"-l <pattern>\" was never correct, as\nthese both worked before Jeff's change:\n\n    git tag -l 'v*'\n    git tag 'v*' -l\n\nOne would expect an option that was documented like that to only\naccept:\n\n    git tag --list\n    git tag --list 'v*rc*'\n\nAnd after Jeff's change, one that took multiple patterns:\n\n    git tag --list 'v*rc*' --list '*2.8*'\n\nBut since it's actually a toggle all of these work as well, and\nproduce identical output to the last example above:\n\n    git tag --list 'v*rc*' '*2.8*'\n    git tag --list 'v*rc*' '*2.8*' --list --list --list\n    git tag --list 'v*rc*' '*2.8*' --list -l --list -l --list\n\nNow the documentation is more in tune with how the \"branch\" command\ndescribes its --list option since commit cddd127b9a (\"branch:\nintroduce --list option\", 2011-08-28).\n\nChange the test suite to assert that these invocations work for the\ncases that weren't already being tested for.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n Documentation/git-tag.txt | 16 +++++++++-------\n t/t7004-tag.sh            | 21 +++++++++++++++++++++\n 2 files changed, 30 insertions(+), 7 deletions(-)\n\ndiff --git a/Documentation/git-tag.txt b/Documentation/git-tag.txt\nindex 448fdf3743..d534c57156 100644\n--- a/Documentation/git-tag.txt\n+++ b/Documentation/git-tag.txt\n@@ -87,13 +87,15 @@ OPTIONS\n \tIf no number is given to `-n`, only the first line is printed.\n \tIf the tag is not annotated, the commit message is displayed instead.\n \n--l <pattern>::\n---list <pattern>::\n-\tList tags with names that match the given pattern (or all if no\n-\tpattern is given).  Running \"git tag\" without arguments also\n-\tlists all tags. The pattern is a shell wildcard (i.e., matched\n-\tusing fnmatch(3)).  Multiple patterns may be given; if any of\n-\tthem matches, the tag is shown.\n+-l::\n+--list::\n+\tActivate the list mode. `git tag <pattern>` would try to create a\n+\ttag, use `git tag --list <pattern>` to list matching branches, (or\n+\tall if no pattern is given).\n++\n+Running \"git tag\" without arguments also lists all tags. The pattern\n+is a shell wildcard (i.e., matched using fnmatch(3)). Multiple\n+patterns may be given; if any of them matches, the tag is shown.\n \n --sort=<key>::\n \tSort based on the key given.  Prefix `-` to sort in\ndiff --git a/t/t7004-tag.sh b/t/t7004-tag.sh\nindex 958c77ab86..1de7185be0 100755\n--- a/t/t7004-tag.sh\n+++ b/t/t7004-tag.sh\n@@ -118,6 +118,18 @@ test_expect_success 'listing all tags if one exists should succeed' '\n \tgit tag\n '\n \n+cat >expect <<EOF\n+mytag\n+EOF\n+test_expect_success 'Multiple -l or --list options are equivalent to one -l option' '\n+\tgit tag -l -l >actual &&\n+\ttest_cmp expect actual &&\n+\tgit tag --list --list >actual &&\n+\ttest_cmp expect actual &&\n+\tgit tag --list -l --list >actual &&\n+\ttest_cmp expect actual\n+'\n+\n test_expect_success 'listing all tags if one exists should output that tag' '\n \ttest $(git tag -l) = mytag &&\n \ttest $(git tag) = mytag\n@@ -336,6 +348,15 @@ test_expect_success 'tag -l can accept multiple patterns' '\n \ttest_cmp expect actual\n '\n \n+test_expect_success 'tag -l can accept multiple patterns interleaved with -l or --list options' '\n+\tgit tag -l \"v1*\" \"v0*\" >actual &&\n+\ttest_cmp expect actual &&\n+\tgit tag -l \"v1*\" --list \"v0*\" >actual &&\n+\ttest_cmp expect actual &&\n+\tgit tag -l \"v1*\" \"v0*\" -l --list >actual &&\n+\ttest_cmp expect actual\n+'\n+\n test_expect_success 'listing tags in column' '\n \tCOLUMNS=40 git tag -l --column=row >actual &&\n \tcat >expected <<\\EOF &&\n-- \n2.11.0\n\n"},{"id":"314806","messageId":"20170321125901.10652-12-avarab@gmail.com","threadId":"45453","inReplyTo":"20170321125901.10652-1-avarab@gmail.com","subject":"[PATCH v2 11/16] tag: implicitly supply --list given another list-like option","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2017-03-21T12:58:56Z","receivedAt":"2017-03-21T13:01:43Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change the \"tag\" command to implicitly turn on its --list mode when\nprovided with a list-like option such as --contains, --points-at etc.\n\nThis is for consistency with how \"branch\" works. When \"branch\" is\ngiven a list-like option, such as --contains, it implicitly provides\n--list. Before this change \"tag\" would error out on those sorts of\ninvocations. I.e. while both of these worked for \"branch\":\n\n    git branch --contains v2.8.0 <pattern>\n    git branch --list --contains v2.8.0 <pattern>\n\nOnly the latter form worked for \"tag\":\n\n    git tag --contains v2.8.0 '*rc*'\n    git tag --list --contains v2.8.0 '*rc*'\n\nNow \"tag\", like \"branch\", will implicitly supply --list when a\nlist-like option is provided, and no other conflicting non-list\noptions (such as -d) are present on the command-line.\n\nSpelunking through the history via:\n\n    git log --reverse -p -G'only allowed with' -- '*builtin*tag*c'\n\nReveals that there was no good reason for not allowing this in the\nfirst place. The --contains option added in 32c35cfb1e (\"git-tag: Add\n--contains option\", 2009-01-26) made this an error,. All the other\nsubsequent list-like options that were added copied its pattern of\nmaking this usage an error.\n\nThe only tests that break as a result of this change are tests that\nwere explicitly checking that this \"branch-like\" usage wasn't\npermitted. Change those failing tests to check that this invocation\nmode is permitted, add extra tests for the list-like options we\nweren't testing, and tests to ensure that e.g. we don't toggle the\nlist mode in the presence of other conflicting non-list options.\n\nWith this change errors messages such as \"--contains option is only\nallowed with -l\" don't make sense anymore, since options like\n--contain turn on -l. Instead we error out when list-like options such\nas --contain are used in conjunction with conflicting options such as\n-d or -v.\n\nThis change does not consider \"-n\" a list-like option, even though\nthat might be logical. Permitting it would allow:\n\n    git tag -n 100\n\nAs a synonym for:\n\n    git tag -n --list 100\n\nWhich, while not technically ambiguous as the option must already be\nprovided as -n<num> rather than -n <num>, would be confusing.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n Documentation/git-tag.txt |  8 ++++++--\n builtin/tag.c             | 17 +++++++++++------\n t/t7004-tag.sh            | 39 +++++++++++++++++++++++++++++++++++----\n 3 files changed, 52 insertions(+), 12 deletions(-)\n\ndiff --git a/Documentation/git-tag.txt b/Documentation/git-tag.txt\nindex d534c57156..b9dffc4128 100644\n--- a/Documentation/git-tag.txt\n+++ b/Documentation/git-tag.txt\n@@ -96,6 +96,10 @@ OPTIONS\n Running \"git tag\" without arguments also lists all tags. The pattern\n is a shell wildcard (i.e., matched using fnmatch(3)). Multiple\n patterns may be given; if any of them matches, the tag is shown.\n++\n+This option is implicitly supplied if any other list-like option such\n+as `--contains` is provided. See the documentation for each of those\n+options for details.\n \n --sort=<key>::\n \tSort based on the key given.  Prefix `-` to sort in\n@@ -124,7 +128,7 @@ This option is only applicable when listing tags without annotation lines.\n \n --contains [<commit>]::\n \tOnly list tags which contain the specified commit (HEAD if not\n-\tspecified).\n+\tspecified). Implies `--list`.\n \n --merged [<commit>]::\n \tOnly list tags whose commits are reachable from the specified\n@@ -135,7 +139,7 @@ This option is only applicable when listing tags without annotation lines.\n \tcommit (`HEAD` if not specified), incompatible with `--merged`.\n \n --points-at <object>::\n-\tOnly list tags of the given object.\n+\tOnly list tags of the given object. Implies `--list`.\n \n -m <msg>::\n --message=<msg>::\ndiff --git a/builtin/tag.c b/builtin/tag.c\nindex ad29be6923..ec987ae3c7 100644\n--- a/builtin/tag.c\n+++ b/builtin/tag.c\n@@ -454,8 +454,13 @@ int cmd_tag(int argc, const char **argv, const char *prefix)\n \t}\n \tcreate_tag_object = (opt.sign || annotate || msg.given || msgfile);\n \n-\tif (argc == 0 && !cmdmode)\n-\t\tcmdmode = 'l';\n+\tif (!cmdmode) {\n+\t\tif (argc == 0)\n+\t\t\tcmdmode = 'l';\n+\t\telse if (filter.with_commit ||\n+\t\t\t filter.points_at.nr || filter.merge_commit)\n+\t\t\tcmdmode = 'l';\n+\t}\n \n \tif ((create_tag_object || force) && (cmdmode != 0))\n \t\tusage_with_options(git_tag_usage, options);\n@@ -485,13 +490,13 @@ int cmd_tag(int argc, const char **argv, const char *prefix)\n \t\treturn ret;\n \t}\n \tif (filter.lines != -1)\n-\t\tdie(_(\"-n option is only allowed with -l.\"));\n+\t\tdie(_(\"-n option is only allowed in list mode\"));\n \tif (filter.with_commit)\n-\t\tdie(_(\"--contains option is only allowed with -l.\"));\n+\t\tdie(_(\"--contains option is only allowed in list mode\"));\n \tif (filter.points_at.nr)\n-\t\tdie(_(\"--points-at option is only allowed with -l.\"));\n+\t\tdie(_(\"--points-at option is only allowed in list mode\"));\n \tif (filter.merge_commit)\n-\t\tdie(_(\"--merged and --no-merged option are only allowed with -l\"));\n+\t\tdie(_(\"--merged and --no-merged options are only allowed in list mode\"));\n \tif (cmdmode == 'd')\n \t\treturn for_each_tag_name(argv, delete_tag, NULL);\n \tif (cmdmode == 'v') {\ndiff --git a/t/t7004-tag.sh b/t/t7004-tag.sh\nindex 1de7185be0..dd793e43aa 100755\n--- a/t/t7004-tag.sh\n+++ b/t/t7004-tag.sh\n@@ -1472,6 +1472,11 @@ test_expect_success 'checking that initial commit is in all tags' \"\n \ttest_cmp expected actual\n \"\n \n+test_expect_success 'checking that --contains can be used in non-list mode' '\n+\tgit tag --contains $hash1 v* >actual &&\n+\ttest_cmp expected actual\n+'\n+\n # mixing modes and options:\n \n test_expect_success 'mixing incompatibles modes and options is forbidden' '\n@@ -1491,6 +1496,7 @@ test_expect_success 'mixing incompatibles modes and options is forbidden' '\n \ttest_must_fail git tag -a -s -m -F -l &&\n \ttest_must_fail git tag -l -v &&\n \ttest_must_fail git tag -n 100 &&\n+\ttest_must_fail git tag -n 100 -v &&\n \ttest_must_fail git tag -l -m msg &&\n \ttest_must_fail git tag -l -F some file &&\n \ttest_must_fail git tag -v -s &&\n@@ -1498,10 +1504,25 @@ test_expect_success 'mixing incompatibles modes and options is forbidden' '\n \ttest_must_fail git tag --contains tag-blob\n '\n \n+for option in --contains --merged --no-merged --points-at\n+do\n+\ttest_expect_success \"mixing incompatible modes with $option is forbidden\" \"\n+\t\ttest_must_fail git tag -d $option HEAD &&\n+\t\ttest_must_fail git tag -d $option HEAD some-tag &&\n+\t\ttest_must_fail git tag -v $option HEAD\n+\t\"\n+\ttest_expect_success \"Doing 'git tag --list-like $option <commit> <pattern> is permitted\" \"\n+\t\tgit tag -n $option HEAD HEAD &&\n+\t\tgit tag $option HEAD HEAD\n+\t\"\n+done\n+\n # check points-at\n \n-test_expect_success '--points-at cannot be used in non-list mode' '\n-\ttest_must_fail git tag --points-at=v4.0 foo\n+test_expect_success '--points-at can be used in non-list mode' '\n+\techo v4.0 >expect &&\n+\tgit tag --points-at=v4.0 \"v*\" >actual &&\n+\ttest_cmp expect actual\n '\n \n test_expect_success '--points-at finds lightweight tags' '\n@@ -1778,8 +1799,13 @@ test_expect_success 'setup --merged test tags' '\n \tgit tag mergetest-3 HEAD\n '\n \n-test_expect_success '--merged cannot be used in non-list mode' '\n-\ttest_must_fail git tag --merged=mergetest-2 foo\n+test_expect_success '--merged can be used in non-list mode' '\n+\tcat >expect <<-\\EOF &&\n+\tmergetest-1\n+\tmergetest-2\n+\tEOF\n+\tgit tag --merged=mergetest-2 \"mergetest*\" >actual &&\n+\ttest_cmp expect actual\n '\n \n test_expect_success '--merged is incompatible with --no-merged' '\n@@ -1803,6 +1829,11 @@ test_expect_success '--no-merged show unmerged tags' '\n \ttest_cmp expect actual\n '\n \n+test_expect_success '--no-merged can be used in non-list mode' '\n+\tgit tag --no-merged=mergetest-2 mergetest-* >actual &&\n+\ttest_cmp expect actual\n+'\n+\n test_expect_success 'ambiguous branch/tags not marked' '\n \tgit tag ambiguous &&\n \tgit branch ambiguous &&\n-- \n2.11.0\n\n"},{"id":"314807","messageId":"20170321125901.10652-1-avarab@gmail.com","threadId":"45453","inReplyTo":null,"subject":"[PATCH v2 00/16] Various changes to the \"tag\" command & related","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2017-03-21T12:58:45Z","receivedAt":"2017-03-21T13:08:18Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"This series is now 2x the size of v1. The reason is that the\ndiscussion for v1 brought up lots of related side-points that I fixed\nwhile I was at it. Most if this *could* be split off, but since a lot\nof it's modifying the same bits of code doing that would result in\nmerge conflict galore, so I think it's easier to bundle it up.\n\nComments on individual patches below:\n\nÆvar Arnfjörð Bjarmason (16):\n  tag doc: move the description of --[no-]merged earlier\n  tag doc: split up the --[no-]merged documentation\n  tag doc: reword --[no-]merged to talk about commits, not tips\n\nNEW: Document that --merged & --no-merged operate on commits, not\nobjects. Split up the docs to document each option indepenently for\nease of subsequent changes.\n\n  ref-filter: make combining --merged & --no-merged an error\n\nNEW: Currently \"--merged HEAD --no-merged HEAD\" is just silently\nequivalent to \"--no-merged HEAD\". Make the former an \"incompatible\noptions\" error.\n\n  ref-filter: add test for --contains on a non-commit\n\nNEW: Jeff suggested we should test for this. Make it so.\n\n  tag: remove a TODO item from the test suite\n\nNo changes.\n\n  tag tests: fix a typo in a test description\n\nNEW: Fix a tag test typo.\n\n  for-each-ref: partly change <object> to <commit> in help\n\nNEW: Clarify the for-each-ref --help output.\n\n  tag: add more incompatibles mode tests\n\nCHANGED: I dropped the \"tag: Refactor the options handling code to be\nless bizarro\" patch, but these are the tests that came along with it.\n\n  tag: change misleading --list <pattern> documentation\n\nNo changes.\n\n  tag: implicitly supply --list given another list-like option\n\nChanged: Typo fixes in commit message, `argc == 0 && !cmdmode` logic\nchanges, code reflow, better error messages etc.\n\n  tag: change --point-at to default to HEAD\n\nChanged: Fixed up an \">expect\" at the start of the test.\n\n  ref-filter: add --no-contains option to tag/branch/for-each-ref\n\nChanged: Typos/grammar in commit message, get rid of needless \"else\",\ntests for tree/tag blobs.\n\n  ref-filter: reflow recently changed branch/tag/for-each-ref docs\n\nNEW: Split off reflowing of documentation paragraphs from the above\nfor ease of reading.\n\n  tag: implicitly supply --list given the -n option\n\nRe-arranged: I still want this included, but the consensus on the list\nwasn't as strong, so it's moved later in the series so it can be\ndropped without conflicts.\n\n  tag: add tests for --with and --without\n\nNo changes.\n\n Documentation/git-branch.txt           |  33 +++--\n Documentation/git-for-each-ref.txt     |  12 +-\n Documentation/git-tag.txt              |  60 ++++++---\n builtin/branch.c                       |   5 +-\n builtin/for-each-ref.c                 |   5 +-\n builtin/tag.c                          |  27 ++--\n contrib/completion/git-completion.bash |   4 +-\n parse-options.h                        |   4 +-\n ref-filter.c                           |  30 ++++-\n ref-filter.h                           |   1 +\n t/t3200-branch.sh                      |   4 +\n t/t3201-branch-contains.sh             |  61 ++++++++-\n t/t6302-for-each-ref-filter.sh         |  20 +++\n t/t7004-tag.sh                         | 237 +++++++++++++++++++++++++++++++--\n 14 files changed, 432 insertions(+), 71 deletions(-)\n\n-- \n2.11.0\n\n"},{"id":"314831","messageId":"xmqqefxqqylm.fsf@gitster.mtv.corp.google.com","threadId":"45453","inReplyTo":"20170321125901.10652-1-avarab@gmail.com","subject":"Re: [PATCH v2 00/16] Various changes to the \"tag\" command & related","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-03-21T18:22:13Z","receivedAt":"2017-03-21T18:22:56Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n\n> This series is now 2x the size of v1. The reason is that the\n> discussion for v1 brought up lots of related side-points that I fixed\n> while I was at it. Most if this *could* be split off, but since a lot\n> of it's modifying the same bits of code doing that would result in\n> merge conflict galore, so I think it's easier to bundle it up.\n\nWhew.  v1 was already a tad larger than v0 and now this ;-)  \n\nThanks for a well-written and concise summary below.  Makes it much\nmore pleasant to review than without them.\n"},{"id":"314832","messageId":"xmqqa88eqykv.fsf@gitster.mtv.corp.google.com","threadId":"45453","inReplyTo":"20170321125901.10652-2-avarab@gmail.com","subject":"Re: [PATCH v2 01/16] tag doc: move the description of --[no-]merged earlier","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-03-21T18:22:40Z","receivedAt":"2017-03-21T18:25:01Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Makes sense.\n"},{"id":"314835","messageId":"xmqq60j2qyf8.fsf@gitster.mtv.corp.google.com","threadId":"45453","inReplyTo":"20170321125901.10652-3-avarab@gmail.com","subject":"Re: [PATCH v2 02/16] tag doc: split up the --[no-]merged documentation","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-03-21T18:26:03Z","receivedAt":"2017-03-21T18:27:09Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n\n> Split up the --[no-]merged documentation into documentation that\n> documents each option independently. This is in line with how \"branch\"\n> and \"for-each-ref\" are documented, and makes subsequent changes to\n> discuss the limits & caveats of each option easier to read.\n>\n> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n> ---\n\nThis is consistent with a possible future (i.e. you do not have to\nbe the one to realize it) where \"--merged A --no-merged B\" can be\ngiven together.  Makes sense.\n\n>  Documentation/git-tag.txt | 11 +++++++----\n>  1 file changed, 7 insertions(+), 4 deletions(-)\n>\n> diff --git a/Documentation/git-tag.txt b/Documentation/git-tag.txt\n> index 33f18ea5fb..68b0ab2410 100644\n> --- a/Documentation/git-tag.txt\n> +++ b/Documentation/git-tag.txt\n> @@ -124,10 +124,13 @@ This option is only applicable when listing tags without annotation lines.\n>  \tOnly list tags which contain the specified commit (HEAD if not\n>  \tspecified).\n>  \n> ---[no-]merged [<commit>]::\n> -\tOnly list tags whose tips are reachable, or not reachable\n> -\tif `--no-merged` is used, from the specified commit (`HEAD`\n> -\tif not specified).\n> +--merged [<commit>]::\n> +\tOnly list tags whose tips are reachable from the specified commit\n> +\t(`HEAD` if not specified).\n> +\n> +--no-merged [<commit>]::\n> +\tOnly list tags whose tips are not reachable from the specified\n> +\tcommit (`HEAD` if not specified).\n>  \n>  --points-at <object>::\n>  \tOnly list tags of the given object.\n"},{"id":"314837","messageId":"xmqq1stqqy9v.fsf@gitster.mtv.corp.google.com","threadId":"45453","inReplyTo":"20170321125901.10652-6-avarab@gmail.com","subject":"Re: [PATCH v2 05/16] ref-filter: add test for --contains on a non-commit","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-03-21T18:29:16Z","receivedAt":"2017-03-21T18:32:47Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n\n> Change the tag test suite to test for --contains on a tree & blob, it\n\nEither s/, it/. It/ or s/, it/; it/.\n\n> only accepts commits and will spew out \"<object> is a tree, not a\n> commit\".\n>\n> It's sufficient to test this just for the \"tag\" and \"branch\" commands,\n> because it covers all the machinery is shared between \"branch\" and\n\nEither s/is shared/shared/ or s/is shared/that is shared/.\n\n> \"for-each-ref\".\n>\n> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n> ---\n\nThe patch itself looks good.\n\nThanks.\n"},{"id":"314838","messageId":"xmqqshm6pjja.fsf@gitster.mtv.corp.google.com","threadId":"45453","inReplyTo":"20170321125901.10652-10-avarab@gmail.com","subject":"Re: [PATCH v2 09/16] tag: add more incompatibles mode tests","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-03-21T18:32:57Z","receivedAt":"2017-03-21T18:38:21Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n\n> Amend the test suite to test for more invalid uses like \"-l -a\"\n> etc. This mainly tests the `(argc == 0 && !cmdmode)` ->\n> `((create_tag_object || force) && (cmdmode != 0))` code path in\n> builtin/tag.c.\n\nThe second sentence is now stale, isn't it?\n\n>\n> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n> ---\n>  t/t7004-tag.sh | 13 +++++++++++++\n>  1 file changed, 13 insertions(+)\n>\n> diff --git a/t/t7004-tag.sh b/t/t7004-tag.sh\n> index 63ee2cf727..958c77ab86 100755\n> --- a/t/t7004-tag.sh\n> +++ b/t/t7004-tag.sh\n> @@ -1455,6 +1455,19 @@ test_expect_success 'checking that initial commit is in all tags' \"\n>  \n>  test_expect_success 'mixing incompatibles modes and options is forbidden' '\n>  \ttest_must_fail git tag -a &&\n> +\ttest_must_fail git tag -a -l &&\n> +\ttest_must_fail git tag -s &&\n> +\ttest_must_fail git tag -s -l &&\n> +\ttest_must_fail git tag -m &&\n> +\ttest_must_fail git tag -m -l &&\n> +\ttest_must_fail git tag -m \"hlagh\" &&\n> +\ttest_must_fail git tag -m \"hlagh\" -l &&\n> +\ttest_must_fail git tag -F &&\n> +\ttest_must_fail git tag -F -l &&\n> +\ttest_must_fail git tag -f &&\n> +\ttest_must_fail git tag -f -l &&\n> +\ttest_must_fail git tag -a -s -m -F &&\n> +\ttest_must_fail git tag -a -s -m -F -l &&\n>  \ttest_must_fail git tag -l -v &&\n>  \ttest_must_fail git tag -n 100 &&\n>  \ttest_must_fail git tag -l -m msg &&\n"},{"id":"314839","messageId":"xmqqwpbipjk9.fsf@gitster.mtv.corp.google.com","threadId":"45453","inReplyTo":"20170321125901.10652-9-avarab@gmail.com","subject":"Re: [PATCH v2 08/16] for-each-ref: partly change <object> to <commit> in help","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-03-21T18:32:22Z","receivedAt":"2017-03-21T18:39:11Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n\n> Change mentions of <object> to <commit> in the help output of\n> for-each-ref as appropriate.\n>\n> Both --[no-]merged and --contains only take commits, but --points-at\n> can take any object, such as a tag pointing to a tree or blob.\n>\n> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n> ---\n\nThis definitely is a correction worth doing.  \n\nDo these strictly require commit, or does any commit-ish also do?\n\n>  builtin/for-each-ref.c | 4 ++--\n>  1 file changed, 2 insertions(+), 2 deletions(-)\n>\n> diff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c\n> index df41fa0350..1a5ed20f59 100644\n> --- a/builtin/for-each-ref.c\n> +++ b/builtin/for-each-ref.c\n> @@ -8,8 +8,8 @@\n>  static char const * const for_each_ref_usage[] = {\n>  \tN_(\"git for-each-ref [<options>] [<pattern>]\"),\n>  \tN_(\"git for-each-ref [--points-at <object>]\"),\n> -\tN_(\"git for-each-ref [(--merged | --no-merged) [<object>]]\"),\n> -\tN_(\"git for-each-ref [--contains [<object>]]\"),\n> +\tN_(\"git for-each-ref [(--merged | --no-merged) [<commit>]]\"),\n> +\tN_(\"git for-each-ref [--contains [<commit>]]\"),\n>  \tNULL\n>  };\n"},{"id":"314840","messageId":"xmqqo9wupixz.fsf@gitster.mtv.corp.google.com","threadId":"45453","inReplyTo":"20170321125901.10652-11-avarab@gmail.com","subject":"Re: [PATCH v2 10/16] tag: change misleading --list <pattern> documentation","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-03-21T18:45:44Z","receivedAt":"2017-03-21T18:48:26Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n\n> And after Jeff's change, one that took multiple patterns:\n>\n>     git tag --list 'v*rc*' --list '*2.8*'\n\nI do not think this is a correct depiction of the evolution, and is\na confusing description.  It should say\n\n    git tag --list 'v*rc*' '*2.8*'\n\ninstead.\n\nWhen the logic was still in scripted Porcelain, <pattern> _was_ an\noptional argument to the \"-l\" option (see b867c7c2 (\"git-tag: -l to\nlist tags (usability).\", 2006-02-17) you quoted earlier).  But way\nbefore Jeff's change, when the command was reimplemented in C and\nstarted using parse_options(), <pattern> stopped being an argument\nto the \"-l\" option.  What Jeff's change did was that the original\ncode that only took\n\n    git tag -l 'v*rc*'\n\nto also take\n\n    git tag -l 'v*rc*' '*2.8*'\n\ni.e. multiple patterns.  Yes, thanks to parse_options, you could\nhave -l twice on the command line, but \"multiple patterns\" does not\nhave anything to do with having to (or allowing to) use '-l'\nmultiple times.\n\n> But since it's actually a toggle all of these work as well, and\n> produce identical output to the last example above:\n>\n>     git tag --list 'v*rc*' '*2.8*'\n>     git tag --list 'v*rc*' '*2.8*' --list --list --list\n>     git tag --list 'v*rc*' '*2.8*' --list -l --list -l --list\n\nSo citing Jeff's change is irrelevant to explain these.  I doubt you\neven need to show these variations.\n\n> Now the documentation is more in tune with how the \"branch\" command\n> describes its --list option since commit cddd127b9a (\"branch:\n> introduce --list option\", 2011-08-28).\n>\n> Change the test suite to assert that these invocations work for the\n> cases that weren't already being tested for.\n\nThese two paragraphs are relevant.\n\n> --l <pattern>::\n> ---list <pattern>::\n> -\tList tags with names that match the given pattern (or all if no\n> -\tpattern is given).  Running \"git tag\" without arguments also\n> -\tlists all tags. The pattern is a shell wildcard (i.e., matched\n> -\tusing fnmatch(3)).  Multiple patterns may be given; if any of\n> -\tthem matches, the tag is shown.\n> +-l::\n> +--list::\n> +\tActivate the list mode. `git tag <pattern>` would try to create a\n\nDont say <pattern> on this line.  It is `git tag <name>`.\n\n> +\ttag, use `git tag --list <pattern>` to list matching branches, (or\n\nPerhaps <pattern>... instead to signal that you can give multiple\npatterns?\n\n> diff --git a/t/t7004-tag.sh b/t/t7004-tag.sh\n> index 958c77ab86..1de7185be0 100755\n> --- a/t/t7004-tag.sh\n> +++ b/t/t7004-tag.sh\n> @@ -118,6 +118,18 @@ test_expect_success 'listing all tags if one exists should succeed' '\n>  \tgit tag\n>  '\n>  \n> +cat >expect <<EOF\n> +mytag\n> +EOF\n> +test_expect_success 'Multiple -l or --list options are equivalent to one -l option' '\n> +\tgit tag -l -l >actual &&\n> +\ttest_cmp expect actual &&\n> +\tgit tag --list --list >actual &&\n> +\ttest_cmp expect actual &&\n> +\tgit tag --list -l --list >actual &&\n> +\ttest_cmp expect actual\n> +'\n\nThe \"-l/-d/-v\" options follow the last-one-wins rule, no?  Perhaps\nalso show how this one works in this test (while retitling it)?\n\n\tgit tag -d -v -l\n\n> @@ -336,6 +348,15 @@ test_expect_success 'tag -l can accept multiple patterns' '\n>  \ttest_cmp expect actual\n>  '\n>  \n> +test_expect_success 'tag -l can accept multiple patterns interleaved with -l or --list options' '\n\nPlease drop \"interleaved\", as we are not encouraging GNUism.  We\njust tolerate it but do not guarantee to keep them working.\n\n> +\tgit tag -l \"v1*\" \"v0*\" >actual &&\n> +\ttest_cmp expect actual &&\n> +\tgit tag -l \"v1*\" --list \"v0*\" >actual &&\n> +\ttest_cmp expect actual &&\n> +\tgit tag -l \"v1*\" \"v0*\" -l --list >actual &&\n> +\ttest_cmp expect actual\n> +'\n> +\n>  test_expect_success 'listing tags in column' '\n>  \tCOLUMNS=40 git tag -l --column=row >actual &&\n>  \tcat >expected <<\\EOF &&\n"},{"id":"314842","messageId":"xmqqbmsupinm.fsf@gitster.mtv.corp.google.com","threadId":"45453","inReplyTo":"20170321125901.10652-14-avarab@gmail.com","subject":"Re: [PATCH v2 13/16] ref-filter: add --no-contains option to tag/branch/for-each-ref","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-03-21T18:51:57Z","receivedAt":"2017-03-21T18:52:33Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n\n> Change the tag, branch & for-each-ref commands to have a --no-contains\n> option in addition to their longstanding --contains options.\n>\n> This allows for finding the last-good rollout tag given a known-bad\n> <commit>. Given a hypothetically bad commit cf5c7253e0, the git\n> version to revert to can be found with this hacky two-liner:\n>\n>     (git tag -l 'v[0-9]*'; git tag -l --contains cf5c7253e0 'v[0-9]*') |\n>         sort | uniq -c | grep -E '^ *1 ' | awk '{print $2}' | tail -n 10\n>\n> With this new --no-contains option the same can be achieved with:\n>\n>     git tag -l --no-contains cf5c7253e0 'v[0-9]*' | sort | tail -n 10\n>\n> As the filtering machinery is shared between the tag, branch &\n> for-each-ref commands, implement this for those commands too. A\n> practical use for this with \"branch\" is e.g. finding branches which\n> were branched off between v2.8.0 and v2.10.0:\n>\n>     git branch --contains v2.8.0 --no-contains v2.10.0\n>\n> The \"describe\" command also has a --contains option, but its semantics\n> are unrelated to what tag/branch/for-each-ref use --contains for. A\n> --no-contains option for \"describe\" wouldn't make any sense, other\n> than being exactly equivalent to not supplying --contains at all,\n> which would be confusing at best.\n\nNicely explained.  Thanks.\n\n> diff --git a/parse-options.h b/parse-options.h\n> index dcd8a0926c..0eac90b510 100644\n> --- a/parse-options.h\n> +++ b/parse-options.h\n> @@ -258,7 +258,9 @@ extern int parse_opt_passthru_argv(const struct option *, const char *, int);\n>  \t  PARSE_OPT_LASTARG_DEFAULT | flag, \\\n>  \t  parse_opt_commits, (intptr_t) \"HEAD\" \\\n>  \t}\n> -#define OPT_CONTAINS(v, h) _OPT_CONTAINS_OR_WITH(\"contains\", v, h, 0)\n> +#define OPT_CONTAINS(v, h) _OPT_CONTAINS_OR_WITH(\"contains\", v, h, PARSE_OPT_NONEG)\n> +#define OPT_NO_CONTAINS(v, h) _OPT_CONTAINS_OR_WITH(\"no-contains\", v, h, PARSE_OPT_NONEG)\n>  #define OPT_WITH(v, h) _OPT_CONTAINS_OR_WITH(\"with\", v, h, PARSE_OPT_HIDDEN)\n> +#define OPT_WITHOUT(v, h) _OPT_CONTAINS_OR_WITH(\"without\", v, h, PARSE_OPT_HIDDEN)\n\nDoesn't OPT_WITHOUT() need PARSE_OPT_NONEG (in addition to HIDDEN),\njust like OPT_NO_CONTAINS() uses one to reject \"--no-no-contains\"?\nDoes the code do a sensible thing when --no-without is given?\n"},{"id":"314843","messageId":"CACBZZX6VxxYD1ev0K4jxyUmqxFpALopkHTUFp4iFtYfSuOgrjQ@mail.gmail.com","threadId":"45453","inReplyTo":"xmqqwpbipjk9.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v2 08/16] for-each-ref: partly change <object> to <commit> in help","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2017-03-21T18:50:15Z","receivedAt":"2017-03-21T18:53:12Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"On Tue, Mar 21, 2017 at 7:32 PM, Junio C Hamano <gitster@pobox.com> wrote:\n> Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n>\n>> Change mentions of <object> to <commit> in the help output of\n>> for-each-ref as appropriate.\n>>\n>> Both --[no-]merged and --contains only take commits, but --points-at\n>> can take any object, such as a tag pointing to a tree or blob.\n>>\n>> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n>> ---\n>\n> This definitely is a correction worth doing.\n>\n> Do these strictly require commit, or does any commit-ish also do?\n\ncommit-ish, but that's a good point, and could be the subject of a\nfuture follow-up patch. Right now most of the things that say <commit>\nreally mean <commit-ish>:\n\n    $ git grep '<commit>' -- builtin|wc -l\n    18\n    $ git grep '<commit.*ish>' -- builtin|wc -l\n    3\n\n\n>>  builtin/for-each-ref.c | 4 ++--\n>>  1 file changed, 2 insertions(+), 2 deletions(-)\n>>\n>> diff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c\n>> index df41fa0350..1a5ed20f59 100644\n>> --- a/builtin/for-each-ref.c\n>> +++ b/builtin/for-each-ref.c\n>> @@ -8,8 +8,8 @@\n>>  static char const * const for_each_ref_usage[] = {\n>>       N_(\"git for-each-ref [<options>] [<pattern>]\"),\n>>       N_(\"git for-each-ref [--points-at <object>]\"),\n>> -     N_(\"git for-each-ref [(--merged | --no-merged) [<object>]]\"),\n>> -     N_(\"git for-each-ref [--contains [<object>]]\"),\n>> +     N_(\"git for-each-ref [(--merged | --no-merged) [<commit>]]\"),\n>> +     N_(\"git for-each-ref [--contains [<commit>]]\"),\n>>       NULL\n>>  };\n"},{"id":"314844","messageId":"xmqqfui6pisx.fsf@gitster.mtv.corp.google.com","threadId":"45453","inReplyTo":"20170321125901.10652-13-avarab@gmail.com","subject":"Re: [PATCH v2 12/16] tag: change --point-at to default to HEAD","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-03-21T18:48:46Z","receivedAt":"2017-03-21T18:55:00Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Makes sense.  Thanks.\n"},{"id":"314845","messageId":"xmqq7f3ipikl.fsf@gitster.mtv.corp.google.com","threadId":"45453","inReplyTo":"20170321125901.10652-15-avarab@gmail.com","subject":"Re: [PATCH v2 14/16] ref-filter: reflow recently changed branch/tag/for-each-ref docs","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-03-21T18:53:46Z","receivedAt":"2017-03-21T18:55:06Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n\n> Reflow the recently changed branch/tag-for-each-ref\n> documentation. This change shows no changes under --word-diff, except\n> the innocuous change of moving git-tag.txt's \"[--sort=<key>]\" around\n> slightly.\n> ---\n\nThanks.  \n\nNeeds sign-off (I could just add it back in if you tell me so ;)\n\n"},{"id":"314846","messageId":"xmqqk27ipitw.fsf@gitster.mtv.corp.google.com","threadId":"45453","inReplyTo":"20170321125901.10652-12-avarab@gmail.com","subject":"Re: [PATCH v2 11/16] tag: implicitly supply --list given another list-like option","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-03-21T18:48:11Z","receivedAt":"2017-03-21T18:55:07Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n\n> Spelunking through the history via:\n>\n>     git log --reverse -p -G'only allowed with' -- '*builtin*tag*c'\n>\n> Reveals that there was no good reason for not allowing this in the\n> first place. The --contains option added in 32c35cfb1e (\"git-tag: Add\n> --contains option\", 2009-01-26) made this an error,. All the other\n\ns/,././\n\n> subsequent list-like options that were added copied its pattern of\n> making this usage an error.\n\nGood digging, and I do agree that this is a good change.\n\nThanks.\n\n"},{"id":"314848","messageId":"CACBZZX4jXtYqnsYuHRohF+zx+y0VyyRudMMYjtLuxoCziccd=w@mail.gmail.com","threadId":"45453","inReplyTo":"xmqqshm6pjja.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v2 09/16] tag: add more incompatibles mode tests","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2017-03-21T18:58:07Z","receivedAt":"2017-03-21T18:58:50Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"On Tue, Mar 21, 2017 at 7:32 PM, Junio C Hamano <gitster@pobox.com> wrote:\n> Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n>\n>> Amend the test suite to test for more invalid uses like \"-l -a\"\n>> etc. This mainly tests the `(argc == 0 && !cmdmode)` ->\n>> `((create_tag_object || force) && (cmdmode != 0))` code path in\n>> builtin/tag.c.\n>\n> The second sentence is now stale, isn't it?\nI've reworded this in WIP v3 to split out the code from the text,\nmaking this less confusing.\n>>\n>> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n>> ---\n>>  t/t7004-tag.sh | 13 +++++++++++++\n>>  1 file changed, 13 insertions(+)\n>>\n>> diff --git a/t/t7004-tag.sh b/t/t7004-tag.sh\n>> index 63ee2cf727..958c77ab86 100755\n>> --- a/t/t7004-tag.sh\n>> +++ b/t/t7004-tag.sh\n>> @@ -1455,6 +1455,19 @@ test_expect_success 'checking that initial commit is in all tags' \"\n>>\n>>  test_expect_success 'mixing incompatibles modes and options is forbidden' '\n>>       test_must_fail git tag -a &&\n>> +     test_must_fail git tag -a -l &&\n>> +     test_must_fail git tag -s &&\n>> +     test_must_fail git tag -s -l &&\n>> +     test_must_fail git tag -m &&\n>> +     test_must_fail git tag -m -l &&\n>> +     test_must_fail git tag -m \"hlagh\" &&\n>> +     test_must_fail git tag -m \"hlagh\" -l &&\n>> +     test_must_fail git tag -F &&\n>> +     test_must_fail git tag -F -l &&\n>> +     test_must_fail git tag -f &&\n>> +     test_must_fail git tag -f -l &&\n>> +     test_must_fail git tag -a -s -m -F &&\n>> +     test_must_fail git tag -a -s -m -F -l &&\n>>       test_must_fail git tag -l -v &&\n>>       test_must_fail git tag -n 100 &&\n>>       test_must_fail git tag -l -m msg &&\n"},{"id":"314849","messageId":"xmqq37e6piae.fsf@gitster.mtv.corp.google.com","threadId":"45453","inReplyTo":"20170321125901.10652-16-avarab@gmail.com","subject":"Re: [PATCH v2 15/16] tag: implicitly supply --list given the -n option","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-03-21T18:59:53Z","receivedAt":"2017-03-21T19:00:55Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n\n> Change the \"tag\" command to treat the \"-n\" invocation as a list-like\n> option in addition to --contains, --points-at etc.\n>\n> Most of the work for this was done in my earlier \"tag: Implicitly\n> supply --list given another list-like option\" commit, but I've split\n> off this patch since it's more contentious. Now these will be\n> synonymous:\n>\n>     git tag -n 100\n>     git tag -n --list 100\n\nHmph.  I would understand if these meant the same thing:\n\n    git tag -l -n 100\n    git tag -l -n=100\n    git tag -l -n100\n\nwith or without \"-l\".  And accepting any of the above three without \"-l\"\ninstead of rejecting is a very good change, I would think.\n\nI however do not understand how accepting this:\n    \n    git tag -n --list 100\n\nwould be a good thing, as \"100\" an optional parameter to the \"-n\"\noption.\n\n> Whereas before the former would die. This doesn't technically\n> introduce any more ambiguity than the aforementioned change applied to\n> th other list-like options, but it does introduce the possibility for\n> more confusion, since instead of the latter of these dying:\n>\n>     git tag -n100\n>     git tag -n 100\n>\n> It now works entirely differently, i.e. invokes list mode with a\n> filter for \"100\" as a pattern. I.e. it's synonymous with:\n>\n>     git tag -n --list 100\n\nAhhh, yuck.  OK, so in \"git tag -n --list 100\", 100 does not have\nanything to do with the -n option.  It is a pattern and -n specifies\n\"just one line\" by default.\n\nOh, boy, that is confusing.  While it is very logical.\n\nStill I think it is OK as I can see why people who wanted to have\n'-n' in the first place may want\n\n    git tag -n -l <pattern>\n\nThanks.\n"},{"id":"314850","messageId":"CACBZZX5-RRrWZfPAtMon_WnioG-9AwfhTFC174=4uBx_QCcEGA@mail.gmail.com","threadId":"45453","inReplyTo":"xmqqbmsupinm.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v2 13/16] ref-filter: add --no-contains option to tag/branch/for-each-ref","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2017-03-21T19:03:35Z","receivedAt":"2017-03-21T19:04:53Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"On Tue, Mar 21, 2017 at 7:51 PM, Junio C Hamano <gitster@pobox.com> wrote:\n> Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n>\n>> Change the tag, branch & for-each-ref commands to have a --no-contains\n>> option in addition to their longstanding --contains options.\n>>\n>> This allows for finding the last-good rollout tag given a known-bad\n>> <commit>. Given a hypothetically bad commit cf5c7253e0, the git\n>> version to revert to can be found with this hacky two-liner:\n>>\n>>     (git tag -l 'v[0-9]*'; git tag -l --contains cf5c7253e0 'v[0-9]*') |\n>>         sort | uniq -c | grep -E '^ *1 ' | awk '{print $2}' | tail -n 10\n>>\n>> With this new --no-contains option the same can be achieved with:\n>>\n>>     git tag -l --no-contains cf5c7253e0 'v[0-9]*' | sort | tail -n 10\n>>\n>> As the filtering machinery is shared between the tag, branch &\n>> for-each-ref commands, implement this for those commands too. A\n>> practical use for this with \"branch\" is e.g. finding branches which\n>> were branched off between v2.8.0 and v2.10.0:\n>>\n>>     git branch --contains v2.8.0 --no-contains v2.10.0\n>>\n>> The \"describe\" command also has a --contains option, but its semantics\n>> are unrelated to what tag/branch/for-each-ref use --contains for. A\n>> --no-contains option for \"describe\" wouldn't make any sense, other\n>> than being exactly equivalent to not supplying --contains at all,\n>> which would be confusing at best.\n>\n> Nicely explained.  Thanks.\n>\n>> diff --git a/parse-options.h b/parse-options.h\n>> index dcd8a0926c..0eac90b510 100644\n>> --- a/parse-options.h\n>> +++ b/parse-options.h\n>> @@ -258,7 +258,9 @@ extern int parse_opt_passthru_argv(const struct option *, const char *, int);\n>>         PARSE_OPT_LASTARG_DEFAULT | flag, \\\n>>         parse_opt_commits, (intptr_t) \"HEAD\" \\\n>>       }\n>> -#define OPT_CONTAINS(v, h) _OPT_CONTAINS_OR_WITH(\"contains\", v, h, 0)\n>> +#define OPT_CONTAINS(v, h) _OPT_CONTAINS_OR_WITH(\"contains\", v, h, PARSE_OPT_NONEG)\n>> +#define OPT_NO_CONTAINS(v, h) _OPT_CONTAINS_OR_WITH(\"no-contains\", v, h, PARSE_OPT_NONEG)\n>>  #define OPT_WITH(v, h) _OPT_CONTAINS_OR_WITH(\"with\", v, h, PARSE_OPT_HIDDEN)\n>> +#define OPT_WITHOUT(v, h) _OPT_CONTAINS_OR_WITH(\"without\", v, h, PARSE_OPT_HIDDEN)\n>\n> Doesn't OPT_WITHOUT() need PARSE_OPT_NONEG (in addition to HIDDEN),\n> just like OPT_NO_CONTAINS() uses one to reject \"--no-no-contains\"?\n> Does the code do a sensible thing when --no-without is given?\n\nYes, you'd mentioned this before but fixing this got lost in my note\ntaking process for v1->v2. Will fix for v3.\n"},{"id":"314851","messageId":"CACBZZX7yRRTQpcFZ9eO2_+HdB979p6URE+jsXJakxw7jpnOvmA@mail.gmail.com","threadId":"45453","inReplyTo":"xmqq37e6piae.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v2 15/16] tag: implicitly supply --list given the -n option","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2017-03-21T19:11:15Z","receivedAt":"2017-03-21T19:11:55Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"On Tue, Mar 21, 2017 at 7:59 PM, Junio C Hamano <gitster@pobox.com> wrote:\n> Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n>\n>> Change the \"tag\" command to treat the \"-n\" invocation as a list-like\n>> option in addition to --contains, --points-at etc.\n>>\n>> Most of the work for this was done in my earlier \"tag: Implicitly\n>> supply --list given another list-like option\" commit, but I've split\n>> off this patch since it's more contentious. Now these will be\n>> synonymous:\n>>\n>>     git tag -n 100\n>>     git tag -n --list 100\n>\n> Hmph.  I would understand if these meant the same thing:\n>\n>     git tag -l -n 100\n>     git tag -l -n=100\n>     git tag -l -n100\n>\n> with or without \"-l\".  And accepting any of the above three without \"-l\"\n> instead of rejecting is a very good change, I would think.\n>\n> I however do not understand how accepting this:\n>\n>     git tag -n --list 100\n>\n> would be a good thing, as \"100\" an optional parameter to the \"-n\"\n> option.\n>\n>> Whereas before the former would die. This doesn't technically\n>> introduce any more ambiguity than the aforementioned change applied to\n>> th other list-like options, but it does introduce the possibility for\n>> more confusion, since instead of the latter of these dying:\n>>\n>>     git tag -n100\n>>     git tag -n 100\n>>\n>> It now works entirely differently, i.e. invokes list mode with a\n>> filter for \"100\" as a pattern. I.e. it's synonymous with:\n>>\n>>     git tag -n --list 100\n>\n> Ahhh, yuck.  OK, so in \"git tag -n --list 100\", 100 does not have\n> anything to do with the -n option.  It is a pattern and -n specifies\n> \"just one line\" by default.\n>\n> Oh, boy, that is confusing.  While it is very logical.\n>\n> Still I think it is OK as I can see why people who wanted to have\n> '-n' in the first place may want\n>\n>     git tag -n -l <pattern>\n\nYeah I see now that this is rather badly explained. I'll fix this up\nfor v3. All of this worked already:\n\n    $ ./git tag 100\n    $ ./git tag -n -l 100\n    100             tag: add tests for --with and --without\n    $ ./git tag -l -n 100\n    100             tag: add tests for --with and --without\n\nSo actually thinking about it again it doesn't add any more ambiguity\nthan we had before. The change is just strictly getting rid of the\nneed for -l for consistency with --contains, --points-at etc.\n\nI see now that the whole thing that led me down this golden path was\nthat I was removing the failing \"git tag -n 100\" test, so while I was\nstill wrapping my mind around this I thought I was introducing some\n*more* confusion, but really that test was just testing that it didn't\nwork, as opposed to \"git tag -l -n 100\".\n\nI'm just going to squash this into the \"tag: implicitly supply --list\ngiven another list-like option\" patch for v3 unless you have\nobjections, I think there's no reason to split this off any more than\nsplitting off e.g. --points-at etc.\n"},{"id":"314853","messageId":"CACBZZX7F66PogXWPQTsMr7d0C5kcxZiG87cn4TrYwFc4U1wsYA@mail.gmail.com","threadId":"45453","inReplyTo":"xmqq7f3ipikl.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v2 14/16] ref-filter: reflow recently changed branch/tag/for-each-ref docs","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2017-03-21T19:12:28Z","receivedAt":"2017-03-21T19:14:55Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"On Tue, Mar 21, 2017 at 7:53 PM, Junio C Hamano <gitster@pobox.com> wrote:\n> Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n>\n>> Reflow the recently changed branch/tag-for-each-ref\n>> documentation. This change shows no changes under --word-diff, except\n>> the innocuous change of moving git-tag.txt's \"[--sort=<key>]\" around\n>> slightly.\n>> ---\n>\n> Thanks.\n>\n> Needs sign-off (I could just add it back in if you tell me so ;)\n\nOops, will fix for v3.\n"},{"id":"314854","messageId":"xmqqy3vyo2yx.fsf@gitster.mtv.corp.google.com","threadId":"45453","inReplyTo":"CACBZZX6VxxYD1ev0K4jxyUmqxFpALopkHTUFp4iFtYfSuOgrjQ@mail.gmail.com","subject":"Re: [PATCH v2 08/16] for-each-ref: partly change <object> to <commit> in help","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-03-21T19:16:06Z","receivedAt":"2017-03-21T19:19:19Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:\n\n> On Tue, Mar 21, 2017 at 7:32 PM, Junio C Hamano <gitster@pobox.com> wrote:\n>\n>> Do these strictly require commit, or does any commit-ish also do?\n>\n> commit-ish, but that's a good point, and could be the subject of a\n> future follow-up patch. Right now most of the things that say <commit>\n> really mean <commit-ish>:\n>\n>     $ git grep '<commit>' -- builtin|wc -l\n>     18\n>     $ git grep '<commit.*ish>' -- builtin|wc -l\n>     3\n\nMy gut feeling is that anywhere we say a <commit> for Porcelain\ncommands, we should be also accepting a <commit-ish>, and it is not\nworth repeating to users that these command accept commit-ish.  So I\nthink it is better to leave these as <commit>, and to add special\nnote to places where the commands insist taking <commit> and not\n<commit-ish>.  They should be minorities, at least for Porcelain\ncommands.  The same for <tree> vs <tree-ish>.\n\nThanks.\n"},{"id":"314857","messageId":"xmqqtw6mo2l2.fsf@gitster.mtv.corp.google.com","threadId":"45453","inReplyTo":"CACBZZX7yRRTQpcFZ9eO2_+HdB979p6URE+jsXJakxw7jpnOvmA@mail.gmail.com","subject":"Re: [PATCH v2 15/16] tag: implicitly supply --list given the -n option","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-03-21T19:24:25Z","receivedAt":"2017-03-21T19:28:00Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:\n\n> Yeah I see now that this is rather badly explained. I'll fix this up\n> for v3. All of this worked already:\n>\n>     $ ./git tag 100\n>     $ ./git tag -n -l 100\n>     100             tag: add tests for --with and --without\n>     $ ./git tag -l -n 100\n>     100             tag: add tests for --with and --without\n>\n> So actually thinking about it again it doesn't add any more ambiguity\n> than we had before. The change is just strictly getting rid of the\n> need for -l for consistency with --contains, --points-at etc.\n>\n> I see now that the whole thing that led me down this golden path was\n> that I was removing the failing \"git tag -n 100\" test,...\n\nWait a minute.  I do not think I would agree with the behaviour of\nthe last one, if \"tag -l -n 100\" is taking 100 as a pattern, not a\nnumerical argument to \"-n\".  That sounds utterly broken.\n\nIs it because we use it OPT_OPTARG, which requires it to be spelled\nas \"-n100\" or \"-n=100\" or somesuch?\n\nIn any case, it is not a new confusion this series introduces, so\nlet's include it in the series, but I'd prefer to see it kept as a\nseparate patch, at least for now.  Maybe somebody else have an idea\nto resolve this apparent confusion in a cleaner way.\n\nThanks.\n"},{"id":"314859","messageId":"CACBZZX6Ak0JOd7Fh5Z2p0md_P8vG__N_gOkfoNueERVF=jVyBg@mail.gmail.com","threadId":"45453","inReplyTo":"xmqqtw6mo2l2.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v2 15/16] tag: implicitly supply --list given the -n option","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2017-03-21T19:33:50Z","receivedAt":"2017-03-21T19:37:28Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"On Tue, Mar 21, 2017 at 8:24 PM, Junio C Hamano <gitster@pobox.com> wrote:\n> Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:\n>\n>> Yeah I see now that this is rather badly explained. I'll fix this up\n>> for v3. All of this worked already:\n>>\n>>     $ ./git tag 100\n>>     $ ./git tag -n -l 100\n>>     100             tag: add tests for --with and --without\n>>     $ ./git tag -l -n 100\n>>     100             tag: add tests for --with and --without\n>>\n>> So actually thinking about it again it doesn't add any more ambiguity\n>> than we had before. The change is just strictly getting rid of the\n>> need for -l for consistency with --contains, --points-at etc.\n>>\n>> I see now that the whole thing that led me down this golden path was\n>> that I was removing the failing \"git tag -n 100\" test,...\n>\n> Wait a minute.  I do not think I would agree with the behaviour of\n> the last one, if \"tag -l -n 100\" is taking 100 as a pattern, not a\n> numerical argument to \"-n\".  That sounds utterly broken.\n>\n> Is it because we use it OPT_OPTARG, which requires it to be spelled\n> as \"-n100\" or \"-n=100\" or somesuch?\n>\n> In any case, it is not a new confusion this series introduces, so\n> let's include it in the series, but I'd prefer to see it kept as a\n> separate patch, at least for now.  Maybe somebody else have an idea\n> to resolve this apparent confusion in a cleaner way.\n\nYup, that's why. This:\n\ndiff --git a/builtin/tag.c b/builtin/tag.c\nindex dbc6f5b74b..1346341413 100644\n--- a/builtin/tag.c\n+++ b/builtin/tag.c\n@@ -403,7 +403,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix)\n                OPT_CMDMODE('l', \"list\", &cmdmode, N_(\"list tag names\"), 'l'),\n                { OPTION_INTEGER, 'n', NULL, &filter.lines, N_(\"n\"),\n                                N_(\"print <n> lines of each tag message\"),\n-                               PARSE_OPT_OPTARG, NULL, 1 },\n+                               0, NULL, 1 },\n                OPT_CMDMODE('d', \"delete\", &cmdmode, N_(\"delete tags\"), 'd'),\n                OPT_CMDMODE('v', \"verify\", &cmdmode, N_(\"verify tags\"), 'v'),\n\nChanges it so that \"git tag -n 100 '*1.6.6*rc*'\" does what \"git tag\n-n100 '*1.6.6*rc*'\" does. But that breaks a bunch of tests / possibly\nsome scripts in the wild, especially because \"git tag -n '*1.6.6*rc*'\"\nnow becomes an error, i.e. we'll try to treat the pattern as the\nnumeric argument.\n"},{"id":"314949","messageId":"CACBZZX70pb=h3nPKDY-rcM3rjh9SNYUzUhxA3Hu0-Jph8ODxdg@mail.gmail.com","threadId":"45453","inReplyTo":"xmqqo9wupixz.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v2 10/16] tag: change misleading --list <pattern> documentation","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2017-03-22T19:32:46Z","receivedAt":"2017-03-22T19:33:26Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"On Tue, Mar 21, 2017 at 7:45 PM, Junio C Hamano <gitster@pobox.com> wrote:\n> Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n>\n>> And after Jeff's change, one that took multiple patterns:\n>>\n>>     git tag --list 'v*rc*' --list '*2.8*'\n>\n> I do not think this is a correct depiction of the evolution, and is\n> a confusing description.  It should say\n>\n>     git tag --list 'v*rc*' '*2.8*'\n>\n> instead.\n\nChanging this from \"--list <pattern> --list <pattern>\" to \"--list\n<pattern> <pattern>\" wouldn't make any sense, because it's in the\nmiddle of a sentence explaining not how the tooling worked, but before\nthis change, how it was documented to work. I.e. read up a few lines\nto  \"One would expect an option that was documented like that...\" for\nthe context.\n\n> When the logic was still in scripted Porcelain, <pattern> _was_ an\n> optional argument to the \"-l\" option (see b867c7c2 (\"git-tag: -l to\n> list tags (usability).\", 2006-02-17) you quoted earlier).  But way\n> before Jeff's change, when the command was reimplemented in C and\n> started using parse_options(), <pattern> stopped being an argument\n> to the \"-l\" option.  What Jeff's change did was that the original\n> code that only took\n>\n>     git tag -l 'v*rc*'\n>\n> to also take\n>\n>     git tag -l 'v*rc*' '*2.8*'\n>\n> i.e. multiple patterns.  Yes, thanks to parse_options, you could\n> have -l twice on the command line, but \"multiple patterns\" does not\n> have anything to do with having to (or allowing to) use '-l'\n> multiple times.\n\nYes, all of this is correct, but not relevant to what I'm describing\nin the commit message, because I'm making a documentation change and\ndescribing how you *would* expect git to work if you read the\n*documentation*, not if you read the code.\n\nIf you read the documentation after Jeff's 588d0e834b, since -l was\nstill documented as taking a <pattern> you'd expect \"tag -l 'v*rc*' -l\n'*2.8*'\" to be how it worked, and for \"tag -l 'v*rc*' '*2.8*'\" to be\nan error.\n\n>> But since it's actually a toggle all of these work as well, and\n>> produce identical output to the last example above:\n>>\n>>     git tag --list 'v*rc*' '*2.8*'\n>>     git tag --list 'v*rc*' '*2.8*' --list --list --list\n>>     git tag --list 'v*rc*' '*2.8*' --list -l --list -l --list\n>\n> So citing Jeff's change is irrelevant to explain these.  I doubt you\n> even need to show these variations.\n\nJeff's change isn't being cited to explain these, everything before\nthe \"But since it's actually\" is describing how the documentation was\nphrased to give you the impression that it worked, including after\nJeff's change where we started accepting multiple patterns. But at\nthis point I'm starting to describe how the code actually parsed the\n--list option.\n\nRegardless of that, I'll try to rephrase this somehow to make it\nclearer, but I'd like to keep the general gist of \"before this change,\nif you read the docs, here's how you'd expect the -l option to work,\nbut it actually worked like so-and-so, and now that's what we document\ninstead\".\n\n>> Now the documentation is more in tune with how the \"branch\" command\n>> describes its --list option since commit cddd127b9a (\"branch:\n>> introduce --list option\", 2011-08-28).\n>>\n>> Change the test suite to assert that these invocations work for the\n>> cases that weren't already being tested for.\n>\n> These two paragraphs are relevant.\n>\n>> --l <pattern>::\n>> ---list <pattern>::\n>> -     List tags with names that match the given pattern (or all if no\n>> -     pattern is given).  Running \"git tag\" without arguments also\n>> -     lists all tags. The pattern is a shell wildcard (i.e., matched\n>> -     using fnmatch(3)).  Multiple patterns may be given; if any of\n>> -     them matches, the tag is shown.\n>> +-l::\n>> +--list::\n>> +     Activate the list mode. `git tag <pattern>` would try to create a\n>\n> Dont say <pattern> on this line.  It is `git tag <name>`.\n\nMakes sense, but this is something I copied as-is from git-branch.txt,\nwhich then has the same issue, so v3 will have yet another related\npatch...\n\n>> +     tag, use `git tag --list <pattern>` to list matching branches, (or\n>\n> Perhaps <pattern>... instead to signal that you can give multiple\n> patterns?\n\nMakes sense.\n\n>> diff --git a/t/t7004-tag.sh b/t/t7004-tag.sh\n>> index 958c77ab86..1de7185be0 100755\n>> --- a/t/t7004-tag.sh\n>> +++ b/t/t7004-tag.sh\n>> @@ -118,6 +118,18 @@ test_expect_success 'listing all tags if one exists should succeed' '\n>>       git tag\n>>  '\n>>\n>> +cat >expect <<EOF\n>> +mytag\n>> +EOF\n>> +test_expect_success 'Multiple -l or --list options are equivalent to one -l option' '\n>> +     git tag -l -l >actual &&\n>> +     test_cmp expect actual &&\n>> +     git tag --list --list >actual &&\n>> +     test_cmp expect actual &&\n>> +     git tag --list -l --list >actual &&\n>> +     test_cmp expect actual\n>> +'\n>\n> The \"-l/-d/-v\" options follow the last-one-wins rule, no?  Perhaps\n> also show how this one works in this test (while retitling it)?\n>\n>         git tag -d -v -l\n\nThis will fail as tested for in \"tag: add more incompatibles mode\ntests\". We weren't testing \"-d\" with \"-l\", or this combination, I'll\nadd both to the tests.\n\n>> @@ -336,6 +348,15 @@ test_expect_success 'tag -l can accept multiple patterns' '\n>>       test_cmp expect actual\n>>  '\n>>\n>> +test_expect_success 'tag -l can accept multiple patterns interleaved with -l or --list options' '\n>\n> Please drop \"interleaved\", as we are not encouraging GNUism.  We\n> just tolerate it but do not guarantee to keep them working.\n\nThis brings up the same point you made in\n<xmqqmvci2zoc.fsf@gitster.mtv.corp.google.com>, I replied to in\n<CACBZZX5LN8nhs85K18XVg4Y9_qb9zKGBoFnnQHSsRZVOP=OkDw@mail.gmail.com>,\nand that you didn't get back to me about.\n\nRather than split the discussion or me copy/pasting large parts of\nthat E-Mail could you please reply to me over in that thread?\n\n>> +     git tag -l \"v1*\" \"v0*\" >actual &&\n>> +     test_cmp expect actual &&\n>> +     git tag -l \"v1*\" --list \"v0*\" >actual &&\n>> +     test_cmp expect actual &&\n>> +     git tag -l \"v1*\" \"v0*\" -l --list >actual &&\n>> +     test_cmp expect actual\n>> +'\n>> +\n>>  test_expect_success 'listing tags in column' '\n>>       COLUMNS=40 git tag -l --column=row >actual &&\n>>       cat >expected <<\\EOF &&\n"},{"id":"314967","messageId":"xmqq1stpj9xv.fsf@gitster.mtv.corp.google.com","threadId":"45453","inReplyTo":"CACBZZX70pb=h3nPKDY-rcM3rjh9SNYUzUhxA3Hu0-Jph8ODxdg@mail.gmail.com","subject":"Re: [PATCH v2 10/16] tag: change misleading --list <pattern> documentation","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-03-22T21:09:00Z","receivedAt":"2017-03-22T21:09:08Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:\n\n>> Please drop \"interleaved\", as we are not encouraging GNUism.  We\n>> just tolerate it but do not guarantee to keep them working.\n>\n> This brings up the same point you made in\n> <xmqqmvci2zoc.fsf@gitster.mtv.corp.google.com>, I replied to in\n> <CACBZZX5LN8nhs85K18XVg4Y9_qb9zKGBoFnnQHSsRZVOP=OkDw@mail.gmail.com>,\n> and that you didn't get back to me about.\n>\n> Rather than split the discussion or me copy/pasting large parts of\n> that E-Mail could you please reply to me over in that thread?\n\nThere is nothing to reply.  We know some people favor GNUism, but we\ndo not actively encourage it, period.\n\n"},{"id":"314970","messageId":"xmqqwpbhhv36.fsf@gitster.mtv.corp.google.com","threadId":"45453","inReplyTo":"CACBZZX70pb=h3nPKDY-rcM3rjh9SNYUzUhxA3Hu0-Jph8ODxdg@mail.gmail.com","subject":"Re: [PATCH v2 10/16] tag: change misleading --list <pattern> documentation","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-03-22T21:15:09Z","receivedAt":"2017-03-22T21:16:31Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:\n\n> Yes, all of this is correct, but not relevant to what I'm describing\n> in the commit message, because I'm making a documentation change and\n> describing how you *would* expect git to work if you read the\n> *documentation*, not if you read the code.\n\nOK.\n\n>>> +-l::\n>>> +--list::\n>>> +     Activate the list mode. `git tag <pattern>` would try to create a\n>>\n>> Dont say <pattern> on this line.  It is `git tag <name>`.\n>\n> Makes sense, but this is something I copied as-is from git-branch.txt,\n> which then has the same issue, so v3 will have yet another related\n> patch...\n\nI think you'd rather want to make it a single patch to be applied\nand merged independently, as a fix to a documentation bug we somehow\nnoticed that is unrelated to the main theme of what we were working\nto perfect ;-)\n\n>> The \"-l/-d/-v\" options follow the last-one-wins rule, no?  Perhaps\n>> also show how this one works in this test (while retitling it)?\n>>\n>>         git tag -d -v -l\n>\n> This will fail as tested for in \"tag: add more incompatibles mode\n> tests\". We weren't testing \"-d\" with \"-l\", or this combination, I'll\n> add both to the tests.\n\nThanks.\n"},{"id":"314992","messageId":"CACBZZX4rofOquS4q0NDCb8cHOF=E7iPzFMxj3bre6CTB7=b_MA@mail.gmail.com","threadId":"45453","inReplyTo":"xmqq1stpj9xv.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v2 10/16] tag: change misleading --list <pattern> documentation","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2017-03-22T22:08:28Z","receivedAt":"2017-03-22T22:08:54Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"On Wed, Mar 22, 2017 at 10:09 PM, Junio C Hamano <gitster@pobox.com> wrote:\n> Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:\n>\n>>> Please drop \"interleaved\", as we are not encouraging GNUism.  We\n>>> just tolerate it but do not guarantee to keep them working.\n>>\n>> This brings up the same point you made in\n>> <xmqqmvci2zoc.fsf@gitster.mtv.corp.google.com>, I replied to in\n>> <CACBZZX5LN8nhs85K18XVg4Y9_qb9zKGBoFnnQHSsRZVOP=OkDw@mail.gmail.com>,\n>> and that you didn't get back to me about.\n>>\n>> Rather than split the discussion or me copy/pasting large parts of\n>> that E-Mail could you please reply to me over in that thread?\n>\n> There is nothing to reply.  We know some people favor GNUism, but we\n> do not actively encourage it, period.\n\nI'd understand the objection to encouraging if I was proposing to\ninclude mentions of \"--list <pattern> --list <pattern>\" in the\ndocumentation, but what this patch is about (and this wasn't clear\nenough from the beginning, I'll reword it), is essentially:\n\n\"So for the last 5 years of Git releases if you'd read the git-tag\ndocs you'd think `--list <pat> --list <pat>` was the blessed way of\nsupplying multiple patterns. That's not actually needed, or\nencouraged, so here's a change to the docs & a test addition to make\nsure we know if we break this long-documented pattern in the future\".\n\nYou'd like the doc change but not the regression test. If so I'm fine\nwith that. The reason I'm asking you follow-up questions about it is\nbecause I'd like to know in general, for future submissions, what sort\nof things you think we should be putting in the test suite. I.e.\nshould the tests be:\n\na) Only be a collection of invocations of git we'd be comfortable\nshowing to someone as \"this works, and this is how you should do it\",\nor things that explicitly fail marked with test_must_fail.\n\nb) or a) && also various surprising combinations of things we don't\nnecessarily want to encourage or even support in the future, but which\nare in there so if we change them, we at least know our change changed\nsomething that worked before.\n\nNow. I think the policy should be \"b\". The main reason is that as I\nnoted in [1] people do write scripts against the porcelain. There's\ndoubtless scripted invocations out there that use multiple GNU-like\n\"-l <pattern>\" options, and it's worthwhile for us to know if we make\na change that breaks that.\n\nBut if you think it should be \"a\" obviously that's the project policy,\nbut then I'd like to know that it's \"a\", both because it'll save me\ntime authoring future patches, and I'd like to submit some change to\nSubmittingPatches or t/README describing to others what sort of tests\nare acceptable for inclusion.\n\nThe reason I brought up a hypothetical \"test_might_get_deprecated\"\nfeature in my original message [2] is that even if you think we should\nonly do \"a\" now and not \"b\", I think that perhaps that's only because\nof some limitation of the current test suite. I.e.:\n\n1) Maybe we shouldn't run these (\"b\" && !\"a\") tests by default unless\nsome flag is provided, so that someone who's working on an otherwise\nworthwhile new feature isn't dissuaded by some failing test that's\nchecking for an obscure and historically unintended feature of git.\n\n2) Or we could run them, but e.g. turn them into TODO's for failure to\nmark them as things we'd like to deprecate.\n\n1. <CACBZZX59KXPOEjiUKtZLN6zjO_xpiWve7Xga6q-53J2LwvfZyw@mail.gmail.com>\n2. <CACBZZX5LN8nhs85K18XVg4Y9_qb9zKGBoFnnQHSsRZVOP=OkDw@mail.gmail.com>,\n"},{"id":"315007","messageId":"xmqqtw6lgd82.fsf@gitster.mtv.corp.google.com","threadId":"45453","inReplyTo":"CACBZZX4rofOquS4q0NDCb8cHOF=E7iPzFMxj3bre6CTB7=b_MA@mail.gmail.com","subject":"Re: [PATCH v2 10/16] tag: change misleading --list <pattern> documentation","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-03-22T22:26:21Z","receivedAt":"2017-03-22T22:26:28Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:\n\n> of things you think we should be putting in the test suite. I.e.\n> should the tests be:\n>\n> a) Only be a collection of invocations of git we'd be comfortable\n> showing to someone as \"this works, and this is how you should do it\",\n> or things that explicitly fail marked with test_must_fail.\n>\n> b) or a) && also various surprising combinations of things we don't\n> necessarily want to encourage or even support in the future, but which\n> are in there so if we change them, we at least know our change changed\n> something that worked before.\n\nI am strongly inclined to (a).  If we cannot decide when we designed\nthe feature, and we anticipate that we may want to change it later,\nthen documenting the choice in a test or two may be a way to remind\nthe choice we happened to have made, but in general I do not think\nwe want to promise (to ourselves) more than what we are willing to\ncommit to.\n"},{"id":"315012","messageId":"20170322223600.huyel6j5wl644ddf@sigill.intra.peff.net","threadId":"45453","inReplyTo":"xmqqtw6lgd82.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v2 10/16] tag: change misleading --list <pattern> documentation","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2017-03-22T22:36:00Z","receivedAt":"2017-03-22T22:36:10Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Wed, Mar 22, 2017 at 03:26:21PM -0700, Junio C Hamano wrote:\n\n> Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:\n> \n> > of things you think we should be putting in the test suite. I.e.\n> > should the tests be:\n> >\n> > a) Only be a collection of invocations of git we'd be comfortable\n> > showing to someone as \"this works, and this is how you should do it\",\n> > or things that explicitly fail marked with test_must_fail.\n> >\n> > b) or a) && also various surprising combinations of things we don't\n> > necessarily want to encourage or even support in the future, but which\n> > are in there so if we change them, we at least know our change changed\n> > something that worked before.\n> \n> I am strongly inclined to (a).  If we cannot decide when we designed\n> the feature, and we anticipate that we may want to change it later,\n> then documenting the choice in a test or two may be a way to remind\n> the choice we happened to have made, but in general I do not think\n> we want to promise (to ourselves) more than what we are willing to\n> commit to.\n\nI've occasionally[1] added tests that are \"what we happen to produce\nnow\", but I almost always mark them with a comment either in the test\nscript or in the commit message.  What I'm _most_ concerned about is a\ndeveloper later breaking the test, but being unsure if they were\nbreaking some real-world case (and not being able to find clues in the\nhistory).\n\nA secondary concern would be people using the test snippets as guidance\non what is normal or encouraged.\n\nSo I could live with these patches, but I'd prefer to see a comment\nsomewhere. And I think I'd have a slight inclination to just stick to\n(a) in the first place, unless there is a really good reason to cover\nthe test (like that we do not care between behaviors X and Y, but we\nneed to check that it does one of them, and not Z).\n\n-Peff\n\n[1] E.g., see the comment in t3204 from a356e8e2a (t3204: test\n    git-branch @-expansion corner cases, 2017-03-02).\n"},{"id":"315023","messageId":"CACBZZX7kJ_G8mAYd3mN5WtP0ZLUUOuWs4hu1fhTSspWuW_O=5A@mail.gmail.com","threadId":"45453","inReplyTo":"20170322223600.huyel6j5wl644ddf@sigill.intra.peff.net","subject":"Re: [PATCH v2 10/16] tag: change misleading --list <pattern> documentation","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2017-03-22T23:43:20Z","receivedAt":"2017-03-22T23:43:47Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"On Wed, Mar 22, 2017 at 11:36 PM, Jeff King <peff@peff.net> wrote:\n> On Wed, Mar 22, 2017 at 03:26:21PM -0700, Junio C Hamano wrote:\n>\n>> Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:\n>>\n>> > of things you think we should be putting in the test suite. I.e.\n>> > should the tests be:\n>> >\n>> > a) Only be a collection of invocations of git we'd be comfortable\n>> > showing to someone as \"this works, and this is how you should do it\",\n>> > or things that explicitly fail marked with test_must_fail.\n>> >\n>> > b) or a) && also various surprising combinations of things we don't\n>> > necessarily want to encourage or even support in the future, but which\n>> > are in there so if we change them, we at least know our change changed\n>> > something that worked before.\n>>\n>> I am strongly inclined to (a).  If we cannot decide when we designed\n>> the feature, and we anticipate that we may want to change it later,\n>> then documenting the choice in a test or two may be a way to remind\n>> the choice we happened to have made, but in general I do not think\n>> we want to promise (to ourselves) more than what we are willing to\n>> commit to.\n>\n> I've occasionally[1] added tests that are \"what we happen to produce\n> now\", but I almost always mark them with a comment either in the test\n> script or in the commit message.  What I'm _most_ concerned about is a\n> developer later breaking the test, but being unsure if they were\n> breaking some real-world case (and not being able to find clues in the\n> history).\n>\n> A secondary concern would be people using the test snippets as guidance\n> on what is normal or encouraged.\n>\n> So I could live with these patches, but I'd prefer to see a comment\n> somewhere. And I think I'd have a slight inclination to just stick to\n> (a) in the first place, unless there is a really good reason to cover\n> the test (like that we do not care between behaviors X and Y, but we\n> need to check that it does one of them, and not Z).\n\nRight, or in this case something where we're testing for behavior we\ndocumented for a long time, but never really intended to support.\nJunio would you be fine with just this on top:\n\ndiff --git a/t/README b/t/README\nindex 4982d1c521..9e079a360a 100644\n--- a/t/README\n+++ b/t/README\n@@ -379,2 +379,5 @@ Do:\n\n+ - Include tests which assert that the desired & recommended behavior\n+   of commands is preserved.\n+\n  - Put all code inside test_expect_success and other assertions.\n@@ -424,2 +427,17 @@ Don't:\n\n+ - Include tests which exhaustively test for various edge cases or\n+   unintended emergent behavior which we're not interested in\n+   supporting in the future.\n+\n+   An exception to this is are cases where we don't care about\n+   different behaviors X and Y, but we need to check that it does one\n+   of them, and not Z.\n+\n+   Another exception are cases where our documentation might\n+   unintentionally stated or implied that something was supported or\n+   recommended, but we'd like to discourage its use going forward.\n+\n+   In both of the above cases please prominently comment the test\n+   indicating that you're testing for one of these two cases.\n+\n  - exit() within a <script> part.\ndiff --git a/t/t7004-tag.sh b/t/t7004-tag.sh\nindex 0a7ebf5358..35402ad9a0 100755\n--- a/t/t7004-tag.sh\n+++ b/t/t7004-tag.sh\n@@ -350,2 +350,6 @@ test_expect_success 'tag -l can accept multiple patterns' '\n\n+# Between around v1.7.6.1 & v2.13.0 the documentation unintentionally\n+# implied that --list was what took the <pattern>, not that patterns\n+# should be clustered at the very end. This test should not imply that\n+# this is a sane thing to support.\n test_expect_success 'tag -l can accept multiple patterns interleaved\nwith -l or --list options' '\n\nOr do you think the \"long documented but unintentional\" argument isn't\nworth a test, in which case squash this:\n\ndiff --git a/t/README b/t/README\nindex 9e079a360a..9f85b8d1cd 100644\n--- a/t/README\n+++ b/t/README\n@@ -433,12 +433,8 @@ Don't:\n    different behaviors X and Y, but we need to check that it does one\n    of them, and not Z.\n\n-   Another exception are cases where our documentation might\n-   unintentionally stated or implied that something was supported or\n-   recommended, but we'd like to discourage its use going forward.\n-\n-   In both of the above cases please prominently comment the test\n-   indicating that you're testing for one of these two cases.\n+   In that case please prominently comment the test indicating that\n+   you're testing for one of these two cases.\n\n  - exit() within a <script> part.\n\ndiff --git a/t/t7004-tag.sh b/t/t7004-tag.sh\nindex 35402ad9a0..83772f6003 100755\n--- a/t/t7004-tag.sh\n+++ b/t/t7004-tag.sh\n@@ -348,19 +348,6 @@ test_expect_success 'tag -l can accept multiple patterns' '\n        test_cmp expect actual\n '\n\n-# Between around v1.7.6.1 & v2.13.0 the documentation unintentionally\n-# implied that --list was what took the <pattern>, not that patterns\n-# should be clustered at the very end. This test should not imply that\n-# this is a sane thing to support.\n-test_expect_success 'tag -l can accept multiple patterns interleaved\nwith -l or --list options' '\n-       git tag -l \"v1*\" \"v0*\" >actual &&\n-       test_cmp expect actual &&\n-       git tag -l \"v1*\" --list \"v0*\" >actual &&\n-       test_cmp expect actual &&\n-       git tag -l \"v1*\" \"v0*\" -l --list >actual &&\n-       test_cmp expect actual\n-'\n-\n test_expect_success 'listing tags in column' '\n        COLUMNS=40 git tag -l --column=row >actual &&\n        cat >expected <<\\EOF &&\n"},{"id":"315031","messageId":"xmqqd1d8hlbg.fsf@gitster.mtv.corp.google.com","threadId":"45453","inReplyTo":"CACBZZX7kJ_G8mAYd3mN5WtP0ZLUUOuWs4hu1fhTSspWuW_O=5A@mail.gmail.com","subject":"Re: [PATCH v2 10/16] tag: change misleading --list <pattern> documentation","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-03-23T00:46:11Z","receivedAt":"2017-03-23T00:46:20Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:\n\n> Junio would you be fine with just this on top:\n>\n> diff --git a/t/README b/t/README\n> index 4982d1c521..9e079a360a 100644\n> --- a/t/README\n> +++ b/t/README\n> @@ -379,2 +379,5 @@ Do:\n>\n> + - Include tests which assert that the desired & recommended behavior\n> +   of commands is preserved.\n> +\n>   - Put all code inside test_expect_success and other assertions.\n> @@ -424,2 +427,17 @@ Don't:\n>\n> + - Include tests which exhaustively test for various edge cases or\n> +   unintended emergent behavior which we're not interested in\n> +   supporting in the future.\n> +\n> +   An exception to this is are cases where we don't care about\n> +   different behaviors X and Y, but we need to check that it does one\n> +   of them, and not Z.\n> +\n> +   Another exception are cases where our documentation might\n> +   unintentionally stated or implied that something was supported or\n> +   recommended, but we'd like to discourage its use going forward.\n> +\n> +   In both of the above cases please prominently comment the test\n> +   indicating that you're testing for one of these two cases.\n> +\n>   - exit() within a <script> part.\n\nThis would probably be part of your other three-patch series for\nt/README?  With a quick read-through I spotted nothing questionable,\nbut I am not 100% sure about the value of going into that level of\ndetails, especially with the latter one about \"discourage and wean\noff of\".\n\n> diff --git a/t/t7004-tag.sh b/t/t7004-tag.sh\n> index 0a7ebf5358..35402ad9a0 100755\n> --- a/t/t7004-tag.sh\n> +++ b/t/t7004-tag.sh\n> @@ -350,2 +350,6 @@ test_expect_success 'tag -l can accept multiple patterns' '\n>\n> +# Between around v1.7.6.1 & v2.13.0 the documentation unintentionally\n> +# implied that --list was what took the <pattern>, not that patterns\n> +# should be clustered at the very end. This test should not imply that\n> +# this is a sane thing to support.\n>  test_expect_success 'tag -l can accept multiple patterns interleaved\n> with -l or --list options' '\n>\n> Or do you think the \"long documented but unintentional\" argument isn't\n> worth a test, in which case squash this:\n\nOh, I didn't know I was given two choices and the second one does\naddress the \"I am not 100% sure\" above ;-).\n\n> diff --git a/t/README b/t/README\n> index 9e079a360a..9f85b8d1cd 100644\n> --- a/t/README\n> +++ b/t/README\n> @@ -433,12 +433,8 @@ Don't:\n>     different behaviors X and Y, but we need to check that it does one\n>     of them, and not Z.\n>\n> -   Another exception are cases where our documentation might\n> -   unintentionally stated or implied that something was supported or\n> -   recommended, but we'd like to discourage its use going forward.\n> -\n> -   In both of the above cases please prominently comment the test\n> -   indicating that you're testing for one of these two cases.\n> +   In that case please prominently comment the test indicating that\n> +   you're testing for one of these two cases.\n>\n>   - exit() within a <script> part.\n\nSo for the doc part, I can go with either, but prefer the latter\nbetween the two.\n\n> diff --git a/t/t7004-tag.sh b/t/t7004-tag.sh\n> index 35402ad9a0..83772f6003 100755\n> --- a/t/t7004-tag.sh\n> +++ b/t/t7004-tag.sh\n> @@ -348,19 +348,6 @@ test_expect_success 'tag -l can accept multiple patterns' '\n>         test_cmp expect actual\n>  '\n>\n> -# Between around v1.7.6.1 & v2.13.0 the documentation unintentionally\n> -# implied that --list was what took the <pattern>, not that patterns\n> -# should be clustered at the very end. This test should not imply that\n> -# this is a sane thing to support.\n> -test_expect_success 'tag -l can accept multiple patterns interleaved\n> with -l or --list options' '\n> -       git tag -l \"v1*\" \"v0*\" >actual &&\n> -       test_cmp expect actual &&\n\nI'd actually think \"multiple patterns\" should be kept, as that is\nreally what we want to support forever.  \n\nAcceptance of multiple and redundant \"--list\", e.g.\n\n\tgit tag -l --list \"v1*\" \"v0*\" >actual &&\n\ttest_cmp expect actual &&\n\nimmediately after the above may also be something worth protecting,\nbut that is how OPT_CMDMODE works in general, so it may not be\nnecessary to test it specifically in a test for \"tag -l\".\n\nAcceptance of multiple and redundant \"--list\" that are given after a\n<pattern> is already given on the command line is not something we\nwant to actively deprecate (it is not worth our time or effort) but\nit is not something we want to encourage, either.  So I have a\npreference for dropping the ones below.\n\n> -       git tag -l \"v1*\" --list \"v0*\" >actual &&\n> -       test_cmp expect actual &&\n> -       git tag -l \"v1*\" \"v0*\" -l --list >actual &&\n> -       test_cmp expect actual\n> -'\n> -\n>  test_expect_success 'listing tags in column' '\n>         COLUMNS=40 git tag -l --column=row >actual &&\n>         cat >expected <<\\EOF &&\n"}]}