git@vger.kernel.org list mirror (unofficial, one of many)
 help / color / Atom feed
* [GSoC][PATCH 0/3] Teach cherry-pick/revert to skip commits
@ 2019-06-08 19:19 Rohit Ashiwal
  2019-06-08 19:19 ` [GSoC][PATCH 1/3] sequencer: add advice for revert Rohit Ashiwal
                   ` (9 more replies)
  0 siblings, 10 replies; 87+ messages in thread
From: Rohit Ashiwal @ 2019-06-08 19:19 UTC (permalink / raw)
  To: git; +Cc: newren, t.gummerer, Rohit Ashiwal

git am or rebase advice user to use git am --skip or git rebase --skip
to skip the commit that has become empty or has risen conflicts. OTOH,
cherry-pick advice user to use git reset HEAD which on the user’s part
is annoying and sometimes confusing. This patch series will bring
consistency between advices of these commands with introduction of
`--skip` flag to cherry-pick and revert.

Rohit Ashiwal (3):
  sequencer: add advice for revert
  cherry-pick/revert: add --skip option
  cherry-pick/revert: update hints

 Documentation/git-cherry-pick.txt |  4 +-
 Documentation/git-revert.txt      |  4 +-
 Documentation/sequencer.txt       |  4 ++
 builtin/commit.c                  | 13 ++++---
 builtin/revert.c                  |  5 +++
 sequencer.c                       | 26 ++++++++++++-
 sequencer.h                       |  1 +
 t/t3510-cherry-pick-sequence.sh   | 63 +++++++++++++++++++++++++++++++
 8 files changed, 108 insertions(+), 12 deletions(-)

PR: https://github.com/r1walz/git/pull/1
Reviewed-by: Elijah Newren <newren@gmail.com>
Reviewed-by: Thomas Gummerer <t.gummerer@gmail.com>
-- 
2.21.0


^ permalink raw reply	[flat|nested] 87+ messages in thread

* [GSoC][PATCH 1/3] sequencer: add advice for revert
  2019-06-08 19:19 [GSoC][PATCH 0/3] Teach cherry-pick/revert to skip commits Rohit Ashiwal
@ 2019-06-08 19:19 ` Rohit Ashiwal
  2019-06-09 17:52   ` Phillip Wood
  2019-06-08 19:19 ` [GSoC][PATCH 2/3] cherry-pick/revert: add --skip option Rohit Ashiwal
                   ` (8 subsequent siblings)
  9 siblings, 1 reply; 87+ messages in thread
From: Rohit Ashiwal @ 2019-06-08 19:19 UTC (permalink / raw)
  To: git; +Cc: newren, t.gummerer, Rohit Ashiwal

In the case of merge conflicts, while performing a revert, we are
currently advised to use `git cherry-pick --<sequencer-options>`
of which --continue is incompatible for continuing the revert.
Introduce a separate advice message for `git revert`.

Signed-off-by: Rohit Ashiwal <rohit.ashiwal265@gmail.com>
---
 sequencer.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/sequencer.c b/sequencer.c
index f88a97fb10..9c561a041b 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -2655,6 +2655,7 @@ static int create_seq_dir(void)
 	if (file_exists(git_path_seq_dir())) {
 		error(_("a cherry-pick or revert is already in progress"));
 		advise(_("try \"git cherry-pick (--continue | --quit | --abort)\""));
+		advise(_("or  \"git revert (--continue | --quit | --abort)\""));
 		return -1;
 	} else if (mkdir(git_path_seq_dir(), 0777) < 0)
 		return error_errno(_("could not create sequencer directory '%s'"),
-- 
2.21.0


^ permalink raw reply	[flat|nested] 87+ messages in thread

* [GSoC][PATCH 2/3] cherry-pick/revert: add --skip option
  2019-06-08 19:19 [GSoC][PATCH 0/3] Teach cherry-pick/revert to skip commits Rohit Ashiwal
  2019-06-08 19:19 ` [GSoC][PATCH 1/3] sequencer: add advice for revert Rohit Ashiwal
@ 2019-06-08 19:19 ` Rohit Ashiwal
  2019-06-09  8:37   ` Thomas Gummerer
  2019-06-09 18:01   ` Phillip Wood
  2019-06-08 19:19 ` [GSoC][PATCH 3/3] cherry-pick/revert: update hints Rohit Ashiwal
                   ` (7 subsequent siblings)
  9 siblings, 2 replies; 87+ messages in thread
From: Rohit Ashiwal @ 2019-06-08 19:19 UTC (permalink / raw)
  To: git; +Cc: newren, t.gummerer, Rohit Ashiwal

git am or rebase advise the user to use `git (am | rebase) --skip` to
skip the commit. cherry-pick and revert also have this concept of
skipping commits but they advise the user to use `git reset` (or in
case of a patch which had conflicts, `git reset --merge`) which on the
user's part is annoying and sometimes confusing. Add a `--skip` option
to make these commands more consistent.

In the next commit, we will change the advice messages hence finishing
the process of teaching revert and cherry-pick "how to skip commits".

Signed-off-by: Rohit Ashiwal <rohit.ashiwal265@gmail.com>
---
 Documentation/git-cherry-pick.txt |  4 +-
 Documentation/git-revert.txt      |  4 +-
 Documentation/sequencer.txt       |  4 ++
 builtin/revert.c                  |  5 +++
 sequencer.c                       | 23 +++++++++++
 sequencer.h                       |  1 +
 t/t3510-cherry-pick-sequence.sh   | 63 +++++++++++++++++++++++++++++++
 7 files changed, 98 insertions(+), 6 deletions(-)

diff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt
index 754b16ce0c..955880ab88 100644
--- a/Documentation/git-cherry-pick.txt
+++ b/Documentation/git-cherry-pick.txt
@@ -10,9 +10,7 @@ SYNOPSIS
 [verse]
 'git cherry-pick' [--edit] [-n] [-m parent-number] [-s] [-x] [--ff]
 		  [-S[<keyid>]] <commit>...
-'git cherry-pick' --continue
-'git cherry-pick' --quit
-'git cherry-pick' --abort
+'git cherry-pick' --continue | --skip | --abort | --quit
 
 DESCRIPTION
 -----------
diff --git a/Documentation/git-revert.txt b/Documentation/git-revert.txt
index 0c82ca5bc0..ffce98099c 100644
--- a/Documentation/git-revert.txt
+++ b/Documentation/git-revert.txt
@@ -9,9 +9,7 @@ SYNOPSIS
 --------
 [verse]
 'git revert' [--[no-]edit] [-n] [-m parent-number] [-s] [-S[<keyid>]] <commit>...
-'git revert' --continue
-'git revert' --quit
-'git revert' --abort
+'git revert' --continue | --skip | --abort | --quit
 
 DESCRIPTION
 -----------
diff --git a/Documentation/sequencer.txt b/Documentation/sequencer.txt
index 5a57c4a407..3bceb56474 100644
--- a/Documentation/sequencer.txt
+++ b/Documentation/sequencer.txt
@@ -3,6 +3,10 @@
 	`.git/sequencer`.  Can be used to continue after resolving
 	conflicts in a failed cherry-pick or revert.
 
+--skip::
+	Skip the current commit and continue with the rest of the
+	sequence.
+
 --quit::
 	Forget about the current operation in progress.  Can be used
 	to clear the sequencer state after a failed cherry-pick or
diff --git a/builtin/revert.c b/builtin/revert.c
index d4dcedbdc6..5dc5891ea2 100644
--- a/builtin/revert.c
+++ b/builtin/revert.c
@@ -102,6 +102,7 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)
 		OPT_CMDMODE(0, "quit", &cmd, N_("end revert or cherry-pick sequence"), 'q'),
 		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_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")),
@@ -151,6 +152,8 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)
 			this_operation = "--quit";
 		else if (cmd == 'c')
 			this_operation = "--continue";
+		else if (cmd == 's')
+			this_operation = "--skip";
 		else {
 			assert(cmd == 'a');
 			this_operation = "--abort";
@@ -210,6 +213,8 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)
 		return sequencer_continue(the_repository, opts);
 	if (cmd == 'a')
 		return sequencer_rollback(the_repository, opts);
+	if (cmd == 's')
+		return sequencer_skip(the_repository, opts);
 	return sequencer_pick_revisions(the_repository, opts);
 }
 
diff --git a/sequencer.c b/sequencer.c
index 9c561a041b..f586e677d3 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -2784,6 +2784,29 @@ int sequencer_rollback(struct repository *r, struct replay_opts *opts)
 	return -1;
 }
 
+int sequencer_skip(struct repository *r, struct replay_opts *opts)
+{
+	switch (opts->action) {
+	case REPLAY_REVERT:
+		if (!file_exists(git_path_revert_head(r)))
+			return error(_("no revert in progress"));
+		break;
+	case REPLAY_PICK:
+		if (!file_exists(git_path_cherry_pick_head(r)))
+			return error(_("no cherry-pick in progress"));
+		break;
+	default:
+		BUG("the control must not reach here.");
+	}
+
+	if (rollback_single_pick(r))
+		return error(_("failed to skip the commit"));
+	if (!is_directory(git_path_seq_dir()))
+		return 0;
+
+	return sequencer_continue(r, opts);
+}
+
 static int save_todo(struct todo_list *todo_list, struct replay_opts *opts)
 {
 	struct lock_file todo_lock = LOCK_INIT;
diff --git a/sequencer.h b/sequencer.h
index 0c494b83d4..731b9853eb 100644
--- a/sequencer.h
+++ b/sequencer.h
@@ -129,6 +129,7 @@ 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_skip(struct repository *repo, struct replay_opts *opts);
 int sequencer_remove_state(struct replay_opts *opts);
 
 #define TODO_LIST_KEEP_EMPTY (1U << 0)
diff --git a/t/t3510-cherry-pick-sequence.sh b/t/t3510-cherry-pick-sequence.sh
index 941d5026da..48cc9f13ee 100755
--- a/t/t3510-cherry-pick-sequence.sh
+++ b/t/t3510-cherry-pick-sequence.sh
@@ -93,6 +93,69 @@ test_expect_success 'cherry-pick cleans up sequencer state upon success' '
 	test_path_is_missing .git/sequencer
 '
 
+test_expect_success 'cherry-pick --skip requires cherry-pick in progress' '
+	pristine_detach initial &&
+	test_must_fail git cherry-pick --skip
+'
+
+test_expect_success 'revert --skip requires revert in progress' '
+	pristine_detach initial &&
+	test_must_fail git revert --skip
+'
+
+test_expect_success 'cherry-pick --skip to skip commit' '
+	pristine_detach initial &&
+	test_must_fail git cherry-pick anotherpick &&
+	test_must_fail git revert --skip &&
+	git cherry-pick --skip &&
+	test_cmp_rev initial HEAD &&
+	test_path_is_missing .git/CHERRY_PICK_HEAD
+'
+
+test_expect_success 'revert --skip to skip commit' '
+	pristine_detach anotherpick &&
+	test_must_fail git revert anotherpick~1 &&
+	test_must_fail git cherry-pick --skip &&
+	git revert --skip &&
+	test_cmp_rev anotherpick HEAD
+'
+
+test_expect_success 'skip "empty" commit' '
+	pristine_detach picked &&
+	test_commit dummy foo d &&
+	test_must_fail git cherry-pick anotherpick &&
+	git cherry-pick --skip &&
+	test_cmp_rev dummy HEAD
+'
+
+test_expect_success 'skip a commit and check if rest of sequence is correct' '
+	pristine_detach initial &&
+	echo e >expect &&
+	cat >expect.log <<-EOF &&
+	OBJID
+	:100644 100644 OBJID OBJID M	foo
+	OBJID
+	:100644 100644 OBJID OBJID M	foo
+	OBJID
+	:100644 100644 OBJID OBJID M	unrelated
+	OBJID
+	:000000 100644 OBJID OBJID A	foo
+	:000000 100644 OBJID OBJID A	unrelated
+	EOF
+	test_must_fail git cherry-pick base..yetanotherpick &&
+	test_must_fail git cherry-pick --skip &&
+	echo d >foo &&
+	git add foo &&
+	git cherry-pick --continue &&
+	{
+		git rev-list HEAD |
+		git diff-tree --root --stdin |
+		sed "s/$OID_REGEX/OBJID/g"
+	} >actual.log &&
+	test_cmp expect foo &&
+	test_cmp expect.log actual.log
+'
+
 test_expect_success '--quit does not complain when no cherry-pick is in progress' '
 	pristine_detach initial &&
 	git cherry-pick --quit
-- 
2.21.0


^ permalink raw reply	[flat|nested] 87+ messages in thread

* [GSoC][PATCH 3/3] cherry-pick/revert: update hints
  2019-06-08 19:19 [GSoC][PATCH 0/3] Teach cherry-pick/revert to skip commits Rohit Ashiwal
  2019-06-08 19:19 ` [GSoC][PATCH 1/3] sequencer: add advice for revert Rohit Ashiwal
  2019-06-08 19:19 ` [GSoC][PATCH 2/3] cherry-pick/revert: add --skip option Rohit Ashiwal
@ 2019-06-08 19:19 ` Rohit Ashiwal
  2019-06-09  8:42   ` Thomas Gummerer
  2019-06-09 18:03   ` Phillip Wood
  2019-06-09  9:02 ` [GSoC][PATCH 0/3] Teach cherry-pick/revert to skip commits Thomas Gummerer
                   ` (6 subsequent siblings)
  9 siblings, 2 replies; 87+ messages in thread
From: Rohit Ashiwal @ 2019-06-08 19:19 UTC (permalink / raw)
  To: git; +Cc: newren, t.gummerer, Rohit Ashiwal

Signed-off-by: Rohit Ashiwal <rohit.ashiwal265@gmail.com>
---
 builtin/commit.c | 13 ++++++++-----
 sequencer.c      |  4 ++--
 2 files changed, 10 insertions(+), 7 deletions(-)

diff --git a/builtin/commit.c b/builtin/commit.c
index 1c9e8e2228..1f47c51bdc 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -60,15 +60,18 @@ N_("The previous cherry-pick is now empty, possibly due to conflict resolution.\
 "\n");
 
 static const char empty_cherry_pick_advice_single[] =
-N_("Otherwise, please use 'git reset'\n");
+N_("Otherwise, please use 'git cherry-pick --skip'\n");
 
 static const char empty_cherry_pick_advice_multi[] =
-N_("If you wish to skip this commit, use:\n"
+N_("and then use:\n"
 "\n"
-"    git reset\n"
+"    git cherry-pick --continue\n"
 "\n"
-"Then \"git cherry-pick --continue\" will resume cherry-picking\n"
-"the remaining commits.\n");
+"to resume cherry-picking the remaining commits.\n"
+"If you wish to skip this commit, use:\n"
+"\n"
+"    git cherry-pick --skip\n"
+"\n");
 
 static const char *color_status_slots[] = {
 	[WT_STATUS_HEADER]	  = "header",
diff --git a/sequencer.c b/sequencer.c
index f586e677d3..e889427eef 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -2654,8 +2654,8 @@ static int create_seq_dir(void)
 {
 	if (file_exists(git_path_seq_dir())) {
 		error(_("a cherry-pick or revert is already in progress"));
-		advise(_("try \"git cherry-pick (--continue | --quit | --abort)\""));
-		advise(_("or  \"git revert (--continue | --quit | --abort)\""));
+		advise(_("try \"git cherry-pick (--continue | --skip | --quit | --abort)\""));
+		advise(_("or  \"git revert (--continue | --skip | --quit | --abort)\""));
 		return -1;
 	} else if (mkdir(git_path_seq_dir(), 0777) < 0)
 		return error_errno(_("could not create sequencer directory '%s'"),
-- 
2.21.0


^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [GSoC][PATCH 2/3] cherry-pick/revert: add --skip option
  2019-06-08 19:19 ` [GSoC][PATCH 2/3] cherry-pick/revert: add --skip option Rohit Ashiwal
@ 2019-06-09  8:37   ` Thomas Gummerer
  2019-06-09 18:01   ` Phillip Wood
  1 sibling, 0 replies; 87+ messages in thread
From: Thomas Gummerer @ 2019-06-09  8:37 UTC (permalink / raw)
  To: Rohit Ashiwal; +Cc: git, newren

On 06/09, Rohit Ashiwal wrote:
> git am or rebase advise the user to use `git (am | rebase) --skip` to
> skip the commit. cherry-pick and revert also have this concept of
> skipping commits but they advise the user to use `git reset` (or in
> case of a patch which had conflicts, `git reset --merge`) which on the
> user's part is annoying and sometimes confusing. Add a `--skip` option
> to make these commands more consistent.

Something I missed in the off-list review for this PR:  I think this
commit message is a bit heavy on the advice part, rather than on the
real advantage the --skip flag brings, which is that it's less
cumbersome for the user to skip a commit, and brings consistency to
the commands.  Maybe something like:

        git am or rebase have a --skip flag to skip the current commit if
        the user wishes to do so.  During a cherry-pick or revert a user
        could likewise skip a commit, but needs to use 'git reset' (or in
        the case of conflicts 'git reset --merge'), followed by 'git
        (cherry-pick | revert) --continue' to skip the commit.  This is
        more annoying and sometimes confusing on the users part.  Add a
        `--skip` option to make skipping commits easier for the user and
        to make the commands more consistent.

> In the next commit, we will change the advice messages hence finishing
> the process of teaching revert and cherry-pick "how to skip commits".
> 
> Signed-off-by: Rohit Ashiwal <rohit.ashiwal265@gmail.com>
> ---
>  Documentation/git-cherry-pick.txt |  4 +-
>  Documentation/git-revert.txt      |  4 +-
>  Documentation/sequencer.txt       |  4 ++
>  builtin/revert.c                  |  5 +++
>  sequencer.c                       | 23 +++++++++++
>  sequencer.h                       |  1 +
>  t/t3510-cherry-pick-sequence.sh   | 63 +++++++++++++++++++++++++++++++
>  7 files changed, 98 insertions(+), 6 deletions(-)
> 
> diff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt
> index 754b16ce0c..955880ab88 100644
> --- a/Documentation/git-cherry-pick.txt
> +++ b/Documentation/git-cherry-pick.txt
> @@ -10,9 +10,7 @@ SYNOPSIS
>  [verse]
>  'git cherry-pick' [--edit] [-n] [-m parent-number] [-s] [-x] [--ff]
>  		  [-S[<keyid>]] <commit>...
> -'git cherry-pick' --continue
> -'git cherry-pick' --quit
> -'git cherry-pick' --abort
> +'git cherry-pick' --continue | --skip | --abort | --quit
>  
>  DESCRIPTION
>  -----------
> diff --git a/Documentation/git-revert.txt b/Documentation/git-revert.txt
> index 0c82ca5bc0..ffce98099c 100644
> --- a/Documentation/git-revert.txt
> +++ b/Documentation/git-revert.txt
> @@ -9,9 +9,7 @@ SYNOPSIS
>  --------
>  [verse]
>  'git revert' [--[no-]edit] [-n] [-m parent-number] [-s] [-S[<keyid>]] <commit>...
> -'git revert' --continue
> -'git revert' --quit
> -'git revert' --abort
> +'git revert' --continue | --skip | --abort | --quit
>  
>  DESCRIPTION
>  -----------
> diff --git a/Documentation/sequencer.txt b/Documentation/sequencer.txt
> index 5a57c4a407..3bceb56474 100644
> --- a/Documentation/sequencer.txt
> +++ b/Documentation/sequencer.txt
> @@ -3,6 +3,10 @@
>  	`.git/sequencer`.  Can be used to continue after resolving
>  	conflicts in a failed cherry-pick or revert.
>  
> +--skip::
> +	Skip the current commit and continue with the rest of the
> +	sequence.
> +
>  --quit::
>  	Forget about the current operation in progress.  Can be used
>  	to clear the sequencer state after a failed cherry-pick or
> diff --git a/builtin/revert.c b/builtin/revert.c
> index d4dcedbdc6..5dc5891ea2 100644
> --- a/builtin/revert.c
> +++ b/builtin/revert.c
> @@ -102,6 +102,7 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)
>  		OPT_CMDMODE(0, "quit", &cmd, N_("end revert or cherry-pick sequence"), 'q'),
>  		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_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")),
> @@ -151,6 +152,8 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)
>  			this_operation = "--quit";
>  		else if (cmd == 'c')
>  			this_operation = "--continue";
> +		else if (cmd == 's')
> +			this_operation = "--skip";
>  		else {
>  			assert(cmd == 'a');
>  			this_operation = "--abort";
> @@ -210,6 +213,8 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)
>  		return sequencer_continue(the_repository, opts);
>  	if (cmd == 'a')
>  		return sequencer_rollback(the_repository, opts);
> +	if (cmd == 's')
> +		return sequencer_skip(the_repository, opts);
>  	return sequencer_pick_revisions(the_repository, opts);
>  }
>  
> diff --git a/sequencer.c b/sequencer.c
> index 9c561a041b..f586e677d3 100644
> --- a/sequencer.c
> +++ b/sequencer.c
> @@ -2784,6 +2784,29 @@ int sequencer_rollback(struct repository *r, struct replay_opts *opts)
>  	return -1;
>  }
>  
> +int sequencer_skip(struct repository *r, struct replay_opts *opts)
> +{
> +	switch (opts->action) {
> +	case REPLAY_REVERT:
> +		if (!file_exists(git_path_revert_head(r)))
> +			return error(_("no revert in progress"));
> +		break;
> +	case REPLAY_PICK:
> +		if (!file_exists(git_path_cherry_pick_head(r)))
> +			return error(_("no cherry-pick in progress"));
> +		break;

I see that in some cases (e.g 'rollback_single_pick'), we just check
if either REVERT_HEAD or CHERRY_PICK_HEAD exist, but would allow the
"wrong" command to be used, e.g. 'git revert --abort' when a
cherry-pick is in progress.  This helps avoiding that, good!

> +	default:
> +		BUG("the control must not reach here.");

We don't support rebase in 'sequencer_skip' yet, makes sense as this
patch is focused on cherry-pick and revert.  There's nothing
preventing supporting that in the future though.

> +	}
> +
> +	if (rollback_single_pick(r))
> +		return error(_("failed to skip the commit"));
> +	if (!is_directory(git_path_seq_dir()))
> +		return 0;

If there's no sequencer directory, we don't need to continue the
cherry-pick/revert, as there's nothing left to do.  Otherwise we
continue.  Good.

So this looks good to me.

> +
> +	return sequencer_continue(r, opts);
> +}
> +
>  static int save_todo(struct todo_list *todo_list, struct replay_opts *opts)
>  {
>  	struct lock_file todo_lock = LOCK_INIT;
> diff --git a/sequencer.h b/sequencer.h
> index 0c494b83d4..731b9853eb 100644
> --- a/sequencer.h
> +++ b/sequencer.h
> @@ -129,6 +129,7 @@ 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_skip(struct repository *repo, struct replay_opts *opts);
>  int sequencer_remove_state(struct replay_opts *opts);
>  
>  #define TODO_LIST_KEEP_EMPTY (1U << 0)
> diff --git a/t/t3510-cherry-pick-sequence.sh b/t/t3510-cherry-pick-sequence.sh
> index 941d5026da..48cc9f13ee 100755
> --- a/t/t3510-cherry-pick-sequence.sh
> +++ b/t/t3510-cherry-pick-sequence.sh
> @@ -93,6 +93,69 @@ test_expect_success 'cherry-pick cleans up sequencer state upon success' '
>  	test_path_is_missing .git/sequencer
>  '
>  
> +test_expect_success 'cherry-pick --skip requires cherry-pick in progress' '
> +	pristine_detach initial &&
> +	test_must_fail git cherry-pick --skip
> +'
> +
> +test_expect_success 'revert --skip requires revert in progress' '
> +	pristine_detach initial &&
> +	test_must_fail git revert --skip
> +'
> +
> +test_expect_success 'cherry-pick --skip to skip commit' '
> +	pristine_detach initial &&
> +	test_must_fail git cherry-pick anotherpick &&
> +	test_must_fail git revert --skip &&
> +	git cherry-pick --skip &&
> +	test_cmp_rev initial HEAD &&
> +	test_path_is_missing .git/CHERRY_PICK_HEAD
> +'
> +
> +test_expect_success 'revert --skip to skip commit' '
> +	pristine_detach anotherpick &&
> +	test_must_fail git revert anotherpick~1 &&
> +	test_must_fail git cherry-pick --skip &&
> +	git revert --skip &&
> +	test_cmp_rev anotherpick HEAD
> +'
> +
> +test_expect_success 'skip "empty" commit' '
> +	pristine_detach picked &&
> +	test_commit dummy foo d &&
> +	test_must_fail git cherry-pick anotherpick &&
> +	git cherry-pick --skip &&
> +	test_cmp_rev dummy HEAD
> +'
> +
> +test_expect_success 'skip a commit and check if rest of sequence is correct' '
> +	pristine_detach initial &&
> +	echo e >expect &&
> +	cat >expect.log <<-EOF &&
> +	OBJID
> +	:100644 100644 OBJID OBJID M	foo
> +	OBJID
> +	:100644 100644 OBJID OBJID M	foo
> +	OBJID
> +	:100644 100644 OBJID OBJID M	unrelated
> +	OBJID
> +	:000000 100644 OBJID OBJID A	foo
> +	:000000 100644 OBJID OBJID A	unrelated
> +	EOF
> +	test_must_fail git cherry-pick base..yetanotherpick &&
> +	test_must_fail git cherry-pick --skip &&
> +	echo d >foo &&
> +	git add foo &&
> +	git cherry-pick --continue &&
> +	{
> +		git rev-list HEAD |
> +		git diff-tree --root --stdin |
> +		sed "s/$OID_REGEX/OBJID/g"
> +	} >actual.log &&
> +	test_cmp expect foo &&
> +	test_cmp expect.log actual.log
> +'
> +
>  test_expect_success '--quit does not complain when no cherry-pick is in progress' '
>  	pristine_detach initial &&
>  	git cherry-pick --quit
> -- 
> 2.21.0
> 

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [GSoC][PATCH 3/3] cherry-pick/revert: update hints
  2019-06-08 19:19 ` [GSoC][PATCH 3/3] cherry-pick/revert: update hints Rohit Ashiwal
@ 2019-06-09  8:42   ` Thomas Gummerer
  2019-06-09 18:03   ` Phillip Wood
  1 sibling, 0 replies; 87+ messages in thread
From: Thomas Gummerer @ 2019-06-09  8:42 UTC (permalink / raw)
  To: Rohit Ashiwal; +Cc: git, newren

> Subject: [GSoC][PATCH 3/3] cherry-pick/revert: update hints

"update hints" is very generic when read in 'git log --oneline', and
doesn't give the reader much useful information.  Maybe something like

        cherry-pick/revert: advice using --skip

        In the previous commit we introduced a --skip flag for
        cherry-pick and revert.  Update the advice messages, to tell
        users about this less cumbersome way of skipping commits

would work better?  The rest of the patch looks good to me.

On 06/09, Rohit Ashiwal wrote:
> Signed-off-by: Rohit Ashiwal <rohit.ashiwal265@gmail.com>
> ---
>  builtin/commit.c | 13 ++++++++-----
>  sequencer.c      |  4 ++--
>  2 files changed, 10 insertions(+), 7 deletions(-)
> 
> diff --git a/builtin/commit.c b/builtin/commit.c
> index 1c9e8e2228..1f47c51bdc 100644
> --- a/builtin/commit.c
> +++ b/builtin/commit.c
> @@ -60,15 +60,18 @@ N_("The previous cherry-pick is now empty, possibly due to conflict resolution.\
>  "\n");
>  
>  static const char empty_cherry_pick_advice_single[] =
> -N_("Otherwise, please use 'git reset'\n");
> +N_("Otherwise, please use 'git cherry-pick --skip'\n");
>  
>  static const char empty_cherry_pick_advice_multi[] =
> -N_("If you wish to skip this commit, use:\n"
> +N_("and then use:\n"
>  "\n"
> -"    git reset\n"
> +"    git cherry-pick --continue\n"
>  "\n"
> -"Then \"git cherry-pick --continue\" will resume cherry-picking\n"
> -"the remaining commits.\n");
> +"to resume cherry-picking the remaining commits.\n"
> +"If you wish to skip this commit, use:\n"
> +"\n"
> +"    git cherry-pick --skip\n"
> +"\n");
>  
>  static const char *color_status_slots[] = {
>  	[WT_STATUS_HEADER]	  = "header",
> diff --git a/sequencer.c b/sequencer.c
> index f586e677d3..e889427eef 100644
> --- a/sequencer.c
> +++ b/sequencer.c
> @@ -2654,8 +2654,8 @@ static int create_seq_dir(void)
>  {
>  	if (file_exists(git_path_seq_dir())) {
>  		error(_("a cherry-pick or revert is already in progress"));
> -		advise(_("try \"git cherry-pick (--continue | --quit | --abort)\""));
> -		advise(_("or  \"git revert (--continue | --quit | --abort)\""));
> +		advise(_("try \"git cherry-pick (--continue | --skip | --quit | --abort)\""));
> +		advise(_("or  \"git revert (--continue | --skip | --quit | --abort)\""));
>  		return -1;
>  	} else if (mkdir(git_path_seq_dir(), 0777) < 0)
>  		return error_errno(_("could not create sequencer directory '%s'"),
> -- 
> 2.21.0
> 

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [GSoC][PATCH 0/3] Teach cherry-pick/revert to skip commits
  2019-06-08 19:19 [GSoC][PATCH 0/3] Teach cherry-pick/revert to skip commits Rohit Ashiwal
                   ` (2 preceding siblings ...)
  2019-06-08 19:19 ` [GSoC][PATCH 3/3] cherry-pick/revert: update hints Rohit Ashiwal
@ 2019-06-09  9:02 ` Thomas Gummerer
  2019-06-09 10:06   ` Rohit Ashiwal
  2019-06-11  7:31 ` [GSoC][PATCH v2 " Rohit Ashiwal
                   ` (5 subsequent siblings)
  9 siblings, 1 reply; 87+ messages in thread
From: Thomas Gummerer @ 2019-06-09  9:02 UTC (permalink / raw)
  To: Rohit Ashiwal; +Cc: git, newren

On 06/09, Rohit Ashiwal wrote:
> git am or rebase advice user to use git am --skip or git rebase --skip
> to skip the commit that has become empty or has risen conflicts. OTOH,
> cherry-pick advice user to use git reset HEAD which on the user’s part
> is annoying and sometimes confusing. This patch series will bring
> consistency between advices of these commands with introduction of
> `--skip` flag to cherry-pick and revert.

Thanks!  I found a few minor nits that I missed in my off-list review
on the PR.  We should give others some time to comment now before you
re-send it with the nits fixed (if you agree with them).

One thing that would be good to add to future cover letters is a
reminder of how this fits in to your GSoC project, where the overall
end goal is to improve the consistency of sequencer commands, and this
is one step along that way.

> Rohit Ashiwal (3):
>   sequencer: add advice for revert
>   cherry-pick/revert: add --skip option
>   cherry-pick/revert: update hints
> 
>  Documentation/git-cherry-pick.txt |  4 +-
>  Documentation/git-revert.txt      |  4 +-
>  Documentation/sequencer.txt       |  4 ++
>  builtin/commit.c                  | 13 ++++---
>  builtin/revert.c                  |  5 +++
>  sequencer.c                       | 26 ++++++++++++-
>  sequencer.h                       |  1 +
>  t/t3510-cherry-pick-sequence.sh   | 63 +++++++++++++++++++++++++++++++
>  8 files changed, 108 insertions(+), 12 deletions(-)
> 
> PR: https://github.com/r1walz/git/pull/1
> Reviewed-by: Elijah Newren <newren@gmail.com>
> Reviewed-by: Thomas Gummerer <t.gummerer@gmail.com>

Note that the 'Reviewed-by' footer is something that is "given" by the
reviewers, and should only be added after they have explicitly given
it for the patch/series in question.  Instead this should probably
mention that Elijah and me reviewed this off-list in the PR you linked
to above.

> -- 
> 2.21.0
> 

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [GSoC][PATCH 0/3] Teach cherry-pick/revert to skip commits
  2019-06-09  9:02 ` [GSoC][PATCH 0/3] Teach cherry-pick/revert to skip commits Thomas Gummerer
@ 2019-06-09 10:06   ` Rohit Ashiwal
  2019-06-09 20:00     ` Thomas Gummerer
  0 siblings, 1 reply; 87+ messages in thread
From: Rohit Ashiwal @ 2019-06-09 10:06 UTC (permalink / raw)
  To: Thomas Gummerer; +Cc: git, Elijah Newren

Hey Thomas

On Sun, Jun 9, 2019 at 2:32 PM Thomas Gummerer <t.gummerer@gmail.com> wrote:
>
> Thanks!  I found a few minor nits that I missed in my off-list review
> on the PR.  We should give others some time to comment now before you
> re-send it with the nits fixed (if you agree with them).

Yes, I'll wait for some more reviews before sending another iteration.

> One thing that would be good to add to future cover letters is a
> reminder of how this fits in to your GSoC project, where the overall
> end goal is to improve the consistency of sequencer commands, and this
> is one step along that way.

Sure, I'll keep this in mind and send some kind of summary in the next
revision.

>
> > PR: https://github.com/r1walz/git/pull/1
> > Reviewed-by: Elijah Newren <newren@gmail.com>
> > Reviewed-by: Thomas Gummerer <t.gummerer@gmail.com>
>
> Note that the 'Reviewed-by' footer is something that is "given" by the
> reviewers, and should only be added after they have explicitly given
> it for the patch/series in question.  Instead this should probably
> mention that Elijah and me reviewed this off-list in the PR you linked
> to above.

Oh! But I read here, SubmittingPatches[1] docs, that it's nice to give
credits to those who helped you. Should we fix it in some way? I don't
know. Anyway, that is beyond the scope of this patch.

>
> > --
> > 2.21.0
> >

Thanks for the review
Rohit

[1]: https://github.com/git/git/blob/v2.22.0/Documentation/SubmittingPatches#L289-L291

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [GSoC][PATCH 1/3] sequencer: add advice for revert
  2019-06-08 19:19 ` [GSoC][PATCH 1/3] sequencer: add advice for revert Rohit Ashiwal
@ 2019-06-09 17:52   ` Phillip Wood
  2019-06-10  5:13     ` Rohit Ashiwal
  0 siblings, 1 reply; 87+ messages in thread
From: Phillip Wood @ 2019-06-09 17:52 UTC (permalink / raw)
  To: Rohit Ashiwal, git; +Cc: newren, t.gummerer

Hi Rohit

Congratulations on your first GSoC patch series!

On 08/06/2019 20:19, Rohit Ashiwal wrote:
> In the case of merge conflicts, while performing a revert, we are
> currently advised to use `git cherry-pick --<sequencer-options>`
> of which --continue is incompatible for continuing the revert.
> Introduce a separate advice message for `git revert`.
> 
> Signed-off-by: Rohit Ashiwal <rohit.ashiwal265@gmail.com>
> ---
>  sequencer.c | 1 +
>  1 file changed, 1 insertion(+)
> 
> diff --git a/sequencer.c b/sequencer.c
> index f88a97fb10..9c561a041b 100644
> --- a/sequencer.c
> +++ b/sequencer.c
> @@ -2655,6 +2655,7 @@ static int create_seq_dir(void)
>  	if (file_exists(git_path_seq_dir())) {
>  		error(_("a cherry-pick or revert is already in progress"));
>  		advise(_("try \"git cherry-pick (--continue | --quit | --abort)\""));
> +		advise(_("or  \"git revert (--continue | --quit | --abort)\""));

I agree that it's a good idea to add advice for revert as well, but it
would be better to call sequencer_get_last_command() to find out if
we're running cherry-pick or revert and tailor the advice appropriately.

Best Wishes

Phillip

>  		return -1;
>  	} else if (mkdir(git_path_seq_dir(), 0777) < 0)
>  		return error_errno(_("could not create sequencer directory '%s'"),
> 


^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [GSoC][PATCH 2/3] cherry-pick/revert: add --skip option
  2019-06-08 19:19 ` [GSoC][PATCH 2/3] cherry-pick/revert: add --skip option Rohit Ashiwal
  2019-06-09  8:37   ` Thomas Gummerer
@ 2019-06-09 18:01   ` Phillip Wood
  2019-06-10  5:57     ` Rohit Ashiwal
  1 sibling, 1 reply; 87+ messages in thread
From: Phillip Wood @ 2019-06-09 18:01 UTC (permalink / raw)
  To: Rohit Ashiwal, git; +Cc: newren, t.gummerer

Hi Rohit

--skip is definitely a useful addition to cherry-pick/revert

On 08/06/2019 20:19, Rohit Ashiwal wrote:
> git am or rebase advise the user to use `git (am | rebase) --skip` to
> skip the commit. cherry-pick and revert also have this concept of
> skipping commits but they advise the user to use `git reset` (or in
> case of a patch which had conflicts, `git reset --merge`) which on the
> user's part is annoying and sometimes confusing. Add a `--skip` option
> to make these commands more consistent.
> 
> In the next commit, we will change the advice messages hence finishing
> the process of teaching revert and cherry-pick "how to skip commits".
> 
> Signed-off-by: Rohit Ashiwal <rohit.ashiwal265@gmail.com>
> ---
>  Documentation/git-cherry-pick.txt |  4 +-
>  Documentation/git-revert.txt      |  4 +-
>  Documentation/sequencer.txt       |  4 ++
>  builtin/revert.c                  |  5 +++
>  sequencer.c                       | 23 +++++++++++
>  sequencer.h                       |  1 +
>  t/t3510-cherry-pick-sequence.sh   | 63 +++++++++++++++++++++++++++++++
>  7 files changed, 98 insertions(+), 6 deletions(-)
> 
> diff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt
> index 754b16ce0c..955880ab88 100644
> --- a/Documentation/git-cherry-pick.txt
> +++ b/Documentation/git-cherry-pick.txt
> @@ -10,9 +10,7 @@ SYNOPSIS
>  [verse]
>  'git cherry-pick' [--edit] [-n] [-m parent-number] [-s] [-x] [--ff]
>  		  [-S[<keyid>]] <commit>...
> -'git cherry-pick' --continue
> -'git cherry-pick' --quit
> -'git cherry-pick' --abort
> +'git cherry-pick' --continue | --skip | --abort | --quit
>  
>  DESCRIPTION
>  -----------
> diff --git a/Documentation/git-revert.txt b/Documentation/git-revert.txt
> index 0c82ca5bc0..ffce98099c 100644
> --- a/Documentation/git-revert.txt
> +++ b/Documentation/git-revert.txt
> @@ -9,9 +9,7 @@ SYNOPSIS
>  --------
>  [verse]
>  'git revert' [--[no-]edit] [-n] [-m parent-number] [-s] [-S[<keyid>]] <commit>...
> -'git revert' --continue
> -'git revert' --quit
> -'git revert' --abort
> +'git revert' --continue | --skip | --abort | --quit
>  
>  DESCRIPTION
>  -----------
> diff --git a/Documentation/sequencer.txt b/Documentation/sequencer.txt
> index 5a57c4a407..3bceb56474 100644
> --- a/Documentation/sequencer.txt
> +++ b/Documentation/sequencer.txt
> @@ -3,6 +3,10 @@
>  	`.git/sequencer`.  Can be used to continue after resolving
>  	conflicts in a failed cherry-pick or revert.
>  
> +--skip::
> +	Skip the current commit and continue with the rest of the
> +	sequence.
> +
>  --quit::
>  	Forget about the current operation in progress.  Can be used
>  	to clear the sequencer state after a failed cherry-pick or
> diff --git a/builtin/revert.c b/builtin/revert.c
> index d4dcedbdc6..5dc5891ea2 100644
> --- a/builtin/revert.c
> +++ b/builtin/revert.c
> @@ -102,6 +102,7 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)
>  		OPT_CMDMODE(0, "quit", &cmd, N_("end revert or cherry-pick sequence"), 'q'),
>  		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_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")),
> @@ -151,6 +152,8 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)
>  			this_operation = "--quit";
>  		else if (cmd == 'c')
>  			this_operation = "--continue";
> +		else if (cmd == 's')
> +			this_operation = "--skip";
>  		else {
>  			assert(cmd == 'a');
>  			this_operation = "--abort";
> @@ -210,6 +213,8 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)
>  		return sequencer_continue(the_repository, opts);
>  	if (cmd == 'a')
>  		return sequencer_rollback(the_repository, opts);
> +	if (cmd == 's')
> +		return sequencer_skip(the_repository, opts);
>  	return sequencer_pick_revisions(the_repository, opts);
>  }
>  
> diff --git a/sequencer.c b/sequencer.c
> index 9c561a041b..f586e677d3 100644
> --- a/sequencer.c
> +++ b/sequencer.c
> @@ -2784,6 +2784,29 @@ int sequencer_rollback(struct repository *r, struct replay_opts *opts)
>  	return -1;
>  }
>  
> +int sequencer_skip(struct repository *r, struct replay_opts *opts)
> +{
> +	switch (opts->action) {
> +	case REPLAY_REVERT:
> +		if (!file_exists(git_path_revert_head(r)))
> +			return error(_("no revert in progress"));

This error message is slightly misleading. If the user has already
committed a conflict resolution then REVERT_HEAD/CHERRY_PICK_HEAD will
not exist but it is possible that a cherry-pick/revert is in progress if
the user was picking a sequence of commits. It would be nice to give a
different error message or maybe just a warning in that case.
sequencer_get_last_command() should help with that.

> +		break;
> +	case REPLAY_PICK:
> +		if (!file_exists(git_path_cherry_pick_head(r)))
> +			return error(_("no cherry-pick in progress"));
> +		break;
> +	default:
> +		BUG("the control must not reach here.");
> +	}
> +
> +	if (rollback_single_pick(r))
> +		return error(_("failed to skip the commit"));

If rollback_single_pick() sees that HEAD is the null oid then it gives
the error "cannot abort from a branch yet to be born". We're not
aborting and if we're picking a sequence of commits the skip ought
succeed, but it won't at the moment. If we're picking a single commit
then the skip should probably fail like abort but with an appropriate
message. Admittedly that's all a bit of a corner case.

> +	if (!is_directory(git_path_seq_dir()))
> +		return 0;
> +
> +	return sequencer_continue(r, opts);
> +}
> +
>  static int save_todo(struct todo_list *todo_list, struct replay_opts *opts)
>  {
>  	struct lock_file todo_lock = LOCK_INIT;
> diff --git a/sequencer.h b/sequencer.h
> index 0c494b83d4..731b9853eb 100644
> --- a/sequencer.h
> +++ b/sequencer.h
> @@ -129,6 +129,7 @@ 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_skip(struct repository *repo, struct replay_opts *opts);
>  int sequencer_remove_state(struct replay_opts *opts);
>  
>  #define TODO_LIST_KEEP_EMPTY (1U << 0)
> diff --git a/t/t3510-cherry-pick-sequence.sh b/t/t3510-cherry-pick-sequence.sh
> index 941d5026da..48cc9f13ee 100755
> --- a/t/t3510-cherry-pick-sequence.sh
> +++ b/t/t3510-cherry-pick-sequence.sh
> @@ -93,6 +93,69 @@ test_expect_success 'cherry-pick cleans up sequencer state upon success' '
>  	test_path_is_missing .git/sequencer
>  '
>  
> +test_expect_success 'cherry-pick --skip requires cherry-pick in progress' '
> +	pristine_detach initial &&
> +	test_must_fail git cherry-pick --skip
> +'
> +
> +test_expect_success 'revert --skip requires revert in progress' '
> +	pristine_detach initial &&
> +	test_must_fail git revert --skip
> +'
> +
> +test_expect_success 'cherry-pick --skip to skip commit' '
> +	pristine_detach initial &&
> +	test_must_fail git cherry-pick anotherpick &&
> +	test_must_fail git revert --skip &&
> +	git cherry-pick --skip &&
> +	test_cmp_rev initial HEAD &&
> +	test_path_is_missing .git/CHERRY_PICK_HEAD
> +'
> +
> +test_expect_success 'revert --skip to skip commit' '
> +	pristine_detach anotherpick &&
> +	test_must_fail git revert anotherpick~1 &&
> +	test_must_fail git cherry-pick --skip &&
> +	git revert --skip &&
> +	test_cmp_rev anotherpick HEAD
> +'
> +
> +test_expect_success 'skip "empty" commit' '
> +	pristine_detach picked &&
> +	test_commit dummy foo d &&
> +	test_must_fail git cherry-pick anotherpick &&
> +	git cherry-pick --skip &&
> +	test_cmp_rev dummy HEAD
> +'
> +
> +test_expect_success 'skip a commit and check if rest of sequence is correct' '
> +	pristine_detach initial &&
> +	echo e >expect &&
> +	cat >expect.log <<-EOF &&
> +	OBJID
> +	:100644 100644 OBJID OBJID M	foo
> +	OBJID
> +	:100644 100644 OBJID OBJID M	foo
> +	OBJID
> +	:100644 100644 OBJID OBJID M	unrelated
> +	OBJID
> +	:000000 100644 OBJID OBJID A	foo
> +	:000000 100644 OBJID OBJID A	unrelated
> +	EOF
> +	test_must_fail git cherry-pick base..yetanotherpick &&
> +	test_must_fail git cherry-pick --skip &&

It would be good to check that the cherry-pick has progressed since
--skip and didn't just fail without trying to pick another commit.


Best Wishes

Phillip

> +	echo d >foo &&
> +	git add foo &&
> +	git cherry-pick --continue &&
> +	{
> +		git rev-list HEAD |
> +		git diff-tree --root --stdin |
> +		sed "s/$OID_REGEX/OBJID/g"
> +	} >actual.log &&
> +	test_cmp expect foo &&
> +	test_cmp expect.log actual.log
> +'
> +
>  test_expect_success '--quit does not complain when no cherry-pick is in progress' '
>  	pristine_detach initial &&
>  	git cherry-pick --quit
> 


^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [GSoC][PATCH 3/3] cherry-pick/revert: update hints
  2019-06-08 19:19 ` [GSoC][PATCH 3/3] cherry-pick/revert: update hints Rohit Ashiwal
  2019-06-09  8:42   ` Thomas Gummerer
@ 2019-06-09 18:03   ` Phillip Wood
  2019-06-10  5:28     ` Rohit Ashiwal
  1 sibling, 1 reply; 87+ messages in thread
From: Phillip Wood @ 2019-06-09 18:03 UTC (permalink / raw)
  To: Rohit Ashiwal, git; +Cc: newren, t.gummerer

Hi Rohit

On 08/06/2019 20:19, Rohit Ashiwal wrote:
> Signed-off-by: Rohit Ashiwal <rohit.ashiwal265@gmail.com>
> ---
>  builtin/commit.c | 13 ++++++++-----
>  sequencer.c      |  4 ++--
>  2 files changed, 10 insertions(+), 7 deletions(-)
> 
> diff --git a/builtin/commit.c b/builtin/commit.c
> index 1c9e8e2228..1f47c51bdc 100644
> --- a/builtin/commit.c
> +++ b/builtin/commit.c
> @@ -60,15 +60,18 @@ N_("The previous cherry-pick is now empty, possibly due to conflict resolution.\
>  "\n");
>  
>  static const char empty_cherry_pick_advice_single[] =
> -N_("Otherwise, please use 'git reset'\n");
> +N_("Otherwise, please use 'git cherry-pick --skip'\n");
>  
>  static const char empty_cherry_pick_advice_multi[] =
> -N_("If you wish to skip this commit, use:\n"
> +N_("and then use:\n"
>  "\n"
> -"    git reset\n"
> +"    git cherry-pick --continue\n"
>  "\n"
> -"Then \"git cherry-pick --continue\" will resume cherry-picking\n"
> -"the remaining commits.\n");
> +"to resume cherry-picking the remaining commits.\n"
> +"If you wish to skip this commit, use:\n"
> +"\n"
> +"    git cherry-pick --skip\n"
> +"\n");
>  
>  static const char *color_status_slots[] = {
>  	[WT_STATUS_HEADER]	  = "header",
> diff --git a/sequencer.c b/sequencer.c
> index f586e677d3..e889427eef 100644
> --- a/sequencer.c
> +++ b/sequencer.c
> @@ -2654,8 +2654,8 @@ static int create_seq_dir(void)
>  {
>  	if (file_exists(git_path_seq_dir())) {
>  		error(_("a cherry-pick or revert is already in progress"));
> -		advise(_("try \"git cherry-pick (--continue | --quit | --abort)\""));
> -		advise(_("or  \"git revert (--continue | --quit | --abort)\""));
> +		advise(_("try \"git cherry-pick (--continue | --skip | --quit | --abort)\""));
> +		advise(_("or  \"git revert (--continue | --skip | --quit | --abort)\""));

If the user has already committed the conflict resolution then we don't
want to recommend --skip as there is nothing to skip.

Best Wishes

Phillip

>  		return -1;
>  	} else if (mkdir(git_path_seq_dir(), 0777) < 0)
>  		return error_errno(_("could not create sequencer directory '%s'"),
> 


^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [GSoC][PATCH 0/3] Teach cherry-pick/revert to skip commits
  2019-06-09 10:06   ` Rohit Ashiwal
@ 2019-06-09 20:00     ` Thomas Gummerer
  0 siblings, 0 replies; 87+ messages in thread
From: Thomas Gummerer @ 2019-06-09 20:00 UTC (permalink / raw)
  To: Rohit Ashiwal; +Cc: git, Elijah Newren

On 06/09, Rohit Ashiwal wrote:
> > > PR: https://github.com/r1walz/git/pull/1
> > > Reviewed-by: Elijah Newren <newren@gmail.com>
> > > Reviewed-by: Thomas Gummerer <t.gummerer@gmail.com>
> >
> > Note that the 'Reviewed-by' footer is something that is "given" by the
> > reviewers, and should only be added after they have explicitly given
> > it for the patch/series in question.  Instead this should probably
> > mention that Elijah and me reviewed this off-list in the PR you linked
> > to above.
> 
> Oh! But I read here, SubmittingPatches[1] docs, that it's nice to give
> credits to those who helped you. Should we fix it in some way? I don't
> know. Anyway, that is beyond the scope of this patch.

Right, thanks for thinking about credit here.  The appropriate way to
do that would be to add a Helped-by trailer to the individual
commits, though especially for the first and last commit in the series
we probably don't deserve that much credit ;)  In past GSoC/Outreachy
projects I've also seen the Mentored-by trailer.

Other than Helped-by, which I've commonly used seen for this they do
seem to be (more or less) documented in SubmittingPatches [2].

> Thanks for the review
> Rohit
> 
> [1]: https://github.com/git/git/blob/v2.22.0/Documentation/SubmittingPatches#L289-L291

[2]: https://github.com/git/git/blob/b697d92f56511e804b8ba20ccbe7bdc85dc66810/Documentation/SubmittingPatches#L353-L365

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [GSoC][PATCH 1/3] sequencer: add advice for revert 
  2019-06-09 17:52   ` Phillip Wood
@ 2019-06-10  5:13     ` Rohit Ashiwal
  2019-06-10 10:39       ` Phillip Wood
  0 siblings, 1 reply; 87+ messages in thread
From: Rohit Ashiwal @ 2019-06-10  5:13 UTC (permalink / raw)
  To: phillip.wood123; +Cc: git, newren, rohit.ashiwal265, t.gummerer

Hi Philip

On 2019-06-09 17:52 UTC Phillip Wood <phillip.wood123@gmail.com> wrote:
>
> Hi Rohit
> 
> Congratulations on your first GSoC patch series!

Thank you very much :)

> On 08/06/2019 20:19, Rohit Ashiwal wrote:
> > [...]
> > @@ -2655,6 +2655,7 @@ static int create_seq_dir(void)
> >  	if (file_exists(git_path_seq_dir())) {
> >  		error(_("a cherry-pick or revert is already in progress"));
> >  		advise(_("try \"git cherry-pick (--continue | --quit | --abort)\""));
> > +		advise(_("or  \"git revert (--continue | --quit | --abort)\""));
> 
> I agree that it's a good idea to add advice for revert as well, but it
> would be better to call sequencer_get_last_command() to find out if
> we're running cherry-pick or revert and tailor the advice appropriately.

Firstly, signature of `create_seq_dir` doesn't allow us to call
`sequencer_get_last_command()`. Changing that for the sake of a
better error message is too much task for this patch as it is a
subject of discussion on its own. (Also changing signature only
makes sense if this patch series gets merged). FWIW, I think we
should left this to further discussions for now and decide what
to do later on.

> Best Wishes
> 
> Phillip

Thanks
Rohit


^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [GSoC][PATCH 3/3] cherry-pick/revert: update hints
  2019-06-09 18:03   ` Phillip Wood
@ 2019-06-10  5:28     ` Rohit Ashiwal
  2019-06-10 10:40       ` Phillip Wood
  0 siblings, 1 reply; 87+ messages in thread
From: Rohit Ashiwal @ 2019-06-10  5:28 UTC (permalink / raw)
  To: phillip.wood123; +Cc: git, newren, rohit.ashiwal265, t.gummerer

Hey Phillip

On Sun, 9 Jun 2019 19:03:02 +0100 Phillip Wood <phillip.wood123@gmail.com> wrote:
> 
> Hi Rohit
> 
> On 08/06/2019 20:19, Rohit Ashiwal wrote:
> > [...]
> > @@ -2654,8 +2654,8 @@ static int create_seq_dir(void)
> >  {
> >  	if (file_exists(git_path_seq_dir())) {
> >  		error(_("a cherry-pick or revert is already in progress"));
> > -		advise(_("try \"git cherry-pick (--continue | --quit | --abort)\""));
> > -		advise(_("or  \"git revert (--continue | --quit | --abort)\""));
> > +		advise(_("try \"git cherry-pick (--continue | --skip | --quit | --abort)\""));
> > +		advise(_("or  \"git revert (--continue | --skip | --quit | --abort)\""));
> 
> If the user has already committed the conflict resolution then we don't
> want to recommend --skip as there is nothing to skip.

I think it is more about suggesting what are all the possibilities
you can try and not about intelligently suggesting what you should
do. ofc, we can not use `revert --<option>` while cherry-picking.(
we should not be able to do so in ideal conditions, but the world
does not work as we think it should). Still we are suggesting so
here.

Also, I think it is more reasonable to make "this" a part of patch
which will cover "tailored" advice messages which is also a topic
of discussion as I described here[1].

> Best Wishes
> 
> Phillip

Thanks
Rohit

[1]: https://public-inbox.org/git/20190609200038.GD28007@hank.intra.tgummerer.com/T/#mbb071f6e29c69f291ecd9c61c71b889774ff33b2


^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [GSoC][PATCH 2/3] cherry-pick/revert: add --skip option
  2019-06-09 18:01   ` Phillip Wood
@ 2019-06-10  5:57     ` Rohit Ashiwal
  2019-06-10 10:40       ` Phillip Wood
  0 siblings, 1 reply; 87+ messages in thread
From: Rohit Ashiwal @ 2019-06-10  5:57 UTC (permalink / raw)
  To: phillip.wood123; +Cc: git, newren, rohit.ashiwal265, t.gummerer

Hey Phillip

On Sun, 9 Jun 2019 19:01:35 +0100 Phillip Wood <phillip.wood123@gmail.com> wrote:
>
> Hi Rohit
> 
> --skip is definitely a useful addition to cherry-pick/revert
> 
> On 08/06/2019 20:19, Rohit Ashiwal wrote:
> >
> > [...]
> > @@ -2784,6 +2784,29 @@ int sequencer_rollback(struct repository *r, struct replay_opts *opts)
> >  	return -1;
> >  }
> >  
> > +int sequencer_skip(struct repository *r, struct replay_opts *opts)
> > +{
> > +	switch (opts->action) {
> > +	case REPLAY_REVERT:
> > +		if (!file_exists(git_path_revert_head(r)))
> > +			return error(_("no revert in progress"));
> 
> This error message is slightly misleading. If the user has already
> committed a conflict resolution then REVERT_HEAD/CHERRY_PICK_HEAD will
> not exist but it is possible that a cherry-pick/revert is in progress if
> the user was picking a sequence of commits. It would be nice to give a
> different error message or maybe just a warning in that case.
> sequencer_get_last_command() should help with that.

Yes, .git/{REVERT|CHERRY_PICK}_HEAD will not exist in this case, but
in case of cherry-picking/reverting:

1. multiple commits:
    sequencer dir will exist which will throw out the error listed
    under `create_seq_dir`
2. single commit:
    Then ACTION is already over and there is nothing to do and the
    error is correct.

> > +		break;
> > +	case REPLAY_PICK:
> > +		if (!file_exists(git_path_cherry_pick_head(r)))
> > +			return error(_("no cherry-pick in progress"));
> > +		break;
> > +	default:
> > +		BUG("the control must not reach here.");
> > +	}
> > +
> > +	if (rollback_single_pick(r))
> > +		return error(_("failed to skip the commit"));
> 
> If rollback_single_pick() sees that HEAD is the null oid then it gives
> the error "cannot abort from a branch yet to be born". We're not
> aborting and if we're picking a sequence of commits the skip ought
> succeed, but it won't at the moment. If we're picking a single commit
> then the skip should probably fail like abort but with an appropriate
> message. Admittedly that's all a bit of a corner case.

Yes, you are right here. We could actually modify the advice there
to be more like _("cannot perform the specified action, the branch
is yet to be born") and I think it should suffice this. What do you
think?

> > [...]
> > +test_expect_success 'skip a commit and check if rest of sequence is correct' '
> > +	pristine_detach initial &&
> > +	echo e >expect &&
> > +	cat >expect.log <<-EOF &&
> > +	OBJID
> > +	:100644 100644 OBJID OBJID M	foo
> > +	OBJID
> > +	:100644 100644 OBJID OBJID M	foo
> > +	OBJID
> > +	:100644 100644 OBJID OBJID M	unrelated
> > +	OBJID
> > +	:000000 100644 OBJID OBJID A	foo
> > +	:000000 100644 OBJID OBJID A	unrelated
> > +	EOF
> > +	test_must_fail git cherry-pick base..yetanotherpick &&
> > +	test_must_fail git cherry-pick --skip &&
> 
> It would be good to check that the cherry-pick has progressed since
> --skip and didn't just fail without trying to pick another commit.

The overall test tests that only, if cherry-pick --skip "failed" then
we won't get 'e' inside of `foo` and `test_cmp expect foo` will also
fail and if it skipped wrongly then expect.log will not match the
actual.log and `test_cmp` will fail. Am I missing something here?
Please tell if so.
 
> Best Wishes
> 
> Phillip

Thanks
Rohit


^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [GSoC][PATCH 1/3] sequencer: add advice for revert
  2019-06-10  5:13     ` Rohit Ashiwal
@ 2019-06-10 10:39       ` Phillip Wood
  2019-06-10 13:25         ` Rohit Ashiwal
  2019-06-10 16:34         ` Junio C Hamano
  0 siblings, 2 replies; 87+ messages in thread
From: Phillip Wood @ 2019-06-10 10:39 UTC (permalink / raw)
  To: Rohit Ashiwal; +Cc: git, newren, t.gummerer

Hi Rohit

On 10/06/2019 06:13, Rohit Ashiwal wrote:
> Hi Philip
> 
> On 2019-06-09 17:52 UTC Phillip Wood <phillip.wood123@gmail.com> wrote:
>>
>> Hi Rohit
>>
>> Congratulations on your first GSoC patch series!
> 
> Thank you very much :)
> 
>> On 08/06/2019 20:19, Rohit Ashiwal wrote:
>>> [...]
>>> @@ -2655,6 +2655,7 @@ static int create_seq_dir(void)
>>>  	if (file_exists(git_path_seq_dir())) {
>>>  		error(_("a cherry-pick or revert is already in progress"));
>>>  		advise(_("try \"git cherry-pick (--continue | --quit | --abort)\""));
>>> +		advise(_("or  \"git revert (--continue | --quit | --abort)\""));
>>
>> I agree that it's a good idea to add advice for revert as well, but it
>> would be better to call sequencer_get_last_command() to find out if
>> we're running cherry-pick or revert and tailor the advice appropriately.
> 
> Firstly, signature of `create_seq_dir` doesn't allow us to call
> `sequencer_get_last_command()`. Changing that for the sake of a
> better error message is too much task for this patch as it is a
> subject of discussion on its own.

There is only one caller and it already has a struct repository pointer
so it is a two line change, one of which is the insertion of a single
character to change create_seq_dir() so it can call
sequencer_get_last_command(). It is normal to change function signatures
(especially for static functions like this) when making changes, it is
part of improving the code base. The quality of error messages is
important to the overall user experience. It's when things go wrong that
users need accurate advice about what to do.

> (Also changing signature only
> makes sense if this patch series gets merged). FWIW, I think we
> should left this to further discussions for now and decide what
> to do later on.

It is only a small change so why not do it now rather than putting it
off for another series which will be more work in the long run.

Best Wishes

Phillip

> 
>> Best Wishes
>>
>> Phillip
> 
> Thanks
> Rohit
> 


^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [GSoC][PATCH 2/3] cherry-pick/revert: add --skip option
  2019-06-10  5:57     ` Rohit Ashiwal
@ 2019-06-10 10:40       ` Phillip Wood
  2019-06-10 13:43         ` Rohit Ashiwal
  0 siblings, 1 reply; 87+ messages in thread
From: Phillip Wood @ 2019-06-10 10:40 UTC (permalink / raw)
  To: Rohit Ashiwal; +Cc: git, newren, t.gummerer

Hi Rohit

On 10/06/2019 06:57, Rohit Ashiwal wrote:
> Hey Phillip
> 
> On Sun, 9 Jun 2019 19:01:35 +0100 Phillip Wood <phillip.wood123@gmail.com> wrote:
>>
>> Hi Rohit
>>
>> --skip is definitely a useful addition to cherry-pick/revert
>>
>> On 08/06/2019 20:19, Rohit Ashiwal wrote:
>>>
>>> [...]
>>> @@ -2784,6 +2784,29 @@ int sequencer_rollback(struct repository *r, struct replay_opts *opts)
>>>  	return -1;
>>>  }
>>>  
>>> +int sequencer_skip(struct repository *r, struct replay_opts *opts)
>>> +{
>>> +	switch (opts->action) {
>>> +	case REPLAY_REVERT:
>>> +		if (!file_exists(git_path_revert_head(r)))
>>> +			return error(_("no revert in progress"));
>>
>> This error message is slightly misleading. If the user has already
>> committed a conflict resolution then REVERT_HEAD/CHERRY_PICK_HEAD will
>> not exist but it is possible that a cherry-pick/revert is in progress if
>> the user was picking a sequence of commits. It would be nice to give a
>> different error message or maybe just a warning in that case.
>> sequencer_get_last_command() should help with that.

It's actually a bit more complicated as if the cherry-pick failed
because it would have overwriten untracked files then CHERRY_PICK_HEAD
will not exist but we want to be able to skip that pick. So it should
not error out in that case either. (I think you may be able to use the
abort safety file (see rollback_is_safe()) to distinguish the 'failed to
pick case' from the 'user committed a conflict resolution' case.)

> Yes, .git/{REVERT|CHERRY_PICK}_HEAD will not exist in this case, but
> in case of cherry-picking/reverting:
> 
> 1. multiple commits:
>     sequencer dir will exist which will throw out the error listed
>     under `create_seq_dir`

I don't understand. Wont it will error out here? Why would we call
create_seq_dir() for --skip?

> 2. single commit:
>     Then ACTION is already over and there is nothing to do and the
>     error is correct.
> 
>>> +		break;
>>> +	case REPLAY_PICK:
>>> +		if (!file_exists(git_path_cherry_pick_head(r)))
>>> +			return error(_("no cherry-pick in progress"));
>>> +		break;
>>> +	default:
>>> +		BUG("the control must not reach here.");
>>> +	}
>>> +
>>> +	if (rollback_single_pick(r))
>>> +		return error(_("failed to skip the commit"));
>>
>> If rollback_single_pick() sees that HEAD is the null oid then it gives
>> the error "cannot abort from a branch yet to be born". We're not
>> aborting and if we're picking a sequence of commits the skip ought
>> succeed, but it won't at the moment. If we're picking a single commit
>> then the skip should probably fail like abort but with an appropriate
>> message. Admittedly that's all a bit of a corner case.
> 
> Yes, you are right here. We could actually modify the advice there
> to be more like _("cannot perform the specified action, the branch
> is yet to be born") and I think it should suffice this. What do you
> think?

I think it should allow the user to skip if there are more commits to
pick . Just changing the error message does not fix that.

> 
>>> [...]
>>> +test_expect_success 'skip a commit and check if rest of sequence is correct' '
>>> +	pristine_detach initial &&
>>> +	echo e >expect &&
>>> +	cat >expect.log <<-EOF &&
>>> +	OBJID
>>> +	:100644 100644 OBJID OBJID M	foo
>>> +	OBJID
>>> +	:100644 100644 OBJID OBJID M	foo
>>> +	OBJID
>>> +	:100644 100644 OBJID OBJID M	unrelated
>>> +	OBJID
>>> +	:000000 100644 OBJID OBJID A	foo
>>> +	:000000 100644 OBJID OBJID A	unrelated
>>> +	EOF
>>> +	test_must_fail git cherry-pick base..yetanotherpick &&
>>> +	test_must_fail git cherry-pick --skip &&
>>
>> It would be good to check that the cherry-pick has progressed since
>> --skip and didn't just fail without trying to pick another commit.
> 
> The overall test tests that only, if cherry-pick --skip "failed" then
> we won't get 'e' inside of `foo` and `test_cmp expect foo` will also
> fail and if it skipped wrongly then expect.log will not match the
> actual.log and `test_cmp` will fail. Am I missing something here?
> Please tell if so.

You're right that the tests at the end would probably pick up a failure,
but I'm concerned that there could be some obscure corner case we've not
thought of so checking HEAD and the file contents here would be an
additional safety measure. It also makes it easier for someone tracking
down a test failure to see what happened. If they rely only on the test
at the end they need to spend time to understand where the mismatched
contents came from.

Best Wishes

Phillip


>  
>> Best Wishes
>>
>> Phillip
> 
> Thanks
> Rohit
> 


^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [GSoC][PATCH 3/3] cherry-pick/revert: update hints
  2019-06-10  5:28     ` Rohit Ashiwal
@ 2019-06-10 10:40       ` Phillip Wood
  2019-06-10 13:33         ` Rohit Ashiwal
  0 siblings, 1 reply; 87+ messages in thread
From: Phillip Wood @ 2019-06-10 10:40 UTC (permalink / raw)
  To: Rohit Ashiwal; +Cc: git, newren, t.gummerer

Hi Rohit

On 10/06/2019 06:28, Rohit Ashiwal wrote:
> Hey Phillip
> 
> On Sun, 9 Jun 2019 19:03:02 +0100 Phillip Wood <phillip.wood123@gmail.com> wrote:
>>
>> Hi Rohit
>>
>> On 08/06/2019 20:19, Rohit Ashiwal wrote:
>>> [...]
>>> @@ -2654,8 +2654,8 @@ static int create_seq_dir(void)
>>>  {
>>>  	if (file_exists(git_path_seq_dir())) {
>>>  		error(_("a cherry-pick or revert is already in progress"));
>>> -		advise(_("try \"git cherry-pick (--continue | --quit | --abort)\""));
>>> -		advise(_("or  \"git revert (--continue | --quit | --abort)\""));
>>> +		advise(_("try \"git cherry-pick (--continue | --skip | --quit | --abort)\""));
>>> +		advise(_("or  \"git revert (--continue | --skip | --quit | --abort)\""));
>>
>> If the user has already committed the conflict resolution then we don't
>> want to recommend --skip as there is nothing to skip.
> I think it is more about suggesting what are all the possibilities
> you can try and not about intelligently suggesting what you should
> do.

Previously all the suggested options were viable, --skip is not
applicable if the user has committed a conflict resolution. The idea of
the advice is to help the user, suggesting options that wont work is not
going to help them.

> ofc, we can not use `revert --<option>` while cherry-picking.(

As I suggested in patch 1 we should tailor the error message to the command.

> we should not be able to do so in ideal conditions, but the world
> does not work as we think it should). Still we are suggesting so
> here.

Yes because you have the power to easily make that change. It is normal
to try and improve the code base when we make related changes.

> Also, I think it is more reasonable to make "this" a part of patch
> which will cover "tailored" advice messages which is also a topic
> of discussion as I described here[1].

That might make sense, but it is a pretty self contained change as part
of this patch.

Best Wishes

Phillip

> 
>> Best Wishes
>>
>> Phillip
> 
> Thanks
> Rohit
> 
> [1]: https://public-inbox.org/git/20190609200038.GD28007@hank.intra.tgummerer.com/T/#mbb071f6e29c69f291ecd9c61c71b889774ff33b2
> 


^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [GSoC][PATCH 1/3] sequencer: add advice for revert
  2019-06-10 10:39       ` Phillip Wood
@ 2019-06-10 13:25         ` Rohit Ashiwal
  2019-06-10 17:46           ` Phillip Wood
  2019-06-10 16:34         ` Junio C Hamano
  1 sibling, 1 reply; 87+ messages in thread
From: Rohit Ashiwal @ 2019-06-10 13:25 UTC (permalink / raw)
  To: phillip.wood123; +Cc: git, newren, rohit.ashiwal265, t.gummerer

Hi Phillip

On 2019-06-10 10:39 UTC Phillip Wood <phillip.wood123@gmail.com> wrote:
>
>Hi Rohit
>
>On 10/06/2019 06:13, Rohit Ashiwal wrote:
>>
>> [...]
>> Firstly, signature of `create_seq_dir` doesn't allow us to call
>> `sequencer_get_last_command()`. Changing that for the sake of a
>> better error message is too much task for this patch as it is a
>> subject of discussion on its own.
>
> There is only one caller and it already has a struct repository pointer
> so it is a two line change, one of which is the insertion of a single
> character to change create_seq_dir() so it can call
> sequencer_get_last_command(). It is normal to change function signatures
> (especially for static functions like this) when making changes, it is
> part of improving the code base. The quality of error messages is
> important to the overall user experience. It's when things go wrong that
> users need accurate advice about what to do.

Nice! I'll do this in next revision then.

>> (Also changing signature only
>> makes sense if this patch series gets merged). FWIW, I think we
>> should left this to further discussions for now and decide what
>> to do later on.
>
> It is only a small change so why not do it now rather than putting it
> off for another series which will be more work in the long run.

I'm fine with changing that here.

Thanks
Rohit


^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [GSoC][PATCH 3/3] cherry-pick/revert: update hints
  2019-06-10 10:40       ` Phillip Wood
@ 2019-06-10 13:33         ` Rohit Ashiwal
  2019-06-10 17:47           ` Phillip Wood
  0 siblings, 1 reply; 87+ messages in thread
From: Rohit Ashiwal @ 2019-06-10 13:33 UTC (permalink / raw)
  To: phillip.wood123; +Cc: git, newren, rohit.ashiwal265, t.gummerer

Hi Phillip

On 2019-06-10 10:40 UTC Phillip Wood <phillip.wood123@gmail.com> wrote:
>
> Hi Rohit
>
> On 10/06/2019 06:28, Rohit Ashiwal wrote:
>> Hey Phillip
>>
>> On Sun, 9 Jun 2019 19:03:02 +0100 Phillip Wood <phillip.wood123@gmail.com> wrote:
>>>
>>> Hi Rohit
>> [...]
>> I think it is more about suggesting what are all the possibilities
>> you can try and not about intelligently suggesting what you should
>> do.
>
> Previously all the suggested options were viable, --skip is not
> applicable if the user has committed a conflict resolution. The idea of
> the advice is to help the user, suggesting options that wont work is not
> going to help them.

Now that I know what I should do, I'll make the change and submit a
better patch.

>> ofc, we can not use `revert --<option>` while cherry-picking.(
>
> As I suggested in patch 1 we should tailor the error message to the command.

Yes, I'll tailor the messages based on which command was ran.

>> we should not be able to do so in ideal conditions, but the world
>> does not work as we think it should). Still we are suggesting so
>> here.
>
> Yes because you have the power to easily make that change. It is normal
> to try and improve the code base when we make related changes.

:)

>> Also, I think it is more reasonable to make "this" a part of patch
>> which will cover "tailored" advice messages which is also a topic
>> of discussion as I described here[1].
>
> That might make sense, but it is a pretty self contained change as part
> of this patch.

Yes, this patch is the place where all changes should be made.

Thanks
Rohit


^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [GSoC][PATCH 2/3] cherry-pick/revert: add --skip option
  2019-06-10 10:40       ` Phillip Wood
@ 2019-06-10 13:43         ` Rohit Ashiwal
  2019-06-10 17:47           ` Phillip Wood
  0 siblings, 1 reply; 87+ messages in thread
From: Rohit Ashiwal @ 2019-06-10 13:43 UTC (permalink / raw)
  To: phillip.wood123; +Cc: git, newren, rohit.ashiwal265, t.gummerer

Hi Phillip

On 2019-06-10 10:40 UTC Phillip Wood <phillip.wood123@gmail.com> wrote:
>
> [...]
> It's actually a bit more complicated as if the cherry-pick failed
> because it would have overwriten untracked files then CHERRY_PICK_HEAD
> will not exist but we want to be able to skip that pick. So it should
> not error out in that case either. (I think you may be able to use the
> abort safety file (see rollback_is_safe()) to distinguish the 'failed to
> pick case' from the 'user committed a conflict resolution' case.)

Oh! I was thinking about some other case. (spawing another cherry-pick,
which is wrong since the topic is --skip). I'm sorry. 

>> Yes, .git/{REVERT|CHERRY_PICK}_HEAD will not exist in this case, but
>> in case of cherry-picking/reverting:
>> 
>> 1. multiple commits:
>>     sequencer dir will exist which will throw out the error listed
>>     under `create_seq_dir`
>
> I don't understand. Wont it will error out here? Why would we call
> create_seq_dir() for --skip?

No, you are correct. This won't skip commit in this case. I'll change
it to do the required.

>>> If rollback_single_pick() sees that HEAD is the null oid then it gives
>>> the error "cannot abort from a branch yet to be born". We're not
>>> aborting and if we're picking a sequence of commits the skip ought
>>> succeed, but it won't at the moment. If we're picking a single commit
>>> then the skip should probably fail like abort but with an appropriate
>>> message. Admittedly that's all a bit of a corner case.
>> 
>> Yes, you are right here. We could actually modify the advice there
>> to be more like _("cannot perform the specified action, the branch
>> is yet to be born") and I think it should suffice this. What do you
>> think?
>
> I think it should allow the user to skip if there are more commits to
> pick . Just changing the error message does not fix that.

Right! I'll check what can be done here.

>> The overall test tests that only, if cherry-pick --skip "failed" then
>> we won't get 'e' inside of `foo` and `test_cmp expect foo` will also
>> fail and if it skipped wrongly then expect.log will not match the
>> actual.log and `test_cmp` will fail. Am I missing something here?
>> Please tell if so.
>
> You're right that the tests at the end would probably pick up a failure,
> but I'm concerned that there could be some obscure corner case we've not
> thought of so checking HEAD and the file contents here would be an
> additional safety measure. It also makes it easier for someone tracking
> down a test failure to see what happened. If they rely only on the test
> at the end they need to spend time to understand where the mismatched
> contents came from.

Yes, it is worth checking here if HEAD after cherry-picking is in the
correct position, same for the file foo. I'll change this test too.
Thanks for pointing out.

Thanks for the review
Rohit


^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [GSoC][PATCH 1/3] sequencer: add advice for revert
  2019-06-10 10:39       ` Phillip Wood
  2019-06-10 13:25         ` Rohit Ashiwal
@ 2019-06-10 16:34         ` Junio C Hamano
  1 sibling, 0 replies; 87+ messages in thread
From: Junio C Hamano @ 2019-06-10 16:34 UTC (permalink / raw)
  To: Phillip Wood; +Cc: Rohit Ashiwal, git, newren, t.gummerer

Phillip Wood <phillip.wood123@gmail.com> writes:

>> Firstly, signature of `create_seq_dir` doesn't allow us to call
>> `sequencer_get_last_command()`. Changing that for the sake of a
>> better error message is too much task for this patch as it is a
>> subject of discussion on its own.
>
> There is only one caller and it already has a struct repository pointer
> so it is a two line change, one of which is the insertion of a single
> character to change create_seq_dir() so it can call
> sequencer_get_last_command(). It is normal to change function signatures
> (especially for static functions like this) when making changes, it is
> part of improving the code base. The quality of error messages is
> important to the overall user experience. It's when things go wrong that
> users need accurate advice about what to do.

Thanks for guiding a new contributor in the right direction gently.
Very much appreciated.

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [GSoC][PATCH 1/3] sequencer: add advice for revert
  2019-06-10 13:25         ` Rohit Ashiwal
@ 2019-06-10 17:46           ` Phillip Wood
  0 siblings, 0 replies; 87+ messages in thread
From: Phillip Wood @ 2019-06-10 17:46 UTC (permalink / raw)
  To: Rohit Ashiwal; +Cc: git, newren, t.gummerer

Hi Rohit

On 10/06/2019 14:25, Rohit Ashiwal wrote:
> Hi Phillip
> 
> On 2019-06-10 10:39 UTC Phillip Wood <phillip.wood123@gmail.com> wrote:
>>
>> Hi Rohit
>>
>> On 10/06/2019 06:13, Rohit Ashiwal wrote:
>>>
>>> [...]
>>> Firstly, signature of `create_seq_dir` doesn't allow us to call
>>> `sequencer_get_last_command()`. Changing that for the sake of a
>>> better error message is too much task for this patch as it is a
>>> subject of discussion on its own.
>>
>> There is only one caller and it already has a struct repository pointer
>> so it is a two line change, one of which is the insertion of a single
>> character to change create_seq_dir() so it can call
>> sequencer_get_last_command(). It is normal to change function signatures
>> (especially for static functions like this) when making changes, it is
>> part of improving the code base. The quality of error messages is
>> important to the overall user experience. It's when things go wrong that
>> users need accurate advice about what to do.
> 
> Nice! I'll do this in next revision then.

I'm glad that helped

> 
>>> (Also changing signature only
>>> makes sense if this patch series gets merged). FWIW, I think we
>>> should left this to further discussions for now and decide what
>>> to do later on.
>>
>> It is only a small change so why not do it now rather than putting it
>> off for another series which will be more work in the long run.
> 
> I'm fine with changing that here.

That's great

Best Wishes

Phillip

> 
> Thanks
> Rohit
> 


^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [GSoC][PATCH 2/3] cherry-pick/revert: add --skip option
  2019-06-10 13:43         ` Rohit Ashiwal
@ 2019-06-10 17:47           ` Phillip Wood
  0 siblings, 0 replies; 87+ messages in thread
From: Phillip Wood @ 2019-06-10 17:47 UTC (permalink / raw)
  To: Rohit Ashiwal; +Cc: git, newren, t.gummerer

Hi Rohit

On 10/06/2019 14:43, Rohit Ashiwal wrote:
> Hi Phillip
> 
> On 2019-06-10 10:40 UTC Phillip Wood <phillip.wood123@gmail.com> wrote:
>>
>> [...]
>> It's actually a bit more complicated as if the cherry-pick failed
>> because it would have overwriten untracked files then CHERRY_PICK_HEAD
>> will not exist but we want to be able to skip that pick. So it should
>> not error out in that case either. (I think you may be able to use the
>> abort safety file (see rollback_is_safe()) to distinguish the 'failed to
>> pick case' from the 'user committed a conflict resolution' case.)
> 
> Oh! I was thinking about some other case. (spawing another cherry-pick,
> which is wrong since the topic is --skip). I'm sorry. 
> 
>>> Yes, .git/{REVERT|CHERRY_PICK}_HEAD will not exist in this case, but
>>> in case of cherry-picking/reverting:
>>>
>>> 1. multiple commits:
>>>     sequencer dir will exist which will throw out the error listed
>>>     under `create_seq_dir`
>>
>> I don't understand. Wont it will error out here? Why would we call
>> create_seq_dir() for --skip?
> 
> No, you are correct. This won't skip commit in this case. I'll change
> it to do the required.

Shout if you get stuck. I think distinguishing the "user committed a
conflict resolution and so we don't want to skip" from the "the pick
would have overwritten an untracked file so we do want to skip" cases
should be possible by calling rollback_is_safe(). It would be good to
have a test case for at least the "pick would have overwritten an
untracked file case" as that would be easy to break in the future
without noticing as it's a rare situation.

> 
>>>> If rollback_single_pick() sees that HEAD is the null oid then it gives
>>>> the error "cannot abort from a branch yet to be born". We're not
>>>> aborting and if we're picking a sequence of commits the skip ought
>>>> succeed, but it won't at the moment. If we're picking a single commit
>>>> then the skip should probably fail like abort but with an appropriate
>>>> message. Admittedly that's all a bit of a corner case.
>>>
>>> Yes, you are right here. We could actually modify the advice there
>>> to be more like _("cannot perform the specified action, the branch
>>> is yet to be born") and I think it should suffice this. What do you
>>> think?
>>
>> I think it should allow the user to skip if there are more commits to
>> pick . Just changing the error message does not fix that.
> 
> Right! I'll check what can be done here.

I think you can just pass a flag to rollback_single_pick() to tell it
whether it is rolling back for --skip or --abort so it can do the right
thing.

Best Wishes

Phillip

> 
>>> The overall test tests that only, if cherry-pick --skip "failed" then
>>> we won't get 'e' inside of `foo` and `test_cmp expect foo` will also
>>> fail and if it skipped wrongly then expect.log will not match the
>>> actual.log and `test_cmp` will fail. Am I missing something here?
>>> Please tell if so.
>>
>> You're right that the tests at the end would probably pick up a failure,
>> but I'm concerned that there could be some obscure corner case we've not
>> thought of so checking HEAD and the file contents here would be an
>> additional safety measure. It also makes it easier for someone tracking
>> down a test failure to see what happened. If they rely only on the test
>> at the end they need to spend time to understand where the mismatched
>> contents came from.
> 
> Yes, it is worth checking here if HEAD after cherry-picking is in the
> correct position, same for the file foo. I'll change this test too.
> Thanks for pointing out.
> 
> Thanks for the review
> Rohit
> 


^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [GSoC][PATCH 3/3] cherry-pick/revert: update hints
  2019-06-10 13:33         ` Rohit Ashiwal
@ 2019-06-10 17:47           ` Phillip Wood
  0 siblings, 0 replies; 87+ messages in thread
From: Phillip Wood @ 2019-06-10 17:47 UTC (permalink / raw)
  To: Rohit Ashiwal; +Cc: git, newren, t.gummerer

Hi Rohit

On 10/06/2019 14:33, Rohit Ashiwal wrote:
> Hi Phillip
> 
> On 2019-06-10 10:40 UTC Phillip Wood <phillip.wood123@gmail.com> wrote:
>>
>> Hi Rohit
>>
>> On 10/06/2019 06:28, Rohit Ashiwal wrote:
>>> Hey Phillip
>>>
>>> On Sun, 9 Jun 2019 19:03:02 +0100 Phillip Wood <phillip.wood123@gmail.com> wrote:
>>>>
>>>> Hi Rohit
>>> [...]
>>> I think it is more about suggesting what are all the possibilities
>>> you can try and not about intelligently suggesting what you should
>>> do.
>>
>> Previously all the suggested options were viable, --skip is not
>> applicable if the user has committed a conflict resolution. The idea of
>> the advice is to help the user, suggesting options that wont work is not
>> going to help them.
> 
> Now that I know what I should do, I'll make the change and submit a
> better patch.


That's great, thanks

Phillip

>>> ofc, we can not use `revert --<option>` while cherry-picking.(
>>
>> As I suggested in patch 1 we should tailor the error message to the command.
> 
> Yes, I'll tailor the messages based on which command was ran.
> 
>>> we should not be able to do so in ideal conditions, but the world
>>> does not work as we think it should). Still we are suggesting so
>>> here.
>>
>> Yes because you have the power to easily make that change. It is normal
>> to try and improve the code base when we make related changes.
> 
> :)
> 
>>> Also, I think it is more reasonable to make "this" a part of patch
>>> which will cover "tailored" advice messages which is also a topic
>>> of discussion as I described here[1].
>>
>> That might make sense, but it is a pretty self contained change as part
>> of this patch.
> 
> Yes, this patch is the place where all changes should be made.
> 
> Thanks
> Rohit
> 


^ permalink raw reply	[flat|nested] 87+ messages in thread

* [GSoC][PATCH v2 0/3] Teach cherry-pick/revert to skip commits
  2019-06-08 19:19 [GSoC][PATCH 0/3] Teach cherry-pick/revert to skip commits Rohit Ashiwal
                   ` (3 preceding siblings ...)
  2019-06-09  9:02 ` [GSoC][PATCH 0/3] Teach cherry-pick/revert to skip commits Thomas Gummerer
@ 2019-06-11  7:31 ` " Rohit Ashiwal
  2019-06-11  7:31   ` [GSoC][PATCH v2 1/3] sequencer: add advice for revert Rohit Ashiwal
                     ` (2 more replies)
  2019-06-13  4:05 ` [GSoC][PATCH v3 0/3] Teach cherry-pick/revert to skip commits Rohit Ashiwal
                   ` (4 subsequent siblings)
  9 siblings, 3 replies; 87+ messages in thread
From: Rohit Ashiwal @ 2019-06-11  7:31 UTC (permalink / raw)
  To: rohit.ashiwal265; +Cc: git, newren, t.gummerer, phillip.wood123, gitster

Adding a `--skip` option to make skipping commits easier for the user
and to make the commands more consistent. This will serve as a small
step to the bigger goal which improving consistency of sequencer commands.

Rohit Ashiwal (3):
  sequencer: add advice for revert
  cherry-pick/revert: add --skip option
  cherry-pick/revert: advise using --skip

 Documentation/git-cherry-pick.txt |   4 +-
 Documentation/git-revert.txt      |   4 +-
 Documentation/sequencer.txt       |   4 +
 builtin/commit.c                  |  13 ++--
 builtin/revert.c                  |   5 ++
 sequencer.c                       |  88 +++++++++++++++++++--
 sequencer.h                       |   1 +
 t/t3510-cherry-pick-sequence.sh   | 124 ++++++++++++++++++++++++++++++
 8 files changed, 225 insertions(+), 18 deletions(-)

-- 
2.21.0


^ permalink raw reply	[flat|nested] 87+ messages in thread

* [GSoC][PATCH v2 1/3] sequencer: add advice for revert
  2019-06-11  7:31 ` [GSoC][PATCH v2 " Rohit Ashiwal
@ 2019-06-11  7:31   ` Rohit Ashiwal
  2019-06-11 21:25     ` Junio C Hamano
  2019-06-11  7:31   ` [GSoC][PATCH v2 2/3] cherry-pick/revert: add --skip option Rohit Ashiwal
  2019-06-11  7:31   ` [GSoC][PATCH v2 3/3] cherry-pick/revert: advise using --skip Rohit Ashiwal
  2 siblings, 1 reply; 87+ messages in thread
From: Rohit Ashiwal @ 2019-06-11  7:31 UTC (permalink / raw)
  To: rohit.ashiwal265; +Cc: git, newren, t.gummerer, phillip.wood123, gitster

In the case of merge conflicts, while performing a revert, we are
currently advised to use `git cherry-pick --<sequencer-options>`
of which --continue is incompatible for continuing the revert.
Introduce a separate advice message for `git revert`. Also change
the signature of `create_seq_dir` to handle which advice to display
selectively.

Signed-off-by: Rohit Ashiwal <rohit.ashiwal265@gmail.com>
---
what has changed:
    Following Phillip's advice, I've changed the signature of `create_seq_dir`
    to selectively handle which advice to display.

 sequencer.c | 29 ++++++++++++++++++++++-------
 1 file changed, 22 insertions(+), 7 deletions(-)

diff --git a/sequencer.c b/sequencer.c
index f88a97fb10..ffb0257f0f 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -2650,15 +2650,30 @@ static int walk_revs_populate_todo(struct todo_list *todo_list,
 	return 0;
 }
 
-static int create_seq_dir(void)
+static int create_seq_dir(struct repository *r)
 {
-	if (file_exists(git_path_seq_dir())) {
-		error(_("a cherry-pick or revert is already in progress"));
-		advise(_("try \"git cherry-pick (--continue | --quit | --abort)\""));
-		return -1;
-	} else if (mkdir(git_path_seq_dir(), 0777) < 0)
+	enum replay_action action;
+
+	if (!sequencer_get_last_command(r, &action)) {
+		switch (action) {
+		case REPLAY_REVERT:
+		case REPLAY_PICK:
+			error(_("a %s is already in progress"),
+				 action == REPLAY_REVERT ?
+				 "revert" : "cherry-pick");
+			advise(_("try \"git %s (--continue | "
+				 "--quit | --abort)\""),
+				 action == REPLAY_REVERT ?
+				 "revert" : "cherry-pick");
+			return -1;
+		default:
+			BUG(_("the control must not reach here"));
+		}
+	}
+	if (mkdir(git_path_seq_dir(), 0777) < 0)
 		return error_errno(_("could not create sequencer directory '%s'"),
 				   git_path_seq_dir());
+
 	return 0;
 }
 
@@ -4237,7 +4252,7 @@ int sequencer_pick_revisions(struct repository *r,
 	 */
 
 	if (walk_revs_populate_todo(&todo_list, opts) ||
-			create_seq_dir() < 0)
+			create_seq_dir(r) < 0)
 		return -1;
 	if (get_oid("HEAD", &oid) && (opts->action == REPLAY_REVERT))
 		return error(_("can't revert as initial commit"));
-- 
2.21.0


^ permalink raw reply	[flat|nested] 87+ messages in thread

* [GSoC][PATCH v2 2/3] cherry-pick/revert: add --skip option
  2019-06-11  7:31 ` [GSoC][PATCH v2 " Rohit Ashiwal
  2019-06-11  7:31   ` [GSoC][PATCH v2 1/3] sequencer: add advice for revert Rohit Ashiwal
@ 2019-06-11  7:31   ` Rohit Ashiwal
  2019-06-12 13:31     ` Phillip Wood
  2019-06-11  7:31   ` [GSoC][PATCH v2 3/3] cherry-pick/revert: advise using --skip Rohit Ashiwal
  2 siblings, 1 reply; 87+ messages in thread
From: Rohit Ashiwal @ 2019-06-11  7:31 UTC (permalink / raw)
  To: rohit.ashiwal265; +Cc: git, newren, t.gummerer, phillip.wood123, gitster

git am or rebase have a --skip flag to skip the current commit if the
user wishes to do so. During a cherry-pick or revert a user could
likewise skip a commit, but needs to use 'git reset' (or in the case
of conflicts 'git reset --merge'), followed by 'git (cherry-pick |
revert) --continue' to skip the commit. This is more annoying and
sometimes confusing on the users' part. Add a `--skip` option to make
skipping commits easier for the user and to make the commands more
consistent.

In the next commit, we will change the advice messages hence finishing
the process of teaching revert and cherry-pick "how to skip commits."

Signed-off-by: Rohit Ashiwal <rohit.ashiwal265@gmail.com>
---
I was not able to think what should I change in 'skip a commit and check
if rest of sequence is correct' test. Please suggest how shall I fix this.
But I think test is fine as it is now (because I wrote it and have been
looking at it for a long time that I am out of ideas).

changes since last revision:
    - introduce new function `reset_merge` which will eliminate the problem
      of wrong error "cannot abort from a branch yet to be born" which occurs
      when head is NULL, but we still can skip (but not abort)
    - `sequencer_skip` now calls `reset_merge` instead of `rollback_single_pick`
    - add more tests

 Documentation/git-cherry-pick.txt |   4 +-
 Documentation/git-revert.txt      |   4 +-
 Documentation/sequencer.txt       |   4 ++
 builtin/revert.c                  |   5 ++
 sequencer.c                       |  56 ++++++++++++++++
 sequencer.h                       |   1 +
 t/t3510-cherry-pick-sequence.sh   | 104 ++++++++++++++++++++++++++++++
 7 files changed, 172 insertions(+), 6 deletions(-)

diff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt
index 754b16ce0c..955880ab88 100644
--- a/Documentation/git-cherry-pick.txt
+++ b/Documentation/git-cherry-pick.txt
@@ -10,9 +10,7 @@ SYNOPSIS
 [verse]
 'git cherry-pick' [--edit] [-n] [-m parent-number] [-s] [-x] [--ff]
 		  [-S[<keyid>]] <commit>...
-'git cherry-pick' --continue
-'git cherry-pick' --quit
-'git cherry-pick' --abort
+'git cherry-pick' --continue | --skip | --abort | --quit
 
 DESCRIPTION
 -----------
diff --git a/Documentation/git-revert.txt b/Documentation/git-revert.txt
index 0c82ca5bc0..ffce98099c 100644
--- a/Documentation/git-revert.txt
+++ b/Documentation/git-revert.txt
@@ -9,9 +9,7 @@ SYNOPSIS
 --------
 [verse]
 'git revert' [--[no-]edit] [-n] [-m parent-number] [-s] [-S[<keyid>]] <commit>...
-'git revert' --continue
-'git revert' --quit
-'git revert' --abort
+'git revert' --continue | --skip | --abort | --quit
 
 DESCRIPTION
 -----------
diff --git a/Documentation/sequencer.txt b/Documentation/sequencer.txt
index 5a57c4a407..3bceb56474 100644
--- a/Documentation/sequencer.txt
+++ b/Documentation/sequencer.txt
@@ -3,6 +3,10 @@
 	`.git/sequencer`.  Can be used to continue after resolving
 	conflicts in a failed cherry-pick or revert.
 
+--skip::
+	Skip the current commit and continue with the rest of the
+	sequence.
+
 --quit::
 	Forget about the current operation in progress.  Can be used
 	to clear the sequencer state after a failed cherry-pick or
diff --git a/builtin/revert.c b/builtin/revert.c
index d4dcedbdc6..5dc5891ea2 100644
--- a/builtin/revert.c
+++ b/builtin/revert.c
@@ -102,6 +102,7 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)
 		OPT_CMDMODE(0, "quit", &cmd, N_("end revert or cherry-pick sequence"), 'q'),
 		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_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")),
@@ -151,6 +152,8 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)
 			this_operation = "--quit";
 		else if (cmd == 'c')
 			this_operation = "--continue";
+		else if (cmd == 's')
+			this_operation = "--skip";
 		else {
 			assert(cmd == 'a');
 			this_operation = "--abort";
@@ -210,6 +213,8 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)
 		return sequencer_continue(the_repository, opts);
 	if (cmd == 'a')
 		return sequencer_rollback(the_repository, opts);
+	if (cmd == 's')
+		return sequencer_skip(the_repository, opts);
 	return sequencer_pick_revisions(the_repository, opts);
 }
 
diff --git a/sequencer.c b/sequencer.c
index ffb0257f0f..93284cd7dd 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -2724,6 +2724,16 @@ static int rollback_is_safe(void)
 	return oideq(&actual_head, &expected_head);
 }
 
+static int reset_merge(void) {
+	const char *argv[3];
+
+	argv[0] = "reset";
+	argv[1] = "--merge";
+	argv[2] = NULL;
+
+	return run_command_v_opt(argv, RUN_GIT_CMD);
+}
+
 static int reset_for_rollback(const struct object_id *oid)
 {
 	const char *argv[4];	/* reset --merge <arg> + NULL */
@@ -2798,6 +2808,52 @@ int sequencer_rollback(struct repository *r, struct replay_opts *opts)
 	return -1;
 }
 
+int sequencer_skip(struct repository *r, struct replay_opts *opts)
+{
+	enum replay_action action = -1;
+	sequencer_get_last_command(r, &action);
+
+	switch (opts->action) {
+	case REPLAY_REVERT:
+		if (!file_exists(git_path_revert_head(r))) {
+			if (action == REPLAY_REVERT) {
+				if (!rollback_is_safe())
+					goto give_advice;
+				else
+					break;
+			}
+			return error(_("no revert in progress"));
+		}
+		break;
+	case REPLAY_PICK:
+		if (!file_exists(git_path_cherry_pick_head(r))) {
+			if (action == REPLAY_PICK) {
+				if (!rollback_is_safe())
+					goto give_advice;
+				else
+					break;
+			}
+			return error(_("no cherry-pick in progress"));
+		}
+		break;
+	default:
+		BUG("the control must not reach here");
+	}
+
+	if (reset_merge())
+		return error(_("failed to skip the commit"));
+	if (!is_directory(git_path_seq_dir()))
+		return 0;
+
+	return sequencer_continue(r, opts);
+
+give_advice:
+	advise(_("have you committed already?\n"
+		 "try \"git %s --continue\""),
+		 action == REPLAY_REVERT ? "revert" : "cherry-pick");
+	return error(_("there is nothing to skip"));
+}
+
 static int save_todo(struct todo_list *todo_list, struct replay_opts *opts)
 {
 	struct lock_file todo_lock = LOCK_INIT;
diff --git a/sequencer.h b/sequencer.h
index 0c494b83d4..731b9853eb 100644
--- a/sequencer.h
+++ b/sequencer.h
@@ -129,6 +129,7 @@ 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_skip(struct repository *repo, struct replay_opts *opts);
 int sequencer_remove_state(struct replay_opts *opts);
 
 #define TODO_LIST_KEEP_EMPTY (1U << 0)
diff --git a/t/t3510-cherry-pick-sequence.sh b/t/t3510-cherry-pick-sequence.sh
index 941d5026da..6c1903a735 100755
--- a/t/t3510-cherry-pick-sequence.sh
+++ b/t/t3510-cherry-pick-sequence.sh
@@ -93,6 +93,110 @@ test_expect_success 'cherry-pick cleans up sequencer state upon success' '
 	test_path_is_missing .git/sequencer
 '
 
+test_expect_success 'cherry-pick --skip requires cherry-pick in progress' '
+	pristine_detach initial &&
+	test_must_fail git cherry-pick --skip
+'
+
+test_expect_success 'revert --skip requires revert in progress' '
+	pristine_detach initial &&
+	test_must_fail git revert --skip
+'
+
+test_expect_success 'cherry-pick --skip to skip commit' '
+	pristine_detach initial &&
+	test_must_fail git cherry-pick anotherpick &&
+	test_must_fail git revert --skip &&
+	git cherry-pick --skip &&
+	test_cmp_rev initial HEAD &&
+	test_path_is_missing .git/CHERRY_PICK_HEAD
+'
+
+test_expect_success 'revert --skip to skip commit' '
+	pristine_detach anotherpick &&
+	test_must_fail git revert anotherpick~1 &&
+	test_must_fail git cherry-pick --skip &&
+	git revert --skip &&
+	test_cmp_rev anotherpick HEAD
+'
+
+test_expect_success 'skip "empty" commit' '
+	pristine_detach picked &&
+	test_commit dummy foo d &&
+	test_must_fail git cherry-pick anotherpick &&
+	git cherry-pick --skip &&
+	test_cmp_rev dummy HEAD
+'
+
+test_expect_success 'skip a commit and check if rest of sequence is correct' '
+	pristine_detach initial &&
+	echo e >expect &&
+	cat >expect.log <<-EOF &&
+	OBJID
+	:100644 100644 OBJID OBJID M	foo
+	OBJID
+	:100644 100644 OBJID OBJID M	foo
+	OBJID
+	:100644 100644 OBJID OBJID M	unrelated
+	OBJID
+	:000000 100644 OBJID OBJID A	foo
+	:000000 100644 OBJID OBJID A	unrelated
+	EOF
+	test_must_fail git cherry-pick base..yetanotherpick &&
+	test_must_fail git cherry-pick --skip &&
+	echo d >foo &&
+	git add foo &&
+	git cherry-pick --continue &&
+	{
+		git rev-list HEAD |
+		git diff-tree --root --stdin |
+		sed "s/$OID_REGEX/OBJID/g"
+	} >actual.log &&
+	test_cmp expect foo &&
+	test_cmp expect.log actual.log
+'
+
+test_expect_success 'check advice when we move HEAD by committing' '
+	pristine_detach initial &&
+	cat >expect <<-EOF &&
+	hint: have you committed already?
+	hint: try "git cherry-pick --continue"
+	error: there is nothing to skip
+	fatal: cherry-pick failed
+	EOF
+	test_must_fail git cherry-pick base..yetanotherpick &&
+	echo c >foo &&
+	git commit -a &&
+	test_path_is_missing .git/CHERRY_PICK_HEAD &&
+	test_must_fail git cherry-pick --skip 2>advice &&
+	test_cmp expect advice
+'
+
+test_expect_success 'allow skipping commit but not abort for a new history' '
+	pristine_detach initial &&
+	cat >expect <<-EOF &&
+	error: cannot abort from a branch yet to be born
+	fatal: cherry-pick failed
+	EOF
+	git checkout --orphan new_disconnected &&
+	git reset --hard &&
+	test_must_fail git cherry-pick anotherpick &&
+	test_must_fail git cherry-pick --abort 2>advice &&
+	git cherry-pick --skip &&
+	test_cmp expect advice
+'
+
+test_expect_success 'allow skipping stopped cherry-pick because of untracked file modifications' '
+	pristine_detach initial &&
+	git checkout --orphan new_disconnected &&
+	git reset --hard &&
+	test_commit new_disconnected foo a &&
+	echo unrelated >unrelated &&
+	test_must_fail git cherry-pick new_disconnected..base &&
+	test_path_is_missing .git/CHERRY_PICK_HEAD &&
+	git cherry-pick --skip
+'
+
 test_expect_success '--quit does not complain when no cherry-pick is in progress' '
 	pristine_detach initial &&
 	git cherry-pick --quit
-- 
2.21.0


^ permalink raw reply	[flat|nested] 87+ messages in thread

* [GSoC][PATCH v2 3/3] cherry-pick/revert: advise using --skip
  2019-06-11  7:31 ` [GSoC][PATCH v2 " Rohit Ashiwal
  2019-06-11  7:31   ` [GSoC][PATCH v2 1/3] sequencer: add advice for revert Rohit Ashiwal
  2019-06-11  7:31   ` [GSoC][PATCH v2 2/3] cherry-pick/revert: add --skip option Rohit Ashiwal
@ 2019-06-11  7:31   ` Rohit Ashiwal
  2019-06-12 15:16     ` Phillip Wood
  2 siblings, 1 reply; 87+ messages in thread
From: Rohit Ashiwal @ 2019-06-11  7:31 UTC (permalink / raw)
  To: rohit.ashiwal265; +Cc: git, newren, t.gummerer, phillip.wood123, gitster

The previous commit introduced a --skip flag for cherry-pick and
revert. Update the advice messages, to tell users about this less
cumbersome way of skipping commits. Also add tests to ensure
everything is working fine.

Signed-off-by: Rohit Ashiwal <rohit.ashiwal265@gmail.com>
---
changes since last revision:
    - selectively advice --skip
    - add new test

 builtin/commit.c                | 13 ++++++++-----
 sequencer.c                     |  7 +++++--
 t/t3510-cherry-pick-sequence.sh | 20 ++++++++++++++++++++
 3 files changed, 33 insertions(+), 7 deletions(-)

diff --git a/builtin/commit.c b/builtin/commit.c
index 1c9e8e2228..1f47c51bdc 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -60,15 +60,18 @@ N_("The previous cherry-pick is now empty, possibly due to conflict resolution.\
 "\n");
 
 static const char empty_cherry_pick_advice_single[] =
-N_("Otherwise, please use 'git reset'\n");
+N_("Otherwise, please use 'git cherry-pick --skip'\n");
 
 static const char empty_cherry_pick_advice_multi[] =
-N_("If you wish to skip this commit, use:\n"
+N_("and then use:\n"
 "\n"
-"    git reset\n"
+"    git cherry-pick --continue\n"
 "\n"
-"Then \"git cherry-pick --continue\" will resume cherry-picking\n"
-"the remaining commits.\n");
+"to resume cherry-picking the remaining commits.\n"
+"If you wish to skip this commit, use:\n"
+"\n"
+"    git cherry-pick --skip\n"
+"\n");
 
 static const char *color_status_slots[] = {
 	[WT_STATUS_HEADER]	  = "header",
diff --git a/sequencer.c b/sequencer.c
index 93284cd7dd..ecf4be7e15 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -2661,10 +2661,13 @@ static int create_seq_dir(struct repository *r)
 			error(_("a %s is already in progress"),
 				 action == REPLAY_REVERT ?
 				 "revert" : "cherry-pick");
-			advise(_("try \"git %s (--continue | "
+			advise(_("try \"git %s (--continue | %s"
 				 "--quit | --abort)\""),
 				 action == REPLAY_REVERT ?
-				 "revert" : "cherry-pick");
+				 "revert" : "cherry-pick",
+				 !file_exists(git_path_revert_head(r)) ?
+				 !file_exists(git_path_cherry_pick_head(r)) ? ""
+				 : "--skip | " : "--skip | ");
 			return -1;
 		default:
 			BUG(_("the control must not reach here"));
diff --git a/t/t3510-cherry-pick-sequence.sh b/t/t3510-cherry-pick-sequence.sh
index 6c1903a735..f298f02cd0 100755
--- a/t/t3510-cherry-pick-sequence.sh
+++ b/t/t3510-cherry-pick-sequence.sh
@@ -172,6 +172,26 @@ test_expect_success 'check advice when we move HEAD by committing' '
 	test_cmp expect advice
 '
 
+test_expect_success 'selectively advise --skip while launching another sequence' '
+	pristine_detach initial &&
+	cat >expect <<-EOF &&
+	error: a cherry-pick is already in progress
+	hint: try "git cherry-pick (--continue | --skip | --quit | --abort)"
+	fatal: cherry-pick failed
+	EOF
+	test_must_fail git cherry-pick picked..yetanotherpick &&
+	test_must_fail git cherry-pick picked..yetanotherpick 2>advice &&
+	test_cmp expect advice &&
+	cat >expect <<-EOF &&
+	error: a cherry-pick is already in progress
+	hint: try "git cherry-pick (--continue | --quit | --abort)"
+	fatal: cherry-pick failed
+	EOF
+	git reset --merge &&
+	test_must_fail git cherry-pick picked..yetanotherpick 2>advice &&
+	test_cmp expect advice
+'
+
 test_expect_success 'allow skipping commit but not abort for a new history' '
 	pristine_detach initial &&
 	cat >expect <<-EOF &&
-- 
2.21.0


^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [GSoC][PATCH v2 1/3] sequencer: add advice for revert
  2019-06-11  7:31   ` [GSoC][PATCH v2 1/3] sequencer: add advice for revert Rohit Ashiwal
@ 2019-06-11 21:25     ` Junio C Hamano
  0 siblings, 0 replies; 87+ messages in thread
From: Junio C Hamano @ 2019-06-11 21:25 UTC (permalink / raw)
  To: Rohit Ashiwal; +Cc: git, newren, t.gummerer, phillip.wood123

Rohit Ashiwal <rohit.ashiwal265@gmail.com> writes:

> -static int create_seq_dir(void)
> +static int create_seq_dir(struct repository *r)
>  {
> -	if (file_exists(git_path_seq_dir())) {
> -		error(_("a cherry-pick or revert is already in progress"));
> -		advise(_("try \"git cherry-pick (--continue | --quit | --abort)\""));
> -		return -1;
> -	} else if (mkdir(git_path_seq_dir(), 0777) < 0)
> +	enum replay_action action;
> +
> +	if (!sequencer_get_last_command(r, &action)) {
> +		switch (action) {
> +		case REPLAY_REVERT:
> +		case REPLAY_PICK:
> +			error(_("a %s is already in progress"),
> +				 action == REPLAY_REVERT ?
> +				 "revert" : "cherry-pick");

I wonder if this poses a challenge to translators (imagine an
alternate world, in which the name of one of these subcommands began
with a vowel---your "a %s is already ..." would not be correct even
without localization).

The same comment applies to the other one, too.

> +			advise(_("try \"git %s (--continue | "
> +				 "--quit | --abort)\""),
> +				 action == REPLAY_REVERT ?
> +				 "revert" : "cherry-pick");

This is horrible but it is not a fault of yours---you merely
inherited it.  A call to advise() that is not behind any "advise.*"
configuration variable like this one should be cleaned up before
we do anything else.

The obvious and straight-forward way to deal with it is to do

	const char *in_progress_error;
        const char *in_progress_advice;

	if (action == REPLAY_REVERT) {
		in_progress_error = _("a revert is already in progress");
		in_progress_advise = _("try ...");
	} else if (action == REPLAY_PICK) {
		... likewise ...
	} else {
		BUG("should not come here");
	}

and then do

	error(in_progress_error);
	if (advise_verbosely_how_to_continue_sequencing)
		advise(in_progress_advise);



> +			return -1;
> +	if (mkdir(git_path_seq_dir(), 0777) < 0)
>  		return error_errno(_("could not create sequencer directory '%s'"),
>  				   git_path_seq_dir());
> +
>  	return 0;
>  }
>  
> @@ -4237,7 +4252,7 @@ int sequencer_pick_revisions(struct repository *r,
>  	 */
>  
>  	if (walk_revs_populate_todo(&todo_list, opts) ||
> -			create_seq_dir() < 0)
> +			create_seq_dir(r) < 0)
>  		return -1;
>  	if (get_oid("HEAD", &oid) && (opts->action == REPLAY_REVERT))
>  		return error(_("can't revert as initial commit"));

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [GSoC][PATCH v2 2/3] cherry-pick/revert: add --skip option
  2019-06-11  7:31   ` [GSoC][PATCH v2 2/3] cherry-pick/revert: add --skip option Rohit Ashiwal
@ 2019-06-12 13:31     ` Phillip Wood
  2019-06-12 18:11       ` Junio C Hamano
  0 siblings, 1 reply; 87+ messages in thread
From: Phillip Wood @ 2019-06-12 13:31 UTC (permalink / raw)
  To: Rohit Ashiwal; +Cc: git, newren, t.gummerer, gitster

Hi Rohit

Thanks for the new version, this is looking pretty good now, just a few 
comments below

On 11/06/2019 08:31, Rohit Ashiwal wrote:
> git am or rebase have a --skip flag to skip the current commit if the
> user wishes to do so. During a cherry-pick or revert a user could
> likewise skip a commit, but needs to use 'git reset' (or in the case
> of conflicts 'git reset --merge'), followed by 'git (cherry-pick |
> revert) --continue' to skip the commit. This is more annoying and
> sometimes confusing on the users' part. Add a `--skip` option to make
> skipping commits easier for the user and to make the commands more
> consistent.
> 
> In the next commit, we will change the advice messages hence finishing
> the process of teaching revert and cherry-pick "how to skip commits."
> 
> Signed-off-by: Rohit Ashiwal <rohit.ashiwal265@gmail.com>
> ---
> I was not able to think what should I change in 'skip a commit and check
> if rest of sequence is correct' test. Please suggest how shall I fix this.
> But I think test is fine as it is now (because I wrote it and have been
> looking at it for a long time that I am out of ideas).

You can call have_finished_the_last_pick() to see if you're skipping the 
last pick. One way would be to modify rollback_single_pick() to take a 
flag for abort vs skip and call it from there.

> 
> changes since last revision:
>      - introduce new function `reset_merge` which will eliminate the problem
>        of wrong error "cannot abort from a branch yet to be born" which occurs
>        when head is NULL, but we still can skip (but not abort)
>      - `sequencer_skip` now calls `reset_merge` instead of `rollback_single_pick`
>      - add more tests

Kudos for the new tests, we can look at Stolee's weekly test coverage 
email once these are merged to check that all the new code is being covered.

> 
>   Documentation/git-cherry-pick.txt |   4 +-
>   Documentation/git-revert.txt      |   4 +-
>   Documentation/sequencer.txt       |   4 ++
>   builtin/revert.c                  |   5 ++
>   sequencer.c                       |  56 ++++++++++++++++
>   sequencer.h                       |   1 +
>   t/t3510-cherry-pick-sequence.sh   | 104 ++++++++++++++++++++++++++++++
>   7 files changed, 172 insertions(+), 6 deletions(-)
> 
> diff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt
> index 754b16ce0c..955880ab88 100644
> --- a/Documentation/git-cherry-pick.txt
> +++ b/Documentation/git-cherry-pick.txt
> @@ -10,9 +10,7 @@ SYNOPSIS
>   [verse]
>   'git cherry-pick' [--edit] [-n] [-m parent-number] [-s] [-x] [--ff]
>   		  [-S[<keyid>]] <commit>...
> -'git cherry-pick' --continue
> -'git cherry-pick' --quit
> -'git cherry-pick' --abort
> +'git cherry-pick' --continue | --skip | --abort | --quit
>   
>   DESCRIPTION
>   -----------
> diff --git a/Documentation/git-revert.txt b/Documentation/git-revert.txt
> index 0c82ca5bc0..ffce98099c 100644
> --- a/Documentation/git-revert.txt
> +++ b/Documentation/git-revert.txt
> @@ -9,9 +9,7 @@ SYNOPSIS
>   --------
>   [verse]
>   'git revert' [--[no-]edit] [-n] [-m parent-number] [-s] [-S[<keyid>]] <commit>...
> -'git revert' --continue
> -'git revert' --quit
> -'git revert' --abort
> +'git revert' --continue | --skip | --abort | --quit
>   
>   DESCRIPTION
>   -----------
> diff --git a/Documentation/sequencer.txt b/Documentation/sequencer.txt
> index 5a57c4a407..3bceb56474 100644
> --- a/Documentation/sequencer.txt
> +++ b/Documentation/sequencer.txt
> @@ -3,6 +3,10 @@
>   	`.git/sequencer`.  Can be used to continue after resolving
>   	conflicts in a failed cherry-pick or revert.
>   
> +--skip::
> +	Skip the current commit and continue with the rest of the
> +	sequence.
> +
>   --quit::
>   	Forget about the current operation in progress.  Can be used
>   	to clear the sequencer state after a failed cherry-pick or
> diff --git a/builtin/revert.c b/builtin/revert.c
> index d4dcedbdc6..5dc5891ea2 100644
> --- a/builtin/revert.c
> +++ b/builtin/revert.c
> @@ -102,6 +102,7 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)
>   		OPT_CMDMODE(0, "quit", &cmd, N_("end revert or cherry-pick sequence"), 'q'),
>   		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_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")),
> @@ -151,6 +152,8 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)
>   			this_operation = "--quit";
>   		else if (cmd == 'c')
>   			this_operation = "--continue";
> +		else if (cmd == 's')
> +			this_operation = "--skip";
>   		else {
>   			assert(cmd == 'a');
>   			this_operation = "--abort";
> @@ -210,6 +213,8 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)
>   		return sequencer_continue(the_repository, opts);
>   	if (cmd == 'a')
>   		return sequencer_rollback(the_repository, opts);
> +	if (cmd == 's')
> +		return sequencer_skip(the_repository, opts);
>   	return sequencer_pick_revisions(the_repository, opts);
>   }
>   
> diff --git a/sequencer.c b/sequencer.c
> index ffb0257f0f..93284cd7dd 100644
> --- a/sequencer.c
> +++ b/sequencer.c
> @@ -2724,6 +2724,16 @@ static int rollback_is_safe(void)
>   	return oideq(&actual_head, &expected_head);
>   }
>   
> +static int reset_merge(void) {
> +	const char *argv[3];
> +
> +	argv[0] = "reset";
> +	argv[1] = "--merge";
> +	argv[2] = NULL;
> +
> +	return run_command_v_opt(argv, RUN_GIT_CMD);
> +}

This is only slightly different from reset_for_rollback() if you decide 
to keep a separate code path for skip vs abort then I'd be tempted to 
combine the two like this.

diff --git a/sequencer.c b/sequencer.c
index ecf4be7e15..b187b4222e 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -2740,11 +2740,13 @@ static int reset_merge(void) {
  static int reset_for_rollback(const struct object_id *oid)
  {
         const char *argv[4];    /* reset --merge <arg> + NULL */
+       size_t i = 0;

-       argv[0] = "reset";
-       argv[1] = "--merge";
-       argv[2] = oid_to_hex(oid);
-       argv[3] = NULL;
+       argv[i++] = "reset";
+       argv[i++] = "--merge";
+       if (oid)
+               argv[i++] = oid_to_hex(oid);
+       argv[i] = NULL;
         return run_command_v_opt(argv, RUN_GIT_CMD);
  }


> +
>   static int reset_for_rollback(const struct object_id *oid)
>   {
>   	const char *argv[4];	/* reset --merge <arg> + NULL */
> @@ -2798,6 +2808,52 @@ int sequencer_rollback(struct repository *r, struct replay_opts *opts)
>   	return -1;
>   }
>   
> +int sequencer_skip(struct repository *r, struct replay_opts *opts)
> +{
> +	enum replay_action action = -1;
> +	sequencer_get_last_command(r, &action);
> +
> +	switch (opts->action) {
> +	case REPLAY_REVERT:
> +		if (!file_exists(git_path_revert_head(r))) {
> +			if (action == REPLAY_REVERT) {
> +				if (!rollback_is_safe())
> +					goto give_advice;
> +				else
> +					break;
> +			}
> +			return error(_("no revert in progress"));
> +		}
> +		break;
> +	case REPLAY_PICK:
> +		if (!file_exists(git_path_cherry_pick_head(r))) {
> +			if (action == REPLAY_PICK) {
> +				if (!rollback_is_safe())
> +					goto give_advice;
> +				else
> +					break;
> +			}
> +			return error(_("no cherry-pick in progress"));
> +		}
> +		break;
> +	default:
> +		BUG("the control must not reach here");
> +	}
> +
> +	if (reset_merge())
> +		return error(_("failed to skip the commit"));
> +	if (!is_directory(git_path_seq_dir()))
> +		return 0;
> +
> +	return sequencer_continue(r, opts);
> +
> +give_advice:
> +	advise(_("have you committed already?\n"
> +		 "try \"git %s --continue\""),
> +		 action == REPLAY_REVERT ? "revert" : "cherry-pick");
> +	return error(_("there is nothing to skip"));
> +}
> +

this looks fine now, it's really good to have specific error messages.

>   static int save_todo(struct todo_list *todo_list, struct replay_opts *opts)
>   {
>   	struct lock_file todo_lock = LOCK_INIT;
> diff --git a/sequencer.h b/sequencer.h
> index 0c494b83d4..731b9853eb 100644
> --- a/sequencer.h
> +++ b/sequencer.h
> @@ -129,6 +129,7 @@ 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_skip(struct repository *repo, struct replay_opts *opts);
>   int sequencer_remove_state(struct replay_opts *opts);
>   
>   #define TODO_LIST_KEEP_EMPTY (1U << 0)
> diff --git a/t/t3510-cherry-pick-sequence.sh b/t/t3510-cherry-pick-sequence.sh
> index 941d5026da..6c1903a735 100755
> --- a/t/t3510-cherry-pick-sequence.sh
> +++ b/t/t3510-cherry-pick-sequence.sh
> @@ -93,6 +93,110 @@ test_expect_success 'cherry-pick cleans up sequencer state upon success' '
>   	test_path_is_missing .git/sequencer
>   '
>   
> +test_expect_success 'cherry-pick --skip requires cherry-pick in progress' '
> +	pristine_detach initial &&
> +	test_must_fail git cherry-pick --skip
> +'
> +
> +test_expect_success 'revert --skip requires revert in progress' '
> +	pristine_detach initial &&
> +	test_must_fail git revert --skip
> +'
> +
> +test_expect_success 'cherry-pick --skip to skip commit' '
> +	pristine_detach initial &&
> +	test_must_fail git cherry-pick anotherpick &&
> +	test_must_fail git revert --skip &&
> +	git cherry-pick --skip &&
> +	test_cmp_rev initial HEAD &&
> +	test_path_is_missing .git/CHERRY_PICK_HEAD
> +'
> +
> +test_expect_success 'revert --skip to skip commit' '
> +	pristine_detach anotherpick &&
> +	test_must_fail git revert anotherpick~1 &&
> +	test_must_fail git cherry-pick --skip &&
> +	git revert --skip &&
> +	test_cmp_rev anotherpick HEAD
> +'
> +
> +test_expect_success 'skip "empty" commit' '
> +	pristine_detach picked &&
> +	test_commit dummy foo d &&
> +	test_must_fail git cherry-pick anotherpick &&
> +	git cherry-pick --skip &&
> +	test_cmp_rev dummy HEAD
> +'
> +
> +test_expect_success 'skip a commit and check if rest of sequence is correct' '
> +	pristine_detach initial &&
> +	echo e >expect &&
> +	cat >expect.log <<-EOF &&
> +	OBJID
> +	:100644 100644 OBJID OBJID M	foo
> +	OBJID
> +	:100644 100644 OBJID OBJID M	foo
> +	OBJID
> +	:100644 100644 OBJID OBJID M	unrelated
> +	OBJID
> +	:000000 100644 OBJID OBJID A	foo
> +	:000000 100644 OBJID OBJID A	unrelated
> +	EOF
> +	test_must_fail git cherry-pick base..yetanotherpick &&
> +	test_must_fail git cherry-pick --skip &&
> +	echo d >foo &&
> +	git add foo &&
> +	git cherry-pick --continue &&
> +	{
> +		git rev-list HEAD |
> +		git diff-tree --root --stdin |
> +		sed "s/$OID_REGEX/OBJID/g"
> +	} >actual.log &&
> +	test_cmp expect foo &&
> +	test_cmp expect.log actual.log
> +'
> +
> +test_expect_success 'check advice when we move HEAD by committing' '
> +	pristine_detach initial &&
> +	cat >expect <<-EOF &&
> +	hint: have you committed already?
> +	hint: try "git cherry-pick --continue"
> +	error: there is nothing to skip
> +	fatal: cherry-pick failed
> +	EOF
> +	test_must_fail git cherry-pick base..yetanotherpick &&
> +	echo c >foo &&
> +	git commit -a &&
> +	test_path_is_missing .git/CHERRY_PICK_HEAD &&
> +	test_must_fail git cherry-pick --skip 2>advice &&
> +	test_cmp expect advice
> +'
> +
> +test_expect_success 'allow skipping commit but not abort for a new history' '
> +	pristine_detach initial &&
> +	cat >expect <<-EOF &&
> +	error: cannot abort from a branch yet to be born
> +	fatal: cherry-pick failed
> +	EOF
> +	git checkout --orphan new_disconnected &&
> +	git reset --hard &&
> +	test_must_fail git cherry-pick anotherpick &&
> +	test_must_fail git cherry-pick --abort 2>advice &&
> +	git cherry-pick --skip &&

If we want to match the abort behavior (we should think if that is 
sensible - I'm not sure at the moment) then we only want to allow --skip 
if there is another pick pending so shouldn't this be failing?

> +	test_cmp expect advice
> +'
> +
> +test_expect_success 'allow skipping stopped cherry-pick because of untracked file modifications' '
> +	pristine_detach initial &&
> +	git checkout --orphan new_disconnected &&

This gives a warning about new_disconnected being an ambiguous refname -
it would be better use a different name from the previous test - I'm not 
sure if you're getting an orphaned branch or not as it stands. (and 
looking more carefully I'm not sure why we want an orphan branch here in 
the first place)

Best Wishes

Phillip

> +	git reset --hard &&
> +	test_commit new_disconnected foo a &&
> +	echo unrelated >unrelated &&
> +	test_must_fail git cherry-pick new_disconnected..base &&
> +	test_path_is_missing .git/CHERRY_PICK_HEAD &&
> +	git cherry-pick --skip
> +'
> +
>   test_expect_success '--quit does not complain when no cherry-pick is in progress' '
>   	pristine_detach initial &&
>   	git cherry-pick --quit
> 

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [GSoC][PATCH v2 3/3] cherry-pick/revert: advise using --skip
  2019-06-11  7:31   ` [GSoC][PATCH v2 3/3] cherry-pick/revert: advise using --skip Rohit Ashiwal
@ 2019-06-12 15:16     ` Phillip Wood
  0 siblings, 0 replies; 87+ messages in thread
From: Phillip Wood @ 2019-06-12 15:16 UTC (permalink / raw)
  To: Rohit Ashiwal; +Cc: git, newren, t.gummerer, gitster

Hi Rohit

On 11/06/2019 08:31, Rohit Ashiwal wrote:
> The previous commit introduced a --skip flag for cherry-pick and
> revert. Update the advice messages, to tell users about this less
> cumbersome way of skipping commits. Also add tests to ensure
> everything is working fine.
> 
> Signed-off-by: Rohit Ashiwal <rohit.ashiwal265@gmail.com>
> ---
> changes since last revision:
>      - selectively advice --skip
>      - add new test
> 
>   builtin/commit.c                | 13 ++++++++-----
>   sequencer.c                     |  7 +++++--
>   t/t3510-cherry-pick-sequence.sh | 20 ++++++++++++++++++++
>   3 files changed, 33 insertions(+), 7 deletions(-)
> 
> diff --git a/builtin/commit.c b/builtin/commit.c
> index 1c9e8e2228..1f47c51bdc 100644
> --- a/builtin/commit.c
> +++ b/builtin/commit.c
> @@ -60,15 +60,18 @@ N_("The previous cherry-pick is now empty, possibly due to conflict resolution.\
>   "\n");
>   
>   static const char empty_cherry_pick_advice_single[] =
> -N_("Otherwise, please use 'git reset'\n");
> +N_("Otherwise, please use 'git cherry-pick --skip'\n");
>   
>   static const char empty_cherry_pick_advice_multi[] =
> -N_("If you wish to skip this commit, use:\n"
> +N_("and then use:\n"
>   "\n"
> -"    git reset\n"
> +"    git cherry-pick --continue\n"
>   "\n"
> -"Then \"git cherry-pick --continue\" will resume cherry-picking\n"
> -"the remaining commits.\n");
> +"to resume cherry-picking the remaining commits.\n"
> +"If you wish to skip this commit, use:\n"
> +"\n"
> +"    git cherry-pick --skip\n"
> +"\n");
>   
>   static const char *color_status_slots[] = {
>   	[WT_STATUS_HEADER]	  = "header",
> diff --git a/sequencer.c b/sequencer.c
> index 93284cd7dd..ecf4be7e15 100644
> --- a/sequencer.c
> +++ b/sequencer.c
> @@ -2661,10 +2661,13 @@ static int create_seq_dir(struct repository *r)
>   			error(_("a %s is already in progress"),
>   				 action == REPLAY_REVERT ?
>   				 "revert" : "cherry-pick");
> -			advise(_("try \"git %s (--continue | "
> +			advise(_("try \"git %s (--continue | %s"
>   				 "--quit | --abort)\""),
>   				 action == REPLAY_REVERT ?
> -				 "revert" : "cherry-pick");
> +				 "revert" : "cherry-pick",
> +				 !file_exists(git_path_revert_head(r)) ?
> +				 !file_exists(git_path_cherry_pick_head(r)) ? ""
> +				 : "--skip | " : "--skip | ");

This could be simplified as
	(file_exists(git_path_revert_head(r) ||
	file_exists(git_path_cherry_pick_head(r)) ?
	"--skip | " ""

Best Wishes

Phillip

>   			return -1;
>   		default:
>   			BUG(_("the control must not reach here"));
> diff --git a/t/t3510-cherry-pick-sequence.sh b/t/t3510-cherry-pick-sequence.sh
> index 6c1903a735..f298f02cd0 100755
> --- a/t/t3510-cherry-pick-sequence.sh
> +++ b/t/t3510-cherry-pick-sequence.sh
> @@ -172,6 +172,26 @@ test_expect_success 'check advice when we move HEAD by committing' '
>   	test_cmp expect advice
>   '
>   
> +test_expect_success 'selectively advise --skip while launching another sequence' '
> +	pristine_detach initial &&
> +	cat >expect <<-EOF &&
> +	error: a cherry-pick is already in progress
> +	hint: try "git cherry-pick (--continue | --skip | --quit | --abort)"
> +	fatal: cherry-pick failed
> +	EOF
> +	test_must_fail git cherry-pick picked..yetanotherpick &&
> +	test_must_fail git cherry-pick picked..yetanotherpick 2>advice && > +	test_cmp expect advice &&
> +	cat >expect <<-EOF &&
> +	error: a cherry-pick is already in progress
> +	hint: try "git cherry-pick (--continue | --quit | --abort)"
> +	fatal: cherry-pick failed
> +	EOF
> +	git reset --merge &&
> +	test_must_fail git cherry-pick picked..yetanotherpick 2>advice &&
> +	test_cmp expect advice
> +'
> +
>   test_expect_success 'allow skipping commit but not abort for a new history' '
>   	pristine_detach initial &&
>   	cat >expect <<-EOF &&
> 

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [GSoC][PATCH v2 2/3] cherry-pick/revert: add --skip option
  2019-06-12 13:31     ` Phillip Wood
@ 2019-06-12 18:11       ` Junio C Hamano
  2019-06-12 18:57         ` Phillip Wood
  0 siblings, 1 reply; 87+ messages in thread
From: Junio C Hamano @ 2019-06-12 18:11 UTC (permalink / raw)
  To: Phillip Wood; +Cc: Rohit Ashiwal, git, newren, t.gummerer

Phillip Wood <phillip.wood123@gmail.com> writes:

> Thanks for the new version, this is looking pretty good now, just a
> few comments below

I agree that this step is looking pretty good now.

I didn't check closely, but when 1/3 undergoes necessary polishing,
it may have repercussions on this step, though (I did see that the
change in 3/3 would have overlaps with what was touched by 1/3 that
needs to be done differently).

Thanks for guiding Rohit's series forward.  

> This is only slightly different from reset_for_rollback() if you
> decide to keep a separate code path for skip vs abort then I'd be
> tempted to combine the two like this.
>
> diff --git a/sequencer.c b/sequencer.c
> index ecf4be7e15..b187b4222e 100644
> --- a/sequencer.c
> +++ b/sequencer.c
> @@ -2740,11 +2740,13 @@ static int reset_merge(void) {
>  static int reset_for_rollback(const struct object_id *oid)
>  {
>         const char *argv[4];    /* reset --merge <arg> + NULL */
> +       size_t i = 0;

That size_t is, eh, "unusual".  For an index into a small local
array of known size, just sticking to bog-standard-and-boring 'int'
would make it less distracting for future readers of the code.

Or even better, perhaps use argv-array, so that you do not have to
worry about sizing the local array sufficiently large in the first
place.

> +       argv[i++] = "reset";
> +       argv[i++] = "--merge";
> +       if (oid)
> +               argv[i++] = oid_to_hex(oid);
> +       argv[i] = NULL;
>         return run_command_v_opt(argv, RUN_GIT_CMD);
>  }


^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [GSoC][PATCH v2 2/3] cherry-pick/revert: add --skip option
  2019-06-12 18:11       ` Junio C Hamano
@ 2019-06-12 18:57         ` Phillip Wood
  0 siblings, 0 replies; 87+ messages in thread
From: Phillip Wood @ 2019-06-12 18:57 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Rohit Ashiwal, git, newren, t.gummerer

On 12/06/2019 19:11, Junio C Hamano wrote:
> Phillip Wood <phillip.wood123@gmail.com> writes:
> 
>> Thanks for the new version, this is looking pretty good now, just a
>> few comments below
> 
> I agree that this step is looking pretty good now.
> 
> I didn't check closely, but when 1/3 undergoes necessary polishing,
> it may have repercussions on this step, though (I did see that the
> change in 3/3 would have overlaps with what was touched by 1/3 that
> needs to be done differently).
> 
> Thanks for guiding Rohit's series forward.
> 
>> This is only slightly different from reset_for_rollback() if you
>> decide to keep a separate code path for skip vs abort then I'd be
>> tempted to combine the two like this.
>>
>> diff --git a/sequencer.c b/sequencer.c
>> index ecf4be7e15..b187b4222e 100644
>> --- a/sequencer.c
>> +++ b/sequencer.c
>> @@ -2740,11 +2740,13 @@ static int reset_merge(void) {
>>   static int reset_for_rollback(const struct object_id *oid)
>>   {
>>          const char *argv[4];    /* reset --merge <arg> + NULL */
>> +       size_t i = 0;
> 
> That size_t is, eh, "unusual".  For an index into a small local
> array of known size, just sticking to bog-standard-and-boring 'int'
> would make it less distracting for future readers of the code.

Yes size_t is overkill here, it tends to be my default "array index" 
type but there's no need for it here.

> Or even better, perhaps use argv-array, so that you do not have to
> worry about sizing the local array sufficiently large in the first
> place.

That would be a much better way of doing it, I was so focussed on the 
existing code I didn't think of that.

Best Wishes

Phillip

> 
>> +       argv[i++] = "reset";
>> +       argv[i++] = "--merge";
>> +       if (oid)
>> +               argv[i++] = oid_to_hex(oid);
>> +       argv[i] = NULL;
>>          return run_command_v_opt(argv, RUN_GIT_CMD);
>>   }
> 

^ permalink raw reply	[flat|nested] 87+ messages in thread

* [GSoC][PATCH v3 0/3] Teach cherry-pick/revert to skip commits
  2019-06-08 19:19 [GSoC][PATCH 0/3] Teach cherry-pick/revert to skip commits Rohit Ashiwal
                   ` (4 preceding siblings ...)
  2019-06-11  7:31 ` [GSoC][PATCH v2 " Rohit Ashiwal
@ 2019-06-13  4:05 ` Rohit Ashiwal
  2019-06-13  4:05   ` [GSoC][PATCH v3 1/3] sequencer: add advice for revert Rohit Ashiwal
                     ` (2 more replies)
  2019-06-16  8:20 ` [GSoC][PATCH v4 0/4] [GSoC][PATCH 0/3] Teach cherry-pick/revert to skip commits Rohit Ashiwal
                   ` (3 subsequent siblings)
  9 siblings, 3 replies; 87+ messages in thread
From: Rohit Ashiwal @ 2019-06-13  4:05 UTC (permalink / raw)
  To: rohit.ashiwal265; +Cc: git, newren, t.gummerer, phillip.wood123, gitster

Adding a `--skip` option to make skipping commits easier for the user
and to make the commands more consistent. This will serve as a small
step to the bigger goal which improving consistency of sequencer commands,
i.e., improving how command line arguments are handled, this will also
lead to better user experience because of the precise advice provided.

Rohit Ashiwal (3):
  sequencer: add advice for revert
  cherry-pick/revert: add --skip option
  cherry-pick/revert: advise using --skip

 Documentation/git-cherry-pick.txt |   4 +-
 Documentation/git-revert.txt      |   4 +-
 Documentation/sequencer.txt       |   4 +
 builtin/commit.c                  |  13 ++--
 builtin/revert.c                  |   5 ++
 sequencer.c                       | 106 ++++++++++++++++++++++----
 sequencer.h                       |   1 +
 t/t3510-cherry-pick-sequence.sh   | 122 ++++++++++++++++++++++++++++++
 8 files changed, 232 insertions(+), 27 deletions(-)

-- 
2.21.0


^ permalink raw reply	[flat|nested] 87+ messages in thread

* [GSoC][PATCH v3 1/3] sequencer: add advice for revert
  2019-06-13  4:05 ` [GSoC][PATCH v3 0/3] Teach cherry-pick/revert to skip commits Rohit Ashiwal
@ 2019-06-13  4:05   ` Rohit Ashiwal
  2019-06-13 17:45     ` Phillip Wood
  2019-06-13  4:05   ` [GSoC][PATCH v3 2/3] cherry-pick/revert: add --skip option Rohit Ashiwal
  2019-06-13  4:05   ` [GSoC][PATCH v3 3/3] cherry-pick/revert: advise using --skip Rohit Ashiwal
  2 siblings, 1 reply; 87+ messages in thread
From: Rohit Ashiwal @ 2019-06-13  4:05 UTC (permalink / raw)
  To: rohit.ashiwal265; +Cc: git, newren, t.gummerer, phillip.wood123, gitster

In the case of merge conflicts, while performing a revert, we are
currently advised to use `git cherry-pick --<sequencer-options>`
of which --continue is incompatible for continuing the revert.
Introduce a separate advice message for `git revert`. Also change
the signature of `create_seq_dir` to handle which advice to display
selectively.

Signed-off-by: Rohit Ashiwal <rohit.ashiwal265@gmail.com>
---
changes:
    - Following Junio's advice[1], I've changed how we're handling error and
      advice fundamentally.

[1]: https://public-inbox.org/git/20190608191958.4593-1-rohit.ashiwal265@gmail.com/T/#mf8eefb068b7246c7c2a02cc8f7120a1a903a1eba

 sequencer.c | 34 ++++++++++++++++++++++++++++------
 1 file changed, 28 insertions(+), 6 deletions(-)

diff --git a/sequencer.c b/sequencer.c
index f88a97fb10..918cb5d761 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -2650,15 +2650,37 @@ static int walk_revs_populate_todo(struct todo_list *todo_list,
 	return 0;
 }
 
-static int create_seq_dir(void)
+static int create_seq_dir(struct repository *r)
 {
-	if (file_exists(git_path_seq_dir())) {
-		error(_("a cherry-pick or revert is already in progress"));
-		advise(_("try \"git cherry-pick (--continue | --quit | --abort)\""));
+	enum replay_action action;
+	const char *in_progress_advice;
+	const char *in_progress_error = NULL;
+
+	if (!sequencer_get_last_command(r, &action)) {
+		switch (action) {
+		case REPLAY_REVERT:
+			in_progress_error = _("revert is already in progress");
+			in_progress_advice =
+			_("try \"git revert (--continue | --abort | --quit)\"");
+			break;
+		case REPLAY_PICK:
+			in_progress_error = _("cherry-pick is already in progress");
+			in_progress_advice =
+			_("try \"git cherry-pick (--continue | --abort | --quit)\"");
+			break;
+		default:
+			BUG(_("the control must not reach here"));
+		}
+	}
+	if (in_progress_error) {
+		error("%s", in_progress_error);
+		advise("%s", in_progress_advice);
 		return -1;
-	} else if (mkdir(git_path_seq_dir(), 0777) < 0)
+	}
+	if (mkdir(git_path_seq_dir(), 0777) < 0)
 		return error_errno(_("could not create sequencer directory '%s'"),
 				   git_path_seq_dir());
+
 	return 0;
 }
 
@@ -4237,7 +4259,7 @@ int sequencer_pick_revisions(struct repository *r,
 	 */
 
 	if (walk_revs_populate_todo(&todo_list, opts) ||
-			create_seq_dir() < 0)
+			create_seq_dir(r) < 0)
 		return -1;
 	if (get_oid("HEAD", &oid) && (opts->action == REPLAY_REVERT))
 		return error(_("can't revert as initial commit"));
-- 
2.21.0


^ permalink raw reply	[flat|nested] 87+ messages in thread

* [GSoC][PATCH v3 2/3] cherry-pick/revert: add --skip option
  2019-06-13  4:05 ` [GSoC][PATCH v3 0/3] Teach cherry-pick/revert to skip commits Rohit Ashiwal
  2019-06-13  4:05   ` [GSoC][PATCH v3 1/3] sequencer: add advice for revert Rohit Ashiwal
@ 2019-06-13  4:05   ` Rohit Ashiwal
  2019-06-13 17:56     ` Junio C Hamano
  2019-06-13 17:59     ` Phillip Wood
  2019-06-13  4:05   ` [GSoC][PATCH v3 3/3] cherry-pick/revert: advise using --skip Rohit Ashiwal
  2 siblings, 2 replies; 87+ messages in thread
From: Rohit Ashiwal @ 2019-06-13  4:05 UTC (permalink / raw)
  To: rohit.ashiwal265; +Cc: git, newren, t.gummerer, phillip.wood123, gitster

git am or rebase have a --skip flag to skip the current commit if the
user wishes to do so. During a cherry-pick or revert a user could
likewise skip a commit, but needs to use 'git reset' (or in the case
of conflicts 'git reset --merge'), followed by 'git (cherry-pick |
revert) --continue' to skip the commit. This is more annoying and
sometimes confusing on the users' part. Add a `--skip` option to make
skipping commits easier for the user and to make the commands more
consistent.

In the next commit, we will change the advice messages and some tests
hence finishing the process of teaching revert and cherry-pick
"how to skip commits".

Signed-off-by: Rohit Ashiwal <rohit.ashiwal265@gmail.com>
---
changes:
    - Remove `reset_merge` from last revision[1] and modified `reset_for_rollback`
      and signature of `rollback_single_pick` to handle if `--skip` flag
    - Modify test which gave "ambiguous refname" warning[2]

[1]: https://public-inbox.org/git/20190608191958.4593-1-rohit.ashiwal265@gmail.com/T/#m11a573a3b91dfd2fcfae40c6ecc2148f8c92e10c
[2]: https://public-inbox.org/git/20190608191958.4593-1-rohit.ashiwal265@gmail.com/T/#m586cb8930cfcb737e4f19662f0eef3716b1e9d35

 Documentation/git-cherry-pick.txt |   4 +-
 Documentation/git-revert.txt      |   4 +-
 Documentation/sequencer.txt       |   4 ++
 builtin/revert.c                  |   5 ++
 sequencer.c                       |  67 +++++++++++++++++---
 sequencer.h                       |   1 +
 t/t3510-cherry-pick-sequence.sh   | 102 ++++++++++++++++++++++++++++++
 7 files changed, 171 insertions(+), 16 deletions(-)

diff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt
index 754b16ce0c..955880ab88 100644
--- a/Documentation/git-cherry-pick.txt
+++ b/Documentation/git-cherry-pick.txt
@@ -10,9 +10,7 @@ SYNOPSIS
 [verse]
 'git cherry-pick' [--edit] [-n] [-m parent-number] [-s] [-x] [--ff]
 		  [-S[<keyid>]] <commit>...
-'git cherry-pick' --continue
-'git cherry-pick' --quit
-'git cherry-pick' --abort
+'git cherry-pick' --continue | --skip | --abort | --quit
 
 DESCRIPTION
 -----------
diff --git a/Documentation/git-revert.txt b/Documentation/git-revert.txt
index 0c82ca5bc0..ffce98099c 100644
--- a/Documentation/git-revert.txt
+++ b/Documentation/git-revert.txt
@@ -9,9 +9,7 @@ SYNOPSIS
 --------
 [verse]
 'git revert' [--[no-]edit] [-n] [-m parent-number] [-s] [-S[<keyid>]] <commit>...
-'git revert' --continue
-'git revert' --quit
-'git revert' --abort
+'git revert' --continue | --skip | --abort | --quit
 
 DESCRIPTION
 -----------
diff --git a/Documentation/sequencer.txt b/Documentation/sequencer.txt
index 5a57c4a407..3bceb56474 100644
--- a/Documentation/sequencer.txt
+++ b/Documentation/sequencer.txt
@@ -3,6 +3,10 @@
 	`.git/sequencer`.  Can be used to continue after resolving
 	conflicts in a failed cherry-pick or revert.
 
+--skip::
+	Skip the current commit and continue with the rest of the
+	sequence.
+
 --quit::
 	Forget about the current operation in progress.  Can be used
 	to clear the sequencer state after a failed cherry-pick or
diff --git a/builtin/revert.c b/builtin/revert.c
index d4dcedbdc6..5dc5891ea2 100644
--- a/builtin/revert.c
+++ b/builtin/revert.c
@@ -102,6 +102,7 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)
 		OPT_CMDMODE(0, "quit", &cmd, N_("end revert or cherry-pick sequence"), 'q'),
 		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_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")),
@@ -151,6 +152,8 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)
 			this_operation = "--quit";
 		else if (cmd == 'c')
 			this_operation = "--continue";
+		else if (cmd == 's')
+			this_operation = "--skip";
 		else {
 			assert(cmd == 'a');
 			this_operation = "--abort";
@@ -210,6 +213,8 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)
 		return sequencer_continue(the_repository, opts);
 	if (cmd == 'a')
 		return sequencer_rollback(the_repository, opts);
+	if (cmd == 's')
+		return sequencer_skip(the_repository, opts);
 	return sequencer_pick_revisions(the_repository, opts);
 }
 
diff --git a/sequencer.c b/sequencer.c
index 918cb5d761..6b78a26920 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -2733,25 +2733,26 @@ static int rollback_is_safe(void)
 
 static int reset_for_rollback(const struct object_id *oid)
 {
-	const char *argv[4];	/* reset --merge <arg> + NULL */
+	struct argv_array argv = ARGV_ARRAY_INIT;	/* reset --merge <arg> + NULL */
 
-	argv[0] = "reset";
-	argv[1] = "--merge";
-	argv[2] = oid_to_hex(oid);
-	argv[3] = NULL;
-	return run_command_v_opt(argv, RUN_GIT_CMD);
+	argv_array_pushl(&argv, "reset", "--merge", NULL);
+
+	if (!is_null_oid(oid))
+		argv_array_push(&argv, oid_to_hex(oid));
+
+	return run_command_v_opt(argv.argv, RUN_GIT_CMD);
 }
 
-static int rollback_single_pick(struct repository *r)
+static int rollback_single_pick(struct repository *r, unsigned int is_skip)
 {
 	struct object_id head_oid;
 
 	if (!file_exists(git_path_cherry_pick_head(r)) &&
-	    !file_exists(git_path_revert_head(r)))
+	    !file_exists(git_path_revert_head(r)) && !is_skip)
 		return error(_("no cherry-pick or revert in progress"));
 	if (read_ref_full("HEAD", 0, &head_oid, NULL))
 		return error(_("cannot resolve HEAD"));
-	if (is_null_oid(&head_oid))
+	if (is_null_oid(&head_oid) && !is_skip)
 		return error(_("cannot abort from a branch yet to be born"));
 	return reset_for_rollback(&head_oid);
 }
@@ -2770,7 +2771,7 @@ int sequencer_rollback(struct repository *r, struct replay_opts *opts)
 		 * If CHERRY_PICK_HEAD or REVERT_HEAD indicates
 		 * a single-cherry-pick in progress, abort that.
 		 */
-		return rollback_single_pick(r);
+		return rollback_single_pick(r, 0);
 	}
 	if (!f)
 		return error_errno(_("cannot open '%s'"), git_path_head_file());
@@ -2805,6 +2806,52 @@ int sequencer_rollback(struct repository *r, struct replay_opts *opts)
 	return -1;
 }
 
+int sequencer_skip(struct repository *r, struct replay_opts *opts)
+{
+	enum replay_action action = -1;
+	sequencer_get_last_command(r, &action);
+
+	switch (opts->action) {
+	case REPLAY_REVERT:
+		if (!file_exists(git_path_revert_head(r))) {
+			if (action == REPLAY_REVERT) {
+				if (!rollback_is_safe())
+					goto give_advice;
+				else
+					break;
+			}
+			return error(_("no revert in progress"));
+		}
+		break;
+	case REPLAY_PICK:
+		if (!file_exists(git_path_cherry_pick_head(r))) {
+			if (action == REPLAY_PICK) {
+				if (!rollback_is_safe())
+					goto give_advice;
+				else
+					break;
+			}
+			return error(_("no cherry-pick in progress"));
+		}
+		break;
+	default:
+		BUG("the control must not reach here");
+	}
+
+	if (rollback_single_pick(r, 1))
+		return error(_("failed to skip the commit"));
+	if (!is_directory(git_path_seq_dir()))
+		return 0;
+
+	return sequencer_continue(r, opts);
+
+give_advice:
+	advise(_("have you committed already?\n"
+		 "try \"git %s --continue\""),
+		 action == REPLAY_REVERT ? "revert" : "cherry-pick");
+	return error(_("there is nothing to skip"));
+}
+
 static int save_todo(struct todo_list *todo_list, struct replay_opts *opts)
 {
 	struct lock_file todo_lock = LOCK_INIT;
diff --git a/sequencer.h b/sequencer.h
index 0c494b83d4..731b9853eb 100644
--- a/sequencer.h
+++ b/sequencer.h
@@ -129,6 +129,7 @@ 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_skip(struct repository *repo, struct replay_opts *opts);
 int sequencer_remove_state(struct replay_opts *opts);
 
 #define TODO_LIST_KEEP_EMPTY (1U << 0)
diff --git a/t/t3510-cherry-pick-sequence.sh b/t/t3510-cherry-pick-sequence.sh
index 941d5026da..f85ef51cac 100755
--- a/t/t3510-cherry-pick-sequence.sh
+++ b/t/t3510-cherry-pick-sequence.sh
@@ -93,6 +93,108 @@ test_expect_success 'cherry-pick cleans up sequencer state upon success' '
 	test_path_is_missing .git/sequencer
 '
 
+test_expect_success 'cherry-pick --skip requires cherry-pick in progress' '
+	pristine_detach initial &&
+	test_must_fail git cherry-pick --skip
+'
+
+test_expect_success 'revert --skip requires revert in progress' '
+	pristine_detach initial &&
+	test_must_fail git revert --skip
+'
+
+test_expect_success 'cherry-pick --skip to skip commit' '
+	pristine_detach initial &&
+	test_must_fail git cherry-pick anotherpick &&
+	test_must_fail git revert --skip &&
+	git cherry-pick --skip &&
+	test_cmp_rev initial HEAD &&
+	test_path_is_missing .git/CHERRY_PICK_HEAD
+'
+
+test_expect_success 'revert --skip to skip commit' '
+	pristine_detach anotherpick &&
+	test_must_fail git revert anotherpick~1 &&
+	test_must_fail git cherry-pick --skip &&
+	git revert --skip &&
+	test_cmp_rev anotherpick HEAD
+'
+
+test_expect_success 'skip "empty" commit' '
+	pristine_detach picked &&
+	test_commit dummy foo d &&
+	test_must_fail git cherry-pick anotherpick &&
+	git cherry-pick --skip &&
+	test_cmp_rev dummy HEAD
+'
+
+test_expect_success 'skip a commit and check if rest of sequence is correct' '
+	pristine_detach initial &&
+	echo e >expect &&
+	cat >expect.log <<-EOF &&
+	OBJID
+	:100644 100644 OBJID OBJID M	foo
+	OBJID
+	:100644 100644 OBJID OBJID M	foo
+	OBJID
+	:100644 100644 OBJID OBJID M	unrelated
+	OBJID
+	:000000 100644 OBJID OBJID A	foo
+	:000000 100644 OBJID OBJID A	unrelated
+	EOF
+	test_must_fail git cherry-pick base..yetanotherpick &&
+	test_must_fail git cherry-pick --skip &&
+	echo d >foo &&
+	git add foo &&
+	git cherry-pick --continue &&
+	{
+		git rev-list HEAD |
+		git diff-tree --root --stdin |
+		sed "s/$OID_REGEX/OBJID/g"
+	} >actual.log &&
+	test_cmp expect foo &&
+	test_cmp expect.log actual.log
+'
+
+test_expect_success 'check advice when we move HEAD by committing' '
+	pristine_detach initial &&
+	cat >expect <<-EOF &&
+	hint: have you committed already?
+	hint: try "git cherry-pick --continue"
+	error: there is nothing to skip
+	fatal: cherry-pick failed
+	EOF
+	test_must_fail git cherry-pick base..yetanotherpick &&
+	echo c >foo &&
+	git commit -a &&
+	test_path_is_missing .git/CHERRY_PICK_HEAD &&
+	test_must_fail git cherry-pick --skip 2>advice &&
+	test_cmp expect advice
+'
+
+test_expect_success 'allow skipping commit but not abort for a new history' '
+	pristine_detach initial &&
+	cat >expect <<-EOF &&
+	error: cannot abort from a branch yet to be born
+	fatal: cherry-pick failed
+	EOF
+	git checkout --orphan new_disconnected &&
+	git reset --hard &&
+	test_must_fail git cherry-pick anotherpick &&
+	test_must_fail git cherry-pick --abort 2>advice &&
+	git cherry-pick --skip &&
+	test_cmp expect advice
+'
+
+test_expect_success 'allow skipping stopped cherry-pick because of untracked file modifications' '
+	pristine_detach initial &&
+	git rm --cached unrelated &&
+	git commit -m "untrack unrelated" &&
+	test_must_fail git cherry-pick initial base &&
+	test_path_is_missing .git/CHERRY_PICK_HEAD &&
+	git cherry-pick --skip
+'
+
 test_expect_success '--quit does not complain when no cherry-pick is in progress' '
 	pristine_detach initial &&
 	git cherry-pick --quit
-- 
2.21.0


^ permalink raw reply	[flat|nested] 87+ messages in thread

* [GSoC][PATCH v3 3/3] cherry-pick/revert: advise using --skip
  2019-06-13  4:05 ` [GSoC][PATCH v3 0/3] Teach cherry-pick/revert to skip commits Rohit Ashiwal
  2019-06-13  4:05   ` [GSoC][PATCH v3 1/3] sequencer: add advice for revert Rohit Ashiwal
  2019-06-13  4:05   ` [GSoC][PATCH v3 2/3] cherry-pick/revert: add --skip option Rohit Ashiwal
@ 2019-06-13  4:05   ` Rohit Ashiwal
  2 siblings, 0 replies; 87+ messages in thread
From: Rohit Ashiwal @ 2019-06-13  4:05 UTC (permalink / raw)
  To: rohit.ashiwal265; +Cc: git, newren, t.gummerer, phillip.wood123, gitster

The previous commit introduced a --skip flag for cherry-pick and
revert. Update the advice messages, to tell users about this less
cumbersome way of skipping commits. Also add tests to ensure
everything is working fine.

Signed-off-by: Rohit Ashiwal <rohit.ashiwal265@gmail.com>
---
changes:
    - No major changes, change slightly according to the previous commits

 builtin/commit.c                | 13 ++++++++-----
 sequencer.c                     | 11 ++++++++---
 t/t3510-cherry-pick-sequence.sh | 20 ++++++++++++++++++++
 3 files changed, 36 insertions(+), 8 deletions(-)

diff --git a/builtin/commit.c b/builtin/commit.c
index 1c9e8e2228..1f47c51bdc 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -60,15 +60,18 @@ N_("The previous cherry-pick is now empty, possibly due to conflict resolution.\
 "\n");
 
 static const char empty_cherry_pick_advice_single[] =
-N_("Otherwise, please use 'git reset'\n");
+N_("Otherwise, please use 'git cherry-pick --skip'\n");
 
 static const char empty_cherry_pick_advice_multi[] =
-N_("If you wish to skip this commit, use:\n"
+N_("and then use:\n"
 "\n"
-"    git reset\n"
+"    git cherry-pick --continue\n"
 "\n"
-"Then \"git cherry-pick --continue\" will resume cherry-picking\n"
-"the remaining commits.\n");
+"to resume cherry-picking the remaining commits.\n"
+"If you wish to skip this commit, use:\n"
+"\n"
+"    git cherry-pick --skip\n"
+"\n");
 
 static const char *color_status_slots[] = {
 	[WT_STATUS_HEADER]	  = "header",
diff --git a/sequencer.c b/sequencer.c
index 6b78a26920..5d189791ee 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -2655,18 +2655,20 @@ static int create_seq_dir(struct repository *r)
 	enum replay_action action;
 	const char *in_progress_advice;
 	const char *in_progress_error = NULL;
+	unsigned int advise_skip = file_exists(git_path_revert_head(r)) ||
+				file_exists(git_path_cherry_pick_head(r));
 
 	if (!sequencer_get_last_command(r, &action)) {
 		switch (action) {
 		case REPLAY_REVERT:
 			in_progress_error = _("revert is already in progress");
 			in_progress_advice =
-			_("try \"git revert (--continue | --abort | --quit)\"");
+			_("try \"git revert (--continue | %s--abort | --quit)\"");
 			break;
 		case REPLAY_PICK:
 			in_progress_error = _("cherry-pick is already in progress");
 			in_progress_advice =
-			_("try \"git cherry-pick (--continue | --abort | --quit)\"");
+			_("try \"git cherry-pick (--continue | %s--abort | --quit)\"");
 			break;
 		default:
 			BUG(_("the control must not reach here"));
@@ -2674,7 +2676,10 @@ static int create_seq_dir(struct repository *r)
 	}
 	if (in_progress_error) {
 		error("%s", in_progress_error);
-		advise("%s", in_progress_advice);
+		if (advise_skip)
+			advise(in_progress_advice, "--skip | ");
+		else
+			advise(in_progress_advice, "");
 		return -1;
 	}
 	if (mkdir(git_path_seq_dir(), 0777) < 0)
diff --git a/t/t3510-cherry-pick-sequence.sh b/t/t3510-cherry-pick-sequence.sh
index f85ef51cac..8672f0b2cd 100755
--- a/t/t3510-cherry-pick-sequence.sh
+++ b/t/t3510-cherry-pick-sequence.sh
@@ -172,6 +172,26 @@ test_expect_success 'check advice when we move HEAD by committing' '
 	test_cmp expect advice
 '
 
+test_expect_success 'selectively advise --skip while launching another sequence' '
+	pristine_detach initial &&
+	cat >expect <<-EOF &&
+	error: cherry-pick is already in progress
+	hint: try "git cherry-pick (--continue | --skip | --abort | --quit)"
+	fatal: cherry-pick failed
+	EOF
+	test_must_fail git cherry-pick picked..yetanotherpick &&
+	test_must_fail git cherry-pick picked..yetanotherpick 2>advice &&
+	test_cmp expect advice &&
+	cat >expect <<-EOF &&
+	error: cherry-pick is already in progress
+	hint: try "git cherry-pick (--continue | --abort | --quit)"
+	fatal: cherry-pick failed
+	EOF
+	git reset --merge &&
+	test_must_fail git cherry-pick picked..yetanotherpick 2>advice &&
+	test_cmp expect advice
+'
+
 test_expect_success 'allow skipping commit but not abort for a new history' '
 	pristine_detach initial &&
 	cat >expect <<-EOF &&
-- 
2.21.0


^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [GSoC][PATCH v3 1/3] sequencer: add advice for revert
  2019-06-13  4:05   ` [GSoC][PATCH v3 1/3] sequencer: add advice for revert Rohit Ashiwal
@ 2019-06-13 17:45     ` Phillip Wood
  2019-06-13 19:21       ` Martin Ågren
  2019-06-14  3:43       ` Rohit Ashiwal
  0 siblings, 2 replies; 87+ messages in thread
From: Phillip Wood @ 2019-06-13 17:45 UTC (permalink / raw)
  To: Rohit Ashiwal; +Cc: git, newren, t.gummerer, gitster

On 13/06/2019 05:05, Rohit Ashiwal wrote:
> In the case of merge conflicts, while performing a revert, we are
> currently advised to use `git cherry-pick --<sequencer-options>`
> of which --continue is incompatible for continuing the revert.
> Introduce a separate advice message for `git revert`. Also change
> the signature of `create_seq_dir` to handle which advice to display
> selectively.
> 
> Signed-off-by: Rohit Ashiwal <rohit.ashiwal265@gmail.com>
> ---
> changes:
>     - Following Junio's advice[1], I've changed how we're handling error and
>       advice fundamentally.
> 
> [1]: https://public-inbox.org/git/20190608191958.4593-1-rohit.ashiwal265@gmail.com/T/#mf8eefb068b7246c7c2a02cc8f7120a1a903a1eba
> 
>  sequencer.c | 34 ++++++++++++++++++++++++++++------
>  1 file changed, 28 insertions(+), 6 deletions(-)
> 
> diff --git a/sequencer.c b/sequencer.c
> index f88a97fb10..918cb5d761 100644
> --- a/sequencer.c
> +++ b/sequencer.c
> @@ -2650,15 +2650,37 @@ static int walk_revs_populate_todo(struct todo_list *todo_list,
>  	return 0;
>  }
>  
> -static int create_seq_dir(void)
> +static int create_seq_dir(struct repository *r)
>  {
> -	if (file_exists(git_path_seq_dir())) {
> -		error(_("a cherry-pick or revert is already in progress"));
> -		advise(_("try \"git cherry-pick (--continue | --quit | --abort)\""));
> +	enum replay_action action;
> +	const char *in_progress_advice;
> +	const char *in_progress_error = NULL;
> +
> +	if (!sequencer_get_last_command(r, &action)) {
> +		switch (action) {
> +		case REPLAY_REVERT:
> +			in_progress_error = _("revert is already in progress");
> +			in_progress_advice =
> +			_("try \"git revert (--continue | --abort | --quit)\"");
> +			break;
> +		case REPLAY_PICK:
> +			in_progress_error = _("cherry-pick is already in progress");
> +			in_progress_advice =
> +			_("try \"git cherry-pick (--continue | --abort | --quit)\"");
> +			break;
> +		default:
> +			BUG(_("the control must not reach here"));

This does not need to be translated as BUG() messages are not really for
users. Everything else looks fine to be now

Best Wishes

Phillip

> +		}
> +	}
> +	if (in_progress_error) {
> +		error("%s", in_progress_error);
> +		advise("%s", in_progress_advice);
>  		return -1;
> -	} else if (mkdir(git_path_seq_dir(), 0777) < 0)
> +	}
> +	if (mkdir(git_path_seq_dir(), 0777) < 0)
>  		return error_errno(_("could not create sequencer directory '%s'"),
>  				   git_path_seq_dir());
> +
>  	return 0;
>  }
>  
> @@ -4237,7 +4259,7 @@ int sequencer_pick_revisions(struct repository *r,
>  	 */
>  
>  	if (walk_revs_populate_todo(&todo_list, opts) ||
> -			create_seq_dir() < 0)
> +			create_seq_dir(r) < 0)
>  		return -1;
>  	if (get_oid("HEAD", &oid) && (opts->action == REPLAY_REVERT))
>  		return error(_("can't revert as initial commit"));
> 


^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [GSoC][PATCH v3 2/3] cherry-pick/revert: add --skip option
  2019-06-13  4:05   ` [GSoC][PATCH v3 2/3] cherry-pick/revert: add --skip option Rohit Ashiwal
@ 2019-06-13 17:56     ` Junio C Hamano
  2019-06-13 19:57       ` Junio C Hamano
                         ` (2 more replies)
  2019-06-13 17:59     ` Phillip Wood
  1 sibling, 3 replies; 87+ messages in thread
From: Junio C Hamano @ 2019-06-13 17:56 UTC (permalink / raw)
  To: Rohit Ashiwal; +Cc: git, newren, t.gummerer, phillip.wood123

Rohit Ashiwal <rohit.ashiwal265@gmail.com> writes:

> diff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt
> index 754b16ce0c..955880ab88 100644
> --- a/Documentation/git-cherry-pick.txt
> +++ b/Documentation/git-cherry-pick.txt
> @@ -10,9 +10,7 @@ SYNOPSIS
>  [verse]
>  'git cherry-pick' [--edit] [-n] [-m parent-number] [-s] [-x] [--ff]
>  		  [-S[<keyid>]] <commit>...
> -'git cherry-pick' --continue
> -'git cherry-pick' --quit
> -'git cherry-pick' --abort
> +'git cherry-pick' --continue | --skip | --abort | --quit

Is this correct, or do we need to enclose these choices inside (),
i.e.

	'git cherry-pick' ( --continue | --skip | --abort | --quit )

?  

> -static int rollback_single_pick(struct repository *r)
> +static int rollback_single_pick(struct repository *r, unsigned int is_skip)
>  {
>  	struct object_id head_oid;
>  
>  	if (!file_exists(git_path_cherry_pick_head(r)) &&
> -	    !file_exists(git_path_revert_head(r)))
> +	    !file_exists(git_path_revert_head(r)) && !is_skip)
>  		return error(_("no cherry-pick or revert in progress"));
>  	if (read_ref_full("HEAD", 0, &head_oid, NULL))
>  		return error(_("cannot resolve HEAD"));
> -	if (is_null_oid(&head_oid))
> +	if (is_null_oid(&head_oid) && !is_skip)
>  		return error(_("cannot abort from a branch yet to be born"));
>  	return reset_for_rollback(&head_oid);
>  }

It is unclear *why* the function (and more importantly, its callers)
would want to omit two sanity checks when is_skip is in effect.

Before this patch introduced such conditional behaviour, the name
was descriptive enough for this single-purpose function that is a
file-local helper, but it is no longer a case.  The function needs a
bit of commentary before it.

When &&-chaining error checks that are optional, check the condition
that makes the error checks optional first, i.e.

	if (!is_skip &&
		!file_exists(...) && !file_exists(...))
		return error(...);

The same comment applies to the "do not barf by checking is-null-oid
under is-skip mode, as that is a sign that we are on an unborn
branch and reset-for-rollback knows how to handle it now".

It may even be a good idea to group the checks that are guarded by
the condition for readability, i.e.

	if (!is_skip &&
		(!file_exists(...) && !file_exists(...)))
		return error(...);

> +int sequencer_skip(struct repository *r, struct replay_opts *opts)
> +{
> +	enum replay_action action = -1;
> +	sequencer_get_last_command(r, &action);
> +
> +	switch (opts->action) {
> +	case REPLAY_REVERT:
> +		if (!file_exists(git_path_revert_head(r))) {
> +			if (action == REPLAY_REVERT) {
> +				if (!rollback_is_safe())
> +					goto give_advice;
> +				else
> +					break;
> +			}
> +			return error(_("no revert in progress"));
> +		}

This part probably deserves a bit of in-code comment.  

    The Git subcommand (i.e. opts->action) tells us that we are
    asked to "git revert --skip".  When REVERT_HEAD is not there, we
    look at the last command of the sequencer state and make sure it
    is 'revert'; all other cases we barf.

That much we can read from the code.  But what are "all other cases"?
Do we cover a single-revert case (i.e. "git revert <commit>" got
conflict and the user is saying "git revert --skip")?  Was the user
in the middle of "git rebase -i" and the last command before we gave
the control back was 'pick'?

> +		break;
> +	case REPLAY_PICK:
> +		if (!file_exists(git_path_cherry_pick_head(r))) {
> +			if (action == REPLAY_PICK) {
> +				if (!rollback_is_safe())
> +					goto give_advice;
> +				else
> +					break;
> +			}
> +			return error(_("no cherry-pick in progress"));
> +		}
> +		break;
> +	default:
> +		BUG("the control must not reach here");
> +	}
> +
> +	if (rollback_single_pick(r, 1))
> +		return error(_("failed to skip the commit"));

And this takes us back to the previous comment.  By passing '1'
here, this caller is asking the callee to omit certain sanity check
the original version of the callee used to do.  What makes it an
appropriate thing to do so here?  "Because we reach at this point
under such and such condition, we would never have CHERRY_PICK_HEAD
or REVERT_HEAD---we do not want it to barf" is a good answer (and
no, do not merely give answer to me in your response---write the
answer as in-code comment to help future readers of the code).

"Because when we come here, sometimes the XXX_HEAD must exist but
some other times XXX_HEAD may not exist, so insisting that either
exists would make the function fail" is *NOT* a good answer, on the
other hand.  Somebody must still check that the necessary file
exists when it must exist.

Thanks.

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [GSoC][PATCH v3 2/3] cherry-pick/revert: add --skip option
  2019-06-13  4:05   ` [GSoC][PATCH v3 2/3] cherry-pick/revert: add --skip option Rohit Ashiwal
  2019-06-13 17:56     ` Junio C Hamano
@ 2019-06-13 17:59     ` Phillip Wood
  1 sibling, 0 replies; 87+ messages in thread
From: Phillip Wood @ 2019-06-13 17:59 UTC (permalink / raw)
  To: Rohit Ashiwal; +Cc: git, newren, t.gummerer, gitster, Jonathan Nieder

Hi Rohit

This is definitely moving in the right direction.

On 13/06/2019 05:05, Rohit Ashiwal wrote:
> git am or rebase have a --skip flag to skip the current commit if the
> user wishes to do so. During a cherry-pick or revert a user could
> likewise skip a commit, but needs to use 'git reset' (or in the case
> of conflicts 'git reset --merge'), followed by 'git (cherry-pick |
> revert) --continue' to skip the commit. This is more annoying and
> sometimes confusing on the users' part. Add a `--skip` option to make
> skipping commits easier for the user and to make the commands more
> consistent.
> 
> In the next commit, we will change the advice messages and some tests
> hence finishing the process of teaching revert and cherry-pick
> "how to skip commits".
> 
> Signed-off-by: Rohit Ashiwal <rohit.ashiwal265@gmail.com>
> ---
> changes:
>     - Remove `reset_merge` from last revision[1] and modified `reset_for_rollback`
>       and signature of `rollback_single_pick` to handle if `--skip` flag
>     - Modify test which gave "ambiguous refname" warning[2]
> 
> [1]: https://public-inbox.org/git/20190608191958.4593-1-rohit.ashiwal265@gmail.com/T/#m11a573a3b91dfd2fcfae40c6ecc2148f8c92e10c
> [2]: https://public-inbox.org/git/20190608191958.4593-1-rohit.ashiwal265@gmail.com/T/#m586cb8930cfcb737e4f19662f0eef3716b1e9d35
> 
>  Documentation/git-cherry-pick.txt |   4 +-
>  Documentation/git-revert.txt      |   4 +-
>  Documentation/sequencer.txt       |   4 ++
>  builtin/revert.c                  |   5 ++
>  sequencer.c                       |  67 +++++++++++++++++---
>  sequencer.h                       |   1 +
>  t/t3510-cherry-pick-sequence.sh   | 102 ++++++++++++++++++++++++++++++
>  7 files changed, 171 insertions(+), 16 deletions(-)
> 
> diff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt
> index 754b16ce0c..955880ab88 100644
> --- a/Documentation/git-cherry-pick.txt
> +++ b/Documentation/git-cherry-pick.txt
> @@ -10,9 +10,7 @@ SYNOPSIS
>  [verse]
>  'git cherry-pick' [--edit] [-n] [-m parent-number] [-s] [-x] [--ff]
>  		  [-S[<keyid>]] <commit>...
> -'git cherry-pick' --continue
> -'git cherry-pick' --quit
> -'git cherry-pick' --abort
> +'git cherry-pick' --continue | --skip | --abort | --quit
>  
>  DESCRIPTION
>  -----------
> diff --git a/Documentation/git-revert.txt b/Documentation/git-revert.txt
> index 0c82ca5bc0..ffce98099c 100644
> --- a/Documentation/git-revert.txt
> +++ b/Documentation/git-revert.txt
> @@ -9,9 +9,7 @@ SYNOPSIS
>  --------
>  [verse]
>  'git revert' [--[no-]edit] [-n] [-m parent-number] [-s] [-S[<keyid>]] <commit>...
> -'git revert' --continue
> -'git revert' --quit
> -'git revert' --abort
> +'git revert' --continue | --skip | --abort | --quit
>  
>  DESCRIPTION
>  -----------
> diff --git a/Documentation/sequencer.txt b/Documentation/sequencer.txt
> index 5a57c4a407..3bceb56474 100644
> --- a/Documentation/sequencer.txt
> +++ b/Documentation/sequencer.txt
> @@ -3,6 +3,10 @@
>  	`.git/sequencer`.  Can be used to continue after resolving
>  	conflicts in a failed cherry-pick or revert.
>  
> +--skip::
> +	Skip the current commit and continue with the rest of the
> +	sequence.
> +
>  --quit::
>  	Forget about the current operation in progress.  Can be used
>  	to clear the sequencer state after a failed cherry-pick or
> diff --git a/builtin/revert.c b/builtin/revert.c
> index d4dcedbdc6..5dc5891ea2 100644
> --- a/builtin/revert.c
> +++ b/builtin/revert.c
> @@ -102,6 +102,7 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)
>  		OPT_CMDMODE(0, "quit", &cmd, N_("end revert or cherry-pick sequence"), 'q'),
>  		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_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")),
> @@ -151,6 +152,8 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)
>  			this_operation = "--quit";
>  		else if (cmd == 'c')
>  			this_operation = "--continue";
> +		else if (cmd == 's')
> +			this_operation = "--skip";
>  		else {
>  			assert(cmd == 'a');
>  			this_operation = "--abort";
> @@ -210,6 +213,8 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)
>  		return sequencer_continue(the_repository, opts);
>  	if (cmd == 'a')
>  		return sequencer_rollback(the_repository, opts);
> +	if (cmd == 's')
> +		return sequencer_skip(the_repository, opts);
>  	return sequencer_pick_revisions(the_repository, opts);
>  }
>  
> diff --git a/sequencer.c b/sequencer.c
> index 918cb5d761..6b78a26920 100644
> --- a/sequencer.c
> +++ b/sequencer.c
> @@ -2733,25 +2733,26 @@ static int rollback_is_safe(void)
>  
>  static int reset_for_rollback(const struct object_id *oid)
>  {
> -	const char *argv[4];	/* reset --merge <arg> + NULL */
> +	struct argv_array argv = ARGV_ARRAY_INIT;	/* reset --merge <arg> + NULL */
>  
> -	argv[0] = "reset";
> -	argv[1] = "--merge";
> -	argv[2] = oid_to_hex(oid);
> -	argv[3] = NULL;
> -	return run_command_v_opt(argv, RUN_GIT_CMD);
> +	argv_array_pushl(&argv, "reset", "--merge", NULL);
> +
> +	if (!is_null_oid(oid))
> +		argv_array_push(&argv, oid_to_hex(oid));
> +

argv_array_pushl() copies the strings so you need to call
argv_array_clear() when you're done with it.

> +	return run_command_v_opt(argv.argv, RUN_GIT_CMD);>  }
>  
> -static int rollback_single_pick(struct repository *r)
> +static int rollback_single_pick(struct repository *r, unsigned int is_skip)
>  {
>  	struct object_id head_oid;
>  
>  	if (!file_exists(git_path_cherry_pick_head(r)) &&
> -	    !file_exists(git_path_revert_head(r)))
> +	    !file_exists(git_path_revert_head(r)) && !is_skip)
>  		return error(_("no cherry-pick or revert in progress"));
>  	if (read_ref_full("HEAD", 0, &head_oid, NULL))
>  		return error(_("cannot resolve HEAD"));
> -	if (is_null_oid(&head_oid))
> +	if (is_null_oid(&head_oid) && !is_skip)
>  		return error(_("cannot abort from a branch yet to be born"));

The changes here look good. One thing though - this still does not check
if we're on the final pick or not. The more I think about it the more I
think it shouldn't matter but I'm bothered about why abort refuses to
run on the null oid. I've cc'd Jonathan in case he can remember why this
code is here. I looked at the discussion [1] of the patch [2] that
introduced this but that bit doesn't seem to have been discussed.

[1]
https://public-inbox.org/git/20111211195836.GA25482@elie.hsd1.il.comcast.net/T/#u

[2]
https://github.com/git/git/commit/539047c19ec040819b6f6af2d55714195b812abb

>  	return reset_for_rollback(&head_oid);
>  }
> @@ -2770,7 +2771,7 @@ int sequencer_rollback(struct repository *r, struct replay_opts *opts)
>  		 * If CHERRY_PICK_HEAD or REVERT_HEAD indicates
>  		 * a single-cherry-pick in progress, abort that.
>  		 */
> -		return rollback_single_pick(r);
> +		return rollback_single_pick(r, 0);
>  	}
>  	if (!f)
>  		return error_errno(_("cannot open '%s'"), git_path_head_file());
> @@ -2805,6 +2806,52 @@ int sequencer_rollback(struct repository *r, struct replay_opts *opts)
>  	return -1;
>  }
>  
> +int sequencer_skip(struct repository *r, struct replay_opts *opts)
> +{
> +	enum replay_action action = -1;
> +	sequencer_get_last_command(r, &action);
> +
> +	switch (opts->action) {
> +	case REPLAY_REVERT:
> +		if (!file_exists(git_path_revert_head(r))) {
> +			if (action == REPLAY_REVERT) {
> +				if (!rollback_is_safe())
> +					goto give_advice;
> +				else
> +					break;
> +			}
> +			return error(_("no revert in progress"));
> +		}
> +		break;
> +	case REPLAY_PICK:
> +		if (!file_exists(git_path_cherry_pick_head(r))) {
> +			if (action == REPLAY_PICK) {
> +				if (!rollback_is_safe())
> +					goto give_advice;
> +				else
> +					break;
> +			}
> +			return error(_("no cherry-pick in progress"));
> +		}
> +		break;
> +	default:
> +		BUG("the control must not reach here");
> +	}
> +
> +	if (rollback_single_pick(r, 1))
> +		return error(_("failed to skip the commit"));
> +	if (!is_directory(git_path_seq_dir()))
> +		return 0;
> +
> +	return sequencer_continue(r, opts);
> +
> +give_advice:
> +	advise(_("have you committed already?\n"
> +		 "try \"git %s --continue\""),
> +		 action == REPLAY_REVERT ? "revert" : "cherry-pick");
> +	return error(_("there is nothing to skip"));
> +}
> +
>  static int save_todo(struct todo_list *todo_list, struct replay_opts *opts)
>  {
>  	struct lock_file todo_lock = LOCK_INIT;
> diff --git a/sequencer.h b/sequencer.h
> index 0c494b83d4..731b9853eb 100644
> --- a/sequencer.h
> +++ b/sequencer.h
> @@ -129,6 +129,7 @@ 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_skip(struct repository *repo, struct replay_opts *opts);
>  int sequencer_remove_state(struct replay_opts *opts);
>  
>  #define TODO_LIST_KEEP_EMPTY (1U << 0)
> diff --git a/t/t3510-cherry-pick-sequence.sh b/t/t3510-cherry-pick-sequence.sh
> index 941d5026da..f85ef51cac 100755
> --- a/t/t3510-cherry-pick-sequence.sh
> +++ b/t/t3510-cherry-pick-sequence.sh
> @@ -93,6 +93,108 @@ test_expect_success 'cherry-pick cleans up sequencer state upon success' '
>  	test_path_is_missing .git/sequencer
>  '
>  
> +test_expect_success 'cherry-pick --skip requires cherry-pick in progress' '
> +	pristine_detach initial &&
> +	test_must_fail git cherry-pick --skip
> +'
> +
> +test_expect_success 'revert --skip requires revert in progress' '
> +	pristine_detach initial &&
> +	test_must_fail git revert --skip
> +'
> +
> +test_expect_success 'cherry-pick --skip to skip commit' '
> +	pristine_detach initial &&
> +	test_must_fail git cherry-pick anotherpick &&
> +	test_must_fail git revert --skip &&
> +	git cherry-pick --skip &&
> +	test_cmp_rev initial HEAD &&
> +	test_path_is_missing .git/CHERRY_PICK_HEAD
> +'
> +
> +test_expect_success 'revert --skip to skip commit' '
> +	pristine_detach anotherpick &&
> +	test_must_fail git revert anotherpick~1 &&
> +	test_must_fail git cherry-pick --skip &&
> +	git revert --skip &&
> +	test_cmp_rev anotherpick HEAD
> +'
> +
> +test_expect_success 'skip "empty" commit' '
> +	pristine_detach picked &&
> +	test_commit dummy foo d &&
> +	test_must_fail git cherry-pick anotherpick &&
> +	git cherry-pick --skip &&
> +	test_cmp_rev dummy HEAD
> +'
> +
> +test_expect_success 'skip a commit and check if rest of sequence is correct' '
> +	pristine_detach initial &&
> +	echo e >expect &&
> +	cat >expect.log <<-EOF &&
> +	OBJID
> +	:100644 100644 OBJID OBJID M	foo
> +	OBJID
> +	:100644 100644 OBJID OBJID M	foo
> +	OBJID
> +	:100644 100644 OBJID OBJID M	unrelated
> +	OBJID
> +	:000000 100644 OBJID OBJID A	foo
> +	:000000 100644 OBJID OBJID A	unrelated
> +	EOF
> +	test_must_fail git cherry-pick base..yetanotherpick &&
> +	test_must_fail git cherry-pick --skip &&
> +	echo d >foo &&
> +	git add foo &&
> +	git cherry-pick --continue &&
> +	{
> +		git rev-list HEAD |
> +		git diff-tree --root --stdin |
> +		sed "s/$OID_REGEX/OBJID/g"
> +	} >actual.log &&
> +	test_cmp expect foo &&
> +	test_cmp expect.log actual.log
> +'
> +
> +test_expect_success 'check advice when we move HEAD by committing' '
> +	pristine_detach initial &&
> +	cat >expect <<-EOF &&
> +	hint: have you committed already?
> +	hint: try "git cherry-pick --continue"
> +	error: there is nothing to skip
> +	fatal: cherry-pick failed
> +	EOF
> +	test_must_fail git cherry-pick base..yetanotherpick &&
> +	echo c >foo &&
> +	git commit -a &&
> +	test_path_is_missing .git/CHERRY_PICK_HEAD &&
> +	test_must_fail git cherry-pick --skip 2>advice &&
> +	test_cmp expect advice

When you compare a translated string you need to use test_i18ncmp to
avoid test breakages when running under GET_TEXT_POISON. The CI suite
shows this up [3]. There are instructions for running tests under travis
in Documentation/SubmittingPatches.txt or Johannes can advise you about
using his CI setup with pull requests on gitgitgadget (and maybe git.git?)

Best Wishes

Phillip


[3] https://travis-ci.org/phillipwood/git/jobs/545251777

> +'
> +
> +test_expect_success 'allow skipping commit but not abort for a new history' '
> +	pristine_detach initial &&
> +	cat >expect <<-EOF &&
> +	error: cannot abort from a branch yet to be born
> +	fatal: cherry-pick failed
> +	EOF
> +	git checkout --orphan new_disconnected &&
> +	git reset --hard &&
> +	test_must_fail git cherry-pick anotherpick &&
> +	test_must_fail git cherry-pick --abort 2>advice &&
> +	git cherry-pick --skip &&
> +	test_cmp expect advice
> +'
> +
> +test_expect_success 'allow skipping stopped cherry-pick because of untracked file modifications' '
> +	pristine_detach initial &&
> +	git rm --cached unrelated &&
> +	git commit -m "untrack unrelated" &&
> +	test_must_fail git cherry-pick initial base &&
> +	test_path_is_missing .git/CHERRY_PICK_HEAD &&
> +	git cherry-pick --skip
> +'
> +
>  test_expect_success '--quit does not complain when no cherry-pick is in progress' '
>  	pristine_detach initial &&
>  	git cherry-pick --quit
> 


^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [GSoC][PATCH v3 1/3] sequencer: add advice for revert
  2019-06-13 17:45     ` Phillip Wood
@ 2019-06-13 19:21       ` Martin Ågren
  2019-06-13 20:59         ` Junio C Hamano
  2019-06-14  3:44         ` Rohit Ashiwal
  2019-06-14  3:43       ` Rohit Ashiwal
  1 sibling, 2 replies; 87+ messages in thread
From: Martin Ågren @ 2019-06-13 19:21 UTC (permalink / raw)
  To: Rohit Ashiwal
  Cc: Git Mailing List, Phillip Wood, Elijah Newren, Thomas Gummerer,
	Junio C Hamano

Hi Rohit,

On Thu, 13 Jun 2019 at 19:46, Phillip Wood <phillip.wood123@gmail.com> wrote:
>
> On 13/06/2019 05:05, Rohit Ashiwal wrote:
> > -static int create_seq_dir(void)
> > +static int create_seq_dir(struct repository *r)
> >  {
> > -     if (file_exists(git_path_seq_dir())) {
> > -             error(_("a cherry-pick or revert is already in progress"));
> > -             advise(_("try \"git cherry-pick (--continue | --quit | --abort)\""));
> > +     enum replay_action action;
> > +     const char *in_progress_advice;
> > +     const char *in_progress_error = NULL;

The assigning vs not assigning is a bit inconsistent, but that's a very
minor nit, and not why I started replying. Only noticed it just now. :-)

> > +     if (!sequencer_get_last_command(r, &action)) {
> > +             switch (action) {
> > +             case REPLAY_REVERT:
> > +                     in_progress_error = _("revert is already in progress");
> > +                     in_progress_advice =
> > +                     _("try \"git revert (--continue | --abort | --quit)\"");
> > +                     break;
> > +             case REPLAY_PICK:
> > +                     in_progress_error = _("cherry-pick is already in progress");
> > +                     in_progress_advice =
> > +                     _("try \"git cherry-pick (--continue | --abort | --quit)\"");
> > +                     break;
> > +             default:
> > +                     BUG(_("the control must not reach here"));
>
> This does not need to be translated as BUG() messages are not really for
> users. Everything else looks fine to be now

I agree 100% with Phillip, but I'll also note that "the control must not
reach here" doesn't tell me anything that BUG() doesn't already. That
is, the point of BUG() is to document that, indeed, we shouldn't get
here and to alert if we do anyway.

An obvious alternative would be

        BUG("action is neither revert nor pick");

but that doesn't say much more than the code already says quite clearly,
plus it risks getting outdated. I'd probably settle on something like

        BUG("unexpected action in create_seq_dir");

which should give us a good clue even if all we have is this message (so
no file, no line number), but I am sure there are other good choices
here. :-)

Thanks Rohit for your work on this. I'm impressed by how you've polished
this series.


Martin

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [GSoC][PATCH v3 2/3] cherry-pick/revert: add --skip option
  2019-06-13 17:56     ` Junio C Hamano
@ 2019-06-13 19:57       ` Junio C Hamano
  2019-06-14  3:48         ` Rohit Ashiwal
  2019-06-14  3:45       ` Rohit Ashiwal
  2019-06-16  7:03       ` Rohit Ashiwal
  2 siblings, 1 reply; 87+ messages in thread
From: Junio C Hamano @ 2019-06-13 19:57 UTC (permalink / raw)
  To: Rohit Ashiwal; +Cc: git, newren, t.gummerer, phillip.wood123

Junio C Hamano <gitster@pobox.com> writes:

>> -static int rollback_single_pick(struct repository *r)
>> +static int rollback_single_pick(struct repository *r, unsigned int is_skip)
>>  {
>> ...
>> +	if (is_null_oid(&head_oid) && !is_skip)
>>  		return error(_("cannot abort from a branch yet to be born"));
>>  	return reset_for_rollback(&head_oid);
>>  }
>
> It is unclear *why* the function (and more importantly, its callers)
> would want to omit two sanity checks when is_skip is in effect.
> ...
>> +	default:
>> +		BUG("the control must not reach here");
>> +	}
>> +
>> +	if (rollback_single_pick(r, 1))
>> +		return error(_("failed to skip the commit"));
>
> And this takes us back to the previous comment.  By passing '1'
> here, this caller is asking the callee to omit certain sanity check
> the original version of the callee used to do.  What makes it an
> appropriate thing to do so here?

I think my earlier comments would lead to a wrong direction, i.e. to
justify the change made to rollback_single_pick(), so let's step
back a bit.  Perhaps the change is unjustifiable and that is why I
had trouble reading it and trying to make sense out of it.

Is it possible that the new callsite that passes is_skip==1 should
not be calling it (while castrating many parts of the callee) in the
first place?  Perhaps it is doing something _different_ from being
called "rollback single pick" (or perhaps the name of the function
is not specific enough to describe what its existing caller, i.e. the
one that passes is_skip==0 after your patch, calls it for)?  IOW,
would it lead to a better code structure if you left the original
rollback_single_pick() helper and its caller alone (perhaps rename
it to make it clearer what it does), and *add* a new helper around
the underlying reset_for_rollback() function and call it from here?

Perhaps it is not rolling back but is skipping, so the new function
needs to be called skip_single_pick() or something, and the existing
one is named correctly and there is no need for even renaming?

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [GSoC][PATCH v3 1/3] sequencer: add advice for revert
  2019-06-13 19:21       ` Martin Ågren
@ 2019-06-13 20:59         ` Junio C Hamano
  2019-06-14  3:44         ` Rohit Ashiwal
  1 sibling, 0 replies; 87+ messages in thread
From: Junio C Hamano @ 2019-06-13 20:59 UTC (permalink / raw)
  To: Martin Ågren
  Cc: Rohit Ashiwal, Git Mailing List, Phillip Wood, Elijah Newren,
	Thomas Gummerer

Martin Ågren <martin.agren@gmail.com> writes:

> ...
> I agree 100% with Phillip, but I'll also note that "the control must not
> reach here" doesn't tell me anything that BUG() doesn't already. That
> is,...

Thanks, all of you involved in this topic, for excellent mentorship.

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [GSoC][PATCH v3 1/3] sequencer: add advice for revert
  2019-06-13 17:45     ` Phillip Wood
  2019-06-13 19:21       ` Martin Ågren
@ 2019-06-14  3:43       ` Rohit Ashiwal
  1 sibling, 0 replies; 87+ messages in thread
From: Rohit Ashiwal @ 2019-06-14  3:43 UTC (permalink / raw)
  To: phillip.wood123; +Cc: git, gitster, newren, rohit.ashiwal265, t.gummerer

Hi Phillip

On 2019-06-13 17:45 UTC Phillip Wood <phillip.wood123@gmail.com> wrote:
>
>> +			break;
>> +		default:
>> +			BUG(_("the control must not reach here"));
>
> This does not need to be translated as BUG() messages are not really for
> users. Everything else looks fine to be now

I know this is not intended for the users, but seeing a message like
this a user might think to report it to the team with the steps for
reproducing the BUG. Yes, I agree this needs a little bit of re-wording.

> Best Wishes
> 
> Phillip

Thanks
Rohit


^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [GSoC][PATCH v3 1/3] sequencer: add advice for revert
  2019-06-13 19:21       ` Martin Ågren
  2019-06-13 20:59         ` Junio C Hamano
@ 2019-06-14  3:44         ` Rohit Ashiwal
  1 sibling, 0 replies; 87+ messages in thread
From: Rohit Ashiwal @ 2019-06-14  3:44 UTC (permalink / raw)
  To: martin.agren
  Cc: git, gitster, newren, phillip.wood123, rohit.ashiwal265, t.gummerer

Hi Martin

On 2019-06-13 19:21 UTC Martin Ågren <martin.agren@gmail.com> wrote:
> 
> > > +     const char *in_progress_advice;
> > > +     const char *in_progress_error = NULL;
> 
> The assigning vs not assigning is a bit inconsistent, but that's a very
> minor nit, and not why I started replying. Only noticed it just now. :-)

Let's make both NULL then.

> I agree 100% with Phillip, but I'll also note that "the control must not
> reach here" doesn't tell me anything that BUG() doesn't already. That
> is, the point of BUG() is to document that, indeed, we shouldn't get
> here and to alert if we do anyway.

Agreed.

> An obvious alternative would be
> 
>         BUG("action is neither revert nor pick");
> 
> but that doesn't say much more than the code already says quite clearly,
> plus it risks getting outdated. I'd probably settle on something like
> 
>         BUG("unexpected action in create_seq_dir");

Yeah, now that I know more about what BUG is truly intended for, I
think you are right here. We should change it.

> which should give us a good clue even if all we have is this message (so
> no file, no line number), but I am sure there are other good choices
> here. :-)
> 
> Thanks Rohit for your work on this. I'm impressed by how you've polished
> this series.

Thank you very much Martin. Appreciations like these help us developers
keep going and working even harder.

Thanks
Rohit


^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [GSoC][PATCH v3 2/3] cherry-pick/revert: add --skip option
  2019-06-13 17:56     ` Junio C Hamano
  2019-06-13 19:57       ` Junio C Hamano
@ 2019-06-14  3:45       ` Rohit Ashiwal
  2019-06-14 15:58         ` Junio C Hamano
  2019-06-16  7:03       ` Rohit Ashiwal
  2 siblings, 1 reply; 87+ messages in thread
From: Rohit Ashiwal @ 2019-06-14  3:45 UTC (permalink / raw)
  To: gitster; +Cc: git, newren, phillip.wood123, rohit.ashiwal265, t.gummerer

Hi Junio

On 2019-06-13 17:56 UTC Junio C Hamano <gitster@pobox.com> wrote:
> 
> > +'git cherry-pick' --continue | --skip | --abort | --quit
> 
> Is this correct, or do we need to enclose these choices inside (),
> i.e.
> 
> 	'git cherry-pick' ( --continue | --skip | --abort | --quit )
> 
> ?

Documentation of `git rebase` also lists these options without the
'('s so, I thought to make it similar to that.
 
> It is unclear *why* the function (and more importantly, its callers)
> would want to omit two sanity checks when is_skip is in effect.
> 
> Before this patch introduced such conditional behaviour, the name
> was descriptive enough for this single-purpose function that is a
> file-local helper, but it is no longer a case.  The function needs a
> bit of commentary before it.
> 
> When &&-chaining error checks that are optional, check the condition
> that makes the error checks optional first, i.e.
> 
> 	if (!is_skip &&
> 		!file_exists(...) && !file_exists(...))
> 		return error(...);
> 
> [...]
> 
> no, do not merely give answer to me in your response---write the
> answer as in-code comment to help future readers of the code).
> 
> "Because when we come here, sometimes the XXX_HEAD must exist but
> some other times XXX_HEAD may not exist, so insisting that either
> exists would make the function fail" is *NOT* a good answer, on the
> other hand.  Somebody must still check that the necessary file
> exists when it must exist.

Yes, I should have added some comments. I'll add them in next revision.

Thanks
Rohit


^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [GSoC][PATCH v3 2/3] cherry-pick/revert: add --skip option
  2019-06-13 19:57       ` Junio C Hamano
@ 2019-06-14  3:48         ` Rohit Ashiwal
  0 siblings, 0 replies; 87+ messages in thread
From: Rohit Ashiwal @ 2019-06-14  3:48 UTC (permalink / raw)
  To: gitster; +Cc: git, newren, phillip.wood123, rohit.ashiwal265, t.gummerer

Hi Junio

On 2019-06-13 19:57 UTC Junio C Hamano <gitster@pobox.com> wrote:
> 
> I think my earlier comments would lead to a wrong direction, i.e. to
> justify the change made to rollback_single_pick(), so let's step
> back a bit.  Perhaps the change is unjustifiable and that is why I
> had trouble reading it and trying to make sense out of it.
> 
> Is it possible that the new callsite that passes is_skip==1 should
> not be calling it (while castrating many parts of the callee) in the
> first place?  Perhaps it is doing something _different_ from being
> called "rollback single pick" (or perhaps the name of the function
> is not specific enough to describe what its existing caller, i.e. the
> one that passes is_skip==0 after your patch, calls it for)?  IOW,
> would it lead to a better code structure if you left the original
> rollback_single_pick() helper and its caller alone (perhaps rename
> it to make it clearer what it does), and *add* a new helper around
> the underlying reset_for_rollback() function and call it from here?

That is why I added a new function, but I was not super sure if it
was a good idea to begin with, since it only introduced small changes
to `reset_for_rollback` (also Phillip[1] discouraged it so, I stopped
thinking in that direction).

> Perhaps it is not rolling back but is skipping, so the new function
> needs to be called skip_single_pick() or something, and the existing
> one is named correctly and there is no need for even renaming?

We could have a wrapper function to `reset_for_rollback` and better
rename it to `reset_merge` since we *are* resetting a merge which
translates to rolling-back in reality?

Thanks
Rohit

[1]: https://public-inbox.org/git/6d3c1c1e-6140-dd8c-c37f-8c625b04ddc9@gmail.com/


^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [GSoC][PATCH v3 2/3] cherry-pick/revert: add --skip option
  2019-06-14  3:45       ` Rohit Ashiwal
@ 2019-06-14 15:58         ` Junio C Hamano
  0 siblings, 0 replies; 87+ messages in thread
From: Junio C Hamano @ 2019-06-14 15:58 UTC (permalink / raw)
  To: Rohit Ashiwal; +Cc: git, newren, phillip.wood123, t.gummerer

Rohit Ashiwal <rohit.ashiwal265@gmail.com> writes:

>> Is this correct, or do we need to enclose these choices inside (),
>> i.e.
>> 
>> 	'git cherry-pick' ( --continue | --skip | --abort | --quit )
>> 
>> ?
>
> Documentation of `git rebase` also lists these options without the
> '('s so, I thought to make it similar to that.

As long as you picked the ones that correctly spell their SYNOPSIS,
it is OK to model yours after them.

Seeing how "git-am.txt", "git-cat-file.txt", "git-checkout.txt", ...
"git-var.txt" etc. all use

	( choice1 | choice2 | choice3 )

when one among the choices MUST be chosen, contrasting with

	[ choice1 | choice2 | choice3 ]

when one can be chosen but not using any is also OK, I am not sure
if the documentation for "git rebase" is done right and should be
used as a model, though.

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [GSoC][PATCH v3 2/3] cherry-pick/revert: add --skip option 
  2019-06-13 17:56     ` Junio C Hamano
  2019-06-13 19:57       ` Junio C Hamano
  2019-06-14  3:45       ` Rohit Ashiwal
@ 2019-06-16  7:03       ` Rohit Ashiwal
  2 siblings, 0 replies; 87+ messages in thread
From: Rohit Ashiwal @ 2019-06-16  7:03 UTC (permalink / raw)
  To: gitster; +Cc: git, newren, phillip.wood123, rohit.ashiwal265, t.gummerer

Hi Junio

I am sorry, I missed to reply to these.

On 2019-06-13 17:56 UTC Junio C Hamano <gitster@pobox.com> wrote:
>
> > +int sequencer_skip(struct repository *r, struct replay_opts *opts)
> > +{
> > +	enum replay_action action = -1;
> > +	sequencer_get_last_command(r, &action);
> > +
> > +	switch (opts->action) {
> > +	case REPLAY_REVERT:
> > +		if (!file_exists(git_path_revert_head(r))) {
> > +			if (action == REPLAY_REVERT) {
> > +				if (!rollback_is_safe())
> > +					goto give_advice;
> > +				else
> > +					break;
> > +			}
> > +			return error(_("no revert in progress"));
> > +		}
> 
> This part probably deserves a bit of in-code comment.
> 
>     The Git subcommand (i.e. opts->action) tells us that we are
>     asked to "git revert --skip".  When REVERT_HEAD is not there, we
>     look at the last command of the sequencer state and make sure it
>     is 'revert'; all other cases we barf.
> 
> That much we can read from the code.  But what are "all other cases"?
> Do we cover a single-revert case (i.e. "git revert <commit>" got
> conflict and the user is saying "git revert --skip")?

Yes, we actually cover the single-revert case. Let's say there were
some conflicts then either .git/REVERT_HEAD will exist allowing
`git revert --skip` it's way or the user has already dealt with it
and committed his way in which case .git/REVERT_HEAD will be removed
and reverting ends (as it should).

> Was the user
> in the middle of "git rebase -i" and the last command before we gave
> the control back was 'pick'?

rebase -i creates different directories so, we are sure that --skip
does not skip in middle of a rebase. Am I right?

Hope these answers your questions
-- Rohit


^ permalink raw reply	[flat|nested] 87+ messages in thread

* [GSoC][PATCH v4 0/4] [GSoC][PATCH 0/3] Teach cherry-pick/revert to skip commits
  2019-06-08 19:19 [GSoC][PATCH 0/3] Teach cherry-pick/revert to skip commits Rohit Ashiwal
                   ` (5 preceding siblings ...)
  2019-06-13  4:05 ` [GSoC][PATCH v3 0/3] Teach cherry-pick/revert to skip commits Rohit Ashiwal
@ 2019-06-16  8:20 ` Rohit Ashiwal
  2019-06-16  8:20   ` [GSoC][PATCH v4 1/4] sequencer: add advice for revert Rohit Ashiwal
                     ` (4 more replies)
  2019-06-18 17:06 ` [GSoC][PATCH v5 0/5] " Rohit Ashiwal
                   ` (2 subsequent siblings)
  9 siblings, 5 replies; 87+ messages in thread
From: Rohit Ashiwal @ 2019-06-16  8:20 UTC (permalink / raw)
  To: rohit.ashiwal265
  Cc: git, newren, t.gummerer, phillip.wood123, martin.agren, jrnieder,
	gitster

Yet another iteration of my patch. We have changed the series a little bit. We
now have a commit that rename `reset_for_rollback` to `reset_merge`. A lot of
nit-picks were handled in this revision.

Thanks
Rohit

Rohit Ashiwal (4):
  sequencer: add advice for revert
  sequencer: rename reset_for_rollback to reset_merge
  cherry-pick/revert: add --skip option
  cherry-pick/revert: advise using --skip

 Documentation/git-cherry-pick.txt |   4 +-
 Documentation/git-revert.txt      |   4 +-
 Documentation/sequencer.txt       |   4 +
 builtin/commit.c                  |  13 +--
 builtin/revert.c                  |   5 ++
 sequencer.c                       | 139 ++++++++++++++++++++++++++----
 sequencer.h                       |   1 +
 t/t3510-cherry-pick-sequence.sh   | 122 ++++++++++++++++++++++++++
 8 files changed, 266 insertions(+), 26 deletions(-)

-- 
2.21.0


^ permalink raw reply	[flat|nested] 87+ messages in thread

* [GSoC][PATCH v4 1/4] sequencer: add advice for revert
  2019-06-16  8:20 ` [GSoC][PATCH v4 0/4] [GSoC][PATCH 0/3] Teach cherry-pick/revert to skip commits Rohit Ashiwal
@ 2019-06-16  8:20   ` Rohit Ashiwal
  2019-06-17  5:51     ` Thomas Gummerer
  2019-06-16  8:20   ` [GSoC][PATCH v4 2/4] sequencer: rename reset_for_rollback to reset_merge Rohit Ashiwal
                     ` (3 subsequent siblings)
  4 siblings, 1 reply; 87+ messages in thread
From: Rohit Ashiwal @ 2019-06-16  8:20 UTC (permalink / raw)
  To: rohit.ashiwal265
  Cc: git, newren, t.gummerer, phillip.wood123, martin.agren, jrnieder,
	gitster

In the case of merge conflicts, while performing a revert, we are
currently advised to use `git cherry-pick --<sequencer-options>`
of which --continue is incompatible for continuing the revert.
Introduce a separate advice message for `git revert`. Also change
the signature of `create_seq_dir` to handle which advice to display
selectively.

Signed-off-by: Rohit Ashiwal <rohit.ashiwal265@gmail.com>
---
changes:
    - change BUG()'s message under create_seq_dir

 sequencer.c | 34 ++++++++++++++++++++++++++++------
 1 file changed, 28 insertions(+), 6 deletions(-)

diff --git a/sequencer.c b/sequencer.c
index f88a97fb10..d80e1c3fbb 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -2650,15 +2650,37 @@ static int walk_revs_populate_todo(struct todo_list *todo_list,
 	return 0;
 }
 
-static int create_seq_dir(void)
+static int create_seq_dir(struct repository *r)
 {
-	if (file_exists(git_path_seq_dir())) {
-		error(_("a cherry-pick or revert is already in progress"));
-		advise(_("try \"git cherry-pick (--continue | --quit | --abort)\""));
+	enum replay_action action;
+	const char *in_progress_error = NULL;
+	const char *in_progress_advice = NULL;
+
+	if (!sequencer_get_last_command(r, &action)) {
+		switch (action) {
+		case REPLAY_REVERT:
+			in_progress_error = _("revert is already in progress");
+			in_progress_advice =
+			_("try \"git revert (--continue | --abort | --quit)\"");
+			break;
+		case REPLAY_PICK:
+			in_progress_error = _("cherry-pick is already in progress");
+			in_progress_advice =
+			_("try \"git cherry-pick (--continue | --abort | --quit)\"");
+			break;
+		default:
+			BUG(_("unexpected action in create_seq_dir"));
+		}
+	}
+	if (in_progress_error) {
+		error("%s", in_progress_error);
+		advise("%s", in_progress_advice);
 		return -1;
-	} else if (mkdir(git_path_seq_dir(), 0777) < 0)
+	}
+	if (mkdir(git_path_seq_dir(), 0777) < 0)
 		return error_errno(_("could not create sequencer directory '%s'"),
 				   git_path_seq_dir());
+
 	return 0;
 }
 
@@ -4237,7 +4259,7 @@ int sequencer_pick_revisions(struct repository *r,
 	 */
 
 	if (walk_revs_populate_todo(&todo_list, opts) ||
-			create_seq_dir() < 0)
+			create_seq_dir(r) < 0)
 		return -1;
 	if (get_oid("HEAD", &oid) && (opts->action == REPLAY_REVERT))
 		return error(_("can't revert as initial commit"));
-- 
2.21.0


^ permalink raw reply	[flat|nested] 87+ messages in thread

* [GSoC][PATCH v4 2/4] sequencer: rename reset_for_rollback to reset_merge
  2019-06-16  8:20 ` [GSoC][PATCH v4 0/4] [GSoC][PATCH 0/3] Teach cherry-pick/revert to skip commits Rohit Ashiwal
  2019-06-16  8:20   ` [GSoC][PATCH v4 1/4] sequencer: add advice for revert Rohit Ashiwal
@ 2019-06-16  8:20   ` Rohit Ashiwal
  2019-06-16  8:20   ` [GSoC][PATCH v4 3/4] cherry-pick/revert: add --skip option Rohit Ashiwal
                     ` (2 subsequent siblings)
  4 siblings, 0 replies; 87+ messages in thread
From: Rohit Ashiwal @ 2019-06-16  8:20 UTC (permalink / raw)
  To: rohit.ashiwal265
  Cc: git, newren, t.gummerer, phillip.wood123, martin.agren, jrnieder,
	gitster

We are on a path to teach cherry-pick/revert how to skip commits. To
achieve this, we could really make use of existing functions.
reset_for_rollback is one such function, but the name does not
intuitively suggest to use it to reset a merge, which it was born to
perform, see 539047c ("revert: introduce --abort to cancel a failed
cherry-pick", 2011-11-23). Change the name to reset_merge to make
it more intuitive.

Signed-off-by: Rohit Ashiwal <rohit.ashiwal265@gmail.com>
---
 sequencer.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/sequencer.c b/sequencer.c
index d80e1c3fbb..408643f88a 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -2731,7 +2731,7 @@ static int rollback_is_safe(void)
 	return oideq(&actual_head, &expected_head);
 }
 
-static int reset_for_rollback(const struct object_id *oid)
+static int reset_merge(const struct object_id *oid)
 {
 	const char *argv[4];	/* reset --merge <arg> + NULL */
 
@@ -2753,7 +2753,7 @@ static int rollback_single_pick(struct repository *r)
 		return error(_("cannot resolve HEAD"));
 	if (is_null_oid(&head_oid))
 		return error(_("cannot abort from a branch yet to be born"));
-	return reset_for_rollback(&head_oid);
+	return reset_merge(&head_oid);
 }
 
 int sequencer_rollback(struct repository *r, struct replay_opts *opts)
@@ -2796,7 +2796,7 @@ int sequencer_rollback(struct repository *r, struct replay_opts *opts)
 		warning(_("You seem to have moved HEAD. "
 			  "Not rewinding, check your HEAD!"));
 	} else
-	if (reset_for_rollback(&oid))
+	if (reset_merge(&oid))
 		goto fail;
 	strbuf_release(&buf);
 	return sequencer_remove_state(opts);
-- 
2.21.0


^ permalink raw reply	[flat|nested] 87+ messages in thread

* [GSoC][PATCH v4 3/4] cherry-pick/revert: add --skip option
  2019-06-16  8:20 ` [GSoC][PATCH v4 0/4] [GSoC][PATCH 0/3] Teach cherry-pick/revert to skip commits Rohit Ashiwal
  2019-06-16  8:20   ` [GSoC][PATCH v4 1/4] sequencer: add advice for revert Rohit Ashiwal
  2019-06-16  8:20   ` [GSoC][PATCH v4 2/4] sequencer: rename reset_for_rollback to reset_merge Rohit Ashiwal
@ 2019-06-16  8:20   ` Rohit Ashiwal
  2019-06-17  8:30     ` Thomas Gummerer
  2019-06-16  8:20   ` [GSoC][PATCH v4 4/4] cherry-pick/revert: advise using --skip Rohit Ashiwal
  2019-06-17  8:39   ` [GSoC][PATCH v4 0/4] [GSoC][PATCH 0/3] Teach cherry-pick/revert to skip commits Thomas Gummerer
  4 siblings, 1 reply; 87+ messages in thread
From: Rohit Ashiwal @ 2019-06-16  8:20 UTC (permalink / raw)
  To: rohit.ashiwal265
  Cc: git, newren, t.gummerer, phillip.wood123, martin.agren, jrnieder,
	gitster

git am or rebase have a --skip flag to skip the current commit if the
user wishes to do so. During a cherry-pick or revert a user could
likewise skip a commit, but needs to use 'git reset' (or in the case
of conflicts 'git reset --merge'), followed by 'git (cherry-pick |
revert) --continue' to skip the commit. This is more annoying and
sometimes confusing on the users' part. Add a `--skip` option to make
skipping commits easier for the user and to make the commands more
consistent.

In the next commit, we will change the advice messages and some tests
hence finishing the process of teaching revert and cherry-pick
"how to skip commits".

Signed-off-by: Rohit Ashiwal <rohit.ashiwal265@gmail.com>
---
changes:
    - Introduce '('s around documentation/help
    - Introduce a wrapper function skip_single_pick to reset_merge
    - Add comments to sequencer_skip
    - Change tests to use test_i18ncmp instead of test_cmp to not fail under
      GETTEXT_POISON

 Documentation/git-cherry-pick.txt |   4 +-
 Documentation/git-revert.txt      |   4 +-
 Documentation/sequencer.txt       |   4 ++
 builtin/revert.c                  |   5 ++
 sequencer.c                       |  94 +++++++++++++++++++++++++--
 sequencer.h                       |   1 +
 t/t3510-cherry-pick-sequence.sh   | 102 ++++++++++++++++++++++++++++++
 7 files changed, 202 insertions(+), 12 deletions(-)

diff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt
index 754b16ce0c..83ce51aedf 100644
--- a/Documentation/git-cherry-pick.txt
+++ b/Documentation/git-cherry-pick.txt
@@ -10,9 +10,7 @@ SYNOPSIS
 [verse]
 'git cherry-pick' [--edit] [-n] [-m parent-number] [-s] [-x] [--ff]
 		  [-S[<keyid>]] <commit>...
-'git cherry-pick' --continue
-'git cherry-pick' --quit
-'git cherry-pick' --abort
+'git cherry-pick' (--continue | --skip | --abort | --quit)
 
 DESCRIPTION
 -----------
diff --git a/Documentation/git-revert.txt b/Documentation/git-revert.txt
index 0c82ca5bc0..665e065ee3 100644
--- a/Documentation/git-revert.txt
+++ b/Documentation/git-revert.txt
@@ -9,9 +9,7 @@ SYNOPSIS
 --------
 [verse]
 'git revert' [--[no-]edit] [-n] [-m parent-number] [-s] [-S[<keyid>]] <commit>...
-'git revert' --continue
-'git revert' --quit
-'git revert' --abort
+'git revert' (--continue | --skip | --abort | --quit)
 
 DESCRIPTION
 -----------
diff --git a/Documentation/sequencer.txt b/Documentation/sequencer.txt
index 5a57c4a407..3bceb56474 100644
--- a/Documentation/sequencer.txt
+++ b/Documentation/sequencer.txt
@@ -3,6 +3,10 @@
 	`.git/sequencer`.  Can be used to continue after resolving
 	conflicts in a failed cherry-pick or revert.
 
+--skip::
+	Skip the current commit and continue with the rest of the
+	sequence.
+
 --quit::
 	Forget about the current operation in progress.  Can be used
 	to clear the sequencer state after a failed cherry-pick or
diff --git a/builtin/revert.c b/builtin/revert.c
index d4dcedbdc6..5dc5891ea2 100644
--- a/builtin/revert.c
+++ b/builtin/revert.c
@@ -102,6 +102,7 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)
 		OPT_CMDMODE(0, "quit", &cmd, N_("end revert or cherry-pick sequence"), 'q'),
 		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_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")),
@@ -151,6 +152,8 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)
 			this_operation = "--quit";
 		else if (cmd == 'c')
 			this_operation = "--continue";
+		else if (cmd == 's')
+			this_operation = "--skip";
 		else {
 			assert(cmd == 'a');
 			this_operation = "--abort";
@@ -210,6 +213,8 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)
 		return sequencer_continue(the_repository, opts);
 	if (cmd == 'a')
 		return sequencer_rollback(the_repository, opts);
+	if (cmd == 's')
+		return sequencer_skip(the_repository, opts);
 	return sequencer_pick_revisions(the_repository, opts);
 }
 
diff --git a/sequencer.c b/sequencer.c
index 408643f88a..95fa19a118 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -2733,13 +2733,18 @@ static int rollback_is_safe(void)
 
 static int reset_merge(const struct object_id *oid)
 {
-	const char *argv[4];	/* reset --merge <arg> + NULL */
+	int ret;
+	struct argv_array argv = ARGV_ARRAY_INIT;
 
-	argv[0] = "reset";
-	argv[1] = "--merge";
-	argv[2] = oid_to_hex(oid);
-	argv[3] = NULL;
-	return run_command_v_opt(argv, RUN_GIT_CMD);
+	argv_array_pushl(&argv, "reset", "--merge", NULL);
+
+	if (!is_null_oid(oid))
+		argv_array_push(&argv, oid_to_hex(oid));
+
+	ret = run_command_v_opt(argv.argv, RUN_GIT_CMD);
+	argv_array_clear(&argv);
+
+	return ret;
 }
 
 static int rollback_single_pick(struct repository *r)
@@ -2756,6 +2761,15 @@ static int rollback_single_pick(struct repository *r)
 	return reset_merge(&head_oid);
 }
 
+static int skip_single_pick(void)
+{
+	struct object_id head;
+
+	if (read_ref_full("HEAD", 0, &head, NULL))
+		return error(_("cannot resolve HEAD"));
+	return reset_merge(&head);
+}
+
 int sequencer_rollback(struct repository *r, struct replay_opts *opts)
 {
 	FILE *f;
@@ -2805,6 +2819,74 @@ int sequencer_rollback(struct repository *r, struct replay_opts *opts)
 	return -1;
 }
 
+int sequencer_skip(struct repository *r, struct replay_opts *opts)
+{
+	enum replay_action action = -1;
+	sequencer_get_last_command(r, &action);
+
+	/*
+	 * opts->action tells us which subcommand requested to skip
+	 * the commit.
+	 */
+	switch (opts->action) {
+	case REPLAY_REVERT:
+		/*
+		 * If .git/REVERT_HEAD exists then we are sure that we are in
+		 * the middle of a revert and we allow to skip the commit.
+		 */
+		if (!file_exists(git_path_revert_head(r))) {
+			/*
+			 * Check if the last instruction executed was related to
+			 * revert. If so, we are sure that a revert is in progress.
+			 *
+			 * NB: single commit revert is also counted in this
+			 * definition of "progress" (and was dealt with in the
+			 * previous check).
+			 */
+			if (action == REPLAY_REVERT) {
+				/*
+				 * Check if the user has moved the HEAD, i.e.,
+				 * already committed. In this case, we would like
+				 * to advise instead of skipping.
+				 */
+				if (!rollback_is_safe())
+					goto give_advice;
+				else
+					/* skip commit :) */
+					break;
+			}
+			return error(_("no revert in progress"));
+		}
+		break;
+	case REPLAY_PICK:
+		if (!file_exists(git_path_cherry_pick_head(r))) {
+			if (action == REPLAY_PICK) {
+				if (!rollback_is_safe())
+					goto give_advice;
+				else
+					break;
+			}
+			return error(_("no cherry-pick in progress"));
+		}
+		break;
+	default:
+		BUG("unexpected action in sequencer_skip");
+	}
+
+	if (skip_single_pick())
+		return error(_("failed to skip the commit"));
+	if (!is_directory(git_path_seq_dir()))
+		return 0;
+
+	return sequencer_continue(r, opts);
+
+give_advice:
+	advise(_("have you committed already?\n"
+		 "try \"git %s --continue\""),
+		 action == REPLAY_REVERT ? "revert" : "cherry-pick");
+	return error(_("there is nothing to skip"));
+}
+
 static int save_todo(struct todo_list *todo_list, struct replay_opts *opts)
 {
 	struct lock_file todo_lock = LOCK_INIT;
diff --git a/sequencer.h b/sequencer.h
index 0c494b83d4..731b9853eb 100644
--- a/sequencer.h
+++ b/sequencer.h
@@ -129,6 +129,7 @@ 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_skip(struct repository *repo, struct replay_opts *opts);
 int sequencer_remove_state(struct replay_opts *opts);
 
 #define TODO_LIST_KEEP_EMPTY (1U << 0)
diff --git a/t/t3510-cherry-pick-sequence.sh b/t/t3510-cherry-pick-sequence.sh
index 941d5026da..dc0ac8343c 100755
--- a/t/t3510-cherry-pick-sequence.sh
+++ b/t/t3510-cherry-pick-sequence.sh
@@ -93,6 +93,108 @@ test_expect_success 'cherry-pick cleans up sequencer state upon success' '
 	test_path_is_missing .git/sequencer
 '
 
+test_expect_success 'cherry-pick --skip requires cherry-pick in progress' '
+	pristine_detach initial &&
+	test_must_fail git cherry-pick --skip
+'
+
+test_expect_success 'revert --skip requires revert in progress' '
+	pristine_detach initial &&
+	test_must_fail git revert --skip
+'
+
+test_expect_success 'cherry-pick --skip to skip commit' '
+	pristine_detach initial &&
+	test_must_fail git cherry-pick anotherpick &&
+	test_must_fail git revert --skip &&
+	git cherry-pick --skip &&
+	test_cmp_rev initial HEAD &&
+	test_path_is_missing .git/CHERRY_PICK_HEAD
+'
+
+test_expect_success 'revert --skip to skip commit' '
+	pristine_detach anotherpick &&
+	test_must_fail git revert anotherpick~1 &&
+	test_must_fail git cherry-pick --skip &&
+	git revert --skip &&
+	test_cmp_rev anotherpick HEAD
+'
+
+test_expect_success 'skip "empty" commit' '
+	pristine_detach picked &&
+	test_commit dummy foo d &&
+	test_must_fail git cherry-pick anotherpick &&
+	git cherry-pick --skip &&
+	test_cmp_rev dummy HEAD
+'
+
+test_expect_success 'skip a commit and check if rest of sequence is correct' '
+	pristine_detach initial &&
+	echo e >expect &&
+	cat >expect.log <<-EOF &&
+	OBJID
+	:100644 100644 OBJID OBJID M	foo
+	OBJID
+	:100644 100644 OBJID OBJID M	foo
+	OBJID
+	:100644 100644 OBJID OBJID M	unrelated
+	OBJID
+	:000000 100644 OBJID OBJID A	foo
+	:000000 100644 OBJID OBJID A	unrelated
+	EOF
+	test_must_fail git cherry-pick base..yetanotherpick &&
+	test_must_fail git cherry-pick --skip &&
+	echo d >foo &&
+	git add foo &&
+	git cherry-pick --continue &&
+	{
+		git rev-list HEAD |
+		git diff-tree --root --stdin |
+		sed "s/$OID_REGEX/OBJID/g"
+	} >actual.log &&
+	test_cmp expect foo &&
+	test_cmp expect.log actual.log
+'
+
+test_expect_success 'check advice when we move HEAD by committing' '
+	pristine_detach initial &&
+	cat >expect <<-EOF &&
+	hint: have you committed already?
+	hint: try "git cherry-pick --continue"
+	error: there is nothing to skip
+	fatal: cherry-pick failed
+	EOF
+	test_must_fail git cherry-pick base..yetanotherpick &&
+	echo c >foo &&
+	git commit -a &&
+	test_path_is_missing .git/CHERRY_PICK_HEAD &&
+	test_must_fail git cherry-pick --skip 2>advice &&
+	test_i18ncmp expect advice
+'
+
+test_expect_success 'allow skipping commit but not abort for a new history' '
+	pristine_detach initial &&
+	cat >expect <<-EOF &&
+	error: cannot abort from a branch yet to be born
+	fatal: cherry-pick failed
+	EOF
+	git checkout --orphan new_disconnected &&
+	git reset --hard &&
+	test_must_fail git cherry-pick anotherpick &&
+	test_must_fail git cherry-pick --abort 2>advice &&
+	git cherry-pick --skip &&
+	test_i18ncmp expect advice
+'
+
+test_expect_success 'allow skipping stopped cherry-pick because of untracked file modifications' '
+	pristine_detach initial &&
+	git rm --cached unrelated &&
+	git commit -m "untrack unrelated" &&
+	test_must_fail git cherry-pick initial base &&
+	test_path_is_missing .git/CHERRY_PICK_HEAD &&
+	git cherry-pick --skip
+'
+
 test_expect_success '--quit does not complain when no cherry-pick is in progress' '
 	pristine_detach initial &&
 	git cherry-pick --quit
-- 
2.21.0


^ permalink raw reply	[flat|nested] 87+ messages in thread

* [GSoC][PATCH v4 4/4] cherry-pick/revert: advise using --skip
  2019-06-16  8:20 ` [GSoC][PATCH v4 0/4] [GSoC][PATCH 0/3] Teach cherry-pick/revert to skip commits Rohit Ashiwal
                     ` (2 preceding siblings ...)
  2019-06-16  8:20   ` [GSoC][PATCH v4 3/4] cherry-pick/revert: add --skip option Rohit Ashiwal
@ 2019-06-16  8:20   ` Rohit Ashiwal
  2019-06-17  8:39   ` [GSoC][PATCH v4 0/4] [GSoC][PATCH 0/3] Teach cherry-pick/revert to skip commits Thomas Gummerer
  4 siblings, 0 replies; 87+ messages in thread
From: Rohit Ashiwal @ 2019-06-16  8:20 UTC (permalink / raw)
  To: rohit.ashiwal265
  Cc: git, newren, t.gummerer, phillip.wood123, martin.agren, jrnieder,
	gitster

The previous commit introduced a --skip flag for cherry-pick and
revert. Update the advice messages, to tell users about this less
cumbersome way of skipping commits. Also add tests to ensure
everything is working fine.

Signed-off-by: Rohit Ashiwal <rohit.ashiwal265@gmail.com>
---
changes:
    - Use test_i18ncmp instead of tmp_cmp

 builtin/commit.c                | 13 ++++++++-----
 sequencer.c                     | 11 ++++++++---
 t/t3510-cherry-pick-sequence.sh | 20 ++++++++++++++++++++
 3 files changed, 36 insertions(+), 8 deletions(-)

diff --git a/builtin/commit.c b/builtin/commit.c
index 1c9e8e2228..1f47c51bdc 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -60,15 +60,18 @@ N_("The previous cherry-pick is now empty, possibly due to conflict resolution.\
 "\n");
 
 static const char empty_cherry_pick_advice_single[] =
-N_("Otherwise, please use 'git reset'\n");
+N_("Otherwise, please use 'git cherry-pick --skip'\n");
 
 static const char empty_cherry_pick_advice_multi[] =
-N_("If you wish to skip this commit, use:\n"
+N_("and then use:\n"
 "\n"
-"    git reset\n"
+"    git cherry-pick --continue\n"
 "\n"
-"Then \"git cherry-pick --continue\" will resume cherry-picking\n"
-"the remaining commits.\n");
+"to resume cherry-picking the remaining commits.\n"
+"If you wish to skip this commit, use:\n"
+"\n"
+"    git cherry-pick --skip\n"
+"\n");
 
 static const char *color_status_slots[] = {
 	[WT_STATUS_HEADER]	  = "header",
diff --git a/sequencer.c b/sequencer.c
index 95fa19a118..6e8afe8f22 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -2655,18 +2655,20 @@ static int create_seq_dir(struct repository *r)
 	enum replay_action action;
 	const char *in_progress_error = NULL;
 	const char *in_progress_advice = NULL;
+	unsigned int advise_skip = file_exists(git_path_revert_head(r)) ||
+				file_exists(git_path_cherry_pick_head(r));
 
 	if (!sequencer_get_last_command(r, &action)) {
 		switch (action) {
 		case REPLAY_REVERT:
 			in_progress_error = _("revert is already in progress");
 			in_progress_advice =
-			_("try \"git revert (--continue | --abort | --quit)\"");
+			_("try \"git revert (--continue | %s--abort | --quit)\"");
 			break;
 		case REPLAY_PICK:
 			in_progress_error = _("cherry-pick is already in progress");
 			in_progress_advice =
-			_("try \"git cherry-pick (--continue | --abort | --quit)\"");
+			_("try \"git cherry-pick (--continue | %s--abort | --quit)\"");
 			break;
 		default:
 			BUG(_("unexpected action in create_seq_dir"));
@@ -2674,7 +2676,10 @@ static int create_seq_dir(struct repository *r)
 	}
 	if (in_progress_error) {
 		error("%s", in_progress_error);
-		advise("%s", in_progress_advice);
+		if (advise_skip)
+			advise(in_progress_advice, "--skip | ");
+		else
+			advise(in_progress_advice, "");
 		return -1;
 	}
 	if (mkdir(git_path_seq_dir(), 0777) < 0)
diff --git a/t/t3510-cherry-pick-sequence.sh b/t/t3510-cherry-pick-sequence.sh
index dc0ac8343c..0e8adc95fc 100755
--- a/t/t3510-cherry-pick-sequence.sh
+++ b/t/t3510-cherry-pick-sequence.sh
@@ -172,6 +172,26 @@ test_expect_success 'check advice when we move HEAD by committing' '
 	test_i18ncmp expect advice
 '
 
+test_expect_success 'selectively advise --skip while launching another sequence' '
+	pristine_detach initial &&
+	cat >expect <<-EOF &&
+	error: cherry-pick is already in progress
+	hint: try "git cherry-pick (--continue | --skip | --abort | --quit)"
+	fatal: cherry-pick failed
+	EOF
+	test_must_fail git cherry-pick picked..yetanotherpick &&
+	test_must_fail git cherry-pick picked..yetanotherpick 2>advice &&
+	test_i18ncmp expect advice &&
+	cat >expect <<-EOF &&
+	error: cherry-pick is already in progress
+	hint: try "git cherry-pick (--continue | --abort | --quit)"
+	fatal: cherry-pick failed
+	EOF
+	git reset --merge &&
+	test_must_fail git cherry-pick picked..yetanotherpick 2>advice &&
+	test_i18ncmp expect advice
+'
+
 test_expect_success 'allow skipping commit but not abort for a new history' '
 	pristine_detach initial &&
 	cat >expect <<-EOF &&
-- 
2.21.0


^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [GSoC][PATCH v4 1/4] sequencer: add advice for revert
  2019-06-16  8:20   ` [GSoC][PATCH v4 1/4] sequencer: add advice for revert Rohit Ashiwal
@ 2019-06-17  5:51     ` Thomas Gummerer
  0 siblings, 0 replies; 87+ messages in thread
From: Thomas Gummerer @ 2019-06-17  5:51 UTC (permalink / raw)
  To: Rohit Ashiwal
  Cc: git, newren, phillip.wood123, martin.agren, jrnieder, gitster

On 06/16, Rohit Ashiwal wrote:
> In the case of merge conflicts, while performing a revert, we are
> currently advised to use `git cherry-pick --<sequencer-options>`
> of which --continue is incompatible for continuing the revert.
> Introduce a separate advice message for `git revert`. Also change
> the signature of `create_seq_dir` to handle which advice to display
> selectively.
> 
> Signed-off-by: Rohit Ashiwal <rohit.ashiwal265@gmail.com>
> ---
> changes:
>     - change BUG()'s message under create_seq_dir
> 
>  sequencer.c | 34 ++++++++++++++++++++++++++++------
>  1 file changed, 28 insertions(+), 6 deletions(-)
> 
> diff --git a/sequencer.c b/sequencer.c
> index f88a97fb10..d80e1c3fbb 100644
> --- a/sequencer.c
> +++ b/sequencer.c
> @@ -2650,15 +2650,37 @@ static int walk_revs_populate_todo(struct todo_list *todo_list,
>  	return 0;
>  }
>  
> -static int create_seq_dir(void)
> +static int create_seq_dir(struct repository *r)
>  {
> -	if (file_exists(git_path_seq_dir())) {
> -		error(_("a cherry-pick or revert is already in progress"));
> -		advise(_("try \"git cherry-pick (--continue | --quit | --abort)\""));
> +	enum replay_action action;
> +	const char *in_progress_error = NULL;
> +	const char *in_progress_advice = NULL;
> +
> +	if (!sequencer_get_last_command(r, &action)) {
> +		switch (action) {
> +		case REPLAY_REVERT:
> +			in_progress_error = _("revert is already in progress");
> +			in_progress_advice =
> +			_("try \"git revert (--continue | --abort | --quit)\"");
> +			break;
> +		case REPLAY_PICK:
> +			in_progress_error = _("cherry-pick is already in progress");
> +			in_progress_advice =
> +			_("try \"git cherry-pick (--continue | --abort | --quit)\"");
> +			break;
> +		default:
> +			BUG(_("unexpected action in create_seq_dir"));

As Phillip mentioned in the previous round, this doesn't need to be
translated.  I'd go one step further and say this should not be
translated.  Translating it just adds extra work for translators for a
message that the user will (hopefully) never see.

In fact if we look through the rest of the codebase, BUG() messages
are never translated anywhere, and neither is the one in 3/4.

> +		}
> +	}
> +	if (in_progress_error) {
> +		error("%s", in_progress_error);
> +		advise("%s", in_progress_advice);
>  		return -1;
> -	} else if (mkdir(git_path_seq_dir(), 0777) < 0)
> +	}
> +	if (mkdir(git_path_seq_dir(), 0777) < 0)
>  		return error_errno(_("could not create sequencer directory '%s'"),
>  				   git_path_seq_dir());
> +
>  	return 0;
>  }
>  
> @@ -4237,7 +4259,7 @@ int sequencer_pick_revisions(struct repository *r,
>  	 */
>  
>  	if (walk_revs_populate_todo(&todo_list, opts) ||
> -			create_seq_dir() < 0)
> +			create_seq_dir(r) < 0)
>  		return -1;
>  	if (get_oid("HEAD", &oid) && (opts->action == REPLAY_REVERT))
>  		return error(_("can't revert as initial commit"));
> -- 
> 2.21.0
> 

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [GSoC][PATCH v4 3/4] cherry-pick/revert: add --skip option
  2019-06-16  8:20   ` [GSoC][PATCH v4 3/4] cherry-pick/revert: add --skip option Rohit Ashiwal
@ 2019-06-17  8:30     ` Thomas Gummerer
  0 siblings, 0 replies; 87+ messages in thread
From: Thomas Gummerer @ 2019-06-17  8:30 UTC (permalink / raw)
  To: Rohit Ashiwal
  Cc: git, newren, phillip.wood123, martin.agren, jrnieder, gitster

On 06/16, Rohit Ashiwal wrote:
> git am or rebase have a --skip flag to skip the current commit if the
> user wishes to do so. During a cherry-pick or revert a user could
> likewise skip a commit, but needs to use 'git reset' (or in the case
> of conflicts 'git reset --merge'), followed by 'git (cherry-pick |
> revert) --continue' to skip the commit. This is more annoying and
> sometimes confusing on the users' part. Add a `--skip` option to make
> skipping commits easier for the user and to make the commands more
> consistent.
> 
> In the next commit, we will change the advice messages and some tests
> hence finishing the process of teaching revert and cherry-pick
> "how to skip commits".

Changing the advice messages and some tests sounds to me like we're
not changing the tests here even though we should.  I know that is not
the case, and in fact we're only adding another test for something
that we're introducing in the next patch.

I think this whole paragraph could be dropped, but at least the "and
some tests" part should be, as it's slightly misleading imo.

> Signed-off-by: Rohit Ashiwal <rohit.ashiwal265@gmail.com>
> ---
> changes:
>     - Introduce '('s around documentation/help
>     - Introduce a wrapper function skip_single_pick to reset_merge
>     - Add comments to sequencer_skip
>     - Change tests to use test_i18ncmp instead of test_cmp to not fail under
>       GETTEXT_POISON
> 
>  Documentation/git-cherry-pick.txt |   4 +-
>  Documentation/git-revert.txt      |   4 +-
>  Documentation/sequencer.txt       |   4 ++
>  builtin/revert.c                  |   5 ++
>  sequencer.c                       |  94 +++++++++++++++++++++++++--
>  sequencer.h                       |   1 +
>  t/t3510-cherry-pick-sequence.sh   | 102 ++++++++++++++++++++++++++++++
>  7 files changed, 202 insertions(+), 12 deletions(-)
> 
> diff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt
> index 754b16ce0c..83ce51aedf 100644
> --- a/Documentation/git-cherry-pick.txt
> +++ b/Documentation/git-cherry-pick.txt
> @@ -10,9 +10,7 @@ SYNOPSIS
>  [verse]
>  'git cherry-pick' [--edit] [-n] [-m parent-number] [-s] [-x] [--ff]
>  		  [-S[<keyid>]] <commit>...
> -'git cherry-pick' --continue
> -'git cherry-pick' --quit
> -'git cherry-pick' --abort
> +'git cherry-pick' (--continue | --skip | --abort | --quit)
>  
>  DESCRIPTION
>  -----------
> diff --git a/Documentation/git-revert.txt b/Documentation/git-revert.txt
> index 0c82ca5bc0..665e065ee3 100644
> --- a/Documentation/git-revert.txt
> +++ b/Documentation/git-revert.txt
> @@ -9,9 +9,7 @@ SYNOPSIS
>  --------
>  [verse]
>  'git revert' [--[no-]edit] [-n] [-m parent-number] [-s] [-S[<keyid>]] <commit>...
> -'git revert' --continue
> -'git revert' --quit
> -'git revert' --abort
> +'git revert' (--continue | --skip | --abort | --quit)
>  
>  DESCRIPTION
>  -----------
> diff --git a/Documentation/sequencer.txt b/Documentation/sequencer.txt
> index 5a57c4a407..3bceb56474 100644
> --- a/Documentation/sequencer.txt
> +++ b/Documentation/sequencer.txt
> @@ -3,6 +3,10 @@
>  	`.git/sequencer`.  Can be used to continue after resolving
>  	conflicts in a failed cherry-pick or revert.
>  
> +--skip::
> +	Skip the current commit and continue with the rest of the
> +	sequence.
> +
>  --quit::
>  	Forget about the current operation in progress.  Can be used
>  	to clear the sequencer state after a failed cherry-pick or
> diff --git a/builtin/revert.c b/builtin/revert.c
> index d4dcedbdc6..5dc5891ea2 100644
> --- a/builtin/revert.c
> +++ b/builtin/revert.c
> @@ -102,6 +102,7 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)
>  		OPT_CMDMODE(0, "quit", &cmd, N_("end revert or cherry-pick sequence"), 'q'),
>  		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_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")),
> @@ -151,6 +152,8 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)
>  			this_operation = "--quit";
>  		else if (cmd == 'c')
>  			this_operation = "--continue";
> +		else if (cmd == 's')
> +			this_operation = "--skip";
>  		else {
>  			assert(cmd == 'a');
>  			this_operation = "--abort";
> @@ -210,6 +213,8 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)
>  		return sequencer_continue(the_repository, opts);
>  	if (cmd == 'a')
>  		return sequencer_rollback(the_repository, opts);
> +	if (cmd == 's')
> +		return sequencer_skip(the_repository, opts);
>  	return sequencer_pick_revisions(the_repository, opts);
>  }
>  
> diff --git a/sequencer.c b/sequencer.c
> index 408643f88a..95fa19a118 100644
> --- a/sequencer.c
> +++ b/sequencer.c
> @@ -2733,13 +2733,18 @@ static int rollback_is_safe(void)
>  
>  static int reset_merge(const struct object_id *oid)
>  {
> -	const char *argv[4];	/* reset --merge <arg> + NULL */
> +	int ret;
> +	struct argv_array argv = ARGV_ARRAY_INIT;
>  
> -	argv[0] = "reset";
> -	argv[1] = "--merge";
> -	argv[2] = oid_to_hex(oid);
> -	argv[3] = NULL;
> -	return run_command_v_opt(argv, RUN_GIT_CMD);
> +	argv_array_pushl(&argv, "reset", "--merge", NULL);
> +
> +	if (!is_null_oid(oid))
> +		argv_array_push(&argv, oid_to_hex(oid));
> +
> +	ret = run_command_v_opt(argv.argv, RUN_GIT_CMD);
> +	argv_array_clear(&argv);
> +
> +	return ret;

Changing this function to use argv_array could potentially be a
separate commit, which would make the changes in this commit a bit
simpler.

>  }
>  
>  static int rollback_single_pick(struct repository *r)
> @@ -2756,6 +2761,15 @@ static int rollback_single_pick(struct repository *r)
>  	return reset_merge(&head_oid);
>  }
>  
> +static int skip_single_pick(void)
> +{
> +	struct object_id head;
> +
> +	if (read_ref_full("HEAD", 0, &head, NULL))
> +		return error(_("cannot resolve HEAD"));
> +	return reset_merge(&head);
> +}
> +
>  int sequencer_rollback(struct repository *r, struct replay_opts *opts)
>  {
>  	FILE *f;
> @@ -2805,6 +2819,74 @@ int sequencer_rollback(struct repository *r, struct replay_opts *opts)
>  	return -1;
>  }
>  
> +int sequencer_skip(struct repository *r, struct replay_opts *opts)
> +{
> +	enum replay_action action = -1;
> +	sequencer_get_last_command(r, &action);
> +
> +	/*
> +	 * opts->action tells us which subcommand requested to skip
> +	 * the commit.
> +	 */
> +	switch (opts->action) {
> +	case REPLAY_REVERT:
> +		/*
> +		 * If .git/REVERT_HEAD exists then we are sure that we are in
> +		 * the middle of a revert and we allow to skip the commit.
> +		 */
> +		if (!file_exists(git_path_revert_head(r))) {
> +			/*
> +			 * Check if the last instruction executed was related to
> +			 * revert. If so, we are sure that a revert is in progress.
> +			 *
> +			 * NB: single commit revert is also counted in this
> +			 * definition of "progress" (and was dealt with in the
> +			 * previous check).
> +			 */
> +			if (action == REPLAY_REVERT) {
> +				/*
> +				 * Check if the user has moved the HEAD, i.e.,
> +				 * already committed. In this case, we would like
> +				 * to advise instead of skipping.
> +				 */
> +				if (!rollback_is_safe())
> +					goto give_advice;
> +				else
> +					/* skip commit :) */
> +					break;
> +			}
> +			return error(_("no revert in progress"));
> +		}
> +		break;
> +	case REPLAY_PICK:
> +		if (!file_exists(git_path_cherry_pick_head(r))) {
> +			if (action == REPLAY_PICK) {
> +				if (!rollback_is_safe())
> +					goto give_advice;
> +				else
> +					break;
> +			}
> +			return error(_("no cherry-pick in progress"));
> +		}
> +		break;
> +	default:
> +		BUG("unexpected action in sequencer_skip");
> +	}

I know it's a bit late, and this switch/case has existed for a few
iterations now.  However, especially seeing it with all the comments
now, I was wondering if it could be simplified a bit, especially
because it gets a bit unsymmetric between the revert and the
cherry-pick case.  This is what I came up with:

	if (opts->action != REPLAY_REVERT && opts->action != REPLAY_PICK)
		BUG("unexpected action in sequencer_skip");
	/*
	 * Check whether the subcommand requested to skip the commit
	 * is actually in progress, and that it's safe to skip the
	 * commit.
	 *
	 * opts->action tells us which subcommand requested to skip
	 * the commit.  If the corresponding .git/<ACTION>_HEAD
	 * exists, we know that the action is in progress, and we can
	 * skip the commit.
	 *
	 * Otherwise we check that the last instruction was related to
	 * the particular subcommand we're trying to execute, and
	 * error out if that's not the case.  
	 *
	 * Finally we check that the rollback is safe. It isn't safe
	 * if the user has already committed.  We only need to check
	 * that when .git/<ACTION>_HEAD doesn't exist, because it gets
	 * removed when the user commits, so if it still exists we're
	 * sure the user can't have committed before.
	 */
	sequencer_get_last_command(r, &action);
	if (opts->action == REPLAY_REVERT && !file_exists(git_path_revert_head(r))) {
		if (action != REPLAY_REVERT)
			return error(_("no revert in progress"));
		if (!rollback_is_safe())
			goto give_advice;
	} else if (opts->action == REPLAY_PICK && !file_exists(git_path_cherry_pick_head(r))) {
		if (action != REPLAY_PICK)
			return error(_("no cherry-pick in progress"));
		if (!rollback_is_safe())
			goto give_advice;
	}

I think we could similarly simplify the switch/case a bit if we want
to stick with that, demonstrated only for the cherry-pick case here
(though this is not even compile tested):

	case REPLAY_PICK:
		if (!file_exists(git_path_cherry_pick_head(r))) {
			if (action != REPLAY_PICK)
				return error(_("no cherry-pick in progress"));
			if (!rollback_is_safe())
				goto give_advice;
		}
		break;

> +
> +	if (skip_single_pick())
> +		return error(_("failed to skip the commit"));
> +	if (!is_directory(git_path_seq_dir()))
> +		return 0;
> +
> +	return sequencer_continue(r, opts);
> +
> +give_advice:
> +	advise(_("have you committed already?\n"
> +		 "try \"git %s --continue\""),
> +		 action == REPLAY_REVERT ? "revert" : "cherry-pick");
> +	return error(_("there is nothing to skip"));
> +}
> +
>  static int save_todo(struct todo_list *todo_list, struct replay_opts *opts)
>  {
>  	struct lock_file todo_lock = LOCK_INIT;
> diff --git a/sequencer.h b/sequencer.h
> index 0c494b83d4..731b9853eb 100644
> --- a/sequencer.h
> +++ b/sequencer.h
> @@ -129,6 +129,7 @@ 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_skip(struct repository *repo, struct replay_opts *opts);
>  int sequencer_remove_state(struct replay_opts *opts);
>  
>  #define TODO_LIST_KEEP_EMPTY (1U << 0)
> diff --git a/t/t3510-cherry-pick-sequence.sh b/t/t3510-cherry-pick-sequence.sh
> index 941d5026da..dc0ac8343c 100755
> --- a/t/t3510-cherry-pick-sequence.sh
> +++ b/t/t3510-cherry-pick-sequence.sh
> @@ -93,6 +93,108 @@ test_expect_success 'cherry-pick cleans up sequencer state upon success' '
>  	test_path_is_missing .git/sequencer
>  '
>  
> +test_expect_success 'cherry-pick --skip requires cherry-pick in progress' '
> +	pristine_detach initial &&
> +	test_must_fail git cherry-pick --skip
> +'
> +
> +test_expect_success 'revert --skip requires revert in progress' '
> +	pristine_detach initial &&
> +	test_must_fail git revert --skip
> +'
> +
> +test_expect_success 'cherry-pick --skip to skip commit' '
> +	pristine_detach initial &&
> +	test_must_fail git cherry-pick anotherpick &&
> +	test_must_fail git revert --skip &&
> +	git cherry-pick --skip &&
> +	test_cmp_rev initial HEAD &&
> +	test_path_is_missing .git/CHERRY_PICK_HEAD
> +'
> +
> +test_expect_success 'revert --skip to skip commit' '
> +	pristine_detach anotherpick &&
> +	test_must_fail git revert anotherpick~1 &&
> +	test_must_fail git cherry-pick --skip &&
> +	git revert --skip &&
> +	test_cmp_rev anotherpick HEAD
> +'
> +
> +test_expect_success 'skip "empty" commit' '
> +	pristine_detach picked &&
> +	test_commit dummy foo d &&
> +	test_must_fail git cherry-pick anotherpick &&
> +	git cherry-pick --skip &&
> +	test_cmp_rev dummy HEAD
> +'
> +
> +test_expect_success 'skip a commit and check if rest of sequence is correct' '
> +	pristine_detach initial &&
> +	echo e >expect &&
> +	cat >expect.log <<-EOF &&
> +	OBJID
> +	:100644 100644 OBJID OBJID M	foo
> +	OBJID
> +	:100644 100644 OBJID OBJID M	foo
> +	OBJID
> +	:100644 100644 OBJID OBJID M	unrelated
> +	OBJID
> +	:000000 100644 OBJID OBJID A	foo
> +	:000000 100644 OBJID OBJID A	unrelated
> +	EOF
> +	test_must_fail git cherry-pick base..yetanotherpick &&
> +	test_must_fail git cherry-pick --skip &&
> +	echo d >foo &&
> +	git add foo &&
> +	git cherry-pick --continue &&
> +	{
> +		git rev-list HEAD |
> +		git diff-tree --root --stdin |
> +		sed "s/$OID_REGEX/OBJID/g"
> +	} >actual.log &&
> +	test_cmp expect foo &&
> +	test_cmp expect.log actual.log
> +'
> +
> +test_expect_success 'check advice when we move HEAD by committing' '
> +	pristine_detach initial &&
> +	cat >expect <<-EOF &&
> +	hint: have you committed already?
> +	hint: try "git cherry-pick --continue"
> +	error: there is nothing to skip
> +	fatal: cherry-pick failed
> +	EOF
> +	test_must_fail git cherry-pick base..yetanotherpick &&
> +	echo c >foo &&
> +	git commit -a &&
> +	test_path_is_missing .git/CHERRY_PICK_HEAD &&
> +	test_must_fail git cherry-pick --skip 2>advice &&
> +	test_i18ncmp expect advice
> +'
> +
> +test_expect_success 'allow skipping commit but not abort for a new history' '
> +	pristine_detach initial &&
> +	cat >expect <<-EOF &&
> +	error: cannot abort from a branch yet to be born
> +	fatal: cherry-pick failed
> +	EOF
> +	git checkout --orphan new_disconnected &&
> +	git reset --hard &&
> +	test_must_fail git cherry-pick anotherpick &&
> +	test_must_fail git cherry-pick --abort 2>advice &&
> +	git cherry-pick --skip &&
> +	test_i18ncmp expect advice
> +'
> +
> +test_expect_success 'allow skipping stopped cherry-pick because of untracked file modifications' '
> +	pristine_detach initial &&
> +	git rm --cached unrelated &&
> +	git commit -m "untrack unrelated" &&
> +	test_must_fail git cherry-pick initial base &&
> +	test_path_is_missing .git/CHERRY_PICK_HEAD &&
> +	git cherry-pick --skip
> +'
> +
>  test_expect_success '--quit does not complain when no cherry-pick is in progress' '
>  	pristine_detach initial &&
>  	git cherry-pick --quit
> -- 
> 2.21.0
> 

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [GSoC][PATCH v4 0/4] [GSoC][PATCH 0/3] Teach cherry-pick/revert to skip commits
  2019-06-16  8:20 ` [GSoC][PATCH v4 0/4] [GSoC][PATCH 0/3] Teach cherry-pick/revert to skip commits Rohit Ashiwal
                     ` (3 preceding siblings ...)
  2019-06-16  8:20   ` [GSoC][PATCH v4 4/4] cherry-pick/revert: advise using --skip Rohit Ashiwal
@ 2019-06-17  8:39   ` Thomas Gummerer
  4 siblings, 0 replies; 87+ messages in thread
From: Thomas Gummerer @ 2019-06-17  8:39 UTC (permalink / raw)
  To: Rohit Ashiwal
  Cc: git, newren, phillip.wood123, martin.agren, jrnieder, gitster

On 06/16, Rohit Ashiwal wrote:
> Yet another iteration of my patch. We have changed the series a little bit. We
> now have a commit that rename `reset_for_rollback` to `reset_merge`. A lot of
> nit-picks were handled in this revision.

Thanks for your work!  I allowed myself to nitpick a bit more at this
stage :)

One other thing I wanted to point out here is range-diff, which can be
helpful to include for the benefit of reviewers that saw this series
before.  See 'man git-range-diff' or the --range-diff flag in 'git
format-patch' for more info on how it works.  It helps seeing at a
glance what changed between versions of a series.

For the benefit of other reviewers that might find it helpful, here's
one I generated between v3 and v4 of the series::

1:  8f29142755 ! 1:  99279e617c sequencer: add advice for revert
    @@ -25,8 +25,8 @@
     -		error(_("a cherry-pick or revert is already in progress"));
     -		advise(_("try \"git cherry-pick (--continue | --quit | --abort)\""));
     +	enum replay_action action;
    -+	const char *in_progress_advice;
     +	const char *in_progress_error = NULL;
    ++	const char *in_progress_advice = NULL;
     +
     +	if (!sequencer_get_last_command(r, &action)) {
     +		switch (action) {
    @@ -41,7 +41,7 @@
     +			_("try \"git cherry-pick (--continue | --abort | --quit)\"");
     +			break;
     +		default:
    -+			BUG(_("the control must not reach here"));
    ++			BUG(_("unexpected action in create_seq_dir"));
     +		}
     +	}
     +	if (in_progress_error) {
-:  ---------- > 2:  c64aabf2d2 sequencer: rename reset_for_rollback to reset_merge
2:  3bc8678df4 ! 3:  8b483815ca cherry-pick/revert: add --skip option
    @@ -27,7 +27,7 @@
     -'git cherry-pick' --continue
     -'git cherry-pick' --quit
     -'git cherry-pick' --abort
    -+'git cherry-pick' --continue | --skip | --abort | --quit
    ++'git cherry-pick' (--continue | --skip | --abort | --quit)
      
      DESCRIPTION
      -----------
    @@ -42,7 +42,7 @@
     -'git revert' --continue
     -'git revert' --quit
     -'git revert' --abort
    -+'git revert' --continue | --skip | --abort | --quit
    ++'git revert' (--continue | --skip | --abort | --quit)
      
      DESCRIPTION
      -----------
    @@ -97,10 +97,11 @@
      +++ b/sequencer.c
     @@
      
    - static int reset_for_rollback(const struct object_id *oid)
    + static int reset_merge(const struct object_id *oid)
      {
     -	const char *argv[4];	/* reset --merge <arg> + NULL */
    -+	struct argv_array argv = ARGV_ARRAY_INIT;	/* reset --merge <arg> + NULL */
    ++	int ret;
    ++	struct argv_array argv = ARGV_ARRAY_INIT;
      
     -	argv[0] = "reset";
     -	argv[1] = "--merge";
    @@ -112,34 +113,29 @@
     +	if (!is_null_oid(oid))
     +		argv_array_push(&argv, oid_to_hex(oid));
     +
    -+	return run_command_v_opt(argv.argv, RUN_GIT_CMD);
    ++	ret = run_command_v_opt(argv.argv, RUN_GIT_CMD);
    ++	argv_array_clear(&argv);
    ++
    ++	return ret;
      }
      
    --static int rollback_single_pick(struct repository *r)
    -+static int rollback_single_pick(struct repository *r, unsigned int is_skip)
    - {
    - 	struct object_id head_oid;
    - 
    - 	if (!file_exists(git_path_cherry_pick_head(r)) &&
    --	    !file_exists(git_path_revert_head(r)))
    -+	    !file_exists(git_path_revert_head(r)) && !is_skip)
    - 		return error(_("no cherry-pick or revert in progress"));
    - 	if (read_ref_full("HEAD", 0, &head_oid, NULL))
    - 		return error(_("cannot resolve HEAD"));
    --	if (is_null_oid(&head_oid))
    -+	if (is_null_oid(&head_oid) && !is_skip)
    - 		return error(_("cannot abort from a branch yet to be born"));
    - 	return reset_for_rollback(&head_oid);
    - }
    + static int rollback_single_pick(struct repository *r)
     @@
    - 		 * If CHERRY_PICK_HEAD or REVERT_HEAD indicates
    - 		 * a single-cherry-pick in progress, abort that.
    - 		 */
    --		return rollback_single_pick(r);
    -+		return rollback_single_pick(r, 0);
    - 	}
    - 	if (!f)
    - 		return error_errno(_("cannot open '%s'"), git_path_head_file());
    + 	return reset_merge(&head_oid);
    + }
    + 
    ++static int skip_single_pick(void)
    ++{
    ++	struct object_id head;
    ++
    ++	if (read_ref_full("HEAD", 0, &head, NULL))
    ++		return error(_("cannot resolve HEAD"));
    ++	return reset_merge(&head);
    ++}
    ++
    + int sequencer_rollback(struct repository *r, struct replay_opts *opts)
    + {
    + 	FILE *f;
     @@
      	return -1;
      }
    @@ -149,13 +145,35 @@
     +	enum replay_action action = -1;
     +	sequencer_get_last_command(r, &action);
     +
    ++	/*
    ++	 * opts->action tells us which subcommand requested to skip
    ++	 * the commit.
    ++	 */
     +	switch (opts->action) {
     +	case REPLAY_REVERT:
    ++		/*
    ++		 * If .git/REVERT_HEAD exists then we are sure that we are in
    ++		 * the middle of a revert and we allow to skip the commit.
    ++		 */
     +		if (!file_exists(git_path_revert_head(r))) {
    ++			/*
    ++			 * Check if the last instruction executed was related to
    ++			 * revert. If so, we are sure that a revert is in progress.
    ++			 *
    ++			 * NB: single commit revert is also counted in this
    ++			 * definition of "progress" (and was dealt with in the
    ++			 * previous check).
    ++			 */
     +			if (action == REPLAY_REVERT) {
    ++				/*
    ++				 * Check if the user has moved the HEAD, i.e.,
    ++				 * already committed. In this case, we would like
    ++				 * to advise instead of skipping.
    ++				 */
     +				if (!rollback_is_safe())
     +					goto give_advice;
     +				else
    ++					/* skip commit :) */
     +					break;
     +			}
     +			return error(_("no revert in progress"));
    @@ -173,10 +191,10 @@
     +		}
     +		break;
     +	default:
    -+		BUG("the control must not reach here");
    ++		BUG("unexpected action in sequencer_skip");
     +	}
     +
    -+	if (rollback_single_pick(r, 1))
    ++	if (skip_single_pick())
     +		return error(_("failed to skip the commit"));
     +	if (!is_directory(git_path_seq_dir()))
     +		return 0;
    @@ -289,7 +307,7 @@
     +	git commit -a &&
     +	test_path_is_missing .git/CHERRY_PICK_HEAD &&
     +	test_must_fail git cherry-pick --skip 2>advice &&
    -+	test_cmp expect advice
    ++	test_i18ncmp expect advice
     +'
     +
     +test_expect_success 'allow skipping commit but not abort for a new history' '
    @@ -303,7 +321,7 @@
     +	test_must_fail git cherry-pick anotherpick &&
     +	test_must_fail git cherry-pick --abort 2>advice &&
     +	git cherry-pick --skip &&
    -+	test_cmp expect advice
    ++	test_i18ncmp expect advice
     +'
     +
     +test_expect_success 'allow skipping stopped cherry-pick because of untracked file modifications' '
3:  a3cd17540b ! 4:  98618e08f4 cherry-pick/revert: advise using --skip
    @@ -42,8 +42,8 @@
      +++ b/sequencer.c
     @@
      	enum replay_action action;
    - 	const char *in_progress_advice;
      	const char *in_progress_error = NULL;
    + 	const char *in_progress_advice = NULL;
     +	unsigned int advise_skip = file_exists(git_path_revert_head(r)) ||
     +				file_exists(git_path_cherry_pick_head(r));
      
    @@ -62,7 +62,7 @@
     +			_("try \"git cherry-pick (--continue | %s--abort | --quit)\"");
      			break;
      		default:
    - 			BUG(_("the control must not reach here"));
    + 			BUG(_("unexpected action in create_seq_dir"));
     @@
      	}
      	if (in_progress_error) {
    @@ -80,7 +80,7 @@
      --- a/t/t3510-cherry-pick-sequence.sh
      +++ b/t/t3510-cherry-pick-sequence.sh
     @@
    - 	test_cmp expect advice
    + 	test_i18ncmp expect advice
      '
      
     +test_expect_success 'selectively advise --skip while launching another sequence' '
    @@ -92,7 +92,7 @@
     +	EOF
     +	test_must_fail git cherry-pick picked..yetanotherpick &&
     +	test_must_fail git cherry-pick picked..yetanotherpick 2>advice &&
    -+	test_cmp expect advice &&
    ++	test_i18ncmp expect advice &&
     +	cat >expect <<-EOF &&
     +	error: cherry-pick is already in progress
     +	hint: try "git cherry-pick (--continue | --abort | --quit)"
    @@ -100,7 +100,7 @@
     +	EOF
     +	git reset --merge &&
     +	test_must_fail git cherry-pick picked..yetanotherpick 2>advice &&
    -+	test_cmp expect advice
    ++	test_i18ncmp expect advice
     +'
     +
      test_expect_success 'allow skipping commit but not abort for a new history' '

> Rohit Ashiwal (4):
>   sequencer: add advice for revert
>   sequencer: rename reset_for_rollback to reset_merge
>   cherry-pick/revert: add --skip option
>   cherry-pick/revert: advise using --skip
> 
>  Documentation/git-cherry-pick.txt |   4 +-
>  Documentation/git-revert.txt      |   4 +-
>  Documentation/sequencer.txt       |   4 +
>  builtin/commit.c                  |  13 +--
>  builtin/revert.c                  |   5 ++
>  sequencer.c                       | 139 ++++++++++++++++++++++++++----
>  sequencer.h                       |   1 +
>  t/t3510-cherry-pick-sequence.sh   | 122 ++++++++++++++++++++++++++
>  8 files changed, 266 insertions(+), 26 deletions(-)
> 
> -- 
> 2.21.0
> 

^ permalink raw reply	[flat|nested] 87+ messages in thread

* [GSoC][PATCH v5 0/5] Teach cherry-pick/revert to skip commits
  2019-06-08 19:19 [GSoC][PATCH 0/3] Teach cherry-pick/revert to skip commits Rohit Ashiwal
                   ` (6 preceding siblings ...)
  2019-06-16  8:20 ` [GSoC][PATCH v4 0/4] [GSoC][PATCH 0/3] Teach cherry-pick/revert to skip commits Rohit Ashiwal
@ 2019-06-18 17:06 ` " Rohit Ashiwal
  2019-06-18 17:06   ` [GSoC][PATCH v5 1/5] sequencer: add advice for revert Rohit Ashiwal
                     ` (4 more replies)
  2019-06-21  9:17 ` [GSoC][PATCH v6 0/5] Teach cherry-pick/revert to skip commits Rohit Ashiwal
  2019-06-23 20:03 ` [GSoC][PATCH v7 0/6] " Rohit Ashiwal
  9 siblings, 5 replies; 87+ messages in thread
From: Rohit Ashiwal @ 2019-06-18 17:06 UTC (permalink / raw)
  To: rohit.ashiwal265
  Cc: git, newren, t.gummerer, phillip.wood123, martin.agren, jrnieder,
	gitster

Here is another round of my patch, hopefully I have addressed all the changes.
  - I have introduced a separate commit which changes `reset_merge` to use
    `argv_array` instead of a manual `char *argv`. This will avoid specifying
    array size and index and make code easier to read and extend
  - Removed _() from BUG() messages
  - Rearrange comments under `sequencer_skip`. I have not changed switch-case to
    if-else since the former looked better to me

Thanks

Rohit Ashiwal (5):
  sequencer: add advice for revert
  sequencer: rename reset_for_rollback to reset_merge
  sequencer: use argv_array in reset_merge
  cherry-pick/revert: add --skip option
  cherry-pick/revert: advise using --skip

 Documentation/git-cherry-pick.txt |   4 +-
 Documentation/git-revert.txt      |   4 +-
 Documentation/sequencer.txt       |   4 +
 builtin/commit.c                  |  13 +--
 builtin/revert.c                  |   5 ++
 sequencer.c                       | 131 ++++++++++++++++++++++++++----
 sequencer.h                       |   1 +
 t/t3510-cherry-pick-sequence.sh   | 122 ++++++++++++++++++++++++++++
 8 files changed, 258 insertions(+), 26 deletions(-)

Range-diff:
1:  59fa13c4d8 ! 1:  67c212090d sequencer: add advice for revert
    @@ -41,7 +41,7 @@
     +			_("try \"git cherry-pick (--continue | --abort | --quit)\"");
     +			break;
     +		default:
    -+			BUG(_("unexpected action in create_seq_dir"));
    ++			BUG("unexpected action in create_seq_dir");
     +		}
     +	}
     +	if (in_progress_error) {
2:  dea4582591 = 2:  300d6f64f0 sequencer: rename reset_for_rollback to reset_merge
-:  ---------- > 3:  edc35f6a4c sequencer: use argv_array in reset_merge
3:  29686d828f ! 4:  825486c22d cherry-pick/revert: add --skip option
    @@ -11,9 +11,8 @@
         skipping commits easier for the user and to make the commands more
         consistent.
     
    -    In the next commit, we will change the advice messages and some tests
    -    hence finishing the process of teaching revert and cherry-pick
    -    "how to skip commits".
    +    In the next commit, we will change the advice messages hence finishing
    +    the process of teaching revert and cherry-pick "how to skip commits".
     
         Signed-off-by: Rohit Ashiwal <rohit.ashiwal265@gmail.com>
     
    @@ -96,31 +95,6 @@
      --- a/sequencer.c
      +++ b/sequencer.c
     @@
    - 
    - static int reset_merge(const struct object_id *oid)
    - {
    --	const char *argv[4];	/* reset --merge <arg> + NULL */
    -+	int ret;
    -+	struct argv_array argv = ARGV_ARRAY_INIT;
    - 
    --	argv[0] = "reset";
    --	argv[1] = "--merge";
    --	argv[2] = oid_to_hex(oid);
    --	argv[3] = NULL;
    --	return run_command_v_opt(argv, RUN_GIT_CMD);
    -+	argv_array_pushl(&argv, "reset", "--merge", NULL);
    -+
    -+	if (!is_null_oid(oid))
    -+		argv_array_push(&argv, oid_to_hex(oid));
    -+
    -+	ret = run_command_v_opt(argv.argv, RUN_GIT_CMD);
    -+	argv_array_clear(&argv);
    -+
    -+	return ret;
    - }
    - 
    - static int rollback_single_pick(struct repository *r)
    -@@
      	return reset_merge(&head_oid);
      }
      
    @@ -146,48 +120,40 @@
     +	sequencer_get_last_command(r, &action);
     +
     +	/*
    -+	 * opts->action tells us which subcommand requested to skip
    -+	 * the commit.
    ++	 * Check whether the subcommand requested to skip the commit is actually
    ++	 * in progress and that it's safe to skip the commit.
    ++	 *
    ++	 * opts->action tells us which subcommand requested to skip the commit.
    ++	 * If the corresponding .git/<ACTION>_HEAD exists, we know that the
    ++	 * action is in progress and we can skip the commit.
    ++	 *
    ++	 * Otherwise we check that the last instruction was related to the
    ++	 * particular subcommand we're trying to execute and barf if that's not
    ++	 * the case.
    ++	 *
    ++	 * Finally we check that the rollback is "safe", i.e., has the HEAD
    ++	 * moved? In this case, it doesn't make sense to "reset the merge" and
    ++	 * "skip the commit" as the user already handled this by committing. But
    ++	 * we'd not want to barf here, instead give advice on how to proceed. We
    ++	 * only need to check that when .git/<ACTION>_HEAD doesn't exist because
    ++	 * it gets removed when the user commits, so if it still exists we're
    ++	 * sure the user can't have committed before.
     +	 */
     +	switch (opts->action) {
     +	case REPLAY_REVERT:
    -+		/*
    -+		 * If .git/REVERT_HEAD exists then we are sure that we are in
    -+		 * the middle of a revert and we allow to skip the commit.
    -+		 */
     +		if (!file_exists(git_path_revert_head(r))) {
    -+			/*
    -+			 * Check if the last instruction executed was related to
    -+			 * revert. If so, we are sure that a revert is in progress.
    -+			 *
    -+			 * NB: single commit revert is also counted in this
    -+			 * definition of "progress" (and was dealt with in the
    -+			 * previous check).
    -+			 */
    -+			if (action == REPLAY_REVERT) {
    -+				/*
    -+				 * Check if the user has moved the HEAD, i.e.,
    -+				 * already committed. In this case, we would like
    -+				 * to advise instead of skipping.
    -+				 */
    -+				if (!rollback_is_safe())
    -+					goto give_advice;
    -+				else
    -+					/* skip commit :) */
    -+					break;
    -+			}
    -+			return error(_("no revert in progress"));
    ++			if (action != REPLAY_REVERT)
    ++				return error(_("no revert in progress"));
    ++			if (!rollback_is_safe())
    ++				goto give_advice;
     +		}
     +		break;
     +	case REPLAY_PICK:
     +		if (!file_exists(git_path_cherry_pick_head(r))) {
    -+			if (action == REPLAY_PICK) {
    -+				if (!rollback_is_safe())
    -+					goto give_advice;
    -+				else
    -+					break;
    -+			}
    -+			return error(_("no cherry-pick in progress"));
    ++			if (action != REPLAY_PICK)
    ++				return error(_("no cherry-pick in progress"));
    ++			if (!rollback_is_safe())
    ++				goto give_advice;
     +		}
     +		break;
     +	default:
4:  941e73b654 ! 5:  63dbc11ab1 cherry-pick/revert: advise using --skip
    @@ -62,7 +62,7 @@
     +			_("try \"git cherry-pick (--continue | %s--abort | --quit)\"");
      			break;
      		default:
    - 			BUG(_("unexpected action in create_seq_dir"));
    + 			BUG("unexpected action in create_seq_dir");
     @@
      	}
      	if (in_progress_error) {
-- 
2.21.0


^ permalink raw reply	[flat|nested] 87+ messages in thread

* [GSoC][PATCH v5 1/5] sequencer: add advice for revert
  2019-06-18 17:06 ` [GSoC][PATCH v5 0/5] " Rohit Ashiwal
@ 2019-06-18 17:06   ` Rohit Ashiwal
  2019-06-18 17:06   ` [GSoC][PATCH v5 2/5] sequencer: rename reset_for_rollback to reset_merge Rohit Ashiwal
                     ` (3 subsequent siblings)
  4 siblings, 0 replies; 87+ messages in thread
From: Rohit Ashiwal @ 2019-06-18 17:06 UTC (permalink / raw)
  To: rohit.ashiwal265
  Cc: git, newren, t.gummerer, phillip.wood123, martin.agren, jrnieder,
	gitster

In the case of merge conflicts, while performing a revert, we are
currently advised to use `git cherry-pick --<sequencer-options>`
of which --continue is incompatible for continuing the revert.
Introduce a separate advice message for `git revert`. Also change
the signature of `create_seq_dir` to handle which advice to display
selectively.

Signed-off-by: Rohit Ashiwal <rohit.ashiwal265@gmail.com>
---
 sequencer.c | 34 ++++++++++++++++++++++++++++------
 1 file changed, 28 insertions(+), 6 deletions(-)

diff --git a/sequencer.c b/sequencer.c
index f88a97fb10..c644368b54 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -2650,15 +2650,37 @@ static int walk_revs_populate_todo(struct todo_list *todo_list,
 	return 0;
 }
 
-static int create_seq_dir(void)
+static int create_seq_dir(struct repository *r)
 {
-	if (file_exists(git_path_seq_dir())) {
-		error(_("a cherry-pick or revert is already in progress"));
-		advise(_("try \"git cherry-pick (--continue | --quit | --abort)\""));
+	enum replay_action action;
+	const char *in_progress_error = NULL;
+	const char *in_progress_advice = NULL;
+
+	if (!sequencer_get_last_command(r, &action)) {
+		switch (action) {
+		case REPLAY_REVERT:
+			in_progress_error = _("revert is already in progress");
+			in_progress_advice =
+			_("try \"git revert (--continue | --abort | --quit)\"");
+			break;
+		case REPLAY_PICK:
+			in_progress_error = _("cherry-pick is already in progress");
+			in_progress_advice =
+			_("try \"git cherry-pick (--continue | --abort | --quit)\"");
+			break;
+		default:
+			BUG("unexpected action in create_seq_dir");
+		}
+	}
+	if (in_progress_error) {
+		error("%s", in_progress_error);
+		advise("%s", in_progress_advice);
 		return -1;
-	} else if (mkdir(git_path_seq_dir(), 0777) < 0)
+	}
+	if (mkdir(git_path_seq_dir(), 0777) < 0)
 		return error_errno(_("could not create sequencer directory '%s'"),
 				   git_path_seq_dir());
+
 	return 0;
 }
 
@@ -4237,7 +4259,7 @@ int sequencer_pick_revisions(struct repository *r,
 	 */
 
 	if (walk_revs_populate_todo(&todo_list, opts) ||
-			create_seq_dir() < 0)
+			create_seq_dir(r) < 0)
 		return -1;
 	if (get_oid("HEAD", &oid) && (opts->action == REPLAY_REVERT))
 		return error(_("can't revert as initial commit"));
-- 
2.21.0


^ permalink raw reply	[flat|nested] 87+ messages in thread

* [GSoC][PATCH v5 2/5] sequencer: rename reset_for_rollback to reset_merge
  2019-06-18 17:06 ` [GSoC][PATCH v5 0/5] " Rohit Ashiwal
  2019-06-18 17:06   ` [GSoC][PATCH v5 1/5] sequencer: add advice for revert Rohit Ashiwal
@ 2019-06-18 17:06   ` Rohit Ashiwal
  2019-06-18 17:06   ` [GSoC][PATCH v5 3/5] sequencer: use argv_array in reset_merge Rohit Ashiwal
                     ` (2 subsequent siblings)
  4 siblings, 0 replies; 87+ messages in thread
From: Rohit Ashiwal @ 2019-06-18 17:06 UTC (permalink / raw)
  To: rohit.ashiwal265
  Cc: git, newren, t.gummerer, phillip.wood123, martin.agren, jrnieder,
	gitster

We are on a path to teach cherry-pick/revert how to skip commits. To
achieve this, we could really make use of existing functions.
reset_for_rollback is one such function, but the name does not
intuitively suggest to use it to reset a merge, which it was born to
perform see 539047c ("revert: introduce --abort to cancel a failed
cherry-pick", 2011-11-23). Change the name to reset_merge to make
it more intuitive.

Signed-off-by: Rohit Ashiwal <rohit.ashiwal265@gmail.com>
---
 sequencer.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/sequencer.c b/sequencer.c
index c644368b54..12f2605ded 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -2731,7 +2731,7 @@ static int rollback_is_safe(void)
 	return oideq(&actual_head, &expected_head);
 }
 
-static int reset_for_rollback(const struct object_id *oid)
+static int reset_merge(const struct object_id *oid)
 {
 	const char *argv[4];	/* reset --merge <arg> + NULL */
 
@@ -2753,7 +2753,7 @@ static int rollback_single_pick(struct repository *r)
 		return error(_("cannot resolve HEAD"));
 	if (is_null_oid(&head_oid))
 		return error(_("cannot abort from a branch yet to be born"));
-	return reset_for_rollback(&head_oid);
+	return reset_merge(&head_oid);
 }
 
 int sequencer_rollback(struct repository *r, struct replay_opts *opts)
@@ -2796,7 +2796,7 @@ int sequencer_rollback(struct repository *r, struct replay_opts *opts)
 		warning(_("You seem to have moved HEAD. "
 			  "Not rewinding, check your HEAD!"));
 	} else
-	if (reset_for_rollback(&oid))
+	if (reset_merge(&oid))
 		goto fail;
 	strbuf_release(&buf);
 	return sequencer_remove_state(opts);
-- 
2.21.0


^ permalink raw reply	[flat|nested] 87+ messages in thread

* [GSoC][PATCH v5 3/5] sequencer: use argv_array in reset_merge
  2019-06-18 17:06 ` [GSoC][PATCH v5 0/5] " Rohit Ashiwal
  2019-06-18 17:06   ` [GSoC][PATCH v5 1/5] sequencer: add advice for revert Rohit Ashiwal
  2019-06-18 17:06   ` [GSoC][PATCH v5 2/5] sequencer: rename reset_for_rollback to reset_merge Rohit Ashiwal
@ 2019-06-18 17:06   ` Rohit Ashiwal
  2019-06-18 17:06   ` [GSoC][PATCH v5 4/5] cherry-pick/revert: add --skip option Rohit Ashiwal
  2019-06-18 17:06   ` [GSoC][PATCH v5 5/5] cherry-pick/revert: advise using --skip Rohit Ashiwal
  4 siblings, 0 replies; 87+ messages in thread
From: Rohit Ashiwal @ 2019-06-18 17:06 UTC (permalink / raw)
  To: rohit.ashiwal265
  Cc: git, newren, t.gummerer, phillip.wood123, martin.agren, jrnieder,
	gitster

Avoid using magic numbers for array size and index under `reset_merge`
function. Use `argv_array` instead. This will make code shorter and
easier to extend.

Signed-off-by: Rohit Ashiwal <rohit.ashiwal265@gmail.com>
---
 sequencer.c | 17 +++++++++++------
 1 file changed, 11 insertions(+), 6 deletions(-)

diff --git a/sequencer.c b/sequencer.c
index 12f2605ded..6762a5f485 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -2733,13 +2733,18 @@ static int rollback_is_safe(void)
 
 static int reset_merge(const struct object_id *oid)
 {
-	const char *argv[4];	/* reset --merge <arg> + NULL */
+	int ret;
+	struct argv_array argv = ARGV_ARRAY_INIT;
 
-	argv[0] = "reset";
-	argv[1] = "--merge";
-	argv[2] = oid_to_hex(oid);
-	argv[3] = NULL;
-	return run_command_v_opt(argv, RUN_GIT_CMD);
+	argv_array_pushl(&argv, "reset", "--merge", NULL);
+
+	if (!is_null_oid(oid))
+		argv_array_push(&argv, oid_to_hex(oid));
+
+	ret = run_command_v_opt(argv.argv, RUN_GIT_CMD);
+	argv_array_clear(&argv);
+
+	return ret;
 }
 
 static int rollback_single_pick(struct repository *r)
-- 
2.21.0


^ permalink raw reply	[flat|nested] 87+ messages in thread

* [GSoC][PATCH v5 4/5] cherry-pick/revert: add --skip option
  2019-06-18 17:06 ` [GSoC][PATCH v5 0/5] " Rohit Ashiwal
                     ` (2 preceding siblings ...)
  2019-06-18 17:06   ` [GSoC][PATCH v5 3/5] sequencer: use argv_array in reset_merge Rohit Ashiwal
@ 2019-06-18 17:06   ` Rohit Ashiwal
  2019-06-20  3:40     ` Junio C Hamano
  2019-06-20 10:02     ` Phillip Wood
  2019-06-18 17:06   ` [GSoC][PATCH v5 5/5] cherry-pick/revert: advise using --skip Rohit Ashiwal
  4 siblings, 2 replies; 87+ messages in thread
From: Rohit Ashiwal @ 2019-06-18 17:06 UTC (permalink / raw)
  To: rohit.ashiwal265
  Cc: git, newren, t.gummerer, phillip.wood123, martin.agren, jrnieder,
	gitster

git am or rebase have a --skip flag to skip the current commit if the
user wishes to do so. During a cherry-pick or revert a user could
likewise skip a commit, but needs to use 'git reset' (or in the case
of conflicts 'git reset --merge'), followed by 'git (cherry-pick |
revert) --continue' to skip the commit. This is more annoying and
sometimes confusing on the users' part. Add a `--skip` option to make
skipping commits easier for the user and to make the commands more
consistent.

In the next commit, we will change the advice messages hence finishing
the process of teaching revert and cherry-pick "how to skip commits".

Signed-off-by: Rohit Ashiwal <rohit.ashiwal265@gmail.com>
---
 Documentation/git-cherry-pick.txt |   4 +-
 Documentation/git-revert.txt      |   4 +-
 Documentation/sequencer.txt       |   4 ++
 builtin/revert.c                  |   5 ++
 sequencer.c                       |  69 ++++++++++++++++++++
 sequencer.h                       |   1 +
 t/t3510-cherry-pick-sequence.sh   | 102 ++++++++++++++++++++++++++++++
 7 files changed, 183 insertions(+), 6 deletions(-)

diff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt
index 754b16ce0c..83ce51aedf 100644
--- a/Documentation/git-cherry-pick.txt
+++ b/Documentation/git-cherry-pick.txt
@@ -10,9 +10,7 @@ SYNOPSIS
 [verse]
 'git cherry-pick' [--edit] [-n] [-m parent-number] [-s] [-x] [--ff]
 		  [-S[<keyid>]] <commit>...
-'git cherry-pick' --continue
-'git cherry-pick' --quit
-'git cherry-pick' --abort
+'git cherry-pick' (--continue | --skip | --abort | --quit)
 
 DESCRIPTION
 -----------
diff --git a/Documentation/git-revert.txt b/Documentation/git-revert.txt
index 0c82ca5bc0..665e065ee3 100644
--- a/Documentation/git-revert.txt
+++ b/Documentation/git-revert.txt
@@ -9,9 +9,7 @@ SYNOPSIS
 --------
 [verse]
 'git revert' [--[no-]edit] [-n] [-m parent-number] [-s] [-S[<keyid>]] <commit>...
-'git revert' --continue
-'git revert' --quit
-'git revert' --abort
+'git revert' (--continue | --skip | --abort | --quit)
 
 DESCRIPTION
 -----------
diff --git a/Documentation/sequencer.txt b/Documentation/sequencer.txt
index 5a57c4a407..3bceb56474 100644
--- a/Documentation/sequencer.txt
+++ b/Documentation/sequencer.txt
@@ -3,6 +3,10 @@
 	`.git/sequencer`.  Can be used to continue after resolving
 	conflicts in a failed cherry-pick or revert.
 
+--skip::
+	Skip the current commit and continue with the rest of the
+	sequence.
+
 --quit::
 	Forget about the current operation in progress.  Can be used
 	to clear the sequencer state after a failed cherry-pick or
diff --git a/builtin/revert.c b/builtin/revert.c
index d4dcedbdc6..5dc5891ea2 100644
--- a/builtin/revert.c
+++ b/builtin/revert.c
@@ -102,6 +102,7 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)
 		OPT_CMDMODE(0, "quit", &cmd, N_("end revert or cherry-pick sequence"), 'q'),
 		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_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")),
@@ -151,6 +152,8 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)
 			this_operation = "--quit";
 		else if (cmd == 'c')
 			this_operation = "--continue";
+		else if (cmd == 's')
+			this_operation = "--skip";
 		else {
 			assert(cmd == 'a');
 			this_operation = "--abort";
@@ -210,6 +213,8 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)
 		return sequencer_continue(the_repository, opts);
 	if (cmd == 'a')
 		return sequencer_rollback(the_repository, opts);
+	if (cmd == 's')
+		return sequencer_skip(the_repository, opts);
 	return sequencer_pick_revisions(the_repository, opts);
 }
 
diff --git a/sequencer.c b/sequencer.c
index 6762a5f485..5720cd1c85 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -2761,6 +2761,15 @@ static int rollback_single_pick(struct repository *r)
 	return reset_merge(&head_oid);
 }
 
+static int skip_single_pick(void)
+{
+	struct object_id head;
+
+	if (read_ref_full("HEAD", 0, &head, NULL))
+		return error(_("cannot resolve HEAD"));
+	return reset_merge(&head);
+}
+
 int sequencer_rollback(struct repository *r, struct replay_opts *opts)
 {
 	FILE *f;
@@ -2810,6 +2819,66 @@ int sequencer_rollback(struct repository *r, struct replay_opts *opts)
 	return -1;
 }
 
+int sequencer_skip(struct repository *r, struct replay_opts *opts)
+{
+	enum replay_action action = -1;
+	sequencer_get_last_command(r, &action);
+
+	/*
+	 * Check whether the subcommand requested to skip the commit is actually
+	 * in progress and that it's safe to skip the commit.
+	 *
+	 * opts->action tells us which subcommand requested to skip the commit.
+	 * If the corresponding .git/<ACTION>_HEAD exists, we know that the
+	 * action is in progress and we can skip the commit.
+	 *
+	 * Otherwise we check that the last instruction was related to the
+	 * particular subcommand we're trying to execute and barf if that's not
+	 * the case.
+	 *
+	 * Finally we check that the rollback is "safe", i.e., has the HEAD
+	 * moved? In this case, it doesn't make sense to "reset the merge" and
+	 * "skip the commit" as the user already handled this by committing. But
+	 * we'd not want to barf here, instead give advice on how to proceed. We
+	 * only need to check that when .git/<ACTION>_HEAD doesn't exist because
+	 * it gets removed when the user commits, so if it still exists we're
+	 * sure the user can't have committed before.
+	 */
+	switch (opts->action) {
+	case REPLAY_REVERT:
+		if (!file_exists(git_path_revert_head(r))) {
+			if (action != REPLAY_REVERT)
+				return error(_("no revert in progress"));
+			if (!rollback_is_safe())
+				goto give_advice;
+		}
+		break;
+	case REPLAY_PICK:
+		if (!file_exists(git_path_cherry_pick_head(r))) {
+			if (action != REPLAY_PICK)
+				return error(_("no cherry-pick in progress"));
+			if (!rollback_is_safe())
+				goto give_advice;
+		}
+		break;
+	default:
+		BUG("unexpected action in sequencer_skip");
+	}
+
+	if (skip_single_pick())
+		return error(_("failed to skip the commit"));
+	if (!is_directory(git_path_seq_dir()))
+		return 0;
+
+	return sequencer_continue(r, opts);
+
+give_advice:
+	advise(_("have you committed already?\n"
+		 "try \"git %s --continue\""),
+		 action == REPLAY_REVERT ? "revert" : "cherry-pick");
+	return error(_("there is nothing to skip"));
+}
+
 static int save_todo(struct todo_list *todo_list, struct replay_opts *opts)
 {
 	struct lock_file todo_lock = LOCK_INIT;
diff --git a/sequencer.h b/sequencer.h
index 0c494b83d4..731b9853eb 100644
--- a/sequencer.h
+++ b/sequencer.h
@@ -129,6 +129,7 @@ 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_skip(struct repository *repo, struct replay_opts *opts);
 int sequencer_remove_state(struct replay_opts *opts);
 
 #define TODO_LIST_KEEP_EMPTY (1U << 0)
diff --git a/t/t3510-cherry-pick-sequence.sh b/t/t3510-cherry-pick-sequence.sh
index 941d5026da..dc0ac8343c 100755
--- a/t/t3510-cherry-pick-sequence.sh
+++ b/t/t3510-cherry-pick-sequence.sh
@@ -93,6 +93,108 @@ test_expect_success 'cherry-pick cleans up sequencer state upon success' '
 	test_path_is_missing .git/sequencer
 '
 
+test_expect_success 'cherry-pick --skip requires cherry-pick in progress' '
+	pristine_detach initial &&
+	test_must_fail git cherry-pick --skip
+'
+
+test_expect_success 'revert --skip requires revert in progress' '
+	pristine_detach initial &&
+	test_must_fail git revert --skip
+'
+
+test_expect_success 'cherry-pick --skip to skip commit' '
+	pristine_detach initial &&
+	test_must_fail git cherry-pick anotherpick &&
+	test_must_fail git revert --skip &&
+	git cherry-pick --skip &&
+	test_cmp_rev initial HEAD &&
+	test_path_is_missing .git/CHERRY_PICK_HEAD
+'
+
+test_expect_success 'revert --skip to skip commit' '
+	pristine_detach anotherpick &&
+	test_must_fail git revert anotherpick~1 &&
+	test_must_fail git cherry-pick --skip &&
+	git revert --skip &&
+	test_cmp_rev anotherpick HEAD
+'
+
+test_expect_success 'skip "empty" commit' '
+	pristine_detach picked &&
+	test_commit dummy foo d &&
+	test_must_fail git cherry-pick anotherpick &&
+	git cherry-pick --skip &&
+	test_cmp_rev dummy HEAD
+'
+
+test_expect_success 'skip a commit and check if rest of sequence is correct' '
+	pristine_detach initial &&
+	echo e >expect &&
+	cat >expect.log <<-EOF &&
+	OBJID
+	:100644 100644 OBJID OBJID M	foo
+	OBJID
+	:100644 100644 OBJID OBJID M	foo
+	OBJID
+	:100644 100644 OBJID OBJID M	unrelated
+	OBJID
+	:000000 100644 OBJID OBJID A	foo
+	:000000 100644 OBJID OBJID A	unrelated
+	EOF
+	test_must_fail git cherry-pick base..yetanotherpick &&
+	test_must_fail git cherry-pick --skip &&
+	echo d >foo &&
+	git add foo &&
+	git cherry-pick --continue &&
+	{
+		git rev-list HEAD |
+		git diff-tree --root --stdin |
+		sed "s/$OID_REGEX/OBJID/g"
+	} >actual.log &&
+	test_cmp expect foo &&
+	test_cmp expect.log actual.log
+'
+
+test_expect_success 'check advice when we move HEAD by committing' '
+	pristine_detach initial &&
+	cat >expect <<-EOF &&
+	hint: have you committed already?
+	hint: try "git cherry-pick --continue"
+	error: there is nothing to skip
+	fatal: cherry-pick failed
+	EOF
+	test_must_fail git cherry-pick base..yetanotherpick &&
+	echo c >foo &&
+	git commit -a &&
+	test_path_is_missing .git/CHERRY_PICK_HEAD &&
+	test_must_fail git cherry-pick --skip 2>advice &&
+	test_i18ncmp expect advice
+'
+
+test_expect_success 'allow skipping commit but not abort for a new history' '
+	pristine_detach initial &&
+	cat >expect <<-EOF &&
+	error: cannot abort from a branch yet to be born
+	fatal: cherry-pick failed
+	EOF
+	git checkout --orphan new_disconnected &&
+	git reset --hard &&
+	test_must_fail git cherry-pick anotherpick &&
+	test_must_fail git cherry-pick --abort 2>advice &&
+	git cherry-pick --skip &&
+	test_i18ncmp expect advice
+'
+
+test_expect_success 'allow skipping stopped cherry-pick because of untracked file modifications' '
+	pristine_detach initial &&
+	git rm --cached unrelated &&
+	git commit -m "untrack unrelated" &&
+	test_must_fail git cherry-pick initial base &&
+	test_path_is_missing .git/CHERRY_PICK_HEAD &&
+	git cherry-pick --skip
+'
+
 test_expect_success '--quit does not complain when no cherry-pick is in progress' '
 	pristine_detach initial &&
 	git cherry-pick --quit
-- 
2.21.0


^ permalink raw reply	[flat|nested] 87+ messages in thread

* [GSoC][PATCH v5 5/5] cherry-pick/revert: advise using --skip
  2019-06-18 17:06 ` [GSoC][PATCH v5 0/5] " Rohit Ashiwal
                     ` (3 preceding siblings ...)
  2019-06-18 17:06   ` [GSoC][PATCH v5 4/5] cherry-pick/revert: add --skip option Rohit Ashiwal
@ 2019-06-18 17:06   ` Rohit Ashiwal
  4 siblings, 0 replies; 87+ messages in thread
From: Rohit Ashiwal @ 2019-06-18 17:06 UTC (permalink / raw)
  To: rohit.ashiwal265
  Cc: git, newren, t.gummerer, phillip.wood123, martin.agren, jrnieder,
	gitster

The previous commit introduced a --skip flag for cherry-pick and
revert. Update the advice messages, to tell users about this less
cumbersome way of skipping commits. Also add tests to ensure
everything is working fine.

Signed-off-by: Rohit Ashiwal <rohit.ashiwal265@gmail.com>
---
 builtin/commit.c                | 13 ++++++++-----
 sequencer.c                     | 11 ++++++++---
 t/t3510-cherry-pick-sequence.sh | 20 ++++++++++++++++++++
 3 files changed, 36 insertions(+), 8 deletions(-)

diff --git a/builtin/commit.c b/builtin/commit.c
index 1c9e8e2228..1f47c51bdc 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -60,15 +60,18 @@ N_("The previous cherry-pick is now empty, possibly due to conflict resolution.\
 "\n");
 
 static const char empty_cherry_pick_advice_single[] =
-N_("Otherwise, please use 'git reset'\n");
+N_("Otherwise, please use 'git cherry-pick --skip'\n");
 
 static const char empty_cherry_pick_advice_multi[] =
-N_("If you wish to skip this commit, use:\n"
+N_("and then use:\n"
 "\n"
-"    git reset\n"
+"    git cherry-pick --continue\n"
 "\n"
-"Then \"git cherry-pick --continue\" will resume cherry-picking\n"
-"the remaining commits.\n");
+"to resume cherry-picking the remaining commits.\n"
+"If you wish to skip this commit, use:\n"
+"\n"
+"    git cherry-pick --skip\n"
+"\n");
 
 static const char *color_status_slots[] = {
 	[WT_STATUS_HEADER]	  = "header",
diff --git a/sequencer.c b/sequencer.c
index 5720cd1c85..cc7f6219e7 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -2655,18 +2655,20 @@ static int create_seq_dir(struct repository *r)
 	enum replay_action action;
 	const char *in_progress_error = NULL;
 	const char *in_progress_advice = NULL;
+	unsigned int advise_skip = file_exists(git_path_revert_head(r)) ||
+				file_exists(git_path_cherry_pick_head(r));
 
 	if (!sequencer_get_last_command(r, &action)) {
 		switch (action) {
 		case REPLAY_REVERT:
 			in_progress_error = _("revert is already in progress");
 			in_progress_advice =
-			_("try \"git revert (--continue | --abort | --quit)\"");
+			_("try \"git revert (--continue | %s--abort | --quit)\"");
 			break;
 		case REPLAY_PICK:
 			in_progress_error = _("cherry-pick is already in progress");
 			in_progress_advice =
-			_("try \"git cherry-pick (--continue | --abort | --quit)\"");
+			_("try \"git cherry-pick (--continue | %s--abort | --quit)\"");
 			break;
 		default:
 			BUG("unexpected action in create_seq_dir");
@@ -2674,7 +2676,10 @@ static int create_seq_dir(struct repository *r)
 	}
 	if (in_progress_error) {
 		error("%s", in_progress_error);
-		advise("%s", in_progress_advice);
+		if (advise_skip)
+			advise(in_progress_advice, "--skip | ");
+		else
+			advise(in_progress_advice, "");
 		return -1;
 	}
 	if (mkdir(git_path_seq_dir(), 0777) < 0)
diff --git a/t/t3510-cherry-pick-sequence.sh b/t/t3510-cherry-pick-sequence.sh
index dc0ac8343c..0e8adc95fc 100755
--- a/t/t3510-cherry-pick-sequence.sh
+++ b/t/t3510-cherry-pick-sequence.sh
@@ -172,6 +172,26 @@ test_expect_success 'check advice when we move HEAD by committing' '
 	test_i18ncmp expect advice
 '
 
+test_expect_success 'selectively advise --skip while launching another sequence' '
+	pristine_detach initial &&
+	cat >expect <<-EOF &&
+	error: cherry-pick is already in progress
+	hint: try "git cherry-pick (--continue | --skip | --abort | --quit)"
+	fatal: cherry-pick failed
+	EOF
+	test_must_fail git cherry-pick picked..yetanotherpick &&
+	test_must_fail git cherry-pick picked..yetanotherpick 2>advice &&
+	test_i18ncmp expect advice &&
+	cat >expect <<-EOF &&
+	error: cherry-pick is already in progress
+	hint: try "git cherry-pick (--continue | --abort | --quit)"
+	fatal: cherry-pick failed
+	EOF
+	git reset --merge &&
+	test_must_fail git cherry-pick picked..yetanotherpick 2>advice &&
+	test_i18ncmp expect advice
+'
+
 test_expect_success 'allow skipping commit but not abort for a new history' '
 	pristine_detach initial &&
 	cat >expect <<-EOF &&
-- 
2.21.0


^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [GSoC][PATCH v5 4/5] cherry-pick/revert: add --skip option
  2019-06-18 17:06   ` [GSoC][PATCH v5 4/5] cherry-pick/revert: add --skip option Rohit Ashiwal
@ 2019-06-20  3:40     ` Junio C Hamano
  2019-06-20  9:46       ` Rohit Ashiwal
  2019-06-20  9:57       ` Phillip Wood
  2019-06-20 10:02     ` Phillip Wood
  1 sibling, 2 replies; 87+ messages in thread
From: Junio C Hamano @ 2019-06-20  3:40 UTC (permalink / raw)
  To: Rohit Ashiwal
  Cc: git, newren, t.gummerer, phillip.wood123, martin.agren, jrnieder

Rohit Ashiwal <rohit.ashiwal265@gmail.com> writes:

> +give_advice:
> +	advise(_("have you committed already?\n"
> +		 "try \"git %s --continue\""),
> +		 action == REPLAY_REVERT ? "revert" : "cherry-pick");
> +	return error(_("there is nothing to skip"));
> +}

Two comments.

The places touched by patch 1/5 emitted the error followed by an
advice message; this new one breaks the pattern by giving the "hint:"
first and then error.  Be consistent by swapping these two (and
return -1, as "error() that returns -1" will no longer be the last
thing executed in this function.

This one, and the in_progress_advice emitted from the patch 1/5, are
both bad in that they make calls to advise() without guarding it
with an advice.* configuration variable. This does not allow the
user to say say "I've learned this part of Git enough; do not tell
me verbosely."

Pick a random global variable that is defined near the top of
advice.c, and learn how they are set (to true by default, allowing
configuration to flip it off) and how they are used in order to
prevent a call to advise() getting made.  Then mimick that to guard
these calls to advise().

Thanks.

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [GSoC][PATCH v5 4/5] cherry-pick/revert: add --skip option
  2019-06-20  3:40     ` Junio C Hamano
@ 2019-06-20  9:46       ` Rohit Ashiwal
  2019-06-20  9:57       ` Phillip Wood
  1 sibling, 0 replies; 87+ messages in thread
From: Rohit Ashiwal @ 2019-06-20  9:46 UTC (permalink / raw)
  To: gitster
  Cc: git, jrnieder, martin.agren, newren, phillip.wood123,
	rohit.ashiwal265, t.gummerer

Hi Junio

On Wed, 19 Jun 2019 20:40:50 -0700 Junio C Hamano <gitster@pobox.com> wrote:
>
> Two comments.
>
> The places touched by patch 1/5 emitted the error followed by an
> advice message; this new one breaks the pattern by giving the "hint:"
> first and then error.  Be consistent by swapping these two (and
> return -1, as "error() that returns -1" will no longer be the last
> thing executed in this function.

Yes, it also makes sense otherwise, but this will be more consistent.

> This one, and the in_progress_advice emitted from the patch 1/5, are
> both bad in that they make calls to advise() without guarding it
> with an advice.* configuration variable. This does not allow the
> user to say say "I've learned this part of Git enough; do not tell
> me verbosely."

Oh~ I was missing this point from the start. I'll make proper changes
to my patch.

> Pick a random global variable that is defined near the top of
> advice.c, and learn how they are set (to true by default, allowing
> configuration to flip it off) and how they are used in order to
> prevent a call to advise() getting made.  Then mimick that to guard
> these calls to advise().

Ok, I'll look into it and change accordingly.

> Thanks.

Thanks
Rohit


^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [GSoC][PATCH v5 4/5] cherry-pick/revert: add --skip option
  2019-06-20  3:40     ` Junio C Hamano
  2019-06-20  9:46       ` Rohit Ashiwal
@ 2019-06-20  9:57       ` Phillip Wood
  2019-06-20 20:09         ` Junio C Hamano
  1 sibling, 1 reply; 87+ messages in thread
From: Phillip Wood @ 2019-06-20  9:57 UTC (permalink / raw)
  To: Junio C Hamano, Rohit Ashiwal
  Cc: git, newren, t.gummerer, martin.agren, jrnieder

On 20/06/2019 04:40, Junio C Hamano wrote:
> Rohit Ashiwal <rohit.ashiwal265@gmail.com> writes:
> 
>> +give_advice:
>> +	advise(_("have you committed already?\n"
>> +		 "try \"git %s --continue\""),
>> +		 action == REPLAY_REVERT ? "revert" : "cherry-pick");
>> +	return error(_("there is nothing to skip"));
>> +}
> 
> Two comments.
> 
> The places touched by patch 1/5 emitted the error followed by an
> advice message; this new one breaks the pattern by giving the "hint:"
> first and then error.  Be consistent by swapping these two (and
> return -1, as "error() that returns -1" will no longer be the last
> thing executed in this function.
> 
> This one, and the in_progress_advice emitted from the patch 1/5, are
> both bad in that they make calls to advise() without guarding it
> with an advice.* configuration variable.

I'm not sure we have one for cherry-pick/revert/rebase. At the moment 
they print advice advice for a failed pick unconditionally (the caller 
of `print_advice()` sets `show_hint` based on the result of the merge 
rather than user preference) it would be nice to fix that. Maybe that 
should be checking advice.resolveConflict though. I'm also not sure if 
that is really within the scope of this patch series.

Best Wishes

Phillip


> This does not allow the
> user to say say "I've learned this part of Git enough; do not tell
> me verbosely."
> 
> Pick a random global variable that is defined near the top of
> advice.c, and learn how they are set (to true by default, allowing
> configuration to flip it off) and how they are used in order to
> prevent a call to advise() getting made.  Then mimick that to guard
> these calls to advise().
> 
> Thanks.
> 

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [GSoC][PATCH v5 4/5] cherry-pick/revert: add --skip option
  2019-06-18 17:06   ` [GSoC][PATCH v5 4/5] cherry-pick/revert: add --skip option Rohit Ashiwal
  2019-06-20  3:40     ` Junio C Hamano
@ 2019-06-20 10:02     ` Phillip Wood
  2019-06-20 10:34       ` Rohit Ashiwal
  1 sibling, 1 reply; 87+ messages in thread
From: Phillip Wood @ 2019-06-20 10:02 UTC (permalink / raw)
  To: Rohit Ashiwal; +Cc: git, newren, t.gummerer, martin.agren, jrnieder, gitster

Hi Rohit

On 18/06/2019 18:06, Rohit Ashiwal wrote:
> git am or rebase have a --skip flag to skip the current commit if the
> user wishes to do so. During a cherry-pick or revert a user could
> likewise skip a commit, but needs to use 'git reset' (or in the case
> of conflicts 'git reset --merge'), followed by 'git (cherry-pick |
> revert) --continue' to skip the commit. This is more annoying and
> sometimes confusing on the users' part. Add a `--skip` option to make
> skipping commits easier for the user and to make the commands more
> consistent.
> 
> In the next commit, we will change the advice messages hence finishing
> the process of teaching revert and cherry-pick "how to skip commits".
> 
> Signed-off-by: Rohit Ashiwal <rohit.ashiwal265@gmail.com>
> ---
>   Documentation/git-cherry-pick.txt |   4 +-
>   Documentation/git-revert.txt      |   4 +-
>   Documentation/sequencer.txt       |   4 ++
>   builtin/revert.c                  |   5 ++
>   sequencer.c                       |  69 ++++++++++++++++++++
>   sequencer.h                       |   1 +
>   t/t3510-cherry-pick-sequence.sh   | 102 ++++++++++++++++++++++++++++++
>   7 files changed, 183 insertions(+), 6 deletions(-)
> 
> diff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt
> index 754b16ce0c..83ce51aedf 100644
> --- a/Documentation/git-cherry-pick.txt
> +++ b/Documentation/git-cherry-pick.txt
> @@ -10,9 +10,7 @@ SYNOPSIS
>   [verse]
>   'git cherry-pick' [--edit] [-n] [-m parent-number] [-s] [-x] [--ff]
>   		  [-S[<keyid>]] <commit>...
> -'git cherry-pick' --continue
> -'git cherry-pick' --quit
> -'git cherry-pick' --abort
> +'git cherry-pick' (--continue | --skip | --abort | --quit)
>   
>   DESCRIPTION
>   -----------
> diff --git a/Documentation/git-revert.txt b/Documentation/git-revert.txt
> index 0c82ca5bc0..665e065ee3 100644
> --- a/Documentation/git-revert.txt
> +++ b/Documentation/git-revert.txt
> @@ -9,9 +9,7 @@ SYNOPSIS
>   --------
>   [verse]
>   'git revert' [--[no-]edit] [-n] [-m parent-number] [-s] [-S[<keyid>]] <commit>...
> -'git revert' --continue
> -'git revert' --quit
> -'git revert' --abort
> +'git revert' (--continue | --skip | --abort | --quit)
>   
>   DESCRIPTION
>   -----------
> diff --git a/Documentation/sequencer.txt b/Documentation/sequencer.txt
> index 5a57c4a407..3bceb56474 100644
> --- a/Documentation/sequencer.txt
> +++ b/Documentation/sequencer.txt
> @@ -3,6 +3,10 @@
>   	`.git/sequencer`.  Can be used to continue after resolving
>   	conflicts in a failed cherry-pick or revert.
>   
> +--skip::
> +	Skip the current commit and continue with the rest of the
> +	sequence.
> +
>   --quit::
>   	Forget about the current operation in progress.  Can be used
>   	to clear the sequencer state after a failed cherry-pick or
> diff --git a/builtin/revert.c b/builtin/revert.c
> index d4dcedbdc6..5dc5891ea2 100644
> --- a/builtin/revert.c
> +++ b/builtin/revert.c
> @@ -102,6 +102,7 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)
>   		OPT_CMDMODE(0, "quit", &cmd, N_("end revert or cherry-pick sequence"), 'q'),
>   		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_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")),
> @@ -151,6 +152,8 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)
>   			this_operation = "--quit";
>   		else if (cmd == 'c')
>   			this_operation = "--continue";
> +		else if (cmd == 's')
> +			this_operation = "--skip";
>   		else {
>   			assert(cmd == 'a');
>   			this_operation = "--abort";
> @@ -210,6 +213,8 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)
>   		return sequencer_continue(the_repository, opts);
>   	if (cmd == 'a')
>   		return sequencer_rollback(the_repository, opts);
> +	if (cmd == 's')
> +		return sequencer_skip(the_repository, opts);
>   	return sequencer_pick_revisions(the_repository, opts);
>   }
>   
> diff --git a/sequencer.c b/sequencer.c
> index 6762a5f485..5720cd1c85 100644
> --- a/sequencer.c
> +++ b/sequencer.c
> @@ -2761,6 +2761,15 @@ static int rollback_single_pick(struct repository *r)
>   	return reset_merge(&head_oid);
>   }
>   
> +static int skip_single_pick(void)
> +{
> +	struct object_id head;
> +
> +	if (read_ref_full("HEAD", 0, &head, NULL))
> +		return error(_("cannot resolve HEAD"));
> +	return reset_merge(&head);
> +}
> +
>   int sequencer_rollback(struct repository *r, struct replay_opts *opts)
>   {
>   	FILE *f;
> @@ -2810,6 +2819,66 @@ int sequencer_rollback(struct repository *r, struct replay_opts *opts)
>   	return -1;
>   }
>   
> +int sequencer_skip(struct repository *r, struct replay_opts *opts)
> +{
> +	enum replay_action action = -1;
> +	sequencer_get_last_command(r, &action);
> +
> +	/*
> +	 * Check whether the subcommand requested to skip the commit is actually
> +	 * in progress and that it's safe to skip the commit.
> +	 *
> +	 * opts->action tells us which subcommand requested to skip the commit.
> +	 * If the corresponding .git/<ACTION>_HEAD exists, we know that the
> +	 * action is in progress and we can skip the commit.
> +	 *
> +	 * Otherwise we check that the last instruction was related to the
> +	 * particular subcommand we're trying to execute and barf if that's not
> +	 * the case.
> +	 *
> +	 * Finally we check that the rollback is "safe", i.e., has the HEAD
> +	 * moved? In this case, it doesn't make sense to "reset the merge" and
> +	 * "skip the commit" as the user already handled this by committing. But
> +	 * we'd not want to barf here, instead give advice on how to proceed. We
> +	 * only need to check that when .git/<ACTION>_HEAD doesn't exist because
> +	 * it gets removed when the user commits, so if it still exists we're
> +	 * sure the user can't have committed before.
> +	 */

Thanks for updating the comment, I think it is easier to follow now 
(Thanks to Thomas for suggesting it as well)

> +	switch (opts->action) {
> +	case REPLAY_REVERT:
> +		if (!file_exists(git_path_revert_head(r))) {
> +			if (action != REPLAY_REVERT)
> +				return error(_("no revert in progress"));
> +			if (!rollback_is_safe())
> +				goto give_advice;
> +		}
> +		break;
> +	case REPLAY_PICK:
> +		if (!file_exists(git_path_cherry_pick_head(r))) {
> +			if (action != REPLAY_PICK)
> +				return error(_("no cherry-pick in progress"));
> +			if (!rollback_is_safe())
> +				goto give_advice;
> +		}
> +		break;
> +	default:
> +		BUG("unexpected action in sequencer_skip");
> +	}
> +
> +	if (skip_single_pick())
> +		return error(_("failed to skip the commit"));
> +	if (!is_directory(git_path_seq_dir()))
> +		return 0;
> +
> +	return sequencer_continue(r, opts);
> +
> +give_advice:
> +	advise(_("have you committed already?\n"
> +		 "try \"git %s --continue\""),
> +		 action == REPLAY_REVERT ? "revert" : "cherry-pick");
> +	return error(_("there is nothing to skip"));
> +}
> +
>   static int save_todo(struct todo_list *todo_list, struct replay_opts *opts)
>   {
>   	struct lock_file todo_lock = LOCK_INIT;
> diff --git a/sequencer.h b/sequencer.h
> index 0c494b83d4..731b9853eb 100644
> --- a/sequencer.h
> +++ b/sequencer.h
> @@ -129,6 +129,7 @@ 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_skip(struct repository *repo, struct replay_opts *opts);
>   int sequencer_remove_state(struct replay_opts *opts);
>   
>   #define TODO_LIST_KEEP_EMPTY (1U << 0)
> diff --git a/t/t3510-cherry-pick-sequence.sh b/t/t3510-cherry-pick-sequence.sh
> index 941d5026da..dc0ac8343c 100755
> --- a/t/t3510-cherry-pick-sequence.sh
> +++ b/t/t3510-cherry-pick-sequence.sh
> @@ -93,6 +93,108 @@ test_expect_success 'cherry-pick cleans up sequencer state upon success' '
>   	test_path_is_missing .git/sequencer
>   '
>   
> +test_expect_success 'cherry-pick --skip requires cherry-pick in progress' '
> +	pristine_detach initial &&
> +	test_must_fail git cherry-pick --skip
> +'
> +
> +test_expect_success 'revert --skip requires revert in progress' '
> +	pristine_detach initial &&
> +	test_must_fail git revert --skip
> +'
> +
> +test_expect_success 'cherry-pick --skip to skip commit' '
> +	pristine_detach initial &&
> +	test_must_fail git cherry-pick anotherpick &&
> +	test_must_fail git revert --skip &&
> +	git cherry-pick --skip &&
> +	test_cmp_rev initial HEAD &&
> +	test_path_is_missing .git/CHERRY_PICK_HEAD
> +'
> +
> +test_expect_success 'revert --skip to skip commit' '
> +	pristine_detach anotherpick &&
> +	test_must_fail git revert anotherpick~1 &&
> +	test_must_fail git cherry-pick --skip &&
> +	git revert --skip &&
> +	test_cmp_rev anotherpick HEAD
> +'
> +
> +test_expect_success 'skip "empty" commit' '
> +	pristine_detach picked &&
> +	test_commit dummy foo d &&
> +	test_must_fail git cherry-pick anotherpick &&
> +	git cherry-pick --skip &&
> +	test_cmp_rev dummy HEAD
> +'
> +
> +test_expect_success 'skip a commit and check if rest of sequence is correct' '
> +	pristine_detach initial &&
> +	echo e >expect &&
> +	cat >expect.log <<-EOF &&
> +	OBJID
> +	:100644 100644 OBJID OBJID M	foo
> +	OBJID
> +	:100644 100644 OBJID OBJID M	foo
> +	OBJID
> +	:100644 100644 OBJID OBJID M	unrelated
> +	OBJID
> +	:000000 100644 OBJID OBJID A	foo
> +	:000000 100644 OBJID OBJID A	unrelated
> +	EOF
> +	test_must_fail git cherry-pick base..yetanotherpick &&
> +	test_must_fail git cherry-pick --skip &&
> +	echo d >foo &&
> +	git add foo &&
> +	git cherry-pick --continue &&
> +	{
> +		git rev-list HEAD |
> +		git diff-tree --root --stdin |
> +		sed "s/$OID_REGEX/OBJID/g"
> +	} >actual.log &&
> +	test_cmp expect foo &&
> +	test_cmp expect.log actual.log
> +'
> +
> +test_expect_success 'check advice when we move HEAD by committing' '
> +	pristine_detach initial &&
> +	cat >expect <<-EOF &&
> +	hint: have you committed already?
> +	hint: try "git cherry-pick --continue"
> +	error: there is nothing to skip
> +	fatal: cherry-pick failed
> +	EOF
> +	test_must_fail git cherry-pick base..yetanotherpick &&
> +	echo c >foo &&
> +	git commit -a &&
> +	test_path_is_missing .git/CHERRY_PICK_HEAD &&
> +	test_must_fail git cherry-pick --skip 2>advice &&
> +	test_i18ncmp expect advice
> +'
> +
> +test_expect_success 'allow skipping commit but not abort for a new history' '
> +	pristine_detach initial &&
> +	cat >expect <<-EOF &&
> +	error: cannot abort from a branch yet to be born
> +	fatal: cherry-pick failed
> +	EOF
> +	git checkout --orphan new_disconnected &&
> +	git reset --hard &&
> +	test_must_fail git cherry-pick anotherpick &&
> +	test_must_fail git cherry-pick --abort 2>advice &&
> +	git cherry-pick --skip &&
> +	test_i18ncmp expect advice
> +'
> +
> +test_expect_success 'allow skipping stopped cherry-pick because of untracked file modifications' '
> +	pristine_detach initial &&
> +	git rm --cached unrelated &&
> +	git commit -m "untrack unrelated" &&
> +	test_must_fail git cherry-pick initial base &&
> +	test_path_is_missing .git/CHERRY_PICK_HEAD &&
> +	git cherry-pick --skip

If you change this to --continue rather than --skip the test also 
passes! I think we could fix this by checking if HEAD has changed if 
CHERRY_PICK_HEAD/REVERT_HEAD is missing and not dropping the last 
command in the todo list in that case when we continue.

Best Wishes

Phillip

> +'
> +
>   test_expect_success '--quit does not complain when no cherry-pick is in progress' '
>   	pristine_detach initial &&
>   	git cherry-pick --quit
> 

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [GSoC][PATCH v5 4/5] cherry-pick/revert: add --skip option
  2019-06-20 10:02     ` Phillip Wood
@ 2019-06-20 10:34       ` Rohit Ashiwal
  2019-06-20 11:42         ` Phillip Wood
  0 siblings, 1 reply; 87+ messages in thread
From: Rohit Ashiwal @ 2019-06-20 10:34 UTC (permalink / raw)
  To: phillip.wood123
  Cc: git, gitster, jrnieder, martin.agren, newren, phillip.wood,
	rohit.ashiwal265, t.gummerer

Hi Phillip

On 2019-06-20 10:02 UTC Phillip Wood <phillip.wood123@gmail.com> wrote:
>
> > +test_expect_success 'allow skipping stopped cherry-pick because of untracked file modifications' '
> > +	pristine_detach initial &&
> > +	git rm --cached unrelated &&
> > +	git commit -m "untrack unrelated" &&
> > +	test_must_fail git cherry-pick initial base &&
> > +	test_path_is_missing .git/CHERRY_PICK_HEAD &&
> > +	git cherry-pick --skip
>
> If you change this to --continue rather than --skip the test also
> passes! I think we could fix this by checking if HEAD has changed if
> CHERRY_PICK_HEAD/REVERT_HEAD is missing and not dropping the last
> command in the todo list in that case when we continue.

I don't think I fully understood this. At this point --skip is essentially
--continue. How is checking unmoved HEAD and unchanged todo uniquely related
to --skip flag (or for that matter any _flag_)?

Thanks
Rohit


^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [GSoC][PATCH v5 4/5] cherry-pick/revert: add --skip option
  2019-06-20 10:34       ` Rohit Ashiwal
@ 2019-06-20 11:42         ` Phillip Wood
  2019-06-21  7:47           ` Rohit Ashiwal
  0 siblings, 1 reply; 87+ messages in thread
From: Phillip Wood @ 2019-06-20 11:42 UTC (permalink / raw)
  To: Rohit Ashiwal
  Cc: git, gitster, jrnieder, martin.agren, newren, phillip.wood, t.gummerer

Hi Rohit

On 20/06/2019 11:34, Rohit Ashiwal wrote:
> Hi Phillip
> 
> On 2019-06-20 10:02 UTC Phillip Wood <phillip.wood123@gmail.com> wrote:
>>
>>> +test_expect_success 'allow skipping stopped cherry-pick because of untracked file modifications' '
>>> +	pristine_detach initial &&
>>> +	git rm --cached unrelated &&
>>> +	git commit -m "untrack unrelated" &&
>>> +	test_must_fail git cherry-pick initial base &&
>>> +	test_path_is_missing .git/CHERRY_PICK_HEAD &&
>>> +	git cherry-pick --skip
>>
>> If you change this to --continue rather than --skip the test also
>> passes! I think we could fix this by checking if HEAD has changed if
>> CHERRY_PICK_HEAD/REVERT_HEAD is missing and not dropping the last
>> command in the todo list in that case when we continue.
> 
> I don't think I fully understood this. At this point --skip is essentially
> --continue. How is checking unmoved HEAD and unchanged todo uniquely related
> to --skip flag (or for that matter any _flag_)?

My point is that --continue should reschedule the failed pick and try to 
pick it again - it should not silently skip a failed pick and  --skip 
should skip it.

Best Wishes

Phillip
> 
> Thanks
> Rohit
> 

^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [GSoC][PATCH v5 4/5] cherry-pick/revert: add --skip option
  2019-06-20  9:57       ` Phillip Wood
@ 2019-06-20 20:09         ` Junio C Hamano
  0 siblings, 0 replies; 87+ messages in thread
From: Junio C Hamano @ 2019-06-20 20:09 UTC (permalink / raw)
  To: Phillip Wood
  Cc: Rohit Ashiwal, git, newren, t.gummerer, martin.agren, jrnieder

Phillip Wood <phillip.wood123@gmail.com> writes:

>> This one, and the in_progress_advice emitted from the patch 1/5, are
>> both bad in that they make calls to advise() without guarding it
>> with an advice.* configuration variable.
>
> I'm not sure we have one for cherry-pick/revert/rebase. At the moment
> they print advice advice for a failed pick unconditionally...

Yes, 1/5 does not introduce a new problem; it just makes it worse by
allowing the misdesign survive another update.  The one introduced
by 4/5 is genuinely new.

> ... Maybe that
> should be checking advice.resolveConflict though.

I think that is a sensible one, rather than inventing a new knob.


^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [GSoC][PATCH v5 4/5] cherry-pick/revert: add --skip option
  2019-06-20 11:42         ` Phillip Wood
@ 2019-06-21  7:47           ` Rohit Ashiwal
  0 siblings, 0 replies; 87+ messages in thread
From: Rohit Ashiwal @ 2019-06-21  7:47 UTC (permalink / raw)
  To: phillip.wood123
  Cc: git, gitster, jrnieder, martin.agren, newren, phillip.wood,
	rohit.ashiwal265, t.gummerer

Hi Phillip

On 2019-06-20 11:42 UTC Phillip Wood <phillip.wood123@gmail.com> wrote:
>
> Hi Rohit
>
> On 20/06/2019 11:34, Rohit Ashiwal wrote:
>> Hi Phillip
>>
>> On 2019-06-20 10:02 UTC Phillip Wood <phillip.wood123@gmail.com> wrote:
>>>
>>>> +test_expect_success 'allow skipping stopped cherry-pick because of untracked file modifications' '
>>>> +	pristine_detach initial &&
>>>> +	git rm --cached unrelated &&
>>>> +	git commit -m "untrack unrelated" &&
>>>> +	test_must_fail git cherry-pick initial base &&
>>>> +	test_path_is_missing .git/CHERRY_PICK_HEAD &&
>>>> +	git cherry-pick --skip
>>>
>>> If you change this to --continue rather than --skip the test also
>>> passes! I think we could fix this by checking if HEAD has changed if
>>> CHERRY_PICK_HEAD/REVERT_HEAD is missing and not dropping the last
>>> command in the todo list in that case when we continue.
>>
>> I don't think I fully understood this. At this point --skip is essentially
>> --continue. How is checking unmoved HEAD and unchanged todo uniquely related
>> to --skip flag (or for that matter any _flag_)?
>
> My point is that --continue should reschedule the failed pick and try to
> pick it again - it should not silently skip a failed pick and  --skip
> should skip it.

So, this is a flaw in the --continue, I guess? Fixing that is beyond the
scope of this patch. May be we can launch another series in which we fix
this and decouple skip and continue?

Thanks
Rohit


^ permalink raw reply	[flat|nested] 87+ messages in thread

* [GSoC][PATCH v6 0/5] Teach cherry-pick/revert to skip commits
  2019-06-08 19:19 [GSoC][PATCH 0/3] Teach cherry-pick/revert to skip commits Rohit Ashiwal
                   ` (7 preceding siblings ...)
  2019-06-18 17:06 ` [GSoC][PATCH v5 0/5] " Rohit Ashiwal
@ 2019-06-21  9:17 ` Rohit Ashiwal
  2019-06-21  9:17   ` [GSoC][PATCH v6 1/5] sequencer: add advice for revert Rohit Ashiwal
                     ` (5 more replies)
  2019-06-23 20:03 ` [GSoC][PATCH v7 0/6] " Rohit Ashiwal
  9 siblings, 6 replies; 87+ messages in thread
From: Rohit Ashiwal @ 2019-06-21  9:17 UTC (permalink / raw)
  To: rohit.ashiwal265
  Cc: git, newren, t.gummerer, phillip.wood123, gitster, jrnieder,
	martin.agren

I've covered the advice message behind `advice_resolve_conflict` variable and
changed the order of error and advice to match that of 1/5. I believe that we
don't have any advice variable appropriate for advice in 1/5.

Rohit Ashiwal (5):
  sequencer: add advice for revert
  sequencer: rename reset_for_rollback to reset_merge
  sequencer: use argv_array in reset_merge
  cherry-pick/revert: add --skip option
  cherry-pick/revert: advise using --skip

 Documentation/git-cherry-pick.txt |   4 +-
 Documentation/git-revert.txt      |   4 +-
 Documentation/sequencer.txt       |   4 +
 builtin/commit.c                  |  13 +--
 builtin/revert.c                  |   5 ++
 sequencer.c                       | 135 ++++++++++++++++++++++++++----
 sequencer.h                       |   1 +
 t/t3510-cherry-pick-sequence.sh   | 122 +++++++++++++++++++++++++++
 8 files changed, 262 insertions(+), 26 deletions(-)

Range-diff:
1:  825486c22d ! 1:  2b16d7ea4d cherry-pick/revert: add --skip option
    @@ -168,10 +168,14 @@
     +	return sequencer_continue(r, opts);
     +
     +give_advice:
    -+	advise(_("have you committed already?\n"
    -+		 "try \"git %s --continue\""),
    -+		 action == REPLAY_REVERT ? "revert" : "cherry-pick");
    -+	return error(_("there is nothing to skip"));
    ++	error(_("there is nothing to skip"));
    ++
    ++	if (advice_resolve_conflict) {
    ++		advise(_("have you committed already?\n"
    ++			 "try \"git %s --continue\""),
    ++			 action == REPLAY_REVERT ? "revert" : "cherry-pick");
    ++	}
    ++	return -1;
     +}
     +
      static int save_todo(struct todo_list *todo_list, struct replay_opts *opts)
    @@ -263,9 +267,9 @@
     +test_expect_success 'check advice when we move HEAD by committing' '
     +	pristine_detach initial &&
     +	cat >expect <<-EOF &&
    ++	error: there is nothing to skip
     +	hint: have you committed already?
     +	hint: try "git cherry-pick --continue"
    -+	error: there is nothing to skip
     +	fatal: cherry-pick failed
     +	EOF
     +	test_must_fail git cherry-pick base..yetanotherpick &&
2:  63dbc11ab1 = 2:  8f278b5139 cherry-pick/revert: advise using --skip
-- 
2.21.0


^ permalink raw reply	[flat|nested] 87+ messages in thread

* [GSoC][PATCH v6 1/5] sequencer: add advice for revert
  2019-06-21  9:17 ` [GSoC][PATCH v6 0/5] Teach cherry-pick/revert to skip commits Rohit Ashiwal
@ 2019-06-21  9:17   ` Rohit Ashiwal
  2019-06-21  9:17   ` [GSoC][PATCH v6 2/5] sequencer: rename reset_for_rollback to reset_merge Rohit Ashiwal
                     ` (4 subsequent siblings)
  5 siblings, 0 replies; 87+ messages in thread
From: Rohit Ashiwal @ 2019-06-21  9:17 UTC (permalink / raw)
  To: rohit.ashiwal265
  Cc: git, newren, t.gummerer, phillip.wood123, gitster, jrnieder,
	martin.agren

In the case of merge conflicts, while performing a revert, we are
currently advised to use `git cherry-pick --<sequencer-options>`
of which --continue is incompatible for continuing the revert.
Introduce a separate advice message for `git revert`. Also change
the signature of `create_seq_dir` to handle which advice to display
selectively.

Signed-off-by: Rohit Ashiwal <rohit.ashiwal265@gmail.com>
---
 sequencer.c | 34 ++++++++++++++++++++++++++++------
 1 file changed, 28 insertions(+), 6 deletions(-)

diff --git a/sequencer.c b/sequencer.c
index f88a97fb10..c644368b54 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -2650,15 +2650,37 @@ static int walk_revs_populate_todo(struct todo_list *todo_list,
 	return 0;
 }
 
-static int create_seq_dir(void)
+static int create_seq_dir(struct repository *r)
 {
-	if (file_exists(git_path_seq_dir())) {
-		error(_("a cherry-pick or revert is already in progress"));
-		advise(_("try \"git cherry-pick (--continue | --quit | --abort)\""));
+	enum replay_action action;
+	const char *in_progress_error = NULL;
+	const char *in_progress_advice = NULL;
+
+	if (!sequencer_get_last_command(r, &action)) {
+		switch (action) {
+		case REPLAY_REVERT:
+			in_progress_error = _("revert is already in progress");
+			in_progress_advice =
+			_("try \"git revert (--continue | --abort | --quit)\"");
+			break;
+		case REPLAY_PICK:
+			in_progress_error = _("cherry-pick is already in progress");
+			in_progress_advice =
+			_("try \"git cherry-pick (--continue | --abort | --quit)\"");
+			break;
+		default:
+			BUG("unexpected action in create_seq_dir");
+		}
+	}
+	if (in_progress_error) {
+		error("%s", in_progress_error);
+		advise("%s", in_progress_advice);
 		return -1;
-	} else if (mkdir(git_path_seq_dir(), 0777) < 0)
+	}
+	if (mkdir(git_path_seq_dir(), 0777) < 0)
 		return error_errno(_("could not create sequencer directory '%s'"),
 				   git_path_seq_dir());
+
 	return 0;
 }
 
@@ -4237,7 +4259,7 @@ int sequencer_pick_revisions(struct repository *r,
 	 */
 
 	if (walk_revs_populate_todo(&todo_list, opts) ||
-			create_seq_dir() < 0)
+			create_seq_dir(r) < 0)
 		return -1;
 	if (get_oid("HEAD", &oid) && (opts->action == REPLAY_REVERT))
 		return error(_("can't revert as initial commit"));
-- 
2.21.0


^ permalink raw reply	[flat|nested] 87+ messages in thread

* [GSoC][PATCH v6 2/5] sequencer: rename reset_for_rollback to reset_merge
  2019-06-21  9:17 ` [GSoC][PATCH v6 0/5] Teach cherry-pick/revert to skip commits Rohit Ashiwal
  2019-06-21  9:17   ` [GSoC][PATCH v6 1/5] sequencer: add advice for revert Rohit Ashiwal
@ 2019-06-21  9:17   ` Rohit Ashiwal
  2019-06-21  9:17   ` [GSoC][PATCH v6 3/5] sequencer: use argv_array in reset_merge Rohit Ashiwal
                     ` (3 subsequent siblings)
  5 siblings, 0 replies; 87+ messages in thread
From: Rohit Ashiwal @ 2019-06-21  9:17 UTC (permalink / raw)
  To: rohit.ashiwal265
  Cc: git, newren, t.gummerer, phillip.wood123, gitster, jrnieder,
	martin.agren

We are on a path to teach cherry-pick/revert how to skip commits. To
achieve this, we could really make use of existing functions.
reset_for_rollback is one such function, but the name does not
intuitively suggest to use it to reset a merge, which it was born to
perform see 539047c ("revert: introduce --abort to cancel a failed
cherry-pick", 2011-11-23). Change the name to reset_merge to make
it more intuitive.

Signed-off-by: Rohit Ashiwal <rohit.ashiwal265@gmail.com>
---
 sequencer.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/sequencer.c b/sequencer.c
index c644368b54..12f2605ded 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -2731,7 +2731,7 @@ static int rollback_is_safe(void)
 	return oideq(&actual_head, &expected_head);
 }
 
-static int reset_for_rollback(const struct object_id *oid)
+static int reset_merge(const struct object_id *oid)
 {
 	const char *argv[4];	/* reset --merge <arg> + NULL */
 
@@ -2753,7 +2753,7 @@ static int rollback_single_pick(struct repository *r)
 		return error(_("cannot resolve HEAD"));
 	if (is_null_oid(&head_oid))
 		return error(_("cannot abort from a branch yet to be born"));
-	return reset_for_rollback(&head_oid);
+	return reset_merge(&head_oid);
 }
 
 int sequencer_rollback(struct repository *r, struct replay_opts *opts)
@@ -2796,7 +2796,7 @@ int sequencer_rollback(struct repository *r, struct replay_opts *opts)
 		warning(_("You seem to have moved HEAD. "
 			  "Not rewinding, check your HEAD!"));
 	} else
-	if (reset_for_rollback(&oid))
+	if (reset_merge(&oid))
 		goto fail;
 	strbuf_release(&buf);
 	return sequencer_remove_state(opts);
-- 
2.21.0


^ permalink raw reply	[flat|nested] 87+ messages in thread

* [GSoC][PATCH v6 3/5] sequencer: use argv_array in reset_merge
  2019-06-21  9:17 ` [GSoC][PATCH v6 0/5] Teach cherry-pick/revert to skip commits Rohit Ashiwal
  2019-06-21  9:17   ` [GSoC][PATCH v6 1/5] sequencer: add advice for revert Rohit Ashiwal
  2019-06-21  9:17   ` [GSoC][PATCH v6 2/5] sequencer: rename reset_for_rollback to reset_merge Rohit Ashiwal
@ 2019-06-21  9:17   ` Rohit Ashiwal
  2019-06-21  9:17   ` [GSoC][PATCH v6 4/5] cherry-pick/revert: add --skip option Rohit Ashiwal
                     ` (2 subsequent siblings)
  5 siblings, 0 replies; 87+ messages in thread
From: Rohit Ashiwal @ 2019-06-21  9:17 UTC (permalink / raw)
  To: rohit.ashiwal265
  Cc: git, newren, t.gummerer, phillip.wood123, gitster, jrnieder,
	martin.agren

Avoid using magic numbers for array size and index under `reset_merge`
function. Use `argv_array` instead. This will make code shorter and
easier to extend.

Signed-off-by: Rohit Ashiwal <rohit.ashiwal265@gmail.com>
---
 sequencer.c | 17 +++++++++++------
 1 file changed, 11 insertions(+), 6 deletions(-)

diff --git a/sequencer.c b/sequencer.c
index 12f2605ded..6762a5f485 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -2733,13 +2733,18 @@ static int rollback_is_safe(void)
 
 static int reset_merge(const struct object_id *oid)
 {
-	const char *argv[4];	/* reset --merge <arg> + NULL */
+	int ret;
+	struct argv_array argv = ARGV_ARRAY_INIT;
 
-	argv[0] = "reset";
-	argv[1] = "--merge";
-	argv[2] = oid_to_hex(oid);
-	argv[3] = NULL;
-	return run_command_v_opt(argv, RUN_GIT_CMD);
+	argv_array_pushl(&argv, "reset", "--merge", NULL);
+
+	if (!is_null_oid(oid))
+		argv_array_push(&argv, oid_to_hex(oid));
+
+	ret = run_command_v_opt(argv.argv, RUN_GIT_CMD);
+	argv_array_clear(&argv);
+
+	return ret;
 }
 
 static int rollback_single_pick(struct repository *r)
-- 
2.21.0


^ permalink raw reply	[flat|nested] 87+ messages in thread

* [GSoC][PATCH v6 4/5] cherry-pick/revert: add --skip option
  2019-06-21  9:17 ` [GSoC][PATCH v6 0/5] Teach cherry-pick/revert to skip commits Rohit Ashiwal
                     ` (2 preceding siblings ...)
  2019-06-21  9:17   ` [GSoC][PATCH v6 3/5] sequencer: use argv_array in reset_merge Rohit Ashiwal
@ 2019-06-21  9:17   ` Rohit Ashiwal
  2019-06-21  9:18   ` [GSoC][PATCH v6 5/5] cherry-pick/revert: advise using --skip Rohit Ashiwal
  2019-06-21 19:09   ` [GSoC][PATCH v6 0/5] Teach cherry-pick/revert to skip commits Junio C Hamano
  5 siblings, 0 replies; 87+ messages in thread
From: Rohit Ashiwal @ 2019-06-21  9:17 UTC (permalink / raw)
  To: rohit.ashiwal265
  Cc: git, newren, t.gummerer, phillip.wood123, gitster, jrnieder,
	martin.agren

git am or rebase have a --skip flag to skip the current commit if the
user wishes to do so. During a cherry-pick or revert a user could
likewise skip a commit, but needs to use 'git reset' (or in the case
of conflicts 'git reset --merge'), followed by 'git (cherry-pick |
revert) --continue' to skip the commit. This is more annoying and
sometimes confusing on the users' part. Add a `--skip` option to make
skipping commits easier for the user and to make the commands more
consistent.

In the next commit, we will change the advice messages hence finishing
the process of teaching revert and cherry-pick "how to skip commits".

Signed-off-by: Rohit Ashiwal <rohit.ashiwal265@gmail.com>
---
 Documentation/git-cherry-pick.txt |   4 +-
 Documentation/git-revert.txt      |   4 +-
 Documentation/sequencer.txt       |   4 ++
 builtin/revert.c                  |   5 ++
 sequencer.c                       |  73 +++++++++++++++++++++
 sequencer.h                       |   1 +
 t/t3510-cherry-pick-sequence.sh   | 102 ++++++++++++++++++++++++++++++
 7 files changed, 187 insertions(+), 6 deletions(-)

diff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt
index 754b16ce0c..83ce51aedf 100644
--- a/Documentation/git-cherry-pick.txt
+++ b/Documentation/git-cherry-pick.txt
@@ -10,9 +10,7 @@ SYNOPSIS
 [verse]
 'git cherry-pick' [--edit] [-n] [-m parent-number] [-s] [-x] [--ff]
 		  [-S[<keyid>]] <commit>...
-'git cherry-pick' --continue
-'git cherry-pick' --quit
-'git cherry-pick' --abort
+'git cherry-pick' (--continue | --skip | --abort | --quit)
 
 DESCRIPTION
 -----------
diff --git a/Documentation/git-revert.txt b/Documentation/git-revert.txt
index 0c82ca5bc0..665e065ee3 100644
--- a/Documentation/git-revert.txt
+++ b/Documentation/git-revert.txt
@@ -9,9 +9,7 @@ SYNOPSIS
 --------
 [verse]
 'git revert' [--[no-]edit] [-n] [-m parent-number] [-s] [-S[<keyid>]] <commit>...
-'git revert' --continue
-'git revert' --quit
-'git revert' --abort
+'git revert' (--continue | --skip | --abort | --quit)
 
 DESCRIPTION
 -----------
diff --git a/Documentation/sequencer.txt b/Documentation/sequencer.txt
index 5a57c4a407..3bceb56474 100644
--- a/Documentation/sequencer.txt
+++ b/Documentation/sequencer.txt
@@ -3,6 +3,10 @@
 	`.git/sequencer`.  Can be used to continue after resolving
 	conflicts in a failed cherry-pick or revert.
 
+--skip::
+	Skip the current commit and continue with the rest of the
+	sequence.
+
 --quit::
 	Forget about the current operation in progress.  Can be used
 	to clear the sequencer state after a failed cherry-pick or
diff --git a/builtin/revert.c b/builtin/revert.c
index d4dcedbdc6..5dc5891ea2 100644
--- a/builtin/revert.c
+++ b/builtin/revert.c
@@ -102,6 +102,7 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)
 		OPT_CMDMODE(0, "quit", &cmd, N_("end revert or cherry-pick sequence"), 'q'),
 		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_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")),
@@ -151,6 +152,8 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)
 			this_operation = "--quit";
 		else if (cmd == 'c')
 			this_operation = "--continue";
+		else if (cmd == 's')
+			this_operation = "--skip";
 		else {
 			assert(cmd == 'a');
 			this_operation = "--abort";
@@ -210,6 +213,8 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)
 		return sequencer_continue(the_repository, opts);
 	if (cmd == 'a')
 		return sequencer_rollback(the_repository, opts);
+	if (cmd == 's')
+		return sequencer_skip(the_repository, opts);
 	return sequencer_pick_revisions(the_repository, opts);
 }
 
diff --git a/sequencer.c b/sequencer.c
index 6762a5f485..c62f7a33aa 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -2761,6 +2761,15 @@ static int rollback_single_pick(struct repository *r)
 	return reset_merge(&head_oid);
 }
 
+static int skip_single_pick(void)
+{
+	struct object_id head;
+
+	if (read_ref_full("HEAD", 0, &head, NULL))
+		return error(_("cannot resolve HEAD"));
+	return reset_merge(&head);
+}
+
 int sequencer_rollback(struct repository *r, struct replay_opts *opts)
 {
 	FILE *f;
@@ -2810,6 +2819,70 @@ int sequencer_rollback(struct repository *r, struct replay_opts *opts)
 	return -1;
 }
 
+int sequencer_skip(struct repository *r, struct replay_opts *opts)
+{
+	enum replay_action action = -1;
+	sequencer_get_last_command(r, &action);
+
+	/*
+	 * Check whether the subcommand requested to skip the commit is actually
+	 * in progress and that it's safe to skip the commit.
+	 *
+	 * opts->action tells us which subcommand requested to skip the commit.
+	 * If the corresponding .git/<ACTION>_HEAD exists, we know that the
+	 * action is in progress and we can skip the commit.
+	 *
+	 * Otherwise we check that the last instruction was related to the
+	 * particular subcommand we're trying to execute and barf if that's not
+	 * the case.
+	 *
+	 * Finally we check that the rollback is "safe", i.e., has the HEAD
+	 * moved? In this case, it doesn't make sense to "reset the merge" and
+	 * "skip the commit" as the user already handled this by committing. But
+	 * we'd not want to barf here, instead give advice on how to proceed. We
+	 * only need to check that when .git/<ACTION>_HEAD doesn't exist because
+	 * it gets removed when the user commits, so if it still exists we're
+	 * sure the user can't have committed before.
+	 */
+	switch (opts->action) {
+	case REPLAY_REVERT:
+		if (!file_exists(git_path_revert_head(r))) {
+			if (action != REPLAY_REVERT)
+				return error(_("no revert in progress"));
+			if (!rollback_is_safe())
+				goto give_advice;
+		}
+		break;
+	case REPLAY_PICK:
+		if (!file_exists(git_path_cherry_pick_head(r))) {
+			if (action != REPLAY_PICK)
+				return error(_("no cherry-pick in progress"));
+			if (!rollback_is_safe())
+				goto give_advice;
+		}
+		break;
+	default:
+		BUG("unexpected action in sequencer_skip");
+	}
+
+	if (skip_single_pick())
+		return error(_("failed to skip the commit"));
+	if (!is_directory(git_path_seq_dir()))
+		return 0;
+
+	return sequencer_continue(r, opts);
+
+give_advice:
+	error(_("there is nothing to skip"));
+
+	if (advice_resolve_conflict) {
+		advise(_("have you committed already?\n"
+			 "try \"git %s --continue\""),
+			 action == REPLAY_REVERT ? "revert" : "cherry-pick");
+	}
+	return -1;
+}
+
 static int save_todo(struct todo_list *todo_list, struct replay_opts *opts)
 {
 	struct lock_file todo_lock = LOCK_INIT;
diff --git a/sequencer.h b/sequencer.h
index 0c494b83d4..731b9853eb 100644
--- a/sequencer.h
+++ b/sequencer.h
@@ -129,6 +129,7 @@ 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_skip(struct repository *repo, struct replay_opts *opts);
 int sequencer_remove_state(struct replay_opts *opts);
 
 #define TODO_LIST_KEEP_EMPTY (1U << 0)
diff --git a/t/t3510-cherry-pick-sequence.sh b/t/t3510-cherry-pick-sequence.sh
index 941d5026da..20515ea37b 100755
--- a/t/t3510-cherry-pick-sequence.sh
+++ b/t/t3510-cherry-pick-sequence.sh
@@ -93,6 +93,108 @@ test_expect_success 'cherry-pick cleans up sequencer state upon success' '
 	test_path_is_missing .git/sequencer
 '
 
+test_expect_success 'cherry-pick --skip requires cherry-pick in progress' '
+	pristine_detach initial &&
+	test_must_fail git cherry-pick --skip
+'
+
+test_expect_success 'revert --skip requires revert in progress' '
+	pristine_detach initial &&
+	test_must_fail git revert --skip
+'
+
+test_expect_success 'cherry-pick --skip to skip commit' '
+	pristine_detach initial &&
+	test_must_fail git cherry-pick anotherpick &&
+	test_must_fail git revert --skip &&
+	git cherry-pick --skip &&
+	test_cmp_rev initial HEAD &&
+	test_path_is_missing .git/CHERRY_PICK_HEAD
+'
+
+test_expect_success 'revert --skip to skip commit' '
+	pristine_detach anotherpick &&
+	test_must_fail git revert anotherpick~1 &&
+	test_must_fail git cherry-pick --skip &&
+	git revert --skip &&
+	test_cmp_rev anotherpick HEAD
+'
+
+test_expect_success 'skip "empty" commit' '
+	pristine_detach picked &&
+	test_commit dummy foo d &&
+	test_must_fail git cherry-pick anotherpick &&
+	git cherry-pick --skip &&
+	test_cmp_rev dummy HEAD
+'
+
+test_expect_success 'skip a commit and check if rest of sequence is correct' '
+	pristine_detach initial &&
+	echo e >expect &&
+	cat >expect.log <<-EOF &&
+	OBJID
+	:100644 100644 OBJID OBJID M	foo
+	OBJID
+	:100644 100644 OBJID OBJID M	foo
+	OBJID
+	:100644 100644 OBJID OBJID M	unrelated
+	OBJID
+	:000000 100644 OBJID OBJID A	foo
+	:000000 100644 OBJID OBJID A	unrelated
+	EOF
+	test_must_fail git cherry-pick base..yetanotherpick &&
+	test_must_fail git cherry-pick --skip &&
+	echo d >foo &&
+	git add foo &&
+	git cherry-pick --continue &&
+	{
+		git rev-list HEAD |
+		git diff-tree --root --stdin |
+		sed "s/$OID_REGEX/OBJID/g"
+	} >actual.log &&
+	test_cmp expect foo &&
+	test_cmp expect.log actual.log
+'
+
+test_expect_success 'check advice when we move HEAD by committing' '
+	pristine_detach initial &&
+	cat >expect <<-EOF &&
+	error: there is nothing to skip
+	hint: have you committed already?
+	hint: try "git cherry-pick --continue"
+	fatal: cherry-pick failed
+	EOF
+	test_must_fail git cherry-pick base..yetanotherpick &&
+	echo c >foo &&
+	git commit -a &&
+	test_path_is_missing .git/CHERRY_PICK_HEAD &&
+	test_must_fail git cherry-pick --skip 2>advice &&
+	test_i18ncmp expect advice
+'
+
+test_expect_success 'allow skipping commit but not abort for a new history' '
+	pristine_detach initial &&
+	cat >expect <<-EOF &&
+	error: cannot abort from a branch yet to be born
+	fatal: cherry-pick failed
+	EOF
+	git checkout --orphan new_disconnected &&
+	git reset --hard &&
+	test_must_fail git cherry-pick anotherpick &&
+	test_must_fail git cherry-pick --abort 2>advice &&
+	git cherry-pick --skip &&
+	test_i18ncmp expect advice
+'
+
+test_expect_success 'allow skipping stopped cherry-pick because of untracked file modifications' '
+	pristine_detach initial &&
+	git rm --cached unrelated &&
+	git commit -m "untrack unrelated" &&
+	test_must_fail git cherry-pick initial base &&
+	test_path_is_missing .git/CHERRY_PICK_HEAD &&
+	git cherry-pick --skip
+'
+
 test_expect_success '--quit does not complain when no cherry-pick is in progress' '
 	pristine_detach initial &&
 	git cherry-pick --quit
-- 
2.21.0


^ permalink raw reply	[flat|nested] 87+ messages in thread

* [GSoC][PATCH v6 5/5] cherry-pick/revert: advise using --skip
  2019-06-21  9:17 ` [GSoC][PATCH v6 0/5] Teach cherry-pick/revert to skip commits Rohit Ashiwal
                     ` (3 preceding siblings ...)
  2019-06-21  9:17   ` [GSoC][PATCH v6 4/5] cherry-pick/revert: add --skip option Rohit Ashiwal
@ 2019-06-21  9:18   ` Rohit Ashiwal
  2019-06-21 19:09   ` [GSoC][PATCH v6 0/5] Teach cherry-pick/revert to skip commits Junio C Hamano
  5 siblings, 0 replies; 87+ messages in thread
From: Rohit Ashiwal @ 2019-06-21  9:18 UTC (permalink / raw)
  To: rohit.ashiwal265
  Cc: git, newren, t.gummerer, phillip.wood123, gitster, jrnieder,
	martin.agren

The previous commit introduced a --skip flag for cherry-pick and
revert. Update the advice messages, to tell users about this less
cumbersome way of skipping commits. Also add tests to ensure
everything is working fine.

Signed-off-by: Rohit Ashiwal <rohit.ashiwal265@gmail.com>
---
 builtin/commit.c                | 13 ++++++++-----
 sequencer.c                     | 11 ++++++++---
 t/t3510-cherry-pick-sequence.sh | 20 ++++++++++++++++++++
 3 files changed, 36 insertions(+), 8 deletions(-)

diff --git a/builtin/commit.c b/builtin/commit.c
index 1c9e8e2228..1f47c51bdc 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -60,15 +60,18 @@ N_("The previous cherry-pick is now empty, possibly due to conflict resolution.\
 "\n");
 
 static const char empty_cherry_pick_advice_single[] =
-N_("Otherwise, please use 'git reset'\n");
+N_("Otherwise, please use 'git cherry-pick --skip'\n");
 
 static const char empty_cherry_pick_advice_multi[] =
-N_("If you wish to skip this commit, use:\n"
+N_("and then use:\n"
 "\n"
-"    git reset\n"
+"    git cherry-pick --continue\n"
 "\n"
-"Then \"git cherry-pick --continue\" will resume cherry-picking\n"
-"the remaining commits.\n");
+"to resume cherry-picking the remaining commits.\n"
+"If you wish to skip this commit, use:\n"
+"\n"
+"    git cherry-pick --skip\n"
+"\n");
 
 static const char *color_status_slots[] = {
 	[WT_STATUS_HEADER]	  = "header",
diff --git a/sequencer.c b/sequencer.c
index c62f7a33aa..98f3537dfc 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -2655,18 +2655,20 @@ static int create_seq_dir(struct repository *r)
 	enum replay_action action;
 	const char *in_progress_error = NULL;
 	const char *in_progress_advice = NULL;
+	unsigned int advise_skip = file_exists(git_path_revert_head(r)) ||
+				file_exists(git_path_cherry_pick_head(r));
 
 	if (!sequencer_get_last_command(r, &action)) {
 		switch (action) {
 		case REPLAY_REVERT:
 			in_progress_error = _("revert is already in progress");
 			in_progress_advice =
-			_("try \"git revert (--continue | --abort | --quit)\"");
+			_("try \"git revert (--continue | %s--abort | --quit)\"");
 			break;
 		case REPLAY_PICK:
 			in_progress_error = _("cherry-pick is already in progress");
 			in_progress_advice =
-			_("try \"git cherry-pick (--continue | --abort | --quit)\"");
+			_("try \"git cherry-pick (--continue | %s--abort | --quit)\"");
 			break;
 		default:
 			BUG("unexpected action in create_seq_dir");
@@ -2674,7 +2676,10 @@ static int create_seq_dir(struct repository *r)
 	}
 	if (in_progress_error) {
 		error("%s", in_progress_error);
-		advise("%s", in_progress_advice);
+		if (advise_skip)
+			advise(in_progress_advice, "--skip | ");
+		else
+			advise(in_progress_advice, "");
 		return -1;
 	}
 	if (mkdir(git_path_seq_dir(), 0777) < 0)
diff --git a/t/t3510-cherry-pick-sequence.sh b/t/t3510-cherry-pick-sequence.sh
index 20515ea37b..793bcc7fe3 100755
--- a/t/t3510-cherry-pick-sequence.sh
+++ b/t/t3510-cherry-pick-sequence.sh
@@ -172,6 +172,26 @@ test_expect_success 'check advice when we move HEAD by committing' '
 	test_i18ncmp expect advice
 '
 
+test_expect_success 'selectively advise --skip while launching another sequence' '
+	pristine_detach initial &&
+	cat >expect <<-EOF &&
+	error: cherry-pick is already in progress
+	hint: try "git cherry-pick (--continue | --skip | --abort | --quit)"
+	fatal: cherry-pick failed
+	EOF
+	test_must_fail git cherry-pick picked..yetanotherpick &&
+	test_must_fail git cherry-pick picked..yetanotherpick 2>advice &&
+	test_i18ncmp expect advice &&
+	cat >expect <<-EOF &&
+	error: cherry-pick is already in progress
+	hint: try "git cherry-pick (--continue | --abort | --quit)"
+	fatal: cherry-pick failed
+	EOF
+	git reset --merge &&
+	test_must_fail git cherry-pick picked..yetanotherpick 2>advice &&
+	test_i18ncmp expect advice
+'
+
 test_expect_success 'allow skipping commit but not abort for a new history' '
 	pristine_detach initial &&
 	cat >expect <<-EOF &&
-- 
2.21.0


^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [GSoC][PATCH v6 0/5] Teach cherry-pick/revert to skip commits
  2019-06-21  9:17 ` [GSoC][PATCH v6 0/5] Teach cherry-pick/revert to skip commits Rohit Ashiwal
                     ` (4 preceding siblings ...)
  2019-06-21  9:18   ` [GSoC][PATCH v6 5/5] cherry-pick/revert: advise using --skip Rohit Ashiwal
@ 2019-06-21 19:09   ` Junio C Hamano
  5 siblings, 0 replies; 87+ messages in thread
From: Junio C Hamano @ 2019-06-21 19:09 UTC (permalink / raw)
  To: Rohit Ashiwal
  Cc: git, newren, t.gummerer, phillip.wood123, jrnieder, martin.agren

Rohit Ashiwal <rohit.ashiwal265@gmail.com> writes:

> I've covered the advice message behind `advice_resolve_conflict` variable and
> changed the order of error and advice to match that of 1/5.

I think the updated text reads much better, i.e. taking from your
range-diff:

>      +	cat >expect <<-EOF &&
>     ++	error: there is nothing to skip
>      +	hint: have you committed already?
>      +	hint: try "git cherry-pick --continue"
>     -+	error: there is nothing to skip
>      +	fatal: cherry-pick failed
>      +	EOF

we say "why we failed" upfront with "error", and then for those who
would need more clues, we give "how you might want to proceed" as an
additionao "hint".  That looks more logical, besides being more
consistent with how advice messages are given in other codepaths.

> I believe that we
> don't have any advice variable appropriate for advice in 1/5.

If there is nothing, perhaps you would need to invent one.  Perhaps
"advice_sequencer_in_use" or something?

Other than that, looks quite good.  Will (re-)queue.


^ permalink raw reply	[flat|nested] 87+ messages in thread

* [GSoC][PATCH v7 0/6] Teach cherry-pick/revert to skip commits
  2019-06-08 19:19 [GSoC][PATCH 0/3] Teach cherry-pick/revert to skip commits Rohit Ashiwal
                   ` (8 preceding siblings ...)
  2019-06-21  9:17 ` [GSoC][PATCH v6 0/5] Teach cherry-pick/revert to skip commits Rohit Ashiwal
@ 2019-06-23 20:03 ` " Rohit Ashiwal
  2019-06-23 20:03   ` [GSoC][PATCH v7 1/6] advice: add sequencerInUse config variable Rohit Ashiwal
                     ` (5 more replies)
  9 siblings, 6 replies; 87+ messages in thread
From: Rohit Ashiwal @ 2019-06-23 20:03 UTC (permalink / raw)
  To: rohit.ashiwal265
  Cc: git, newren, t.gummerer, phillip.wood123, gitster, martin.agren

Tied all loose ends. Add an advice config variable to guard advise() call
in 2/6.

Rohit Ashiwal (6):
  advice: add sequencerInUse config variable
  sequencer: add advice for revert
  sequencer: rename reset_for_rollback to reset_merge
  sequencer: use argv_array in reset_merge
  cherry-pick/revert: add --skip option
  cherry-pick/revert: advise using --skip

 Documentation/config/advice.txt   |   2 +
 Documentation/git-cherry-pick.txt |   4 +-
 Documentation/git-revert.txt      |   4 +-
 Documentation/sequencer.txt       |   4 +
 advice.c                          |   2 +
 advice.h                          |   1 +
 builtin/commit.c                  |  13 +--
 builtin/revert.c                  |   5 ++
 sequencer.c                       | 134 ++++++++++++++++++++++++++----
 sequencer.h                       |   1 +
 t/t3510-cherry-pick-sequence.sh   | 122 +++++++++++++++++++++++++++
 11 files changed, 266 insertions(+), 26 deletions(-)

Range-diff:
-:  ---------- > 1:  207042a895 advice: add sequencerInUse config variable
1:  67c212090d ! 2:  d7c603d47f sequencer: add advice for revert
    @@ -46,7 +46,8 @@
     +	}
     +	if (in_progress_error) {
     +		error("%s", in_progress_error);
    -+		advise("%s", in_progress_advice);
    ++		if (advice_sequencer_in_use)
    ++			advise("%s", in_progress_advice);
      		return -1;
     -	} else if (mkdir(git_path_seq_dir(), 0777) < 0)
     +	}
2:  300d6f64f0 = 3:  b70299c572 sequencer: rename reset_for_rollback to reset_merge
3:  edc35f6a4c = 4:  569122c861 sequencer: use argv_array in reset_merge
4:  2b16d7ea4d = 5:  4580f0e5af cherry-pick/revert: add --skip option
5:  8f278b5139 ! 6:  f6f21b055b cherry-pick/revert: advise using --skip
    @@ -64,14 +64,12 @@
      		default:
      			BUG("unexpected action in create_seq_dir");
     @@
    - 	}
      	if (in_progress_error) {
      		error("%s", in_progress_error);
    --		advise("%s", in_progress_advice);
    -+		if (advise_skip)
    -+			advise(in_progress_advice, "--skip | ");
    -+		else
    -+			advise(in_progress_advice, "");
    + 		if (advice_sequencer_in_use)
    +-			advise("%s", in_progress_advice);
    ++			advise(in_progress_advice,
    ++				advise_skip ? "--skip | " : "");
      		return -1;
      	}
      	if (mkdir(git_path_seq_dir(), 0777) < 0)
-- 
2.21.0


^ permalink raw reply	[flat|nested] 87+ messages in thread

* [GSoC][PATCH v7 1/6] advice: add sequencerInUse config variable
  2019-06-23 20:03 ` [GSoC][PATCH v7 0/6] " Rohit Ashiwal
@ 2019-06-23 20:03   ` Rohit Ashiwal
  2019-06-25  9:18     ` Thomas Gummerer
  2019-06-23 20:03   ` [GSoC][PATCH v7 2/6] sequencer: add advice for revert Rohit Ashiwal
                     ` (4 subsequent siblings)
  5 siblings, 1 reply; 87+ messages in thread
From: Rohit Ashiwal @ 2019-06-23 20:03 UTC (permalink / raw)
  To: rohit.ashiwal265
  Cc: git, newren, t.gummerer, phillip.wood123, gitster, martin.agren

Calls to advise() which are not guarded by advice.* config variables
are "bad" as they do not let the user say, "I've learned this part
of Git enough, please don't tell me what to do verbosely.". Add a
configuration variable "sequencerInUse" which controls whether to
display advice when any sequencer command is in progress.

Signed-off-by: Rohit Ashiwal <rohit.ashiwal265@gmail.com>
---
 Documentation/config/advice.txt | 2 ++
 advice.c                        | 2 ++
 advice.h                        | 1 +
 3 files changed, 5 insertions(+)

diff --git a/Documentation/config/advice.txt b/Documentation/config/advice.txt
index ec4f6ae658..1cd9096c98 100644
--- a/Documentation/config/advice.txt
+++ b/Documentation/config/advice.txt
@@ -57,6 +57,8 @@ advice.*::
 	resolveConflict::
 		Advice shown by various commands when conflicts
 		prevent the operation from being performed.
+	sequencerInUse::
+		Advice shown when a sequencer command is already in progress.
 	implicitIdentity::
 		Advice on how to set your identity configuration when
 		your information is guessed from the system username and
diff --git a/advice.c b/advice.c
index ce5f374ecd..b101f0c264 100644
--- a/advice.c
+++ b/advice.c
@@ -15,6 +15,7 @@ int advice_status_u_option = 1;
 int advice_commit_before_merge = 1;
 int advice_reset_quiet_warning = 1;
 int advice_resolve_conflict = 1;
+int advice_sequencer_in_use = 1;
 int advice_implicit_identity = 1;
 int advice_detached_head = 1;
 int advice_set_upstream_failure = 1;
@@ -71,6 +72,7 @@ static struct {
 	{ "commitBeforeMerge", &advice_commit_before_merge },
 	{ "resetQuiet", &advice_reset_quiet_warning },
 	{ "resolveConflict", &advice_resolve_conflict },
+	{ "sequencerInUse", &advice_sequencer_in_use },
 	{ "implicitIdentity", &advice_implicit_identity },
 	{ "detachedHead", &advice_detached_head },
 	{ "setupStreamFailure", &advice_set_upstream_failure },
diff --git a/advice.h b/advice.h
index e50f02cdfe..ebc838d7bc 100644
--- a/advice.h
+++ b/advice.h
@@ -15,6 +15,7 @@ extern int advice_status_u_option;
 extern int advice_commit_before_merge;
 extern int advice_reset_quiet_warning;
 extern int advice_resolve_conflict;
+extern int advice_sequencer_in_use;
 extern int advice_implicit_identity;
 extern int advice_detached_head;
 extern int advice_set_upstream_failure;
-- 
2.21.0


^ permalink raw reply	[flat|nested] 87+ messages in thread

* [GSoC][PATCH v7 2/6] sequencer: add advice for revert
  2019-06-23 20:03 ` [GSoC][PATCH v7 0/6] " Rohit Ashiwal
  2019-06-23 20:03   ` [GSoC][PATCH v7 1/6] advice: add sequencerInUse config variable Rohit Ashiwal
@ 2019-06-23 20:03   ` Rohit Ashiwal
  2019-06-23 20:03   ` [GSoC][PATCH v7 3/6] sequencer: rename reset_for_rollback to reset_merge Rohit Ashiwal
                     ` (3 subsequent siblings)
  5 siblings, 0 replies; 87+ messages in thread
From: Rohit Ashiwal @ 2019-06-23 20:03 UTC (permalink / raw)
  To: rohit.ashiwal265
  Cc: git, newren, t.gummerer, phillip.wood123, gitster, martin.agren

In the case of merge conflicts, while performing a revert, we are
currently advised to use `git cherry-pick --<sequencer-options>`
of which --continue is incompatible for continuing the revert.
Introduce a separate advice message for `git revert`. Also change
the signature of `create_seq_dir` to handle which advice to display
selectively.

Signed-off-by: Rohit Ashiwal <rohit.ashiwal265@gmail.com>
---
 sequencer.c | 35 +++++++++++++++++++++++++++++------
 1 file changed, 29 insertions(+), 6 deletions(-)

diff --git a/sequencer.c b/sequencer.c
index f88a97fb10..0ef2622a69 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -2650,15 +2650,38 @@ static int walk_revs_populate_todo(struct todo_list *todo_list,
 	return 0;
 }
 
-static int create_seq_dir(void)
+static int create_seq_dir(struct repository *r)
 {
-	if (file_exists(git_path_seq_dir())) {
-		error(_("a cherry-pick or revert is already in progress"));
-		advise(_("try \"git cherry-pick (--continue | --quit | --abort)\""));
+	enum replay_action action;
+	const char *in_progress_error = NULL;
+	const char *in_progress_advice = NULL;
+
+	if (!sequencer_get_last_command(r, &action)) {
+		switch (action) {
+		case REPLAY_REVERT:
+			in_progress_error = _("revert is already in progress");
+			in_progress_advice =
+			_("try \"git revert (--continue | --abort | --quit)\"");
+			break;
+		case REPLAY_PICK:
+			in_progress_error = _("cherry-pick is already in progress");
+			in_progress_advice =
+			_("try \"git cherry-pick (--continue | --abort | --quit)\"");
+			break;
+		default:
+			BUG("unexpected action in create_seq_dir");
+		}
+	}
+	if (in_progress_error) {
+		error("%s", in_progress_error);
+		if (advice_sequencer_in_use)
+			advise("%s", in_progress_advice);
 		return -1;
-	} else if (mkdir(git_path_seq_dir(), 0777) < 0)
+	}
+	if (mkdir(git_path_seq_dir(), 0777) < 0)
 		return error_errno(_("could not create sequencer directory '%s'"),
 				   git_path_seq_dir());
+
 	return 0;
 }
 
@@ -4237,7 +4260,7 @@ int sequencer_pick_revisions(struct repository *r,
 	 */
 
 	if (walk_revs_populate_todo(&todo_list, opts) ||
-			create_seq_dir() < 0)
+			create_seq_dir(r) < 0)
 		return -1;
 	if (get_oid("HEAD", &oid) && (opts->action == REPLAY_REVERT))
 		return error(_("can't revert as initial commit"));
-- 
2.21.0


^ permalink raw reply	[flat|nested] 87+ messages in thread

* [GSoC][PATCH v7 3/6] sequencer: rename reset_for_rollback to reset_merge
  2019-06-23 20:03 ` [GSoC][PATCH v7 0/6] " Rohit Ashiwal
  2019-06-23 20:03   ` [GSoC][PATCH v7 1/6] advice: add sequencerInUse config variable Rohit Ashiwal
  2019-06-23 20:03   ` [GSoC][PATCH v7 2/6] sequencer: add advice for revert Rohit Ashiwal
@ 2019-06-23 20:03   ` Rohit Ashiwal
  2019-06-23 20:03   ` [GSoC][PATCH v7 4/6] sequencer: use argv_array in reset_merge Rohit Ashiwal
                     ` (2 subsequent siblings)
  5 siblings, 0 replies; 87+ messages in thread
From: Rohit Ashiwal @ 2019-06-23 20:03 UTC (permalink / raw)
  To: rohit.ashiwal265
  Cc: git, newren, t.gummerer, phillip.wood123, gitster, martin.agren

We are on a path to teach cherry-pick/revert how to skip commits. To
achieve this, we could really make use of existing functions.
reset_for_rollback is one such function, but the name does not
intuitively suggest to use it to reset a merge, which it was born to
perform see 539047c ("revert: introduce --abort to cancel a failed
cherry-pick", 2011-11-23). Change the name to reset_merge to make
it more intuitive.

Signed-off-by: Rohit Ashiwal <rohit.ashiwal265@gmail.com>
---
 sequencer.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/sequencer.c b/sequencer.c
index 0ef2622a69..cb856bcfc3 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -2732,7 +2732,7 @@ static int rollback_is_safe(void)
 	return oideq(&actual_head, &expected_head);
 }
 
-static int reset_for_rollback(const struct object_id *oid)
+static int reset_merge(const struct object_id *oid)
 {
 	const char *argv[4];	/* reset --merge <arg> + NULL */
 
@@ -2754,7 +2754,7 @@ static int rollback_single_pick(struct repository *r)
 		return error(_("cannot resolve HEAD"));
 	if (is_null_oid(&head_oid))
 		return error(_("cannot abort from a branch yet to be born"));
-	return reset_for_rollback(&head_oid);
+	return reset_merge(&head_oid);
 }
 
 int sequencer_rollback(struct repository *r, struct replay_opts *opts)
@@ -2797,7 +2797,7 @@ int sequencer_rollback(struct repository *r, struct replay_opts *opts)
 		warning(_("You seem to have moved HEAD. "
 			  "Not rewinding, check your HEAD!"));
 	} else
-	if (reset_for_rollback(&oid))
+	if (reset_merge(&oid))
 		goto fail;
 	strbuf_release(&buf);
 	return sequencer_remove_state(opts);
-- 
2.21.0


^ permalink raw reply	[flat|nested] 87+ messages in thread

* [GSoC][PATCH v7 4/6] sequencer: use argv_array in reset_merge
  2019-06-23 20:03 ` [GSoC][PATCH v7 0/6] " Rohit Ashiwal
                     ` (2 preceding siblings ...)
  2019-06-23 20:03   ` [GSoC][PATCH v7 3/6] sequencer: rename reset_for_rollback to reset_merge Rohit Ashiwal
@ 2019-06-23 20:03   ` Rohit Ashiwal
  2019-06-23 20:03   ` [GSoC][PATCH v7 5/6] cherry-pick/revert: add --skip option Rohit Ashiwal
  2019-06-23 20:03   ` [GSoC][PATCH v7 6/6] cherry-pick/revert: advise using --skip Rohit Ashiwal
  5 siblings, 0 replies; 87+ messages in thread
From: Rohit Ashiwal @ 2019-06-23 20:03 UTC (permalink / raw)
  To: rohit.ashiwal265
  Cc: git, newren, t.gummerer, phillip.wood123, gitster, martin.agren

Avoid using magic numbers for array size and index under `reset_merge`
function. Use `argv_array` instead. This will make code shorter and
easier to extend.

Signed-off-by: Rohit Ashiwal <rohit.ashiwal265@gmail.com>
---
 sequencer.c | 17 +++++++++++------
 1 file changed, 11 insertions(+), 6 deletions(-)

diff --git a/sequencer.c b/sequencer.c
index cb856bcfc3..70efe36ee8 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -2734,13 +2734,18 @@ static int rollback_is_safe(void)
 
 static int reset_merge(const struct object_id *oid)
 {
-	const char *argv[4];	/* reset --merge <arg> + NULL */
+	int ret;
+	struct argv_array argv = ARGV_ARRAY_INIT;
 
-	argv[0] = "reset";
-	argv[1] = "--merge";
-	argv[2] = oid_to_hex(oid);
-	argv[3] = NULL;
-	return run_command_v_opt(argv, RUN_GIT_CMD);
+	argv_array_pushl(&argv, "reset", "--merge", NULL);
+
+	if (!is_null_oid(oid))
+		argv_array_push(&argv, oid_to_hex(oid));
+
+	ret = run_command_v_opt(argv.argv, RUN_GIT_CMD);
+	argv_array_clear(&argv);
+
+	return ret;
 }
 
 static int rollback_single_pick(struct repository *r)
-- 
2.21.0


^ permalink raw reply	[flat|nested] 87+ messages in thread

* [GSoC][PATCH v7 5/6] cherry-pick/revert: add --skip option
  2019-06-23 20:03 ` [GSoC][PATCH v7 0/6] " Rohit Ashiwal
                     ` (3 preceding siblings ...)
  2019-06-23 20:03   ` [GSoC][PATCH v7 4/6] sequencer: use argv_array in reset_merge Rohit Ashiwal
@ 2019-06-23 20:03   ` Rohit Ashiwal
  2019-06-23 20:03   ` [GSoC][PATCH v7 6/6] cherry-pick/revert: advise using --skip Rohit Ashiwal
  5 siblings, 0 replies; 87+ messages in thread
From: Rohit Ashiwal @ 2019-06-23 20:03 UTC (permalink / raw)
  To: rohit.ashiwal265
  Cc: git, newren, t.gummerer, phillip.wood123, gitster, martin.agren

git am or rebase have a --skip flag to skip the current commit if the
user wishes to do so. During a cherry-pick or revert a user could
likewise skip a commit, but needs to use 'git reset' (or in the case
of conflicts 'git reset --merge'), followed by 'git (cherry-pick |
revert) --continue' to skip the commit. This is more annoying and
sometimes confusing on the users' part. Add a `--skip` option to make
skipping commits easier for the user and to make the commands more
consistent.

In the next commit, we will change the advice messages hence finishing
the process of teaching revert and cherry-pick "how to skip commits".

Signed-off-by: Rohit Ashiwal <rohit.ashiwal265@gmail.com>
---
 Documentation/git-cherry-pick.txt |   4 +-
 Documentation/git-revert.txt      |   4 +-
 Documentation/sequencer.txt       |   4 ++
 builtin/revert.c                  |   5 ++
 sequencer.c                       |  73 +++++++++++++++++++++
 sequencer.h                       |   1 +
 t/t3510-cherry-pick-sequence.sh   | 102 ++++++++++++++++++++++++++++++
 7 files changed, 187 insertions(+), 6 deletions(-)

diff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt
index 754b16ce0c..83ce51aedf 100644
--- a/Documentation/git-cherry-pick.txt
+++ b/Documentation/git-cherry-pick.txt
@@ -10,9 +10,7 @@ SYNOPSIS
 [verse]
 'git cherry-pick' [--edit] [-n] [-m parent-number] [-s] [-x] [--ff]
 		  [-S[<keyid>]] <commit>...
-'git cherry-pick' --continue
-'git cherry-pick' --quit
-'git cherry-pick' --abort
+'git cherry-pick' (--continue | --skip | --abort | --quit)
 
 DESCRIPTION
 -----------
diff --git a/Documentation/git-revert.txt b/Documentation/git-revert.txt
index 0c82ca5bc0..665e065ee3 100644
--- a/Documentation/git-revert.txt
+++ b/Documentation/git-revert.txt
@@ -9,9 +9,7 @@ SYNOPSIS
 --------
 [verse]
 'git revert' [--[no-]edit] [-n] [-m parent-number] [-s] [-S[<keyid>]] <commit>...
-'git revert' --continue
-'git revert' --quit
-'git revert' --abort
+'git revert' (--continue | --skip | --abort | --quit)
 
 DESCRIPTION
 -----------
diff --git a/Documentation/sequencer.txt b/Documentation/sequencer.txt
index 5a57c4a407..3bceb56474 100644
--- a/Documentation/sequencer.txt
+++ b/Documentation/sequencer.txt
@@ -3,6 +3,10 @@
 	`.git/sequencer`.  Can be used to continue after resolving
 	conflicts in a failed cherry-pick or revert.
 
+--skip::
+	Skip the current commit and continue with the rest of the
+	sequence.
+
 --quit::
 	Forget about the current operation in progress.  Can be used
 	to clear the sequencer state after a failed cherry-pick or
diff --git a/builtin/revert.c b/builtin/revert.c
index d4dcedbdc6..5dc5891ea2 100644
--- a/builtin/revert.c
+++ b/builtin/revert.c
@@ -102,6 +102,7 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)
 		OPT_CMDMODE(0, "quit", &cmd, N_("end revert or cherry-pick sequence"), 'q'),
 		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_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")),
@@ -151,6 +152,8 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)
 			this_operation = "--quit";
 		else if (cmd == 'c')
 			this_operation = "--continue";
+		else if (cmd == 's')
+			this_operation = "--skip";
 		else {
 			assert(cmd == 'a');
 			this_operation = "--abort";
@@ -210,6 +213,8 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)
 		return sequencer_continue(the_repository, opts);
 	if (cmd == 'a')
 		return sequencer_rollback(the_repository, opts);
+	if (cmd == 's')
+		return sequencer_skip(the_repository, opts);
 	return sequencer_pick_revisions(the_repository, opts);
 }
 
diff --git a/sequencer.c b/sequencer.c
index 70efe36ee8..f5e3d60878 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -2762,6 +2762,15 @@ static int rollback_single_pick(struct repository *r)
 	return reset_merge(&head_oid);
 }
 
+static int skip_single_pick(void)
+{
+	struct object_id head;
+
+	if (read_ref_full("HEAD", 0, &head, NULL))
+		return error(_("cannot resolve HEAD"));
+	return reset_merge(&head);
+}
+
 int sequencer_rollback(struct repository *r, struct replay_opts *opts)
 {
 	FILE *f;
@@ -2811,6 +2820,70 @@ int sequencer_rollback(struct repository *r, struct replay_opts *opts)
 	return -1;
 }
 
+int sequencer_skip(struct repository *r, struct replay_opts *opts)
+{
+	enum replay_action action = -1;
+	sequencer_get_last_command(r, &action);
+
+	/*
+	 * Check whether the subcommand requested to skip the commit is actually
+	 * in progress and that it's safe to skip the commit.
+	 *
+	 * opts->action tells us which subcommand requested to skip the commit.
+	 * If the corresponding .git/<ACTION>_HEAD exists, we know that the
+	 * action is in progress and we can skip the commit.
+	 *
+	 * Otherwise we check that the last instruction was related to the
+	 * particular subcommand we're trying to execute and barf if that's not
+	 * the case.
+	 *
+	 * Finally we check that the rollback is "safe", i.e., has the HEAD
+	 * moved? In this case, it doesn't make sense to "reset the merge" and
+	 * "skip the commit" as the user already handled this by committing. But
+	 * we'd not want to barf here, instead give advice on how to proceed. We
+	 * only need to check that when .git/<ACTION>_HEAD doesn't exist because
+	 * it gets removed when the user commits, so if it still exists we're
+	 * sure the user can't have committed before.
+	 */
+	switch (opts->action) {
+	case REPLAY_REVERT:
+		if (!file_exists(git_path_revert_head(r))) {
+			if (action != REPLAY_REVERT)
+				return error(_("no revert in progress"));
+			if (!rollback_is_safe())
+				goto give_advice;
+		}
+		break;
+	case REPLAY_PICK:
+		if (!file_exists(git_path_cherry_pick_head(r))) {
+			if (action != REPLAY_PICK)
+				return error(_("no cherry-pick in progress"));
+			if (!rollback_is_safe())
+				goto give_advice;
+		}
+		break;
+	default:
+		BUG("unexpected action in sequencer_skip");
+	}
+
+	if (skip_single_pick())
+		return error(_("failed to skip the commit"));
+	if (!is_directory(git_path_seq_dir()))
+		return 0;
+
+	return sequencer_continue(r, opts);
+
+give_advice:
+	error(_("there is nothing to skip"));
+
+	if (advice_resolve_conflict) {
+		advise(_("have you committed already?\n"
+			 "try \"git %s --continue\""),
+			 action == REPLAY_REVERT ? "revert" : "cherry-pick");
+	}
+	return -1;
+}
+
 static int save_todo(struct todo_list *todo_list, struct replay_opts *opts)
 {
 	struct lock_file todo_lock = LOCK_INIT;
diff --git a/sequencer.h b/sequencer.h
index 0c494b83d4..731b9853eb 100644
--- a/sequencer.h
+++ b/sequencer.h
@@ -129,6 +129,7 @@ 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_skip(struct repository *repo, struct replay_opts *opts);
 int sequencer_remove_state(struct replay_opts *opts);
 
 #define TODO_LIST_KEEP_EMPTY (1U << 0)
diff --git a/t/t3510-cherry-pick-sequence.sh b/t/t3510-cherry-pick-sequence.sh
index 941d5026da..20515ea37b 100755
--- a/t/t3510-cherry-pick-sequence.sh
+++ b/t/t3510-cherry-pick-sequence.sh
@@ -93,6 +93,108 @@ test_expect_success 'cherry-pick cleans up sequencer state upon success' '
 	test_path_is_missing .git/sequencer
 '
 
+test_expect_success 'cherry-pick --skip requires cherry-pick in progress' '
+	pristine_detach initial &&
+	test_must_fail git cherry-pick --skip
+'
+
+test_expect_success 'revert --skip requires revert in progress' '
+	pristine_detach initial &&
+	test_must_fail git revert --skip
+'
+
+test_expect_success 'cherry-pick --skip to skip commit' '
+	pristine_detach initial &&
+	test_must_fail git cherry-pick anotherpick &&
+	test_must_fail git revert --skip &&
+	git cherry-pick --skip &&
+	test_cmp_rev initial HEAD &&
+	test_path_is_missing .git/CHERRY_PICK_HEAD
+'
+
+test_expect_success 'revert --skip to skip commit' '
+	pristine_detach anotherpick &&
+	test_must_fail git revert anotherpick~1 &&
+	test_must_fail git cherry-pick --skip &&
+	git revert --skip &&
+	test_cmp_rev anotherpick HEAD
+'
+
+test_expect_success 'skip "empty" commit' '
+	pristine_detach picked &&
+	test_commit dummy foo d &&
+	test_must_fail git cherry-pick anotherpick &&
+	git cherry-pick --skip &&
+	test_cmp_rev dummy HEAD
+'
+
+test_expect_success 'skip a commit and check if rest of sequence is correct' '
+	pristine_detach initial &&
+	echo e >expect &&
+	cat >expect.log <<-EOF &&
+	OBJID
+	:100644 100644 OBJID OBJID M	foo
+	OBJID
+	:100644 100644 OBJID OBJID M	foo
+	OBJID
+	:100644 100644 OBJID OBJID M	unrelated
+	OBJID
+	:000000 100644 OBJID OBJID A	foo
+	:000000 100644 OBJID OBJID A	unrelated
+	EOF
+	test_must_fail git cherry-pick base..yetanotherpick &&
+	test_must_fail git cherry-pick --skip &&
+	echo d >foo &&
+	git add foo &&
+	git cherry-pick --continue &&
+	{
+		git rev-list HEAD |
+		git diff-tree --root --stdin |
+		sed "s/$OID_REGEX/OBJID/g"
+	} >actual.log &&
+	test_cmp expect foo &&
+	test_cmp expect.log actual.log
+'
+
+test_expect_success 'check advice when we move HEAD by committing' '
+	pristine_detach initial &&
+	cat >expect <<-EOF &&
+	error: there is nothing to skip
+	hint: have you committed already?
+	hint: try "git cherry-pick --continue"
+	fatal: cherry-pick failed
+	EOF
+	test_must_fail git cherry-pick base..yetanotherpick &&
+	echo c >foo &&
+	git commit -a &&
+	test_path_is_missing .git/CHERRY_PICK_HEAD &&
+	test_must_fail git cherry-pick --skip 2>advice &&
+	test_i18ncmp expect advice
+'
+
+test_expect_success 'allow skipping commit but not abort for a new history' '
+	pristine_detach initial &&
+	cat >expect <<-EOF &&
+	error: cannot abort from a branch yet to be born
+	fatal: cherry-pick failed
+	EOF
+	git checkout --orphan new_disconnected &&
+	git reset --hard &&
+	test_must_fail git cherry-pick anotherpick &&
+	test_must_fail git cherry-pick --abort 2>advice &&
+	git cherry-pick --skip &&
+	test_i18ncmp expect advice
+'
+
+test_expect_success 'allow skipping stopped cherry-pick because of untracked file modifications' '
+	pristine_detach initial &&
+	git rm --cached unrelated &&
+	git commit -m "untrack unrelated" &&
+	test_must_fail git cherry-pick initial base &&
+	test_path_is_missing .git/CHERRY_PICK_HEAD &&
+	git cherry-pick --skip
+'
+
 test_expect_success '--quit does not complain when no cherry-pick is in progress' '
 	pristine_detach initial &&
 	git cherry-pick --quit
-- 
2.21.0


^ permalink raw reply	[flat|nested] 87+ messages in thread

* [GSoC][PATCH v7 6/6] cherry-pick/revert: advise using --skip
  2019-06-23 20:03 ` [GSoC][PATCH v7 0/6] " Rohit Ashiwal
                     ` (4 preceding siblings ...)
  2019-06-23 20:03   ` [GSoC][PATCH v7 5/6] cherry-pick/revert: add --skip option Rohit Ashiwal
@ 2019-06-23 20:03   ` Rohit Ashiwal
  5 siblings, 0 replies; 87+ messages in thread
From: Rohit Ashiwal @ 2019-06-23 20:03 UTC (permalink / raw)
  To: rohit.ashiwal265
  Cc: git, newren, t.gummerer, phillip.wood123, gitster, martin.agren

The previous commit introduced a --skip flag for cherry-pick and
revert. Update the advice messages, to tell users about this less
cumbersome way of skipping commits. Also add tests to ensure
everything is working fine.

Signed-off-by: Rohit Ashiwal <rohit.ashiwal265@gmail.com>
---
 builtin/commit.c                | 13 ++++++++-----
 sequencer.c                     |  9 ++++++---
 t/t3510-cherry-pick-sequence.sh | 20 ++++++++++++++++++++
 3 files changed, 34 insertions(+), 8 deletions(-)

diff --git a/builtin/commit.c b/builtin/commit.c
index 1c9e8e2228..1f47c51bdc 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -60,15 +60,18 @@ N_("The previous cherry-pick is now empty, possibly due to conflict resolution.\
 "\n");
 
 static const char empty_cherry_pick_advice_single[] =
-N_("Otherwise, please use 'git reset'\n");
+N_("Otherwise, please use 'git cherry-pick --skip'\n");
 
 static const char empty_cherry_pick_advice_multi[] =
-N_("If you wish to skip this commit, use:\n"
+N_("and then use:\n"
 "\n"
-"    git reset\n"
+"    git cherry-pick --continue\n"
 "\n"
-"Then \"git cherry-pick --continue\" will resume cherry-picking\n"
-"the remaining commits.\n");
+"to resume cherry-picking the remaining commits.\n"
+"If you wish to skip this commit, use:\n"
+"\n"
+"    git cherry-pick --skip\n"
+"\n");
 
 static const char *color_status_slots[] = {
 	[WT_STATUS_HEADER]	  = "header",
diff --git a/sequencer.c b/sequencer.c
index f5e3d60878..2e7b16b75f 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -2655,18 +2655,20 @@ static int create_seq_dir(struct repository *r)
 	enum replay_action action;
 	const char *in_progress_error = NULL;
 	const char *in_progress_advice = NULL;
+	unsigned int advise_skip = file_exists(git_path_revert_head(r)) ||
+				file_exists(git_path_cherry_pick_head(r));
 
 	if (!sequencer_get_last_command(r, &action)) {
 		switch (action) {
 		case REPLAY_REVERT:
 			in_progress_error = _("revert is already in progress");
 			in_progress_advice =
-			_("try \"git revert (--continue | --abort | --quit)\"");
+			_("try \"git revert (--continue | %s--abort | --quit)\"");
 			break;
 		case REPLAY_PICK:
 			in_progress_error = _("cherry-pick is already in progress");
 			in_progress_advice =
-			_("try \"git cherry-pick (--continue | --abort | --quit)\"");
+			_("try \"git cherry-pick (--continue | %s--abort | --quit)\"");
 			break;
 		default:
 			BUG("unexpected action in create_seq_dir");
@@ -2675,7 +2677,8 @@ static int create_seq_dir(struct repository *r)
 	if (in_progress_error) {
 		error("%s", in_progress_error);
 		if (advice_sequencer_in_use)
-			advise("%s", in_progress_advice);
+			advise(in_progress_advice,
+				advise_skip ? "--skip | " : "");
 		return -1;
 	}
 	if (mkdir(git_path_seq_dir(), 0777) < 0)
diff --git a/t/t3510-cherry-pick-sequence.sh b/t/t3510-cherry-pick-sequence.sh
index 20515ea37b..793bcc7fe3 100755
--- a/t/t3510-cherry-pick-sequence.sh
+++ b/t/t3510-cherry-pick-sequence.sh
@@ -172,6 +172,26 @@ test_expect_success 'check advice when we move HEAD by committing' '
 	test_i18ncmp expect advice
 '
 
+test_expect_success 'selectively advise --skip while launching another sequence' '
+	pristine_detach initial &&
+	cat >expect <<-EOF &&
+	error: cherry-pick is already in progress
+	hint: try "git cherry-pick (--continue | --skip | --abort | --quit)"
+	fatal: cherry-pick failed
+	EOF
+	test_must_fail git cherry-pick picked..yetanotherpick &&
+	test_must_fail git cherry-pick picked..yetanotherpick 2>advice &&
+	test_i18ncmp expect advice &&
+	cat >expect <<-EOF &&
+	error: cherry-pick is already in progress
+	hint: try "git cherry-pick (--continue | --abort | --quit)"
+	fatal: cherry-pick failed
+	EOF
+	git reset --merge &&
+	test_must_fail git cherry-pick picked..yetanotherpick 2>advice &&
+	test_i18ncmp expect advice
+'
+
 test_expect_success 'allow skipping commit but not abort for a new history' '
 	pristine_detach initial &&
 	cat >expect <<-EOF &&
-- 
2.21.0


^ permalink raw reply	[flat|nested] 87+ messages in thread

* Re: [GSoC][PATCH v7 1/6] advice: add sequencerInUse config variable
  2019-06-23 20:03   ` [GSoC][PATCH v7 1/6] advice: add sequencerInUse config variable Rohit Ashiwal
@ 2019-06-25  9:18     ` Thomas Gummerer
  0 siblings, 0 replies; 87+ messages in thread
From: Thomas Gummerer @ 2019-06-25  9:18 UTC (permalink / raw)
  To: Rohit Ashiwal; +Cc: git, newren, phillip.wood123, gitster, martin.agren

On 06/24, Rohit Ashiwal wrote:
> Calls to advise() which are not guarded by advice.* config variables
> are "bad" as they do not let the user say, "I've learned this part
> of Git enough, please don't tell me what to do verbosely.". Add a
> configuration variable "sequencerInUse" which controls whether to
> display advice when any sequencer command is in progress.

It would be nice if this patch not only introduced this config
variable, but also started making use of it.  That would make it
immediately clear why this variable is useful.  Otherwise the commit
message should state that this is only useful in a future commit.

Not sure that's worth a reroll by itself though.

> Signed-off-by: Rohit Ashiwal <rohit.ashiwal265@gmail.com>
> ---
>  Documentation/config/advice.txt | 2 ++
>  advice.c                        | 2 ++
>  advice.h                        | 1 +
>  3 files changed, 5 insertions(+)
> 
> diff --git a/Documentation/config/advice.txt b/Documentation/config/advice.txt
> index ec4f6ae658..1cd9096c98 100644
> --- a/Documentation/config/advice.txt
> +++ b/Documentation/config/advice.txt
> @@ -57,6 +57,8 @@ advice.*::
>  	resolveConflict::
>  		Advice shown by various commands when conflicts
>  		prevent the operation from being performed.
> +	sequencerInUse::
> +		Advice shown when a sequencer command is already in progress.
>  	implicitIdentity::
>  		Advice on how to set your identity configuration when
>  		your information is guessed from the system username and
> diff --git a/advice.c b/advice.c
> index ce5f374ecd..b101f0c264 100644
> --- a/advice.c
> +++ b/advice.c
> @@ -15,6 +15,7 @@ int advice_status_u_option = 1;
>  int advice_commit_before_merge = 1;
>  int advice_reset_quiet_warning = 1;
>  int advice_resolve_conflict = 1;
> +int advice_sequencer_in_use = 1;
>  int advice_implicit_identity = 1;
>  int advice_detached_head = 1;
>  int advice_set_upstream_failure = 1;
> @@ -71,6 +72,7 @@ static struct {
>  	{ "commitBeforeMerge", &advice_commit_before_merge },
>  	{ "resetQuiet", &advice_reset_quiet_warning },
>  	{ "resolveConflict", &advice_resolve_conflict },
> +	{ "sequencerInUse", &advice_sequencer_in_use },
>  	{ "implicitIdentity", &advice_implicit_identity },
>  	{ "detachedHead", &advice_detached_head },
>  	{ "setupStreamFailure", &advice_set_upstream_failure },
> diff --git a/advice.h b/advice.h
> index e50f02cdfe..ebc838d7bc 100644
> --- a/advice.h
> +++ b/advice.h
> @@ -15,6 +15,7 @@ extern int advice_status_u_option;
>  extern int advice_commit_before_merge;
>  extern int advice_reset_quiet_warning;
>  extern int advice_resolve_conflict;
> +extern int advice_sequencer_in_use;
>  extern int advice_implicit_identity;
>  extern int advice_detached_head;
>  extern int advice_set_upstream_failure;
> -- 
> 2.21.0
> 

^ permalink raw reply	[flat|nested] 87+ messages in thread

end of thread, back to index

Thread overview: 87+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-06-08 19:19 [GSoC][PATCH 0/3] Teach cherry-pick/revert to skip commits Rohit Ashiwal
2019-06-08 19:19 ` [GSoC][PATCH 1/3] sequencer: add advice for revert Rohit Ashiwal
2019-06-09 17:52   ` Phillip Wood
2019-06-10  5:13     ` Rohit Ashiwal
2019-06-10 10:39       ` Phillip Wood
2019-06-10 13:25         ` Rohit Ashiwal
2019-06-10 17:46           ` Phillip Wood
2019-06-10 16:34         ` Junio C Hamano
2019-06-08 19:19 ` [GSoC][PATCH 2/3] cherry-pick/revert: add --skip option Rohit Ashiwal
2019-06-09  8:37   ` Thomas Gummerer
2019-06-09 18:01   ` Phillip Wood
2019-06-10  5:57     ` Rohit Ashiwal
2019-06-10 10:40       ` Phillip Wood
2019-06-10 13:43         ` Rohit Ashiwal
2019-06-10 17:47           ` Phillip Wood
2019-06-08 19:19 ` [GSoC][PATCH 3/3] cherry-pick/revert: update hints Rohit Ashiwal
2019-06-09  8:42   ` Thomas Gummerer
2019-06-09 18:03   ` Phillip Wood
2019-06-10  5:28     ` Rohit Ashiwal
2019-06-10 10:40       ` Phillip Wood
2019-06-10 13:33         ` Rohit Ashiwal
2019-06-10 17:47           ` Phillip Wood
2019-06-09  9:02 ` [GSoC][PATCH 0/3] Teach cherry-pick/revert to skip commits Thomas Gummerer
2019-06-09 10:06   ` Rohit Ashiwal
2019-06-09 20:00     ` Thomas Gummerer
2019-06-11  7:31 ` [GSoC][PATCH v2 " Rohit Ashiwal
2019-06-11  7:31   ` [GSoC][PATCH v2 1/3] sequencer: add advice for revert Rohit Ashiwal
2019-06-11 21:25     ` Junio C Hamano
2019-06-11  7:31   ` [GSoC][PATCH v2 2/3] cherry-pick/revert: add --skip option Rohit Ashiwal
2019-06-12 13:31     ` Phillip Wood
2019-06-12 18:11       ` Junio C Hamano
2019-06-12 18:57         ` Phillip Wood
2019-06-11  7:31   ` [GSoC][PATCH v2 3/3] cherry-pick/revert: advise using --skip Rohit Ashiwal
2019-06-12 15:16     ` Phillip Wood
2019-06-13  4:05 ` [GSoC][PATCH v3 0/3] Teach cherry-pick/revert to skip commits Rohit Ashiwal
2019-06-13  4:05   ` [GSoC][PATCH v3 1/3] sequencer: add advice for revert Rohit Ashiwal
2019-06-13 17:45     ` Phillip Wood
2019-06-13 19:21       ` Martin Ågren
2019-06-13 20:59         ` Junio C Hamano
2019-06-14  3:44         ` Rohit Ashiwal
2019-06-14  3:43       ` Rohit Ashiwal
2019-06-13  4:05   ` [GSoC][PATCH v3 2/3] cherry-pick/revert: add --skip option Rohit Ashiwal
2019-06-13 17:56     ` Junio C Hamano
2019-06-13 19:57       ` Junio C Hamano
2019-06-14  3:48         ` Rohit Ashiwal
2019-06-14  3:45       ` Rohit Ashiwal
2019-06-14 15:58         ` Junio C Hamano
2019-06-16  7:03       ` Rohit Ashiwal
2019-06-13 17:59     ` Phillip Wood
2019-06-13  4:05   ` [GSoC][PATCH v3 3/3] cherry-pick/revert: advise using --skip Rohit Ashiwal
2019-06-16  8:20 ` [GSoC][PATCH v4 0/4] [GSoC][PATCH 0/3] Teach cherry-pick/revert to skip commits Rohit Ashiwal
2019-06-16  8:20   ` [GSoC][PATCH v4 1/4] sequencer: add advice for revert Rohit Ashiwal
2019-06-17  5:51     ` Thomas Gummerer
2019-06-16  8:20   ` [GSoC][PATCH v4 2/4] sequencer: rename reset_for_rollback to reset_merge Rohit Ashiwal
2019-06-16  8:20   ` [GSoC][PATCH v4 3/4] cherry-pick/revert: add --skip option Rohit Ashiwal
2019-06-17  8:30     ` Thomas Gummerer
2019-06-16  8:20   ` [GSoC][PATCH v4 4/4] cherry-pick/revert: advise using --skip Rohit Ashiwal
2019-06-17  8:39   ` [GSoC][PATCH v4 0/4] [GSoC][PATCH 0/3] Teach cherry-pick/revert to skip commits Thomas Gummerer
2019-06-18 17:06 ` [GSoC][PATCH v5 0/5] " Rohit Ashiwal
2019-06-18 17:06   ` [GSoC][PATCH v5 1/5] sequencer: add advice for revert Rohit Ashiwal
2019-06-18 17:06   ` [GSoC][PATCH v5 2/5] sequencer: rename reset_for_rollback to reset_merge Rohit Ashiwal
2019-06-18 17:06   ` [GSoC][PATCH v5 3/5] sequencer: use argv_array in reset_merge Rohit Ashiwal
2019-06-18 17:06   ` [GSoC][PATCH v5 4/5] cherry-pick/revert: add --skip option Rohit Ashiwal
2019-06-20  3:40     ` Junio C Hamano
2019-06-20  9:46       ` Rohit Ashiwal
2019-06-20  9:57       ` Phillip Wood
2019-06-20 20:09         ` Junio C Hamano
2019-06-20 10:02     ` Phillip Wood
2019-06-20 10:34       ` Rohit Ashiwal
2019-06-20 11:42         ` Phillip Wood
2019-06-21  7:47           ` Rohit Ashiwal
2019-06-18 17:06   ` [GSoC][PATCH v5 5/5] cherry-pick/revert: advise using --skip Rohit Ashiwal
2019-06-21  9:17 ` [GSoC][PATCH v6 0/5] Teach cherry-pick/revert to skip commits Rohit Ashiwal
2019-06-21  9:17   ` [GSoC][PATCH v6 1/5] sequencer: add advice for revert Rohit Ashiwal
2019-06-21  9:17   ` [GSoC][PATCH v6 2/5] sequencer: rename reset_for_rollback to reset_merge Rohit Ashiwal
2019-06-21  9:17   ` [GSoC][PATCH v6 3/5] sequencer: use argv_array in reset_merge Rohit Ashiwal
2019-06-21  9:17   ` [GSoC][PATCH v6 4/5] cherry-pick/revert: add --skip option Rohit Ashiwal
2019-06-21  9:18   ` [GSoC][PATCH v6 5/5] cherry-pick/revert: advise using --skip Rohit Ashiwal
2019-06-21 19:09   ` [GSoC][PATCH v6 0/5] Teach cherry-pick/revert to skip commits Junio C Hamano
2019-06-23 20:03 ` [GSoC][PATCH v7 0/6] " Rohit Ashiwal
2019-06-23 20:03   ` [GSoC][PATCH v7 1/6] advice: add sequencerInUse config variable Rohit Ashiwal
2019-06-25  9:18     ` Thomas Gummerer
2019-06-23 20:03   ` [GSoC][PATCH v7 2/6] sequencer: add advice for revert Rohit Ashiwal
2019-06-23 20:03   ` [GSoC][PATCH v7 3/6] sequencer: rename reset_for_rollback to reset_merge Rohit Ashiwal
2019-06-23 20:03   ` [GSoC][PATCH v7 4/6] sequencer: use argv_array in reset_merge Rohit Ashiwal
2019-06-23 20:03   ` [GSoC][PATCH v7 5/6] cherry-pick/revert: add --skip option Rohit Ashiwal
2019-06-23 20:03   ` [GSoC][PATCH v7 6/6] cherry-pick/revert: advise using --skip Rohit Ashiwal

git@vger.kernel.org list mirror (unofficial, one of many)

Archives are clonable:
	git clone --mirror https://public-inbox.org/git
	git clone --mirror http://ou63pmih66umazou.onion/git
	git clone --mirror http://czquwvybam4bgbro.onion/git
	git clone --mirror http://hjrcffqmbrq6wope.onion/git

Newsgroups are available over NNTP:
	nntp://news.public-inbox.org/inbox.comp.version-control.git
	nntp://ou63pmih66umazou.onion/inbox.comp.version-control.git
	nntp://czquwvybam4bgbro.onion/inbox.comp.version-control.git
	nntp://hjrcffqmbrq6wope.onion/inbox.comp.version-control.git
	nntp://news.gmane.org/gmane.comp.version-control.git

 note: .onion URLs require Tor: https://www.torproject.org/

AGPL code for this site: git clone https://public-inbox.org/ public-inbox