@matheusbsbs / matheus-bagliano / commits / 67ac1e1d57
Fork 0

cherry-pick/revert: add support for -X/--strategy-option

For example, this would allow cherry-picking or reverting patches from a piece of history with a different end-of-line style, like so: $ git revert -Xrenormalize old-problematic-commit Currently that is possible with manual use of merge-recursive but the cherry-pick/revert porcelain does not expose the functionality. While at it, document the existing support for --strategy. Signed-off-by: Jonathan Nieder <jrnieder@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Jonathan Nieder committed Dec 10, 2010 at 18:51 UTC 67ac1e1d57e45899a4dfd900a0249f48507584b5
7 files changed +97 -11
Documentation/git-cherry-pick.txt
+32
@@ -79,6 +79,16 @@ effect to your index in a row.
79 cherry-pick'ed commit, then a fast forward to this commit will
80 be performed.
81
82 +--strategy=<strategy>::
83 + Use the given merge strategy. Should only be used once.
84 + See the MERGE STRATEGIES section in linkgit:git-merge[1]
85 + for details.
86 +
87 +-X<option>::
88 +--strategy-option=<option>::
89 + Pass the merge strategy-specific option through to the
90 + merge strategy. See linkgit:git-merge[1] for details.
91 +
92 EXAMPLES
93 --------
94 git cherry-pick master::
@@ -120,6 +130,28 @@ git rev-list --reverse master \-- README | git cherry-pick -n --stdin::
130 so the result can be inspected and made into a single new
131 commit if suitable.
132
133 +The following sequence attempts to backport a patch, bails out because
134 +the code the patch applies to has changed too much, and then tries
135 +again, this time exercising more care about matching up context lines.
136 +
137 +------------
138 +$ git cherry-pick topic^ <1>
139 +$ git diff <2>
140 +$ git reset --merge ORIG_HEAD <3>
141 +$ git cherry-pick -Xpatience topic^ <4>
142 +------------
143 +<1> apply the change that would be shown by `git show topic^`.
144 +In this example, the patch does not apply cleanly, so
145 +information about the conflict is written to the index and
146 +working tree and no new commit results.
147 +<2> summarize changes to be reconciled
148 +<3> cancel the cherry-pick. In other words, return to the
149 +pre-cherry-pick state, preserving any local modifications you had in
150 +the working tree.
151 +<4> try to apply the change introduced by `topic^` again,
152 +spending extra time to avoid mistakes based on incorrectly matching
153 +context lines.
154 +
155 Author
156 ------
157 Written by Junio C Hamano <gitster@pobox.com>
Documentation/git-revert.txt
+10
@@ -80,6 +80,16 @@ effect to your index in a row.
80 --signoff::
81 Add Signed-off-by line at the end of the commit message.
82
83 +--strategy=<strategy>::
84 + Use the given merge strategy. Should only be used once.
85 + See the MERGE STRATEGIES section in linkgit:git-merge[1]
86 + for details.
87 +
88 +-X<option>::
89 +--strategy-option=<option>::
90 + Pass the merge strategy-specific option through to the
91 + merge strategy. See linkgit:git-merge[1] for details.
92 +
93 EXAMPLES
94 --------
95 git revert HEAD~3::
builtin/merge.c
+4 -2
@@ -582,7 +582,8 @@ static void write_tree_trivial(unsigned char *sha1)
582 die("git write-tree failed to write a tree");
583 }
584
585 -int try_merge_command(const char *strategy, struct commit_list *common,
585 +int try_merge_command(const char *strategy, size_t xopts_nr,
586 + const char **xopts, struct commit_list *common,
587 const char *head_arg, struct commit_list *remotes)
588 {
589 const char **args;
@@ -680,7 +681,8 @@ static int try_merge_strategy(const char *strategy, struct commit_list *common,
681 rollback_lock_file(lock);
682 return clean ? 0 : 1;
683 } else {
683 - return try_merge_command(strategy, common, head_arg, remoteheads);
684 + return try_merge_command(strategy, xopts_nr, xopts,
685 + common, head_arg, remoteheads);
686 }
687 }
688
builtin/revert.c
+22 -7
@@ -44,7 +44,11 @@ static const char **commit_argv;
44 static int allow_rerere_auto;
45
46 static const char *me;
47 +
48 +/* Merge strategy. */
49 static const char *strategy;
50 +static const char **xopts;
51 +static size_t xopts_nr, xopts_alloc;
52
53 #define GIT_REFLOG_ACTION "GIT_REFLOG_ACTION"
54
@@ -55,6 +59,17 @@ static const char * const *revert_or_cherry_pick_usage(void)
59 return action == REVERT ? revert_usage : cherry_pick_usage;
60 }
61
62 +static int option_parse_x(const struct option *opt,
63 + const char *arg, int unset)
64 +{
65 + if (unset)
66 + return 0;
67 +
68 + ALLOC_GROW(xopts, xopts_nr + 1, xopts_alloc);
69 + xopts[xopts_nr++] = xstrdup(arg);
70 + return 0;
71 +}
72 +
73 static void parse_args(int argc, const char **argv)
74 {
75 const char * const * usage_str = revert_or_cherry_pick_usage();
@@ -67,6 +82,8 @@ static void parse_args(int argc, const char **argv)
82 OPT_INTEGER('m', "mainline", &mainline, "parent number"),
83 OPT_RERERE_AUTOUPDATE(&allow_rerere_auto),
84 OPT_STRING(0, "strategy", &strategy, "strategy", "merge strategy"),
85 + OPT_CALLBACK('X', "strategy-option", &xopts, "option",
86 + "option for merge strategy", option_parse_x),
87 OPT_END(),
88 OPT_END(),
89 OPT_END(),
@@ -311,18 +328,13 @@ static int do_recursive_merge(struct commit *base, struct commit *next,
328 struct merge_options o;
329 struct tree *result, *next_tree, *base_tree, *head_tree;
330 int clean, index_fd;
331 + const char **xopt;
332 static struct lock_file index_lock;
333
334 index_fd = hold_locked_index(&index_lock, 1);
335
336 read_cache();
337
320 - /*
321 - * NEEDSWORK: cherry-picking between branches with
322 - * different end-of-line normalization is a pain;
323 - * plumb in an option to set o.renormalize?
324 - * (or better: arbitrary -X options)
325 - */
338 init_merge_options(&o);
339 o.ancestor = base ? base_label : "(empty tree)";
340 o.branch1 = "HEAD";
@@ -332,6 +344,9 @@ static int do_recursive_merge(struct commit *base, struct commit *next,
344 next_tree = next ? next->tree : empty_tree();
345 base_tree = base ? base->tree : empty_tree();
346
347 + for (xopt = xopts; xopt != xopts + xopts_nr; xopt++)
348 + parse_merge_opt(&o, *xopt);
349 +
350 clean = merge_trees(&o,
351 head_tree,
352 next_tree, base_tree, &result);
@@ -503,7 +518,7 @@ static int do_pick_commit(void)
518
519 commit_list_insert(base, &common);
520 commit_list_insert(next, &remotes);
506 - res = try_merge_command(strategy, common,
521 + res = try_merge_command(strategy, xopts_nr, xopts, common,
522 sha1_to_hex(head), remotes);
523 free_commit_list(common);
524 free_commit_list(remotes);
contrib/examples/git-revert.sh
+12 -1
@@ -26,6 +26,7 @@ require_work_tree
26 cd_to_toplevel
27
28 no_commit=
29 +xopt=
30 while case "$#" in 0) break ;; esac
31 do
32 case "$1" in
@@ -44,6 +45,16 @@ do
45 -x|--i-really-want-to-expose-my-private-commit-object-name)
46 replay=
47 ;;
48 + -X?*)
49 + xopt="$xopt$(git rev-parse --sq-quote "--${1#-X}")"
50 + ;;
51 + --strategy-option=*)
52 + xopt="$xopt$(git rev-parse --sq-quote "--${1#--strategy-option=}")"
53 + ;;
54 + -X|--strategy-option)
55 + shift
56 + xopt="$xopt$(git rev-parse --sq-quote "--$1")"
57 + ;;
58 -*)
59 usage
60 ;;
@@ -159,7 +170,7 @@ export GITHEAD_$head GITHEAD_$next
170 # and $prev on top of us (when reverting), or the change between
171 # $prev and $commit on top of us (when cherry-picking or replaying).
172
162 -git-merge-recursive $base -- $head $next &&
173 +eval "git merge-recursive $xopt $base -- $head $next" &&
174 result=$(git-write-tree 2>/dev/null) || {
175 mv -f .msg "$GIT_DIR/MERGE_MSG"
176 {
merge-recursive.h
+3 -1
@@ -57,6 +57,8 @@ struct tree *write_tree_from_memory(struct merge_options *o);
57 int parse_merge_opt(struct merge_options *out, const char *s);
58
59 /* builtin/merge.c */
60 -int try_merge_command(const char *strategy, struct commit_list *common, const char *head_arg, struct commit_list *remotes);
60 +int try_merge_command(const char *strategy, size_t xopts_nr,
61 + const char **xopts, struct commit_list *common,
62 + const char *head_arg, struct commit_list *remotes);
63
64 #endif
t/t3032-merge-recursive-options.sh
+14
@@ -107,6 +107,20 @@ test_expect_success '--ignore-space-change makes merge succeed' '
107 git merge-recursive --ignore-space-change HEAD^ -- HEAD remote
108 '
109
110 +test_expect_success 'naive cherry-pick fails' '
111 + git read-tree --reset -u HEAD &&
112 + test_must_fail git cherry-pick --no-commit remote &&
113 + git read-tree --reset -u HEAD &&
114 + test_must_fail git cherry-pick remote &&
115 + test_must_fail git update-index --refresh &&
116 + grep "<<<<<<" text.txt
117 +'
118 +
119 +test_expect_success '-Xignore-space-change makes cherry-pick succeed' '
120 + git read-tree --reset -u HEAD &&
121 + git cherry-pick --no-commit -Xignore-space-change remote
122 +'
123 +
124 test_expect_success '--ignore-space-change: our w/s-only change wins' '
125 q_to_cr <<-\EOF >expected &&
126 justice and holiness and is the nurse of his age and theQ