@matheusbsbs / matheus-bagliano / commits / d7e5c0cbfb
Fork 0

Introduce CHERRY_PICK_HEAD

When a cherry-pick conflicts git advises: $ git commit -c <original commit id> to preserve the original commit message and authorship. Instead, let's record the original commit id in CHERRY_PICK_HEAD and advise: $ git commit -c CHERRY_PICK_HEAD A later patch teaches git to handle the '-c CHERRY_PICK_HEAD' part. Note that we record CHERRY_PICK_HEAD even in the case where there are no conflicts so that we may use it to communicate authorship to commit; this will then allow us to remove set_author_ident_env from revert.c. However, we do not record CHERRY_PICK_HEAD when --no-commit is used, as presumably the user intends to further edit the commit and possibly even cherry-pick additional commits on top. Tests and documentation contributed by Jonathan Nieder. Reviewed-by: Jonathan Nieder <jrnieder@gmail.com> Signed-off-by: Jay Soffian <jaysoffian@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Jay Soffian committed Feb 19, 2011 at 23:12 UTC d7e5c0cbfb0421d8a609f1125267dbad73069410
7 files changed +132 -4
Documentation/git-cherry-pick.txt
+19
@@ -16,6 +16,25 @@ Given one or more existing commits, apply the change each one
16 introduces, recording a new commit for each. This requires your
17 working tree to be clean (no modifications from the HEAD commit).
18
19 +When it is not obvious how to apply a change, the following
20 +happens:
21 +
22 +1. The current branch and `HEAD` pointer stay at the last commit
23 + successfully made.
24 +2. The `CHERRY_PICK_HEAD` ref is set to point at the commit that
25 + introduced the change that is difficult to apply.
26 +3. Paths in which the change applied cleanly are updated both
27 + in the index file and in your working tree.
28 +4. For conflicting paths, the index file records up to three
29 + versions, as described in the "TRUE MERGE" section of
30 + linkgit:git-merge[1]. The working tree files will include
31 + a description of the conflict bracketed by the usual
32 + conflict markers `<<<<<<<` and `>>>>>>>`.
33 +5. No other modifications are made.
34 +
35 +See linkgit:git-merge[1] for some hints on resolving such
36 +conflicts.
37 +
38 OPTIONS
39 -------
40 <commit>...::
Documentation/revisions.txt
+4 -1
@@ -25,7 +25,8 @@ blobs contained in a commit.
25 first match in the following rules:
26
27 . if `$GIT_DIR/<name>` exists, that is what you mean (this is usually
28 - useful only for `HEAD`, `FETCH_HEAD`, `ORIG_HEAD` and `MERGE_HEAD`);
28 + useful only for `HEAD`, `FETCH_HEAD`, `ORIG_HEAD`, `MERGE_HEAD`
29 + and `CHERRY_PICK_HEAD`);
30
31 . otherwise, `refs/<name>` if exists;
32
@@ -46,6 +47,8 @@ you can change the tip of the branch back to the state before you ran
47 them easily.
48 MERGE_HEAD records the commit(s) you are merging into your branch
49 when you run 'git merge'.
50 +CHERRY_PICK_HEAD records the commit you are cherry-picking
51 +when you run 'git cherry-pick'.
52 +
53 Note that any of the `refs/*` cases above may come either from
54 the `$GIT_DIR/refs` directory or from the `$GIT_DIR/packed-refs` file.
branch.c
+1
@@ -217,6 +217,7 @@ void create_branch(const char *head,
217
218 void remove_branch_state(void)
219 {
220 + unlink(git_path("CHERRY_PICK_HEAD"));
221 unlink(git_path("MERGE_HEAD"));
222 unlink(git_path("MERGE_RR"));
223 unlink(git_path("MERGE_MSG"));
builtin/commit.c
+1
@@ -1424,6 +1424,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
1424 die("cannot update HEAD ref");
1425 }
1426
1427 + unlink(git_path("CHERRY_PICK_HEAD"));
1428 unlink(git_path("MERGE_HEAD"));
1429 unlink(git_path("MERGE_MSG"));
1430 unlink(git_path("MERGE_MODE"));
builtin/merge.c
+7
@@ -969,6 +969,13 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
969 else
970 die("You have not concluded your merge (MERGE_HEAD exists).");
971 }
972 + if (file_exists(git_path("CHERRY_PICK_HEAD"))) {
973 + if (advice_resolve_conflict)
974 + die("You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists).\n"
975 + "Please, commit your changes before you can merge.");
976 + else
977 + die("You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists).");
978 + }
979 resolve_undo_clear();
980
981 if (verbosity < 0)
builtin/revert.c
+25 -2
@@ -231,6 +231,22 @@ static void set_author_ident_env(const char *message)
231 sha1_to_hex(commit->object.sha1));
232 }
233
234 +static void write_cherry_pick_head(void)
235 +{
236 + int fd;
237 + struct strbuf buf = STRBUF_INIT;
238 +
239 + strbuf_addf(&buf, "%s\n", sha1_to_hex(commit->object.sha1));
240 +
241 + fd = open(git_path("CHERRY_PICK_HEAD"), O_WRONLY | O_CREAT, 0666);
242 + if (fd < 0)
243 + die_errno("Could not open '%s' for writing",
244 + git_path("CHERRY_PICK_HEAD"));
245 + if (write_in_full(fd, buf.buf, buf.len) != buf.len || close(fd))
246 + die_errno("Could not write to '%s'", git_path("CHERRY_PICK_HEAD"));
247 + strbuf_release(&buf);
248 +}
249 +
250 static void advise(const char *advice, ...)
251 {
252 va_list params;
@@ -246,6 +262,12 @@ static void print_advice(void)
262
263 if (msg) {
264 fprintf(stderr, "%s\n", msg);
265 + /*
266 + * A conflict has occured but the porcelain
267 + * (typically rebase --interactive) wants to take care
268 + * of the commit itself so remove CHERRY_PICK_HEAD
269 + */
270 + unlink(git_path("CHERRY_PICK_HEAD"));
271 return;
272 }
273
@@ -253,8 +275,7 @@ static void print_advice(void)
275 advise("with 'git add <paths>' or 'git rm <paths>'");
276
277 if (action == CHERRY_PICK)
256 - advise("and commit the result with 'git commit -c %s'",
257 - find_unique_abbrev(commit->object.sha1, DEFAULT_ABBREV));
278 + advise("and commit the result with 'git commit -c CHERRY_PICK_HEAD'");
279 }
280
281 static void write_message(struct strbuf *msgbuf, const char *filename)
@@ -489,6 +510,8 @@ static int do_pick_commit(void)
510 strbuf_addstr(&msgbuf, sha1_to_hex(commit->object.sha1));
511 strbuf_addstr(&msgbuf, ")\n");
512 }
513 + if (!no_commit)
514 + write_cherry_pick_head();
515 }
516
517 if (!strategy || !strcmp(strategy, "recursive") || action == REVERT) {
t/t3507-cherry-pick-conflict.sh
+75 -1
@@ -52,13 +52,87 @@ test_expect_success 'advice from failed cherry-pick' "
52 error: could not apply \$picked... picked
53 hint: after resolving the conflicts, mark the corrected paths
54 hint: with 'git add <paths>' or 'git rm <paths>'
55 - hint: and commit the result with 'git commit -c \$picked'
55 + hint: and commit the result with 'git commit -c CHERRY_PICK_HEAD'
56 EOF
57 test_must_fail git cherry-pick picked 2>actual &&
58
59 test_cmp expected actual
60 "
61
62 +test_expect_success 'failed cherry-pick sets CHERRY_PICK_HEAD' '
63 + pristine_detach initial &&
64 + test_must_fail git cherry-pick picked &&
65 + test_cmp_rev picked CHERRY_PICK_HEAD
66 +'
67 +
68 +test_expect_success 'successful cherry-pick does not set CHERRY_PICK_HEAD' '
69 + pristine_detach initial &&
70 + git cherry-pick base &&
71 + test_must_fail git rev-parse --verify CHERRY_PICK_HEAD
72 +'
73 +
74 +test_expect_success 'cherry-pick --no-commit does not set CHERRY_PICK_HEAD' '
75 + pristine_detach initial &&
76 + git cherry-pick --no-commit base &&
77 + test_must_fail git rev-parse --verify CHERRY_PICK_HEAD
78 +'
79 +
80 +test_expect_success 'GIT_CHERRY_PICK_HELP suppresses CHERRY_PICK_HEAD' '
81 + pristine_detach initial &&
82 + (
83 + GIT_CHERRY_PICK_HELP="and then do something else" &&
84 + export GIT_CHERRY_PICK_HELP &&
85 + test_must_fail git cherry-pick picked
86 + ) &&
87 + test_must_fail git rev-parse --verify CHERRY_PICK_HEAD
88 +'
89 +
90 +test_expect_success 'git reset clears CHERRY_PICK_HEAD' '
91 + pristine_detach initial &&
92 +
93 + test_must_fail git cherry-pick picked &&
94 + git reset &&
95 +
96 + test_must_fail git rev-parse --verify CHERRY_PICK_HEAD
97 +'
98 +
99 +test_expect_success 'failed commit does not clear CHERRY_PICK_HEAD' '
100 + pristine_detach initial &&
101 +
102 + test_must_fail git cherry-pick picked &&
103 + test_must_fail git commit &&
104 +
105 + test_cmp_rev picked CHERRY_PICK_HEAD
106 +'
107 +
108 +test_expect_success 'cancelled commit does not clear CHERRY_PICK_HEAD' '
109 + pristine_detach initial &&
110 +
111 + test_must_fail git cherry-pick picked &&
112 + echo resolved >foo &&
113 + git add foo &&
114 + git update-index --refresh -q &&
115 + test_must_fail git diff-index --exit-code HEAD &&
116 + (
117 + GIT_EDITOR=false &&
118 + export GIT_EDITOR &&
119 + test_must_fail git commit
120 + ) &&
121 +
122 + test_cmp_rev picked CHERRY_PICK_HEAD
123 +'
124 +
125 +test_expect_success 'successful commit clears CHERRY_PICK_HEAD' '
126 + pristine_detach initial &&
127 +
128 + test_must_fail git cherry-pick picked &&
129 + echo resolved >foo &&
130 + git add foo &&
131 + git commit &&
132 +
133 + test_must_fail git rev-parse --verify CHERRY_PICK_HEAD
134 +'
135 +
136 test_expect_success 'failed cherry-pick produces dirty index' '
137 pristine_detach initial &&
138