summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJunio C Hamano <gitster@pobox.com>2011-03-23 04:38:50 (GMT)
committerJunio C Hamano <gitster@pobox.com>2011-03-23 04:38:50 (GMT)
commitaeb2aaa7712f7af8237d5bceb725a7db8c2d4620 (patch)
tree179be08e021c12d073818ca78bc63846b10da8a5
parent281ee1d0c2c3f73bdc9012a5ac52feff97f72acd (diff)
parentb1b47554ae889ca76b66349819c9b95a8be5f646 (diff)
downloadgit-aeb2aaa7712f7af8237d5bceb725a7db8c2d4620.zip
git-aeb2aaa7712f7af8237d5bceb725a7db8c2d4620.tar.gz
git-aeb2aaa7712f7af8237d5bceb725a7db8c2d4620.tar.bz2
Merge branch 'mg/rev-list-one-side-only'
* 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
-rw-r--r--Documentation/git-rev-list.txt3
-rw-r--r--Documentation/rev-list-options.txt26
-rw-r--r--builtin/rev-list.c14
-rwxr-xr-xgit-svn.perl2
-rw-r--r--graph.c17
-rw-r--r--log-tree.c28
-rw-r--r--pretty.c6
-rw-r--r--revision.c82
-rw-r--r--revision.h8
-rwxr-xr-xt/t6007-rev-list-cherry-pick-file.sh113
10 files changed, 230 insertions, 69 deletions
diff --git a/Documentation/git-rev-list.txt b/Documentation/git-rev-list.txt
index 5ce4d7f..b08dfbc 100644
--- a/Documentation/git-rev-list.txt
+++ b/Documentation/git-rev-list.txt
@@ -31,6 +31,9 @@ SYNOPSIS
[ \--parents ]
[ \--timestamp ]
[ \--left-right ]
+ [ \--left-only ]
+ [ \--right-only ]
+ [ \--cherry-mark ]
[ \--cherry-pick ]
[ \--encoding[=<encoding>] ]
[ \--(author|committer|grep)=<pattern> ]
diff --git a/Documentation/rev-list-options.txt b/Documentation/rev-list-options.txt
index 09860de..5c6850f 100644
--- a/Documentation/rev-list-options.txt
+++ b/Documentation/rev-list-options.txt
@@ -151,6 +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 +170,27 @@ from the other branch (for example, "3rd on b" may be cherry-picked
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::
diff --git a/builtin/rev-list.c b/builtin/rev-list.c
index ba27d39..f458cb7 100644
--- a/builtin/rev-list.c
+++ b/builtin/rev-list.c
@@ -64,18 +64,8 @@ static void show_commit(struct commit *commit, void *data)
if (info->header_prefix)
fputs(info->header_prefix, stdout);
- if (!revs->graph) {
- if (commit->object.flags & BOUNDARY)
- putchar('-');
- else if (commit->object.flags & UNINTERESTING)
- putchar('^');
- else if (revs->left_right) {
- if (commit->object.flags & SYMMETRIC_LEFT)
- putchar('<');
- else
- putchar('>');
- }
- }
+ if (!revs->graph)
+ fputs(get_revision_mark(revs, commit), stdout);
if (revs->abbrev_commit && revs->abbrev)
fputs(find_unique_abbrev(commit->object.sha1, revs->abbrev),
stdout);
diff --git a/git-svn.perl b/git-svn.perl
index 177dd25..a5857c1 100755
--- a/git-svn.perl
+++ b/git-svn.perl
@@ -5734,7 +5734,7 @@ sub cmd_show_log {
my (@k, $c, $d, $stat);
my $esc_color = qr/(?:\033\[(?:(?:\d+;)*\d*)?m)*/;
while (<$log>) {
- if (/^${esc_color}commit -?($::sha1_short)/o) {
+ if (/^${esc_color}commit (- )?($::sha1_short)/o) {
my $cmt = $1;
if ($c && cmt_showable($c) && $c->{r} != $r_last) {
$r_last = $c->{r};
diff --git a/graph.c b/graph.c
index f1a63c2..ef2e24e 100644
--- a/graph.c
+++ b/graph.c
@@ -798,22 +798,9 @@ static void graph_output_commit_char(struct git_graph *graph, struct strbuf *sb)
}
/*
- * If revs->left_right is set, print '<' for commits that
- * come from the left side, and '>' for commits from the right
- * side.
+ * get_revision_mark() handles all other cases without assert()
*/
- if (graph->revs && graph->revs->left_right) {
- if (graph->commit->object.flags & SYMMETRIC_LEFT)
- strbuf_addch(sb, '<');
- else
- strbuf_addch(sb, '>');
- return;
- }
-
- /*
- * Print '*' in all other cases
- */
- strbuf_addch(sb, '*');
+ strbuf_addstr(sb, get_revision_mark(graph->revs, graph->commit));
}
/*
diff --git a/log-tree.c b/log-tree.c
index b46ed3b..2a1e3a9 100644
--- a/log-tree.c
+++ b/log-tree.c
@@ -380,18 +380,8 @@ void show_log(struct rev_info *opt)
if (!opt->verbose_header) {
graph_show_commit(opt->graph);
- if (!opt->graph) {
- if (commit->object.flags & BOUNDARY)
- putchar('-');
- else if (commit->object.flags & UNINTERESTING)
- putchar('^');
- else if (opt->left_right) {
- if (commit->object.flags & SYMMETRIC_LEFT)
- putchar('<');
- else
- putchar('>');
- }
- }
+ if (!opt->graph)
+ put_revision_mark(opt, commit);
fputs(find_unique_abbrev(commit->object.sha1, abbrev_commit), stdout);
if (opt->print_parents)
show_parents(commit, abbrev_commit);
@@ -448,18 +438,8 @@ void show_log(struct rev_info *opt)
if (opt->commit_format != CMIT_FMT_ONELINE)
fputs("commit ", stdout);
- if (!opt->graph) {
- if (commit->object.flags & BOUNDARY)
- putchar('-');
- else if (commit->object.flags & UNINTERESTING)
- putchar('^');
- else if (opt->left_right) {
- if (commit->object.flags & SYMMETRIC_LEFT)
- putchar('<');
- else
- putchar('>');
- }
- }
+ if (!opt->graph)
+ put_revision_mark(opt, commit);
fputs(find_unique_abbrev(commit->object.sha1, abbrev_commit),
stdout);
if (opt->print_parents)
diff --git a/pretty.c b/pretty.c
index 65d20a7..e1d8a8f 100644
--- a/pretty.c
+++ b/pretty.c
@@ -876,11 +876,7 @@ static size_t format_commit_one(struct strbuf *sb, const char *placeholder,
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);
diff --git a/revision.c b/revision.c
index 86d2470..e96c281 100644
--- a/revision.c
+++ b/revision.c
@@ -535,6 +535,7 @@ static void cherry_pick_list(struct commit_list *list, struct rev_info *revs)
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) {
@@ -572,6 +573,9 @@ static void cherry_pick_list(struct commit_list *list, struct rev_info *revs)
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;
@@ -594,7 +598,7 @@ static void cherry_pick_list(struct commit_list *list, struct rev_info *revs)
if (!id)
continue;
id->seen = 1;
- commit->object.flags |= SHOWN;
+ commit->object.flags |= cherry_flag;
}
/* Now check the original side for seen ones */
@@ -606,7 +610,7 @@ static void cherry_pick_list(struct commit_list *list, struct rev_info *revs)
if (!ent)
continue;
if (ent->seen)
- commit->object.flags |= SHOWN;
+ commit->object.flags |= cherry_flag;
commit->util = NULL;
}
@@ -729,6 +733,23 @@ static struct commit_list *collect_bottom_commits(struct commit_list *list)
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;
@@ -781,9 +802,12 @@ static int limit_list(struct rev_info *revs)
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);
@@ -1260,9 +1284,32 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
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")) {
@@ -2232,3 +2279,32 @@ struct commit *get_revision(struct rev_info *revs)
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 --git a/revision.h b/revision.h
index 82509dd..ae94860 100644
--- a/revision.h
+++ b/revision.h
@@ -14,7 +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
@@ -59,6 +60,8 @@ struct rev_info {
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 @@ struct rev_info {
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 @@ extern int handle_revision_arg(const char *arg, struct rev_info *revs,int flags,
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);
diff --git a/t/t6007-rev-list-cherry-pick-file.sh b/t/t6007-rev-list-cherry-pick-file.sh
index b565638..cacf3de 100755
--- a/t/t6007-rev-list-cherry-pick-file.sh
+++ b/t/t6007-rev-list-cherry-pick-file.sh
@@ -4,13 +4,14 @@ test_description='test git rev-list --cherry-pick -- file'
. ./test-lib.sh
-# A---B
+# A---B---D---F
# \
# \
-# C
+# C---E
#
# B changes a file foo.c, adding a line of text. C changes foo.c as
# well as bar.c, but the change in foo.c was identical to change B.
+# D and C change bar in the same way, E and F differently.
test_expect_success setup '
echo Hallo > foo &&
@@ -25,11 +26,26 @@ test_expect_success setup '
test_tick &&
git commit -m "C" &&
git tag C &&
+ echo Dello > bar &&
+ git add bar &&
+ test_tick &&
+ git commit -m "E" &&
+ git tag E &&
git checkout master &&
git checkout branch foo &&
test_tick &&
git commit -m "B" &&
- git tag B
+ git tag B &&
+ echo Cello > bar &&
+ git add bar &&
+ test_tick &&
+ git commit -m "D" &&
+ git tag D &&
+ echo Nello > bar &&
+ git add bar &&
+ test_tick &&
+ git commit -m "F" &&
+ git tag F
'
cat >expect <<EOF
@@ -53,8 +69,92 @@ test_expect_success '--cherry-pick foo comes up empty' '
test -z "$(git rev-list --left-right --cherry-pick B...C -- foo)"
'
+cat >expect <<EOF
+>tags/C
+EOF
+
test_expect_success '--cherry-pick bar does not come up empty' '
- ! test -z "$(git rev-list --left-right --cherry-pick B...C -- bar)"
+ git rev-list --left-right --cherry-pick B...C -- bar > actual &&
+ git name-rev --stdin --name-only --refs="*tags/*" \
+ < actual > actual.named &&
+ test_cmp actual.named expect
+'
+
+test_expect_success 'bar does not come up empty' '
+ git rev-list --left-right B...C -- bar > actual &&
+ git name-rev --stdin --name-only --refs="*tags/*" \
+ < actual > actual.named &&
+ test_cmp actual.named expect
+'
+
+cat >expect <<EOF
+<tags/F
+>tags/E
+EOF
+
+test_expect_success '--cherry-pick bar does not come up empty (II)' '
+ git rev-list --left-right --cherry-pick F...E -- bar > actual &&
+ git name-rev --stdin --name-only --refs="*tags/*" \
+ < actual > actual.named &&
+ test_cmp actual.named expect
+'
+
+cat >expect <<EOF
++tags/F
+=tags/D
++tags/E
+=tags/C
+EOF
+
+test_expect_success '--cherry-mark' '
+ git rev-list --cherry-mark F...E -- bar > actual &&
+ git name-rev --stdin --name-only --refs="*tags/*" \
+ < actual > actual.named &&
+ test_cmp actual.named expect
+'
+
+cat >expect <<EOF
+<tags/F
+=tags/D
+>tags/E
+=tags/C
+EOF
+
+test_expect_success '--cherry-mark --left-right' '
+ git rev-list --cherry-mark --left-right F...E -- bar > actual &&
+ git name-rev --stdin --name-only --refs="*tags/*" \
+ < actual > actual.named &&
+ test_cmp actual.named expect
+'
+
+cat >expect <<EOF
+tags/E
+EOF
+
+test_expect_success '--cherry-pick --right-only' '
+ git rev-list --cherry-pick --right-only F...E -- bar > actual &&
+ git name-rev --stdin --name-only --refs="*tags/*" \
+ < actual > actual.named &&
+ test_cmp actual.named expect
+'
+
+test_expect_success '--cherry-pick --left-only' '
+ git rev-list --cherry-pick --left-only E...F -- bar > actual &&
+ git name-rev --stdin --name-only --refs="*tags/*" \
+ < actual > actual.named &&
+ test_cmp actual.named expect
+'
+
+cat >expect <<EOF
++tags/E
+=tags/C
+EOF
+
+test_expect_success '--cherry' '
+ git rev-list --cherry F...E -- bar > actual &&
+ git name-rev --stdin --name-only --refs="*tags/*" \
+ < actual > actual.named &&
+ test_cmp actual.named expect
'
test_expect_success '--cherry-pick with independent, but identical branches' '
@@ -75,11 +175,8 @@ cat >expect <<EOF
1 2
EOF
-# Insert an extra commit to break the symmetry
test_expect_success '--count --left-right' '
- git checkout branch &&
- test_commit D &&
- git rev-list --count --left-right B...D > actual &&
+ git rev-list --count --left-right C...D > actual &&
test_cmp expect actual
'