CHERRY_PICK_HEAD
cover CHERRY_PICK_HEAD
Re-roll of http://thread.gmane.org/gmane.comp.version-control.git/166878
If not ready for inclusion, hopefully very close.
Jay Soffian (2):
Introduce CHERRY_PICK_HEAD
Teach commit about CHERRY_PICK_HEAD
Documentation/git-cherry-pick.txt | 19 +++++ Documentation/git-commit.txt | 7 +- Documentation/revisions.txt | 5 +- branch.c | 1 + builtin/commit.c | 136 ++++++++++++++++++++++---------- builtin/merge.c | 7 ++ builtin/revert.c | 68 ++++------------ contrib/completion/git-completion.bash | 2 + t/t3507-cherry-pick-conflict.sh | 22 +++++- t/t7509-commit.sh | 29 +++++++ wt-status.c | 4 +- wt-status.h | 8 ++- 12 files changed, 204 insertions(+), 104 deletions(-)
Signature · 1 line
1.7.4.1.28.gd46b3
PATCH 1/2 Introduce CHERRY_PICK_HEAD
When a cherry-pick conflicts git advises to use:
$ git commit -c <original commit id>
to preserve the original commit message and authorship. Instead, let's record the original commit id in CHERRY_PICK_HEAD and advise to use:
$ git commit -c CHERRY_PICK_HEAD
In the next commit, we teach git to handle the '-c CHERRY_PICK_HEAD' part. Note that wWe record CHERRY_PICK_HEAD even in the case where there are no conflicts so that we may use it to communicate authorship to commit; this will then allow us to remove set_author_ident_env from revert.c.
--- Documentation/git-cherry-pick.txt | 19 +++++++++++++++++++ Documentation/revisions.txt | 5 ++++- branch.c | 1 + builtin/commit.c | 1 + builtin/merge.c | 7 +++++++ builtin/revert.c | 20 ++++++++++++++++++-- t/t3507-cherry-pick-conflict.sh | 22 +++++++++++++++++++++- 7 files changed, 71 insertions(+), 4 deletions(-)
Documentation/git-cherry-pick.txt +19 -0
@@ -16,6 +16,25 @@ Given one or more existing commits, apply the change each one introduces, recording a new commit for each. This requires your working tree to be clean (no modifications from the HEAD commit). +When it is not obvious how to apply a change, the following +happens: + +1. The current branch and `HEAD` pointer stay at the last commit + successfully made. +2. The `CHERRY_PICK_HEAD` ref is set to point at the commit that + introduced the change that is difficult to apply. +3. Paths in which the change applied cleanly are updated both + in the index file and in your working tree. +4. For conflicting paths, the index file records up to three + versions, as described in the "TRUE MERGE" section of + linkgit:git-merge[1]. The working tree files will include + a description of the conflict bracketed by the usual + conflict markers `<<<<<<<` and `>>>>>>>`. +5. No other modifications are made. + +See linkgit:git-merge[1] for some hints on resolving such +conflicts. + OPTIONS ------- <commit>...::
Documentation/revisions.txt +4 -1
@@ -25,7 +25,8 @@ blobs contained in a commit. first match in the following rules: . if `$GIT_DIR/<name>` exists, that is what you mean (this is usually - useful only for `HEAD`, `FETCH_HEAD`, `ORIG_HEAD` and `MERGE_HEAD`); + useful only for `HEAD`, `FETCH_HEAD`, `ORIG_HEAD`, `MERGE_HEAD` + and `CHERRY_PICK_HEAD`); . otherwise, `refs/<name>` if exists;
@@ -46,6 +47,8 @@ you can change the tip of the branch back to the state before you ran them easily. MERGE_HEAD records the commit(s) you are merging into your branch when you run 'git merge'. +CHERRY_PICK_HEAD records the commit you are cherry-picking +when you run 'git cherry-pick'. + Note that any of the `refs/*` cases above may come either from the `$GIT_DIR/refs` directory or from the `$GIT_DIR/packed-refs` file.
branch.c +1 -0
@@ -217,6 +217,7 @@ void create_branch(const char *head,void remove_branch_state (void ) { +unlink (git_path ("CHERRY_PICK_HEAD" ));unlink (git_path ("MERGE_HEAD" ));unlink (git_path ("MERGE_RR" ));unlink (git_path ("MERGE_MSG" ));
builtin/commit.c +1 -0
@@ -1424,6 +1424,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)die ("cannot update HEAD ref" ); } +unlink (git_path ("CHERRY_PICK_HEAD" ));unlink (git_path ("MERGE_HEAD" ));unlink (git_path ("MERGE_MSG" ));unlink (git_path ("MERGE_MODE" ));
builtin/merge.c +7 -0
@@ -971,6 +971,13 @@ int cmd_merge(int argc, const char **argv, const char *prefix)else die ("You have not concluded your merge (MERGE_HEAD exists)." ); } +if (file_exists (git_path ("CHERRY_PICK_HEAD" ))) { +if (advice_resolve_conflict) +die ("You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists).\n" +"Please, commit your changes before you can merge." ); +else +die ("You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists)." ); + }resolve_undo_clear ();if (verbosity <0 )
builtin/revert.c +18 -2
@@ -248,6 +248,22 @@ static void set_author_ident_env(const char *message) sha1_to_hex(commit->object.sha1)); } +static void write_cherry_pick_head (void ) +{ +int fd; +struct strbuf buf =STRBUF_INIT ; + +strbuf_addf (&buf,"%s\n" ,sha1_to_hex (commit->object.sha1)); + + fd =open (git_path ("CHERRY_PICK_HEAD" ),O_WRONLY |O_CREAT ,0666 ); +if (fd <0 ) +die_errno ("Could not open '%s' for writing" , +git_path ("CHERRY_PICK_HEAD" )); +if (write_in_full (fd, buf.buf, buf.len) != buf.len ||close (fd)) +die_errno ("Could not write to '%s'" ,git_path ("CHERRY_PICK_HEAD" )); +strbuf_release (&buf); +} +static void advise (const char *advice, ...) {va_list params;
@@ -270,8 +286,7 @@ static void print_advice(void)advise ("with 'git add <paths>' or 'git rm <paths>'" );if (action ==CHERRY_PICK ) -advise ("and commit the result with 'git commit -c %s'" , -find_unique_abbrev (commit->object.sha1,DEFAULT_ABBREV )); +advise ("and commit the result with 'git commit -c CHERRY_PICK_HEAD'" ); }static void write_message (struct strbuf *msgbuf,const char *filename)
@@ -504,6 +519,7 @@ static int do_pick_commit(void)strbuf_addstr (&msgbuf,sha1_to_hex (commit->object.sha1));strbuf_addstr (&msgbuf,")\n" ); } +write_cherry_pick_head (); }if (!strategy || !strcmp (strategy,"recursive" ) || action ==REVERT ) {
t/t3507-cherry-pick-conflict.sh +21 -1
@@ -11,6 +11,12 @@ test_description='test cherry-pick and revert with conflicts . ./test-lib.sh +test_cmp_rev () { + git rev-parse --verify "$1" >expect.rev && + git rev-parse --verify "$2" >actual.rev && + test_cmp expect.rev actual.rev +} + test_expect_success setup ' echo unrelated >unrelated &&
@@ -51,13 +57,27 @@ test_expect_success 'advice from failed cherry-pick' " error: could not apply \$picked... picked hint: after resolving the conflicts, mark the corrected paths hint: with 'git add <paths>' or 'git rm <paths>' - hint: and commit the result with 'git commit -c \$picked' + hint: and commit the result with 'git commit -c CHERRY_PICK_HEAD' EOF test_must_fail git cherry-pick picked 2>actual && test_cmp expected actual " +test_expect_success 'failed cherry-pick sets CHERRY_PICK_HEAD' ' + + git checkout -f initial^0 && + git read-tree -u --reset HEAD && + git clean -d -f -f -q -x && + + git update-index --refresh && + git diff-index --exit-code HEAD && + + test_must_fail git cherry-pick picked && + + test_cmp_rev picked CHERRY_PICK_HEAD +' + test_expect_success 'failed cherry-pick produces dirty index' ' git checkout -f initial^0 &&
Signature · 1 line
1.7.4.1.28.gd46b3
PATCH v2 1/1 Introduce CHERRY_PICK_HEAD
When a cherry-pick conflicts git advises to use:
$ git commit -c <original commit id>
to preserve the original commit message and authorship. Instead, let's record the original commit id in CHERRY_PICK_HEAD and advise to use:
$ git commit -c CHERRY_PICK_HEAD
In the next commit, we teach git to handle the '-c CHERRY_PICK_HEAD' part. Note that we record CHERRY_PICK_HEAD even in the case where there are no conflicts so that we may use it to communicate authorship to commit; this will then allow us to remove set_author_ident_env from revert.c.
---
Compared to the original patch, this removes CHERRY_PICK_HEAD when a conflict occurs during an interactive rebase. Also corrected a minor typo in the commit message. There were no changes to the next patch in the series, so I didn't resend it.
Documentation/git-cherry-pick.txt | 19 +++++++++++++++++++ Documentation/revisions.txt | 5 ++++- branch.c | 1 + builtin/commit.c | 1 + builtin/merge.c | 7 +++++++ builtin/revert.c | 25 +++++++++++++++++++++++-- t/t3507-cherry-pick-conflict.sh | 22 +++++++++++++++++++++- 7 files changed, 76 insertions(+), 4 deletions(-)
Documentation/git-cherry-pick.txt +19 -0
@@ -16,6 +16,25 @@ Given one or more existing commits, apply the change each one introduces, recording a new commit for each. This requires your working tree to be clean (no modifications from the HEAD commit). +When it is not obvious how to apply a change, the following +happens: + +1. The current branch and `HEAD` pointer stay at the last commit + successfully made. +2. The `CHERRY_PICK_HEAD` ref is set to point at the commit that + introduced the change that is difficult to apply. +3. Paths in which the change applied cleanly are updated both + in the index file and in your working tree. +4. For conflicting paths, the index file records up to three + versions, as described in the "TRUE MERGE" section of + linkgit:git-merge[1]. The working tree files will include + a description of the conflict bracketed by the usual + conflict markers `<<<<<<<` and `>>>>>>>`. +5. No other modifications are made. + +See linkgit:git-merge[1] for some hints on resolving such +conflicts. + OPTIONS ------- <commit>...::
Documentation/revisions.txt +4 -1
@@ -25,7 +25,8 @@ blobs contained in a commit. first match in the following rules: . if `$GIT_DIR/<name>` exists, that is what you mean (this is usually - useful only for `HEAD`, `FETCH_HEAD`, `ORIG_HEAD` and `MERGE_HEAD`); + useful only for `HEAD`, `FETCH_HEAD`, `ORIG_HEAD`, `MERGE_HEAD` + and `CHERRY_PICK_HEAD`); . otherwise, `refs/<name>` if exists;
@@ -46,6 +47,8 @@ you can change the tip of the branch back to the state before you ran them easily. MERGE_HEAD records the commit(s) you are merging into your branch when you run 'git merge'. +CHERRY_PICK_HEAD records the commit you are cherry-picking +when you run 'git cherry-pick'. + Note that any of the `refs/*` cases above may come either from the `$GIT_DIR/refs` directory or from the `$GIT_DIR/packed-refs` file.
branch.c +1 -0
@@ -217,6 +217,7 @@ void create_branch(const char *head,void remove_branch_state (void ) { +unlink (git_path ("CHERRY_PICK_HEAD" ));unlink (git_path ("MERGE_HEAD" ));unlink (git_path ("MERGE_RR" ));unlink (git_path ("MERGE_MSG" ));
builtin/commit.c +1 -0
@@ -1424,6 +1424,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)die ("cannot update HEAD ref" ); } +unlink (git_path ("CHERRY_PICK_HEAD" ));unlink (git_path ("MERGE_HEAD" ));unlink (git_path ("MERGE_MSG" ));unlink (git_path ("MERGE_MODE" ));
builtin/merge.c +7 -0
@@ -971,6 +971,13 @@ int cmd_merge(int argc, const char **argv, const char *prefix)else die ("You have not concluded your merge (MERGE_HEAD exists)." ); } +if (file_exists (git_path ("CHERRY_PICK_HEAD" ))) { +if (advice_resolve_conflict) +die ("You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists).\n" +"Please, commit your changes before you can merge." ); +else +die ("You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists)." ); + }resolve_undo_clear ();if (verbosity <0 )
builtin/revert.c +23 -2
@@ -248,6 +248,22 @@ static void set_author_ident_env(const char *message) sha1_to_hex(commit->object.sha1)); } +static void write_cherry_pick_head (void ) +{ +int fd; +struct strbuf buf =STRBUF_INIT ; + +strbuf_addf (&buf,"%s\n" ,sha1_to_hex (commit->object.sha1)); + + fd =open (git_path ("CHERRY_PICK_HEAD" ),O_WRONLY |O_CREAT ,0666 ); +if (fd <0 ) +die_errno ("Could not open '%s' for writing" , +git_path ("CHERRY_PICK_HEAD" )); +if (write_in_full (fd, buf.buf, buf.len) != buf.len ||close (fd)) +die_errno ("Could not write to '%s'" ,git_path ("CHERRY_PICK_HEAD" )); +strbuf_release (&buf); +} +static void advise (const char *advice, ...) {va_list params;
@@ -263,6 +279,11 @@ static void print_advice(void)if (msg) {fprintf (stderr,"%s\n" , msg); +/* +* rebase interactive takes care of the authorship +* when the user invokes rebase --continue +*/ +unlink (git_path ("CHERRY_PICK_HEAD" ));return ; }
@@ -270,8 +291,7 @@ static void print_advice(void)advise ("with 'git add <paths>' or 'git rm <paths>'" );if (action ==CHERRY_PICK ) -advise ("and commit the result with 'git commit -c %s'" , -find_unique_abbrev (commit->object.sha1,DEFAULT_ABBREV )); +advise ("and commit the result with 'git commit -c CHERRY_PICK_HEAD'" ); }static void write_message (struct strbuf *msgbuf,const char *filename)
@@ -504,6 +524,7 @@ static int do_pick_commit(void)strbuf_addstr (&msgbuf,sha1_to_hex (commit->object.sha1));strbuf_addstr (&msgbuf,")\n" ); } +write_cherry_pick_head (); }if (!strategy || !strcmp (strategy,"recursive" ) || action ==REVERT ) {
t/t3507-cherry-pick-conflict.sh +21 -1
@@ -11,6 +11,12 @@ test_description='test cherry-pick and revert with conflicts . ./test-lib.sh +test_cmp_rev () { + git rev-parse --verify "$1" >expect.rev && + git rev-parse --verify "$2" >actual.rev && + test_cmp expect.rev actual.rev +} + test_expect_success setup ' echo unrelated >unrelated &&
@@ -51,13 +57,27 @@ test_expect_success 'advice from failed cherry-pick' " error: could not apply \$picked... picked hint: after resolving the conflicts, mark the corrected paths hint: with 'git add <paths>' or 'git rm <paths>' - hint: and commit the result with 'git commit -c \$picked' + hint: and commit the result with 'git commit -c CHERRY_PICK_HEAD' EOF test_must_fail git cherry-pick picked 2>actual && test_cmp expected actual " +test_expect_success 'failed cherry-pick sets CHERRY_PICK_HEAD' ' + + git checkout -f initial^0 && + git read-tree -u --reset HEAD && + git clean -d -f -f -q -x && + + git update-index --refresh && + git diff-index --exit-code HEAD && + + test_must_fail git cherry-pick picked && + + test_cmp_rev picked CHERRY_PICK_HEAD +' + test_expect_success 'failed cherry-pick produces dirty index' ' git checkout -f initial^0 &&
Signature · 1 line
1.7.4.1.28.gb39462
Re: [PATCH v2] Introduce CHERRY_PICK_HEAD
Quoted 7 lines · Jay Soffian
When a cherry-pick conflicts git advises to use:
$ git commit -c <original commit id>to preserve the original commit message and authorship. Instead, let's record the original commit id in
CHERRY_PICK_HEADand advise to use:
Quoted 7 lines
$ git commit -c CHERRY_PICK_HEADIn the next commit, we teach git to handle the '-c
CHERRY_PICK_HEAD' part. Note that we recordCHERRY_PICK_HEADeven in the case where there are no conflicts so that we may use it to communicate authorship to commit; this will then allow us to removeset_author_ident_envfromrevert.c.
This "In the next commit" phrasing is dangerous, since a person can build on top of your first commit at any time. :) I would say:
A later patch will teach "git commit" without -c to use CHERRY_PICK_HEAD to set the authorship automatically. Note that[...]
[...]
Review static void print_advice(void) · line 286
Quoted 10 lines
+++
b/builtin/revert.c(quoted diff) +5
-0@@ -263,6 +279,11 @@ static void print_advice(void) if (msg) { fprintf(stderr, "%s\n", msg); + /* + * rebase interactive takes care of the authorship + * when the user invokes rebase --continue + */ + unlink(git_path("CHERRY_PICK_HEAD"));
Nit: GIT_CHERRY_PICK_HELP is not just for rebase --interactive but for arbitrary porcelain that wants to take care of the commit itself (see v1.5.4-rc0~106^2~1, revert/cherry-pick: Allow overriding the help text by the calling Porcelain, 2007-11-28).
The conservative thing to do is indeed to remove CHERRY_PICK_HEAD in this case, I suppose. But I'd like to have the CHERRY_PICK_HEAD to get the --amend safety when rebasing. I can send a separate patch for it if you'd like.
Quoted 3 lines
t/t3507-cherry-pick-conflict.sh +0
-0@@ -11,6 +11,12 @@ test_description='test cherry-pick and revert with conflicts
[...]
Quoted 1 line
+test_expect_success 'failed cherry-pick sets
CHERRY_PICK_HEAD' '
Some more tests. Yes, they are repetitive. A patch on top to factor out the setup into a function might help, but that feels out of scope here.
With whatever subset of the below looks good,
Thanks.
--- t/t3507-cherry-pick-conflict.sh | 116 +++++++++++++++++++++++++++++++++++++++ 1 files changed, 116 insertions(+), 0 deletions(-)
t/t3507-cherry-pick-conflict.sh +116 -0
@@ -78,6 +78,122 @@ test_expect_success 'failed cherry-pick sets CHERRY_PICK_HEAD' ' test_cmp_rev picked CHERRY_PICK_HEAD ' +test_expect_success 'successful cherry-pick does not set CHERRY_PICK_HEAD' ' + + git checkout -f initial^0 && + git read-tree -u --reset HEAD && + git clean -d -f -f -q -x && + + git update-index --refresh && + git diff-index --exit-code HEAD && + + git cherry-pick base && + + test_must_fail git rev-parse --verify CHERRY_PICK_HEAD +' + +test_expect_success 'cherry-pick --no-commit sets CHERRY_PICK_HEAD' ' + + git checkout -f initial^0 && + git read-tree -u --reset HEAD && + git clean -d -f -f -q -x && + + git update-index --refresh && + git diff-index --exit-code HEAD && + + git cherry-pick --no-commit base && + + test_cmp_rev base CHERRY_PICK_HEAD +' + +test_expect_success 'GIT_CHERRY_PICK_HELP suppresses CHERRY_PICK_HEAD' ' + + git checkout -f initial^0 && + git read-tree -u --reset HEAD && + git clean -d -f -f -q -x && + + git update-index --refresh && + git diff-index --exit-code HEAD && + + ( + GIT_CHERRY_PICK_HELP="and then do something else" && + export GIT_CHERRY_PICK_HELP && + test_must_fail git cherry-pick picked + ) && + + test_must_fail git rev-parse --verify CHERRY_PICK_HEAD +' + +test_expect_success 'git reset clears CHERRY_PICK_HEAD' ' + + git checkout -f initial^0 && + git read-tree -u --reset HEAD && + git clean -d -f -f -q -x && + + git update-index --refresh && + git diff-index --exit-code HEAD && + + test_must_fail git cherry-pick picked && + git reset && + + test_must_fail git rev-parse --verify CHERRY_PICK_HEAD +' + +test_expect_success 'failed commit does not clear CHERRY_PICK_HEAD' ' + + git checkout -f initial^0 && + git read-tree -u --reset HEAD && + git clean -d -f -f -q -x && + + git update-index --refresh && + git diff-index --exit-code HEAD && + + test_must_fail git cherry-pick picked && + test_must_fail git commit && + + test_cmp_rev picked CHERRY_PICK_HEAD +' + +test_expect_success 'cancelled commit does not clear CHERRY_PICK_HEAD' ' + + git checkout -f initial^0 && + git read-tree -u --reset HEAD && + git clean -d -f -f -q -x && + + git update-index --refresh && + git diff-index --exit-code HEAD && + + test_must_fail git cherry-pick picked && + echo resolved >foo && + git add foo && + git update-index --refresh -q && + test_must_fail git diff-index --exit-code HEAD && + ( + GIT_EDITOR=false && + export GIT_EDITOR && + test_must_fail git commit + ) && + + test_cmp_rev picked CHERRY_PICK_HEAD +' + +test_expect_success 'successful commit clears CHERRY_PICK_HEAD' ' + + git checkout -f initial^0 && + git read-tree -u --reset HEAD && + git clean -d -f -f -q -x && + + git update-index --refresh && + git diff-index --exit-code HEAD && + + test_must_fail git cherry-pick picked && + echo resolved >foo && + git add foo && + git commit && + + test_must_fail git rev-parse --verify CHERRY_PICK_HEAD +' + test_expect_success 'failed cherry-pick produces dirty index' ' git checkout -f initial^0 &&
Signature · 1 line
1.7.4.1
Re: [PATCH v2] Introduce CHERRY_PICK_HEAD
Quoted 4 lines · Jonathan Nieder
Nit:
GIT_CHERRY_PICK_HELPis not just for rebase --interactive but for arbitrary porcelain that wants to take care of the commit itself (see v1.5.4-rc0~106^2~1, revert/cherry-pick: Allow overriding the help text by the calling Porcelain, 2007-11-28).
What is the arbitrary porcelain you have in mind? :-)
Quoted 4 lines
The conservative thing to do is indeed to remove
CHERRY_PICK_HEADin this case, I suppose. But I'd like to have theCHERRY_PICK_HEADto get the --amend safety when rebasing. I can send a separate patch for it if you'd like.
Please do, since I'm not really sure what you have in mind. If CHERRY_PICK_HEAD is left-behind, it interferes with the eventually commit done by rebase --continue. I suppose we could give commit.c some additional logic to detect when it's being called by rebase (setting whence = FROM_REBASE?).
In the mean time, I'll re-roll with your additional tests and Junio's prior feedback.
Thanks,
j.
Re: [PATCH v2] Introduce CHERRY_PICK_HEAD
Quoted 8 lines · Jay Soffian
Quoted 4 lines · Jonathan Nieder
Nit:
GIT_CHERRY_PICK_HELPis not just for rebase --interactive but for arbitrary porcelain that wants to take care of the commit itself (see v1.5.4-rc0~106^2~1, revert/cherry-pick: Allow overriding the help text by the calling Porcelain, 2007-11-28).What is the arbitrary porcelain you have in mind? :-)
git sequencer, for example. Or any out-of-tree tool that is using cherry-pick to move around commits and wants to know where they end up.
Quoted 8 lines
Quoted 4 lines
The conservative thing to do is indeed to remove
CHERRY_PICK_HEADin this case, I suppose. But I'd like to have theCHERRY_PICK_HEADto get the --amend safety when rebasing. I can send a separate patch for it if you'd like.Please do, since I'm not really sure what you have in mind. If
CHERRY_PICK_HEADis left-behind, it interferes with the eventually commit done by rebase --continue.
Wait, does this mean that -c/-C/--amend/CHERRY_PICK_HEAD overrides GIT_AUTHOR_NAME, GIT_AUTHOR_EMAIL, and GIT_AUTHOR_DATE?
*checks*
Yes, it does. The behavior is carried over from v0.99~185 (git-commit-script: get commit message from an existing one, 2005-06-25), but imho it is wrong.
Does this seem worth fixing?
Jonathan
Re: [PATCH v2] Introduce CHERRY_PICK_HEAD
Quoted 8 lines · Jonathan Nieder
Wait, does this mean that -c/-C/--amend/CHERRY_PICK_HEAD overrides
GIT_AUTHOR_NAME,GIT_AUTHOR_EMAIL, andGIT_AUTHOR_DATE?*checks*
Yes, it does. The behavior is carried over from v0.99~185 (git-commit-script: get commit message from an existing one, 2005-06-25), but imho it is wrong.
Hmph, -c/-C/--amend is like giving the identity with --author from the command line so overriding the values from the environment variables sounds like the right thing to do.
Where am I confused?
Re: [PATCH v2] Introduce CHERRY_PICK_HEAD
Quoted 4 lines · Junio C Hamano
Quoted 2 lines · Jonathan Nieder
Wait, does this mean that -c/-C/--amend/CHERRY_PICK_HEAD overrides
GIT_AUTHOR_NAME,GIT_AUTHOR_EMAIL, andGIT_AUTHOR_DATE?
[...]
Quoted 3 lines
Hmph, -c/-C/--amend is like giving the identity with --author from the command line so overriding the values from the environment variables sounds like the right thing to do.
Good point. There are two principles at work here:
- options with more specific effect override more general ones
- options on the command line override the environment
On second thought, the latter does seem more relevant (though it need not apply to CHERRY_PICK_HEAD).
Thanks for a sanity check.
Jonathan
Re: [PATCH v2] Introduce CHERRY_PICK_HEAD
In reply to Jay Soffianbuiltin/revert.c static void print_advice(void) · line 289
Quoted 13 lines · Jay Soffian
builtin/revert.c +5
-0@@ -263,6 +279,11 @@ static void print_advice(void) if (msg) { fprintf(stderr, "%s\n", msg); + /* + * rebase interactive takes care of the authorship + * when the user invokes rebase --continue + */ + unlink(git_path("CHERRY_PICK_HEAD")); return; }
Oops, I amended the comment and then fed the wrong commit to format-patch. That should be:
@@ -263,6 +279,11 @@ static void print_advice(void)
if (msg) {
fprintf(stderr, "%s\n", msg);
+ /*
+ * we're in the middle of an interactive rebase, we
+ * don't want it to look like we're cherry-picking.
+ */
+ unlink(git_path("CHERRY_PICK_HEAD"));
return;
}Let me know if you want me to resend. (Sorry.)
j.
Re: [PATCH 1/2] Introduce CHERRY_PICK_HEAD
In reply to Jay SoffianQuoted 8 lines · Jay Soffian
When a cherry-pick conflicts git advises to use:
$ git commit -c <original commit id>to preserve the original commit message and authorship. Instead, let's record the original commit id in
CHERRY_PICK_HEADand advise to use:$ git commit -c CHERRY_PICK_HEAD
Wouldn't it be more convenient to do "git cherry-pick --continue" instead of "git commit -c CHERRY_PICK_HEAD"?
Signature · 1 line
Duy
Re: [PATCH 1/2] Introduce CHERRY_PICK_HEAD
Quoted 5 lines · Nguyen Thai Ngoc Duy
Quoted 4 lines · Jay Soffian
When a cherry-pick conflicts git advises to use:
$ git commit -c <original commit id>
Quoted 7 lines
Quoted 4 lines
to preserve the original commit message and authorship. Instead, let's record the original commit id in
CHERRY_PICK_HEADand advise to use:$ git commit -c CHERRY_PICK_HEADWouldn't it be more convenient to do "git cherry-pick --continue" instead of "git commit -c
CHERRY_PICK_HEAD"?
As mentioned in the part of the commit message you trimmed away: "In the next commit, we teach git to handle the '-c CHERRY_PICK_HEAD' part". Now, you may ask, why use "git commit" after resolving the conflict (a la merge) instead of "git cherry-pick --continue" (a la rebase).
I addressed this in the previous thread, see
http://article.gmane.org/gmane.comp.version-control.git/166884
j.
PATCH 2/2 Teach commit about CHERRY_PICK_HEAD
In reply to Jay SoffianPreviously the user was advised to use commit -c CHERRY_PICK_HEAD after a conflicting cherry-pick. While this would preserve the original commit's authorship, it would sadly discard cherry-pick's carefully crafted MERGE_MSG (which contains the list of conflicts as well as the original commit-id in the case of cherry-pick -x).
On the other hand, if a bare 'commit' were performed, it would preserve the MERGE_MSG while resetting the authorship.
In other words, there was no way to simultaneously take the authorship from CHERRY_PICK_HEAD and the commit message from MERGE_MSG.
This change fixes that situation. A bare 'commit' will now take the authorship from CHERRY_PICK_HEAD and the commit message from MERGE_MSG. If the user wishes to reset authorship, that must now be done explicitly via --reset-author.
A side-benefit of passing commit authorship along this way is that we can eliminate redundant authorship parsing code from revert.c.
A couple minor points:
* While we're at it, we update git-completion.bash to be CHERRY_PICK_HEAD aware.
* We remove a unused import from revert.c
--- Documentation/git-commit.txt | 7 +- builtin/commit.c | 137 +++++++++++++++++++++---------- builtin/revert.c | 56 +------------- contrib/completion/git-completion.bash | 2 + t/t3507-cherry-pick-conflict.sh | 2 +- t/t7509-commit.sh | 29 +++++++ wt-status.c | 4 +- wt-status.h | 8 ++- 8 files changed, 139 insertions(+), 106 deletions(-)
Documentation/git-commit.txt +4 -3
@@ -84,9 +84,10 @@ OPTIONS linkgit:git-rebase[1] for details. --reset-author:: - When used with -C/-c/--amend options, declare that the - authorship of the resulting commit now belongs of the committer. - This also renews the author timestamp. + When used with -C/-c/--amend options, or when committing after a + a conflicting cherry-pick, declare that the authorship of the + resulting commit now belongs of the committer. This also renews + the author timestamp. --short:: When doing a dry-run, give the output in the short-format. See
builtin/commit.c +93 -44
270 lines not on this page · raw message
builtin/revert.c +1 -55
80 lines not on this page · raw message
contrib/completion/git-completion.bash +2 -0
@@ -246,6 +246,8 @@ __git_ps1 () fi elif [ -f "$g/MERGE_HEAD" ]; then r="|MERGING" + elif [ -f "$g/CHERRY_PICK_HEAD" ]; then + r="|CHERRY-PICKING" elif [ -f "$g/BISECT_LOG" ]; then r="|BISECTING" fi
t/t3507-cherry-pick-conflict.sh +1 -1
@@ -57,7 +57,7 @@ test_expect_success 'advice from failed cherry-pick' " error: could not apply \$picked... picked hint: after resolving the conflicts, mark the corrected paths hint: with 'git add <paths>' or 'git rm <paths>' - hint: and commit the result with 'git commit -c CHERRY_PICK_HEAD' + hint: and commit the result with 'git commit' EOF test_must_fail git cherry-pick picked 2>actual &&
t/t7509-commit.sh +29 -0
@@ -157,4 +157,33 @@ test_expect_success '--reset-author should be rejected without -c/-C/--amend' ' test_must_fail git commit -a --reset-author -m done ' +test_expect_success 'commit respects CHERRY_PICK_HEAD and MERGE_MSG' ' + echo "cherry-pick 1a" >>foo && + test_tick && + git commit -am "cherry-pick 1" --author="Cherry <[email protected]>" && + git tag cherry-pick-head && + git rev-parse cherry-pick-head >.git/CHERRY_PICK_HEAD && + echo "This is a MERGE_MSG" >.git/MERGE_MSG && + echo "cherry-pick 1b" >>foo && + test_tick && + git commit -a && + author_header cherry-pick-head >expect && + author_header HEAD >actual && + test_cmp expect actual && + + echo "This is a MERGE_MSG" >expect && + message_body HEAD >actual && + test_cmp expect actual +' + +test_expect_success '--reset-author with CHERRY_PICK_HEAD' ' + git rev-parse cherry-pick-head >.git/CHERRY_PICK_HEAD && + echo "cherry-pick 2" >>foo && + test_tick && + git commit -am "cherry-pick 2" --reset-author && + echo "author $GIT_AUTHOR_NAME <$GIT_AUTHOR_EMAIL> $GIT_AUTHOR_DATE" >expect && + author_header HEAD >actual && + test_cmp expect actual +' + test_done
wt-status.c +2 -2
@@ -60,7 +60,7 @@ static void wt_status_print_unmerged_header(struct wt_status *s)color_fprintf_ln (s->fp, c,"# Unmerged paths:" );if (!advice_status_hints)return ; -if (s->in_merge) +if (s->whence !=FROM_COMMIT ) ;else if (!s->is_initial)color_fprintf_ln (s->fp, c,"# (use \"git reset %s <file>...\" to unstage)" , s->reference);
@@ -77,7 +77,7 @@ static void wt_status_print_cached_header(struct wt_status *s)color_fprintf_ln (s->fp, c,"# Changes to be committed:" );if (!advice_status_hints)return ; -if (s->in_merge) +if (s->whence !=FROM_COMMIT ) ;/* NEEDSWORK: use "git reset --unresolve"??? */ else if (!s->is_initial)color_fprintf_ln (s->fp, c,"# (use \"git reset %s <file>...\" to unstage)" , s->reference);
wt-status.h +7 -1
@@ -24,6 +24,12 @@ enum untracked_status_type {SHOW_ALL_UNTRACKED_FILES }; +enum commit_whence { +FROM_COMMIT , +FROM_MERGE , +FROM_CHERRY_PICK +}; +struct wt_status_change_data {int worktree_status;int index_status;
@@ -40,7 +46,7 @@ struct wt_status {const char **pathspec;int verbose;int amend; -int in_merge; +enum commit_whence whence;int nowarn;int use_color;int relative_paths;
Signature · 1 line
1.7.4.1.28.gd46b3
PATCH 1/1 bash: teach __git_ps1 about CHERRY_PICK_HEAD
From: Jay Soffian <[email protected]>
Make the git prompt (when enabled) show a CHERRY-PICKING indicator when we are in the middle of a conflicted cherry-pick, analogous to the existing MERGING and BISECTING flags.
---
Quoted 2 lines
* While we're at it, we update git-completion.bash to be
CHERRY_PICK_HEADaware.
Hmm, it seems I don't like this "while at it". :)
contrib/completion/git-completion.bash | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-)
contrib/completion/git-completion.bash +2 -0
@@ -246,6 +246,8 @@ __git_ps1 () fi elif [ -f "$g/MERGE_HEAD" ]; then r="|MERGING" + elif [ -f "$g/CHERRY_PICK_HEAD" ]; then + r="|CHERRY-PICKING" elif [ -f "$g/BISECT_LOG" ]; then r="|BISECTING" fi
Signature · 1 line
1.7.4.1
Re: [PATCH 1.5/2] bash: teach __git_ps1 about CHERRY_PICK_HEAD
Quoted 1 line · Jonathan Nieder
Hmm, it seems I don't like this "while at it". :)
I don't either. The series will be re-rolled so I don't have to pick this up myself, yes?
Re: [PATCH 2/2] Teach commit about CHERRY_PICK_HEAD
In reply to Jay SoffianQuoted 4 lines · Jay Soffian
This change fixes that situation. A bare 'commit' will now take the authorship from
CHERRY_PICK_HEADand the commit message fromMERGE_MSG. If the user wishes to reset authorship, that must now be done explicitly via --reset-author.
Might also be worth mentioning that it makes --amend fail in such a situation (a change worth celebrating).
builtin/commit.c static const char empty_amend_advice[] = · line 62
Quoted 11 lines
builtin/commit.c +3
-1@@ -56,8 +56,10 @@ static const char empty_amend_advice[] =static unsigned char head_sha1[20 ]; -static char *use_message_buffer; +static const char *use_message_buffer;static const char commit_editmsg[] ="COMMIT_EDITMSG" ; +static const char cherry_pick_head[] ="CHERRY_PICK_HEAD" ; +static const char merge_head[] ="MERGE_HEAD" ;
Hmm, these variables but not MERGE_MSG, MERGE_MODE, and SQUASH_MSG?
builtin/commit.c static enum { · line 73
Quoted 5 lines
builtin/commit.c +1
-0@@ -68,6 +70,7 @@ static enum {static const char *logfile, *force_author;static const char *template_file; +static const char *author_message, *author_message_buffer;
That's not a message at all, is it? On first reading I thought it would be a message about the author. Maybe a comment can help.
/* name and content of commit from which to copy authorship */
builtin/commit.c static enum { · line 95
Quoted 7 lines
builtin/commit.c +2
-1@@ -88,7 +91,8 @@ static enum { } cleanup_mode;static char *cleanup_arg; -static int use_editor =1 , initial_commit, in_merge, include_status =1 ; +static enum commit_whence whence; +static int use_editor =1 , initial_commit, include_status =1 ;
The name "whence" is not so self-explanatory but I don't have any better ideas (I probably would have written "merge_or_cherry_pick"; we can be glad you came up with something better).
builtin/commit.c static struct option builtin_commit_options[] = { · line 173
Quoted 8 lines
builtin/commit.c +4
-0@@ -163,6 +167,36 @@ static struct option builtin_commit_options[] = { OPT_END() }; +static void determine_whence (struct wt_status *s) +{ +if (file_exists (git_path (merge_head))) + whence =FROM_MERGE ;
Micronit: maybe COMMITTING_A_MERGE or COMMIT_DURING_MERGE to avoid using valuable namespace?
builtin/commit.c static int prepare_to_commit(const char *index_file, const char *prefix, · line 682
Quoted 7 lines
builtin/commit.c +1
-1@@ -644,7 +678,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix,* This final case does not modify the template message, * it just sets the argument to the prepare-commit-msg hook. */ - else if (in_merge) + else if (whence == FROM_MERGE) hook_arg1 ="merge" ;
Perhaps:
else if (whence == CHERRY_PICK) {
hook_arg1 = "commit";
hook_arg2 = author_message;
}Quoted 1 line
builtin/commit.c +0
-0@@ -694,16 +728,18 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
[...]
builtin/commit.c static int prepare_to_commit(const char *index_file, const char *prefix, · line 742
Quoted 8 lines
builtin/commit.c +4
-0"# If this is not correct, please remove the file\n" "# %s\n" "# and try again.\n" "#\n" , +whence_s (), +git_path (whence ==FROM_MERGE + ? merge_head + : cherry_pick_head));
Ok. We probably should move away from having to suggest "rm -f .git/whatever" in the future (maybe
git update-ref -d %s
is simpler advice? I dunno).
builtin/commit.c static void handle_untracked_files_arg(struct wt_status *s) · line 937
Quoted 5 lines
builtin/commit.c +1
-0@@ -898,6 +934,27 @@ static void handle_untracked_files_arg(struct wt_status *s)die ("Invalid untracked files mode '%s'" , untracked_files_arg); } +static const char *read_commit_message (const char *name) {
Nice. Opening '{' should be in the first column.
Quoted 1 line
builtin/commit.c +1
-0+++ b/builtin/revert.c
[...]
builtin/commit.c static void print_advice(void) · line 236
Quoted 8 lines
builtin/commit.c +1
-3@@ -284,9 +233,7 @@ static void print_advice(void)advise ("after resolving the conflicts, mark the corrected paths" );advise ("with 'git add <paths>' or 'git rm <paths>'" ); - -if (action ==CHERRY_PICK ) -advise ("and commit the result with 'git commit -c CHERRY_PICK_HEAD'" ); +advise ("and commit the result with 'git commit'" );
Hoorah!
wt-status.c static void wt_status_print_unmerged_header(struct wt_status *s) · line 66
Quoted 11 lines
wt-status.c +1
-1@@ -60,7 +60,7 @@ static void wt_status_print_unmerged_header(struct wt_status *s)color_fprintf_ln (s->fp, c,"# Unmerged paths:" );if (!advice_status_hints)return ; -if (s->in_merge) +if (s->whence !=FROM_COMMIT ) ;else if (!s->is_initial)color_fprintf_ln (s->fp, c,"# (use \"git reset %s <file>...\" to unstage)" , s->reference);
Isn't the advice of using "git reset -- <paths>" still good in the CHERRY_PICK case?
wt-status.c static void wt_status_print_cached_header(struct wt_status *s) · line 81
Quoted 7 lines
wt-status.c +1
-1@@ -77,7 +77,7 @@ static void wt_status_print_cached_header(struct wt_status *s)color_fprintf_ln (s->fp, c,"# Changes to be committed:" );if (!advice_status_hints)return ; -if (s->in_merge) +if (s->whence !=FROM_COMMIT ) ;/* NEEDSWORK: use "git reset --unresolve"??? */
Likewise here.
wt-status.h enum untracked_status_type { · line 31
Quoted 11 lines
wt-status.h +5
-0@@ -24,6 +24,12 @@ enum untracked_status_type { SHOW_ALL_UNTRACKED_FILES }; +enum commit_whence { +FROM_COMMIT , +FROM_MERGE , +FROM_CHERRY_PICK +};
Style: please use tabs to indent.
wt-status.h struct wt_status { · line 49
Quoted 6 lines
wt-status.h +1
-1@@ -40,7 +46,7 @@ struct wt_status {const char **pathspec;int verbose;int amend; -int in_merge; +enum commit_whence whence;
Might benefit from a comment.
/* whether a merge or cherry-pick is in progress */ enum commit_whence whence;
Thanks, very readable.
Re: [PATCH 2/2] Teach commit about CHERRY_PICK_HEAD
Quoted 2 lines · Jonathan Nieder
Might also be worth mentioning that it makes --amend fail in such a situation (a change worth celebrating).
Never made that particular mistake myself, but okay.
Quoted 6 lines
Quoted 6 lines
builtin/commit.c +0
-0@@ -56,8 +56,10 @@ static const char empty_amend_advice[] = static unsigned char head_sha1[20];
Quoted 7 lines
builtin/commit.c static const char empty_amend_advice[] = · line 62
Quoted 5 lines
builtin/commit.c +3
-1-static char *use_message_buffer; +static const char *use_message_buffer; static const char commit_editmsg[] = "COMMIT_EDITMSG"; +static const char cherry_pick_head[] ="CHERRY_PICK_HEAD" ; +static const char merge_head[] ="MERGE_HEAD" ;Hmm, these variables but not
MERGE_MSG,MERGE_MODE, andSQUASH_MSG?
I cleaned up the ones my patch touched. Cleaning up the rest of commit.c was out of my purview. :-)
I'll clean them up to be consistent, but I'll do it as a separate patch (before this one).
Quoted 10 lines
builtin/commit.c static enum { · line 73
Quoted 5 lines
builtin/commit.c +1
-0@@ -68,6 +70,7 @@ static enum { static const char *logfile, *force_author; static const char *template_file; +static const char *author_message, *author_message_buffer;That's not a message at all, is it? On first reading I thought it would be a message about the author. Maybe a comment can help.
/* name and content of commit from which to copy authorship */
The name is consistent with the other similar purpose variables:use_message, edit_message, squash_message, fixup_message, which all take a committish and aren't actually messages. None of those others have comments, but it's obvious in context how they are used.
Quoted 11 lines
builtin/commit.c static enum { · line 95
Quoted 7 lines
builtin/commit.c +2
-1@@ -88,7 +91,8 @@ static enum { } cleanup_mode; static char *cleanup_arg; -static int use_editor =1 , initial_commit, in_merge, include_status =1 ; +static enum commit_whence whence; +static int use_editor =1 , initial_commit, include_status =1 ;The name "whence" is not so self-explanatory but I don't have any better ideas (I probably would have written "
merge_or_cherry_pick"; we can be glad you came up with something better).
Respectfully disagree. Whence means "from where something came" as in "from where did this commit we're about to make originate?" and I intentionally didn't use _ORIGIN as "origin" has another meaning already in git context.
Quoted 11 lines
builtin/commit.c static struct option builtin_commit_options[] = { · line 173
Quoted 8 lines
builtin/commit.c +4
-0@@ -163,6 +167,36 @@ static struct option builtin_commit_options[] = { OPT_END() }; +static void determine_whence (struct wt_status *s) +{ + if (file_exists(git_path(merge_head))) + whence = FROM_MERGE;Micronit: maybe
COMMITTING_A_MERGEorCOMMIT_DURING_MERGEto avoid using valuable namespace?
Respectfully disagree.
Quoted 6 lines
Perhaps:
else if (whence ==
CHERRY_PICK) {
hook_arg1 = "commit";
hook_arg2 =author_message;
}
Perhaps.
Quoted 6 lines
Ok. We probably should move away from having to suggest "rm -f .git/whatever" in the future (maybe
git update-ref -d %s
is simpler advice? I dunno).
Out of scope for this patch. :-)
Quoted 1 line
Nice. Opening '{' should be in the first column.
Good catch.
Quoted 2 lines
Isn't the advice of using "git reset -- <paths>" still good in the
CHERRY_PICKcase?
I don't know. I couldn't make up my mind. If it's a conflicted path you've edited in the working copy, then the advice should be "checkout --merge". I think. Maybe. I don't find wt-status.c to be very much fun, so I punted.
Quoted 5 lines
Quoted 3 lines
builtin/commit.c +1
-1- if (s->in_merge) + if (s->whence != FROM_COMMIT); /* NEEDSWORK: use "git reset --unresolve"??? */
Likewise here.
Checkout that NEEDSWORK. Someone should get on that. :-)
Quoted 1 line
Style: please use tabs to indent.
Who ate my tabs?
Quoted 4 lines
Might benefit from a comment.
/* whether a merge or cherry-pick is in progress */ enum
commit_whencewhence;
Agreed.
Quoted 1 line
Thanks, very readable.
Good feedback.
j.
Re: [PATCH 2/2] Teach commit about CHERRY_PICK_HEAD
In reply to Jay SoffianQuoted 2 lines · Jay Soffian
If the user wishes to reset authorship, that must now be done explicitly via --reset-author.
This is not a new requirement, is it? Even "commit -c $that_commit" before the previous "commit -c CHERRY_PICK_HEAD" does use the original, no?
I think the changed code is _MUCH_ easier to follow compared to the previous round; the only thing the reader needs to keep in mind is that the most of the change essentially is "s/in_merge/whence != FROM_COMMIT/" and making that work.
Quoted 1 line
* We remove a unused import from
revert.c
Micronit: s/import/include/.
builtin/commit.c static int prepare_to_commit(const char *index_file, const char *prefix, · line 808
Quoted 9 lines
builtin/commit.c +1
-1@@ -766,7 +802,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix,fclose (fp); -if (!commitable && !in_merge && !allow_empty && +if (!commitable && whence !=FROM_MERGE && !allow_empty && !(amend &&is_a_merge (head_sha1))) {run_status (stdout, index_file, prefix,0 , s);if (amend)
The original says that we reject an attempt to record a no-change commit when the user is making his own commit without an explicit --allow-empty request. Should cherry-pick change this?
"git cherry-pick $a_no_change_commit" does not cause conflicts but it does fail with "nothing added to commit". If you said "whence == FROM_COMMIT" here, you would end up allowing "git commit" following such a failure to commit without --allow-empty, and that inconsistency is to be avoided (note that I didn't check if you leave CHERRY_PICK_HEAD behind to trigger this codepath when this happens).
On the other hand, when the earlier cherry-pick did fail with conflict, but the resolution ended up to be a no-change commit, you would not blindly want to record the result as a no-change commit, either.
So I think the above is the right thing to do, but we probably need a bit of in-code comment to describe why we say "whence != FROM_MERGE" here.
Thanks.
Re: [PATCH 2/2] Teach commit about CHERRY_PICK_HEAD
Quoted 8 lines · Junio C Hamano
Quoted 2 lines · Jay Soffian
If the user wishes to reset authorship, that must now be done explicitly via --reset-author.
This is not a new requirement, is it? Even "commit -c $that_commit" before the previous "commit -c
CHERRY_PICK_HEAD" does use the original, no?
It is a new requirement for when the user does a bare "commit" _and_ CHERRY_PICK_HEAD exists.
Normally a bare "commit" creates new authorship, but when CHERRY_PICK_HEAD exists, authorship is taken from CHERRY_PICK_HEAD commit unless --reset-author is specified.
Quoted 4 lines
I think the changed code is _MUCH_ easier to follow compared to the previous round; the only thing the reader needs to keep in mind is that the most of the change essentially is "s/in_merge/whence != FROM_COMMIT/" and making that work.
I think I was trying to be too clever in the previous round.
Quoted 3 lines
Quoted 1 line
* We remove a unused import from
revert.cMicronit: s/import/include/.
Okay.
Quoted 2 lines
So I think the above is the right thing to do, but we probably need a bit of in-code comment to describe why we say "whence !=
FROM_MERGE" here.
Will do. It took me several tries to understand what that code block was trying to do, so a comment will certainly help future readers.
Thanks,
j.