Re: [PATCH v2] ref-filter: Add --no-contains option to tag/branch/for-each-ref

2017-03-10 Thread Ævar Arnfjörð Bjarmason
On Fri, Mar 10, 2017 at 12:46 PM, Ævar Arnfjörð Bjarmason
 wrote:
> On Thu, Mar 9, 2017 at 9:31 PM, Christian Couder
>  wrote:
>> On Thu, Mar 9, 2017 at 9:02 PM, Ævar Arnfjörð Bjarmason
>>  wrote:
>>>
>>> diff --git a/Documentation/git-tag.txt b/Documentation/git-tag.txt
>>> index 525737a5d8..4938496194 100644
>>> --- a/Documentation/git-tag.txt
>>> +++ b/Documentation/git-tag.txt
>>> @@ -12,7 +12,7 @@ SYNOPSIS
>>>  'git tag' [-a | -s | -u ] [-f] [-m  | -F ]
>>>  [ | ]
>>>  'git tag' -d ...
>>> -'git tag' [-n[]] -l [--contains ] [--points-at ]
>>> +'git tag' [-n[]] -l [--[no-]contains ] [--points-at ]
>>> [--column[=] | --no-column] [--create-reflog] 
>>> [--sort=]
>>> [--format=] [--[no-]merged []] [...]
>>>  'git tag' -v [--format=] ...
>>> @@ -124,6 +124,10 @@ This option is only applicable when listing tags 
>>> without annotation lines.
>>> Only list tags which contain the specified commit (HEAD if not
>>> specified).
>>>
>>> +--no-contains []::
>>> +   Only list tags which don't contain the specified commit (HEAD if
>>> +   not secified).
>>
>> s/secified/specified/
>>
>>> +
>>>  --points-at ::
>>> Only list tags of the given object.
>>>
>>> diff --git a/builtin/branch.c b/builtin/branch.c
>>> index 94f7de7fa5..e8d534604c 100644
>>> --- a/builtin/branch.c
>>> +++ b/builtin/branch.c
>>> @@ -548,7 +548,9 @@ int cmd_branch(int argc, const char **argv, const char 
>>> *prefix)
>>> OPT_SET_INT('r', "remotes", &filter.kind, N_("act on 
>>> remote-tracking branches"),
>>> FILTER_REFS_REMOTES),
>>> OPT_CONTAINS(&filter.with_commit, N_("print only branches 
>>> that contain the commit")),
>>> +   OPT_NO_CONTAINS(&filter.no_commit, N_("print only branches 
>>> that don't contain the commit")),
>>> OPT_WITH(&filter.with_commit, N_("print only branches that 
>>> contain the commit")),
>>> +   OPT_WITHOUT(&filter.with_commit, N_("print only branches 
>>> that don't contain the commit")),
>>
>> s/with_commit/no_commit/
>
> Thanks!
>
> FWIW this is the current status of my WIP v3. I noticed a couple of
> other issues where --contains was mentioned without --no-contains.
>
> diff --git a/Documentation/git-tag.txt b/Documentation/git-tag.txt
> index 4938496194..d9243bf5e4 100644
> --- a/Documentation/git-tag.txt
> +++ b/Documentation/git-tag.txt
> @@ -129 +129 @@ This option is only applicable when listing tags
> without annotation lines.
> -   not secified).
> +   not specified).
> diff --git a/builtin/branch.c b/builtin/branch.c
> index e8d534604c..dd96319726 100644
> --- a/builtin/branch.c
> +++ b/builtin/branch.c
> @@ -553 +553 @@ int cmd_branch(int argc, const char **argv, const char 
> *prefix)
> -   OPT_WITHOUT(&filter.with_commit, N_("print only
> branches that don't contain the commit")),
> +   OPT_WITHOUT(&filter.no_commit, N_("print only branches
> that don't contain the commit")),
> diff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c
> index b1ae2388e6..a11542c4fd 100644
> --- a/builtin/for-each-ref.c
> +++ b/builtin/for-each-ref.c
> @@ -12 +12 @@ static char const * const for_each_ref_usage[] = {
> -   N_("git for-each-ref [--contains []]"),
> +   N_("git for-each-ref [(--contains | --no-contains) []]"),
> diff --git a/builtin/tag.c b/builtin/tag.c
> index d83674e3e6..57289132a9 100644
> --- a/builtin/tag.c
> +++ b/builtin/tag.c
> @@ -25 +25 @@ static const char * const git_tag_usage[] = {
> -   N_("git tag -l [-n[]] [--contains ] [--points-at 
> ]"
> +   N_("git tag -l [-n[]] [--[no-]contains ]
> [--points-at ]"

Add to that:

diff --git a/t/t7004-tag.sh b/t/t7004-tag.sh
index 8ad5719962..bec3d0fb42 100755
--- a/t/t7004-tag.sh
+++ b/t/t7004-tag.sh
@@ -1804 +1804 @@ EOF"
-   test_line_count ">" 70 actual
+   test_line_count ">" 10 actual

The tests currently fail with v2 if gpg isn't installed, which'll
cause the number to dip below 70, just setting it to a much more
conservative 10, but maybe this should just be "test -s actual" ...

>
> These last two hunks are going to bust the i18n files for most
> languages. Junio/Jiang, in cases like these where I could fix those up
> with a search/replace on po/* without knowing the languages in
> question (since it's purely changing e.g. --contains to
> --[no-]contains), what do you prefer to do, have that as part of this
> patch, or do it after the fact through the normal i18n maintenance
> process?


Re: [PATCH v2] ref-filter: Add --no-contains option to tag/branch/for-each-ref

2017-03-10 Thread Ævar Arnfjörð Bjarmason
On Thu, Mar 9, 2017 at 9:31 PM, Christian Couder
 wrote:
> On Thu, Mar 9, 2017 at 9:02 PM, Ævar Arnfjörð Bjarmason
>  wrote:
>>
>> diff --git a/Documentation/git-tag.txt b/Documentation/git-tag.txt
>> index 525737a5d8..4938496194 100644
>> --- a/Documentation/git-tag.txt
>> +++ b/Documentation/git-tag.txt
>> @@ -12,7 +12,7 @@ SYNOPSIS
>>  'git tag' [-a | -s | -u ] [-f] [-m  | -F ]
>>  [ | ]
>>  'git tag' -d ...
>> -'git tag' [-n[]] -l [--contains ] [--points-at ]
>> +'git tag' [-n[]] -l [--[no-]contains ] [--points-at ]
>> [--column[=] | --no-column] [--create-reflog] [--sort=]
>> [--format=] [--[no-]merged []] [...]
>>  'git tag' -v [--format=] ...
>> @@ -124,6 +124,10 @@ This option is only applicable when listing tags 
>> without annotation lines.
>> Only list tags which contain the specified commit (HEAD if not
>> specified).
>>
>> +--no-contains []::
>> +   Only list tags which don't contain the specified commit (HEAD if
>> +   not secified).
>
> s/secified/specified/
>
>> +
>>  --points-at ::
>> Only list tags of the given object.
>>
>> diff --git a/builtin/branch.c b/builtin/branch.c
>> index 94f7de7fa5..e8d534604c 100644
>> --- a/builtin/branch.c
>> +++ b/builtin/branch.c
>> @@ -548,7 +548,9 @@ int cmd_branch(int argc, const char **argv, const char 
>> *prefix)
>> OPT_SET_INT('r', "remotes", &filter.kind, N_("act on 
>> remote-tracking branches"),
>> FILTER_REFS_REMOTES),
>> OPT_CONTAINS(&filter.with_commit, N_("print only branches 
>> that contain the commit")),
>> +   OPT_NO_CONTAINS(&filter.no_commit, N_("print only branches 
>> that don't contain the commit")),
>> OPT_WITH(&filter.with_commit, N_("print only branches that 
>> contain the commit")),
>> +   OPT_WITHOUT(&filter.with_commit, N_("print only branches 
>> that don't contain the commit")),
>
> s/with_commit/no_commit/

Thanks!

FWIW this is the current status of my WIP v3. I noticed a couple of
other issues where --contains was mentioned without --no-contains.

diff --git a/Documentation/git-tag.txt b/Documentation/git-tag.txt
index 4938496194..d9243bf5e4 100644
--- a/Documentation/git-tag.txt
+++ b/Documentation/git-tag.txt
@@ -129 +129 @@ This option is only applicable when listing tags
without annotation lines.
-   not secified).
+   not specified).
diff --git a/builtin/branch.c b/builtin/branch.c
index e8d534604c..dd96319726 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -553 +553 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
-   OPT_WITHOUT(&filter.with_commit, N_("print only
branches that don't contain the commit")),
+   OPT_WITHOUT(&filter.no_commit, N_("print only branches
that don't contain the commit")),
diff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c
index b1ae2388e6..a11542c4fd 100644
--- a/builtin/for-each-ref.c
+++ b/builtin/for-each-ref.c
@@ -12 +12 @@ static char const * const for_each_ref_usage[] = {
-   N_("git for-each-ref [--contains []]"),
+   N_("git for-each-ref [(--contains | --no-contains) []]"),
diff --git a/builtin/tag.c b/builtin/tag.c
index d83674e3e6..57289132a9 100644
--- a/builtin/tag.c
+++ b/builtin/tag.c
@@ -25 +25 @@ static const char * const git_tag_usage[] = {
-   N_("git tag -l [-n[]] [--contains ] [--points-at ]"
+   N_("git tag -l [-n[]] [--[no-]contains ]
[--points-at ]"


These last two hunks are going to bust the i18n files for most
languages. Junio/Jiang, in cases like these where I could fix those up
with a search/replace on po/* without knowing the languages in
question (since it's purely changing e.g. --contains to
--[no-]contains), what do you prefer to do, have that as part of this
patch, or do it after the fact through the normal i18n maintenance
process?


Re: [PATCH v2] ref-filter: Add --no-contains option to tag/branch/for-each-ref

2017-03-09 Thread Christian Couder
On Thu, Mar 9, 2017 at 9:02 PM, Ævar Arnfjörð Bjarmason
 wrote:
>
> diff --git a/Documentation/git-tag.txt b/Documentation/git-tag.txt
> index 525737a5d8..4938496194 100644
> --- a/Documentation/git-tag.txt
> +++ b/Documentation/git-tag.txt
> @@ -12,7 +12,7 @@ SYNOPSIS
>  'git tag' [-a | -s | -u ] [-f] [-m  | -F ]
>  [ | ]
>  'git tag' -d ...
> -'git tag' [-n[]] -l [--contains ] [--points-at ]
> +'git tag' [-n[]] -l [--[no-]contains ] [--points-at ]
> [--column[=] | --no-column] [--create-reflog] [--sort=]
> [--format=] [--[no-]merged []] [...]
>  'git tag' -v [--format=] ...
> @@ -124,6 +124,10 @@ This option is only applicable when listing tags without 
> annotation lines.
> Only list tags which contain the specified commit (HEAD if not
> specified).
>
> +--no-contains []::
> +   Only list tags which don't contain the specified commit (HEAD if
> +   not secified).

s/secified/specified/

> +
>  --points-at ::
> Only list tags of the given object.
>
> diff --git a/builtin/branch.c b/builtin/branch.c
> index 94f7de7fa5..e8d534604c 100644
> --- a/builtin/branch.c
> +++ b/builtin/branch.c
> @@ -548,7 +548,9 @@ int cmd_branch(int argc, const char **argv, const char 
> *prefix)
> OPT_SET_INT('r', "remotes", &filter.kind, N_("act on 
> remote-tracking branches"),
> FILTER_REFS_REMOTES),
> OPT_CONTAINS(&filter.with_commit, N_("print only branches 
> that contain the commit")),
> +   OPT_NO_CONTAINS(&filter.no_commit, N_("print only branches 
> that don't contain the commit")),
> OPT_WITH(&filter.with_commit, N_("print only branches that 
> contain the commit")),
> +   OPT_WITHOUT(&filter.with_commit, N_("print only branches that 
> don't contain the commit")),

s/with_commit/no_commit/


[PATCH v2] ref-filter: Add --no-contains option to tag/branch/for-each-ref

2017-03-09 Thread Ævar Arnfjörð Bjarmason
Change the tag, branch & for-each-ref commands to have a --no-contains
option in addition to their longstanding --contains options.

The use-case I have for this is to find the last-good rollout tag
given a known-bad . Right now, given a hypothetically bad
commit v2.10.1-3-gcf5c7253e0, you can find which git version to revert
to with this hacky two-liner:

(./git tag -l 'v[0-9]*'; ./git tag -l 'v[0-9]*' --contains 
v2.10.1-3-gcf5c7253e0) \
|sort|uniq -c|grep -E '^ *1 '|awk '{print $2}' | tail -n 10

But with the --no-contains option you can now get the exact same
output with:

./git tag -l 'v[0-9]*' --no-contains v2.10.1-3-gcf5c7253e0|sort|tail -n 10

The filtering machinery is generic between the tag, branch &
for-each-ref commands, so once I'd implemented it for tag it was
trivial to add support for this to the other two.

A practical use for this with "branch" is e.g. finding branches which
diverged between 2.8 & 2.10:

./git branch --contains v2.8.0 --no-contains v2.10.0

The "describe" command also has a --contains option, but its semantics
are unrelated to what tag/branch/for-each-ref use --contains for. I
don't see how a --no-contains option for "describe" would make any
sense, other than being exactly equivalent to not supplying --contains
at all, which would be confusing at best.

I'm adding a --without option to "tag" as an alias for --no-contains
for consistency with --with and --contains. Since we don't even
document --with anymore (or test it). The --with option is
undocumented, and possibly the only user of it is Junio[1]. But it's
trivial to support, so let's do that.

Where I'm changing existing documentation lines I'm mainly word
wrapping at 75 columns to be consistent with the existing style. The
changes to Documentation/ are much smaller with: git show --word-diff,
same for the minor change to git-completion.bash.

Most of the test changes I've made are just doing the inverse of the
existing --contains tests, with this change --no-contains for tag,
branch & for-each-ref is just as well tested as the existing
--contains option.

In addition to those tests I've added tests for --contains in
combination with --no-contains for all three commands, and a test for
"tag" which asserts that --no-contains won't find tree/blob tags,
which is slightly unintuitive, but consistent with how --contains
works.

When --contains and --no-contains are provided to "tag" we disable the
optimized code to find tags added in v1.7.2-rc1-1-gffc4b8012d. That
code changes flags on commit objects as an optimization, and thus
can't be called twice.

Jeff King has a WIP patch to fix that[2], but rather than try to
incorporate that into this already big patch I'm just disabling the
optimized codepath. Using both --contains and --no-contains will most
likely be rare, and we can get an initial correct version working &
optimize it later.

It's possible that the --merge & --no-merge codepaths for "tag" have a
similar bug, but as of writing I can't produce any evidence of that
via a brute-force test script[3].

1. 
2. <20170309125132.tubwxtneffok4...@sigill.intra.peff.net>
3. 

Signed-off-by: Ævar Arnfjörð Bjarmason 
---

Changes since v1:

 * Now git-for-each-ref has --no-contains

 * Doc fixes, happy with the NOTES section in git-branch.txt now.

 * Now tag --contains works with --no-contains, but falls back on
   the much slower pre-1.8 era code pending efforts to make
   commit_contains() re-callable.

 * Now `git tag --no-contains HEAD hi` dies, just like `git tag
   --contains HEAD hi` does.

 * Fixed up my shitty C in ref-filter.c as Peff suggested.

 * Tests for --contains combined with --no-contains for all the
   commands.

 * Rewrote the very verbose t7004-tag.sh tag test Peff complied
   about.

 Documentation/git-branch.txt   |  24 ---
 Documentation/git-for-each-ref.txt |   6 +-
 Documentation/git-tag.txt  |   6 +-
 builtin/branch.c   |   4 +-
 builtin/for-each-ref.c |   1 +
 builtin/tag.c  |  15 +++-
 contrib/completion/git-completion.bash |   9 +--
 parse-options.h|   4 +-
 ref-filter.c   |  16 +++--
 ref-filter.h   |   1 +
 t/t3201-branch-contains.sh |  51 +-
 t/t6302-for-each-ref-filter.sh |  16 +
 t/t7004-tag.sh | 123 -
 13 files changed, 249 insertions(+), 27 deletions(-)

diff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt
index 092f1bcf9f..28a36a8a0a 100644
--- a/Documentation/git-branch.txt
+++ b/Documentation/git-branch.txt
@@ -11,7 +11,7 @@ SYNOPSIS
 'git branch' [--color[=] | --no-color] [-r | -a]
[--list] [-v [--abbrev= | --no-abbrev]]
[--column[=] | --no-column]
-   [(--merged | --no-merged | --contains) []] [--sort=]
+   [(--merged | --no-merged | --contains | --no-contains) []] 
[--s