diff mbox series

[1/1] revert/cherry-pick: add --show-current-patch option

Message ID 20231218121048.68290-2-mi.al.lohmann@gmail.com (mailing list archive)
State New, archived
Headers show
Series revert/cherry-pick: add --show-current-patch option | expand

Commit Message

Michael Lohmann Dec. 18, 2023, 12:10 p.m. UTC
This aligns the interface to the rebase one and allows for an easier way
of figuring out how to resolve conflicts if commits fail to apply
(especially when reverting/cherry-picking multiple commits at the same
time)

Signed-off-by: Michael Lohmann <mi.al.lohmann@gmail.com>
---
 Documentation/git-cherry-pick.txt      |  2 +-
 Documentation/git-revert.txt           |  2 +-
 Documentation/sequencer.txt            |  5 +++++
 builtin/rebase.c                       |  7 ++----
 builtin/revert.c                       |  9 ++++++--
 contrib/completion/git-completion.bash |  2 +-
 sequencer.c                            | 24 +++++++++++++++++++++
 sequencer.h                            |  2 ++
 t/t3507-cherry-pick-conflict.sh        | 30 ++++++++++++++++++++++++++
 9 files changed, 73 insertions(+), 10 deletions(-)
diff mbox series

Patch

diff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt
index fdcad3d200..af41903fe7 100644
--- a/Documentation/git-cherry-pick.txt
+++ b/Documentation/git-cherry-pick.txt
@@ -10,7 +10,7 @@  SYNOPSIS
 [verse]
 'git cherry-pick' [--edit] [-n] [-m <parent-number>] [-s] [-x] [--ff]
 		  [-S[<keyid>]] <commit>...
-'git cherry-pick' (--continue | --skip | --abort | --quit)
+'git cherry-pick' (--continue | --skip | --abort | --quit | --show-current-patch)
 
 DESCRIPTION
 -----------
diff --git a/Documentation/git-revert.txt b/Documentation/git-revert.txt
index cbe0208834..5bd2ecf35a 100644
--- a/Documentation/git-revert.txt
+++ b/Documentation/git-revert.txt
@@ -9,7 +9,7 @@  SYNOPSIS
 --------
 [verse]
 'git revert' [--[no-]edit] [-n] [-m <parent-number>] [-s] [-S[<keyid>]] <commit>...
-'git revert' (--continue | --skip | --abort | --quit)
+'git revert' (--continue | --skip | --abort | --quit | --show-current-patch)
 
 DESCRIPTION
 -----------
diff --git a/Documentation/sequencer.txt b/Documentation/sequencer.txt
index 3bceb56474..e9394761bc 100644
--- a/Documentation/sequencer.txt
+++ b/Documentation/sequencer.txt
@@ -12,5 +12,10 @@ 
 	to clear the sequencer state after a failed cherry-pick or
 	revert.
 
+--show-current-patch::
+	Show the current patch when a revert or cherry-pick is
+	stopped because of conflicts. This is the equivalent of
+	`git show REVERT_HEAD` or `git show CHERRY_PICK_HEAD`.
+
 --abort::
 	Cancel the operation and return to the pre-sequence state.
diff --git a/builtin/rebase.c b/builtin/rebase.c
index 9f8192e0a5..8ad3cf3e90 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -360,12 +360,9 @@  static int run_sequencer_rebase(struct rebase_options *opts)
 		ret = edit_todo_file(flags);
 		break;
 	case ACTION_SHOW_CURRENT_PATCH: {
-		struct child_process cmd = CHILD_PROCESS_INIT;
-
-		cmd.git_cmd = 1;
-		strvec_pushl(&cmd.args, "show", "REBASE_HEAD", "--", NULL);
-		ret = run_command(&cmd);
+		struct replay_opts replay_opts = get_replay_opts(opts);
 
+		ret = sequencer_show_current_patch(the_repository, &replay_opts);
 		break;
 	}
 	default:
diff --git a/builtin/revert.c b/builtin/revert.c
index e6f9a1ad26..cbcd9fdc23 100644
--- a/builtin/revert.c
+++ b/builtin/revert.c
@@ -24,14 +24,14 @@ 
 
 static const char * const revert_usage[] = {
 	N_("git revert [--[no-]edit] [-n] [-m <parent-number>] [-s] [-S[<keyid>]] <commit>..."),
-	N_("git revert (--continue | --skip | --abort | --quit)"),
+	N_("git revert (--continue | --skip | --abort | --quit | --show-current-patch)"),
 	NULL
 };
 
 static const char * const cherry_pick_usage[] = {
 	N_("git cherry-pick [--edit] [-n] [-m <parent-number>] [-s] [-x] [--ff]\n"
 	   "                [-S[<keyid>]] <commit>..."),
-	N_("git cherry-pick (--continue | --skip | --abort | --quit)"),
+	N_("git cherry-pick (--continue | --skip | --abort | --quit | --show-current-patch)"),
 	NULL
 };
 
@@ -93,6 +93,7 @@  static int run_sequencer(int argc, const char **argv, const char *prefix,
 		OPT_CMDMODE(0, "continue", &cmd, N_("resume revert or cherry-pick sequence"), 'c'),
 		OPT_CMDMODE(0, "abort", &cmd, N_("cancel revert or cherry-pick sequence"), 'a'),
 		OPT_CMDMODE(0, "skip", &cmd, N_("skip current commit and continue"), 's'),
+		OPT_CMDMODE(0, "show-current-patch", &cmd, N_("show the patch file being reverted or cherry-picked"), 'p'),
 		OPT_CLEANUP(&cleanup_arg),
 		OPT_BOOL('n', "no-commit", &opts->no_commit, N_("don't automatically commit")),
 		OPT_BOOL('e', "edit", &opts->edit, N_("edit the commit message")),
@@ -154,6 +155,8 @@  static int run_sequencer(int argc, const char **argv, const char *prefix,
 			this_operation = "--continue";
 		else if (cmd == 's')
 			this_operation = "--skip";
+		else if (cmd == 'p')
+			this_operation = "--show-current-patch";
 		else {
 			assert(cmd == 'a');
 			this_operation = "--abort";
@@ -224,6 +227,8 @@  static int run_sequencer(int argc, const char **argv, const char *prefix,
 		return sequencer_rollback(the_repository, opts);
 	if (cmd == 's')
 		return sequencer_skip(the_repository, opts);
+	if (cmd == 'p')
+		return sequencer_show_current_patch(the_repository, opts);
 	return sequencer_pick_revisions(the_repository, opts);
 }
 
diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index 13a39ebd2e..b740b7d48c 100644
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -1618,7 +1618,7 @@  _git_checkout ()
 	esac
 }
 
-__git_sequencer_inprogress_options="--continue --quit --abort --skip"
+__git_sequencer_inprogress_options="--continue --quit --abort --skip --show-current-patch"
 
 __git_cherry_pick_inprogress_options=$__git_sequencer_inprogress_options
 
diff --git a/sequencer.c b/sequencer.c
index d584cac8ed..3f6f9ad75c 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -3417,6 +3417,30 @@  int sequencer_skip(struct repository *r, struct replay_opts *opts)
 	return -1;
 }
 
+int sequencer_show_current_patch(struct repository *r, struct replay_opts *opts)
+{
+	struct child_process cmd = CHILD_PROCESS_INIT;
+	cmd.git_cmd = 1;
+	switch (opts->action) {
+	case REPLAY_REVERT:
+		if (!refs_ref_exists(get_main_ref_store(r), "REVERT_HEAD"))
+			die(_("No revert in progress?"));
+		strvec_pushl(&cmd.args, "show", "REVERT_HEAD", "--", NULL);
+		break;
+	case REPLAY_PICK:
+		if (!refs_ref_exists(get_main_ref_store(r), "CHERRY_PICK_HEAD"))
+			die(_("No cherry-pick in progress?"));
+		strvec_pushl(&cmd.args, "show", "CHERRY_PICK_HEAD", "--", NULL);
+		break;
+	case REPLAY_INTERACTIVE_REBASE:
+		if (!refs_ref_exists(get_main_ref_store(r), "REBASE_HEAD"))
+			die(_("No rebase in progress?"));
+		strvec_pushl(&cmd.args, "show", "REBASE_HEAD", "--", NULL);
+		break;
+	}
+	return run_command(&cmd);
+}
+
 static int save_todo(struct todo_list *todo_list, struct replay_opts *opts,
 		     int reschedule)
 {
diff --git a/sequencer.h b/sequencer.h
index 913a0f652d..e20cb8bc56 100644
--- a/sequencer.h
+++ b/sequencer.h
@@ -162,6 +162,8 @@  int sequencer_pick_revisions(struct repository *repo,
 			     struct replay_opts *opts);
 int sequencer_continue(struct repository *repo, struct replay_opts *opts);
 int sequencer_rollback(struct repository *repo, struct replay_opts *opts);
+int sequencer_show_current_patch(struct repository *repo,
+				 struct replay_opts *opts);
 int sequencer_skip(struct repository *repo, struct replay_opts *opts);
 void replay_opts_release(struct replay_opts *opts);
 int sequencer_remove_state(struct replay_opts *opts);
diff --git a/t/t3507-cherry-pick-conflict.sh b/t/t3507-cherry-pick-conflict.sh
index c88d597b12..4f50d287a6 100755
--- a/t/t3507-cherry-pick-conflict.sh
+++ b/t/t3507-cherry-pick-conflict.sh
@@ -566,6 +566,36 @@  test_expect_success 'cherry-pick preserves sparse-checkout' '
 	test_grep ! "Changes not staged for commit:" actual
 '
 
+test_expect_success 'cherry-pick --show-current-patch fails if no cherry-pick in progress' '
+	pristine_detach initial &&
+	test_must_fail git cherry-pick --show-current-patch
+'
+
+test_expect_success 'cherry-pick --show-current-patch describes patch that failed to apply' '
+	test_when_finished "git cherry-pick --abort || :" &&
+	pristine_detach initial &&
+	git show picked >expected &&
+
+	test_must_fail git cherry-pick picked &&
+
+	git cherry-pick --show-current-patch >actual &&
+	test_cmp expected actual
+'
+
+test_expect_success 'revert --show-current-patch fails if no revert in progress' '
+	pristine_detach initial &&
+	test_must_fail git revert --show-current-patch
+'
+
+test_expect_success 'revert --show-current-patch describes patch that failed to apply' '
+	test_when_finished "git revert --abort || :" &&
+	pristine_detach initial &&
+	git show picked >expected &&
+	test_must_fail git revert picked &&
+	git revert --show-current-patch >actual &&
+	test_cmp expected actual
+'
+
 test_expect_success 'cherry-pick --continue remembers --keep-redundant-commits' '
 	test_when_finished "git cherry-pick --abort || :" &&
 	pristine_detach initial &&