Ævar Arnfjörð Bjarmason <avarab@xxxxxxxxx> writes: > Change the tag, branch & for-each-ref commands to have a --no-contains > option in addition to their longstanding --contains options. > > This allows for finding the last-good rollout tag given a known-bad > <commit>. Given a hypothetically bad commit cf5c7253e0, the git > version to revert to can be found with this hacky two-liner: > > (git tag -l 'v[0-9]*'; git tag -l --contains cf5c7253e0 'v[0-9]*') | > sort | uniq -c | grep -E '^ *1 ' | awk '{print $2}' | tail -n 10 > > With this new --no-contains option the same can be achieved with: > > git tag -l --no-contains cf5c7253e0 'v[0-9]*' | sort | tail -n 10 > > As the filtering machinery is shared between the tag, branch & > for-each-ref commands, implement this for those commands too. A > practical use for this with "branch" is e.g. finding branches which > were branched off between v2.8.0 and v2.10.0: > > 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. A > --no-contains option for "describe" wouldn't make any sense, other > than being exactly equivalent to not supplying --contains at all, > which would be confusing at best. Nicely explained. Thanks. > diff --git a/parse-options.h b/parse-options.h > index dcd8a0926c..0eac90b510 100644 > --- a/parse-options.h > +++ b/parse-options.h > @@ -258,7 +258,9 @@ extern int parse_opt_passthru_argv(const struct option *, const char *, int); > PARSE_OPT_LASTARG_DEFAULT | flag, \ > parse_opt_commits, (intptr_t) "HEAD" \ > } > -#define OPT_CONTAINS(v, h) _OPT_CONTAINS_OR_WITH("contains", v, h, 0) > +#define OPT_CONTAINS(v, h) _OPT_CONTAINS_OR_WITH("contains", v, h, PARSE_OPT_NONEG) > +#define OPT_NO_CONTAINS(v, h) _OPT_CONTAINS_OR_WITH("no-contains", v, h, PARSE_OPT_NONEG) > #define OPT_WITH(v, h) _OPT_CONTAINS_OR_WITH("with", v, h, PARSE_OPT_HIDDEN) > +#define OPT_WITHOUT(v, h) _OPT_CONTAINS_OR_WITH("without", v, h, PARSE_OPT_HIDDEN) Doesn't OPT_WITHOUT() need PARSE_OPT_NONEG (in addition to HIDDEN), just like OPT_NO_CONTAINS() uses one to reject "--no-no-contains"? Does the code do a sensible thing when --no-without is given?