revert: allow cherry-pick --continue to commit before resuming

When "git cherry-pick ..bar" encounters conflicts, permit the operator
to use cherry-pick --continue after resolving them as a shortcut for
"git commit && git cherry-pick --continue" to record the resolution
and carry on with the rest of the sequence.

This improves the analogy with "git rebase" (in olden days --continue
was the way to preserve authorship when a rebase encountered
conflicts) and fits well with a general UI goal of making "git cmd
--continue" save humans the trouble of deciding what to do next.

Example: after encountering a conflict from running "git cherry-pick
foo bar baz":

	CONFLICT (content): Merge conflict in main.c
	error: could not apply f78a8d98c... bar!
	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'

We edit main.c to resolve the conflict, mark it acceptable with "git
add main.c", and can run "cherry-pick --continue" to resume the
sequence.

	$ git cherry-pick --continue
	[editor opens to confirm commit message]
	[master 78c8a8c98] bar!
	 1 files changed, 1 insertions(+), 1 deletions(-)
	[master 87ca8798c] baz!
	 1 files changed, 1 insertions(+), 1 deletions(-)

This is done for both codepaths to pick multiple commits and a single
commit.

Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Jonathan Nieder
2011-12-10 06:49:25 -06:00
committed by Junio C Hamano
parent 1df9bf46d6
commit 093a309136
2 changed files with 156 additions and 6 deletions

View File

@ -1038,18 +1038,35 @@ static int pick_commits(struct commit_list *todo_list, struct replay_opts *opts)
return 0;
}
static int continue_single_pick(void)
{
const char *argv[] = { "commit", NULL };
if (!file_exists(git_path("CHERRY_PICK_HEAD")) &&
!file_exists(git_path("REVERT_HEAD")))
return error(_("no cherry-pick or revert in progress"));
return run_command_v_opt(argv, RUN_GIT_CMD);
}
static int sequencer_continue(struct replay_opts *opts)
{
struct commit_list *todo_list = NULL;
if (!file_exists(git_path(SEQ_TODO_FILE)))
return error(_("No %s in progress"), action_name(opts));
return continue_single_pick();
read_populate_opts(&opts);
read_populate_todo(&todo_list, opts);
/* Verify that the conflict has been resolved */
if (!index_differs_from("HEAD", 0))
todo_list = todo_list->next;
if (file_exists(git_path("CHERRY_PICK_HEAD")) ||
file_exists(git_path("REVERT_HEAD"))) {
int ret = continue_single_pick();
if (ret)
return ret;
}
if (index_differs_from("HEAD", 0))
return error_dirty_index(opts);
todo_list = todo_list->next;
return pick_commits(todo_list, opts);
}