Merge branch 'mg/rev-list-one-side-only'
authorJunio C Hamano <gitster@pobox.com>
Wed, 23 Mar 2011 04:38:50 +0000 (21:38 -0700)
committerJunio C Hamano <gitster@pobox.com>
Wed, 23 Mar 2011 04:38:50 +0000 (21:38 -0700)
* mg/rev-list-one-side-only:
git-log: put space after commit mark
t6007: test rev-list --cherry
log --cherry: a synonym
rev-list: documentation and test for --cherry-mark
revision.c: introduce --cherry-mark
rev-list/log: factor out revision mark generation
rev-list: --left/right-only are mutually exclusive
rev-list: documentation and test for --left/right-only
t6007: Make sure we test --cherry-pick
revlist.c: introduce --left/right-only for unsymmetric picking

1  2 
Documentation/git-rev-list.txt
Documentation/rev-list-options.txt
pretty.c
revision.c
revision.h
index 5ce4d7fd0b2fbab894e67fa266afae2d13c78284,8a891ca68dc9ab3e0d547256166d41db81bf22f5..b08dfbc3c455a19b3257e7e921c2a1a7436ddf3e
@@@ -31,6 -31,9 +31,9 @@@ SYNOPSI
             [ \--parents ]
             [ \--timestamp ]
             [ \--left-right ]
+            [ \--left-only ]
+            [ \--right-only ]
+            [ \--cherry-mark ]
             [ \--cherry-pick ]
             [ \--encoding[=<encoding>] ]
             [ \--(author|committer|grep)=<pattern> ]
@@@ -105,6 -108,16 +108,6 @@@ include::rev-list-options.txt[
  
  include::pretty-formats.txt[]
  
 -
 -Author
 -------
 -Written by Linus Torvalds <torvalds@osdl.org>
 -
 -Documentation
 ---------------
 -Documentation by David Greaves, Junio C Hamano, Jonas Fonseca
 -and the git-list <git@vger.kernel.org>.
 -
  GIT
  ---
  Part of the linkgit:git[1] suite
index 09860de9c2ff18115806c3cdf50ebd6163b3560e,95d209c11da4ab829d0617894cad637f96da3f24..5c6850f0486dbea0c515e2323bc6455d89897628
 -Commit Formatting
 -~~~~~~~~~~~~~~~~~
 -
 -ifdef::git-rev-list[]
 -Using these options, linkgit:git-rev-list[1] will act similar to the
 -more specialized family of commit log tools: linkgit:git-log[1],
 -linkgit:git-show[1], and linkgit:git-whatchanged[1]
 -endif::git-rev-list[]
 -
 -include::pretty-options.txt[]
 -
 ---relative-date::
 -
 -      Synonym for `--date=relative`.
 -
 ---date=(relative|local|default|iso|rfc|short|raw)::
 -
 -      Only takes effect for dates shown in human-readable format, such
 -      as when using "--pretty". `log.date` config variable sets a default
 -      value for log command's --date option.
 -+
 -`--date=relative` shows dates relative to the current time,
 -e.g. "2 hours ago".
 -+
 -`--date=local` shows timestamps in user's local timezone.
 -+
 -`--date=iso` (or `--date=iso8601`) shows timestamps in ISO 8601 format.
 -+
 -`--date=rfc` (or `--date=rfc2822`) shows timestamps in RFC 2822
 -format, often found in E-mail messages.
 -+
 -`--date=short` shows only date but not time, in `YYYY-MM-DD` format.
 -+
 -`--date=raw` shows the date in the internal raw git format `%s %z` format.
 -+
 -`--date=default` shows timestamps in the original timezone
 -(either committer's or author's).
 -
 -ifdef::git-rev-list[]
 ---header::
 -
 -      Print the contents of the commit in raw-format; each record is
 -      separated with a NUL character.
 -endif::git-rev-list[]
 -
 ---parents::
 -
 -      Print also the parents of the commit (in the form "commit parent...").
 -      Also enables parent rewriting, see 'History Simplification' below.
 -
 ---children::
 -
 -      Print also the children of the commit (in the form "commit child...").
 -      Also enables parent rewriting, see 'History Simplification' below.
 -
 -ifdef::git-rev-list[]
 ---timestamp::
 -      Print the raw commit timestamp.
 -endif::git-rev-list[]
 -
 ---left-right::
 -
 -      Mark which side of a symmetric diff a commit is reachable from.
 -      Commits from the left side are prefixed with `<` and those from
 -      the right with `>`.  If combined with `--boundary`, those
 -      commits are prefixed with `-`.
 -+
 -For example, if you have this topology:
 -+
 ------------------------------------------------------------------------
 -             y---b---b  branch B
 -            / \ /
 -           /   .
 -          /   / \
 -         o---x---a---a  branch A
 ------------------------------------------------------------------------
 -+
 -you would get an output like this:
 -+
 ------------------------------------------------------------------------
 -      $ git rev-list --left-right --boundary --pretty=oneline A...B
 -
 -      >bbbbbbb... 3rd on b
 -      >bbbbbbb... 2nd on b
 -      <aaaaaaa... 3rd on a
 -      <aaaaaaa... 2nd on a
 -      -yyyyyyy... 1st on b
 -      -xxxxxxx... 1st on a
 ------------------------------------------------------------------------
 -
 ---graph::
 -
 -      Draw a text-based graphical representation of the commit history
 -      on the left hand side of the output.  This may cause extra lines
 -      to be printed in between commits, in order for the graph history
 -      to be drawn properly.
 -+
 -This enables parent rewriting, see 'History Simplification' below.
 -+
 -This implies the '--topo-order' option by default, but the
 -'--date-order' option may also be specified.
 -
 -ifdef::git-rev-list[]
 ---count::
 -      Print a number stating how many commits would have been
 -      listed, and suppress all other output.  When used together
 -      with '--left-right', instead print the counts for left and
 -      right commits, separated by a tab.
 -endif::git-rev-list[]
 -
 -
 -ifndef::git-rev-list[]
 -Diff Formatting
 -~~~~~~~~~~~~~~~
 -
 -Below are listed options that control the formatting of diff output.
 -Some of them are specific to linkgit:git-rev-list[1], however other diff
 -options may be given. See linkgit:git-diff-files[1] for more options.
 -
 --c::
 -
 -      With this option, diff output for a merge commit
 -      shows the differences from each of the parents to the merge result
 -      simultaneously instead of showing pairwise diff between a parent
 -      and the result one at a time. Furthermore, it lists only files
 -      which were modified from all parents.
 -
 ---cc::
 -
 -      This flag implies the '-c' options and further compresses the
 -      patch output by omitting uninteresting hunks whose contents in
 -      the parents have only two variants and the merge result picks
 -      one of them without modification.
 -
 --m::
 -
 -      This flag makes the merge commits show the full diff like
 -      regular commits; for each merge parent, a separate log entry
 -      and diff is generated. An exception is that only diff against
 -      the first parent is shown when '--first-parent' option is given;
 -      in that case, the output represents the changes the merge
 -      brought _into_ the then-current branch.
 -
 --r::
 -
 -      Show recursive diffs.
 -
 --t::
 -
 -      Show the tree objects in the diff output. This implies '-r'.
 -
 --s::
 -      Suppress diff output.
 -endif::git-rev-list[]
 -
  Commit Limiting
  ~~~~~~~~~~~~~~~
  
  Besides specifying a range of commits that should be listed using the
  special notations explained in the description, additional commit
 -limiting may be applied.
 +limiting may be applied. Note that they are applied before commit
 +ordering and formatting options, such as '--reverse'.
  
  --
  
  -n 'number'::
  --max-count=<number>::
  
 -      Limit the number of commits output.
 +      Limit the number of commits to output.
  
  --skip=<number>::
  
@@@ -151,6 -305,11 +151,11 @@@ ifdef::git-rev-list[
        to /dev/null as the output does not have to be formatted.
  endif::git-rev-list[]
  
+ --cherry-mark::
+       Like `--cherry-pick` (see below) but mark equivalent commits
+       with `=` rather than omitting them, and inequivalent ones with `+`.
  --cherry-pick::
  
        Omit any commit that introduces the same change as
@@@ -165,6 -324,27 +170,27 @@@ from the other branch (for example, "3r
  from branch A).  With this option, such pairs of commits are
  excluded from the output.
  
+ --left-only::
+ --right-only::
+       List only commits on the respective side of a symmetric range,
+       i.e. only those which would be marked `<` resp. `>` by
+       `--left-right`.
+ +
+ For example, `--cherry-pick --right-only A...B` omits those
+ commits from `B` which are in `A` or are patch-equivalent to a commit in
+ `A`. In other words, this lists the `{plus}` commits from `git cherry A B`.
+ More precisely, `--cherry-pick --right-only --no-merges` gives the exact
+ list.
+ --cherry::
+       A synonym for `--right-only --cherry-mark --no-merges`; useful to
+       limit the output to the commits on our side and mark those that
+       have been applied to the other side of a forked history with
+       `git log --cherry upstream...mybranch`, similar to
+       `git cherry upstream mybranch`.
  -g::
  --walk-reflogs::
  
@@@ -581,158 -761,3 +607,158 @@@ These options are mostly targeted for p
  --do-walk::
  
        Overrides a previous --no-walk.
 +
 +Commit Formatting
 +~~~~~~~~~~~~~~~~~
 +
 +ifdef::git-rev-list[]
 +Using these options, linkgit:git-rev-list[1] will act similar to the
 +more specialized family of commit log tools: linkgit:git-log[1],
 +linkgit:git-show[1], and linkgit:git-whatchanged[1]
 +endif::git-rev-list[]
 +
 +include::pretty-options.txt[]
 +
 +--relative-date::
 +
 +      Synonym for `--date=relative`.
 +
 +--date=(relative|local|default|iso|rfc|short|raw)::
 +
 +      Only takes effect for dates shown in human-readable format, such
 +      as when using "--pretty". `log.date` config variable sets a default
 +      value for log command's --date option.
 ++
 +`--date=relative` shows dates relative to the current time,
 +e.g. "2 hours ago".
 ++
 +`--date=local` shows timestamps in user's local timezone.
 ++
 +`--date=iso` (or `--date=iso8601`) shows timestamps in ISO 8601 format.
 ++
 +`--date=rfc` (or `--date=rfc2822`) shows timestamps in RFC 2822
 +format, often found in E-mail messages.
 ++
 +`--date=short` shows only date but not time, in `YYYY-MM-DD` format.
 ++
 +`--date=raw` shows the date in the internal raw git format `%s %z` format.
 ++
 +`--date=default` shows timestamps in the original timezone
 +(either committer's or author's).
 +
 +ifdef::git-rev-list[]
 +--header::
 +
 +      Print the contents of the commit in raw-format; each record is
 +      separated with a NUL character.
 +endif::git-rev-list[]
 +
 +--parents::
 +
 +      Print also the parents of the commit (in the form "commit parent...").
 +      Also enables parent rewriting, see 'History Simplification' below.
 +
 +--children::
 +
 +      Print also the children of the commit (in the form "commit child...").
 +      Also enables parent rewriting, see 'History Simplification' below.
 +
 +ifdef::git-rev-list[]
 +--timestamp::
 +      Print the raw commit timestamp.
 +endif::git-rev-list[]
 +
 +--left-right::
 +
 +      Mark which side of a symmetric diff a commit is reachable from.
 +      Commits from the left side are prefixed with `<` and those from
 +      the right with `>`.  If combined with `--boundary`, those
 +      commits are prefixed with `-`.
 ++
 +For example, if you have this topology:
 ++
 +-----------------------------------------------------------------------
 +           y---b---b  branch B
 +          / \ /
 +         /   .
 +        /   / \
 +       o---x---a---a  branch A
 +-----------------------------------------------------------------------
 ++
 +you would get an output like this:
 ++
 +-----------------------------------------------------------------------
 +      $ git rev-list --left-right --boundary --pretty=oneline A...B
 +
 +      >bbbbbbb... 3rd on b
 +      >bbbbbbb... 2nd on b
 +      <aaaaaaa... 3rd on a
 +      <aaaaaaa... 2nd on a
 +      -yyyyyyy... 1st on b
 +      -xxxxxxx... 1st on a
 +-----------------------------------------------------------------------
 +
 +--graph::
 +
 +      Draw a text-based graphical representation of the commit history
 +      on the left hand side of the output.  This may cause extra lines
 +      to be printed in between commits, in order for the graph history
 +      to be drawn properly.
 ++
 +This enables parent rewriting, see 'History Simplification' below.
 ++
 +This implies the '--topo-order' option by default, but the
 +'--date-order' option may also be specified.
 +
 +ifdef::git-rev-list[]
 +--count::
 +      Print a number stating how many commits would have been
 +      listed, and suppress all other output.  When used together
 +      with '--left-right', instead print the counts for left and
 +      right commits, separated by a tab.
 +endif::git-rev-list[]
 +
 +
 +ifndef::git-rev-list[]
 +Diff Formatting
 +~~~~~~~~~~~~~~~
 +
 +Below are listed options that control the formatting of diff output.
 +Some of them are specific to linkgit:git-rev-list[1], however other diff
 +options may be given. See linkgit:git-diff-files[1] for more options.
 +
 +-c::
 +
 +      With this option, diff output for a merge commit
 +      shows the differences from each of the parents to the merge result
 +      simultaneously instead of showing pairwise diff between a parent
 +      and the result one at a time. Furthermore, it lists only files
 +      which were modified from all parents.
 +
 +--cc::
 +
 +      This flag implies the '-c' options and further compresses the
 +      patch output by omitting uninteresting hunks whose contents in
 +      the parents have only two variants and the merge result picks
 +      one of them without modification.
 +
 +-m::
 +
 +      This flag makes the merge commits show the full diff like
 +      regular commits; for each merge parent, a separate log entry
 +      and diff is generated. An exception is that only diff against
 +      the first parent is shown when '--first-parent' option is given;
 +      in that case, the output represents the changes the merge
 +      brought _into_ the then-current branch.
 +
 +-r::
 +
 +      Show recursive diffs.
 +
 +-t::
 +
 +      Show the tree objects in the diff output. This implies '-r'.
 +
 +-s::
 +      Suppress diff output.
 +endif::git-rev-list[]
diff --combined pretty.c
index 65d20a7a2e7cafd79ff95c02cab3303ebb72351c,f21a30ccca66e31130edf85a935f350a8b73a4ad..e1d8a8f414bf052a59fbe78d022e611f44ed8361
+++ b/pretty.c
@@@ -216,53 -216,36 +216,53 @@@ static int is_rfc2047_special(char ch
  static void add_rfc2047(struct strbuf *sb, const char *line, int len,
                       const char *encoding)
  {
 -      int i, last;
 +      static const int max_length = 78; /* per rfc2822 */
 +      int i;
 +      int line_len;
 +
 +      /* How many bytes are already used on the current line? */
 +      for (i = sb->len - 1; i >= 0; i--)
 +              if (sb->buf[i] == '\n')
 +                      break;
 +      line_len = sb->len - (i+1);
  
        for (i = 0; i < len; i++) {
                int ch = line[i];
 -              if (non_ascii(ch))
 +              if (non_ascii(ch) || ch == '\n')
                        goto needquote;
                if ((i + 1 < len) && (ch == '=' && line[i+1] == '?'))
                        goto needquote;
        }
 -      strbuf_add(sb, line, len);
 +      strbuf_add_wrapped_bytes(sb, line, len, 0, 1, max_length - line_len);
        return;
  
  needquote:
        strbuf_grow(sb, len * 3 + strlen(encoding) + 100);
        strbuf_addf(sb, "=?%s?q?", encoding);
 -      for (i = last = 0; i < len; i++) {
 +      line_len += strlen(encoding) + 5; /* 5 for =??q? */
 +      for (i = 0; i < len; i++) {
                unsigned ch = line[i] & 0xFF;
 +
 +              if (line_len >= max_length - 2) {
 +                      strbuf_addf(sb, "?=\n =?%s?q?", encoding);
 +                      line_len = strlen(encoding) + 5 + 1; /* =??q? plus SP */
 +              }
 +
                /*
                 * We encode ' ' using '=20' even though rfc2047
                 * allows using '_' for readability.  Unfortunately,
                 * many programs do not understand this and just
                 * leave the underscore in place.
                 */
 -              if (is_rfc2047_special(ch) || ch == ' ') {
 -                      strbuf_add(sb, line + last, i - last);
 +              if (is_rfc2047_special(ch) || ch == ' ' || ch == '\n') {
                        strbuf_addf(sb, "=%02X", ch);
 -                      last = i + 1;
 +                      line_len += 3;
 +              }
 +              else {
 +                      strbuf_addch(sb, ch);
 +                      line_len++;
                }
        }
 -      strbuf_add(sb, line + last, len - last);
        strbuf_addstr(sb, "?=");
  }
  
@@@ -876,11 -859,7 +876,7 @@@ static size_t format_commit_one(struct 
                                              c->abbrev_parent_hashes.off;
                return 1;
        case 'm':               /* left/right/bottom */
-               strbuf_addch(sb, (commit->object.flags & BOUNDARY)
-                                ? '-'
-                                : (commit->object.flags & SYMMETRIC_LEFT)
-                                ? '<'
-                                : '>');
+               strbuf_addstr(sb, get_revision_mark(NULL, commit));
                return 1;
        case 'd':
                format_decoration(sb, commit);
@@@ -1123,10 -1102,11 +1119,10 @@@ void pp_title_line(enum cmit_fmt fmt
                   const char *encoding,
                   int need_8bit_cte)
  {
 -      const char *line_separator = (fmt == CMIT_FMT_EMAIL) ? "\n " : " ";
        struct strbuf title;
  
        strbuf_init(&title, 80);
 -      *msg_p = format_subject(&title, *msg_p, line_separator);
 +      *msg_p = format_subject(&title, *msg_p, " ");
  
        strbuf_grow(sb, title.len + 1024);
        if (subject) {
diff --combined revision.c
index 86d24704896d71de7bb554a3925ea88e2be3417b,626f6a23d140d5b0094ac694b92c429bc5a596e3..e96c281d1f04f37e519e9447e18e43b86cb2363a
@@@ -323,7 -323,7 +323,7 @@@ static int rev_compare_tree(struct rev_
                 * tagged commit by specifying both --simplify-by-decoration
                 * and pathspec.
                 */
 -              if (!revs->prune_data)
 +              if (!revs->prune_data.nr)
                        return REV_TREE_SAME;
        }
  
@@@ -535,6 -535,7 +535,7 @@@ static void cherry_pick_list(struct com
        int left_count = 0, right_count = 0;
        int left_first;
        struct patch_ids ids;
+       unsigned cherry_flag;
  
        /* First count the commits on the left and on the right */
        for (p = list; p; p = p->next) {
  
        left_first = left_count < right_count;
        init_patch_ids(&ids);
 -      if (revs->diffopt.nr_paths) {
 -              ids.diffopts.nr_paths = revs->diffopt.nr_paths;
 -              ids.diffopts.paths = revs->diffopt.paths;
 -              ids.diffopts.pathlens = revs->diffopt.pathlens;
 -      }
 +      ids.diffopts.pathspec = revs->diffopt.pathspec;
  
        /* Compute patch-ids for one side */
        for (p = list; p; p = p->next) {
                commit->util = add_commit_patch_id(commit, &ids);
        }
  
+       /* either cherry_mark or cherry_pick are true */
+       cherry_flag = revs->cherry_mark ? PATCHSAME : SHOWN;
        /* Check the other side */
        for (p = list; p; p = p->next) {
                struct commit *commit = p->item;
                if (!id)
                        continue;
                id->seen = 1;
-               commit->object.flags |= SHOWN;
+               commit->object.flags |= cherry_flag;
        }
  
        /* Now check the original side for seen ones */
                if (!ent)
                        continue;
                if (ent->seen)
-                       commit->object.flags |= SHOWN;
+                       commit->object.flags |= cherry_flag;
                commit->util = NULL;
        }
  
@@@ -729,6 -737,23 +733,23 @@@ static struct commit_list *collect_bott
        return bottom;
  }
  
+ /* Assumes either left_only or right_only is set */
+ static void limit_left_right(struct commit_list *list, struct rev_info *revs)
+ {
+       struct commit_list *p;
+       for (p = list; p; p = p->next) {
+               struct commit *commit = p->item;
+               if (revs->right_only) {
+                       if (commit->object.flags & SYMMETRIC_LEFT)
+                               commit->object.flags |= SHOWN;
+               } else  /* revs->left_only is set */
+                       if (!(commit->object.flags & SYMMETRIC_LEFT))
+                               commit->object.flags |= SHOWN;
+       }
+ }
  static int limit_list(struct rev_info *revs)
  {
        int slop = SLOP;
                show(revs, newlist);
                show_early_output = NULL;
        }
-       if (revs->cherry_pick)
+       if (revs->cherry_pick || revs->cherry_mark)
                cherry_pick_list(newlist, revs);
  
+       if (revs->left_only || revs->right_only)
+               limit_left_right(newlist, revs);
        if (bottom) {
                limit_to_ancestry(bottom, newlist);
                free_commit_list(bottom);
@@@ -969,7 -997,7 +993,7 @@@ static void prepare_show_merge(struct r
                struct cache_entry *ce = active_cache[i];
                if (!ce_stage(ce))
                        continue;
 -              if (ce_path_match(ce, revs->prune_data)) {
 +              if (ce_path_match(ce, &revs->prune_data)) {
                        prune_num++;
                        prune = xrealloc(prune, sizeof(*prune) * prune_num);
                        prune[prune_num-2] = ce->name;
                       ce_same_name(ce, active_cache[i+1]))
                        i++;
        }
 -      revs->prune_data = prune;
 +      free_pathspec(&revs->prune_data);
 +      init_pathspec(&revs->prune_data, prune);
        revs->limited = 1;
  }
  
@@@ -1260,9 -1287,32 +1284,32 @@@ static int handle_revision_opt(struct r
                revs->boundary = 1;
        } else if (!strcmp(arg, "--left-right")) {
                revs->left_right = 1;
+       } else if (!strcmp(arg, "--left-only")) {
+               if (revs->right_only)
+                       die("--left-only is incompatible with --right-only"
+                           " or --cherry");
+               revs->left_only = 1;
+       } else if (!strcmp(arg, "--right-only")) {
+               if (revs->left_only)
+                       die("--right-only is incompatible with --left-only");
+               revs->right_only = 1;
+       } else if (!strcmp(arg, "--cherry")) {
+               if (revs->left_only)
+                       die("--cherry is incompatible with --left-only");
+               revs->cherry_mark = 1;
+               revs->right_only = 1;
+               revs->no_merges = 1;
+               revs->limited = 1;
        } else if (!strcmp(arg, "--count")) {
                revs->count = 1;
+       } else if (!strcmp(arg, "--cherry-mark")) {
+               if (revs->cherry_pick)
+                       die("--cherry-mark is incompatible with --cherry-pick");
+               revs->cherry_mark = 1;
+               revs->limited = 1; /* needs limit_list() */
        } else if (!strcmp(arg, "--cherry-pick")) {
+               if (revs->cherry_mark)
+                       die("--cherry-pick is incompatible with --cherry-mark");
                revs->cherry_pick = 1;
                revs->limited = 1;
        } else if (!strcmp(arg, "--objects")) {
@@@ -1617,7 -1667,7 +1664,7 @@@ int setup_revisions(int argc, const cha
        }
  
        if (prune_data)
 -              revs->prune_data = get_pathspec(revs->prefix, prune_data);
 +              init_pathspec(&revs->prune_data, get_pathspec(revs->prefix, prune_data));
  
        if (revs->def == NULL)
                revs->def = opt ? opt->def : NULL;
        if (revs->topo_order)
                revs->limited = 1;
  
 -      if (revs->prune_data) {
 -              diff_tree_setup_paths(revs->prune_data, &revs->pruning);
 +      if (revs->prune_data.nr) {
 +              diff_tree_setup_paths(revs->prune_data.raw, &revs->pruning);
                /* Can't prune commits with rename following: the paths change.. */
                if (!DIFF_OPT_TST(&revs->diffopt, FOLLOW_RENAMES))
                        revs->prune = 1;
                if (!revs->full_diff)
 -                      diff_tree_setup_paths(revs->prune_data, &revs->diffopt);
 +                      diff_tree_setup_paths(revs->prune_data.raw, &revs->diffopt);
        }
        if (revs->combine_merges)
                revs->ignore_merges = 0;
@@@ -2232,3 -2282,32 +2279,32 @@@ struct commit *get_revision(struct rev_
                graph_update(revs->graph, c);
        return c;
  }
+ char *get_revision_mark(const struct rev_info *revs, const struct commit *commit)
+ {
+       if (commit->object.flags & BOUNDARY)
+               return "-";
+       else if (commit->object.flags & UNINTERESTING)
+               return "^";
+       else if (commit->object.flags & PATCHSAME)
+               return "=";
+       else if (!revs || revs->left_right) {
+               if (commit->object.flags & SYMMETRIC_LEFT)
+                       return "<";
+               else
+                       return ">";
+       } else if (revs->graph)
+               return "*";
+       else if (revs->cherry_mark)
+               return "+";
+       return "";
+ }
+ void put_revision_mark(const struct rev_info *revs, const struct commit *commit)
+ {
+       char *mark = get_revision_mark(revs, commit);
+       if (!strlen(mark))
+               return;
+       fputs(mark, stdout);
+       putchar(' ');
+ }
diff --combined revision.h
index 82509dd1d9ad7b1824971be4884409060f10aee3,1c0abf0f58e3559588cd6522210bc9cf76d43f0f..ae948601f94c726c3677f23517dba5c046431904
@@@ -14,7 -14,8 +14,8 @@@
  #define CHILD_SHOWN   (1u<<6)
  #define ADDED         (1u<<7) /* Parents already parsed and added? */
  #define SYMMETRIC_LEFT        (1u<<8)
- #define ALL_REV_FLAGS ((1u<<9)-1)
+ #define PATCHSAME     (1u<<9)
+ #define ALL_REV_FLAGS ((1u<<10)-1)
  
  #define DECORATE_SHORT_REFS   1
  #define DECORATE_FULL_REFS    2
@@@ -34,7 -35,7 +35,7 @@@ struct rev_info 
        /* Basic information */
        const char *prefix;
        const char *def;
 -      void *prune_data;
 +      struct pathspec prune_data;
        unsigned int early_output;
  
        /* Traversal flags */
@@@ -59,6 -60,8 +60,8 @@@
                        boundary:2,
                        count:1,
                        left_right:1,
+                       left_only:1,
+                       right_only:1,
                        rewrite_parents:1,
                        print_parents:1,
                        show_source:1,
@@@ -66,6 -69,7 +69,7 @@@
                        reverse:1,
                        reverse_output_stage:1,
                        cherry_pick:1,
+                       cherry_mark:1,
                        bisect:1,
                        ancestry_path:1,
                        first_parent_only:1;
@@@ -163,6 -167,8 +167,8 @@@ extern int handle_revision_arg(const ch
  
  extern int prepare_revision_walk(struct rev_info *revs);
  extern struct commit *get_revision(struct rev_info *revs);
+ extern char *get_revision_mark(const struct rev_info *revs, const struct commit *commit);
+ extern void put_revision_mark(const struct rev_info *revs, const struct commit *commit);
  
  extern void mark_parents_uninteresting(struct commit *commit);
  extern void mark_tree_uninteresting(struct tree *tree);