{"thread":{"id":"26684","subject":"[PATCHv2 0/9] --left/right-only and --cherry-mark","startedAt":"2011-03-07T12:31:34Z","lastAt":"2011-03-11T08:02:15Z","messageCount":30,"participants":["Michael J Gruber","Junio C Hamano"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"162907","messageId":"cover.1299499429.git.git@drmicha.warpmail.net","threadId":"26684","inReplyTo":null,"subject":"[PATCHv2 0/9] --left/right-only and --cherry-mark","fromName":"Michael J Gruber","fromEmail":"git@drmicha.warpmail.net","sentAt":"2011-03-07T12:31:34Z","receivedAt":"2011-03-07T12:31:34Z","isPatch":false,"sender":{"key":"git@grubix.eu","avatar":"https://avatars.githubusercontent.com/u/233215?v=4"},"body":"This is a replacement for mg/rev-list-one-side-only in pu.\nThe --left/right-only related commits (1-4/9) are unchanged.\n\n5/9 is new and refactors the generation of commit marks (<>-) which we\ncurrently do in 5 places, to ease maintenance and extensibility.\n\n6,7 are new and introduce \"--cherry-mark\" to the revision walker which marks\nthose commits which \"--cherry-pick\" would omit.\n\n8,9 are amended as compared to pu, introducing \"--cherry\" as a shortcut for\n\"--cherry-mark --right-only --no-merges\" to produce output much like \"git\ncherry\" with the full flexibility of rev-list/log. (We could use the previous\nversion instead, or with a different synonym; or introduce rev-list-option\naliases...)\n\nThe mark for patch-equivalent commits is '=' because git-cherry's '-' is used\nfor boundary commits already.\n\nThe mark for non-equivalent commits is '+' (following git-cherry), or '<'/'>'\nwith --left-right, or '*' with --graph.\n\nThis is up for bike-shed^W^Wdiscussing - we could use ' ' instead or even '*'\nalso without --graph, or '+' even with --graph.\n\nI would in fact prefer ' ' without --graph and '*' with --graph, which would\nmake it even more different from git-cherry's output, though.\n(Personally, I never liked git-cherry's output anyways.)\n\nThis is also the base for refactoring git-format-patch and git-cherry, of\ncourse, where the latter would be helped if it's ok to change the output\nformat.\n\nJunio C Hamano (1):\n  rev-list: --left/right-only are mutually exclusive\n\nMichael J Gruber (8):\n  revlist.c: introduce --left/right-only for unsymmetric picking\n  t6007: Make sure we test --cherry-pick\n  rev-list: documentation and test for --left/right-only\n  rev-list/log: factor out revision mark generation\n  revision.c: introduce --cherry-mark\n  rev-list: documentation and test for --cherry-mark\n  log --cherry: a synonym\n  t6007: test rev-list --cherry\n\n Documentation/git-rev-list.txt       |    3 +\n Documentation/rev-list-options.txt   |   26 ++++++++\n builtin/rev-list.c                   |   14 +----\n graph.c                              |   17 +-----\n log-tree.c                           |   28 +-------\n pretty.c                             |    6 +--\n revision.c                           |   74 +++++++++++++++++++++-\n revision.h                           |    7 ++-\n t/t6007-rev-list-cherry-pick-file.sh |  113 +++++++++++++++++++++++++++++++---\n 9 files changed, 220 insertions(+), 68 deletions(-)\n\n-- \n1.7.4.1.299.g567d7.dirty\n"},{"id":"162908","messageId":"60adf7d73e44126289a98dada60f9c335ffc84b0.1299499429.git.git@drmicha.warpmail.net","threadId":"26684","inReplyTo":"cover.1299499429.git.git@drmicha.warpmail.net","subject":"[PATCHv2 1/9] revlist.c: introduce --left/right-only for unsymmetric picking","fromName":"Michael J Gruber","fromEmail":"git@drmicha.warpmail.net","sentAt":"2011-03-07T12:31:35Z","receivedAt":"2011-03-07T12:31:35Z","isPatch":false,"sender":{"key":"git@grubix.eu","avatar":"https://avatars.githubusercontent.com/u/233215?v=4"},"body":"The existing \"--cherry-pick\" does not work with unsymmetric ranges\n(A..B) for obvious reasons.\n\nIntroduce \"--left-only\" and \"--right-only\" which limit the output to\ncommits on the respective sides of a symmetric range (i.e. only \"<\"\nresp. \">\" commits as per \"--left-right\").\n\nThis is especially useful for things like\n\n    git log --cherry-pick --right-only @{u}...\n\nwhich is much more flexible (and descriptive) than\n\n    git cherry @{u} | sed -ne 's/^+ //p'\n\nand potentially more useful than\n\n    git log --cherry-pick @{u}...\n\nSigned-off-by: Michael J Gruber <git@drmicha.warpmail.net>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n revision.c |   24 ++++++++++++++++++++++++\n revision.h |    2 ++\n 2 files changed, 26 insertions(+), 0 deletions(-)\n\ndiff --git a/revision.c b/revision.c\nindex 7b9eaef..0681c7c 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -733,6 +733,23 @@ static struct commit_list *collect_bottom_commits(struct commit_list *list)\n \treturn bottom;\n }\n \n+/* Assumes either left_only or right_only is set */\n+static void limit_left_right(struct commit_list *list, struct rev_info *revs)\n+{\n+\tstruct commit_list *p;\n+\n+\tfor (p = list; p; p = p->next) {\n+\t\tstruct commit *commit = p->item;\n+\n+\t\tif (revs->right_only) {\n+\t\t\tif (commit->object.flags & SYMMETRIC_LEFT)\n+\t\t\t\tcommit->object.flags |= SHOWN;\n+\t\t} else\t/* revs->left_only is set */\n+\t\t\tif (!(commit->object.flags & SYMMETRIC_LEFT))\n+\t\t\t\tcommit->object.flags |= SHOWN;\n+\t}\n+}\n+\n static int limit_list(struct rev_info *revs)\n {\n \tint slop = SLOP;\n@@ -788,6 +805,9 @@ static int limit_list(struct rev_info *revs)\n \tif (revs->cherry_pick)\n \t\tcherry_pick_list(newlist, revs);\n \n+\tif (revs->left_only || revs->right_only)\n+\t\tlimit_left_right(newlist, revs);\n+\n \tif (bottom) {\n \t\tlimit_to_ancestry(bottom, newlist);\n \t\tfree_commit_list(bottom);\n@@ -1263,6 +1283,10 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg\n \t\trevs->boundary = 1;\n \t} else if (!strcmp(arg, \"--left-right\")) {\n \t\trevs->left_right = 1;\n+\t} else if (!strcmp(arg, \"--left-only\")) {\n+\t\trevs->left_only = 1;\n+\t} else if (!strcmp(arg, \"--right-only\")) {\n+\t\trevs->right_only = 1;\n \t} else if (!strcmp(arg, \"--count\")) {\n \t\trevs->count = 1;\n \t} else if (!strcmp(arg, \"--cherry-pick\")) {\ndiff --git a/revision.h b/revision.h\nindex 05659c6..d2ffde1 100644\n--- a/revision.h\n+++ b/revision.h\n@@ -59,6 +59,8 @@ struct rev_info {\n \t\t\tboundary:2,\n \t\t\tcount:1,\n \t\t\tleft_right:1,\n+\t\t\tleft_only:1,\n+\t\t\tright_only:1,\n \t\t\trewrite_parents:1,\n \t\t\tprint_parents:1,\n \t\t\tshow_source:1,\n-- \n1.7.4.1.299.g567d7.dirty\n"},{"id":"162909","messageId":"e0b9c34f7eec9d7943bbb8a3134f24e6e4e4ed3e.1299499429.git.git@drmicha.warpmail.net","threadId":"26684","inReplyTo":"cover.1299499429.git.git@drmicha.warpmail.net","subject":"[PATCHv2 2/9] t6007: Make sure we test --cherry-pick","fromName":"Michael J Gruber","fromEmail":"git@drmicha.warpmail.net","sentAt":"2011-03-07T12:31:36Z","receivedAt":"2011-03-07T12:31:36Z","isPatch":false,"sender":{"key":"git@grubix.eu","avatar":"https://avatars.githubusercontent.com/u/233215?v=4"},"body":"Test 5 wants to test --cherry-pick but limits by pathspec in such a way\nthat there are no commits on the left side of the range.\n\nAdd a test without \"--cherry-pick\" which displays this, and add two\nmore commits and another test which tests what we're after. This also\nshortens the last test.\n\nSigned-off-by: Michael J Gruber <git@drmicha.warpmail.net>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n t/t6007-rev-list-cherry-pick-file.sh |   49 ++++++++++++++++++++++++++++-----\n 1 files changed, 41 insertions(+), 8 deletions(-)\n\ndiff --git a/t/t6007-rev-list-cherry-pick-file.sh b/t/t6007-rev-list-cherry-pick-file.sh\nindex b565638..64b72a3 100755\n--- a/t/t6007-rev-list-cherry-pick-file.sh\n+++ b/t/t6007-rev-list-cherry-pick-file.sh\n@@ -4,13 +4,14 @@ test_description='test git rev-list --cherry-pick -- file'\n \n . ./test-lib.sh\n \n-# A---B\n+# A---B---D\n #  \\\n #   \\\n-#    C\n+#    C---E\n #\n # B changes a file foo.c, adding a line of text.  C changes foo.c as\n # well as bar.c, but the change in foo.c was identical to change B.\n+# D and C change bar in the same way, E differently.\n \n test_expect_success setup '\n \techo Hallo > foo &&\n@@ -25,11 +26,21 @@ test_expect_success setup '\n \ttest_tick &&\n \tgit commit -m \"C\" &&\n \tgit tag C &&\n+\techo Dello > bar &&\n+\tgit add bar &&\n+\ttest_tick &&\n+\tgit commit -m \"E\" &&\n+\tgit tag E &&\n \tgit checkout master &&\n \tgit checkout branch foo &&\n \ttest_tick &&\n \tgit commit -m \"B\" &&\n-\tgit tag B\n+\tgit tag B &&\n+\techo Cello > bar &&\n+\tgit add bar &&\n+\ttest_tick &&\n+\tgit commit -m \"D\" &&\n+\tgit tag D\n '\n \n cat >expect <<EOF\n@@ -53,8 +64,33 @@ test_expect_success '--cherry-pick foo comes up empty' '\n \ttest -z \"$(git rev-list --left-right --cherry-pick B...C -- foo)\"\n '\n \n+cat >expect <<EOF\n+>tags/C\n+EOF\n+\n test_expect_success '--cherry-pick bar does not come up empty' '\n-\t! test -z \"$(git rev-list --left-right --cherry-pick B...C -- bar)\"\n+\tgit rev-list --left-right --cherry-pick B...C -- bar > actual &&\n+\tgit name-rev --stdin --name-only --refs=\"*tags/*\" \\\n+\t\t< actual > actual.named &&\n+\ttest_cmp actual.named expect\n+'\n+\n+test_expect_success 'bar does not come up empty' '\n+\tgit rev-list --left-right B...C -- bar > actual &&\n+\tgit name-rev --stdin --name-only --refs=\"*tags/*\" \\\n+\t\t< actual > actual.named &&\n+\ttest_cmp actual.named expect\n+'\n+\n+cat >expect <<EOF\n+>tags/E\n+EOF\n+\n+test_expect_success '--cherry-pick bar does not come up empty (II)' '\n+\tgit rev-list --left-right --cherry-pick D...E -- bar > actual &&\n+\tgit name-rev --stdin --name-only --refs=\"*tags/*\" \\\n+\t\t< actual > actual.named &&\n+\ttest_cmp actual.named expect\n '\n \n test_expect_success '--cherry-pick with independent, but identical branches' '\n@@ -75,11 +111,8 @@ cat >expect <<EOF\n 1\t2\n EOF\n \n-# Insert an extra commit to break the symmetry\n test_expect_success '--count --left-right' '\n-\tgit checkout branch &&\n-\ttest_commit D &&\n-\tgit rev-list --count --left-right B...D > actual &&\n+\tgit rev-list --count --left-right C...D > actual &&\n \ttest_cmp expect actual\n '\n \n-- \n1.7.4.1.299.g567d7.dirty\n"},{"id":"162910","messageId":"59c8afdf475d2b072fb63383df9f62afd2b3b1ee.1299499429.git.git@drmicha.warpmail.net","threadId":"26684","inReplyTo":"cover.1299499429.git.git@drmicha.warpmail.net","subject":"[PATCHv2 3/9] rev-list: documentation and test for --left/right-only","fromName":"Michael J Gruber","fromEmail":"git@drmicha.warpmail.net","sentAt":"2011-03-07T12:31:37Z","receivedAt":"2011-03-07T12:31:37Z","isPatch":false,"sender":{"key":"git@grubix.eu","avatar":"https://avatars.githubusercontent.com/u/233215?v=4"},"body":"Signed-off-by: Michael J Gruber <git@drmicha.warpmail.net>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n Documentation/git-rev-list.txt       |    2 ++\n Documentation/rev-list-options.txt   |   13 +++++++++++++\n t/t6007-rev-list-cherry-pick-file.sh |   32 ++++++++++++++++++++++++++++----\n 3 files changed, 43 insertions(+), 4 deletions(-)\n\ndiff --git a/Documentation/git-rev-list.txt b/Documentation/git-rev-list.txt\nindex 8e1e329..5f47a13 100644\n--- a/Documentation/git-rev-list.txt\n+++ b/Documentation/git-rev-list.txt\n@@ -31,6 +31,8 @@ SYNOPSIS\n \t     [ \\--parents ]\n \t     [ \\--timestamp ]\n \t     [ \\--left-right ]\n+\t     [ \\--left-only ]\n+\t     [ \\--right-only ]\n \t     [ \\--cherry-pick ]\n \t     [ \\--encoding[=<encoding>] ]\n \t     [ \\--(author|committer|grep)=<pattern> ]\ndiff --git a/Documentation/rev-list-options.txt b/Documentation/rev-list-options.txt\nindex 44a2ef1..cebba62 100644\n--- a/Documentation/rev-list-options.txt\n+++ b/Documentation/rev-list-options.txt\n@@ -319,6 +319,19 @@ from the other branch (for example, \"3rd on b\" may be cherry-picked\n from branch A).  With this option, such pairs of commits are\n excluded from the output.\n \n+--left-only::\n+--right-only::\n+\n+\tList only commits on the respective side of a symmetric range,\n+\ti.e. only those which would be marked `<` resp. `>` by\n+\t`--left-right`.\n++\n+For example, `--cherry-pick --right-only A...B` omits those\n+commits from `B` which are in `A` or are patch-equivalent to a commit in\n+`A`. In other words, this lists the `{plus}` commits from `git cherry A B`.\n+More precisely, `--cherry-pick --right-only --no-merges` gives the exact\n+list.\n+\n -g::\n --walk-reflogs::\n \ndiff --git a/t/t6007-rev-list-cherry-pick-file.sh b/t/t6007-rev-list-cherry-pick-file.sh\nindex 64b72a3..cd089a9 100755\n--- a/t/t6007-rev-list-cherry-pick-file.sh\n+++ b/t/t6007-rev-list-cherry-pick-file.sh\n@@ -4,14 +4,14 @@ test_description='test git rev-list --cherry-pick -- file'\n \n . ./test-lib.sh\n \n-# A---B---D\n+# A---B---D---F\n #  \\\n #   \\\n #    C---E\n #\n # B changes a file foo.c, adding a line of text.  C changes foo.c as\n # well as bar.c, but the change in foo.c was identical to change B.\n-# D and C change bar in the same way, E differently.\n+# D and C change bar in the same way, E and F differently.\n \n test_expect_success setup '\n \techo Hallo > foo &&\n@@ -40,7 +40,12 @@ test_expect_success setup '\n \tgit add bar &&\n \ttest_tick &&\n \tgit commit -m \"D\" &&\n-\tgit tag D\n+\tgit tag D &&\n+\techo Nello > bar &&\n+\tgit add bar &&\n+\ttest_tick &&\n+\tgit commit -m \"F\" &&\n+\tgit tag F\n '\n \n cat >expect <<EOF\n@@ -83,11 +88,30 @@ test_expect_success 'bar does not come up empty' '\n '\n \n cat >expect <<EOF\n+<tags/F\n >tags/E\n EOF\n \n test_expect_success '--cherry-pick bar does not come up empty (II)' '\n-\tgit rev-list --left-right --cherry-pick D...E -- bar > actual &&\n+\tgit rev-list --left-right --cherry-pick F...E -- bar > actual &&\n+\tgit name-rev --stdin --name-only --refs=\"*tags/*\" \\\n+\t\t< actual > actual.named &&\n+\ttest_cmp actual.named expect\n+'\n+\n+cat >expect <<EOF\n+tags/E\n+EOF\n+\n+test_expect_success '--cherry-pick --right-only' '\n+\tgit rev-list --cherry-pick --right-only F...E -- bar > actual &&\n+\tgit name-rev --stdin --name-only --refs=\"*tags/*\" \\\n+\t\t< actual > actual.named &&\n+\ttest_cmp actual.named expect\n+'\n+\n+test_expect_success '--cherry-pick --left-only' '\n+\tgit rev-list --cherry-pick --left-only E...F -- bar > actual &&\n \tgit name-rev --stdin --name-only --refs=\"*tags/*\" \\\n \t\t< actual > actual.named &&\n \ttest_cmp actual.named expect\n-- \n1.7.4.1.299.g567d7.dirty\n"},{"id":"162913","messageId":"24852d917104e294726c54803d5c9012997506ca.1299499429.git.git@drmicha.warpmail.net","threadId":"26684","inReplyTo":"cover.1299499429.git.git@drmicha.warpmail.net","subject":"[PATCHv2 4/9] rev-list: --left/right-only are mutually exclusive","fromName":"Michael J Gruber","fromEmail":"git@drmicha.warpmail.net","sentAt":"2011-03-07T12:31:38Z","receivedAt":"2011-03-07T12:31:38Z","isPatch":false,"sender":{"key":"git@grubix.eu","avatar":"https://avatars.githubusercontent.com/u/233215?v=4"},"body":"From: Junio C Hamano <gitster@pobox.com>\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n revision.c |    4 ++++\n 1 files changed, 4 insertions(+), 0 deletions(-)\n\ndiff --git a/revision.c b/revision.c\nindex 0681c7c..1fcaeb7 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -1284,8 +1284,12 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg\n \t} else if (!strcmp(arg, \"--left-right\")) {\n \t\trevs->left_right = 1;\n \t} else if (!strcmp(arg, \"--left-only\")) {\n+\t\tif (revs->right_only)\n+\t\t\tdie(\"--left-only is incompatible with --right-only\");\n \t\trevs->left_only = 1;\n \t} else if (!strcmp(arg, \"--right-only\")) {\n+\t\tif (revs->left_only)\n+\t\t\tdie(\"--right-only is incompatible with --left-only\");\n \t\trevs->right_only = 1;\n \t} else if (!strcmp(arg, \"--count\")) {\n \t\trevs->count = 1;\n-- \n1.7.4.1.299.g567d7.dirty\n"},{"id":"162915","messageId":"bc30fe8d0aa63a46b6dcaee365dbb6addf11909f.1299499429.git.git@drmicha.warpmail.net","threadId":"26684","inReplyTo":"cover.1299499429.git.git@drmicha.warpmail.net","subject":"[PATCHv2 5/9] rev-list/log: factor out revision mark generation","fromName":"Michael J Gruber","fromEmail":"git@drmicha.warpmail.net","sentAt":"2011-03-07T12:31:39Z","receivedAt":"2011-03-07T12:31:39Z","isPatch":false,"sender":{"key":"git@grubix.eu","avatar":"https://avatars.githubusercontent.com/u/233215?v=4"},"body":"Currently, we have identical code for generating revision marks ('<',\n'>', '-') in 5 places.\n\nFactor out the code to a single function get_revision_mark() for easier\nmaintenance and extensibility.\n\nNote that the check for !!revs in graph.c (which gets removed\neffectively by this patch) is superfluous.\n\nSigned-off-by: Michael J Gruber <git@drmicha.warpmail.net>\n---\n builtin/rev-list.c |   14 ++------------\n graph.c            |   17 ++---------------\n log-tree.c         |   28 ++++------------------------\n pretty.c           |    6 +-----\n revision.c         |   17 +++++++++++++++++\n revision.h         |    1 +\n 6 files changed, 27 insertions(+), 56 deletions(-)\n\ndiff --git a/builtin/rev-list.c b/builtin/rev-list.c\nindex ba27d39..f458cb7 100644\n--- a/builtin/rev-list.c\n+++ b/builtin/rev-list.c\n@@ -64,18 +64,8 @@ static void show_commit(struct commit *commit, void *data)\n \tif (info->header_prefix)\n \t\tfputs(info->header_prefix, stdout);\n \n-\tif (!revs->graph) {\n-\t\tif (commit->object.flags & BOUNDARY)\n-\t\t\tputchar('-');\n-\t\telse if (commit->object.flags & UNINTERESTING)\n-\t\t\tputchar('^');\n-\t\telse if (revs->left_right) {\n-\t\t\tif (commit->object.flags & SYMMETRIC_LEFT)\n-\t\t\t\tputchar('<');\n-\t\t\telse\n-\t\t\t\tputchar('>');\n-\t\t}\n-\t}\n+\tif (!revs->graph)\n+\t\tfputs(get_revision_mark(revs, commit), stdout);\n \tif (revs->abbrev_commit && revs->abbrev)\n \t\tfputs(find_unique_abbrev(commit->object.sha1, revs->abbrev),\n \t\t      stdout);\ndiff --git a/graph.c b/graph.c\nindex f1a63c2..ef2e24e 100644\n--- a/graph.c\n+++ b/graph.c\n@@ -798,22 +798,9 @@ static void graph_output_commit_char(struct git_graph *graph, struct strbuf *sb)\n \t}\n \n \t/*\n-\t * If revs->left_right is set, print '<' for commits that\n-\t * come from the left side, and '>' for commits from the right\n-\t * side.\n+\t * get_revision_mark() handles all other cases without assert()\n \t */\n-\tif (graph->revs && graph->revs->left_right) {\n-\t\tif (graph->commit->object.flags & SYMMETRIC_LEFT)\n-\t\t\tstrbuf_addch(sb, '<');\n-\t\telse\n-\t\t\tstrbuf_addch(sb, '>');\n-\t\treturn;\n-\t}\n-\n-\t/*\n-\t * Print '*' in all other cases\n-\t */\n-\tstrbuf_addch(sb, '*');\n+\tstrbuf_addstr(sb, get_revision_mark(graph->revs, graph->commit));\n }\n \n /*\ndiff --git a/log-tree.c b/log-tree.c\nindex b46ed3b..1257040 100644\n--- a/log-tree.c\n+++ b/log-tree.c\n@@ -380,18 +380,8 @@ void show_log(struct rev_info *opt)\n \tif (!opt->verbose_header) {\n \t\tgraph_show_commit(opt->graph);\n \n-\t\tif (!opt->graph) {\n-\t\t\tif (commit->object.flags & BOUNDARY)\n-\t\t\t\tputchar('-');\n-\t\t\telse if (commit->object.flags & UNINTERESTING)\n-\t\t\t\tputchar('^');\n-\t\t\telse if (opt->left_right) {\n-\t\t\t\tif (commit->object.flags & SYMMETRIC_LEFT)\n-\t\t\t\t\tputchar('<');\n-\t\t\t\telse\n-\t\t\t\t\tputchar('>');\n-\t\t\t}\n-\t\t}\n+\t\tif (!opt->graph)\n+\t\t\tfputs(get_revision_mark(opt, commit), stdout);\n \t\tfputs(find_unique_abbrev(commit->object.sha1, abbrev_commit), stdout);\n \t\tif (opt->print_parents)\n \t\t\tshow_parents(commit, abbrev_commit);\n@@ -448,18 +438,8 @@ void show_log(struct rev_info *opt)\n \t\tif (opt->commit_format != CMIT_FMT_ONELINE)\n \t\t\tfputs(\"commit \", stdout);\n \n-\t\tif (!opt->graph) {\n-\t\t\tif (commit->object.flags & BOUNDARY)\n-\t\t\t\tputchar('-');\n-\t\t\telse if (commit->object.flags & UNINTERESTING)\n-\t\t\t\tputchar('^');\n-\t\t\telse if (opt->left_right) {\n-\t\t\t\tif (commit->object.flags & SYMMETRIC_LEFT)\n-\t\t\t\t\tputchar('<');\n-\t\t\t\telse\n-\t\t\t\t\tputchar('>');\n-\t\t\t}\n-\t\t}\n+\t\tif (!opt->graph)\n+\t\t\tfputs(get_revision_mark(opt, commit), stdout);\n \t\tfputs(find_unique_abbrev(commit->object.sha1, abbrev_commit),\n \t\t      stdout);\n \t\tif (opt->print_parents)\ndiff --git a/pretty.c b/pretty.c\nindex 8549934..f21a30c 100644\n--- a/pretty.c\n+++ b/pretty.c\n@@ -859,11 +859,7 @@ static size_t format_commit_one(struct strbuf *sb, const char *placeholder,\n \t\t                              c->abbrev_parent_hashes.off;\n \t\treturn 1;\n \tcase 'm':\t\t/* left/right/bottom */\n-\t\tstrbuf_addch(sb, (commit->object.flags & BOUNDARY)\n-\t\t                 ? '-'\n-\t\t                 : (commit->object.flags & SYMMETRIC_LEFT)\n-\t\t                 ? '<'\n-\t\t                 : '>');\n+\t\tstrbuf_addstr(sb, get_revision_mark(NULL, commit));\n \t\treturn 1;\n \tcase 'd':\n \t\tformat_decoration(sb, commit);\ndiff --git a/revision.c b/revision.c\nindex 1fcaeb7..49d9ba8 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -2263,3 +2263,20 @@ struct commit *get_revision(struct rev_info *revs)\n \t\tgraph_update(revs->graph, c);\n \treturn c;\n }\n+\n+char *get_revision_mark(const struct rev_info *revs, const struct commit *commit)\n+{\n+\tif (commit->object.flags & BOUNDARY)\n+\t\treturn \"-\";\n+\telse if (commit->object.flags & UNINTERESTING)\n+\t\treturn \"^\";\n+\telse if (!revs || revs->left_right) {\n+\t\tif (commit->object.flags & SYMMETRIC_LEFT)\n+\t\t\treturn \"<\";\n+\t\telse\n+\t\t\treturn \">\";\n+\t}\n+\telse if (revs->graph)\n+\t\treturn \"*\";\n+\treturn \"\";\n+}\ndiff --git a/revision.h b/revision.h\nindex d2ffde1..0e4b35e 100644\n--- a/revision.h\n+++ b/revision.h\n@@ -165,6 +165,7 @@ extern int handle_revision_arg(const char *arg, struct rev_info *revs,int flags,\n \n extern int prepare_revision_walk(struct rev_info *revs);\n extern struct commit *get_revision(struct rev_info *revs);\n+extern char *get_revision_mark(const struct rev_info *revs, const struct commit *commit);\n \n extern void mark_parents_uninteresting(struct commit *commit);\n extern void mark_tree_uninteresting(struct tree *tree);\n-- \n1.7.4.1.299.g567d7.dirty\n"},{"id":"162912","messageId":"4b4b4f78372167c76224903f0a360c3c9ab62728.1299499429.git.git@drmicha.warpmail.net","threadId":"26684","inReplyTo":"cover.1299499429.git.git@drmicha.warpmail.net","subject":"[PATCHv2 6/9] revision.c: introduce --cherry-mark","fromName":"Michael J Gruber","fromEmail":"git@drmicha.warpmail.net","sentAt":"2011-03-07T12:31:40Z","receivedAt":"2011-03-07T12:31:40Z","isPatch":false,"sender":{"key":"git@grubix.eu","avatar":"https://avatars.githubusercontent.com/u/233215?v=4"},"body":"for marking those commits which \"--cherry-pick\" would drop.\nThe marker for those commits is '=' because '-' denotes a boundary\ncommit already, even though 'git cherry' uses it.\n\nNonequivalent commits are denoted '+' unless '--left-right' is used.\n\nSigned-off-by: Michael J Gruber <git@drmicha.warpmail.net>\n---\n revision.c |   21 ++++++++++++++++++---\n revision.h |    4 +++-\n 2 files changed, 21 insertions(+), 4 deletions(-)\n\ndiff --git a/revision.c b/revision.c\nindex 49d9ba8..3da403e 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -535,6 +535,7 @@ static void cherry_pick_list(struct commit_list *list, struct rev_info *revs)\n \tint left_count = 0, right_count = 0;\n \tint left_first;\n \tstruct patch_ids ids;\n+\tunsigned cherryflag;\n \n \t/* First count the commits on the left and on the right */\n \tfor (p = list; p; p = p->next) {\n@@ -576,6 +577,9 @@ static void cherry_pick_list(struct commit_list *list, struct rev_info *revs)\n \t\tcommit->util = add_commit_patch_id(commit, &ids);\n \t}\n \n+\t/* either cherry_mark or cherry_pick are true */\n+\tcherryflag = revs->cherry_mark ? PATCHSAME : SHOWN;\n+\n \t/* Check the other side */\n \tfor (p = list; p; p = p->next) {\n \t\tstruct commit *commit = p->item;\n@@ -598,7 +602,7 @@ static void cherry_pick_list(struct commit_list *list, struct rev_info *revs)\n \t\tif (!id)\n \t\t\tcontinue;\n \t\tid->seen = 1;\n-\t\tcommit->object.flags |= SHOWN;\n+\t\tcommit->object.flags |= cherryflag;\n \t}\n \n \t/* Now check the original side for seen ones */\n@@ -610,7 +614,7 @@ static void cherry_pick_list(struct commit_list *list, struct rev_info *revs)\n \t\tif (!ent)\n \t\t\tcontinue;\n \t\tif (ent->seen)\n-\t\t\tcommit->object.flags |= SHOWN;\n+\t\t\tcommit->object.flags |= cherryflag;\n \t\tcommit->util = NULL;\n \t}\n \n@@ -802,7 +806,7 @@ static int limit_list(struct rev_info *revs)\n \t\tshow(revs, newlist);\n \t\tshow_early_output = NULL;\n \t}\n-\tif (revs->cherry_pick)\n+\tif (revs->cherry_pick || revs->cherry_mark)\n \t\tcherry_pick_list(newlist, revs);\n \n \tif (revs->left_only || revs->right_only)\n@@ -1293,7 +1297,14 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg\n \t\trevs->right_only = 1;\n \t} else if (!strcmp(arg, \"--count\")) {\n \t\trevs->count = 1;\n+\t} else if (!strcmp(arg, \"--cherry-mark\")) {\n+\t\tif (revs->cherry_pick)\n+\t\t\tdie(\"--cherry-mark is incompatible with --cherry-pick\");\n+\t\trevs->cherry_mark = 1;\n+\t\trevs->limited = 1; /* needs limit_list() */\n \t} else if (!strcmp(arg, \"--cherry-pick\")) {\n+\t\tif (revs->cherry_mark)\n+\t\t\tdie(\"--cherry-pick is incompatible with --cherry-mark\");\n \t\trevs->cherry_pick = 1;\n \t\trevs->limited = 1;\n \t} else if (!strcmp(arg, \"--objects\")) {\n@@ -2270,6 +2281,8 @@ char *get_revision_mark(const struct rev_info *revs, const struct commit *commit\n \t\treturn \"-\";\n \telse if (commit->object.flags & UNINTERESTING)\n \t\treturn \"^\";\n+\telse if (commit->object.flags & PATCHSAME)\n+\t\treturn \"=\";\n \telse if (!revs || revs->left_right) {\n \t\tif (commit->object.flags & SYMMETRIC_LEFT)\n \t\t\treturn \"<\";\n@@ -2278,5 +2291,7 @@ char *get_revision_mark(const struct rev_info *revs, const struct commit *commit\n \t}\n \telse if (revs->graph)\n \t\treturn \"*\";\n+\telse if (revs->cherry_mark)\n+\t\treturn \"+\";\n \treturn \"\";\n }\ndiff --git a/revision.h b/revision.h\nindex 0e4b35e..ee380ad 100644\n--- a/revision.h\n+++ b/revision.h\n@@ -14,7 +14,8 @@\n #define CHILD_SHOWN\t(1u<<6)\n #define ADDED\t\t(1u<<7)\t/* Parents already parsed and added? */\n #define SYMMETRIC_LEFT\t(1u<<8)\n-#define ALL_REV_FLAGS\t((1u<<9)-1)\n+#define PATCHSAME\t(1u<<10)\n+#define ALL_REV_FLAGS\t((1u<<10)-1)\n \n #define DECORATE_SHORT_REFS\t1\n #define DECORATE_FULL_REFS\t2\n@@ -68,6 +69,7 @@ struct rev_info {\n \t\t\treverse:1,\n \t\t\treverse_output_stage:1,\n \t\t\tcherry_pick:1,\n+\t\t\tcherry_mark:1,\n \t\t\tbisect:1,\n \t\t\tancestry_path:1,\n \t\t\tfirst_parent_only:1;\n-- \n1.7.4.1.299.g567d7.dirty\n"},{"id":"162914","messageId":"438c61ffc424fd29b124927536981c11587e00b6.1299499429.git.git@drmicha.warpmail.net","threadId":"26684","inReplyTo":"cover.1299499429.git.git@drmicha.warpmail.net","subject":"[PATCHv2 7/9] rev-list: documentation and test for --cherry-mark","fromName":"Michael J Gruber","fromEmail":"git@drmicha.warpmail.net","sentAt":"2011-03-07T12:31:41Z","receivedAt":"2011-03-07T12:31:41Z","isPatch":false,"sender":{"key":"git@grubix.eu","avatar":"https://avatars.githubusercontent.com/u/233215?v=4"},"body":"Signed-off-by: Michael J Gruber <git@drmicha.warpmail.net>\n---\n Documentation/git-rev-list.txt       |    1 +\n Documentation/rev-list-options.txt   |    5 +++++\n t/t6007-rev-list-cherry-pick-file.sh |   28 ++++++++++++++++++++++++++++\n 3 files changed, 34 insertions(+), 0 deletions(-)\n\ndiff --git a/Documentation/git-rev-list.txt b/Documentation/git-rev-list.txt\nindex 5f47a13..8a891ca 100644\n--- a/Documentation/git-rev-list.txt\n+++ b/Documentation/git-rev-list.txt\n@@ -33,6 +33,7 @@ SYNOPSIS\n \t     [ \\--left-right ]\n \t     [ \\--left-only ]\n \t     [ \\--right-only ]\n+\t     [ \\--cherry-mark ]\n \t     [ \\--cherry-pick ]\n \t     [ \\--encoding[=<encoding>] ]\n \t     [ \\--(author|committer|grep)=<pattern> ]\ndiff --git a/Documentation/rev-list-options.txt b/Documentation/rev-list-options.txt\nindex cebba62..4755b83 100644\n--- a/Documentation/rev-list-options.txt\n+++ b/Documentation/rev-list-options.txt\n@@ -305,6 +305,11 @@ ifdef::git-rev-list[]\n \tto /dev/null as the output does not have to be formatted.\n endif::git-rev-list[]\n \n+--cherry-mark::\n+\n+\tLike `--cherry-pick` (see below) but mark equivalent commits\n+\twith `=` rather than omitting them, and inequivalent ones with `+`.\n+\n --cherry-pick::\n \n \tOmit any commit that introduces the same change as\ndiff --git a/t/t6007-rev-list-cherry-pick-file.sh b/t/t6007-rev-list-cherry-pick-file.sh\nindex cd089a9..37bd25e 100755\n--- a/t/t6007-rev-list-cherry-pick-file.sh\n+++ b/t/t6007-rev-list-cherry-pick-file.sh\n@@ -100,6 +100,34 @@ test_expect_success '--cherry-pick bar does not come up empty (II)' '\n '\n \n cat >expect <<EOF\n++tags/F\n+=tags/D\n++tags/E\n+=tags/C\n+EOF\n+\n+test_expect_success '--cherry-mark' '\n+\tgit rev-list --cherry-mark F...E -- bar > actual &&\n+\tgit name-rev --stdin --name-only --refs=\"*tags/*\" \\\n+\t\t< actual > actual.named &&\n+\ttest_cmp actual.named expect\n+'\n+\n+cat >expect <<EOF\n+<tags/F\n+=tags/D\n+>tags/E\n+=tags/C\n+EOF\n+\n+test_expect_success '--cherry-mark --left-right' '\n+\tgit rev-list --cherry-mark --left-right F...E -- bar > actual &&\n+\tgit name-rev --stdin --name-only --refs=\"*tags/*\" \\\n+\t\t< actual > actual.named &&\n+\ttest_cmp actual.named expect\n+'\n+\n+cat >expect <<EOF\n tags/E\n EOF\n \n-- \n1.7.4.1.299.g567d7.dirty\n"},{"id":"162911","messageId":"83edad511550713d81a7aedec9fb852c117556fc.1299499429.git.git@drmicha.warpmail.net","threadId":"26684","inReplyTo":"cover.1299499429.git.git@drmicha.warpmail.net","subject":"[PATCHv2 8/9] log --cherry: a synonym","fromName":"Michael J Gruber","fromEmail":"git@drmicha.warpmail.net","sentAt":"2011-03-07T12:31:42Z","receivedAt":"2011-03-07T12:31:42Z","isPatch":false,"sender":{"key":"git@grubix.eu","avatar":"https://avatars.githubusercontent.com/u/233215?v=4"},"body":"At the porcelain level, because by definition there are many more contributors\nthan integrators, it makes sense to give a handy short-hand for --right-only\nused with --cherry-mark and --no-merges.  Make it so.\n\nIn other words, this provides \"git cherry with rev-list interface\".\n\nSigned-off-by: Michael J Gruber <git@drmicha.warpmail.net>\n---\n Documentation/rev-list-options.txt |    8 ++++++++\n revision.c                         |   10 +++++++++-\n 2 files changed, 17 insertions(+), 1 deletions(-)\n\ndiff --git a/Documentation/rev-list-options.txt b/Documentation/rev-list-options.txt\nindex 4755b83..95d209c 100644\n--- a/Documentation/rev-list-options.txt\n+++ b/Documentation/rev-list-options.txt\n@@ -337,6 +337,14 @@ commits from `B` which are in `A` or are patch-equivalent to a commit in\n More precisely, `--cherry-pick --right-only --no-merges` gives the exact\n list.\n \n+--cherry::\n+\n+\tA synonym for `--right-only --cherry-mark --no-merges`; useful to\n+\tlimit the output to the commits on our side and mark those that\n+\thave been applied to the other side of a forked history with\n+\t`git log --cherry upstream...mybranch`, similar to\n+\t`git cherry upstream mybranch`.\n+\n -g::\n --walk-reflogs::\n \ndiff --git a/revision.c b/revision.c\nindex 3da403e..61f571e 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -1289,12 +1289,20 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg\n \t\trevs->left_right = 1;\n \t} else if (!strcmp(arg, \"--left-only\")) {\n \t\tif (revs->right_only)\n-\t\t\tdie(\"--left-only is incompatible with --right-only\");\n+\t\t\tdie(\"--left-only is incompatible with --right-only\"\n+\t\t\t    \" or --cherry\");\n \t\trevs->left_only = 1;\n \t} else if (!strcmp(arg, \"--right-only\")) {\n \t\tif (revs->left_only)\n \t\t\tdie(\"--right-only is incompatible with --left-only\");\n \t\trevs->right_only = 1;\n+\t} else if (!strcmp(arg, \"--cherry\")) {\n+\t\tif (revs->left_only)\n+\t\t\tdie(\"--cherry is incompatible with --left-only\");\n+\t\trevs->cherry_mark = 1;\n+\t\trevs->right_only = 1;\n+\t\trevs->no_merges = 1;\n+\t\trevs->limited = 1;\n \t} else if (!strcmp(arg, \"--count\")) {\n \t\trevs->count = 1;\n \t} else if (!strcmp(arg, \"--cherry-mark\")) {\n-- \n1.7.4.1.299.g567d7.dirty\n"},{"id":"162916","messageId":"cb4f7705217f252ca1156babd8bcbea67ba38f13.1299499429.git.git@drmicha.warpmail.net","threadId":"26684","inReplyTo":"cover.1299499429.git.git@drmicha.warpmail.net","subject":"[PATCHv2 9/9] t6007: test rev-list --cherry","fromName":"Michael J Gruber","fromEmail":"git@drmicha.warpmail.net","sentAt":"2011-03-07T12:31:43Z","receivedAt":"2011-03-07T12:31:43Z","isPatch":false,"sender":{"key":"git@grubix.eu","avatar":"https://avatars.githubusercontent.com/u/233215?v=4"},"body":"Signed-off-by: Michael J Gruber <git@drmicha.warpmail.net>\n---\n t/t6007-rev-list-cherry-pick-file.sh |   12 ++++++++++++\n 1 files changed, 12 insertions(+), 0 deletions(-)\n\ndiff --git a/t/t6007-rev-list-cherry-pick-file.sh b/t/t6007-rev-list-cherry-pick-file.sh\nindex 37bd25e..cacf3de 100755\n--- a/t/t6007-rev-list-cherry-pick-file.sh\n+++ b/t/t6007-rev-list-cherry-pick-file.sh\n@@ -145,6 +145,18 @@ test_expect_success '--cherry-pick --left-only' '\n \ttest_cmp actual.named expect\n '\n \n+cat >expect <<EOF\n++tags/E\n+=tags/C\n+EOF\n+\n+test_expect_success '--cherry' '\n+\tgit rev-list --cherry F...E -- bar > actual &&\n+\tgit name-rev --stdin --name-only --refs=\"*tags/*\" \\\n+\t\t< actual > actual.named &&\n+\ttest_cmp actual.named expect\n+'\n+\n test_expect_success '--cherry-pick with independent, but identical branches' '\n \tgit symbolic-ref HEAD refs/heads/independent &&\n \trm .git/index &&\n-- \n1.7.4.1.299.g567d7.dirty\n"},{"id":"163087","messageId":"7vy64o7zki.fsf@alter.siamese.dyndns.org","threadId":"26684","inReplyTo":"4b4b4f78372167c76224903f0a360c3c9ab62728.1299499429.git.git@drmicha.warpmail.net","subject":"Re: [PATCHv2 6/9] revision.c: introduce --cherry-mark","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2011-03-09T21:29:17Z","receivedAt":"2011-03-09T21:29:17Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Michael J Gruber <git@drmicha.warpmail.net> writes:\n\n> for marking those commits which \"--cherry-pick\" would drop.\n\nPlease do not start your second paragraph with a half-sentence.\n\n> The marker for those commits is '=' because '-' denotes a boundary\n> commit already, even though 'git cherry' uses it.\n>\n> Nonequivalent commits are denoted '+' unless '--left-right' is used.\n>\n> Signed-off-by: Michael J Gruber <git@drmicha.warpmail.net>\n> ---\n>  revision.c |   21 ++++++++++++++++++---\n>  revision.h |    4 +++-\n>  2 files changed, 21 insertions(+), 4 deletions(-)\n>\n> diff --git a/revision.c b/revision.c\n> index 49d9ba8..3da403e 100644\n> --- a/revision.c\n> +++ b/revision.c\n> @@ -535,6 +535,7 @@ static void cherry_pick_list(struct commit_list *list, struct rev_info *revs)\n>  \tint left_count = 0, right_count = 0;\n>  \tint left_first;\n>  \tstruct patch_ids ids;\n> +\tunsigned cherryflag;\n\ns/cherryflag/cherry_flag/;\n\n> diff --git a/revision.h b/revision.h\n> index 0e4b35e..ee380ad 100644\n> --- a/revision.h\n> +++ b/revision.h\n> @@ -14,7 +14,8 @@\n>  #define CHILD_SHOWN\t(1u<<6)\n>  #define ADDED\t\t(1u<<7)\t/* Parents already parsed and added? */\n>  #define SYMMETRIC_LEFT\t(1u<<8)\n> -#define ALL_REV_FLAGS\t((1u<<9)-1)\n> +#define PATCHSAME\t(1u<<10)\n> +#define ALL_REV_FLAGS\t((1u<<10)-1)\n\nI think you meant (1u<<9) so that ALL can cover that bit with\n((1u<<10)-1).\n"},{"id":"163091","messageId":"7vtyfc7ymk.fsf@alter.siamese.dyndns.org","threadId":"26684","inReplyTo":"cover.1299499429.git.git@drmicha.warpmail.net","subject":"Re: [PATCHv2 0/9] --left/right-only and --cherry-mark","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2011-03-09T21:49:39Z","receivedAt":"2011-03-09T21:49:39Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Michael J Gruber <git@drmicha.warpmail.net> writes:\n\n> This is a replacement for mg/rev-list-one-side-only in pu.\n> The --left/right-only related commits (1-4/9) are unchanged.\n\nI like the general idea of marking the equivalent ones instead of outright\ndiscarding the commits in the cherry_pick_list() function.\n\nIt might be a good idea to record the correspondence between equivalent\ncommits in some way; the current topic does not need that information in\norder to produce its output, so that is something other people can build\non top of this topic in the future.\n\nThere is only one minor point that nagged me while reading this series.\n\nConceptually revs->cherry_mark ought to be a subset of revs->cherry_pick\nand the code shouldn't have to do something like this:\n\n\tif (revs->cherry_pick || revs->cherry_mark)\n        \tcherry_pick_list();\n\nInstead, the code should arrange that revs->cherry_pick is always set\nwhen revs->cherry_mark is set before the calling application enters the\nloop to call get_revision().\n\nBut that would make the command line parsing more cumbersome (you would\neither waste one bit so that you can tell if you saw --cherry-pick on the\ncommand line, or keep the version of parser in this series as-is, and add\npostprocessing code to flip revs->cherry_pick on when revs->cherry_mark\nwas given in prepare_revision_walk()), and I understand that is why you\ndid it that way?\n\nThanks.\n"},{"id":"163118","messageId":"4D7886FD.60109@drmicha.warpmail.net","threadId":"26684","inReplyTo":"7vtyfc7ymk.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCHv2 0/9] --left/right-only and --cherry-mark","fromName":"Michael J Gruber","fromEmail":"git@drmicha.warpmail.net","sentAt":"2011-03-10T08:08:29Z","receivedAt":"2011-03-10T08:08:29Z","isPatch":false,"sender":{"key":"git@grubix.eu","avatar":"https://avatars.githubusercontent.com/u/233215?v=4"},"body":"Junio C Hamano venit, vidit, dixit 09.03.2011 22:49:\n> Michael J Gruber <git@drmicha.warpmail.net> writes:\n> \n>> This is a replacement for mg/rev-list-one-side-only in pu.\n>> The --left/right-only related commits (1-4/9) are unchanged.\n> \n> I like the general idea of marking the equivalent ones instead of outright\n> discarding the commits in the cherry_pick_list() function.\n> \n> It might be a good idea to record the correspondence between equivalent\n> commits in some way; the current topic does not need that information in\n> order to produce its output, so that is something other people can build\n> on top of this topic in the future.\n\nYes, I often want to look up the commit on pu which a patch resulted in.\nBut usually looking it up by commit subject works better than by\npatch-id (because of occasional minor edits).\n\nIn general it might be nice to have maybe --patch-ids similar to\n--parents, or a --patch=<commit> limitting option. (I don't think\noutputting equivalent commits along with all commits is viable.)\n\n> There is only one minor point that nagged me while reading this series.\n> \n> Conceptually revs->cherry_mark ought to be a subset of revs->cherry_pick\n> and the code shouldn't have to do something like this:\n> \n> \tif (revs->cherry_pick || revs->cherry_mark)\n>         \tcherry_pick_list();\n> \n> Instead, the code should arrange that revs->cherry_pick is always set\n> when revs->cherry_mark is set before the calling application enters the\n> loop to call get_revision().\n> \n> But that would make the command line parsing more cumbersome (you would\n> either waste one bit so that you can tell if you saw --cherry-pick on the\n> command line, or keep the version of parser in this series as-is, and add\n> postprocessing code to flip revs->cherry_pick on when revs->cherry_mark\n> was given in prepare_revision_walk()), and I understand that is why you\n> did it that way?\n\nYes, I think so :) Another reason is that even cherry_pick_list() needs\nto know which object flag it should set. So we could\n\n- leave the parser as is\n- set cherry_pick when cherry_mark is set\n- if (revs->cherry_pick) cherry_pick_list();\n- leave cherry_pick_list() as is\n\nWould that be better? I didn't do that because it changes the meaning of\ncherry_pick (it can mean two things then). It would introduce the\nassumption \"pick is set when mark is\" instead of \"at most one is set\"\nwhich is as good or bad. (The current series does cherry_mark when both\nare set by a different caller, and the above would do neither when only\ncherry_mark is set.)\n\nI think I also didn't do it because \"marking\" does not do any \"picking\",\nso with the above \"cherry_pick\" would really be \"cherry_process\".\n\nBut I'm open to changing this, of course (maybe along with renaming\nrevs->cherry_pick).\n\nAny thoughts on the actual marks ('+' vs. ' ' vs. '*')?\n\nI also feel like we could use a space between the mark and the sha1\n(like git cherry does) to ease copy and paste but that is an orthogonal\nissue applying to all marks (<>-^+=).\n\nMichael\n"},{"id":"163119","messageId":"49bfbea68bc42fa3e2903dbc8e63cf152b153d03.1299745278.git.git@drmicha.warpmail.net","threadId":"26684","inReplyTo":"7vy64o7zki.fsf@alter.siamese.dyndns.org","subject":"[PATCHv2+ 6/9] revision.c: introduce --cherry-mark","fromName":"Michael J Gruber","fromEmail":"git@drmicha.warpmail.net","sentAt":"2011-03-10T08:23:34Z","receivedAt":"2011-03-10T08:23:34Z","isPatch":false,"sender":{"key":"git@grubix.eu","avatar":"https://avatars.githubusercontent.com/u/233215?v=4"},"body":"Introduce --cherry-mark for marking those commits which \"--cherry-pick\"\nwould drop.  The marker for those commits is '=' because '-' denotes a\nboundary commit already, even though 'git cherry' uses it.\n\nNonequivalent commits are denoted '+' unless '--left-right' is used.\n\nSigned-off-by: Michael J Gruber <git@drmicha.warpmail.net>\n---\nJunio C Hamano venit, vidit, dixit 09.03.2011 22:29:\n> Michael J Gruber <git@drmicha.warpmail.net> writes:\n>\n>> for marking those commits which \"--cherry-pick\" would drop.\n>\n> Please do not start your second paragraph with a half-sentence.\n\nI try to get rid of that acquired habit!\n\n>> The marker for those commits is '=' because '-' denotes a boundary\n>> commit already, even though 'git cherry' uses it.\n>>\n>> Nonequivalent commits are denoted '+' unless '--left-right' is used.\n>>\n>> Signed-off-by: Michael J Gruber <git@drmicha.warpmail.net>\n>> ---\n>>  revision.c |   21 ++++++++++++++++++---\n>>  revision.h |    4 +++-\n>>  2 files changed, 21 insertions(+), 4 deletions(-)\n>>\n>> diff --git a/revision.c b/revision.c\n>> index 49d9ba8..3da403e 100644\n>> --- a/revision.c\n>> +++ b/revision.c\n>> @@ -535,6 +535,7 @@ static void cherry_pick_list(struct commit_list *list, struct rev_info *revs)\n>>  \tint left_count = 0, right_count = 0;\n>>  \tint left_first;\n>>  \tstruct patch_ids ids;\n>> +\tunsigned cherryflag;\n>\n> s/cherryflag/cherry_flag/;\n\nOK.\n\n>> diff --git a/revision.h b/revision.h\n>> index 0e4b35e..ee380ad 100644\n>> --- a/revision.h\n>> +++ b/revision.h\n>> @@ -14,7 +14,8 @@\n>>  #define CHILD_SHOWN\t(1u<<6)\n>>  #define ADDED\t\t(1u<<7)\t/* Parents already parsed and added? */\n>>  #define SYMMETRIC_LEFT\t(1u<<8)\n>> -#define ALL_REV_FLAGS\t((1u<<9)-1)\n>> +#define PATCHSAME\t(1u<<10)\n>> +#define ALL_REV_FLAGS\t((1u<<10)-1)\n>\n> I think you meant (1u<<9) so that ALL can cover that bit with\n> ((1u<<10)-1).\n\nThanks for reading so carefully. What a blunder, and who knows when we would\nhave noticed (not with the current users of ALL_REV_FLAGS).\n\nOh wait, my v3 is patch-equivalent to what you have in pu already. How did I\nfind out? \"git log1 --cherry origin/pu...\", of course :) At least I changed the\nmessage.\n\nMichael\n\nIn case someone wonders:\ngit help log1\n`git log1' is aliased to `log --abbrev-commit --pretty=oneline --decorate'\n\n revision.c |   21 ++++++++++++++++++---\n revision.h |    4 +++-\n 2 files changed, 21 insertions(+), 4 deletions(-)\n\ndiff --git a/revision.c b/revision.c\nindex 0de1608..36022a6 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -535,6 +535,7 @@ static void cherry_pick_list(struct commit_list *list, struct rev_info *revs)\n \tint left_count = 0, right_count = 0;\n \tint left_first;\n \tstruct patch_ids ids;\n+\tunsigned cherry_flag;\n \n \t/* First count the commits on the left and on the right */\n \tfor (p = list; p; p = p->next) {\n@@ -576,6 +577,9 @@ static void cherry_pick_list(struct commit_list *list, struct rev_info *revs)\n \t\tcommit->util = add_commit_patch_id(commit, &ids);\n \t}\n \n+\t/* either cherry_mark or cherry_pick are true */\n+\tcherry_flag = revs->cherry_mark ? PATCHSAME : SHOWN;\n+\n \t/* Check the other side */\n \tfor (p = list; p; p = p->next) {\n \t\tstruct commit *commit = p->item;\n@@ -598,7 +602,7 @@ static void cherry_pick_list(struct commit_list *list, struct rev_info *revs)\n \t\tif (!id)\n \t\t\tcontinue;\n \t\tid->seen = 1;\n-\t\tcommit->object.flags |= SHOWN;\n+\t\tcommit->object.flags |= cherry_flag;\n \t}\n \n \t/* Now check the original side for seen ones */\n@@ -610,7 +614,7 @@ static void cherry_pick_list(struct commit_list *list, struct rev_info *revs)\n \t\tif (!ent)\n \t\t\tcontinue;\n \t\tif (ent->seen)\n-\t\t\tcommit->object.flags |= SHOWN;\n+\t\t\tcommit->object.flags |= cherry_flag;\n \t\tcommit->util = NULL;\n \t}\n \n@@ -802,7 +806,7 @@ static int limit_list(struct rev_info *revs)\n \t\tshow(revs, newlist);\n \t\tshow_early_output = NULL;\n \t}\n-\tif (revs->cherry_pick)\n+\tif (revs->cherry_pick || revs->cherry_mark)\n \t\tcherry_pick_list(newlist, revs);\n \n \tif (revs->left_only || revs->right_only)\n@@ -1293,7 +1297,14 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg\n \t\trevs->right_only = 1;\n \t} else if (!strcmp(arg, \"--count\")) {\n \t\trevs->count = 1;\n+\t} else if (!strcmp(arg, \"--cherry-mark\")) {\n+\t\tif (revs->cherry_pick)\n+\t\t\tdie(\"--cherry-mark is incompatible with --cherry-pick\");\n+\t\trevs->cherry_mark = 1;\n+\t\trevs->limited = 1; /* needs limit_list() */\n \t} else if (!strcmp(arg, \"--cherry-pick\")) {\n+\t\tif (revs->cherry_mark)\n+\t\t\tdie(\"--cherry-pick is incompatible with --cherry-mark\");\n \t\trevs->cherry_pick = 1;\n \t\trevs->limited = 1;\n \t} else if (!strcmp(arg, \"--objects\")) {\n@@ -2270,6 +2281,8 @@ char *get_revision_mark(const struct rev_info *revs, const struct commit *commit\n \t\treturn \"-\";\n \telse if (commit->object.flags & UNINTERESTING)\n \t\treturn \"^\";\n+\telse if (commit->object.flags & PATCHSAME)\n+\t\treturn \"=\";\n \telse if (!revs || revs->left_right) {\n \t\tif (commit->object.flags & SYMMETRIC_LEFT)\n \t\t\treturn \"<\";\n@@ -2277,5 +2290,7 @@ char *get_revision_mark(const struct rev_info *revs, const struct commit *commit\n \t\t\treturn \">\";\n \t} else if (revs->graph)\n \t\treturn \"*\";\n+\telse if (revs->cherry_mark)\n+\t\treturn \"+\";\n \treturn \"\";\n }\ndiff --git a/revision.h b/revision.h\nindex 0e4b35e..d38f135 100644\n--- a/revision.h\n+++ b/revision.h\n@@ -14,7 +14,8 @@\n #define CHILD_SHOWN\t(1u<<6)\n #define ADDED\t\t(1u<<7)\t/* Parents already parsed and added? */\n #define SYMMETRIC_LEFT\t(1u<<8)\n-#define ALL_REV_FLAGS\t((1u<<9)-1)\n+#define PATCHSAME\t(1u<<9)\n+#define ALL_REV_FLAGS\t((1u<<10)-1)\n \n #define DECORATE_SHORT_REFS\t1\n #define DECORATE_FULL_REFS\t2\n@@ -68,6 +69,7 @@ struct rev_info {\n \t\t\treverse:1,\n \t\t\treverse_output_stage:1,\n \t\t\tcherry_pick:1,\n+\t\t\tcherry_mark:1,\n \t\t\tbisect:1,\n \t\t\tancestry_path:1,\n \t\t\tfirst_parent_only:1;\n-- \n1.7.4.1.317.gf445f\n"},{"id":"163126","messageId":"7vd3lz5me5.fsf@alter.siamese.dyndns.org","threadId":"26684","inReplyTo":"4D7886FD.60109@drmicha.warpmail.net","subject":"Re: [PATCHv2 0/9] --left/right-only and --cherry-mark","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2011-03-10T09:56:50Z","receivedAt":"2011-03-10T09:56:50Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Michael J Gruber <git@drmicha.warpmail.net> writes:\n\n> Junio C Hamano venit, vidit, dixit 09.03.2011 22:49:\n> ...\n>> Conceptually revs->cherry_mark ought to be a subset of revs->cherry_pick\n>> and the code shouldn't have to do something like this:\n>> \n>> \tif (revs->cherry_pick || revs->cherry_mark)\n>>         \tcherry_pick_list();\n>> \n>> Instead, the code should arrange that revs->cherry_pick is always set\n>> when revs->cherry_mark is set before the calling application enters the\n>> loop to call get_revision().\n>> \n>> But that would make the command line parsing more cumbersome (you would\n>> either waste one bit so that you can tell if you saw --cherry-pick on the\n>> command line, or keep the version of parser in this series as-is, and add\n>> postprocessing code to flip revs->cherry_pick on when revs->cherry_mark\n>> was given in prepare_revision_walk()), and I understand that is why you\n>> did it that way?\n>\n> Yes, I think so :) Another reason is that even cherry_pick_list() needs\n> to know which object flag it should set.\n\nI didn't have trouble with \"if (revs->cherry_mark)\" used for that purpose\nat all.\n\nThat is what I meant by \"cherry-mark is a _subset_ of cherry-pick\".  In\nother words, if you are marking the cherry-pick result, you must be doing\na cherry-pick to begin with, so having to say \"cherry-pick || cherry-mark\"\nis a bad taste.\n\nBut that does not contradict with the need to do something differently\nbetween the case where you are cherry-marking and where you are not\ncherry-marking.\n\n> - leave the parser as is\n> - set cherry_pick when cherry_mark is set\n> - if (revs->cherry_pick) cherry_pick_list();\n> - leave cherry_pick_list() as is\n\nI think that essentially is what I speculated in \"either X or Y\" part as\nsolution Y.\n\n> Would that be better? I didn't do that because it changes the meaning of\n> cherry_pick (it can mean two things then). It would introduce the\n> assumption \"pick is set when mark is\" instead of \"at most one is set\"\n\nWell, as I said earlier, my suggestion was coming from \"if you are\ncherry-marking, you must be cherry-picking in the first place\", so yes, I\nam saying that \"at most one is set\" is a bad taste.  If the assumption has\nto change to match the better taste, that can only be a good thing ;-).\n\n> Any thoughts on the actual marks ('+' vs. ' ' vs. '*')?\n> I also feel like we could use a space between the mark and the sha1\n> (like git cherry does) to ease copy and paste but that is an orthogonal\n> issue applying to all marks (<>-^+=).\n\nI personally don't care very much and also choose not to say much on it\ntoo early even if I had opinion on the choice, because I know there are\nmany people with better visual tastes than I on the list and I am sure\nthey will voice their opinion once they see sample output.\n"},{"id":"163130","messageId":"4D78AC8B.7010308@drmicha.warpmail.net","threadId":"26684","inReplyTo":"7vd3lz5me5.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCHv2 0/9] --left/right-only and --cherry-mark","fromName":"Michael J Gruber","fromEmail":"git@drmicha.warpmail.net","sentAt":"2011-03-10T10:48:43Z","receivedAt":"2011-03-10T10:48:43Z","isPatch":false,"sender":{"key":"git@grubix.eu","avatar":"https://avatars.githubusercontent.com/u/233215?v=4"},"body":"Junio C Hamano venit, vidit, dixit 10.03.2011 10:56:\n> Michael J Gruber <git@drmicha.warpmail.net> writes:\n> \n>> Junio C Hamano venit, vidit, dixit 09.03.2011 22:49:\n>> ...\n>>> Conceptually revs->cherry_mark ought to be a subset of revs->cherry_pick\n>>> and the code shouldn't have to do something like this:\n>>>\n>>> \tif (revs->cherry_pick || revs->cherry_mark)\n>>>         \tcherry_pick_list();\n>>>\n>>> Instead, the code should arrange that revs->cherry_pick is always set\n>>> when revs->cherry_mark is set before the calling application enters the\n>>> loop to call get_revision().\n>>>\n>>> But that would make the command line parsing more cumbersome (you would\n>>> either waste one bit so that you can tell if you saw --cherry-pick on the\n>>> command line, or keep the version of parser in this series as-is, and add\n>>> postprocessing code to flip revs->cherry_pick on when revs->cherry_mark\n>>> was given in prepare_revision_walk()), and I understand that is why you\n>>> did it that way?\n>>\n>> Yes, I think so :) Another reason is that even cherry_pick_list() needs\n>> to know which object flag it should set.\n> \n> I didn't have trouble with \"if (revs->cherry_mark)\" used for that purpose\n> at all.\n> \n> That is what I meant by \"cherry-mark is a _subset_ of cherry-pick\".  In\n> other words, if you are marking the cherry-pick result, you must be doing\n> a cherry-pick to begin with, so having to say \"cherry-pick || cherry-mark\"\n> is a bad taste.\n> \n> But that does not contradict with the need to do something differently\n> between the case where you are cherry-marking and where you are not\n> cherry-marking.\n> \n>> - leave the parser as is\n>> - set cherry_pick when cherry_mark is set\n>> - if (revs->cherry_pick) cherry_pick_list();\n>> - leave cherry_pick_list() as is\n> \n> I think that essentially is what I speculated in \"either X or Y\" part as\n> solution Y.\n> \n>> Would that be better? I didn't do that because it changes the meaning of\n>> cherry_pick (it can mean two things then). It would introduce the\n>> assumption \"pick is set when mark is\" instead of \"at most one is set\"\n> \n> Well, as I said earlier, my suggestion was coming from \"if you are\n> cherry-marking, you must be cherry-picking in the first place\", so yes, I\n> am saying that \"at most one is set\" is a bad taste.  If the assumption has\n> to change to match the better taste, that can only be a good thing ;-).\n\nBeing half-way through doing \"Y\" I remember why I really disliked \"Y\":\nbecause it breaks the association between option names (--cherry-pick,\n--cherry-mark) and rev flags (cherry_pick, cherry_mark). With \"Y\",\ncherry_pick would mean --cherry-pick or --cherry-mark. (Also, as\nmentioned, we're not \"picking\" when marking.)\n\nAdditionally, since parse_revision_opt (which calls handle_revision_opt)\nis called from other sites for individual args we would need to do the\nhandling in the Y case (set pick when marking) right in\nhandle_revision_opt, not just in setup_revisions. It's a matter of a few\nmore if's and or's, but still.\n\nTaking these together, I wonder whether we shouldn't leave it as in v2.\n\nMichael\n"},{"id":"163138","messageId":"cover.1299767412.git.git@drmicha.warpmail.net","threadId":"26684","inReplyTo":"4D78AC8B.7010308@drmicha.warpmail.net","subject":"[PATCHv3 00/10] --left/right-only and --cherry-mark","fromName":"Michael J Gruber","fromEmail":"git@drmicha.warpmail.net","sentAt":"2011-03-10T14:44:53Z","receivedAt":"2011-03-10T14:44:53Z","isPatch":false,"sender":{"key":"git@grubix.eu","avatar":"https://avatars.githubusercontent.com/u/233215?v=4"},"body":"Anyway, this is what it looks like with \"Y\" (even though I prefer \"X\"\nbecause of the option to flag correspondence.\n\nv3 is v2 plus what we have discussed (pu had v2 plus Junio's amends).\nIn addition, 6 and 9 use \"Y\" rather than \"X\".\n\nTo make it less boring, I added 10 which changes the output format with\ncommit marks. See an example there and below. (10 is independent of the\nchoice of X vs. Y, of course.)\n\nAll together, this gives output (from my branch) like:\n\ngit-log --oneline --cherry origin/pu...\n\n+ dfe27d4 git-log: put space after commit mark\n= ca14e3f t6007: test rev-list --cherry\n+ e5a72f0 log --cherry: a synonym\n= fd5b652 rev-list: documentation and test for --cherry-mark\n+ c17a824 revision.c: introduce --cherry-mark\n= 3d5377a rev-list/log: factor out revision mark generation\n\n\ngit-log --oneline --graph --cherry origin/pu...\n\n* dfe27d4 git-log: put space after commit mark\n= ca14e3f t6007: test rev-list --cherry\n* e5a72f0 log --cherry: a synonym\n= fd5b652 rev-list: documentation and test for --cherry-mark\n* c17a824 revision.c: introduce --cherry-mark\n= 3d5377a rev-list/log: factor out revision mark generation\n\n\ngit-log --oneline --graph --cherry-mark origin/pu...\n\n* dfe27d4 git-log: put space after commit mark\n= ca14e3f t6007: test rev-list --cherry\n* e5a72f0 log --cherry: a synonym\n= fd5b652 rev-list: documentation and test for --cherry-mark\n* c17a824 revision.c: introduce --cherry-mark\n= 3d5377a rev-list/log: factor out revision mark generation\n*   0cb35e5 Merge branch 'mm/maint-log-n-with-diff-filtering' into pu\n|\\  \n| * 251df09 log: fix --max-count when used together with -S or -G\n* |   803ba88 Merge branch 'jk/edit-notes-in-commit-log' into pu\n...\n|  / / / / / / / / / /  \n* | | | | | | | | | |   f1b3ae0 Merge branch 'mg/rev-list-one-side-only' into pu\n|\\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \\  \n| = | | | | | | | | | | fe3b59e t6007: test rev-list --cherry\n| * | | | | | | | | | | 94f605e log --cherry: a synonym\n| = | | | | | | | | | | cb56e30 rev-list: documentation and test for --cherry-mark\n| * | | | | | | | | | | adbbb31 revision.c: introduce --cherry-mark\n| = | | | | | | | | | | 1df2d65 rev-list/log: factor out revision mark generation\n\nAnd all this in beautiful color (and full log interface), of course! Compare with:\n\ngit cherry origin/pu -v\n- 3d5377ae86c22a73bdce7896abe2953019039e0e rev-list/log: factor out revision mark generation\n+ c17a82478307a5a29455de09232087b17435c52a revision.c: introduce --cherry-mark\n- fd5b65227573cb8d5ff7c8087814f9b8f8e0851e rev-list: documentation and test for --cherry-mark\n+ e5a72f0ddc0ddc9b6087c08143b188043f3bea1f log --cherry: a synonym\n- ca14e3fb22b91653086fbd8c8600f2f93409a0a6 t6007: test rev-list --cherry\n+ dfe27d480258ab4af4fa50628a9bbaff33ba6860 git-log: put space after commit mark\n\nLet the bike-shedding begin!\n\nJunio C Hamano (1):\n  rev-list: --left/right-only are mutually exclusive\n\nMichael J Gruber (9):\n  revlist.c: introduce --left/right-only for unsymmetric picking\n  t6007: Make sure we test --cherry-pick\n  rev-list: documentation and test for --left/right-only\n  rev-list/log: factor out revision mark generation\n  revision.c: introduce --cherry-mark\n  rev-list: documentation and test for --cherry-mark\n  log --cherry: a synonym\n  t6007: test rev-list --cherry\n  git-log: put space after commit mark\n\n Documentation/git-rev-list.txt       |    3 +\n Documentation/rev-list-options.txt   |   26 ++++++++\n builtin/rev-list.c                   |   14 +----\n git-svn.perl                         |    2 +-\n graph.c                              |   17 +-----\n log-tree.c                           |   28 +-------\n pretty.c                             |    6 +--\n revision.c                           |   81 +++++++++++++++++++++++-\n revision.h                           |    8 ++-\n t/t6007-rev-list-cherry-pick-file.sh |  113 +++++++++++++++++++++++++++++++---\n 10 files changed, 230 insertions(+), 68 deletions(-)\n\n-- \n1.7.4.1.317.gf445f\n"},{"id":"163141","messageId":"60adf7d73e44126289a98dada60f9c335ffc84b0.1299767412.git.git@drmicha.warpmail.net","threadId":"26684","inReplyTo":"4D78AC8B.7010308@drmicha.warpmail.net","subject":"[PATCHv3 01/10] revlist.c: introduce --left/right-only for unsymmetric picking","fromName":"Michael J Gruber","fromEmail":"git@drmicha.warpmail.net","sentAt":"2011-03-10T14:44:54Z","receivedAt":"2011-03-10T14:44:54Z","isPatch":false,"sender":{"key":"git@grubix.eu","avatar":"https://avatars.githubusercontent.com/u/233215?v=4"},"body":"The existing \"--cherry-pick\" does not work with unsymmetric ranges\n(A..B) for obvious reasons.\n\nIntroduce \"--left-only\" and \"--right-only\" which limit the output to\ncommits on the respective sides of a symmetric range (i.e. only \"<\"\nresp. \">\" commits as per \"--left-right\").\n\nThis is especially useful for things like\n\n    git log --cherry-pick --right-only @{u}...\n\nwhich is much more flexible (and descriptive) than\n\n    git cherry @{u} | sed -ne 's/^+ //p'\n\nand potentially more useful than\n\n    git log --cherry-pick @{u}...\n\nSigned-off-by: Michael J Gruber <git@drmicha.warpmail.net>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n revision.c |   24 ++++++++++++++++++++++++\n revision.h |    2 ++\n 2 files changed, 26 insertions(+), 0 deletions(-)\n\ndiff --git a/revision.c b/revision.c\nindex 7b9eaef..0681c7c 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -733,6 +733,23 @@ static struct commit_list *collect_bottom_commits(struct commit_list *list)\n \treturn bottom;\n }\n \n+/* Assumes either left_only or right_only is set */\n+static void limit_left_right(struct commit_list *list, struct rev_info *revs)\n+{\n+\tstruct commit_list *p;\n+\n+\tfor (p = list; p; p = p->next) {\n+\t\tstruct commit *commit = p->item;\n+\n+\t\tif (revs->right_only) {\n+\t\t\tif (commit->object.flags & SYMMETRIC_LEFT)\n+\t\t\t\tcommit->object.flags |= SHOWN;\n+\t\t} else\t/* revs->left_only is set */\n+\t\t\tif (!(commit->object.flags & SYMMETRIC_LEFT))\n+\t\t\t\tcommit->object.flags |= SHOWN;\n+\t}\n+}\n+\n static int limit_list(struct rev_info *revs)\n {\n \tint slop = SLOP;\n@@ -788,6 +805,9 @@ static int limit_list(struct rev_info *revs)\n \tif (revs->cherry_pick)\n \t\tcherry_pick_list(newlist, revs);\n \n+\tif (revs->left_only || revs->right_only)\n+\t\tlimit_left_right(newlist, revs);\n+\n \tif (bottom) {\n \t\tlimit_to_ancestry(bottom, newlist);\n \t\tfree_commit_list(bottom);\n@@ -1263,6 +1283,10 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg\n \t\trevs->boundary = 1;\n \t} else if (!strcmp(arg, \"--left-right\")) {\n \t\trevs->left_right = 1;\n+\t} else if (!strcmp(arg, \"--left-only\")) {\n+\t\trevs->left_only = 1;\n+\t} else if (!strcmp(arg, \"--right-only\")) {\n+\t\trevs->right_only = 1;\n \t} else if (!strcmp(arg, \"--count\")) {\n \t\trevs->count = 1;\n \t} else if (!strcmp(arg, \"--cherry-pick\")) {\ndiff --git a/revision.h b/revision.h\nindex 05659c6..d2ffde1 100644\n--- a/revision.h\n+++ b/revision.h\n@@ -59,6 +59,8 @@ struct rev_info {\n \t\t\tboundary:2,\n \t\t\tcount:1,\n \t\t\tleft_right:1,\n+\t\t\tleft_only:1,\n+\t\t\tright_only:1,\n \t\t\trewrite_parents:1,\n \t\t\tprint_parents:1,\n \t\t\tshow_source:1,\n-- \n1.7.4.1.317.gf445f\n"},{"id":"163140","messageId":"e0b9c34f7eec9d7943bbb8a3134f24e6e4e4ed3e.1299767412.git.git@drmicha.warpmail.net","threadId":"26684","inReplyTo":"4D78AC8B.7010308@drmicha.warpmail.net","subject":"[PATCHv3 02/10] t6007: Make sure we test --cherry-pick","fromName":"Michael J Gruber","fromEmail":"git@drmicha.warpmail.net","sentAt":"2011-03-10T14:44:55Z","receivedAt":"2011-03-10T14:44:55Z","isPatch":false,"sender":{"key":"git@grubix.eu","avatar":"https://avatars.githubusercontent.com/u/233215?v=4"},"body":"Test 5 wants to test --cherry-pick but limits by pathspec in such a way\nthat there are no commits on the left side of the range.\n\nAdd a test without \"--cherry-pick\" which displays this, and add two\nmore commits and another test which tests what we're after. This also\nshortens the last test.\n\nSigned-off-by: Michael J Gruber <git@drmicha.warpmail.net>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n t/t6007-rev-list-cherry-pick-file.sh |   49 ++++++++++++++++++++++++++++-----\n 1 files changed, 41 insertions(+), 8 deletions(-)\n\ndiff --git a/t/t6007-rev-list-cherry-pick-file.sh b/t/t6007-rev-list-cherry-pick-file.sh\nindex b565638..64b72a3 100755\n--- a/t/t6007-rev-list-cherry-pick-file.sh\n+++ b/t/t6007-rev-list-cherry-pick-file.sh\n@@ -4,13 +4,14 @@ test_description='test git rev-list --cherry-pick -- file'\n \n . ./test-lib.sh\n \n-# A---B\n+# A---B---D\n #  \\\n #   \\\n-#    C\n+#    C---E\n #\n # B changes a file foo.c, adding a line of text.  C changes foo.c as\n # well as bar.c, but the change in foo.c was identical to change B.\n+# D and C change bar in the same way, E differently.\n \n test_expect_success setup '\n \techo Hallo > foo &&\n@@ -25,11 +26,21 @@ test_expect_success setup '\n \ttest_tick &&\n \tgit commit -m \"C\" &&\n \tgit tag C &&\n+\techo Dello > bar &&\n+\tgit add bar &&\n+\ttest_tick &&\n+\tgit commit -m \"E\" &&\n+\tgit tag E &&\n \tgit checkout master &&\n \tgit checkout branch foo &&\n \ttest_tick &&\n \tgit commit -m \"B\" &&\n-\tgit tag B\n+\tgit tag B &&\n+\techo Cello > bar &&\n+\tgit add bar &&\n+\ttest_tick &&\n+\tgit commit -m \"D\" &&\n+\tgit tag D\n '\n \n cat >expect <<EOF\n@@ -53,8 +64,33 @@ test_expect_success '--cherry-pick foo comes up empty' '\n \ttest -z \"$(git rev-list --left-right --cherry-pick B...C -- foo)\"\n '\n \n+cat >expect <<EOF\n+>tags/C\n+EOF\n+\n test_expect_success '--cherry-pick bar does not come up empty' '\n-\t! test -z \"$(git rev-list --left-right --cherry-pick B...C -- bar)\"\n+\tgit rev-list --left-right --cherry-pick B...C -- bar > actual &&\n+\tgit name-rev --stdin --name-only --refs=\"*tags/*\" \\\n+\t\t< actual > actual.named &&\n+\ttest_cmp actual.named expect\n+'\n+\n+test_expect_success 'bar does not come up empty' '\n+\tgit rev-list --left-right B...C -- bar > actual &&\n+\tgit name-rev --stdin --name-only --refs=\"*tags/*\" \\\n+\t\t< actual > actual.named &&\n+\ttest_cmp actual.named expect\n+'\n+\n+cat >expect <<EOF\n+>tags/E\n+EOF\n+\n+test_expect_success '--cherry-pick bar does not come up empty (II)' '\n+\tgit rev-list --left-right --cherry-pick D...E -- bar > actual &&\n+\tgit name-rev --stdin --name-only --refs=\"*tags/*\" \\\n+\t\t< actual > actual.named &&\n+\ttest_cmp actual.named expect\n '\n \n test_expect_success '--cherry-pick with independent, but identical branches' '\n@@ -75,11 +111,8 @@ cat >expect <<EOF\n 1\t2\n EOF\n \n-# Insert an extra commit to break the symmetry\n test_expect_success '--count --left-right' '\n-\tgit checkout branch &&\n-\ttest_commit D &&\n-\tgit rev-list --count --left-right B...D > actual &&\n+\tgit rev-list --count --left-right C...D > actual &&\n \ttest_cmp expect actual\n '\n \n-- \n1.7.4.1.317.gf445f\n"},{"id":"163142","messageId":"59c8afdf475d2b072fb63383df9f62afd2b3b1ee.1299767412.git.git@drmicha.warpmail.net","threadId":"26684","inReplyTo":"4D78AC8B.7010308@drmicha.warpmail.net","subject":"[PATCHv3 03/10] rev-list: documentation and test for --left/right-only","fromName":"Michael J Gruber","fromEmail":"git@drmicha.warpmail.net","sentAt":"2011-03-10T14:44:56Z","receivedAt":"2011-03-10T14:44:56Z","isPatch":false,"sender":{"key":"git@grubix.eu","avatar":"https://avatars.githubusercontent.com/u/233215?v=4"},"body":"Signed-off-by: Michael J Gruber <git@drmicha.warpmail.net>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n Documentation/git-rev-list.txt       |    2 ++\n Documentation/rev-list-options.txt   |   13 +++++++++++++\n t/t6007-rev-list-cherry-pick-file.sh |   32 ++++++++++++++++++++++++++++----\n 3 files changed, 43 insertions(+), 4 deletions(-)\n\ndiff --git a/Documentation/git-rev-list.txt b/Documentation/git-rev-list.txt\nindex 8e1e329..5f47a13 100644\n--- a/Documentation/git-rev-list.txt\n+++ b/Documentation/git-rev-list.txt\n@@ -31,6 +31,8 @@ SYNOPSIS\n \t     [ \\--parents ]\n \t     [ \\--timestamp ]\n \t     [ \\--left-right ]\n+\t     [ \\--left-only ]\n+\t     [ \\--right-only ]\n \t     [ \\--cherry-pick ]\n \t     [ \\--encoding[=<encoding>] ]\n \t     [ \\--(author|committer|grep)=<pattern> ]\ndiff --git a/Documentation/rev-list-options.txt b/Documentation/rev-list-options.txt\nindex 44a2ef1..cebba62 100644\n--- a/Documentation/rev-list-options.txt\n+++ b/Documentation/rev-list-options.txt\n@@ -319,6 +319,19 @@ from the other branch (for example, \"3rd on b\" may be cherry-picked\n from branch A).  With this option, such pairs of commits are\n excluded from the output.\n \n+--left-only::\n+--right-only::\n+\n+\tList only commits on the respective side of a symmetric range,\n+\ti.e. only those which would be marked `<` resp. `>` by\n+\t`--left-right`.\n++\n+For example, `--cherry-pick --right-only A...B` omits those\n+commits from `B` which are in `A` or are patch-equivalent to a commit in\n+`A`. In other words, this lists the `{plus}` commits from `git cherry A B`.\n+More precisely, `--cherry-pick --right-only --no-merges` gives the exact\n+list.\n+\n -g::\n --walk-reflogs::\n \ndiff --git a/t/t6007-rev-list-cherry-pick-file.sh b/t/t6007-rev-list-cherry-pick-file.sh\nindex 64b72a3..cd089a9 100755\n--- a/t/t6007-rev-list-cherry-pick-file.sh\n+++ b/t/t6007-rev-list-cherry-pick-file.sh\n@@ -4,14 +4,14 @@ test_description='test git rev-list --cherry-pick -- file'\n \n . ./test-lib.sh\n \n-# A---B---D\n+# A---B---D---F\n #  \\\n #   \\\n #    C---E\n #\n # B changes a file foo.c, adding a line of text.  C changes foo.c as\n # well as bar.c, but the change in foo.c was identical to change B.\n-# D and C change bar in the same way, E differently.\n+# D and C change bar in the same way, E and F differently.\n \n test_expect_success setup '\n \techo Hallo > foo &&\n@@ -40,7 +40,12 @@ test_expect_success setup '\n \tgit add bar &&\n \ttest_tick &&\n \tgit commit -m \"D\" &&\n-\tgit tag D\n+\tgit tag D &&\n+\techo Nello > bar &&\n+\tgit add bar &&\n+\ttest_tick &&\n+\tgit commit -m \"F\" &&\n+\tgit tag F\n '\n \n cat >expect <<EOF\n@@ -83,11 +88,30 @@ test_expect_success 'bar does not come up empty' '\n '\n \n cat >expect <<EOF\n+<tags/F\n >tags/E\n EOF\n \n test_expect_success '--cherry-pick bar does not come up empty (II)' '\n-\tgit rev-list --left-right --cherry-pick D...E -- bar > actual &&\n+\tgit rev-list --left-right --cherry-pick F...E -- bar > actual &&\n+\tgit name-rev --stdin --name-only --refs=\"*tags/*\" \\\n+\t\t< actual > actual.named &&\n+\ttest_cmp actual.named expect\n+'\n+\n+cat >expect <<EOF\n+tags/E\n+EOF\n+\n+test_expect_success '--cherry-pick --right-only' '\n+\tgit rev-list --cherry-pick --right-only F...E -- bar > actual &&\n+\tgit name-rev --stdin --name-only --refs=\"*tags/*\" \\\n+\t\t< actual > actual.named &&\n+\ttest_cmp actual.named expect\n+'\n+\n+test_expect_success '--cherry-pick --left-only' '\n+\tgit rev-list --cherry-pick --left-only E...F -- bar > actual &&\n \tgit name-rev --stdin --name-only --refs=\"*tags/*\" \\\n \t\t< actual > actual.named &&\n \ttest_cmp actual.named expect\n-- \n1.7.4.1.317.gf445f\n"},{"id":"163139","messageId":"24852d917104e294726c54803d5c9012997506ca.1299767412.git.git@drmicha.warpmail.net","threadId":"26684","inReplyTo":"4D78AC8B.7010308@drmicha.warpmail.net","subject":"[PATCHv3 04/10] rev-list: --left/right-only are mutually exclusive","fromName":"Michael J Gruber","fromEmail":"git@drmicha.warpmail.net","sentAt":"2011-03-10T14:44:57Z","receivedAt":"2011-03-10T14:44:57Z","isPatch":false,"sender":{"key":"git@grubix.eu","avatar":"https://avatars.githubusercontent.com/u/233215?v=4"},"body":"From: Junio C Hamano <gitster@pobox.com>\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n revision.c |    4 ++++\n 1 files changed, 4 insertions(+), 0 deletions(-)\n\ndiff --git a/revision.c b/revision.c\nindex 0681c7c..1fcaeb7 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -1284,8 +1284,12 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg\n \t} else if (!strcmp(arg, \"--left-right\")) {\n \t\trevs->left_right = 1;\n \t} else if (!strcmp(arg, \"--left-only\")) {\n+\t\tif (revs->right_only)\n+\t\t\tdie(\"--left-only is incompatible with --right-only\");\n \t\trevs->left_only = 1;\n \t} else if (!strcmp(arg, \"--right-only\")) {\n+\t\tif (revs->left_only)\n+\t\t\tdie(\"--right-only is incompatible with --left-only\");\n \t\trevs->right_only = 1;\n \t} else if (!strcmp(arg, \"--count\")) {\n \t\trevs->count = 1;\n-- \n1.7.4.1.317.gf445f\n"},{"id":"163148","messageId":"3d5377ae86c22a73bdce7896abe2953019039e0e.1299767412.git.git@drmicha.warpmail.net","threadId":"26684","inReplyTo":"4D78AC8B.7010308@drmicha.warpmail.net","subject":"[PATCHv3 05/10] rev-list/log: factor out revision mark generation","fromName":"Michael J Gruber","fromEmail":"git@drmicha.warpmail.net","sentAt":"2011-03-10T14:44:58Z","receivedAt":"2011-03-10T14:44:58Z","isPatch":false,"sender":{"key":"git@grubix.eu","avatar":"https://avatars.githubusercontent.com/u/233215?v=4"},"body":"Currently, we have identical code for generating revision marks ('<',\n'>', '-') in 5 places.\n\nFactor out the code to a single function get_revsion_mark() for easier\nmaintenance and extensibility.\n\nNote that the check for !!revs in graph.c (which gets removed\neffectively by this patch) is superfluous.\n\nSigned-off-by: Michael J Gruber <git@drmicha.warpmail.net>\n---\n builtin/rev-list.c |   14 ++------------\n graph.c            |   17 ++---------------\n log-tree.c         |   28 ++++------------------------\n pretty.c           |    6 +-----\n revision.c         |   16 ++++++++++++++++\n revision.h         |    1 +\n 6 files changed, 26 insertions(+), 56 deletions(-)\n\ndiff --git a/builtin/rev-list.c b/builtin/rev-list.c\nindex ba27d39..f458cb7 100644\n--- a/builtin/rev-list.c\n+++ b/builtin/rev-list.c\n@@ -64,18 +64,8 @@ static void show_commit(struct commit *commit, void *data)\n \tif (info->header_prefix)\n \t\tfputs(info->header_prefix, stdout);\n \n-\tif (!revs->graph) {\n-\t\tif (commit->object.flags & BOUNDARY)\n-\t\t\tputchar('-');\n-\t\telse if (commit->object.flags & UNINTERESTING)\n-\t\t\tputchar('^');\n-\t\telse if (revs->left_right) {\n-\t\t\tif (commit->object.flags & SYMMETRIC_LEFT)\n-\t\t\t\tputchar('<');\n-\t\t\telse\n-\t\t\t\tputchar('>');\n-\t\t}\n-\t}\n+\tif (!revs->graph)\n+\t\tfputs(get_revision_mark(revs, commit), stdout);\n \tif (revs->abbrev_commit && revs->abbrev)\n \t\tfputs(find_unique_abbrev(commit->object.sha1, revs->abbrev),\n \t\t      stdout);\ndiff --git a/graph.c b/graph.c\nindex f1a63c2..ef2e24e 100644\n--- a/graph.c\n+++ b/graph.c\n@@ -798,22 +798,9 @@ static void graph_output_commit_char(struct git_graph *graph, struct strbuf *sb)\n \t}\n \n \t/*\n-\t * If revs->left_right is set, print '<' for commits that\n-\t * come from the left side, and '>' for commits from the right\n-\t * side.\n+\t * get_revision_mark() handles all other cases without assert()\n \t */\n-\tif (graph->revs && graph->revs->left_right) {\n-\t\tif (graph->commit->object.flags & SYMMETRIC_LEFT)\n-\t\t\tstrbuf_addch(sb, '<');\n-\t\telse\n-\t\t\tstrbuf_addch(sb, '>');\n-\t\treturn;\n-\t}\n-\n-\t/*\n-\t * Print '*' in all other cases\n-\t */\n-\tstrbuf_addch(sb, '*');\n+\tstrbuf_addstr(sb, get_revision_mark(graph->revs, graph->commit));\n }\n \n /*\ndiff --git a/log-tree.c b/log-tree.c\nindex b46ed3b..1257040 100644\n--- a/log-tree.c\n+++ b/log-tree.c\n@@ -380,18 +380,8 @@ void show_log(struct rev_info *opt)\n \tif (!opt->verbose_header) {\n \t\tgraph_show_commit(opt->graph);\n \n-\t\tif (!opt->graph) {\n-\t\t\tif (commit->object.flags & BOUNDARY)\n-\t\t\t\tputchar('-');\n-\t\t\telse if (commit->object.flags & UNINTERESTING)\n-\t\t\t\tputchar('^');\n-\t\t\telse if (opt->left_right) {\n-\t\t\t\tif (commit->object.flags & SYMMETRIC_LEFT)\n-\t\t\t\t\tputchar('<');\n-\t\t\t\telse\n-\t\t\t\t\tputchar('>');\n-\t\t\t}\n-\t\t}\n+\t\tif (!opt->graph)\n+\t\t\tfputs(get_revision_mark(opt, commit), stdout);\n \t\tfputs(find_unique_abbrev(commit->object.sha1, abbrev_commit), stdout);\n \t\tif (opt->print_parents)\n \t\t\tshow_parents(commit, abbrev_commit);\n@@ -448,18 +438,8 @@ void show_log(struct rev_info *opt)\n \t\tif (opt->commit_format != CMIT_FMT_ONELINE)\n \t\t\tfputs(\"commit \", stdout);\n \n-\t\tif (!opt->graph) {\n-\t\t\tif (commit->object.flags & BOUNDARY)\n-\t\t\t\tputchar('-');\n-\t\t\telse if (commit->object.flags & UNINTERESTING)\n-\t\t\t\tputchar('^');\n-\t\t\telse if (opt->left_right) {\n-\t\t\t\tif (commit->object.flags & SYMMETRIC_LEFT)\n-\t\t\t\t\tputchar('<');\n-\t\t\t\telse\n-\t\t\t\t\tputchar('>');\n-\t\t\t}\n-\t\t}\n+\t\tif (!opt->graph)\n+\t\t\tfputs(get_revision_mark(opt, commit), stdout);\n \t\tfputs(find_unique_abbrev(commit->object.sha1, abbrev_commit),\n \t\t      stdout);\n \t\tif (opt->print_parents)\ndiff --git a/pretty.c b/pretty.c\nindex 8549934..f21a30c 100644\n--- a/pretty.c\n+++ b/pretty.c\n@@ -859,11 +859,7 @@ static size_t format_commit_one(struct strbuf *sb, const char *placeholder,\n \t\t                              c->abbrev_parent_hashes.off;\n \t\treturn 1;\n \tcase 'm':\t\t/* left/right/bottom */\n-\t\tstrbuf_addch(sb, (commit->object.flags & BOUNDARY)\n-\t\t                 ? '-'\n-\t\t                 : (commit->object.flags & SYMMETRIC_LEFT)\n-\t\t                 ? '<'\n-\t\t                 : '>');\n+\t\tstrbuf_addstr(sb, get_revision_mark(NULL, commit));\n \t\treturn 1;\n \tcase 'd':\n \t\tformat_decoration(sb, commit);\ndiff --git a/revision.c b/revision.c\nindex 1fcaeb7..0de1608 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -2263,3 +2263,19 @@ struct commit *get_revision(struct rev_info *revs)\n \t\tgraph_update(revs->graph, c);\n \treturn c;\n }\n+\n+char *get_revision_mark(const struct rev_info *revs, const struct commit *commit)\n+{\n+\tif (commit->object.flags & BOUNDARY)\n+\t\treturn \"-\";\n+\telse if (commit->object.flags & UNINTERESTING)\n+\t\treturn \"^\";\n+\telse if (!revs || revs->left_right) {\n+\t\tif (commit->object.flags & SYMMETRIC_LEFT)\n+\t\t\treturn \"<\";\n+\t\telse\n+\t\t\treturn \">\";\n+\t} else if (revs->graph)\n+\t\treturn \"*\";\n+\treturn \"\";\n+}\ndiff --git a/revision.h b/revision.h\nindex d2ffde1..0e4b35e 100644\n--- a/revision.h\n+++ b/revision.h\n@@ -165,6 +165,7 @@ extern int handle_revision_arg(const char *arg, struct rev_info *revs,int flags,\n \n extern int prepare_revision_walk(struct rev_info *revs);\n extern struct commit *get_revision(struct rev_info *revs);\n+extern char *get_revision_mark(const struct rev_info *revs, const struct commit *commit);\n \n extern void mark_parents_uninteresting(struct commit *commit);\n extern void mark_tree_uninteresting(struct tree *tree);\n-- \n1.7.4.1.317.gf445f\n"},{"id":"163147","messageId":"c17a82478307a5a29455de09232087b17435c52a.1299767413.git.git@drmicha.warpmail.net","threadId":"26684","inReplyTo":"4D78AC8B.7010308@drmicha.warpmail.net","subject":"[PATCHv3 06/10] revision.c: introduce --cherry-mark","fromName":"Michael J Gruber","fromEmail":"git@drmicha.warpmail.net","sentAt":"2011-03-10T14:44:59Z","receivedAt":"2011-03-10T14:44:59Z","isPatch":false,"sender":{"key":"git@grubix.eu","avatar":"https://avatars.githubusercontent.com/u/233215?v=4"},"body":"Introduce --cherry-mark for marking those commits which \"--cherry-pick\"\nwould drop.  The marker for those commits is '=' because '-' denotes a\nboundary commit already, even though 'git cherry' uses it.\n\nNonequivalent commits are denoted '+' unless '--left-right' is used.\n\nSigned-off-by: Michael J Gruber <git@drmicha.warpmail.net>\n---\n revision.c |   19 +++++++++++++++++--\n revision.h |    4 +++-\n 2 files changed, 20 insertions(+), 3 deletions(-)\n\ndiff --git a/revision.c b/revision.c\nindex 0de1608..864bc9b 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -535,6 +535,7 @@ static void cherry_pick_list(struct commit_list *list, struct rev_info *revs)\n \tint left_count = 0, right_count = 0;\n \tint left_first;\n \tstruct patch_ids ids;\n+\tunsigned cherry_flag;\n \n \t/* First count the commits on the left and on the right */\n \tfor (p = list; p; p = p->next) {\n@@ -576,6 +577,8 @@ static void cherry_pick_list(struct commit_list *list, struct rev_info *revs)\n \t\tcommit->util = add_commit_patch_id(commit, &ids);\n \t}\n \n+\tcherry_flag = revs->cherry_mark ? PATCHSAME : SHOWN;\n+\n \t/* Check the other side */\n \tfor (p = list; p; p = p->next) {\n \t\tstruct commit *commit = p->item;\n@@ -598,7 +601,7 @@ static void cherry_pick_list(struct commit_list *list, struct rev_info *revs)\n \t\tif (!id)\n \t\t\tcontinue;\n \t\tid->seen = 1;\n-\t\tcommit->object.flags |= SHOWN;\n+\t\tcommit->object.flags |= cherry_flag;\n \t}\n \n \t/* Now check the original side for seen ones */\n@@ -610,7 +613,7 @@ static void cherry_pick_list(struct commit_list *list, struct rev_info *revs)\n \t\tif (!ent)\n \t\t\tcontinue;\n \t\tif (ent->seen)\n-\t\t\tcommit->object.flags |= SHOWN;\n+\t\t\tcommit->object.flags |= cherry_flag;\n \t\tcommit->util = NULL;\n \t}\n \n@@ -1293,7 +1296,15 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg\n \t\trevs->right_only = 1;\n \t} else if (!strcmp(arg, \"--count\")) {\n \t\trevs->count = 1;\n+\t} else if (!strcmp(arg, \"--cherry-mark\")) {\n+\t\tif (revs->cherry_pick && !revs->cherry-mark)\n+\t\t\tdie(\"--cherry-mark is incompatible with --cherry-pick\");\n+\t\trevs->cherry_mark = 1;\n+\t\trevs->cherry_pick = 1;\n+\t\trevs->limited = 1; /* needs limit_list() */\n \t} else if (!strcmp(arg, \"--cherry-pick\")) {\n+\t\tif (revs->cherry_mark)\n+\t\t\tdie(\"--cherry-pick is incompatible with --cherry-mark\");\n \t\trevs->cherry_pick = 1;\n \t\trevs->limited = 1;\n \t} else if (!strcmp(arg, \"--objects\")) {\n@@ -2270,6 +2281,8 @@ char *get_revision_mark(const struct rev_info *revs, const struct commit *commit\n \t\treturn \"-\";\n \telse if (commit->object.flags & UNINTERESTING)\n \t\treturn \"^\";\n+\telse if (commit->object.flags & PATCHSAME)\n+\t\treturn \"=\";\n \telse if (!revs || revs->left_right) {\n \t\tif (commit->object.flags & SYMMETRIC_LEFT)\n \t\t\treturn \"<\";\n@@ -2277,5 +2290,7 @@ char *get_revision_mark(const struct rev_info *revs, const struct commit *commit\n \t\t\treturn \">\";\n \t} else if (revs->graph)\n \t\treturn \"*\";\n+\telse if (revs->cherry_mark)\n+\t\treturn \"+\";\n \treturn \"\";\n }\ndiff --git a/revision.h b/revision.h\nindex 0e4b35e..d38f135 100644\n--- a/revision.h\n+++ b/revision.h\n@@ -14,7 +14,8 @@\n #define CHILD_SHOWN\t(1u<<6)\n #define ADDED\t\t(1u<<7)\t/* Parents already parsed and added? */\n #define SYMMETRIC_LEFT\t(1u<<8)\n-#define ALL_REV_FLAGS\t((1u<<9)-1)\n+#define PATCHSAME\t(1u<<9)\n+#define ALL_REV_FLAGS\t((1u<<10)-1)\n \n #define DECORATE_SHORT_REFS\t1\n #define DECORATE_FULL_REFS\t2\n@@ -68,6 +69,7 @@ struct rev_info {\n \t\t\treverse:1,\n \t\t\treverse_output_stage:1,\n \t\t\tcherry_pick:1,\n+\t\t\tcherry_mark:1,\n \t\t\tbisect:1,\n \t\t\tancestry_path:1,\n \t\t\tfirst_parent_only:1;\n-- \n1.7.4.1.317.gf445f\n"},{"id":"163146","messageId":"fd5b65227573cb8d5ff7c8087814f9b8f8e0851e.1299767413.git.git@drmicha.warpmail.net","threadId":"26684","inReplyTo":"4D78AC8B.7010308@drmicha.warpmail.net","subject":"[PATCHv3 07/10] rev-list: documentation and test for --cherry-mark","fromName":"Michael J Gruber","fromEmail":"git@drmicha.warpmail.net","sentAt":"2011-03-10T14:45:00Z","receivedAt":"2011-03-10T14:45:00Z","isPatch":false,"sender":{"key":"git@grubix.eu","avatar":"https://avatars.githubusercontent.com/u/233215?v=4"},"body":"Signed-off-by: Michael J Gruber <git@drmicha.warpmail.net>\n---\n Documentation/git-rev-list.txt       |    1 +\n Documentation/rev-list-options.txt   |    5 +++++\n t/t6007-rev-list-cherry-pick-file.sh |   28 ++++++++++++++++++++++++++++\n 3 files changed, 34 insertions(+), 0 deletions(-)\n\ndiff --git a/Documentation/git-rev-list.txt b/Documentation/git-rev-list.txt\nindex 5f47a13..8a891ca 100644\n--- a/Documentation/git-rev-list.txt\n+++ b/Documentation/git-rev-list.txt\n@@ -33,6 +33,7 @@ SYNOPSIS\n \t     [ \\--left-right ]\n \t     [ \\--left-only ]\n \t     [ \\--right-only ]\n+\t     [ \\--cherry-mark ]\n \t     [ \\--cherry-pick ]\n \t     [ \\--encoding[=<encoding>] ]\n \t     [ \\--(author|committer|grep)=<pattern> ]\ndiff --git a/Documentation/rev-list-options.txt b/Documentation/rev-list-options.txt\nindex cebba62..4755b83 100644\n--- a/Documentation/rev-list-options.txt\n+++ b/Documentation/rev-list-options.txt\n@@ -305,6 +305,11 @@ ifdef::git-rev-list[]\n \tto /dev/null as the output does not have to be formatted.\n endif::git-rev-list[]\n \n+--cherry-mark::\n+\n+\tLike `--cherry-pick` (see below) but mark equivalent commits\n+\twith `=` rather than omitting them, and inequivalent ones with `+`.\n+\n --cherry-pick::\n \n \tOmit any commit that introduces the same change as\ndiff --git a/t/t6007-rev-list-cherry-pick-file.sh b/t/t6007-rev-list-cherry-pick-file.sh\nindex cd089a9..37bd25e 100755\n--- a/t/t6007-rev-list-cherry-pick-file.sh\n+++ b/t/t6007-rev-list-cherry-pick-file.sh\n@@ -100,6 +100,34 @@ test_expect_success '--cherry-pick bar does not come up empty (II)' '\n '\n \n cat >expect <<EOF\n++tags/F\n+=tags/D\n++tags/E\n+=tags/C\n+EOF\n+\n+test_expect_success '--cherry-mark' '\n+\tgit rev-list --cherry-mark F...E -- bar > actual &&\n+\tgit name-rev --stdin --name-only --refs=\"*tags/*\" \\\n+\t\t< actual > actual.named &&\n+\ttest_cmp actual.named expect\n+'\n+\n+cat >expect <<EOF\n+<tags/F\n+=tags/D\n+>tags/E\n+=tags/C\n+EOF\n+\n+test_expect_success '--cherry-mark --left-right' '\n+\tgit rev-list --cherry-mark --left-right F...E -- bar > actual &&\n+\tgit name-rev --stdin --name-only --refs=\"*tags/*\" \\\n+\t\t< actual > actual.named &&\n+\ttest_cmp actual.named expect\n+'\n+\n+cat >expect <<EOF\n tags/E\n EOF\n \n-- \n1.7.4.1.317.gf445f\n"},{"id":"163144","messageId":"e5a72f0ddc0ddc9b6087c08143b188043f3bea1f.1299767413.git.git@drmicha.warpmail.net","threadId":"26684","inReplyTo":"4D78AC8B.7010308@drmicha.warpmail.net","subject":"[PATCHv3 08/10] log --cherry: a synonym","fromName":"Michael J Gruber","fromEmail":"git@drmicha.warpmail.net","sentAt":"2011-03-10T14:45:01Z","receivedAt":"2011-03-10T14:45:01Z","isPatch":false,"sender":{"key":"git@grubix.eu","avatar":"https://avatars.githubusercontent.com/u/233215?v=4"},"body":"At the Porcelain level, because by definition there are many more contributors\nthan integrators, it makes sense to give a handy short-hand for --right-only\nused with --cherry-mark and --no-merges.  Make it so.\n\nIn other words, this provides \"git cherry with rev-list interface\".\n\nSigned-off-by: Michael J Gruber <git@drmicha.warpmail.net>\n---\n Documentation/rev-list-options.txt |    8 ++++++++\n revision.c                         |   13 +++++++++++--\n 2 files changed, 19 insertions(+), 2 deletions(-)\n\ndiff --git a/Documentation/rev-list-options.txt b/Documentation/rev-list-options.txt\nindex 4755b83..95d209c 100644\n--- a/Documentation/rev-list-options.txt\n+++ b/Documentation/rev-list-options.txt\n@@ -337,6 +337,14 @@ commits from `B` which are in `A` or are patch-equivalent to a commit in\n More precisely, `--cherry-pick --right-only --no-merges` gives the exact\n list.\n \n+--cherry::\n+\n+\tA synonym for `--right-only --cherry-mark --no-merges`; useful to\n+\tlimit the output to the commits on our side and mark those that\n+\thave been applied to the other side of a forked history with\n+\t`git log --cherry upstream...mybranch`, similar to\n+\t`git cherry upstream mybranch`.\n+\n -g::\n --walk-reflogs::\n \ndiff --git a/revision.c b/revision.c\nindex 864bc9b..4881263 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -1288,16 +1288,25 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg\n \t\trevs->left_right = 1;\n \t} else if (!strcmp(arg, \"--left-only\")) {\n \t\tif (revs->right_only)\n-\t\t\tdie(\"--left-only is incompatible with --right-only\");\n+\t\t\tdie(\"--left-only is incompatible with --right-only\"\n+\t\t\t    \" or --cherry\");\n \t\trevs->left_only = 1;\n \t} else if (!strcmp(arg, \"--right-only\")) {\n \t\tif (revs->left_only)\n \t\t\tdie(\"--right-only is incompatible with --left-only\");\n \t\trevs->right_only = 1;\n+\t} else if (!strcmp(arg, \"--cherry\")) {\n+\t\tif (revs->left_only)\n+\t\t\tdie(\"--cherry is incompatible with --left-only\");\n+\t\trevs->cherry_mark = 1;\n+\t\trevs->cherry_pick = 1;\n+\t\trevs->right_only = 1;\n+\t\trevs->no_merges = 1;\n+\t\trevs->limited = 1;\n \t} else if (!strcmp(arg, \"--count\")) {\n \t\trevs->count = 1;\n \t} else if (!strcmp(arg, \"--cherry-mark\")) {\n-\t\tif (revs->cherry_pick && !revs->cherry-mark)\n+\t\tif (revs->cherry_pick && !revs->cherry_mark)\n \t\t\tdie(\"--cherry-mark is incompatible with --cherry-pick\");\n \t\trevs->cherry_mark = 1;\n \t\trevs->cherry_pick = 1;\n-- \n1.7.4.1.317.gf445f\n"},{"id":"163145","messageId":"ca14e3fb22b91653086fbd8c8600f2f93409a0a6.1299767413.git.git@drmicha.warpmail.net","threadId":"26684","inReplyTo":"4D78AC8B.7010308@drmicha.warpmail.net","subject":"[PATCHv3 09/10] t6007: test rev-list --cherry","fromName":"Michael J Gruber","fromEmail":"git@drmicha.warpmail.net","sentAt":"2011-03-10T14:45:02Z","receivedAt":"2011-03-10T14:45:02Z","isPatch":false,"sender":{"key":"git@grubix.eu","avatar":"https://avatars.githubusercontent.com/u/233215?v=4"},"body":"Signed-off-by: Michael J Gruber <git@drmicha.warpmail.net>\n---\n t/t6007-rev-list-cherry-pick-file.sh |   12 ++++++++++++\n 1 files changed, 12 insertions(+), 0 deletions(-)\n\ndiff --git a/t/t6007-rev-list-cherry-pick-file.sh b/t/t6007-rev-list-cherry-pick-file.sh\nindex 37bd25e..cacf3de 100755\n--- a/t/t6007-rev-list-cherry-pick-file.sh\n+++ b/t/t6007-rev-list-cherry-pick-file.sh\n@@ -145,6 +145,18 @@ test_expect_success '--cherry-pick --left-only' '\n \ttest_cmp actual.named expect\n '\n \n+cat >expect <<EOF\n++tags/E\n+=tags/C\n+EOF\n+\n+test_expect_success '--cherry' '\n+\tgit rev-list --cherry F...E -- bar > actual &&\n+\tgit name-rev --stdin --name-only --refs=\"*tags/*\" \\\n+\t\t< actual > actual.named &&\n+\ttest_cmp actual.named expect\n+'\n+\n test_expect_success '--cherry-pick with independent, but identical branches' '\n \tgit symbolic-ref HEAD refs/heads/independent &&\n \trm .git/index &&\n-- \n1.7.4.1.317.gf445f\n"},{"id":"163143","messageId":"dfe27d480258ab4af4fa50628a9bbaff33ba6860.1299767413.git.git@drmicha.warpmail.net","threadId":"26684","inReplyTo":"4D78AC8B.7010308@drmicha.warpmail.net","subject":"[PATCHv3 10/10] git-log: put space after commit mark","fromName":"Michael J Gruber","fromEmail":"git@drmicha.warpmail.net","sentAt":"2011-03-10T14:45:03Z","receivedAt":"2011-03-10T14:45:03Z","isPatch":false,"sender":{"key":"git@grubix.eu","avatar":"https://avatars.githubusercontent.com/u/233215?v=4"},"body":"Currently, commit marks (left, right, boundary, cherry) are output right\nbefore the commit sha1, which makes it difficult to copy sha1s. Sample\noutput for \"git log --oneline --cherry\":\n\n=049c269 t6007: test rev-list --cherry\n\nChange this to\n\n= 049c269 t6007: test rev-list --cherry\n\nwhich matches exactly the current output of \"git log --graph\".\n\nLeave \"git rev-list\" output as is (no space) so that they do not break.\n\nAdjust \"git-svn\" which uses \"git log --pretty=raw --boundary\".\n\nSigned-off-by: Michael J Gruber <git@drmicha.warpmail.net>\n---\n git-svn.perl |    2 +-\n log-tree.c   |    4 ++--\n revision.c   |    9 +++++++++\n revision.h   |    1 +\n 4 files changed, 13 insertions(+), 3 deletions(-)\n\ndiff --git a/git-svn.perl b/git-svn.perl\nindex 177dd25..a5857c1 100755\n--- a/git-svn.perl\n+++ b/git-svn.perl\n@@ -5734,7 +5734,7 @@ sub cmd_show_log {\n \tmy (@k, $c, $d, $stat);\n \tmy $esc_color = qr/(?:\\033\\[(?:(?:\\d+;)*\\d*)?m)*/;\n \twhile (<$log>) {\n-\t\tif (/^${esc_color}commit -?($::sha1_short)/o) {\n+\t\tif (/^${esc_color}commit (- )?($::sha1_short)/o) {\n \t\t\tmy $cmt = $1;\n \t\t\tif ($c && cmt_showable($c) && $c->{r} != $r_last) {\n \t\t\t\t$r_last = $c->{r};\ndiff --git a/log-tree.c b/log-tree.c\nindex 1257040..2a1e3a9 100644\n--- a/log-tree.c\n+++ b/log-tree.c\n@@ -381,7 +381,7 @@ void show_log(struct rev_info *opt)\n \t\tgraph_show_commit(opt->graph);\n \n \t\tif (!opt->graph)\n-\t\t\tfputs(get_revision_mark(opt, commit), stdout);\n+\t\t\tput_revision_mark(opt, commit);\n \t\tfputs(find_unique_abbrev(commit->object.sha1, abbrev_commit), stdout);\n \t\tif (opt->print_parents)\n \t\t\tshow_parents(commit, abbrev_commit);\n@@ -439,7 +439,7 @@ void show_log(struct rev_info *opt)\n \t\t\tfputs(\"commit \", stdout);\n \n \t\tif (!opt->graph)\n-\t\t\tfputs(get_revision_mark(opt, commit), stdout);\n+\t\t\tput_revision_mark(opt, commit);\n \t\tfputs(find_unique_abbrev(commit->object.sha1, abbrev_commit),\n \t\t      stdout);\n \t\tif (opt->print_parents)\ndiff --git a/revision.c b/revision.c\nindex 4881263..725f9b7 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -2303,3 +2303,12 @@ char *get_revision_mark(const struct rev_info *revs, const struct commit *commit\n \t\treturn \"+\";\n \treturn \"\";\n }\n+\n+void put_revision_mark(const struct rev_info *revs, const struct commit *commit)\n+{\n+\tchar *mark = get_revision_mark(revs, commit);\n+\tif (!strlen(mark))\n+\t\treturn;\n+\tfputs(mark, stdout);\n+\tputchar(' ');\n+}\ndiff --git a/revision.h b/revision.h\nindex d38f135..1c0abf0 100644\n--- a/revision.h\n+++ b/revision.h\n@@ -168,6 +168,7 @@ extern int handle_revision_arg(const char *arg, struct rev_info *revs,int flags,\n extern int prepare_revision_walk(struct rev_info *revs);\n extern struct commit *get_revision(struct rev_info *revs);\n extern char *get_revision_mark(const struct rev_info *revs, const struct commit *commit);\n+extern void put_revision_mark(const struct rev_info *revs, const struct commit *commit);\n \n extern void mark_parents_uninteresting(struct commit *commit);\n extern void mark_tree_uninteresting(struct tree *tree);\n-- \n1.7.4.1.317.gf445f\n"},{"id":"163163","messageId":"7v4o7a6dj3.fsf@alter.siamese.dyndns.org","threadId":"26684","inReplyTo":"4D78AC8B.7010308@drmicha.warpmail.net","subject":"Re: [PATCHv2 0/9] --left/right-only and --cherry-mark","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2011-03-10T18:22:56Z","receivedAt":"2011-03-10T18:22:56Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Michael J Gruber <git@drmicha.warpmail.net> writes:\n\n> ...\n> Additionally, since parse_revision_opt (which calls handle_revision_opt)\n> is called from other sites for individual args we would need to do the\n> handling in the Y case (set pick when marking) right in\n> handle_revision_opt, not just in setup_revisions. It's a matter of a few\n> more if's and or's, but still.\n>\n> Taking these together, I wonder whether we shouldn't leave it as in v2.\n\nThe primary downside of keeping cherry_pick and cherry_mark as independent\nI see is what would happen to the \"if (cherry_pick || cherry_mark)\" when\nsomebody comes up with the next bright idea to use the change equivalence\ncomputed in cherry_pick_list(). With the approach in v2, the natural way\nof enhancing this would be to add another \"|| cherry_xyzzy\" there, and the\nnext bright idea would add another \"|| cherry_frotz\".\n\nMy gut feeling was that it would be a more maintainable implementation to\nhave an internal bit that does not have to be exposed to the UI and that\ntells the revision machinery that we need to compute the equivalence, and\nan enum (if the three modes of using the equivalence are incompatible with\neach other) or a one-bit-per-feature bitset (if the three features that\nuse the equivalence can be used at the same time) that tells the machinery\nwhat to do with the equivalence information. From the UI level, the user\nonly asks for the feature(s) that use(s) the equivalence information, and\nasking for any of them would set the internal \"need equivalence\" bit.\n\nThe above is modeled after the way how revs.limited bit is used. That bit\ncorresponds to the \"internal bit\" that is flipped by many features that\ncan be triggered from the UI level that depends on having the history\ngraph before they do their work.\n\nCounting the number of \"if (limited)\" and tricky codepaths around it, and\ncontrasting that with the number of ways we flip the \"limited = 1\" bit\n(which grew over time), I think you can understand where my fear of\npotential future complexity against \"if (cherry_pick || cherry_mark)\"\ncomes from.\n\nAs I said earlier, this was only a minor thing that nagged me. Considering\nthat currently there is only one place that checks if we are doing any of\nthe operation that requires us to have change equivalence information to\nchange the behaviour depending on the result, I wouldn't be too unhappy if\nthis feature is done in the way you did in your v2 patch.\n\nThanks.\n"},{"id":"163208","messageId":"4D79D4CC.7020806@drmicha.warpmail.net","threadId":"26684","inReplyTo":"7v4o7a6dj3.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCHv2 0/9] --left/right-only and --cherry-mark","fromName":"Michael J Gruber","fromEmail":"git@drmicha.warpmail.net","sentAt":"2011-03-11T07:52:44Z","receivedAt":"2011-03-11T07:52:44Z","isPatch":false,"sender":{"key":"git@grubix.eu","avatar":"https://avatars.githubusercontent.com/u/233215?v=4"},"body":"Junio C Hamano venit, vidit, dixit 10.03.2011 19:22:\n> Michael J Gruber <git@drmicha.warpmail.net> writes:\n> \n>> ...\n>> Additionally, since parse_revision_opt (which calls handle_revision_opt)\n>> is called from other sites for individual args we would need to do the\n>> handling in the Y case (set pick when marking) right in\n>> handle_revision_opt, not just in setup_revisions. It's a matter of a few\n>> more if's and or's, but still.\n>>\n>> Taking these together, I wonder whether we shouldn't leave it as in v2.\n> \n> The primary downside of keeping cherry_pick and cherry_mark as independent\n> I see is what would happen to the \"if (cherry_pick || cherry_mark)\" when\n> somebody comes up with the next bright idea to use the change equivalence\n> computed in cherry_pick_list(). With the approach in v2, the natural way\n> of enhancing this would be to add another \"|| cherry_xyzzy\" there, and the\n> next bright idea would add another \"|| cherry_frotz\".\n> \n> My gut feeling was that it would be a more maintainable implementation to\n> have an internal bit that does not have to be exposed to the UI and that\n> tells the revision machinery that we need to compute the equivalence, and\n> an enum (if the three modes of using the equivalence are incompatible with\n> each other) or a one-bit-per-feature bitset (if the three features that\n> use the equivalence can be used at the same time) that tells the machinery\n> what to do with the equivalence information. From the UI level, the user\n> only asks for the feature(s) that use(s) the equivalence information, and\n> asking for any of them would set the internal \"need equivalence\" bit.\n> \n> The above is modeled after the way how revs.limited bit is used. That bit\n> corresponds to the \"internal bit\" that is flipped by many features that\n> can be triggered from the UI level that depends on having the history\n> graph before they do their work.\n> \n> Counting the number of \"if (limited)\" and tricky codepaths around it, and\n> contrasting that with the number of ways we flip the \"limited = 1\" bit\n> (which grew over time), I think you can understand where my fear of\n> potential future complexity against \"if (cherry_pick || cherry_mark)\"\n> comes from.\n\nI see, thanks for the background!\n\nOther callers of the revision walker have to remember that they need to\nset revs->limited already when they want to use any limitting flags, so\nrevs->cherry_pick as in v3 would be no different.(*)\n\nSo maybe we should have another flag revs->cherry_process which is set\nautomatically when needed, after processing all options (same with\nlimited), and leave cherry_pick to keep track of --cherry-pick?\n\n(*) Well, in fact they don't as long as they use the api correctly.\nblame and shortlog call parse_revision_opt but use setup_revisions and\nprepare_revision_walk afterwards.\npack-objects calls handle_revision_arg after setup_revisions but\nprepare_revision_walk after. I was afraid of callers setting\nrevs->something inconsistently and then jumping into the walker.\n\nSo, maybe prepare_revision_walk is the most sensible place to set\nrevs->limited and revs->cherry_process when needed as indicated by other\nflags (or set already), and take out their handling from the option parser?\n\nMichael\n"},{"id":"163209","messageId":"7v1v2e13w8.fsf@alter.siamese.dyndns.org","threadId":"26684","inReplyTo":"4D79D4CC.7020806@drmicha.warpmail.net","subject":"Re: [PATCHv2 0/9] --left/right-only and --cherry-mark","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2011-03-11T08:02:15Z","receivedAt":"2011-03-11T08:02:15Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Michael J Gruber <git@drmicha.warpmail.net> writes:\n\n> I see, thanks for the background!\n> ...\n> So maybe we should have another flag revs->cherry_process which is set\n> automatically when needed, after processing all options (same with\n> limited), and leave cherry_pick to keep track of --cherry-pick?\n\nI actually read the two series again and decided that we can worry about\nit when somebody actually wants to add the third one. The \"cherry_process\"\nflag modeled after \"limited\" would be the right approach when we do so.\n\nSo I've kept your v2 as-is (the one you saw in 'pu' last night) and added\nthe 10th patch from v3.\n\nThanks.\n"}]}