{"thread":{"id":"49591","subject":"[RFC v2] revision: Add --sticky-default option","startedAt":"2018-10-17T13:49:54Z","lastAt":"2018-10-18T12:52:42Z","messageCount":3,"participants":["Andreas Gruenbacher","Jeff King"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"360751","messageId":"20181017134947.12571-1-agruenba@redhat.com","threadId":"49591","inReplyTo":null,"subject":"[RFC v2] revision: Add --sticky-default option","fromName":"Andreas Gruenbacher","fromEmail":"agruenba@redhat.com","sentAt":"2018-10-17T13:49:47Z","receivedAt":"2018-10-17T13:49:54Z","isPatch":false,"sender":{"key":"agruenba@redhat.com","avatar":null},"body":"Some commands like 'log' default to HEAD if no other revisions are\nspecified on the command line or otherwise.  Currently, excludes\n(^<rev>) cancel out that default, so when a command only excludes\nrevisions (e.g., 'git log ^origin/master'), it will produce no output.\n\nWith the --sticky-default option, the default becomes more \"sticky\" and\nis no longer canceled out by excludes.\n\nThis is useful in wrappers that exclude certain revisions: for example,\na simple alias l='git log --sticky-default ^origin/master' will show the\nrevisions between origin/master and HEAD when invoked without arguments,\nand 'l foo' will show the revisions between origin/master and foo.\n\nSigned-off-by: Andreas Gruenbacher <agruenba@redhat.com>\n---\n Documentation/rev-list-options.txt | 10 ++++++++++\n revision.c                         | 21 ++++++++++++++++++++-\n revision.h                         |  1 +\n t/t4202-log.sh                     |  6 ++++++\n 4 files changed, 37 insertions(+), 1 deletion(-)\n\ndiff --git a/Documentation/rev-list-options.txt b/Documentation/rev-list-options.txt\nindex 7b273635d..46fab2b42 100644\n--- a/Documentation/rev-list-options.txt\n+++ b/Documentation/rev-list-options.txt\n@@ -210,6 +210,16 @@ endif::git-rev-list[]\n \tseen, stop reading commits and start reading paths to limit the\n \tresult.\n \n+--default=<rev>::\n+\tInstead of `HEAD`, use '<rev>' when no revisions are specified.\n+\n+--sticky-default:\n+\tBy default, excludes ('^<rev>') override the default revision (i.e.\n+\t`HEAD` or the revision specified with `--default`).  This option causes\n+\texcludes to no longer override the default revision, so commands like\n+\t`git log --sticky-default ^origin/master` will continue to operate on\n+\tthe default revision as long as no other revisions are specified.\n+\n ifdef::git-rev-list[]\n --quiet::\n \tDon't print anything to standard output.  This form\ndiff --git a/revision.c b/revision.c\nindex e18bd530e..e61f28b92 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -1159,6 +1159,18 @@ static void add_rev_cmdline(struct rev_info *revs,\n \tinfo->nr++;\n }\n \n+static int has_interesting_revisions(struct rev_info *revs)\n+{\n+\tstruct rev_cmdline_info *info = &revs->cmdline;\n+\tunsigned int n;\n+\n+\tfor (n = 0; n < info->nr; n++) {\n+\t\tif (!(info->rev[n].flags & UNINTERESTING))\n+\t\t\treturn 1;\n+\t}\n+\treturn 0;\n+}\n+\n static void add_rev_cmdline_list(struct rev_info *revs,\n \t\t\t\t struct commit_list *commit_list,\n \t\t\t\t int whence,\n@@ -2132,6 +2144,8 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg\n \t} else if (!strcmp(arg, \"--children\")) {\n \t\trevs->children.name = \"children\";\n \t\trevs->limited = 1;\n+\t} else if (!strcmp(arg, \"--sticky-default\")) {\n+\t\trevs->sticky_default = 1;\n \t} else if (!strcmp(arg, \"--ignore-missing\")) {\n \t\trevs->ignore_missing = 1;\n \t} else if (!strcmp(arg, \"--exclude-promisor-objects\")) {\n@@ -2320,6 +2334,7 @@ static void NORETURN diagnose_missing_default(const char *def)\n int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct setup_revision_opt *opt)\n {\n \tint i, flags, left, seen_dashdash, got_rev_arg = 0, revarg_opt;\n+\tint cancel_default;\n \tstruct argv_array prune_data = ARGV_ARRAY_INIT;\n \tconst char *submodule = NULL;\n \n@@ -2431,7 +2446,11 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s\n \t\topt->tweak(revs, opt);\n \tif (revs->show_merge)\n \t\tprepare_show_merge(revs);\n-\tif (revs->def && !revs->pending.nr && !revs->rev_input_given && !got_rev_arg) {\n+\tif (revs->sticky_default)\n+\t\tcancel_default = has_interesting_revisions();\n+\telse\n+\t\tcancel_default = got_rev_arg;\n+\tif (revs->def && !revs->rev_input_given && !cancel_default) {\n \t\tstruct object_id oid;\n \t\tstruct object *object;\n \t\tstruct object_context oc;\ndiff --git a/revision.h b/revision.h\nindex 2b30ac270..6498ba263 100644\n--- a/revision.h\n+++ b/revision.h\n@@ -73,6 +73,7 @@ struct rev_info {\n \t/* Basic information */\n \tconst char *prefix;\n \tconst char *def;\n+\tunsigned int sticky_default:1;\n \tstruct pathspec prune_data;\n \n \t/*\ndiff --git a/t/t4202-log.sh b/t/t4202-log.sh\nindex 153a50615..5ac93f5ec 100755\n--- a/t/t4202-log.sh\n+++ b/t/t4202-log.sh\n@@ -213,6 +213,12 @@ test_expect_success 'git show <commits> leaves list of commits as given' '\n \ttest_cmp expect actual\n '\n \n+test_expect_success '--sticky-default ^<rev>' '\n+\ttest_write_lines sixth fifth > expect &&\n+\tgit log --pretty=\"tformat:%s\" --sticky-default ^HEAD~2 > actual &&\n+\ttest_cmp expect actual\n+'\n+\n test_expect_success 'setup case sensitivity tests' '\n \techo case >one &&\n \ttest_tick &&\n-- \n2.17.2\n\n"},{"id":"360821","messageId":"20181018065328.GC23537@sigill.intra.peff.net","threadId":"49591","inReplyTo":"20181017134947.12571-1-agruenba@redhat.com","subject":"Re: [RFC v2] revision: Add --sticky-default option","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2018-10-18T06:53:29Z","receivedAt":"2018-10-18T06:53:33Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Wed, Oct 17, 2018 at 03:49:47PM +0200, Andreas Gruenbacher wrote:\n\n> @@ -2431,7 +2446,11 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s\n>  \t\topt->tweak(revs, opt);\n>  \tif (revs->show_merge)\n>  \t\tprepare_show_merge(revs);\n> -\tif (revs->def && !revs->pending.nr && !revs->rev_input_given && !got_rev_arg) {\n> +\tif (revs->sticky_default)\n> +\t\tcancel_default = has_interesting_revisions();\n> +\telse\n> +\t\tcancel_default = got_rev_arg;\n> +\tif (revs->def && !revs->rev_input_given && !cancel_default) {\n\nHow do you want to handle \"maybe has a ref\" options like --stdin,\n--tags, etc? Those set revs->rev_input_given.\n\nWith the code you have here, rev_input_given overrides any\nsticky_default decision, and you cannot do this:\n\n  git log --not --remotes=origin\n\nand get the default, because even though you have only UNINTERESTING\ncommits, rev_input_given is true.\n\nIf you move rev_input_given to the cancel_default line above the final\nconditional and turn that conditional into:\n\n  if (revs->def && !cancel_default)\n\nthen it works.\n\n-Peff\n"},{"id":"360844","messageId":"CAHc6FU7iZN6t-mN=nrAptg7WgeDGXVpKwZawSq80+S-bKH1isg@mail.gmail.com","threadId":"49591","inReplyTo":"20181018065328.GC23537@sigill.intra.peff.net","subject":"Re: [RFC v2] revision: Add --sticky-default option","fromName":"Andreas Gruenbacher","fromEmail":"agruenba@redhat.com","sentAt":"2018-10-18T12:52:28Z","receivedAt":"2018-10-18T12:52:42Z","isPatch":false,"sender":{"key":"agruenba@redhat.com","avatar":null},"body":"On Thu, 18 Oct 2018 at 08:53, Jeff King <peff@peff.net> wrote:\n> On Wed, Oct 17, 2018 at 03:49:47PM +0200, Andreas Gruenbacher wrote:\n> > @@ -2431,7 +2446,11 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s\n> >               opt->tweak(revs, opt);\n> >       if (revs->show_merge)\n> >               prepare_show_merge(revs);\n> > -     if (revs->def && !revs->pending.nr && !revs->rev_input_given && !got_rev_arg) {\n> > +     if (revs->sticky_default)\n> > +             cancel_default = has_interesting_revisions();\n> > +     else\n> > +             cancel_default = got_rev_arg;\n> > +     if (revs->def && !revs->rev_input_given && !cancel_default) {\n>\n> How do you want to handle \"maybe has a ref\" options like --stdin,\n> --tags, etc? Those set revs->rev_input_given.\n>\n> With the code you have here, rev_input_given overrides any\n> sticky_default decision, and you cannot do this:\n>\n>   git log --not --remotes=origin\n>\n> and get the default, because even though you have only UNINTERESTING\n> commits, rev_input_given is true.\n>\n> If you move rev_input_given to the cancel_default line above the final\n> conditional and turn that conditional into:\n>\n>   if (revs->def && !cancel_default)\n>\n> then it works.\n\nYes, this still needs fixing, I'm just not sure yet if this is the right way.\n\nThanks,\nAndreas\n"}]}