{"thread":{"id":"26528","subject":"[PATCH v3 0/4] CHERRY_PICK_HEAD","startedAt":"2011-02-17T04:18:41Z","lastAt":"2011-02-20T06:43:33Z","messageCount":17,"participants":["Jay Soffian","Jonathan Nieder","Junio C Hamano"],"isPatch":true,"patchVersion":3,"patchTotal":4},"messages":[{"id":"161367","messageId":"1297916325-89688-1-git-send-email-jaysoffian@gmail.com","threadId":"26528","inReplyTo":null,"subject":"[PATCH v3 0/4] CHERRY_PICK_HEAD","fromName":"Jay Soffian","fromEmail":"jaysoffian@gmail.com","sentAt":"2011-02-17T04:18:41Z","receivedAt":"2011-02-17T04:18:41Z","isPatch":true,"sender":{"key":"jaysoffian@gmail.com","avatar":"https://avatars.githubusercontent.com/u/155970?v=4"},"body":"Incorporating feedback from http://thread.gmane.org/gmane.comp.version-control.git/166945\n\nJay Soffian (4):\n  Introduce CHERRY_PICK_HEAD\n  bash: teach __git_ps1 about CHERRY_PICK_HEAD\n  commit.c: replace some literal strings with constants\n  Teach commit about CHERRY_PICK_HEAD\n\n Documentation/git-cherry-pick.txt      |   19 +++\n Documentation/git-commit.txt           |    7 +-\n Documentation/revisions.txt            |    5 +-\n branch.c                               |    1 +\n builtin/commit.c                       |  196 ++++++++++++++++++++++----------\n builtin/merge.c                        |    7 +\n builtin/revert.c                       |   74 ++++---------\n contrib/completion/git-completion.bash |    2 +\n t/t3507-cherry-pick-conflict.sh        |  138 ++++++++++++++++++++++-\n t/t7509-commit.sh                      |   29 +++++\n wt-status.c                            |    4 +-\n wt-status.h                            |    9 ++-\n 12 files changed, 371 insertions(+), 120 deletions(-)\n\n-- \n1.7.4.1.30.g7fe09\n"},{"id":"161368","messageId":"1297916325-89688-2-git-send-email-jaysoffian@gmail.com","threadId":"26528","inReplyTo":"1297916325-89688-1-git-send-email-jaysoffian@gmail.com","subject":"[PATCH v3 1/4] Introduce CHERRY_PICK_HEAD","fromName":"Jay Soffian","fromEmail":"jaysoffian@gmail.com","sentAt":"2011-02-17T04:18:42Z","receivedAt":"2011-02-17T04:18:42Z","isPatch":true,"sender":{"key":"jaysoffian@gmail.com","avatar":"https://avatars.githubusercontent.com/u/155970?v=4"},"body":"When a cherry-pick conflicts git advises to use:\n\n $ git commit -c <original commit id>\n\nto preserve the original commit message and authorship. Instead, let's\nrecord the original commit id in CHERRY_PICK_HEAD and advise to use:\n\n  $ git commit -c CHERRY_PICK_HEAD\n\nA later patch teaches git to handle the '-c CHERRY_PICK_HEAD' part.\nNote that we record CHERRY_PICK_HEAD even in the case where there\nare no conflicts so that we may use it to communicate authorship to\ncommit; this will then allow us to remove set_author_ident_env from\nrevert.c.\n\nTests and documentation contributed by Jonathan Nieder.\n\nReviewed-by: Jonathan Nieder <jrnieder@gmail.com>\nSigned-off-by: Jay Soffian <jaysoffian@gmail.com>\n---\nIncorporated feedback and additional tests from\nhttp://article.gmane.org/gmane.comp.version-control.git/167007\n\n Documentation/git-cherry-pick.txt |   19 +++++\n Documentation/revisions.txt       |    5 +-\n branch.c                          |    1 +\n builtin/commit.c                  |    1 +\n builtin/merge.c                   |    7 ++\n builtin/revert.c                  |   26 +++++++-\n t/t3507-cherry-pick-conflict.sh   |  138 ++++++++++++++++++++++++++++++++++++-\n 7 files changed, 193 insertions(+), 4 deletions(-)\n\ndiff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt\nindex 749d68a..5d85daa 100644\n--- a/Documentation/git-cherry-pick.txt\n+++ b/Documentation/git-cherry-pick.txt\n@@ -16,6 +16,25 @@ Given one or more existing commits, apply the change each one\n introduces, recording a new commit for each.  This requires your\n working tree to be clean (no modifications from the HEAD commit).\n \n+When it is not obvious how to apply a change, the following\n+happens:\n+\n+1. The current branch and `HEAD` pointer stay at the last commit\n+   successfully made.\n+2. The `CHERRY_PICK_HEAD` ref is set to point at the commit that\n+   introduced the change that is difficult to apply.\n+3. Paths in which the change applied cleanly are updated both\n+   in the index file and in your working tree.\n+4. For conflicting paths, the index file records up to three\n+   versions, as described in the \"TRUE MERGE\" section of\n+   linkgit:git-merge[1].  The working tree files will include\n+   a description of the conflict bracketed by the usual\n+   conflict markers `<<<<<<<` and `>>>>>>>`.\n+5. No other modifications are made.\n+\n+See linkgit:git-merge[1] for some hints on resolving such\n+conflicts.\n+\n OPTIONS\n -------\n <commit>...::\ndiff --git a/Documentation/revisions.txt b/Documentation/revisions.txt\nindex 9e92734..04fceee 100644\n--- a/Documentation/revisions.txt\n+++ b/Documentation/revisions.txt\n@@ -25,7 +25,8 @@ blobs contained in a commit.\n   first match in the following rules:\n \n   . if `$GIT_DIR/<name>` exists, that is what you mean (this is usually\n-    useful only for `HEAD`, `FETCH_HEAD`, `ORIG_HEAD` and `MERGE_HEAD`);\n+    useful only for `HEAD`, `FETCH_HEAD`, `ORIG_HEAD`, `MERGE_HEAD`\n+    and `CHERRY_PICK_HEAD`);\n \n   . otherwise, `refs/<name>` if exists;\n \n@@ -46,6 +47,8 @@ you can change the tip of the branch back to the state before you ran\n them easily.\n MERGE_HEAD records the commit(s) you are merging into your branch\n when you run 'git merge'.\n+CHERRY_PICK_HEAD records the commit you are cherry-picking\n+when you run 'git cherry-pick'.\n +\n Note that any of the `refs/*` cases above may come either from\n the `$GIT_DIR/refs` directory or from the `$GIT_DIR/packed-refs` file.\ndiff --git a/branch.c b/branch.c\nindex 93dc866..dc23e95 100644\n--- a/branch.c\n+++ b/branch.c\n@@ -217,6 +217,7 @@ void create_branch(const char *head,\n \n void remove_branch_state(void)\n {\n+\tunlink(git_path(\"CHERRY_PICK_HEAD\"));\n \tunlink(git_path(\"MERGE_HEAD\"));\n \tunlink(git_path(\"MERGE_RR\"));\n \tunlink(git_path(\"MERGE_MSG\"));\ndiff --git a/builtin/commit.c b/builtin/commit.c\nindex 03cff5a..0def540 100644\n--- a/builtin/commit.c\n+++ b/builtin/commit.c\n@@ -1424,6 +1424,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)\n \t\tdie(\"cannot update HEAD ref\");\n \t}\n \n+\tunlink(git_path(\"CHERRY_PICK_HEAD\"));\n \tunlink(git_path(\"MERGE_HEAD\"));\n \tunlink(git_path(\"MERGE_MSG\"));\n \tunlink(git_path(\"MERGE_MODE\"));\ndiff --git a/builtin/merge.c b/builtin/merge.c\nindex 9403747..454dad2 100644\n--- a/builtin/merge.c\n+++ b/builtin/merge.c\n@@ -971,6 +971,13 @@ int cmd_merge(int argc, const char **argv, const char *prefix)\n \t\telse\n \t\t\tdie(\"You have not concluded your merge (MERGE_HEAD exists).\");\n \t}\n+\tif (file_exists(git_path(\"CHERRY_PICK_HEAD\"))) {\n+\t\tif (advice_resolve_conflict)\n+\t\t\tdie(\"You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists).\\n\"\n+\t\t\t    \"Please, commit your changes before you can merge.\");\n+\t\telse\n+\t\t\tdie(\"You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists).\");\n+\t}\n \tresolve_undo_clear();\n \n \tif (verbosity < 0)\ndiff --git a/builtin/revert.c b/builtin/revert.c\nindex dc1b702..fbb465a 100644\n--- a/builtin/revert.c\n+++ b/builtin/revert.c\n@@ -248,6 +248,22 @@ static void set_author_ident_env(const char *message)\n \t\t\tsha1_to_hex(commit->object.sha1));\n }\n \n+static void write_cherry_pick_head(void)\n+{\n+\tint fd;\n+\tstruct strbuf buf = STRBUF_INIT;\n+\n+\tstrbuf_addf(&buf, \"%s\\n\", sha1_to_hex(commit->object.sha1));\n+\n+\tfd = open(git_path(\"CHERRY_PICK_HEAD\"), O_WRONLY | O_CREAT, 0666);\n+\tif (fd < 0)\n+\t\tdie_errno(\"Could not open '%s' for writing\",\n+\t\t\t  git_path(\"CHERRY_PICK_HEAD\"));\n+\tif (write_in_full(fd, buf.buf, buf.len) != buf.len || close(fd))\n+\t\tdie_errno(\"Could not write to '%s'\", git_path(\"CHERRY_PICK_HEAD\"));\n+\tstrbuf_release(&buf);\n+}\n+\n static void advise(const char *advice, ...)\n {\n \tva_list params;\n@@ -263,6 +279,12 @@ static void print_advice(void)\n \n \tif (msg) {\n \t\tfprintf(stderr, \"%s\\n\", msg);\n+\t\t/*\n+\t\t * A conflict has occured but the porcelain\n+\t\t * (typically rebase --interactive) wants to take care\n+\t\t * of the commit itself so remove CHERRY_PICK_HEAD\n+\t\t */\n+\t\tunlink(git_path(\"CHERRY_PICK_HEAD\"));\n \t\treturn;\n \t}\n \n@@ -270,8 +292,7 @@ static void print_advice(void)\n \tadvise(\"with 'git add <paths>' or 'git rm <paths>'\");\n \n \tif (action == CHERRY_PICK)\n-\t\tadvise(\"and commit the result with 'git commit -c %s'\",\n-\t\t       find_unique_abbrev(commit->object.sha1, DEFAULT_ABBREV));\n+\t\tadvise(\"and commit the result with 'git commit -c CHERRY_PICK_HEAD'\");\n }\n \n static void write_message(struct strbuf *msgbuf, const char *filename)\n@@ -504,6 +525,7 @@ static int do_pick_commit(void)\n \t\t\tstrbuf_addstr(&msgbuf, sha1_to_hex(commit->object.sha1));\n \t\t\tstrbuf_addstr(&msgbuf, \")\\n\");\n \t\t}\n+\t\twrite_cherry_pick_head();\n \t}\n \n \tif (!strategy || !strcmp(strategy, \"recursive\") || action == REVERT) {\ndiff --git a/t/t3507-cherry-pick-conflict.sh b/t/t3507-cherry-pick-conflict.sh\nindex 607bf25..ea52720 100755\n--- a/t/t3507-cherry-pick-conflict.sh\n+++ b/t/t3507-cherry-pick-conflict.sh\n@@ -11,6 +11,12 @@ test_description='test cherry-pick and revert with conflicts\n \n . ./test-lib.sh\n \n+test_cmp_rev () {\n+\tgit rev-parse --verify \"$1\" >expect.rev &&\n+\tgit rev-parse --verify \"$2\" >actual.rev &&\n+\ttest_cmp expect.rev actual.rev\n+}\n+\n test_expect_success setup '\n \n \techo unrelated >unrelated &&\n@@ -51,13 +57,143 @@ test_expect_success 'advice from failed cherry-pick' \"\n \terror: could not apply \\$picked... picked\n \thint: after resolving the conflicts, mark the corrected paths\n \thint: with 'git add <paths>' or 'git rm <paths>'\n-\thint: and commit the result with 'git commit -c \\$picked'\n+\thint: and commit the result with 'git commit -c CHERRY_PICK_HEAD'\n \tEOF\n \ttest_must_fail git cherry-pick picked 2>actual &&\n \n \ttest_cmp expected actual\n \"\n \n+test_expect_success 'failed cherry-pick sets CHERRY_PICK_HEAD' '\n+\n+\tgit checkout -f initial^0 &&\n+\tgit read-tree -u --reset HEAD &&\n+\tgit clean -d -f -f -q -x &&\n+\n+\tgit update-index --refresh &&\n+\tgit diff-index --exit-code HEAD &&\n+\n+\ttest_must_fail git cherry-pick picked &&\n+\n+\ttest_cmp_rev picked CHERRY_PICK_HEAD\n+'\n+\n+test_expect_success 'successful cherry-pick does not set CHERRY_PICK_HEAD' '\n+\n+\tgit checkout -f initial^0 &&\n+\tgit read-tree -u --reset HEAD &&\n+\tgit clean -d -f -f -q -x &&\n+\n+\tgit update-index --refresh &&\n+\tgit diff-index --exit-code HEAD &&\n+\n+\tgit cherry-pick base &&\n+\n+\ttest_must_fail git rev-parse --verify CHERRY_PICK_HEAD\n+'\n+\n+test_expect_success 'cherry-pick --no-commit sets CHERRY_PICK_HEAD' '\n+\n+\tgit checkout -f initial^0 &&\n+\tgit read-tree -u --reset HEAD &&\n+\tgit clean -d -f -f -q -x &&\n+\n+\tgit update-index --refresh &&\n+\tgit diff-index --exit-code HEAD &&\n+\n+\tgit cherry-pick --no-commit base &&\n+\n+\ttest_cmp_rev base CHERRY_PICK_HEAD\n+'\n+\n+test_expect_success 'GIT_CHERRY_PICK_HELP suppresses CHERRY_PICK_HEAD' '\n+\n+\tgit checkout -f initial^0 &&\n+\tgit read-tree -u --reset HEAD &&\n+\tgit clean -d -f -f -q -x &&\n+\n+\tgit update-index --refresh &&\n+\tgit diff-index --exit-code HEAD &&\n+\n+\t(\n+\t\tGIT_CHERRY_PICK_HELP=\"and then do something else\" &&\n+\t\texport GIT_CHERRY_PICK_HELP &&\n+\t\ttest_must_fail git cherry-pick picked\n+\t) &&\n+\n+\ttest_must_fail git rev-parse --verify CHERRY_PICK_HEAD\n+'\n+\n+test_expect_success 'git reset clears CHERRY_PICK_HEAD' '\n+\n+\tgit checkout -f initial^0 &&\n+\tgit read-tree -u --reset HEAD &&\n+\tgit clean -d -f -f -q -x &&\n+\n+\tgit update-index --refresh &&\n+\tgit diff-index --exit-code HEAD &&\n+\n+\ttest_must_fail git cherry-pick picked &&\n+\tgit reset &&\n+\n+\ttest_must_fail git rev-parse --verify CHERRY_PICK_HEAD\n+'\n+\n+test_expect_success 'failed commit does not clear CHERRY_PICK_HEAD' '\n+\n+\tgit checkout -f initial^0 &&\n+\tgit read-tree -u --reset HEAD &&\n+\tgit clean -d -f -f -q -x &&\n+\n+\tgit update-index --refresh &&\n+\tgit diff-index --exit-code HEAD &&\n+\n+\ttest_must_fail git cherry-pick picked &&\n+\ttest_must_fail git commit &&\n+\n+\ttest_cmp_rev picked CHERRY_PICK_HEAD\n+'\n+\n+test_expect_success 'cancelled commit does not clear CHERRY_PICK_HEAD' '\n+\n+\tgit checkout -f initial^0 &&\n+\tgit read-tree -u --reset HEAD &&\n+\tgit clean -d -f -f -q -x &&\n+\n+\tgit update-index --refresh &&\n+\tgit diff-index --exit-code HEAD &&\n+\n+\ttest_must_fail git cherry-pick picked &&\n+\techo resolved >foo &&\n+\tgit add foo &&\n+\tgit update-index --refresh -q &&\n+\ttest_must_fail git diff-index --exit-code HEAD &&\n+\t(\n+\t\tGIT_EDITOR=false &&\n+\t\texport GIT_EDITOR &&\n+\t\ttest_must_fail git commit\n+\t) &&\n+\n+\ttest_cmp_rev picked CHERRY_PICK_HEAD\n+'\n+\n+test_expect_success 'successful commit clears CHERRY_PICK_HEAD' '\n+\n+\tgit checkout -f initial^0 &&\n+\tgit read-tree -u --reset HEAD &&\n+\tgit clean -d -f -f -q -x &&\n+\n+\tgit update-index --refresh &&\n+\tgit diff-index --exit-code HEAD &&\n+\n+\ttest_must_fail git cherry-pick picked &&\n+\techo resolved >foo &&\n+\tgit add foo &&\n+\tgit commit &&\n+\n+\ttest_must_fail git rev-parse --verify CHERRY_PICK_HEAD\n+'\n+\n test_expect_success 'failed cherry-pick produces dirty index' '\n \n \tgit checkout -f initial^0 &&\n-- \n1.7.4.1.30.g7fe09\n"},{"id":"161369","messageId":"1297916325-89688-3-git-send-email-jaysoffian@gmail.com","threadId":"26528","inReplyTo":"1297916325-89688-1-git-send-email-jaysoffian@gmail.com","subject":"[PATCH v3 2/4] bash: teach __git_ps1 about CHERRY_PICK_HEAD","fromName":"Jay Soffian","fromEmail":"jaysoffian@gmail.com","sentAt":"2011-02-17T04:18:43Z","receivedAt":"2011-02-17T04:18:43Z","isPatch":true,"sender":{"key":"jaysoffian@gmail.com","avatar":"https://avatars.githubusercontent.com/u/155970?v=4"},"body":"Make the git prompt (when enabled) show a CHERRY-PICKING indicator\nwhen we are in the middle of a conflicted cherry-pick, analogous\nto the existing MERGING and BISECTING flags.\n\nSigned-off-by: Jay Soffian <jaysoffian@gmail.com>\nSigned-off-by: Jonathan Nieder <jrnieder@gmail.com>\n---\nSplit this out into its own patch per \nhttp://article.gmane.org/gmane.comp.version-control.git/167009\n\n contrib/completion/git-completion.bash |    2 ++\n 1 files changed, 2 insertions(+), 0 deletions(-)\n\ndiff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\nindex 893b771..0b0b913 100755\n--- a/contrib/completion/git-completion.bash\n+++ b/contrib/completion/git-completion.bash\n@@ -246,6 +246,8 @@ __git_ps1 ()\n \t\t\t\tfi\n \t\t\telif [ -f \"$g/MERGE_HEAD\" ]; then\n \t\t\t\tr=\"|MERGING\"\n+\t\t\telif [ -f \"$g/CHERRY_PICK_HEAD\" ]; then\n+\t\t\t\tr=\"|CHERRY-PICKING\"\n \t\t\telif [ -f \"$g/BISECT_LOG\" ]; then\n \t\t\t\tr=\"|BISECTING\"\n \t\t\tfi\n-- \n1.7.4.1.30.g7fe09\n"},{"id":"161370","messageId":"1297916325-89688-4-git-send-email-jaysoffian@gmail.com","threadId":"26528","inReplyTo":"1297916325-89688-1-git-send-email-jaysoffian@gmail.com","subject":"[PATCH v3 3/4] commit.c: replace some literal strings with constants","fromName":"Jay Soffian","fromEmail":"jaysoffian@gmail.com","sentAt":"2011-02-17T04:18:44Z","receivedAt":"2011-02-17T04:18:44Z","isPatch":true,"sender":{"key":"jaysoffian@gmail.com","avatar":"https://avatars.githubusercontent.com/u/155970?v=4"},"body":"A typo in any of these would be bad, so let's use\nconstants for them\n\nSigned-off-by: Jay Soffian <jaysoffian@gmail.com>\n---\nI converted these per\nhttp://article.gmane.org/gmane.comp.version-control.git/167015\n\nMaybe this should be the last patch in the series; it's questionable to\nme whether it's even worth doing.\n\n builtin/commit.c |   48 +++++++++++++++++++++++++++---------------------\n 1 files changed, 27 insertions(+), 21 deletions(-)\n\ndiff --git a/builtin/commit.c b/builtin/commit.c\nindex 0def540..5b32743 100644\n--- a/builtin/commit.c\n+++ b/builtin/commit.c\n@@ -54,10 +54,16 @@ static const char empty_amend_advice[] =\n \"it empty. You can repeat your command with --allow-empty, or you can\\n\"\n \"remove the commit entirely with \\\"git reset HEAD^\\\".\\n\";\n \n+static const char commit_editmsg[] = \"COMMIT_EDITMSG\";\n+static const char cherry_pick_head[] = \"CHERRY_PICK_HEAD\";\n+static const char merge_head[] = \"MERGE_HEAD\";\n+static const char merge_msg[] = \"MERGE_MSG\";\n+static const char merge_mode[] = \"MERGE_MODE\";\n+static const char squash_msg[] = \"SQUASH_MSG\";\n+\n static unsigned char head_sha1[20];\n \n static char *use_message_buffer;\n-static const char commit_editmsg[] = \"COMMIT_EDITMSG\";\n static struct lock_file index_lock; /* real index */\n static struct lock_file false_lock; /* used only for partial commits */\n static enum {\n@@ -626,13 +632,13 @@ static int prepare_to_commit(const char *index_file, const char *prefix,\n \t\tformat_commit_message(commit, \"fixup! %s\\n\\n\",\n \t\t\t\t      &sb, &ctx);\n \t\thook_arg1 = \"message\";\n-\t} else if (!stat(git_path(\"MERGE_MSG\"), &statbuf)) {\n-\t\tif (strbuf_read_file(&sb, git_path(\"MERGE_MSG\"), 0) < 0)\n-\t\t\tdie_errno(\"could not read MERGE_MSG\");\n+\t} else if (!stat(git_path(merge_msg), &statbuf)) {\n+\t\tif (strbuf_read_file(&sb, git_path(merge_msg), 0) < 0)\n+\t\t\tdie_errno(\"could not read %s\", merge_msg);\n \t\thook_arg1 = \"merge\";\n-\t} else if (!stat(git_path(\"SQUASH_MSG\"), &statbuf)) {\n-\t\tif (strbuf_read_file(&sb, git_path(\"SQUASH_MSG\"), 0) < 0)\n-\t\t\tdie_errno(\"could not read SQUASH_MSG\");\n+\t} else if (!stat(git_path(squash_msg), &statbuf)) {\n+\t\tif (strbuf_read_file(&sb, git_path(squash_msg), 0) < 0)\n+\t\t\tdie_errno(\"could not read %s\", squash_msg);\n \t\thook_arg1 = \"squash\";\n \t} else if (template_file && !stat(template_file, &statbuf)) {\n \t\tif (strbuf_read_file(&sb, template_file, 0) < 0)\n@@ -702,7 +708,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix,\n \t\t\t\t\"#\t%s\\n\"\n \t\t\t\t\"# and try again.\\n\"\n \t\t\t\t\"#\\n\",\n-\t\t\t\tgit_path(\"MERGE_HEAD\"));\n+\t\t\t\tgit_path(merge_head));\n \n \t\tfprintf(fp,\n \t\t\t\"\\n\"\n@@ -1117,7 +1123,7 @@ int cmd_status(int argc, const char **argv, const char *prefix)\n \twt_status_prepare(&s);\n \tgitmodules_config();\n \tgit_config(git_status_config, &s);\n-\tin_merge = file_exists(git_path(\"MERGE_HEAD\"));\n+\tin_merge = file_exists(git_path(merge_head));\n \targc = parse_options(argc, argv, prefix,\n \t\t\t     builtin_status_options,\n \t\t\t     builtin_status_usage, 0);\n@@ -1302,7 +1308,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)\n \n \twt_status_prepare(&s);\n \tgit_config(git_commit_config, &s);\n-\tin_merge = file_exists(git_path(\"MERGE_HEAD\"));\n+\tin_merge = file_exists(git_path(merge_head));\n \ts.in_merge = in_merge;\n \n \tif (s.use_color == -1)\n@@ -1347,21 +1353,21 @@ int cmd_commit(int argc, const char **argv, const char *prefix)\n \t\tif (!reflog_msg)\n \t\t\treflog_msg = \"commit (merge)\";\n \t\tpptr = &commit_list_insert(lookup_commit(head_sha1), pptr)->next;\n-\t\tfp = fopen(git_path(\"MERGE_HEAD\"), \"r\");\n+\t\tfp = fopen(git_path(merge_head), \"r\");\n \t\tif (fp == NULL)\n \t\t\tdie_errno(\"could not open '%s' for reading\",\n-\t\t\t\t  git_path(\"MERGE_HEAD\"));\n+\t\t\t\t  git_path(merge_head));\n \t\twhile (strbuf_getline(&m, fp, '\\n') != EOF) {\n \t\t\tunsigned char sha1[20];\n \t\t\tif (get_sha1_hex(m.buf, sha1) < 0)\n-\t\t\t\tdie(\"Corrupt MERGE_HEAD file (%s)\", m.buf);\n+\t\t\t\tdie(\"Corrupt %s file (%s)\", merge_head, m.buf);\n \t\t\tpptr = &commit_list_insert(lookup_commit(sha1), pptr)->next;\n \t\t}\n \t\tfclose(fp);\n \t\tstrbuf_release(&m);\n-\t\tif (!stat(git_path(\"MERGE_MODE\"), &statbuf)) {\n-\t\t\tif (strbuf_read_file(&sb, git_path(\"MERGE_MODE\"), 0) < 0)\n-\t\t\t\tdie_errno(\"could not read MERGE_MODE\");\n+\t\tif (!stat(git_path(merge_mode), &statbuf)) {\n+\t\t\tif (strbuf_read_file(&sb, git_path(merge_mode), 0) < 0)\n+\t\t\t\tdie_errno(\"could not read %s\", merge_mode);\n \t\t\tif (!strcmp(sb.buf, \"no-ff\"))\n \t\t\t\tallow_fast_forward = 0;\n \t\t}\n@@ -1424,11 +1430,11 @@ int cmd_commit(int argc, const char **argv, const char *prefix)\n \t\tdie(\"cannot update HEAD ref\");\n \t}\n \n-\tunlink(git_path(\"CHERRY_PICK_HEAD\"));\n-\tunlink(git_path(\"MERGE_HEAD\"));\n-\tunlink(git_path(\"MERGE_MSG\"));\n-\tunlink(git_path(\"MERGE_MODE\"));\n-\tunlink(git_path(\"SQUASH_MSG\"));\n+\tunlink(git_path(cherry_pick_head));\n+\tunlink(git_path(merge_head));\n+\tunlink(git_path(merge_msg));\n+\tunlink(git_path(merge_mode));\n+\tunlink(git_path(squash_msg));\n \n \tif (commit_index_files())\n \t\tdie (\"Repository has been updated, but unable to write\\n\"\n-- \n1.7.4.1.30.g7fe09\n"},{"id":"161371","messageId":"1297916325-89688-5-git-send-email-jaysoffian@gmail.com","threadId":"26528","inReplyTo":"1297916325-89688-1-git-send-email-jaysoffian@gmail.com","subject":"[PATCH v3 4/4] Teach commit about CHERRY_PICK_HEAD","fromName":"Jay Soffian","fromEmail":"jaysoffian@gmail.com","sentAt":"2011-02-17T04:18:45Z","receivedAt":"2011-02-17T04:18:45Z","isPatch":true,"sender":{"key":"jaysoffian@gmail.com","avatar":"https://avatars.githubusercontent.com/u/155970?v=4"},"body":"Previously the user was advised to use commit -c CHERRY_PICK_HEAD after\na conflicting cherry-pick. While this would preserve the original\ncommit's authorship, it would sadly discard cherry-pick's carefully\ncrafted MERGE_MSG (which contains the list of conflicts as well as the\noriginal commit-id in the case of cherry-pick -x).\n\nOn the other hand, if a bare 'commit' were performed, it would preserve\nthe MERGE_MSG while resetting the authorship.\n\nIn other words, there was no way to simultaneously take the authorship\nfrom CHERRY_PICK_HEAD and the commit message from MERGE_MSG.\n\nThis change fixes that situation. A bare 'commit' will now take the\nauthorship from CHERRY_PICK_HEAD and the commit message from MERGE_MSG.\nIf the user wishes to reset authorship, that must now be done explicitly\nvia --reset-author.\n\nA side-benefit of passing commit authorship along this way is that we\ncan eliminate redundant authorship parsing code from revert.c.\n\n(Also removed an unused include from revert.c)\n\nSigned-off-by: Jay Soffian <jaysoffian@gmail.com>\n---\nIncorporates feedback from:\n - http://article.gmane.org/gmane.comp.version-control.git/167000\n - http://article.gmane.org/gmane.comp.version-control.git/167015\n\n Documentation/git-commit.txt    |    7 +-\n builtin/commit.c                |  155 ++++++++++++++++++++++++++++-----------\n builtin/revert.c                |   56 +--------------\n t/t3507-cherry-pick-conflict.sh |    2 +-\n t/t7509-commit.sh               |   29 +++++++\n wt-status.c                     |    4 +-\n wt-status.h                     |    9 ++-\n 7 files changed, 158 insertions(+), 104 deletions(-)\n\ndiff --git a/Documentation/git-commit.txt b/Documentation/git-commit.txt\nindex b586c0f..fd6a1f7 100644\n--- a/Documentation/git-commit.txt\n+++ b/Documentation/git-commit.txt\n@@ -84,9 +84,10 @@ OPTIONS\n \tlinkgit:git-rebase[1] for details.\n \n --reset-author::\n-\tWhen used with -C/-c/--amend options, declare that the\n-\tauthorship of the resulting commit now belongs of the committer.\n-\tThis also renews the author timestamp.\n+\tWhen used with -C/-c/--amend options, or when committing after a\n+\ta conflicting cherry-pick, declare that the authorship of the\n+\tresulting commit now belongs of the committer. This also renews\n+\tthe author timestamp.\n \n --short::\n \tWhen doing a dry-run, give the output in the short-format. See\ndiff --git a/builtin/commit.c b/builtin/commit.c\nindex 5b32743..af750df 100644\n--- a/builtin/commit.c\n+++ b/builtin/commit.c\n@@ -54,6 +54,13 @@ static const char empty_amend_advice[] =\n \"it empty. You can repeat your command with --allow-empty, or you can\\n\"\n \"remove the commit entirely with \\\"git reset HEAD^\\\".\\n\";\n \n+static const char empty_cherry_pick_advice[] =\n+\"The most recent cherry-pick is empty. If you wish to commit it, use:\\n\"\n+\"\\n\"\n+\"    git commit --allow-empty\\n\"\n+\"\\n\"\n+\"Otherwise, please remove the file %s\\n\";\n+\n static const char commit_editmsg[] = \"COMMIT_EDITMSG\";\n static const char cherry_pick_head[] = \"CHERRY_PICK_HEAD\";\n static const char merge_head[] = \"MERGE_HEAD\";\n@@ -63,7 +70,7 @@ static const char squash_msg[] = \"SQUASH_MSG\";\n \n static unsigned char head_sha1[20];\n \n-static char *use_message_buffer;\n+static const char *use_message_buffer;\n static struct lock_file index_lock; /* real index */\n static struct lock_file false_lock; /* used only for partial commits */\n static enum {\n@@ -74,6 +81,11 @@ static enum {\n \n static const char *logfile, *force_author;\n static const char *template_file;\n+/*\n+ * The _message variables are commit names from which to take\n+ * the commit message and/or authorship.\n+ */\n+static const char *author_message, *author_message_buffer;\n static char *edit_message, *use_message;\n static char *fixup_message, *squash_message;\n static int all, edit_flag, also, interactive, only, amend, signoff;\n@@ -94,7 +106,8 @@ static enum {\n } cleanup_mode;\n static char *cleanup_arg;\n \n-static int use_editor = 1, initial_commit, in_merge, include_status = 1;\n+static enum commit_whence whence;\n+static int use_editor = 1, initial_commit, include_status = 1;\n static int show_ignored_in_status;\n static const char *only_include_assumed;\n static struct strbuf message;\n@@ -169,6 +182,36 @@ static struct option builtin_commit_options[] = {\n \tOPT_END()\n };\n \n+static void determine_whence(struct wt_status *s)\n+{\n+\tif (file_exists(git_path(merge_head)))\n+\t\twhence = FROM_MERGE;\n+\telse if (file_exists(git_path(cherry_pick_head)))\n+\t\twhence = FROM_CHERRY_PICK;\n+\telse\n+\t\twhence = FROM_COMMIT;\n+\tif (s)\n+\t\ts->whence = whence;\n+}\n+\n+static const char *whence_s(void)\n+{\n+\tchar *s = \"\";\n+\n+\tswitch (whence) {\n+\tcase FROM_COMMIT:\n+\t\tbreak;\n+\tcase FROM_MERGE:\n+\t\ts = \"merge\";\n+\t\tbreak;\n+\tcase FROM_CHERRY_PICK:\n+\t\ts = \"cherry-pick\";\n+\t\tbreak;\n+\t}\n+\n+\treturn s;\n+}\n+\n static void rollback_index_files(void)\n {\n \tswitch (commit_style) {\n@@ -384,8 +427,8 @@ static char *prepare_index(int argc, const char **argv, const char *prefix, int\n \t */\n \tcommit_style = COMMIT_PARTIAL;\n \n-\tif (in_merge)\n-\t\tdie(\"cannot do a partial commit during a merge.\");\n+\tif (whence != FROM_COMMIT)\n+\t\tdie(\"cannot do a partial commit during a %s.\", whence_s());\n \n \tmemset(&partial, 0, sizeof(partial));\n \tpartial.strdup_strings = 1;\n@@ -475,18 +518,18 @@ static void determine_author_info(struct strbuf *author_ident)\n \temail = getenv(\"GIT_AUTHOR_EMAIL\");\n \tdate = getenv(\"GIT_AUTHOR_DATE\");\n \n-\tif (use_message && !renew_authorship) {\n+\tif (author_message) {\n \t\tconst char *a, *lb, *rb, *eol;\n \n-\t\ta = strstr(use_message_buffer, \"\\nauthor \");\n+\t\ta = strstr(author_message_buffer, \"\\nauthor \");\n \t\tif (!a)\n-\t\t\tdie(\"invalid commit: %s\", use_message);\n+\t\t\tdie(\"invalid commit: %s\", author_message);\n \n \t\tlb = strchrnul(a + strlen(\"\\nauthor \"), '<');\n \t\trb = strchrnul(lb, '>');\n \t\teol = strchrnul(rb, '\\n');\n \t\tif (!*lb || !*rb || !*eol)\n-\t\t\tdie(\"invalid commit: %s\", use_message);\n+\t\t\tdie(\"invalid commit: %s\", author_message);\n \n \t\tif (lb == a + strlen(\"\\nauthor \"))\n \t\t\t/* \\nauthor <foo@example.com> */\n@@ -647,11 +690,15 @@ static int prepare_to_commit(const char *index_file, const char *prefix,\n \t}\n \n \t/*\n-\t * This final case does not modify the template message,\n-\t * it just sets the argument to the prepare-commit-msg hook.\n+\t * The remaining cases don't modify the template message, but\n+\t * just set the argument(s) to the prepare-commit-msg hook.\n \t */\n-\telse if (in_merge)\n+\telse if (whence == FROM_MERGE)\n \t\thook_arg1 = \"merge\";\n+\telse if (whence == FROM_CHERRY_PICK) {\n+\t\thook_arg1 = \"commit\";\n+\t\thook_arg2 = cherry_pick_head;\n+\t}\n \n \tif (squash_message) {\n \t\t/*\n@@ -700,16 +747,18 @@ static int prepare_to_commit(const char *index_file, const char *prefix,\n \tstrbuf_addstr(&committer_ident, git_committer_info(0));\n \tif (use_editor && include_status) {\n \t\tchar *ai_tmp, *ci_tmp;\n-\t\tif (in_merge)\n+\t\tif (whence != FROM_COMMIT)\n \t\t\tfprintf(fp,\n \t\t\t\t\"#\\n\"\n-\t\t\t\t\"# It looks like you may be committing a MERGE.\\n\"\n+\t\t\t\t\"# It looks like you may be committing a %s.\\n\"\n \t\t\t\t\"# If this is not correct, please remove the file\\n\"\n \t\t\t\t\"#\t%s\\n\"\n \t\t\t\t\"# and try again.\\n\"\n \t\t\t\t\"#\\n\",\n-\t\t\t\tgit_path(merge_head));\n-\n+\t\t\t\twhence_s(),\n+\t\t\t\tgit_path(whence == FROM_MERGE\n+\t\t\t\t\t ? merge_head\n+\t\t\t\t\t : cherry_pick_head));\n \t\tfprintf(fp,\n \t\t\t\"\\n\"\n \t\t\t\"# Please enter the commit message for your changes.\");\n@@ -772,11 +821,19 @@ static int prepare_to_commit(const char *index_file, const char *prefix,\n \n \tfclose(fp);\n \n-\tif (!commitable && !in_merge && !allow_empty &&\n+\t/*\n+\t * Reject an attempt to record a non-merge empty commit without\n+\t * explicit --allow-empty. In the cherry-pick case, it may be\n+\t * empty due to conflict resolution, which the user should okay.\n+\t */\n+\tif (!commitable && whence != FROM_MERGE && !allow_empty &&\n \t    !(amend && is_a_merge(head_sha1))) {\n \t\trun_status(stdout, index_file, prefix, 0, s);\n \t\tif (amend)\n \t\t\tfputs(empty_amend_advice, stderr);\n+\t\telse if (whence == FROM_CHERRY_PICK)\n+\t\t\tfprintf(stderr, empty_cherry_pick_advice,\n+\t\t\t\tgit_path(cherry_pick_head));\n \t\treturn 0;\n \t}\n \n@@ -904,6 +961,28 @@ static void handle_untracked_files_arg(struct wt_status *s)\n \t\tdie(\"Invalid untracked files mode '%s'\", untracked_files_arg);\n }\n \n+static const char *read_commit_message(const char *name)\n+{\n+\tconst char *out_enc, *out;\n+\tstruct commit *commit;\n+\n+\tcommit = lookup_commit_reference_by_name(name);\n+\tif (!commit)\n+\t\tdie(\"could not lookup commit %s\", name);\n+\tout_enc = get_commit_output_encoding();\n+\tout = logmsg_reencode(commit, out_enc);\n+\n+\t/*\n+\t * If we failed to reencode the buffer, just copy it\n+\t * byte for byte so the user can try to fix it up.\n+\t * This also handles the case where input and output\n+\t * encodings are identical.\n+\t */\n+\tif (out == NULL)\n+\t\tout = xstrdup(commit->buffer);\n+\treturn out;\n+}\n+\n static int parse_and_validate_options(int argc, const char *argv[],\n \t\t\t\t      const char * const usage[],\n \t\t\t\t      const char *prefix,\n@@ -933,8 +1012,8 @@ static int parse_and_validate_options(int argc, const char *argv[],\n \t/* Sanity check options */\n \tif (amend && initial_commit)\n \t\tdie(\"You have nothing to amend.\");\n-\tif (amend && in_merge)\n-\t\tdie(\"You are in the middle of a merge -- cannot amend.\");\n+\tif (amend && whence != FROM_COMMIT)\n+\t\tdie(\"You are in the middle of a %s -- cannot amend.\", whence_s());\n \tif (fixup_message && squash_message)\n \t\tdie(\"Options --squash and --fixup cannot be used together\");\n \tif (use_message)\n@@ -953,26 +1032,18 @@ static int parse_and_validate_options(int argc, const char *argv[],\n \t\tuse_message = edit_message;\n \tif (amend && !use_message && !fixup_message)\n \t\tuse_message = \"HEAD\";\n-\tif (!use_message && renew_authorship)\n+\tif (!use_message && whence != FROM_CHERRY_PICK && renew_authorship)\n \t\tdie(\"--reset-author can be used only with -C, -c or --amend.\");\n \tif (use_message) {\n-\t\tconst char *out_enc;\n-\t\tstruct commit *commit;\n-\n-\t\tcommit = lookup_commit_reference_by_name(use_message);\n-\t\tif (!commit)\n-\t\t\tdie(\"could not lookup commit %s\", use_message);\n-\t\tout_enc = get_commit_output_encoding();\n-\t\tuse_message_buffer = logmsg_reencode(commit, out_enc);\n-\n-\t\t/*\n-\t\t * If we failed to reencode the buffer, just copy it\n-\t\t * byte for byte so the user can try to fix it up.\n-\t\t * This also handles the case where input and output\n-\t\t * encodings are identical.\n-\t\t */\n-\t\tif (use_message_buffer == NULL)\n-\t\t\tuse_message_buffer = xstrdup(commit->buffer);\n+\t\tuse_message_buffer = read_commit_message(use_message);\n+\t\tif (!renew_authorship) {\n+\t\t\tauthor_message = use_message;\n+\t\t\tauthor_message_buffer = use_message_buffer;\n+\t\t}\n+\t}\n+\tif (whence == FROM_CHERRY_PICK && !renew_authorship) {\n+\t\tauthor_message = cherry_pick_head;\n+\t\tauthor_message_buffer = read_commit_message(author_message);\n \t}\n \n \tif (!!also + !!only + !!all + !!interactive > 1)\n@@ -1123,7 +1194,7 @@ int cmd_status(int argc, const char **argv, const char *prefix)\n \twt_status_prepare(&s);\n \tgitmodules_config();\n \tgit_config(git_status_config, &s);\n-\tin_merge = file_exists(git_path(merge_head));\n+\tdetermine_whence(&s);\n \targc = parse_options(argc, argv, prefix,\n \t\t\t     builtin_status_options,\n \t\t\t     builtin_status_usage, 0);\n@@ -1146,7 +1217,6 @@ int cmd_status(int argc, const char **argv, const char *prefix)\n \t}\n \n \ts.is_initial = get_sha1(s.reference, sha1) ? 1 : 0;\n-\ts.in_merge = in_merge;\n \ts.ignore_submodule_arg = ignore_submodule_arg;\n \twt_status_collect(&s);\n \n@@ -1308,8 +1378,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)\n \n \twt_status_prepare(&s);\n \tgit_config(git_commit_config, &s);\n-\tin_merge = file_exists(git_path(merge_head));\n-\ts.in_merge = in_merge;\n+\tdetermine_whence(&s);\n \n \tif (s.use_color == -1)\n \t\ts.use_color = git_use_color_default;\n@@ -1346,7 +1415,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)\n \n \t\tfor (c = commit->parents; c; c = c->next)\n \t\t\tpptr = &commit_list_insert(c->item, pptr)->next;\n-\t} else if (in_merge) {\n+\t} else if (whence == FROM_MERGE) {\n \t\tstruct strbuf m = STRBUF_INIT;\n \t\tFILE *fp;\n \n@@ -1375,7 +1444,9 @@ int cmd_commit(int argc, const char **argv, const char *prefix)\n \t\t\tparents = reduce_heads(parents);\n \t} else {\n \t\tif (!reflog_msg)\n-\t\t\treflog_msg = \"commit\";\n+\t\t\treflog_msg = (whence == FROM_CHERRY_PICK)\n+\t\t\t\t\t? \"commit (cherry-pick)\"\n+\t\t\t\t\t: \"commit\";\n \t\tpptr = &commit_list_insert(lookup_commit(head_sha1), pptr)->next;\n \t}\n \ndiff --git a/builtin/revert.c b/builtin/revert.c\nindex fbb465a..2ecc6e1 100644\n--- a/builtin/revert.c\n+++ b/builtin/revert.c\n@@ -3,7 +3,6 @@\n #include \"object.h\"\n #include \"commit.h\"\n #include \"tag.h\"\n-#include \"wt-status.h\"\n #include \"run-command.h\"\n #include \"exec_cmd.h\"\n #include \"utf8.h\"\n@@ -198,56 +197,6 @@ static void add_message_to_msg(struct strbuf *msgbuf, const char *message)\n \tstrbuf_addstr(msgbuf, p);\n }\n \n-static void set_author_ident_env(const char *message)\n-{\n-\tconst char *p = message;\n-\tif (!p)\n-\t\tdie (\"Could not read commit message of %s\",\n-\t\t\t\tsha1_to_hex(commit->object.sha1));\n-\twhile (*p && *p != '\\n') {\n-\t\tconst char *eol;\n-\n-\t\tfor (eol = p; *eol && *eol != '\\n'; eol++)\n-\t\t\t; /* do nothing */\n-\t\tif (!prefixcmp(p, \"author \")) {\n-\t\t\tchar *line, *pend, *email, *timestamp;\n-\n-\t\t\tp += 7;\n-\t\t\tline = xmemdupz(p, eol - p);\n-\t\t\temail = strchr(line, '<');\n-\t\t\tif (!email)\n-\t\t\t\tdie (\"Could not extract author email from %s\",\n-\t\t\t\t\tsha1_to_hex(commit->object.sha1));\n-\t\t\tif (email == line)\n-\t\t\t\tpend = line;\n-\t\t\telse\n-\t\t\t\tfor (pend = email; pend != line + 1 &&\n-\t\t\t\t\t\tisspace(pend[-1]); pend--);\n-\t\t\t\t\t; /* do nothing */\n-\t\t\t*pend = '\\0';\n-\t\t\temail++;\n-\t\t\ttimestamp = strchr(email, '>');\n-\t\t\tif (!timestamp)\n-\t\t\t\tdie (\"Could not extract author time from %s\",\n-\t\t\t\t\tsha1_to_hex(commit->object.sha1));\n-\t\t\t*timestamp = '\\0';\n-\t\t\tfor (timestamp++; *timestamp && isspace(*timestamp);\n-\t\t\t\t\ttimestamp++)\n-\t\t\t\t; /* do nothing */\n-\t\t\tsetenv(\"GIT_AUTHOR_NAME\", line, 1);\n-\t\t\tsetenv(\"GIT_AUTHOR_EMAIL\", email, 1);\n-\t\t\tsetenv(\"GIT_AUTHOR_DATE\", timestamp, 1);\n-\t\t\tfree(line);\n-\t\t\treturn;\n-\t\t}\n-\t\tp = eol;\n-\t\tif (*p == '\\n')\n-\t\t\tp++;\n-\t}\n-\tdie (\"No author information found in %s\",\n-\t\t\tsha1_to_hex(commit->object.sha1));\n-}\n-\n static void write_cherry_pick_head(void)\n {\n \tint fd;\n@@ -290,9 +239,7 @@ static void print_advice(void)\n \n \tadvise(\"after resolving the conflicts, mark the corrected paths\");\n \tadvise(\"with 'git add <paths>' or 'git rm <paths>'\");\n-\n-\tif (action == CHERRY_PICK)\n-\t\tadvise(\"and commit the result with 'git commit -c CHERRY_PICK_HEAD'\");\n+\tadvise(\"and commit the result with 'git commit'\");\n }\n \n static void write_message(struct strbuf *msgbuf, const char *filename)\n@@ -518,7 +465,6 @@ static int do_pick_commit(void)\n \t\tbase_label = msg.parent_label;\n \t\tnext = commit;\n \t\tnext_label = msg.label;\n-\t\tset_author_ident_env(msg.message);\n \t\tadd_message_to_msg(&msgbuf, msg.message);\n \t\tif (no_replay) {\n \t\t\tstrbuf_addstr(&msgbuf, \"(cherry picked from commit \");\ndiff --git a/t/t3507-cherry-pick-conflict.sh b/t/t3507-cherry-pick-conflict.sh\nindex ea52720..3e8d177 100755\n--- a/t/t3507-cherry-pick-conflict.sh\n+++ b/t/t3507-cherry-pick-conflict.sh\n@@ -57,7 +57,7 @@ test_expect_success 'advice from failed cherry-pick' \"\n \terror: could not apply \\$picked... picked\n \thint: after resolving the conflicts, mark the corrected paths\n \thint: with 'git add <paths>' or 'git rm <paths>'\n-\thint: and commit the result with 'git commit -c CHERRY_PICK_HEAD'\n+\thint: and commit the result with 'git commit'\n \tEOF\n \ttest_must_fail git cherry-pick picked 2>actual &&\n \ndiff --git a/t/t7509-commit.sh b/t/t7509-commit.sh\nindex 77b6920..b61fd3c 100755\n--- a/t/t7509-commit.sh\n+++ b/t/t7509-commit.sh\n@@ -157,4 +157,33 @@ test_expect_success '--reset-author should be rejected without -c/-C/--amend' '\n \ttest_must_fail git commit -a --reset-author -m done\n '\n \n+test_expect_success 'commit respects CHERRY_PICK_HEAD and MERGE_MSG' '\n+\techo \"cherry-pick 1a\" >>foo &&\n+\ttest_tick &&\n+\tgit commit -am \"cherry-pick 1\" --author=\"Cherry <cherry@pick.er>\" &&\n+\tgit tag cherry-pick-head &&\n+\tgit rev-parse cherry-pick-head >.git/CHERRY_PICK_HEAD &&\n+\techo \"This is a MERGE_MSG\" >.git/MERGE_MSG &&\n+\techo \"cherry-pick 1b\" >>foo &&\n+\ttest_tick &&\n+\tgit commit -a &&\n+\tauthor_header cherry-pick-head >expect &&\n+\tauthor_header HEAD >actual &&\n+\ttest_cmp expect actual &&\n+\n+\techo \"This is a MERGE_MSG\" >expect &&\n+\tmessage_body HEAD >actual &&\n+\ttest_cmp expect actual\n+'\n+\n+test_expect_success '--reset-author with CHERRY_PICK_HEAD' '\n+\tgit rev-parse cherry-pick-head >.git/CHERRY_PICK_HEAD &&\n+\techo \"cherry-pick 2\" >>foo &&\n+\ttest_tick &&\n+\tgit commit -am \"cherry-pick 2\" --reset-author &&\n+\techo \"author $GIT_AUTHOR_NAME <$GIT_AUTHOR_EMAIL> $GIT_AUTHOR_DATE\" >expect &&\n+\tauthor_header HEAD >actual &&\n+\ttest_cmp expect actual\n+'\n+\n test_done\ndiff --git a/wt-status.c b/wt-status.c\nindex 123582b..fbaaf54 100644\n--- a/wt-status.c\n+++ b/wt-status.c\n@@ -60,7 +60,7 @@ static void wt_status_print_unmerged_header(struct wt_status *s)\n \tcolor_fprintf_ln(s->fp, c, \"# Unmerged paths:\");\n \tif (!advice_status_hints)\n \t\treturn;\n-\tif (s->in_merge)\n+\tif (s->whence != FROM_COMMIT)\n \t\t;\n \telse if (!s->is_initial)\n \t\tcolor_fprintf_ln(s->fp, c, \"#   (use \\\"git reset %s <file>...\\\" to unstage)\", s->reference);\n@@ -77,7 +77,7 @@ static void wt_status_print_cached_header(struct wt_status *s)\n \tcolor_fprintf_ln(s->fp, c, \"# Changes to be committed:\");\n \tif (!advice_status_hints)\n \t\treturn;\n-\tif (s->in_merge)\n+\tif (s->whence != FROM_COMMIT)\n \t\t; /* NEEDSWORK: use \"git reset --unresolve\"??? */\n \telse if (!s->is_initial)\n \t\tcolor_fprintf_ln(s->fp, c, \"#   (use \\\"git reset %s <file>...\\\" to unstage)\", s->reference);\ndiff --git a/wt-status.h b/wt-status.h\nindex 20b17cf..cec482a 100644\n--- a/wt-status.h\n+++ b/wt-status.h\n@@ -24,6 +24,13 @@ enum untracked_status_type {\n \tSHOW_ALL_UNTRACKED_FILES\n };\n \n+/* from where does this commit originate */\n+enum commit_whence {\n+\tFROM_COMMIT,     /* normal */\n+\tFROM_MERGE,      /* commit came from merge */\n+\tFROM_CHERRY_PICK /* commit came from cherry-pick */\n+};\n+\n struct wt_status_change_data {\n \tint worktree_status;\n \tint index_status;\n@@ -40,7 +47,7 @@ struct wt_status {\n \tconst char **pathspec;\n \tint verbose;\n \tint amend;\n-\tint in_merge;\n+\tenum commit_whence whence;\n \tint nowarn;\n \tint use_color;\n \tint relative_paths;\n-- \n1.7.4.1.30.g7fe09\n"},{"id":"161377","messageId":"20110217051919.GA7740@elie","threadId":"26528","inReplyTo":"1297916325-89688-4-git-send-email-jaysoffian@gmail.com","subject":"Re: [PATCH v3 3/4] commit.c: replace some literal strings with constants","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2011-02-17T05:19:19Z","receivedAt":"2011-02-17T05:19:19Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Jay Soffian wrote:\n\n> I converted these per\n> http://article.gmane.org/gmane.comp.version-control.git/167015\n>\n> Maybe this should be the last patch in the series; it's questionable to\n> me whether it's even worth doing.\n\nWhat have I wrought?  I think this makes the code much less readable.\n\n> --- a/builtin/commit.c\n> +++ b/builtin/commit.c\n> @@ -626,13 +632,13 @@ static int prepare_to_commit(const char *index_file, const char *prefix,\n>  \t\tformat_commit_message(commit, \"fixup! %s\\n\\n\",\n>  \t\t\t\t      &sb, &ctx);\n>  \t\thook_arg1 = \"message\";\n> -\t} else if (!stat(git_path(\"MERGE_MSG\"), &statbuf)) {\n> -\t\tif (strbuf_read_file(&sb, git_path(\"MERGE_MSG\"), 0) < 0)\n> -\t\t\tdie_errno(\"could not read MERGE_MSG\");\n> +\t} else if (!stat(git_path(merge_msg), &statbuf)) {\n> +\t\tif (strbuf_read_file(&sb, git_path(merge_msg), 0) < 0)\n> +\t\t\tdie_errno(\"could not read %s\", merge_msg);\n\nSo now a person needs to look earlier in the file to see that\nmerge_msg means \"MERGE_MSG\" rather than being something that\ncan vary.\n\nYes, commit_editmsg has the same problem.  If I get to choose[*] then\ncache.h would contain something like\n\n\t#define MERGE_HEAD_FILE \"MERGE_HEAD\"\n\t#define PREPARED_COMMIT_MESSAGE_FILE \"MERGE_MSG\"\n\t#define <description of SQUASH_MSG goes here> \"SQUASH_MSG\"\n\nand commit.c or cache.h would contain something like\n\n\t#define EDITABLE_COMMIT_MESSAGE_FILE \"COMMIT_EDITMSG\"\n\nand those symbolic names would be used throughout builtin code to\nname those files.  So we would get\n\n (1) documentation of what filenames are special to git, collected\n     in one place\n (2) protection against typos\n\nwithout losing\n\n (3) names that look like constants\n\nJonathan\n\n[*] and I shouldn't!  What I like should matter much less than what is\nright.\n"},{"id":"161379","messageId":"7vlj1fdxcl.fsf@alter.siamese.dyndns.org","threadId":"26528","inReplyTo":"1297916325-89688-4-git-send-email-jaysoffian@gmail.com","subject":"Re: [PATCH v3 3/4] commit.c: replace some literal strings with constants","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2011-02-17T05:49:30Z","receivedAt":"2011-02-17T05:49:30Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jay Soffian <jaysoffian@gmail.com> writes:\n\n> A typo in any of these would be bad, so let's use\n> constants for them\n>\n> Signed-off-by: Jay Soffian <jaysoffian@gmail.com>\n> ---\n> I converted these per\n> http://article.gmane.org/gmane.comp.version-control.git/167015\n>\n> Maybe this should be the last patch in the series; it's questionable to\n> me whether it's even worth doing.\n\nYeah, it's horrible ;-)\n\n> +static const char commit_editmsg[] = \"COMMIT_EDITMSG\";\n> +static const char cherry_pick_head[] = \"CHERRY_PICK_HEAD\";\n> +static const char merge_head[] = \"MERGE_HEAD\";\n> +static const char merge_msg[] = \"MERGE_MSG\";\n> +static const char merge_mode[] = \"MERGE_MODE\";\n> +static const char squash_msg[] = \"SQUASH_MSG\";\n\nIf they were like\n\n\tstatic const char COMMIT_EDITMSG[] = \"...\";\n\nthen that would give us typo-safety while keeping the similarity from\noriginal code.  Uppercase variable names are a bit weird, though.\n"},{"id":"161380","messageId":"1297921850-94962-1-git-send-email-jaysoffian@gmail.com","threadId":"26528","inReplyTo":"20110217051919.GA7740@elie","subject":"[PATCH] Teach commit about CHERRY_PICK_HEAD","fromName":"Jay Soffian","fromEmail":"jaysoffian@gmail.com","sentAt":"2011-02-17T05:50:50Z","receivedAt":"2011-02-17T05:50:50Z","isPatch":true,"sender":{"key":"jaysoffian@gmail.com","avatar":"https://avatars.githubusercontent.com/u/155970?v=4"},"body":"Previously the user was advised to use commit -c CHERRY_PICK_HEAD after\na conflicting cherry-pick. While this would preserve the original\ncommit's authorship, it would sadly discard cherry-pick's carefully\ncrafted MERGE_MSG (which contains the list of conflicts as well as the\noriginal commit-id in the case of cherry-pick -x).\n\nOn the other hand, if a bare 'commit' were performed, it would preserve\nthe MERGE_MSG while resetting the authorship.\n\nIn other words, there was no way to simultaneously take the authorship\nfrom CHERRY_PICK_HEAD and the commit message from MERGE_MSG.\n\nThis change fixes that situation. A bare 'commit' will now take the\nauthorship from CHERRY_PICK_HEAD and the commit message from MERGE_MSG.\nIf the user wishes to reset authorship, that must now be done explicitly\nvia --reset-author.\n\nA side-benefit of passing commit authorship along this way is that we\ncan eliminate redundant authorship parsing code from revert.c.\n\n(Also removed an unused include from revert.c)\n\nSigned-off-by: Jay Soffian <jaysoffian@gmail.com>\n---\nOn Thu, Feb 17, 2011 at 12:19 AM, Jonathan Nieder <jrnieder@gmail.com> wrote:\n\n> What have I wrought?  I think this makes the code much less readable.\n\nI agree. Junio - this is a respin of \"[PATCH v3 4/4] Teach commit about\nCHERRY_PICK_HEAD\" with \"[PATCH v3 3/4] commit.c: replace some literal\nstrings with constants\" dropped.\n\n Documentation/git-commit.txt    |    7 +-\n builtin/commit.c                |  155 ++++++++++++++++++++++++++++-----------\n builtin/revert.c                |   56 +--------------\n t/t3507-cherry-pick-conflict.sh |    2 +-\n t/t7509-commit.sh               |   29 +++++++\n wt-status.c                     |    4 +-\n wt-status.h                     |    9 ++-\n 7 files changed, 158 insertions(+), 104 deletions(-)\n\ndiff --git a/Documentation/git-commit.txt b/Documentation/git-commit.txt\nindex b586c0f..fd6a1f7 100644\n--- a/Documentation/git-commit.txt\n+++ b/Documentation/git-commit.txt\n@@ -84,9 +84,10 @@ OPTIONS\n \tlinkgit:git-rebase[1] for details.\n \n --reset-author::\n-\tWhen used with -C/-c/--amend options, declare that the\n-\tauthorship of the resulting commit now belongs of the committer.\n-\tThis also renews the author timestamp.\n+\tWhen used with -C/-c/--amend options, or when committing after a\n+\ta conflicting cherry-pick, declare that the authorship of the\n+\tresulting commit now belongs of the committer. This also renews\n+\tthe author timestamp.\n \n --short::\n \tWhen doing a dry-run, give the output in the short-format. See\ndiff --git a/builtin/commit.c b/builtin/commit.c\nindex 0def540..0c7b439 100644\n--- a/builtin/commit.c\n+++ b/builtin/commit.c\n@@ -54,9 +54,16 @@ static const char empty_amend_advice[] =\n \"it empty. You can repeat your command with --allow-empty, or you can\\n\"\n \"remove the commit entirely with \\\"git reset HEAD^\\\".\\n\";\n \n+static const char empty_cherry_pick_advice[] =\n+\"The most recent cherry-pick is empty. If you wish to commit it, use:\\n\"\n+\"\\n\"\n+\"    git commit --allow-empty\\n\"\n+\"\\n\"\n+\"Otherwise, please remove the file %s\\n\";\n+\n static unsigned char head_sha1[20];\n \n-static char *use_message_buffer;\n+static const char *use_message_buffer;\n static const char commit_editmsg[] = \"COMMIT_EDITMSG\";\n static struct lock_file index_lock; /* real index */\n static struct lock_file false_lock; /* used only for partial commits */\n@@ -68,6 +75,11 @@ static enum {\n \n static const char *logfile, *force_author;\n static const char *template_file;\n+/*\n+ * The _message variables are commit names from which to take\n+ * the commit message and/or authorship.\n+ */\n+static const char *author_message, *author_message_buffer;\n static char *edit_message, *use_message;\n static char *fixup_message, *squash_message;\n static int all, edit_flag, also, interactive, only, amend, signoff;\n@@ -88,7 +100,8 @@ static enum {\n } cleanup_mode;\n static char *cleanup_arg;\n \n-static int use_editor = 1, initial_commit, in_merge, include_status = 1;\n+static enum commit_whence whence;\n+static int use_editor = 1, initial_commit, include_status = 1;\n static int show_ignored_in_status;\n static const char *only_include_assumed;\n static struct strbuf message;\n@@ -163,6 +176,36 @@ static struct option builtin_commit_options[] = {\n \tOPT_END()\n };\n \n+static void determine_whence(struct wt_status *s)\n+{\n+\tif (file_exists(git_path(\"MERGE_HEAD\")))\n+\t\twhence = FROM_MERGE;\n+\telse if (file_exists(git_path(\"CHERRY_PICK_HEAD\")))\n+\t\twhence = FROM_CHERRY_PICK;\n+\telse\n+\t\twhence = FROM_COMMIT;\n+\tif (s)\n+\t\ts->whence = whence;\n+}\n+\n+static const char *whence_s(void)\n+{\n+\tchar *s = \"\";\n+\n+\tswitch (whence) {\n+\tcase FROM_COMMIT:\n+\t\tbreak;\n+\tcase FROM_MERGE:\n+\t\ts = \"merge\";\n+\t\tbreak;\n+\tcase FROM_CHERRY_PICK:\n+\t\ts = \"cherry-pick\";\n+\t\tbreak;\n+\t}\n+\n+\treturn s;\n+}\n+\n static void rollback_index_files(void)\n {\n \tswitch (commit_style) {\n@@ -378,8 +421,8 @@ static char *prepare_index(int argc, const char **argv, const char *prefix, int\n \t */\n \tcommit_style = COMMIT_PARTIAL;\n \n-\tif (in_merge)\n-\t\tdie(\"cannot do a partial commit during a merge.\");\n+\tif (whence != FROM_COMMIT)\n+\t\tdie(\"cannot do a partial commit during a %s.\", whence_s());\n \n \tmemset(&partial, 0, sizeof(partial));\n \tpartial.strdup_strings = 1;\n@@ -469,18 +512,18 @@ static void determine_author_info(struct strbuf *author_ident)\n \temail = getenv(\"GIT_AUTHOR_EMAIL\");\n \tdate = getenv(\"GIT_AUTHOR_DATE\");\n \n-\tif (use_message && !renew_authorship) {\n+\tif (author_message) {\n \t\tconst char *a, *lb, *rb, *eol;\n \n-\t\ta = strstr(use_message_buffer, \"\\nauthor \");\n+\t\ta = strstr(author_message_buffer, \"\\nauthor \");\n \t\tif (!a)\n-\t\t\tdie(\"invalid commit: %s\", use_message);\n+\t\t\tdie(\"invalid commit: %s\", author_message);\n \n \t\tlb = strchrnul(a + strlen(\"\\nauthor \"), '<');\n \t\trb = strchrnul(lb, '>');\n \t\teol = strchrnul(rb, '\\n');\n \t\tif (!*lb || !*rb || !*eol)\n-\t\t\tdie(\"invalid commit: %s\", use_message);\n+\t\t\tdie(\"invalid commit: %s\", author_message);\n \n \t\tif (lb == a + strlen(\"\\nauthor \"))\n \t\t\t/* \\nauthor <foo@example.com> */\n@@ -641,11 +684,15 @@ static int prepare_to_commit(const char *index_file, const char *prefix,\n \t}\n \n \t/*\n-\t * This final case does not modify the template message,\n-\t * it just sets the argument to the prepare-commit-msg hook.\n+\t * The remaining cases don't modify the template message, but\n+\t * just set the argument(s) to the prepare-commit-msg hook.\n \t */\n-\telse if (in_merge)\n+\telse if (whence == FROM_MERGE)\n \t\thook_arg1 = \"merge\";\n+\telse if (whence == FROM_CHERRY_PICK) {\n+\t\thook_arg1 = \"commit\";\n+\t\thook_arg2 = \"CHERRY_PICK_HEAD\";\n+\t}\n \n \tif (squash_message) {\n \t\t/*\n@@ -694,16 +741,18 @@ static int prepare_to_commit(const char *index_file, const char *prefix,\n \tstrbuf_addstr(&committer_ident, git_committer_info(0));\n \tif (use_editor && include_status) {\n \t\tchar *ai_tmp, *ci_tmp;\n-\t\tif (in_merge)\n+\t\tif (whence != FROM_COMMIT)\n \t\t\tfprintf(fp,\n \t\t\t\t\"#\\n\"\n-\t\t\t\t\"# It looks like you may be committing a MERGE.\\n\"\n+\t\t\t\t\"# It looks like you may be committing a %s.\\n\"\n \t\t\t\t\"# If this is not correct, please remove the file\\n\"\n \t\t\t\t\"#\t%s\\n\"\n \t\t\t\t\"# and try again.\\n\"\n \t\t\t\t\"#\\n\",\n-\t\t\t\tgit_path(\"MERGE_HEAD\"));\n-\n+\t\t\t\twhence_s(),\n+\t\t\t\tgit_path(whence == FROM_MERGE\n+\t\t\t\t\t ? \"MERGE_HEAD\"\n+\t\t\t\t\t : \"CHERRY_PICK_HEAD\"));\n \t\tfprintf(fp,\n \t\t\t\"\\n\"\n \t\t\t\"# Please enter the commit message for your changes.\");\n@@ -766,11 +815,19 @@ static int prepare_to_commit(const char *index_file, const char *prefix,\n \n \tfclose(fp);\n \n-\tif (!commitable && !in_merge && !allow_empty &&\n+\t/*\n+\t * Reject an attempt to record a non-merge empty commit without\n+\t * explicit --allow-empty. In the cherry-pick case, it may be\n+\t * empty due to conflict resolution, which the user should okay.\n+\t */\n+\tif (!commitable && whence != FROM_MERGE && !allow_empty &&\n \t    !(amend && is_a_merge(head_sha1))) {\n \t\trun_status(stdout, index_file, prefix, 0, s);\n \t\tif (amend)\n \t\t\tfputs(empty_amend_advice, stderr);\n+\t\telse if (whence == FROM_CHERRY_PICK)\n+\t\t\tfprintf(stderr, empty_cherry_pick_advice,\n+\t\t\t\tgit_path(\"CHERRY_PICK_HEAD\"));\n \t\treturn 0;\n \t}\n \n@@ -898,6 +955,28 @@ static void handle_untracked_files_arg(struct wt_status *s)\n \t\tdie(\"Invalid untracked files mode '%s'\", untracked_files_arg);\n }\n \n+static const char *read_commit_message(const char *name)\n+{\n+\tconst char *out_enc, *out;\n+\tstruct commit *commit;\n+\n+\tcommit = lookup_commit_reference_by_name(name);\n+\tif (!commit)\n+\t\tdie(\"could not lookup commit %s\", name);\n+\tout_enc = get_commit_output_encoding();\n+\tout = logmsg_reencode(commit, out_enc);\n+\n+\t/*\n+\t * If we failed to reencode the buffer, just copy it\n+\t * byte for byte so the user can try to fix it up.\n+\t * This also handles the case where input and output\n+\t * encodings are identical.\n+\t */\n+\tif (out == NULL)\n+\t\tout = xstrdup(commit->buffer);\n+\treturn out;\n+}\n+\n static int parse_and_validate_options(int argc, const char *argv[],\n \t\t\t\t      const char * const usage[],\n \t\t\t\t      const char *prefix,\n@@ -927,8 +1006,8 @@ static int parse_and_validate_options(int argc, const char *argv[],\n \t/* Sanity check options */\n \tif (amend && initial_commit)\n \t\tdie(\"You have nothing to amend.\");\n-\tif (amend && in_merge)\n-\t\tdie(\"You are in the middle of a merge -- cannot amend.\");\n+\tif (amend && whence != FROM_COMMIT)\n+\t\tdie(\"You are in the middle of a %s -- cannot amend.\", whence_s());\n \tif (fixup_message && squash_message)\n \t\tdie(\"Options --squash and --fixup cannot be used together\");\n \tif (use_message)\n@@ -947,26 +1026,18 @@ static int parse_and_validate_options(int argc, const char *argv[],\n \t\tuse_message = edit_message;\n \tif (amend && !use_message && !fixup_message)\n \t\tuse_message = \"HEAD\";\n-\tif (!use_message && renew_authorship)\n+\tif (!use_message && whence != FROM_CHERRY_PICK && renew_authorship)\n \t\tdie(\"--reset-author can be used only with -C, -c or --amend.\");\n \tif (use_message) {\n-\t\tconst char *out_enc;\n-\t\tstruct commit *commit;\n-\n-\t\tcommit = lookup_commit_reference_by_name(use_message);\n-\t\tif (!commit)\n-\t\t\tdie(\"could not lookup commit %s\", use_message);\n-\t\tout_enc = get_commit_output_encoding();\n-\t\tuse_message_buffer = logmsg_reencode(commit, out_enc);\n-\n-\t\t/*\n-\t\t * If we failed to reencode the buffer, just copy it\n-\t\t * byte for byte so the user can try to fix it up.\n-\t\t * This also handles the case where input and output\n-\t\t * encodings are identical.\n-\t\t */\n-\t\tif (use_message_buffer == NULL)\n-\t\t\tuse_message_buffer = xstrdup(commit->buffer);\n+\t\tuse_message_buffer = read_commit_message(use_message);\n+\t\tif (!renew_authorship) {\n+\t\t\tauthor_message = use_message;\n+\t\t\tauthor_message_buffer = use_message_buffer;\n+\t\t}\n+\t}\n+\tif (whence == FROM_CHERRY_PICK && !renew_authorship) {\n+\t\tauthor_message = \"CHERRY_PICK_HEAD\";\n+\t\tauthor_message_buffer = read_commit_message(author_message);\n \t}\n \n \tif (!!also + !!only + !!all + !!interactive > 1)\n@@ -1117,7 +1188,7 @@ int cmd_status(int argc, const char **argv, const char *prefix)\n \twt_status_prepare(&s);\n \tgitmodules_config();\n \tgit_config(git_status_config, &s);\n-\tin_merge = file_exists(git_path(\"MERGE_HEAD\"));\n+\tdetermine_whence(&s);\n \targc = parse_options(argc, argv, prefix,\n \t\t\t     builtin_status_options,\n \t\t\t     builtin_status_usage, 0);\n@@ -1140,7 +1211,6 @@ int cmd_status(int argc, const char **argv, const char *prefix)\n \t}\n \n \ts.is_initial = get_sha1(s.reference, sha1) ? 1 : 0;\n-\ts.in_merge = in_merge;\n \ts.ignore_submodule_arg = ignore_submodule_arg;\n \twt_status_collect(&s);\n \n@@ -1302,8 +1372,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)\n \n \twt_status_prepare(&s);\n \tgit_config(git_commit_config, &s);\n-\tin_merge = file_exists(git_path(\"MERGE_HEAD\"));\n-\ts.in_merge = in_merge;\n+\tdetermine_whence(&s);\n \n \tif (s.use_color == -1)\n \t\ts.use_color = git_use_color_default;\n@@ -1340,7 +1409,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)\n \n \t\tfor (c = commit->parents; c; c = c->next)\n \t\t\tpptr = &commit_list_insert(c->item, pptr)->next;\n-\t} else if (in_merge) {\n+\t} else if (whence == FROM_MERGE) {\n \t\tstruct strbuf m = STRBUF_INIT;\n \t\tFILE *fp;\n \n@@ -1369,7 +1438,9 @@ int cmd_commit(int argc, const char **argv, const char *prefix)\n \t\t\tparents = reduce_heads(parents);\n \t} else {\n \t\tif (!reflog_msg)\n-\t\t\treflog_msg = \"commit\";\n+\t\t\treflog_msg = (whence == FROM_CHERRY_PICK)\n+\t\t\t\t\t? \"commit (cherry-pick)\"\n+\t\t\t\t\t: \"commit\";\n \t\tpptr = &commit_list_insert(lookup_commit(head_sha1), pptr)->next;\n \t}\n \ndiff --git a/builtin/revert.c b/builtin/revert.c\nindex fbb465a..2ecc6e1 100644\n--- a/builtin/revert.c\n+++ b/builtin/revert.c\n@@ -3,7 +3,6 @@\n #include \"object.h\"\n #include \"commit.h\"\n #include \"tag.h\"\n-#include \"wt-status.h\"\n #include \"run-command.h\"\n #include \"exec_cmd.h\"\n #include \"utf8.h\"\n@@ -198,56 +197,6 @@ static void add_message_to_msg(struct strbuf *msgbuf, const char *message)\n \tstrbuf_addstr(msgbuf, p);\n }\n \n-static void set_author_ident_env(const char *message)\n-{\n-\tconst char *p = message;\n-\tif (!p)\n-\t\tdie (\"Could not read commit message of %s\",\n-\t\t\t\tsha1_to_hex(commit->object.sha1));\n-\twhile (*p && *p != '\\n') {\n-\t\tconst char *eol;\n-\n-\t\tfor (eol = p; *eol && *eol != '\\n'; eol++)\n-\t\t\t; /* do nothing */\n-\t\tif (!prefixcmp(p, \"author \")) {\n-\t\t\tchar *line, *pend, *email, *timestamp;\n-\n-\t\t\tp += 7;\n-\t\t\tline = xmemdupz(p, eol - p);\n-\t\t\temail = strchr(line, '<');\n-\t\t\tif (!email)\n-\t\t\t\tdie (\"Could not extract author email from %s\",\n-\t\t\t\t\tsha1_to_hex(commit->object.sha1));\n-\t\t\tif (email == line)\n-\t\t\t\tpend = line;\n-\t\t\telse\n-\t\t\t\tfor (pend = email; pend != line + 1 &&\n-\t\t\t\t\t\tisspace(pend[-1]); pend--);\n-\t\t\t\t\t; /* do nothing */\n-\t\t\t*pend = '\\0';\n-\t\t\temail++;\n-\t\t\ttimestamp = strchr(email, '>');\n-\t\t\tif (!timestamp)\n-\t\t\t\tdie (\"Could not extract author time from %s\",\n-\t\t\t\t\tsha1_to_hex(commit->object.sha1));\n-\t\t\t*timestamp = '\\0';\n-\t\t\tfor (timestamp++; *timestamp && isspace(*timestamp);\n-\t\t\t\t\ttimestamp++)\n-\t\t\t\t; /* do nothing */\n-\t\t\tsetenv(\"GIT_AUTHOR_NAME\", line, 1);\n-\t\t\tsetenv(\"GIT_AUTHOR_EMAIL\", email, 1);\n-\t\t\tsetenv(\"GIT_AUTHOR_DATE\", timestamp, 1);\n-\t\t\tfree(line);\n-\t\t\treturn;\n-\t\t}\n-\t\tp = eol;\n-\t\tif (*p == '\\n')\n-\t\t\tp++;\n-\t}\n-\tdie (\"No author information found in %s\",\n-\t\t\tsha1_to_hex(commit->object.sha1));\n-}\n-\n static void write_cherry_pick_head(void)\n {\n \tint fd;\n@@ -290,9 +239,7 @@ static void print_advice(void)\n \n \tadvise(\"after resolving the conflicts, mark the corrected paths\");\n \tadvise(\"with 'git add <paths>' or 'git rm <paths>'\");\n-\n-\tif (action == CHERRY_PICK)\n-\t\tadvise(\"and commit the result with 'git commit -c CHERRY_PICK_HEAD'\");\n+\tadvise(\"and commit the result with 'git commit'\");\n }\n \n static void write_message(struct strbuf *msgbuf, const char *filename)\n@@ -518,7 +465,6 @@ static int do_pick_commit(void)\n \t\tbase_label = msg.parent_label;\n \t\tnext = commit;\n \t\tnext_label = msg.label;\n-\t\tset_author_ident_env(msg.message);\n \t\tadd_message_to_msg(&msgbuf, msg.message);\n \t\tif (no_replay) {\n \t\t\tstrbuf_addstr(&msgbuf, \"(cherry picked from commit \");\ndiff --git a/t/t3507-cherry-pick-conflict.sh b/t/t3507-cherry-pick-conflict.sh\nindex ea52720..3e8d177 100755\n--- a/t/t3507-cherry-pick-conflict.sh\n+++ b/t/t3507-cherry-pick-conflict.sh\n@@ -57,7 +57,7 @@ test_expect_success 'advice from failed cherry-pick' \"\n \terror: could not apply \\$picked... picked\n \thint: after resolving the conflicts, mark the corrected paths\n \thint: with 'git add <paths>' or 'git rm <paths>'\n-\thint: and commit the result with 'git commit -c CHERRY_PICK_HEAD'\n+\thint: and commit the result with 'git commit'\n \tEOF\n \ttest_must_fail git cherry-pick picked 2>actual &&\n \ndiff --git a/t/t7509-commit.sh b/t/t7509-commit.sh\nindex 77b6920..b61fd3c 100755\n--- a/t/t7509-commit.sh\n+++ b/t/t7509-commit.sh\n@@ -157,4 +157,33 @@ test_expect_success '--reset-author should be rejected without -c/-C/--amend' '\n \ttest_must_fail git commit -a --reset-author -m done\n '\n \n+test_expect_success 'commit respects CHERRY_PICK_HEAD and MERGE_MSG' '\n+\techo \"cherry-pick 1a\" >>foo &&\n+\ttest_tick &&\n+\tgit commit -am \"cherry-pick 1\" --author=\"Cherry <cherry@pick.er>\" &&\n+\tgit tag cherry-pick-head &&\n+\tgit rev-parse cherry-pick-head >.git/CHERRY_PICK_HEAD &&\n+\techo \"This is a MERGE_MSG\" >.git/MERGE_MSG &&\n+\techo \"cherry-pick 1b\" >>foo &&\n+\ttest_tick &&\n+\tgit commit -a &&\n+\tauthor_header cherry-pick-head >expect &&\n+\tauthor_header HEAD >actual &&\n+\ttest_cmp expect actual &&\n+\n+\techo \"This is a MERGE_MSG\" >expect &&\n+\tmessage_body HEAD >actual &&\n+\ttest_cmp expect actual\n+'\n+\n+test_expect_success '--reset-author with CHERRY_PICK_HEAD' '\n+\tgit rev-parse cherry-pick-head >.git/CHERRY_PICK_HEAD &&\n+\techo \"cherry-pick 2\" >>foo &&\n+\ttest_tick &&\n+\tgit commit -am \"cherry-pick 2\" --reset-author &&\n+\techo \"author $GIT_AUTHOR_NAME <$GIT_AUTHOR_EMAIL> $GIT_AUTHOR_DATE\" >expect &&\n+\tauthor_header HEAD >actual &&\n+\ttest_cmp expect actual\n+'\n+\n test_done\ndiff --git a/wt-status.c b/wt-status.c\nindex 123582b..fbaaf54 100644\n--- a/wt-status.c\n+++ b/wt-status.c\n@@ -60,7 +60,7 @@ static void wt_status_print_unmerged_header(struct wt_status *s)\n \tcolor_fprintf_ln(s->fp, c, \"# Unmerged paths:\");\n \tif (!advice_status_hints)\n \t\treturn;\n-\tif (s->in_merge)\n+\tif (s->whence != FROM_COMMIT)\n \t\t;\n \telse if (!s->is_initial)\n \t\tcolor_fprintf_ln(s->fp, c, \"#   (use \\\"git reset %s <file>...\\\" to unstage)\", s->reference);\n@@ -77,7 +77,7 @@ static void wt_status_print_cached_header(struct wt_status *s)\n \tcolor_fprintf_ln(s->fp, c, \"# Changes to be committed:\");\n \tif (!advice_status_hints)\n \t\treturn;\n-\tif (s->in_merge)\n+\tif (s->whence != FROM_COMMIT)\n \t\t; /* NEEDSWORK: use \"git reset --unresolve\"??? */\n \telse if (!s->is_initial)\n \t\tcolor_fprintf_ln(s->fp, c, \"#   (use \\\"git reset %s <file>...\\\" to unstage)\", s->reference);\ndiff --git a/wt-status.h b/wt-status.h\nindex 20b17cf..cec482a 100644\n--- a/wt-status.h\n+++ b/wt-status.h\n@@ -24,6 +24,13 @@ enum untracked_status_type {\n \tSHOW_ALL_UNTRACKED_FILES\n };\n \n+/* from where does this commit originate */\n+enum commit_whence {\n+\tFROM_COMMIT,     /* normal */\n+\tFROM_MERGE,      /* commit came from merge */\n+\tFROM_CHERRY_PICK /* commit came from cherry-pick */\n+};\n+\n struct wt_status_change_data {\n \tint worktree_status;\n \tint index_status;\n@@ -40,7 +47,7 @@ struct wt_status {\n \tconst char **pathspec;\n \tint verbose;\n \tint amend;\n-\tint in_merge;\n+\tenum commit_whence whence;\n \tint nowarn;\n \tint use_color;\n \tint relative_paths;\n-- \n1.7.4.1.29.g21713\n"},{"id":"161445","messageId":"7vipwibfc5.fsf@alter.siamese.dyndns.org","threadId":"26528","inReplyTo":"1297916325-89688-2-git-send-email-jaysoffian@gmail.com","subject":"Re: [PATCH v3 1/4] Introduce CHERRY_PICK_HEAD","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2011-02-17T20:01:30Z","receivedAt":"2011-02-17T20:01:30Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jay Soffian <jaysoffian@gmail.com> writes:\n\n> diff --git a/builtin/merge.c b/builtin/merge.c\n> index 9403747..454dad2 100644\n> --- a/builtin/merge.c\n> +++ b/builtin/merge.c\n> @@ -971,6 +971,13 @@ int cmd_merge(int argc, const char **argv, const char *prefix)\n>  \t\telse\n>  \t\t\tdie(\"You have not concluded your merge (MERGE_HEAD exists).\");\n>  \t}\n> +\tif (file_exists(git_path(\"CHERRY_PICK_HEAD\"))) {\n> +\t\tif (advice_resolve_conflict)\n> +\t\t\tdie(\"You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists).\\n\"\n> +\t\t\t    \"Please, commit your changes before you can merge.\");\n> +\t\telse\n> +\t\t\tdie(\"You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists).\");\n> +\t}\n\nMicronit: \"Please, commit your changes before you can merge.\"\n\n - We are not merging in this codepath to begin with;\n\n - I'd suggest rephrasing this (together with \"MERGE_HEAD\" codepath) to\n   something like:\n\n\t\"Commit your changes first before retrying.\"\n\n> +test_expect_success 'cherry-pick --no-commit sets CHERRY_PICK_HEAD' '\n> +\n> +\tgit checkout -f initial^0 &&\n> +\tgit read-tree -u --reset HEAD &&\n> +\tgit clean -d -f -f -q -x &&\n> +\n> +\tgit update-index --refresh &&\n> +\tgit diff-index --exit-code HEAD &&\n\nGetting tired of seeing these five lines repeated over and over.  Perhaps\nit is time to introduce:\n\n\tpristine_detach () {\n        \tgit checkout -f \"$1^0\" &&\n                git read-tree -u --reset HEAD &&\n                git clean -d -f -f -q -x\n\t}\n\nI don't think \"diff-index --exit-code HEAD\" is necessary as the point of\nthis testsuite is not about testing \"read-tree --reset\", and the index\nrefresh is just a prerequisite for diff-index that can go together with\nit.\n\n> +\tgit cherry-pick --no-commit base &&\n> +\n> +\ttest_cmp_rev base CHERRY_PICK_HEAD\n\nIf the next \"git commit\" would notice and use this information, that would\nintroduce an unpleasant regression to one use case in my workflow, which\nis to pick and consolidate one or more small pieces made on a private\n\"misc\" branch, possibly with a bit of further work, into a new commit with\na readable explanation that is unrelated to any of the original commits:\n\n\tgit cherry-pick --no-commit $some_commit\n\tgit cherry-pick --no-commit $another_commit ;# optional\n\tedit ;# optional\n        git commit\n\nI'd prefer to see a way to tell cherry-pick not to leave CHERRY_PICK_HEAD\nbehind when \"cherry-pick --no-commit\" results in a successful cherry-pick\nto avoid a backward incompatibility surprise.  Otherwise people need to\nretrain their fingers to say --reset-author when they run \"git commit\".\n\nOther then the above three points, this patch looks good.  Thanks.\n"},{"id":"161462","messageId":"7v39nm9vgv.fsf@alter.siamese.dyndns.org","threadId":"26528","inReplyTo":"1297916325-89688-2-git-send-email-jaysoffian@gmail.com","subject":"Re: [PATCH v3 1/4] Introduce CHERRY_PICK_HEAD","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2011-02-17T21:56:00Z","receivedAt":"2011-02-17T21:56:00Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"This series in 'pu' seems to break t3404#16.\n"},{"id":"161465","messageId":"20110217223216.GB10007@elie","threadId":"26528","inReplyTo":"7vipwibfc5.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH v3 1/4] Introduce CHERRY_PICK_HEAD","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2011-02-17T22:32:16Z","receivedAt":"2011-02-17T22:32:16Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Junio C Hamano wrote:\n> Jay Soffian <jaysoffian@gmail.com> writes:\n\n>> +test_expect_success 'cherry-pick --no-commit sets CHERRY_PICK_HEAD' '\n>> +\n>> +\tgit checkout -f initial^0 &&\n>> +\tgit read-tree -u --reset HEAD &&\n>> +\tgit clean -d -f -f -q -x &&\n>> +\n>> +\tgit update-index --refresh &&\n>> +\tgit diff-index --exit-code HEAD &&\n>\n> Getting tired of seeing these five lines repeated over and over.  Perhaps\n> it is time to introduce:\n> \n> \tpristine_detach () {\n\nThe following patch (modulo naming) was sitting in my tree as a separate\npatch on top.\n\n> I don't think \"diff-index --exit-code HEAD\" is necessary as the point of\n> this testsuite is not about testing \"read-tree --reset\", and the index\n> refresh is just a prerequisite for diff-index that can go together with\n> it.\n\nYep.  Confusingly, the index refresh was just meant to check for a\nclean index.\n\n-- 8< --\nSubject: [PATCH] tests: introduce pristine-detach helper\n\nAll the tests in t3507 (cherry-pick with conflicts) begin with the\nsame checkout + read-tree + clean incantation to ensure a predictable\nstarting point.  Factor out a function for that so the interesting\npart of the tests is easier to read.\n\nThe \"update-index --refresh\" and \"diff-index --exit-code HEAD\" are not\nnecessary as the point of this testsuite is not about testing\n\"read-tree --reset\".\n\nImproved-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Jonathan Nieder <jrnieder@gmail.com>\n---\nApplies on top of the CHERRY_PICK_HEAD tests.\n\n t/t3507-cherry-pick-conflict.sh |  142 +++++++--------------------------------\n 1 files changed, 24 insertions(+), 118 deletions(-)\n\ndiff --git a/t/t3507-cherry-pick-conflict.sh b/t/t3507-cherry-pick-conflict.sh\nindex ea52720..2d8437e 100755\n--- a/t/t3507-cherry-pick-conflict.sh\n+++ b/t/t3507-cherry-pick-conflict.sh\n@@ -17,6 +17,12 @@ test_cmp_rev () {\n \ttest_cmp expect.rev actual.rev\n }\n \n+pristine_detach () {\n+\tgit checkout -f \"$1^0\" &&\n+\tgit read-tree -u --reset HEAD &&\n+\tgit clean -d -f -f -q -x\n+}\n+\n test_expect_success setup '\n \n \techo unrelated >unrelated &&\n@@ -29,13 +35,7 @@ test_expect_success setup '\n '\n \n test_expect_success 'failed cherry-pick does not advance HEAD' '\n-\n-\tgit checkout -f initial^0 &&\n-\tgit read-tree -u --reset HEAD &&\n-\tgit clean -d -f -f -q -x &&\n-\n-\tgit update-index --refresh &&\n-\tgit diff-index --exit-code HEAD &&\n+\tpristine_detach initial &&\n \n \thead=$(git rev-parse HEAD) &&\n \ttest_must_fail git cherry-pick picked &&\n@@ -45,12 +45,7 @@ test_expect_success 'failed cherry-pick does not advance HEAD' '\n '\n \n test_expect_success 'advice from failed cherry-pick' \"\n-\tgit checkout -f initial^0 &&\n-\tgit read-tree -u --reset HEAD &&\n-\tgit clean -d -f -f -q -x &&\n-\n-\tgit update-index --refresh &&\n-\tgit diff-index --exit-code HEAD &&\n+\tpristine_detach initial &&\n \n \tpicked=\\$(git rev-parse --short picked) &&\n \tcat <<-EOF >expected &&\n@@ -65,73 +60,35 @@ test_expect_success 'advice from failed cherry-pick' \"\n \"\n \n test_expect_success 'failed cherry-pick sets CHERRY_PICK_HEAD' '\n-\n-\tgit checkout -f initial^0 &&\n-\tgit read-tree -u --reset HEAD &&\n-\tgit clean -d -f -f -q -x &&\n-\n-\tgit update-index --refresh &&\n-\tgit diff-index --exit-code HEAD &&\n-\n+\tpristine_detach initial &&\n \ttest_must_fail git cherry-pick picked &&\n-\n \ttest_cmp_rev picked CHERRY_PICK_HEAD\n '\n \n test_expect_success 'successful cherry-pick does not set CHERRY_PICK_HEAD' '\n-\n-\tgit checkout -f initial^0 &&\n-\tgit read-tree -u --reset HEAD &&\n-\tgit clean -d -f -f -q -x &&\n-\n-\tgit update-index --refresh &&\n-\tgit diff-index --exit-code HEAD &&\n-\n+\tpristine_detach initial &&\n \tgit cherry-pick base &&\n-\n \ttest_must_fail git rev-parse --verify CHERRY_PICK_HEAD\n '\n \n test_expect_success 'cherry-pick --no-commit sets CHERRY_PICK_HEAD' '\n-\n-\tgit checkout -f initial^0 &&\n-\tgit read-tree -u --reset HEAD &&\n-\tgit clean -d -f -f -q -x &&\n-\n-\tgit update-index --refresh &&\n-\tgit diff-index --exit-code HEAD &&\n-\n+\tpristine_detach initial &&\n \tgit cherry-pick --no-commit base &&\n-\n \ttest_cmp_rev base CHERRY_PICK_HEAD\n '\n \n test_expect_success 'GIT_CHERRY_PICK_HELP suppresses CHERRY_PICK_HEAD' '\n-\n-\tgit checkout -f initial^0 &&\n-\tgit read-tree -u --reset HEAD &&\n-\tgit clean -d -f -f -q -x &&\n-\n-\tgit update-index --refresh &&\n-\tgit diff-index --exit-code HEAD &&\n-\n+\tpristine_detach initial &&\n \t(\n \t\tGIT_CHERRY_PICK_HELP=\"and then do something else\" &&\n \t\texport GIT_CHERRY_PICK_HELP &&\n \t\ttest_must_fail git cherry-pick picked\n \t) &&\n-\n \ttest_must_fail git rev-parse --verify CHERRY_PICK_HEAD\n '\n \n test_expect_success 'git reset clears CHERRY_PICK_HEAD' '\n-\n-\tgit checkout -f initial^0 &&\n-\tgit read-tree -u --reset HEAD &&\n-\tgit clean -d -f -f -q -x &&\n-\n-\tgit update-index --refresh &&\n-\tgit diff-index --exit-code HEAD &&\n+\tpristine_detach initial &&\n \n \ttest_must_fail git cherry-pick picked &&\n \tgit reset &&\n@@ -140,13 +97,7 @@ test_expect_success 'git reset clears CHERRY_PICK_HEAD' '\n '\n \n test_expect_success 'failed commit does not clear CHERRY_PICK_HEAD' '\n-\n-\tgit checkout -f initial^0 &&\n-\tgit read-tree -u --reset HEAD &&\n-\tgit clean -d -f -f -q -x &&\n-\n-\tgit update-index --refresh &&\n-\tgit diff-index --exit-code HEAD &&\n+\tpristine_detach initial &&\n \n \ttest_must_fail git cherry-pick picked &&\n \ttest_must_fail git commit &&\n@@ -155,13 +106,7 @@ test_expect_success 'failed commit does not clear CHERRY_PICK_HEAD' '\n '\n \n test_expect_success 'cancelled commit does not clear CHERRY_PICK_HEAD' '\n-\n-\tgit checkout -f initial^0 &&\n-\tgit read-tree -u --reset HEAD &&\n-\tgit clean -d -f -f -q -x &&\n-\n-\tgit update-index --refresh &&\n-\tgit diff-index --exit-code HEAD &&\n+\tpristine_detach initial &&\n \n \ttest_must_fail git cherry-pick picked &&\n \techo resolved >foo &&\n@@ -178,13 +123,7 @@ test_expect_success 'cancelled commit does not clear CHERRY_PICK_HEAD' '\n '\n \n test_expect_success 'successful commit clears CHERRY_PICK_HEAD' '\n-\n-\tgit checkout -f initial^0 &&\n-\tgit read-tree -u --reset HEAD &&\n-\tgit clean -d -f -f -q -x &&\n-\n-\tgit update-index --refresh &&\n-\tgit diff-index --exit-code HEAD &&\n+\tpristine_detach initial &&\n \n \ttest_must_fail git cherry-pick picked &&\n \techo resolved >foo &&\n@@ -195,13 +134,7 @@ test_expect_success 'successful commit clears CHERRY_PICK_HEAD' '\n '\n \n test_expect_success 'failed cherry-pick produces dirty index' '\n-\n-\tgit checkout -f initial^0 &&\n-\tgit read-tree -u --reset HEAD &&\n-\tgit clean -d -f -f -q -x &&\n-\n-\tgit update-index --refresh &&\n-\tgit diff-index --exit-code HEAD &&\n+\tpristine_detach initial &&\n \n \ttest_must_fail git cherry-pick picked &&\n \n@@ -210,9 +143,7 @@ test_expect_success 'failed cherry-pick produces dirty index' '\n '\n \n test_expect_success 'failed cherry-pick registers participants in index' '\n-\n-\tgit read-tree -u --reset HEAD &&\n-\tgit clean -d -f -f -q -x &&\n+\tpristine_detach initial &&\n \t{\n \t\tgit checkout base -- foo &&\n \t\tgit ls-files --stage foo &&\n@@ -226,10 +157,7 @@ test_expect_success 'failed cherry-pick registers participants in index' '\n \t\t2 s/ 0\t/ 2\t/\n \t\t3 s/ 0\t/ 3\t/\n \t\" < stages > expected &&\n-\tgit checkout -f initial^0 &&\n-\n-\tgit update-index --refresh &&\n-\tgit diff-index --exit-code HEAD &&\n+\tgit read-tree -u --reset HEAD &&\n \n \ttest_must_fail git cherry-pick picked &&\n \tgit ls-files --stage --unmerged > actual &&\n@@ -238,10 +166,7 @@ test_expect_success 'failed cherry-pick registers participants in index' '\n '\n \n test_expect_success 'failed cherry-pick describes conflict in work tree' '\n-\n-\tgit checkout -f initial^0 &&\n-\tgit read-tree -u --reset HEAD &&\n-\tgit clean -d -f -f -q -x &&\n+\tpristine_detach initial &&\n \tcat <<-EOF > expected &&\n \t<<<<<<< HEAD\n \ta\n@@ -250,9 +175,6 @@ test_expect_success 'failed cherry-pick describes conflict in work tree' '\n \t>>>>>>> objid picked\n \tEOF\n \n-\tgit update-index --refresh &&\n-\tgit diff-index --exit-code HEAD &&\n-\n \ttest_must_fail git cherry-pick picked &&\n \n \tsed \"s/[a-f0-9]*\\.\\.\\./objid/\" foo > actual &&\n@@ -260,11 +182,8 @@ test_expect_success 'failed cherry-pick describes conflict in work tree' '\n '\n \n test_expect_success 'diff3 -m style' '\n-\n+\tpristine_detach initial &&\n \tgit config merge.conflictstyle diff3 &&\n-\tgit checkout -f initial^0 &&\n-\tgit read-tree -u --reset HEAD &&\n-\tgit clean -d -f -f -q -x &&\n \tcat <<-EOF > expected &&\n \t<<<<<<< HEAD\n \ta\n@@ -275,9 +194,6 @@ test_expect_success 'diff3 -m style' '\n \t>>>>>>> objid picked\n \tEOF\n \n-\tgit update-index --refresh &&\n-\tgit diff-index --exit-code HEAD &&\n-\n \ttest_must_fail git cherry-pick picked &&\n \n \tsed \"s/[a-f0-9]*\\.\\.\\./objid/\" foo > actual &&\n@@ -285,10 +201,8 @@ test_expect_success 'diff3 -m style' '\n '\n \n test_expect_success 'revert also handles conflicts sanely' '\n-\n \tgit config --unset merge.conflictstyle &&\n-\tgit read-tree -u --reset HEAD &&\n-\tgit clean -d -f -f -q -x &&\n+\tpristine_detach initial &&\n \tcat <<-EOF > expected &&\n \t<<<<<<< HEAD\n \ta\n@@ -309,10 +223,7 @@ test_expect_success 'revert also handles conflicts sanely' '\n \t\t2 s/ 0\t/ 2\t/\n \t\t3 s/ 0\t/ 3\t/\n \t\" < stages > expected-stages &&\n-\tgit checkout -f initial^0 &&\n-\n-\tgit update-index --refresh &&\n-\tgit diff-index --exit-code HEAD &&\n+\tgit read-tree -u --reset HEAD &&\n \n \thead=$(git rev-parse HEAD) &&\n \ttest_must_fail git revert picked &&\n@@ -328,10 +239,8 @@ test_expect_success 'revert also handles conflicts sanely' '\n '\n \n test_expect_success 'revert conflict, diff3 -m style' '\n+\tpristine_detach initial &&\n \tgit config merge.conflictstyle diff3 &&\n-\tgit checkout -f initial^0 &&\n-\tgit read-tree -u --reset HEAD &&\n-\tgit clean -d -f -f -q -x &&\n \tcat <<-EOF > expected &&\n \t<<<<<<< HEAD\n \ta\n@@ -342,9 +251,6 @@ test_expect_success 'revert conflict, diff3 -m style' '\n \t>>>>>>> parent of objid picked\n \tEOF\n \n-\tgit update-index --refresh &&\n-\tgit diff-index --exit-code HEAD &&\n-\n \ttest_must_fail git revert picked &&\n \n \tsed \"s/[a-f0-9]*\\.\\.\\./objid/\" foo > actual &&\n-- \n1.7.4.1\n"},{"id":"161466","messageId":"AANLkTinWCZqb=C5qbiGpwq4=PQCUswfyxekTDD6scNbm@mail.gmail.com","threadId":"26528","inReplyTo":"7v39nm9vgv.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH v3 1/4] Introduce CHERRY_PICK_HEAD","fromName":"Jay Soffian","fromEmail":"jaysoffian@gmail.com","sentAt":"2011-02-17T22:42:52Z","receivedAt":"2011-02-17T22:42:52Z","isPatch":true,"sender":{"key":"jaysoffian@gmail.com","avatar":"https://avatars.githubusercontent.com/u/155970?v=4"},"body":"On Thu, Feb 17, 2011 at 4:56 PM, Junio C Hamano <gitster@pobox.com> wrote:\n> This series in 'pu' seems to break t3404#16.\n\nSorry for the breakage, I was running the test suite piecemeal and\nmust've not run that test (which was dumb of me). I'll figure out\nwhat's going on and re-roll with Jonathan's t3507 improvements as\nwell.\n\nThank you for your patience.\n\nj.\n"},{"id":"161467","messageId":"20110217224855.GC10007@elie","threadId":"26528","inReplyTo":"AANLkTinWCZqb=C5qbiGpwq4=PQCUswfyxekTDD6scNbm@mail.gmail.com","subject":"Re: [PATCH v3 1/4] Introduce CHERRY_PICK_HEAD","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2011-02-17T22:48:55Z","receivedAt":"2011-02-17T22:48:55Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Jay Soffian wrote:\n> On Thu, Feb 17, 2011 at 4:56 PM, Junio C Hamano <gitster@pobox.com> wrote:\n\n>> This series in 'pu' seems to break t3404#16.\n>\n> Sorry for the breakage, I was running the test suite piecemeal and\n> must've not run that test (which was dumb of me).\n\nI made the same mistake, too.  Sorry for the trouble.\n\n> I'll figure out\n> what's going on and re-roll with Jonathan's t3507 improvements as\n> well.\n\nFWIW (probably you noticed, but just in case) I imagine the t3507\nimprovements should go as a separate patch, since their main effect\nis to clean up existing tests.\n"},{"id":"161475","messageId":"20110218002913.GB12182@elie","threadId":"26528","inReplyTo":"1297921850-94962-1-git-send-email-jaysoffian@gmail.com","subject":"Re: [PATCH] Teach commit about CHERRY_PICK_HEAD","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2011-02-18T00:29:40Z","receivedAt":"2011-02-18T00:29:40Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Jay Soffian wrote:\n\n> --- a/builtin/commit.c\n> +++ b/builtin/commit.c\n> @@ -54,9 +54,16 @@ static const char empty_amend_advice[] =\n>  \"it empty. You can repeat your command with --allow-empty, or you can\\n\"\n>  \"remove the commit entirely with \\\"git reset HEAD^\\\".\\n\";\n>  \n> +static const char empty_cherry_pick_advice[] =\n> +\"The most recent cherry-pick is empty. If you wish to commit it, use:\\n\"\n> +\"\\n\"\n> +\"    git commit --allow-empty\\n\"\n> +\"\\n\"\n> +\"Otherwise, please remove the file %s\\n\";\n\nAfter scratching my head a little, this seems to mean\n\n\tAfter conflict resolution, your last cherry-pick does not\n\tintroduce any changes. To commit it as an empty commit, use:\\n\n\t\\n\n\t    git commit --allow-empty\\n\n\t\\n\n\tAlternatively, you can cancel the cherry-pick by removing\\n\n\tthe file %s\\n\n\nIt suspect it might be more intuitive to say\n\n\tAlternatively, you can cancel the cherry-pick by running\\n\n\t\"git reset\".\\n\n\nwhich works because the index is known to be clean at that point.\n\n> +/*\n> + * The _message variables are commit names from which to take\n> + * the commit message and/or authorship.\n> + */\n\nMakes sense, thanks.  I'll think more about an intuitive and\nconsistent name for these and hopefully send a patch for it later as a\nseparate topic.\n\n> +       if (whence == FROM_CHERRY_PICK && !renew_authorship) {\n> +               author_message = \"CHERRY_PICK_HEAD\";\n> +               author_message_buffer = read_commit_message(author_message);\n\nI mentioned in a side thread that script authors might be happier if\ntheir carefully prepared GIT_AUTHOR_NAME and GIT_AUTHOR_EMAIL do not\nget overridden in this case, but I was wrong[*].  Might make sense\nto add a test for that:\n\n\tGIT_AUTHOR_NAME=\"Someone else\" &&\n\tGIT_AUTHOR_EMAIL=someone@else.example.com &&\n\texport GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL &&\n\tgit cherry-pick something &&\n\n\tgit diff-tree -s --format=\"%an <%ae>\" >actual &&\n\ttest_cmp expect actual\n\n(This is just a side note; the patch is good.)\n\nIn the $GIT_CHERRY_PICK_HELP set case, won't the CHERRY_PICK_HEAD\nbehavior be harmless?  rebase --interactive --continue wants to set\nGIT_AUTHOR_NAME and GIT_AUTHOR_EMAIL but that is only in order to copy\nthe author identity from the original commit.\n\n> --- a/wt-status.c\n> +++ b/wt-status.c\n> @@ -60,7 +60,7 @@ static void wt_status_print_unmerged_header(struct wt_status *s)\n>  \tcolor_fprintf_ln(s->fp, c, \"# Unmerged paths:\");\n>  \tif (!advice_status_hints)\n>  \t\treturn;\n> -\tif (s->in_merge)\n> +\tif (s->whence != FROM_COMMIT)\n>  \t\t;\n>  \telse if (!s->is_initial)\n>  \t\tcolor_fprintf_ln(s->fp, c, \"#   (use \\\"git reset %s <file>...\\\" to unstage)\", s->reference);\n\nThe advice 'use \"git reset HEAD -- <file>...\" to unstage' makes\nperfect sense to me in the cherry-pick case, no?  The operator is\nreplaying an existing commit, and tweaking the result amounts to\npretending she made the change herself and tweaking that.\n\n> @@ -77,7 +77,7 @@ static void wt_status_print_cached_header(struct wt_status *s)\n>  \tcolor_fprintf_ln(s->fp, c, \"# Changes to be committed:\");\n>  \tif (!advice_status_hints)\n>  \t\treturn;\n> -\tif (s->in_merge)\n> +\tif (s->whence != FROM_COMMIT)\n>  \t\t; /* NEEDSWORK: use \"git reset --unresolve\"??? */\n\nLikewise.\n\n> --- a/wt-status.h\n> +++ b/wt-status.h\n> @@ -24,6 +24,13 @@ enum untracked_status_type {\n>  \tSHOW_ALL_UNTRACKED_FILES\n>  };\n>  \n> +/* from where does this commit originate */\n> +enum commit_whence {\n> +\tFROM_COMMIT,     /* normal */\n> +\tFROM_MERGE,      /* commit came from merge */\n> +\tFROM_CHERRY_PICK /* commit came from cherry-pick */\n> +};\n\nI think these comments are not in a place that will help a person\nunderstand the code, but I don't have the energy to go back and forth\non it.\n\nEverything not mentioned above except the --no-commit case mentioned\nby Junio looks good to me, though I haven't tested.\n\nThanks for your thoughtfulness.\nJonathan\n\n[*]\n-- 8< --\nSubject: [BAD IDEA] commit: let GIT_AUTHOR_NAME/EMAIL take effect when commiting a cherry-pick\n\ncommit -c/-C/--amend to take the commit message and author from\nanother message has always overridden the GIT_AUTHOR_NAME and\nGIT_AUTHOR_EMAIL variables.  Letting the command line override the\nenvironment in this way is generally convenient and more intuitive if\na person has forgotten what is in the environment:\n\n\tGIT_AUTHOR_NAME=me\n\tGIT_AUTHOR_EMAIL=email@example.com\n\texport GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL\n\n\t...\n\tgit commit;\t# using identity from environment\n\t...\n\tgit commit;\t# another commit as me\n\t...\n\t# commit by someone else\n\tgit commit --author='Someone Else <other@example.com>'\n\t...\n\t# commit by someone else\n\tgit commit -c someone-elses-commit\n\nThe new CHERRY_PICK_HEAD feature inherits the same semantics.\nUncareful scripts that want to commit with a different author name and\nemail when taking over after a failed cherry-pick use authorship from\nthe cherry-picked commit instead of the environment:\n\n\t! git cherry-pick complicated;\t# failed cherry-pick\n\t... resolve the conflict ...\n\tgit commit\n\nWhile that could theoretically break some scripts, it's worth it for\nconsistency, the intuitiveness-when-user-forgets-environment issue\nmentioned above, and because cherry-pick itself, which internally\ndoes something like\n\n\tgit cherry-pick --no-commit $1;\t# simple cherry-pick\n\tgit commit\n\nhas always ignored the GIT_AUTHOR_NAME/EMAIL environment settings.\n\nThe patch below makes commit with CHERRY_PICK_HEAD respect\nGIT_AUTHOR_NAME/EMAIL anyway, to demonstrate how broken that is.  It\nbreaks tests t3404 and t3506.\n\nSigned-off-by: Jonathan Nieder <jrnieder@gmail.com>\n---\n builtin/commit.c |   59 ++++++++++++++++++++++++++++++++---------------------\n 1 files changed, 36 insertions(+), 23 deletions(-)\n\ndiff --git a/builtin/commit.c b/builtin/commit.c\nindex 35eb024..f398910 100644\n--- a/builtin/commit.c\n+++ b/builtin/commit.c\n@@ -80,6 +80,7 @@ static const char *template_file;\n  * the commit message and/or authorship.\n  */\n static const char *author_message, *author_message_buffer;\n+static int author_message_overrides_environ;\n static char *edit_message, *use_message;\n static char *fixup_message, *squash_message;\n static int all, edit_flag, also, interactive, only, amend, signoff;\n@@ -504,6 +505,38 @@ static int is_a_merge(const unsigned char *sha1)\n \n static const char sign_off_header[] = \"Signed-off-by: \";\n \n+static void reuse_author_info(char **name, char **email, char **date)\n+{\n+\tconst char *a, *lb, *rb, *eol;\n+\n+\tif (author_message_overrides_environ)\n+\t\t*name = *email = *date = NULL;\n+\n+\ta = strstr(author_message_buffer, \"\\nauthor \");\n+\tif (!a)\n+\t\tdie(\"invalid commit: %s\", author_message);\n+\n+\tlb = strchrnul(a + strlen(\"\\nauthor \"), '<');\n+\trb = strchrnul(lb, '>');\n+\teol = strchrnul(rb, '\\n');\n+\tif (!*lb || !*rb || !*eol)\n+\t\tdie(\"invalid commit: %s\", author_message);\n+\n+\tif (!*name) {\n+\t\tif (lb == a + strlen(\"\\nauthor \"))\n+\t\t\t/* \\nauthor <foo@example.com> */\n+\t\t\t*name = xcalloc(1, 1);\n+\t\telse\n+\t\t\t*name = xmemdupz(a + strlen(\"\\nauthor \"),\n+\t\t\t\t\t (lb - strlen(\" \") -\n+\t\t\t\t\t  (a + strlen(\"\\nauthor \"))));\n+\t}\n+\tif (!*email)\n+\t\t*email = xmemdupz(lb + strlen(\"<\"), rb - (lb + strlen(\"<\")));\n+\tif (!*date)\n+\t\t*date = xmemdupz(rb + strlen(\"> \"), eol - (rb + strlen(\"> \")));\n+}\n+\n static void determine_author_info(struct strbuf *author_ident)\n {\n \tchar *name, *email, *date;\n@@ -512,29 +545,8 @@ static void determine_author_info(struct strbuf *author_ident)\n \temail = getenv(\"GIT_AUTHOR_EMAIL\");\n \tdate = getenv(\"GIT_AUTHOR_DATE\");\n \n-\tif (author_message) {\n-\t\tconst char *a, *lb, *rb, *eol;\n-\n-\t\ta = strstr(author_message_buffer, \"\\nauthor \");\n-\t\tif (!a)\n-\t\t\tdie(\"invalid commit: %s\", author_message);\n-\n-\t\tlb = strchrnul(a + strlen(\"\\nauthor \"), '<');\n-\t\trb = strchrnul(lb, '>');\n-\t\teol = strchrnul(rb, '\\n');\n-\t\tif (!*lb || !*rb || !*eol)\n-\t\t\tdie(\"invalid commit: %s\", author_message);\n-\n-\t\tif (lb == a + strlen(\"\\nauthor \"))\n-\t\t\t/* \\nauthor <foo@example.com> */\n-\t\t\tname = xcalloc(1, 1);\n-\t\telse\n-\t\t\tname = xmemdupz(a + strlen(\"\\nauthor \"),\n-\t\t\t\t\t(lb - strlen(\" \") -\n-\t\t\t\t\t (a + strlen(\"\\nauthor \"))));\n-\t\temail = xmemdupz(lb + strlen(\"<\"), rb - (lb + strlen(\"<\")));\n-\t\tdate = xmemdupz(rb + strlen(\"> \"), eol - (rb + strlen(\"> \")));\n-\t}\n+\tif (author_message)\n+\t\treuse_author_info(&name, &email, &date);\n \n \tif (force_author) {\n \t\tconst char *lb = strstr(force_author, \" <\");\n@@ -1034,6 +1046,7 @@ static int parse_and_validate_options(int argc, const char *argv[],\n \t\t\tauthor_message = use_message;\n \t\t\tauthor_message_buffer = use_message_buffer;\n \t\t}\n+\t\tauthor_message_overrides_environ = 1;\n \t}\n \tif (whence == FROM_CHERRY_PICK && !renew_authorship) {\n \t\tauthor_message = \"CHERRY_PICK_HEAD\";\n-- \n1.7.4.1\n"},{"id":"161727","messageId":"AANLkTik7cfihdu5-0pvgkq1u7kVShEqnjzh07T+5pU16@mail.gmail.com","threadId":"26528","inReplyTo":"7vipwibfc5.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH v3 1/4] Introduce CHERRY_PICK_HEAD","fromName":"Jay Soffian","fromEmail":"jaysoffian@gmail.com","sentAt":"2011-02-20T02:29:28Z","receivedAt":"2011-02-20T02:29:28Z","isPatch":true,"sender":{"key":"jaysoffian@gmail.com","avatar":"https://avatars.githubusercontent.com/u/155970?v=4"},"body":"On Thu, Feb 17, 2011 at 3:01 PM, Junio C Hamano <gitster@pobox.com> wrote:\n> Jay Soffian <jaysoffian@gmail.com> writes:\n>\n>> diff --git a/builtin/merge.c b/builtin/merge.c\n>> index 9403747..454dad2 100644\n>> --- a/builtin/merge.c\n>> +++ b/builtin/merge.c\n>> @@ -971,6 +971,13 @@ int cmd_merge(int argc, const char **argv, const char *prefix)\n>>               else\n>>                       die(\"You have not concluded your merge (MERGE_HEAD exists).\");\n>>       }\n>> +     if (file_exists(git_path(\"CHERRY_PICK_HEAD\"))) {\n>> +             if (advice_resolve_conflict)\n>> +                     die(\"You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists).\\n\"\n>> +                         \"Please, commit your changes before you can merge.\");\n>> +             else\n>> +                     die(\"You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists).\");\n>> +     }\n>\n> Micronit: \"Please, commit your changes before you can merge.\"\n>\n>  - We are not merging in this codepath to begin with;\n>\n>  - I'd suggest rephrasing this (together with \"MERGE_HEAD\" codepath) to\n>   something like:\n>\n>        \"Commit your changes first before retrying.\"\n\nThis hunk is from Jonathan, so I'd like him to address your comment as\nwell, but I think the current message is correct. This hunk is inside\ncmd_merge and the user is about to start a merge. IOW:\n\n$ git cherry-pick   # fails, leave behinds CHERRY_PICK_HEAD\n [... time passes ...]\n$ git merge\nYou have not concluded your cherry-pick (CHERRY_PICK_HEAD exists).\nPlease, commit your changes before you can merge.\n\n> Getting tired of seeing these five lines repeated over and over.  Perhaps\n> it is time to introduce:\n\nOkay. (Will roll in from Jonathan's later email.)\n\n>> +     git cherry-pick --no-commit base &&\n>> +\n>> +     test_cmp_rev base CHERRY_PICK_HEAD\n>\n> If the next \"git commit\" would notice and use this information, that would\n> introduce an unpleasant regression to one use case in my workflow, which\n> is to pick and consolidate one or more small pieces made on a private\n> \"misc\" branch, possibly with a bit of further work, into a new commit with\n> a readable explanation that is unrelated to any of the original commits:\n>\n>        git cherry-pick --no-commit $some_commit\n>        git cherry-pick --no-commit $another_commit ;# optional\n>        edit ;# optional\n>        git commit\n>\n> I'd prefer to see a way to tell cherry-pick not to leave CHERRY_PICK_HEAD\n> behind when \"cherry-pick --no-commit\" results in a successful cherry-pick\n> to avoid a backward incompatibility surprise.  Otherwise people need to\n> retrain their fingers to say --reset-author when they run \"git commit\".\n\nOkay. In that case, I think when using --no-commit, we shouldn't write\nCHERRY_PICK_HEAD regardless of whether there is a conflict or not.\n\nj.\n"},{"id":"161728","messageId":"20110220024826.GB17547@elie","threadId":"26528","inReplyTo":"AANLkTik7cfihdu5-0pvgkq1u7kVShEqnjzh07T+5pU16@mail.gmail.com","subject":"Re: [PATCH v3 1/4] Introduce CHERRY_PICK_HEAD","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2011-02-20T02:48:26Z","receivedAt":"2011-02-20T02:48:26Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Hi,\n\nJay Soffian wrote:\n> On Thu, Feb 17, 2011 at 3:01 PM, Junio C Hamano <gitster@pobox.com> wrote:\n\n>> Micronit: \"Please, commit your changes before you can merge.\"\n>>\n>>  - We are not merging in this codepath to begin with;\n>>\n>>  - I'd suggest rephrasing this (together with \"MERGE_HEAD\" codepath) to\n>>   something like:\n>>\n>>        \"Commit your changes first before retrying.\"\n>\n> This hunk is from Jonathan\n\nI agree with what Jay said --- this is in cmd_merge, so the current\nmessage is correct.  I like your wording (\"before retrying\") more, but\nthat seems orthogonal to the topic at hand.  I can send a patch\nrephrasing it on top if someone reminds me.\n\n> Okay. In that case, I think when using --no-commit, we shouldn't write\n> CHERRY_PICK_HEAD regardless of whether there is a conflict or not.\n\nThanks for your attention to detail.\nJonathan\n"},{"id":"161735","messageId":"7vhbbzmciy.fsf@alter.siamese.dyndns.org","threadId":"26528","inReplyTo":"AANLkTik7cfihdu5-0pvgkq1u7kVShEqnjzh07T+5pU16@mail.gmail.com","subject":"Re: [PATCH v3 1/4] Introduce CHERRY_PICK_HEAD","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2011-02-20T06:43:33Z","receivedAt":"2011-02-20T06:43:33Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jay Soffian <jaysoffian@gmail.com> writes:\n\n> ..., but I think the current message is correct. This hunk is inside\n> cmd_merge and the user is about to start a merge.\n\nYes, you are right; I misread the patch.  Sorry about that.\n"}]}