{"thread":{"id":"51269","subject":"[GSoC][PATCH 0/3] Teach cherry-pick/revert to skip commits","startedAt":"2019-06-08T19:22:57Z","lastAt":"2019-07-02T15:26:34Z","messageCount":95,"participants":["Rohit Ashiwal","Thomas Gummerer","Phillip Wood","Junio C Hamano","Martin Ågren"],"isPatch":true,"patchVersion":1,"patchTotal":3},"messages":[{"id":"376863","messageId":"20190608191958.4593-1-rohit.ashiwal265@gmail.com","threadId":"51269","inReplyTo":null,"subject":"[GSoC][PATCH 0/3] Teach cherry-pick/revert to skip commits","fromName":"Rohit Ashiwal","fromEmail":"rohit.ashiwal265@gmail.com","sentAt":"2019-06-08T19:19:55Z","receivedAt":"2019-06-08T19:22:57Z","isPatch":true,"sender":{"key":"rohit.ashiwal265@gmail.com","avatar":"https://avatars.githubusercontent.com/u/31043830?v=4"},"body":"git am or rebase advice user to use git am --skip or git rebase --skip\nto skip the commit that has become empty or has risen conflicts. OTOH,\ncherry-pick advice user to use git reset HEAD which on the user’s part\nis annoying and sometimes confusing. This patch series will bring\nconsistency between advices of these commands with introduction of\n`--skip` flag to cherry-pick and revert.\n\nRohit Ashiwal (3):\n  sequencer: add advice for revert\n  cherry-pick/revert: add --skip option\n  cherry-pick/revert: update hints\n\n Documentation/git-cherry-pick.txt |  4 +-\n Documentation/git-revert.txt      |  4 +-\n Documentation/sequencer.txt       |  4 ++\n builtin/commit.c                  | 13 ++++---\n builtin/revert.c                  |  5 +++\n sequencer.c                       | 26 ++++++++++++-\n sequencer.h                       |  1 +\n t/t3510-cherry-pick-sequence.sh   | 63 +++++++++++++++++++++++++++++++\n 8 files changed, 108 insertions(+), 12 deletions(-)\n\nPR: https://github.com/r1walz/git/pull/1\nReviewed-by: Elijah Newren <newren@gmail.com>\nReviewed-by: Thomas Gummerer <t.gummerer@gmail.com>\n-- \n2.21.0\n\n"},{"id":"376864","messageId":"20190608191958.4593-2-rohit.ashiwal265@gmail.com","threadId":"51269","inReplyTo":"20190608191958.4593-1-rohit.ashiwal265@gmail.com","subject":"[GSoC][PATCH 1/3] sequencer: add advice for revert","fromName":"Rohit Ashiwal","fromEmail":"rohit.ashiwal265@gmail.com","sentAt":"2019-06-08T19:19:56Z","receivedAt":"2019-06-08T19:23:01Z","isPatch":true,"sender":{"key":"rohit.ashiwal265@gmail.com","avatar":"https://avatars.githubusercontent.com/u/31043830?v=4"},"body":"In the case of merge conflicts, while performing a revert, we are\ncurrently advised to use `git cherry-pick --<sequencer-options>`\nof which --continue is incompatible for continuing the revert.\nIntroduce a separate advice message for `git revert`.\n\nSigned-off-by: Rohit Ashiwal <rohit.ashiwal265@gmail.com>\n---\n sequencer.c | 1 +\n 1 file changed, 1 insertion(+)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex f88a97fb10..9c561a041b 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -2655,6 +2655,7 @@ static int create_seq_dir(void)\n \tif (file_exists(git_path_seq_dir())) {\n \t\terror(_(\"a cherry-pick or revert is already in progress\"));\n \t\tadvise(_(\"try \\\"git cherry-pick (--continue | --quit | --abort)\\\"\"));\n+\t\tadvise(_(\"or  \\\"git revert (--continue | --quit | --abort)\\\"\"));\n \t\treturn -1;\n \t} else if (mkdir(git_path_seq_dir(), 0777) < 0)\n \t\treturn error_errno(_(\"could not create sequencer directory '%s'\"),\n-- \n2.21.0\n\n"},{"id":"376865","messageId":"20190608191958.4593-3-rohit.ashiwal265@gmail.com","threadId":"51269","inReplyTo":"20190608191958.4593-1-rohit.ashiwal265@gmail.com","subject":"[GSoC][PATCH 2/3] cherry-pick/revert: add --skip option","fromName":"Rohit Ashiwal","fromEmail":"rohit.ashiwal265@gmail.com","sentAt":"2019-06-08T19:19:57Z","receivedAt":"2019-06-08T19:23:06Z","isPatch":true,"sender":{"key":"rohit.ashiwal265@gmail.com","avatar":"https://avatars.githubusercontent.com/u/31043830?v=4"},"body":"git am or rebase advise the user to use `git (am | rebase) --skip` to\nskip the commit. cherry-pick and revert also have this concept of\nskipping commits but they advise the user to use `git reset` (or in\ncase of a patch which had conflicts, `git reset --merge`) which on the\nuser's part is annoying and sometimes confusing. Add a `--skip` option\nto make these commands more consistent.\n\nIn the next commit, we will change the advice messages hence finishing\nthe process of teaching revert and cherry-pick \"how to skip commits\".\n\nSigned-off-by: Rohit Ashiwal <rohit.ashiwal265@gmail.com>\n---\n Documentation/git-cherry-pick.txt |  4 +-\n Documentation/git-revert.txt      |  4 +-\n Documentation/sequencer.txt       |  4 ++\n builtin/revert.c                  |  5 +++\n sequencer.c                       | 23 +++++++++++\n sequencer.h                       |  1 +\n t/t3510-cherry-pick-sequence.sh   | 63 +++++++++++++++++++++++++++++++\n 7 files changed, 98 insertions(+), 6 deletions(-)\n\ndiff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt\nindex 754b16ce0c..955880ab88 100644\n--- a/Documentation/git-cherry-pick.txt\n+++ b/Documentation/git-cherry-pick.txt\n@@ -10,9 +10,7 @@ SYNOPSIS\n [verse]\n 'git cherry-pick' [--edit] [-n] [-m parent-number] [-s] [-x] [--ff]\n \t\t  [-S[<keyid>]] <commit>...\n-'git cherry-pick' --continue\n-'git cherry-pick' --quit\n-'git cherry-pick' --abort\n+'git cherry-pick' --continue | --skip | --abort | --quit\n \n DESCRIPTION\n -----------\ndiff --git a/Documentation/git-revert.txt b/Documentation/git-revert.txt\nindex 0c82ca5bc0..ffce98099c 100644\n--- a/Documentation/git-revert.txt\n+++ b/Documentation/git-revert.txt\n@@ -9,9 +9,7 @@ SYNOPSIS\n --------\n [verse]\n 'git revert' [--[no-]edit] [-n] [-m parent-number] [-s] [-S[<keyid>]] <commit>...\n-'git revert' --continue\n-'git revert' --quit\n-'git revert' --abort\n+'git revert' --continue | --skip | --abort | --quit\n \n DESCRIPTION\n -----------\ndiff --git a/Documentation/sequencer.txt b/Documentation/sequencer.txt\nindex 5a57c4a407..3bceb56474 100644\n--- a/Documentation/sequencer.txt\n+++ b/Documentation/sequencer.txt\n@@ -3,6 +3,10 @@\n \t`.git/sequencer`.  Can be used to continue after resolving\n \tconflicts in a failed cherry-pick or revert.\n \n+--skip::\n+\tSkip the current commit and continue with the rest of the\n+\tsequence.\n+\n --quit::\n \tForget about the current operation in progress.  Can be used\n \tto clear the sequencer state after a failed cherry-pick or\ndiff --git a/builtin/revert.c b/builtin/revert.c\nindex d4dcedbdc6..5dc5891ea2 100644\n--- a/builtin/revert.c\n+++ b/builtin/revert.c\n@@ -102,6 +102,7 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)\n \t\tOPT_CMDMODE(0, \"quit\", &cmd, N_(\"end revert or cherry-pick sequence\"), 'q'),\n \t\tOPT_CMDMODE(0, \"continue\", &cmd, N_(\"resume revert or cherry-pick sequence\"), 'c'),\n \t\tOPT_CMDMODE(0, \"abort\", &cmd, N_(\"cancel revert or cherry-pick sequence\"), 'a'),\n+\t\tOPT_CMDMODE(0, \"skip\", &cmd, N_(\"skip current commit and continue\"), 's'),\n \t\tOPT_CLEANUP(&cleanup_arg),\n \t\tOPT_BOOL('n', \"no-commit\", &opts->no_commit, N_(\"don't automatically commit\")),\n \t\tOPT_BOOL('e', \"edit\", &opts->edit, N_(\"edit the commit message\")),\n@@ -151,6 +152,8 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)\n \t\t\tthis_operation = \"--quit\";\n \t\telse if (cmd == 'c')\n \t\t\tthis_operation = \"--continue\";\n+\t\telse if (cmd == 's')\n+\t\t\tthis_operation = \"--skip\";\n \t\telse {\n \t\t\tassert(cmd == 'a');\n \t\t\tthis_operation = \"--abort\";\n@@ -210,6 +213,8 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)\n \t\treturn sequencer_continue(the_repository, opts);\n \tif (cmd == 'a')\n \t\treturn sequencer_rollback(the_repository, opts);\n+\tif (cmd == 's')\n+\t\treturn sequencer_skip(the_repository, opts);\n \treturn sequencer_pick_revisions(the_repository, opts);\n }\n \ndiff --git a/sequencer.c b/sequencer.c\nindex 9c561a041b..f586e677d3 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -2784,6 +2784,29 @@ int sequencer_rollback(struct repository *r, struct replay_opts *opts)\n \treturn -1;\n }\n \n+int sequencer_skip(struct repository *r, struct replay_opts *opts)\n+{\n+\tswitch (opts->action) {\n+\tcase REPLAY_REVERT:\n+\t\tif (!file_exists(git_path_revert_head(r)))\n+\t\t\treturn error(_(\"no revert in progress\"));\n+\t\tbreak;\n+\tcase REPLAY_PICK:\n+\t\tif (!file_exists(git_path_cherry_pick_head(r)))\n+\t\t\treturn error(_(\"no cherry-pick in progress\"));\n+\t\tbreak;\n+\tdefault:\n+\t\tBUG(\"the control must not reach here.\");\n+\t}\n+\n+\tif (rollback_single_pick(r))\n+\t\treturn error(_(\"failed to skip the commit\"));\n+\tif (!is_directory(git_path_seq_dir()))\n+\t\treturn 0;\n+\n+\treturn sequencer_continue(r, opts);\n+}\n+\n static int save_todo(struct todo_list *todo_list, struct replay_opts *opts)\n {\n \tstruct lock_file todo_lock = LOCK_INIT;\ndiff --git a/sequencer.h b/sequencer.h\nindex 0c494b83d4..731b9853eb 100644\n--- a/sequencer.h\n+++ b/sequencer.h\n@@ -129,6 +129,7 @@ int sequencer_pick_revisions(struct repository *repo,\n \t\t\t     struct replay_opts *opts);\n int sequencer_continue(struct repository *repo, struct replay_opts *opts);\n int sequencer_rollback(struct repository *repo, struct replay_opts *opts);\n+int sequencer_skip(struct repository *repo, struct replay_opts *opts);\n int sequencer_remove_state(struct replay_opts *opts);\n \n #define TODO_LIST_KEEP_EMPTY (1U << 0)\ndiff --git a/t/t3510-cherry-pick-sequence.sh b/t/t3510-cherry-pick-sequence.sh\nindex 941d5026da..48cc9f13ee 100755\n--- a/t/t3510-cherry-pick-sequence.sh\n+++ b/t/t3510-cherry-pick-sequence.sh\n@@ -93,6 +93,69 @@ test_expect_success 'cherry-pick cleans up sequencer state upon success' '\n \ttest_path_is_missing .git/sequencer\n '\n \n+test_expect_success 'cherry-pick --skip requires cherry-pick in progress' '\n+\tpristine_detach initial &&\n+\ttest_must_fail git cherry-pick --skip\n+'\n+\n+test_expect_success 'revert --skip requires revert in progress' '\n+\tpristine_detach initial &&\n+\ttest_must_fail git revert --skip\n+'\n+\n+test_expect_success 'cherry-pick --skip to skip commit' '\n+\tpristine_detach initial &&\n+\ttest_must_fail git cherry-pick anotherpick &&\n+\ttest_must_fail git revert --skip &&\n+\tgit cherry-pick --skip &&\n+\ttest_cmp_rev initial HEAD &&\n+\ttest_path_is_missing .git/CHERRY_PICK_HEAD\n+'\n+\n+test_expect_success 'revert --skip to skip commit' '\n+\tpristine_detach anotherpick &&\n+\ttest_must_fail git revert anotherpick~1 &&\n+\ttest_must_fail git cherry-pick --skip &&\n+\tgit revert --skip &&\n+\ttest_cmp_rev anotherpick HEAD\n+'\n+\n+test_expect_success 'skip \"empty\" commit' '\n+\tpristine_detach picked &&\n+\ttest_commit dummy foo d &&\n+\ttest_must_fail git cherry-pick anotherpick &&\n+\tgit cherry-pick --skip &&\n+\ttest_cmp_rev dummy HEAD\n+'\n+\n+test_expect_success 'skip a commit and check if rest of sequence is correct' '\n+\tpristine_detach initial &&\n+\techo e >expect &&\n+\tcat >expect.log <<-EOF &&\n+\tOBJID\n+\t:100644 100644 OBJID OBJID M\tfoo\n+\tOBJID\n+\t:100644 100644 OBJID OBJID M\tfoo\n+\tOBJID\n+\t:100644 100644 OBJID OBJID M\tunrelated\n+\tOBJID\n+\t:000000 100644 OBJID OBJID A\tfoo\n+\t:000000 100644 OBJID OBJID A\tunrelated\n+\tEOF\n+\ttest_must_fail git cherry-pick base..yetanotherpick &&\n+\ttest_must_fail git cherry-pick --skip &&\n+\techo d >foo &&\n+\tgit add foo &&\n+\tgit cherry-pick --continue &&\n+\t{\n+\t\tgit rev-list HEAD |\n+\t\tgit diff-tree --root --stdin |\n+\t\tsed \"s/$OID_REGEX/OBJID/g\"\n+\t} >actual.log &&\n+\ttest_cmp expect foo &&\n+\ttest_cmp expect.log actual.log\n+'\n+\n test_expect_success '--quit does not complain when no cherry-pick is in progress' '\n \tpristine_detach initial &&\n \tgit cherry-pick --quit\n-- \n2.21.0\n\n"},{"id":"376866","messageId":"20190608191958.4593-4-rohit.ashiwal265@gmail.com","threadId":"51269","inReplyTo":"20190608191958.4593-1-rohit.ashiwal265@gmail.com","subject":"[GSoC][PATCH 3/3] cherry-pick/revert: update hints","fromName":"Rohit Ashiwal","fromEmail":"rohit.ashiwal265@gmail.com","sentAt":"2019-06-08T19:19:58Z","receivedAt":"2019-06-08T19:23:09Z","isPatch":true,"sender":{"key":"rohit.ashiwal265@gmail.com","avatar":"https://avatars.githubusercontent.com/u/31043830?v=4"},"body":"Signed-off-by: Rohit Ashiwal <rohit.ashiwal265@gmail.com>\n---\n builtin/commit.c | 13 ++++++++-----\n sequencer.c      |  4 ++--\n 2 files changed, 10 insertions(+), 7 deletions(-)\n\ndiff --git a/builtin/commit.c b/builtin/commit.c\nindex 1c9e8e2228..1f47c51bdc 100644\n--- a/builtin/commit.c\n+++ b/builtin/commit.c\n@@ -60,15 +60,18 @@ N_(\"The previous cherry-pick is now empty, possibly due to conflict resolution.\\\n \"\\n\");\n \n static const char empty_cherry_pick_advice_single[] =\n-N_(\"Otherwise, please use 'git reset'\\n\");\n+N_(\"Otherwise, please use 'git cherry-pick --skip'\\n\");\n \n static const char empty_cherry_pick_advice_multi[] =\n-N_(\"If you wish to skip this commit, use:\\n\"\n+N_(\"and then use:\\n\"\n \"\\n\"\n-\"    git reset\\n\"\n+\"    git cherry-pick --continue\\n\"\n \"\\n\"\n-\"Then \\\"git cherry-pick --continue\\\" will resume cherry-picking\\n\"\n-\"the remaining commits.\\n\");\n+\"to resume cherry-picking the remaining commits.\\n\"\n+\"If you wish to skip this commit, use:\\n\"\n+\"\\n\"\n+\"    git cherry-pick --skip\\n\"\n+\"\\n\");\n \n static const char *color_status_slots[] = {\n \t[WT_STATUS_HEADER]\t  = \"header\",\ndiff --git a/sequencer.c b/sequencer.c\nindex f586e677d3..e889427eef 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -2654,8 +2654,8 @@ static int create_seq_dir(void)\n {\n \tif (file_exists(git_path_seq_dir())) {\n \t\terror(_(\"a cherry-pick or revert is already in progress\"));\n-\t\tadvise(_(\"try \\\"git cherry-pick (--continue | --quit | --abort)\\\"\"));\n-\t\tadvise(_(\"or  \\\"git revert (--continue | --quit | --abort)\\\"\"));\n+\t\tadvise(_(\"try \\\"git cherry-pick (--continue | --skip | --quit | --abort)\\\"\"));\n+\t\tadvise(_(\"or  \\\"git revert (--continue | --skip | --quit | --abort)\\\"\"));\n \t\treturn -1;\n \t} else if (mkdir(git_path_seq_dir(), 0777) < 0)\n \t\treturn error_errno(_(\"could not create sequencer directory '%s'\"),\n-- \n2.21.0\n\n"},{"id":"376876","messageId":"20190609083708.GA28007@hank.intra.tgummerer.com","threadId":"51269","inReplyTo":"20190608191958.4593-3-rohit.ashiwal265@gmail.com","subject":"Re: [GSoC][PATCH 2/3] cherry-pick/revert: add --skip option","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2019-06-09T08:37:09Z","receivedAt":"2019-06-09T08:37:17Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"On 06/09, Rohit Ashiwal wrote:\n> git am or rebase advise the user to use `git (am | rebase) --skip` to\n> skip the commit. cherry-pick and revert also have this concept of\n> skipping commits but they advise the user to use `git reset` (or in\n> case of a patch which had conflicts, `git reset --merge`) which on the\n> user's part is annoying and sometimes confusing. Add a `--skip` option\n> to make these commands more consistent.\n\nSomething I missed in the off-list review for this PR:  I think this\ncommit message is a bit heavy on the advice part, rather than on the\nreal advantage the --skip flag brings, which is that it's less\ncumbersome for the user to skip a commit, and brings consistency to\nthe commands.  Maybe something like:\n\n        git am or rebase have a --skip flag to skip the current commit if\n        the user wishes to do so.  During a cherry-pick or revert a user\n        could likewise skip a commit, but needs to use 'git reset' (or in\n        the case of conflicts 'git reset --merge'), followed by 'git\n        (cherry-pick | revert) --continue' to skip the commit.  This is\n        more annoying and sometimes confusing on the users part.  Add a\n        `--skip` option to make skipping commits easier for the user and\n        to make the commands more consistent.\n\n> In the next commit, we will change the advice messages hence finishing\n> the process of teaching revert and cherry-pick \"how to skip commits\".\n> \n> Signed-off-by: Rohit Ashiwal <rohit.ashiwal265@gmail.com>\n> ---\n>  Documentation/git-cherry-pick.txt |  4 +-\n>  Documentation/git-revert.txt      |  4 +-\n>  Documentation/sequencer.txt       |  4 ++\n>  builtin/revert.c                  |  5 +++\n>  sequencer.c                       | 23 +++++++++++\n>  sequencer.h                       |  1 +\n>  t/t3510-cherry-pick-sequence.sh   | 63 +++++++++++++++++++++++++++++++\n>  7 files changed, 98 insertions(+), 6 deletions(-)\n> \n> diff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt\n> index 754b16ce0c..955880ab88 100644\n> --- a/Documentation/git-cherry-pick.txt\n> +++ b/Documentation/git-cherry-pick.txt\n> @@ -10,9 +10,7 @@ SYNOPSIS\n>  [verse]\n>  'git cherry-pick' [--edit] [-n] [-m parent-number] [-s] [-x] [--ff]\n>  \t\t  [-S[<keyid>]] <commit>...\n> -'git cherry-pick' --continue\n> -'git cherry-pick' --quit\n> -'git cherry-pick' --abort\n> +'git cherry-pick' --continue | --skip | --abort | --quit\n>  \n>  DESCRIPTION\n>  -----------\n> diff --git a/Documentation/git-revert.txt b/Documentation/git-revert.txt\n> index 0c82ca5bc0..ffce98099c 100644\n> --- a/Documentation/git-revert.txt\n> +++ b/Documentation/git-revert.txt\n> @@ -9,9 +9,7 @@ SYNOPSIS\n>  --------\n>  [verse]\n>  'git revert' [--[no-]edit] [-n] [-m parent-number] [-s] [-S[<keyid>]] <commit>...\n> -'git revert' --continue\n> -'git revert' --quit\n> -'git revert' --abort\n> +'git revert' --continue | --skip | --abort | --quit\n>  \n>  DESCRIPTION\n>  -----------\n> diff --git a/Documentation/sequencer.txt b/Documentation/sequencer.txt\n> index 5a57c4a407..3bceb56474 100644\n> --- a/Documentation/sequencer.txt\n> +++ b/Documentation/sequencer.txt\n> @@ -3,6 +3,10 @@\n>  \t`.git/sequencer`.  Can be used to continue after resolving\n>  \tconflicts in a failed cherry-pick or revert.\n>  \n> +--skip::\n> +\tSkip the current commit and continue with the rest of the\n> +\tsequence.\n> +\n>  --quit::\n>  \tForget about the current operation in progress.  Can be used\n>  \tto clear the sequencer state after a failed cherry-pick or\n> diff --git a/builtin/revert.c b/builtin/revert.c\n> index d4dcedbdc6..5dc5891ea2 100644\n> --- a/builtin/revert.c\n> +++ b/builtin/revert.c\n> @@ -102,6 +102,7 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)\n>  \t\tOPT_CMDMODE(0, \"quit\", &cmd, N_(\"end revert or cherry-pick sequence\"), 'q'),\n>  \t\tOPT_CMDMODE(0, \"continue\", &cmd, N_(\"resume revert or cherry-pick sequence\"), 'c'),\n>  \t\tOPT_CMDMODE(0, \"abort\", &cmd, N_(\"cancel revert or cherry-pick sequence\"), 'a'),\n> +\t\tOPT_CMDMODE(0, \"skip\", &cmd, N_(\"skip current commit and continue\"), 's'),\n>  \t\tOPT_CLEANUP(&cleanup_arg),\n>  \t\tOPT_BOOL('n', \"no-commit\", &opts->no_commit, N_(\"don't automatically commit\")),\n>  \t\tOPT_BOOL('e', \"edit\", &opts->edit, N_(\"edit the commit message\")),\n> @@ -151,6 +152,8 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)\n>  \t\t\tthis_operation = \"--quit\";\n>  \t\telse if (cmd == 'c')\n>  \t\t\tthis_operation = \"--continue\";\n> +\t\telse if (cmd == 's')\n> +\t\t\tthis_operation = \"--skip\";\n>  \t\telse {\n>  \t\t\tassert(cmd == 'a');\n>  \t\t\tthis_operation = \"--abort\";\n> @@ -210,6 +213,8 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)\n>  \t\treturn sequencer_continue(the_repository, opts);\n>  \tif (cmd == 'a')\n>  \t\treturn sequencer_rollback(the_repository, opts);\n> +\tif (cmd == 's')\n> +\t\treturn sequencer_skip(the_repository, opts);\n>  \treturn sequencer_pick_revisions(the_repository, opts);\n>  }\n>  \n> diff --git a/sequencer.c b/sequencer.c\n> index 9c561a041b..f586e677d3 100644\n> --- a/sequencer.c\n> +++ b/sequencer.c\n> @@ -2784,6 +2784,29 @@ int sequencer_rollback(struct repository *r, struct replay_opts *opts)\n>  \treturn -1;\n>  }\n>  \n> +int sequencer_skip(struct repository *r, struct replay_opts *opts)\n> +{\n> +\tswitch (opts->action) {\n> +\tcase REPLAY_REVERT:\n> +\t\tif (!file_exists(git_path_revert_head(r)))\n> +\t\t\treturn error(_(\"no revert in progress\"));\n> +\t\tbreak;\n> +\tcase REPLAY_PICK:\n> +\t\tif (!file_exists(git_path_cherry_pick_head(r)))\n> +\t\t\treturn error(_(\"no cherry-pick in progress\"));\n> +\t\tbreak;\n\nI see that in some cases (e.g 'rollback_single_pick'), we just check\nif either REVERT_HEAD or CHERRY_PICK_HEAD exist, but would allow the\n\"wrong\" command to be used, e.g. 'git revert --abort' when a\ncherry-pick is in progress.  This helps avoiding that, good!\n\n> +\tdefault:\n> +\t\tBUG(\"the control must not reach here.\");\n\nWe don't support rebase in 'sequencer_skip' yet, makes sense as this\npatch is focused on cherry-pick and revert.  There's nothing\npreventing supporting that in the future though.\n\n> +\t}\n> +\n> +\tif (rollback_single_pick(r))\n> +\t\treturn error(_(\"failed to skip the commit\"));\n> +\tif (!is_directory(git_path_seq_dir()))\n> +\t\treturn 0;\n\nIf there's no sequencer directory, we don't need to continue the\ncherry-pick/revert, as there's nothing left to do.  Otherwise we\ncontinue.  Good.\n\nSo this looks good to me.\n\n> +\n> +\treturn sequencer_continue(r, opts);\n> +}\n> +\n>  static int save_todo(struct todo_list *todo_list, struct replay_opts *opts)\n>  {\n>  \tstruct lock_file todo_lock = LOCK_INIT;\n> diff --git a/sequencer.h b/sequencer.h\n> index 0c494b83d4..731b9853eb 100644\n> --- a/sequencer.h\n> +++ b/sequencer.h\n> @@ -129,6 +129,7 @@ int sequencer_pick_revisions(struct repository *repo,\n>  \t\t\t     struct replay_opts *opts);\n>  int sequencer_continue(struct repository *repo, struct replay_opts *opts);\n>  int sequencer_rollback(struct repository *repo, struct replay_opts *opts);\n> +int sequencer_skip(struct repository *repo, struct replay_opts *opts);\n>  int sequencer_remove_state(struct replay_opts *opts);\n>  \n>  #define TODO_LIST_KEEP_EMPTY (1U << 0)\n> diff --git a/t/t3510-cherry-pick-sequence.sh b/t/t3510-cherry-pick-sequence.sh\n> index 941d5026da..48cc9f13ee 100755\n> --- a/t/t3510-cherry-pick-sequence.sh\n> +++ b/t/t3510-cherry-pick-sequence.sh\n> @@ -93,6 +93,69 @@ test_expect_success 'cherry-pick cleans up sequencer state upon success' '\n>  \ttest_path_is_missing .git/sequencer\n>  '\n>  \n> +test_expect_success 'cherry-pick --skip requires cherry-pick in progress' '\n> +\tpristine_detach initial &&\n> +\ttest_must_fail git cherry-pick --skip\n> +'\n> +\n> +test_expect_success 'revert --skip requires revert in progress' '\n> +\tpristine_detach initial &&\n> +\ttest_must_fail git revert --skip\n> +'\n> +\n> +test_expect_success 'cherry-pick --skip to skip commit' '\n> +\tpristine_detach initial &&\n> +\ttest_must_fail git cherry-pick anotherpick &&\n> +\ttest_must_fail git revert --skip &&\n> +\tgit cherry-pick --skip &&\n> +\ttest_cmp_rev initial HEAD &&\n> +\ttest_path_is_missing .git/CHERRY_PICK_HEAD\n> +'\n> +\n> +test_expect_success 'revert --skip to skip commit' '\n> +\tpristine_detach anotherpick &&\n> +\ttest_must_fail git revert anotherpick~1 &&\n> +\ttest_must_fail git cherry-pick --skip &&\n> +\tgit revert --skip &&\n> +\ttest_cmp_rev anotherpick HEAD\n> +'\n> +\n> +test_expect_success 'skip \"empty\" commit' '\n> +\tpristine_detach picked &&\n> +\ttest_commit dummy foo d &&\n> +\ttest_must_fail git cherry-pick anotherpick &&\n> +\tgit cherry-pick --skip &&\n> +\ttest_cmp_rev dummy HEAD\n> +'\n> +\n> +test_expect_success 'skip a commit and check if rest of sequence is correct' '\n> +\tpristine_detach initial &&\n> +\techo e >expect &&\n> +\tcat >expect.log <<-EOF &&\n> +\tOBJID\n> +\t:100644 100644 OBJID OBJID M\tfoo\n> +\tOBJID\n> +\t:100644 100644 OBJID OBJID M\tfoo\n> +\tOBJID\n> +\t:100644 100644 OBJID OBJID M\tunrelated\n> +\tOBJID\n> +\t:000000 100644 OBJID OBJID A\tfoo\n> +\t:000000 100644 OBJID OBJID A\tunrelated\n> +\tEOF\n> +\ttest_must_fail git cherry-pick base..yetanotherpick &&\n> +\ttest_must_fail git cherry-pick --skip &&\n> +\techo d >foo &&\n> +\tgit add foo &&\n> +\tgit cherry-pick --continue &&\n> +\t{\n> +\t\tgit rev-list HEAD |\n> +\t\tgit diff-tree --root --stdin |\n> +\t\tsed \"s/$OID_REGEX/OBJID/g\"\n> +\t} >actual.log &&\n> +\ttest_cmp expect foo &&\n> +\ttest_cmp expect.log actual.log\n> +'\n> +\n>  test_expect_success '--quit does not complain when no cherry-pick is in progress' '\n>  \tpristine_detach initial &&\n>  \tgit cherry-pick --quit\n> -- \n> 2.21.0\n> \n"},{"id":"376877","messageId":"20190609084236.GB28007@hank.intra.tgummerer.com","threadId":"51269","inReplyTo":"20190608191958.4593-4-rohit.ashiwal265@gmail.com","subject":"Re: [GSoC][PATCH 3/3] cherry-pick/revert: update hints","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2019-06-09T08:42:36Z","receivedAt":"2019-06-09T08:42:43Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"> Subject: [GSoC][PATCH 3/3] cherry-pick/revert: update hints\n\n\"update hints\" is very generic when read in 'git log --oneline', and\ndoesn't give the reader much useful information.  Maybe something like\n\n        cherry-pick/revert: advice using --skip\n\n        In the previous commit we introduced a --skip flag for\n        cherry-pick and revert.  Update the advice messages, to tell\n        users about this less cumbersome way of skipping commits\n\nwould work better?  The rest of the patch looks good to me.\n\nOn 06/09, Rohit Ashiwal wrote:\n> Signed-off-by: Rohit Ashiwal <rohit.ashiwal265@gmail.com>\n> ---\n>  builtin/commit.c | 13 ++++++++-----\n>  sequencer.c      |  4 ++--\n>  2 files changed, 10 insertions(+), 7 deletions(-)\n> \n> diff --git a/builtin/commit.c b/builtin/commit.c\n> index 1c9e8e2228..1f47c51bdc 100644\n> --- a/builtin/commit.c\n> +++ b/builtin/commit.c\n> @@ -60,15 +60,18 @@ N_(\"The previous cherry-pick is now empty, possibly due to conflict resolution.\\\n>  \"\\n\");\n>  \n>  static const char empty_cherry_pick_advice_single[] =\n> -N_(\"Otherwise, please use 'git reset'\\n\");\n> +N_(\"Otherwise, please use 'git cherry-pick --skip'\\n\");\n>  \n>  static const char empty_cherry_pick_advice_multi[] =\n> -N_(\"If you wish to skip this commit, use:\\n\"\n> +N_(\"and then use:\\n\"\n>  \"\\n\"\n> -\"    git reset\\n\"\n> +\"    git cherry-pick --continue\\n\"\n>  \"\\n\"\n> -\"Then \\\"git cherry-pick --continue\\\" will resume cherry-picking\\n\"\n> -\"the remaining commits.\\n\");\n> +\"to resume cherry-picking the remaining commits.\\n\"\n> +\"If you wish to skip this commit, use:\\n\"\n> +\"\\n\"\n> +\"    git cherry-pick --skip\\n\"\n> +\"\\n\");\n>  \n>  static const char *color_status_slots[] = {\n>  \t[WT_STATUS_HEADER]\t  = \"header\",\n> diff --git a/sequencer.c b/sequencer.c\n> index f586e677d3..e889427eef 100644\n> --- a/sequencer.c\n> +++ b/sequencer.c\n> @@ -2654,8 +2654,8 @@ static int create_seq_dir(void)\n>  {\n>  \tif (file_exists(git_path_seq_dir())) {\n>  \t\terror(_(\"a cherry-pick or revert is already in progress\"));\n> -\t\tadvise(_(\"try \\\"git cherry-pick (--continue | --quit | --abort)\\\"\"));\n> -\t\tadvise(_(\"or  \\\"git revert (--continue | --quit | --abort)\\\"\"));\n> +\t\tadvise(_(\"try \\\"git cherry-pick (--continue | --skip | --quit | --abort)\\\"\"));\n> +\t\tadvise(_(\"or  \\\"git revert (--continue | --skip | --quit | --abort)\\\"\"));\n>  \t\treturn -1;\n>  \t} else if (mkdir(git_path_seq_dir(), 0777) < 0)\n>  \t\treturn error_errno(_(\"could not create sequencer directory '%s'\"),\n> -- \n> 2.21.0\n> \n"},{"id":"376878","messageId":"20190609090235.GC28007@hank.intra.tgummerer.com","threadId":"51269","inReplyTo":"20190608191958.4593-1-rohit.ashiwal265@gmail.com","subject":"Re: [GSoC][PATCH 0/3] Teach cherry-pick/revert to skip commits","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2019-06-09T09:02:35Z","receivedAt":"2019-06-09T09:02:41Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"On 06/09, Rohit Ashiwal wrote:\n> git am or rebase advice user to use git am --skip or git rebase --skip\n> to skip the commit that has become empty or has risen conflicts. OTOH,\n> cherry-pick advice user to use git reset HEAD which on the user’s part\n> is annoying and sometimes confusing. This patch series will bring\n> consistency between advices of these commands with introduction of\n> `--skip` flag to cherry-pick and revert.\n\nThanks!  I found a few minor nits that I missed in my off-list review\non the PR.  We should give others some time to comment now before you\nre-send it with the nits fixed (if you agree with them).\n\nOne thing that would be good to add to future cover letters is a\nreminder of how this fits in to your GSoC project, where the overall\nend goal is to improve the consistency of sequencer commands, and this\nis one step along that way.\n\n> Rohit Ashiwal (3):\n>   sequencer: add advice for revert\n>   cherry-pick/revert: add --skip option\n>   cherry-pick/revert: update hints\n> \n>  Documentation/git-cherry-pick.txt |  4 +-\n>  Documentation/git-revert.txt      |  4 +-\n>  Documentation/sequencer.txt       |  4 ++\n>  builtin/commit.c                  | 13 ++++---\n>  builtin/revert.c                  |  5 +++\n>  sequencer.c                       | 26 ++++++++++++-\n>  sequencer.h                       |  1 +\n>  t/t3510-cherry-pick-sequence.sh   | 63 +++++++++++++++++++++++++++++++\n>  8 files changed, 108 insertions(+), 12 deletions(-)\n> \n> PR: https://github.com/r1walz/git/pull/1\n> Reviewed-by: Elijah Newren <newren@gmail.com>\n> Reviewed-by: Thomas Gummerer <t.gummerer@gmail.com>\n\nNote that the 'Reviewed-by' footer is something that is \"given\" by the\nreviewers, and should only be added after they have explicitly given\nit for the patch/series in question.  Instead this should probably\nmention that Elijah and me reviewed this off-list in the PR you linked\nto above.\n\n> -- \n> 2.21.0\n> \n"},{"id":"376880","messageId":"CAL7ArXpMBXwOGXWmYx8Rv9bj2trJ-FS_VGgPmJbAh+evbaxNEw@mail.gmail.com","threadId":"51269","inReplyTo":"20190609090235.GC28007@hank.intra.tgummerer.com","subject":"Re: [GSoC][PATCH 0/3] Teach cherry-pick/revert to skip commits","fromName":"Rohit Ashiwal","fromEmail":"rohit.ashiwal265@gmail.com","sentAt":"2019-06-09T10:06:23Z","receivedAt":"2019-06-09T10:09:21Z","isPatch":true,"sender":{"key":"rohit.ashiwal265@gmail.com","avatar":"https://avatars.githubusercontent.com/u/31043830?v=4"},"body":"Hey Thomas\n\nOn Sun, Jun 9, 2019 at 2:32 PM Thomas Gummerer <t.gummerer@gmail.com> wrote:\n>\n> Thanks!  I found a few minor nits that I missed in my off-list review\n> on the PR.  We should give others some time to comment now before you\n> re-send it with the nits fixed (if you agree with them).\n\nYes, I'll wait for some more reviews before sending another iteration.\n\n> One thing that would be good to add to future cover letters is a\n> reminder of how this fits in to your GSoC project, where the overall\n> end goal is to improve the consistency of sequencer commands, and this\n> is one step along that way.\n\nSure, I'll keep this in mind and send some kind of summary in the next\nrevision.\n\n>\n> > PR: https://github.com/r1walz/git/pull/1\n> > Reviewed-by: Elijah Newren <newren@gmail.com>\n> > Reviewed-by: Thomas Gummerer <t.gummerer@gmail.com>\n>\n> Note that the 'Reviewed-by' footer is something that is \"given\" by the\n> reviewers, and should only be added after they have explicitly given\n> it for the patch/series in question.  Instead this should probably\n> mention that Elijah and me reviewed this off-list in the PR you linked\n> to above.\n\nOh! But I read here, SubmittingPatches[1] docs, that it's nice to give\ncredits to those who helped you. Should we fix it in some way? I don't\nknow. Anyway, that is beyond the scope of this patch.\n\n>\n> > --\n> > 2.21.0\n> >\n\nThanks for the review\nRohit\n\n[1]: https://github.com/git/git/blob/v2.22.0/Documentation/SubmittingPatches#L289-L291\n"},{"id":"376888","messageId":"2007ef79-1791-4f77-f9e4-34c59b4f0c36@gmail.com","threadId":"51269","inReplyTo":"20190608191958.4593-2-rohit.ashiwal265@gmail.com","subject":"Re: [GSoC][PATCH 1/3] sequencer: add advice for revert","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2019-06-09T17:52:42Z","receivedAt":"2019-06-09T17:56:01Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"Hi Rohit\n\nCongratulations on your first GSoC patch series!\n\nOn 08/06/2019 20:19, Rohit Ashiwal wrote:\n> In the case of merge conflicts, while performing a revert, we are\n> currently advised to use `git cherry-pick --<sequencer-options>`\n> of which --continue is incompatible for continuing the revert.\n> Introduce a separate advice message for `git revert`.\n> \n> Signed-off-by: Rohit Ashiwal <rohit.ashiwal265@gmail.com>\n> ---\n>  sequencer.c | 1 +\n>  1 file changed, 1 insertion(+)\n> \n> diff --git a/sequencer.c b/sequencer.c\n> index f88a97fb10..9c561a041b 100644\n> --- a/sequencer.c\n> +++ b/sequencer.c\n> @@ -2655,6 +2655,7 @@ static int create_seq_dir(void)\n>  \tif (file_exists(git_path_seq_dir())) {\n>  \t\terror(_(\"a cherry-pick or revert is already in progress\"));\n>  \t\tadvise(_(\"try \\\"git cherry-pick (--continue | --quit | --abort)\\\"\"));\n> +\t\tadvise(_(\"or  \\\"git revert (--continue | --quit | --abort)\\\"\"));\n\nI agree that it's a good idea to add advice for revert as well, but it\nwould be better to call sequencer_get_last_command() to find out if\nwe're running cherry-pick or revert and tailor the advice appropriately.\n\nBest Wishes\n\nPhillip\n\n>  \t\treturn -1;\n>  \t} else if (mkdir(git_path_seq_dir(), 0777) < 0)\n>  \t\treturn error_errno(_(\"could not create sequencer directory '%s'\"),\n> \n\n"},{"id":"376889","messageId":"0659a53e-0712-eb50-f15f-1c6a56fd3213@gmail.com","threadId":"51269","inReplyTo":"20190608191958.4593-3-rohit.ashiwal265@gmail.com","subject":"Re: [GSoC][PATCH 2/3] cherry-pick/revert: add --skip option","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2019-06-09T18:01:35Z","receivedAt":"2019-06-09T18:06:44Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"Hi Rohit\n\n--skip is definitely a useful addition to cherry-pick/revert\n\nOn 08/06/2019 20:19, Rohit Ashiwal wrote:\n> git am or rebase advise the user to use `git (am | rebase) --skip` to\n> skip the commit. cherry-pick and revert also have this concept of\n> skipping commits but they advise the user to use `git reset` (or in\n> case of a patch which had conflicts, `git reset --merge`) which on the\n> user's part is annoying and sometimes confusing. Add a `--skip` option\n> to make these commands more consistent.\n> \n> In the next commit, we will change the advice messages hence finishing\n> the process of teaching revert and cherry-pick \"how to skip commits\".\n> \n> Signed-off-by: Rohit Ashiwal <rohit.ashiwal265@gmail.com>\n> ---\n>  Documentation/git-cherry-pick.txt |  4 +-\n>  Documentation/git-revert.txt      |  4 +-\n>  Documentation/sequencer.txt       |  4 ++\n>  builtin/revert.c                  |  5 +++\n>  sequencer.c                       | 23 +++++++++++\n>  sequencer.h                       |  1 +\n>  t/t3510-cherry-pick-sequence.sh   | 63 +++++++++++++++++++++++++++++++\n>  7 files changed, 98 insertions(+), 6 deletions(-)\n> \n> diff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt\n> index 754b16ce0c..955880ab88 100644\n> --- a/Documentation/git-cherry-pick.txt\n> +++ b/Documentation/git-cherry-pick.txt\n> @@ -10,9 +10,7 @@ SYNOPSIS\n>  [verse]\n>  'git cherry-pick' [--edit] [-n] [-m parent-number] [-s] [-x] [--ff]\n>  \t\t  [-S[<keyid>]] <commit>...\n> -'git cherry-pick' --continue\n> -'git cherry-pick' --quit\n> -'git cherry-pick' --abort\n> +'git cherry-pick' --continue | --skip | --abort | --quit\n>  \n>  DESCRIPTION\n>  -----------\n> diff --git a/Documentation/git-revert.txt b/Documentation/git-revert.txt\n> index 0c82ca5bc0..ffce98099c 100644\n> --- a/Documentation/git-revert.txt\n> +++ b/Documentation/git-revert.txt\n> @@ -9,9 +9,7 @@ SYNOPSIS\n>  --------\n>  [verse]\n>  'git revert' [--[no-]edit] [-n] [-m parent-number] [-s] [-S[<keyid>]] <commit>...\n> -'git revert' --continue\n> -'git revert' --quit\n> -'git revert' --abort\n> +'git revert' --continue | --skip | --abort | --quit\n>  \n>  DESCRIPTION\n>  -----------\n> diff --git a/Documentation/sequencer.txt b/Documentation/sequencer.txt\n> index 5a57c4a407..3bceb56474 100644\n> --- a/Documentation/sequencer.txt\n> +++ b/Documentation/sequencer.txt\n> @@ -3,6 +3,10 @@\n>  \t`.git/sequencer`.  Can be used to continue after resolving\n>  \tconflicts in a failed cherry-pick or revert.\n>  \n> +--skip::\n> +\tSkip the current commit and continue with the rest of the\n> +\tsequence.\n> +\n>  --quit::\n>  \tForget about the current operation in progress.  Can be used\n>  \tto clear the sequencer state after a failed cherry-pick or\n> diff --git a/builtin/revert.c b/builtin/revert.c\n> index d4dcedbdc6..5dc5891ea2 100644\n> --- a/builtin/revert.c\n> +++ b/builtin/revert.c\n> @@ -102,6 +102,7 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)\n>  \t\tOPT_CMDMODE(0, \"quit\", &cmd, N_(\"end revert or cherry-pick sequence\"), 'q'),\n>  \t\tOPT_CMDMODE(0, \"continue\", &cmd, N_(\"resume revert or cherry-pick sequence\"), 'c'),\n>  \t\tOPT_CMDMODE(0, \"abort\", &cmd, N_(\"cancel revert or cherry-pick sequence\"), 'a'),\n> +\t\tOPT_CMDMODE(0, \"skip\", &cmd, N_(\"skip current commit and continue\"), 's'),\n>  \t\tOPT_CLEANUP(&cleanup_arg),\n>  \t\tOPT_BOOL('n', \"no-commit\", &opts->no_commit, N_(\"don't automatically commit\")),\n>  \t\tOPT_BOOL('e', \"edit\", &opts->edit, N_(\"edit the commit message\")),\n> @@ -151,6 +152,8 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)\n>  \t\t\tthis_operation = \"--quit\";\n>  \t\telse if (cmd == 'c')\n>  \t\t\tthis_operation = \"--continue\";\n> +\t\telse if (cmd == 's')\n> +\t\t\tthis_operation = \"--skip\";\n>  \t\telse {\n>  \t\t\tassert(cmd == 'a');\n>  \t\t\tthis_operation = \"--abort\";\n> @@ -210,6 +213,8 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)\n>  \t\treturn sequencer_continue(the_repository, opts);\n>  \tif (cmd == 'a')\n>  \t\treturn sequencer_rollback(the_repository, opts);\n> +\tif (cmd == 's')\n> +\t\treturn sequencer_skip(the_repository, opts);\n>  \treturn sequencer_pick_revisions(the_repository, opts);\n>  }\n>  \n> diff --git a/sequencer.c b/sequencer.c\n> index 9c561a041b..f586e677d3 100644\n> --- a/sequencer.c\n> +++ b/sequencer.c\n> @@ -2784,6 +2784,29 @@ int sequencer_rollback(struct repository *r, struct replay_opts *opts)\n>  \treturn -1;\n>  }\n>  \n> +int sequencer_skip(struct repository *r, struct replay_opts *opts)\n> +{\n> +\tswitch (opts->action) {\n> +\tcase REPLAY_REVERT:\n> +\t\tif (!file_exists(git_path_revert_head(r)))\n> +\t\t\treturn error(_(\"no revert in progress\"));\n\nThis error message is slightly misleading. If the user has already\ncommitted a conflict resolution then REVERT_HEAD/CHERRY_PICK_HEAD will\nnot exist but it is possible that a cherry-pick/revert is in progress if\nthe user was picking a sequence of commits. It would be nice to give a\ndifferent error message or maybe just a warning in that case.\nsequencer_get_last_command() should help with that.\n\n> +\t\tbreak;\n> +\tcase REPLAY_PICK:\n> +\t\tif (!file_exists(git_path_cherry_pick_head(r)))\n> +\t\t\treturn error(_(\"no cherry-pick in progress\"));\n> +\t\tbreak;\n> +\tdefault:\n> +\t\tBUG(\"the control must not reach here.\");\n> +\t}\n> +\n> +\tif (rollback_single_pick(r))\n> +\t\treturn error(_(\"failed to skip the commit\"));\n\nIf rollback_single_pick() sees that HEAD is the null oid then it gives\nthe error \"cannot abort from a branch yet to be born\". We're not\naborting and if we're picking a sequence of commits the skip ought\nsucceed, but it won't at the moment. If we're picking a single commit\nthen the skip should probably fail like abort but with an appropriate\nmessage. Admittedly that's all a bit of a corner case.\n\n> +\tif (!is_directory(git_path_seq_dir()))\n> +\t\treturn 0;\n> +\n> +\treturn sequencer_continue(r, opts);\n> +}\n> +\n>  static int save_todo(struct todo_list *todo_list, struct replay_opts *opts)\n>  {\n>  \tstruct lock_file todo_lock = LOCK_INIT;\n> diff --git a/sequencer.h b/sequencer.h\n> index 0c494b83d4..731b9853eb 100644\n> --- a/sequencer.h\n> +++ b/sequencer.h\n> @@ -129,6 +129,7 @@ int sequencer_pick_revisions(struct repository *repo,\n>  \t\t\t     struct replay_opts *opts);\n>  int sequencer_continue(struct repository *repo, struct replay_opts *opts);\n>  int sequencer_rollback(struct repository *repo, struct replay_opts *opts);\n> +int sequencer_skip(struct repository *repo, struct replay_opts *opts);\n>  int sequencer_remove_state(struct replay_opts *opts);\n>  \n>  #define TODO_LIST_KEEP_EMPTY (1U << 0)\n> diff --git a/t/t3510-cherry-pick-sequence.sh b/t/t3510-cherry-pick-sequence.sh\n> index 941d5026da..48cc9f13ee 100755\n> --- a/t/t3510-cherry-pick-sequence.sh\n> +++ b/t/t3510-cherry-pick-sequence.sh\n> @@ -93,6 +93,69 @@ test_expect_success 'cherry-pick cleans up sequencer state upon success' '\n>  \ttest_path_is_missing .git/sequencer\n>  '\n>  \n> +test_expect_success 'cherry-pick --skip requires cherry-pick in progress' '\n> +\tpristine_detach initial &&\n> +\ttest_must_fail git cherry-pick --skip\n> +'\n> +\n> +test_expect_success 'revert --skip requires revert in progress' '\n> +\tpristine_detach initial &&\n> +\ttest_must_fail git revert --skip\n> +'\n> +\n> +test_expect_success 'cherry-pick --skip to skip commit' '\n> +\tpristine_detach initial &&\n> +\ttest_must_fail git cherry-pick anotherpick &&\n> +\ttest_must_fail git revert --skip &&\n> +\tgit cherry-pick --skip &&\n> +\ttest_cmp_rev initial HEAD &&\n> +\ttest_path_is_missing .git/CHERRY_PICK_HEAD\n> +'\n> +\n> +test_expect_success 'revert --skip to skip commit' '\n> +\tpristine_detach anotherpick &&\n> +\ttest_must_fail git revert anotherpick~1 &&\n> +\ttest_must_fail git cherry-pick --skip &&\n> +\tgit revert --skip &&\n> +\ttest_cmp_rev anotherpick HEAD\n> +'\n> +\n> +test_expect_success 'skip \"empty\" commit' '\n> +\tpristine_detach picked &&\n> +\ttest_commit dummy foo d &&\n> +\ttest_must_fail git cherry-pick anotherpick &&\n> +\tgit cherry-pick --skip &&\n> +\ttest_cmp_rev dummy HEAD\n> +'\n> +\n> +test_expect_success 'skip a commit and check if rest of sequence is correct' '\n> +\tpristine_detach initial &&\n> +\techo e >expect &&\n> +\tcat >expect.log <<-EOF &&\n> +\tOBJID\n> +\t:100644 100644 OBJID OBJID M\tfoo\n> +\tOBJID\n> +\t:100644 100644 OBJID OBJID M\tfoo\n> +\tOBJID\n> +\t:100644 100644 OBJID OBJID M\tunrelated\n> +\tOBJID\n> +\t:000000 100644 OBJID OBJID A\tfoo\n> +\t:000000 100644 OBJID OBJID A\tunrelated\n> +\tEOF\n> +\ttest_must_fail git cherry-pick base..yetanotherpick &&\n> +\ttest_must_fail git cherry-pick --skip &&\n\nIt would be good to check that the cherry-pick has progressed since\n--skip and didn't just fail without trying to pick another commit.\n\n\nBest Wishes\n\nPhillip\n\n> +\techo d >foo &&\n> +\tgit add foo &&\n> +\tgit cherry-pick --continue &&\n> +\t{\n> +\t\tgit rev-list HEAD |\n> +\t\tgit diff-tree --root --stdin |\n> +\t\tsed \"s/$OID_REGEX/OBJID/g\"\n> +\t} >actual.log &&\n> +\ttest_cmp expect foo &&\n> +\ttest_cmp expect.log actual.log\n> +'\n> +\n>  test_expect_success '--quit does not complain when no cherry-pick is in progress' '\n>  \tpristine_detach initial &&\n>  \tgit cherry-pick --quit\n> \n\n"},{"id":"376890","messageId":"61a8bfde-018c-5a69-5abd-89d4a332e39e@gmail.com","threadId":"51269","inReplyTo":"20190608191958.4593-4-rohit.ashiwal265@gmail.com","subject":"Re: [GSoC][PATCH 3/3] cherry-pick/revert: update hints","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2019-06-09T18:03:02Z","receivedAt":"2019-06-09T18:06:44Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"Hi Rohit\n\nOn 08/06/2019 20:19, Rohit Ashiwal wrote:\n> Signed-off-by: Rohit Ashiwal <rohit.ashiwal265@gmail.com>\n> ---\n>  builtin/commit.c | 13 ++++++++-----\n>  sequencer.c      |  4 ++--\n>  2 files changed, 10 insertions(+), 7 deletions(-)\n> \n> diff --git a/builtin/commit.c b/builtin/commit.c\n> index 1c9e8e2228..1f47c51bdc 100644\n> --- a/builtin/commit.c\n> +++ b/builtin/commit.c\n> @@ -60,15 +60,18 @@ N_(\"The previous cherry-pick is now empty, possibly due to conflict resolution.\\\n>  \"\\n\");\n>  \n>  static const char empty_cherry_pick_advice_single[] =\n> -N_(\"Otherwise, please use 'git reset'\\n\");\n> +N_(\"Otherwise, please use 'git cherry-pick --skip'\\n\");\n>  \n>  static const char empty_cherry_pick_advice_multi[] =\n> -N_(\"If you wish to skip this commit, use:\\n\"\n> +N_(\"and then use:\\n\"\n>  \"\\n\"\n> -\"    git reset\\n\"\n> +\"    git cherry-pick --continue\\n\"\n>  \"\\n\"\n> -\"Then \\\"git cherry-pick --continue\\\" will resume cherry-picking\\n\"\n> -\"the remaining commits.\\n\");\n> +\"to resume cherry-picking the remaining commits.\\n\"\n> +\"If you wish to skip this commit, use:\\n\"\n> +\"\\n\"\n> +\"    git cherry-pick --skip\\n\"\n> +\"\\n\");\n>  \n>  static const char *color_status_slots[] = {\n>  \t[WT_STATUS_HEADER]\t  = \"header\",\n> diff --git a/sequencer.c b/sequencer.c\n> index f586e677d3..e889427eef 100644\n> --- a/sequencer.c\n> +++ b/sequencer.c\n> @@ -2654,8 +2654,8 @@ static int create_seq_dir(void)\n>  {\n>  \tif (file_exists(git_path_seq_dir())) {\n>  \t\terror(_(\"a cherry-pick or revert is already in progress\"));\n> -\t\tadvise(_(\"try \\\"git cherry-pick (--continue | --quit | --abort)\\\"\"));\n> -\t\tadvise(_(\"or  \\\"git revert (--continue | --quit | --abort)\\\"\"));\n> +\t\tadvise(_(\"try \\\"git cherry-pick (--continue | --skip | --quit | --abort)\\\"\"));\n> +\t\tadvise(_(\"or  \\\"git revert (--continue | --skip | --quit | --abort)\\\"\"));\n\nIf the user has already committed the conflict resolution then we don't\nwant to recommend --skip as there is nothing to skip.\n\nBest Wishes\n\nPhillip\n\n>  \t\treturn -1;\n>  \t} else if (mkdir(git_path_seq_dir(), 0777) < 0)\n>  \t\treturn error_errno(_(\"could not create sequencer directory '%s'\"),\n> \n\n"},{"id":"376892","messageId":"20190609200038.GD28007@hank.intra.tgummerer.com","threadId":"51269","inReplyTo":"CAL7ArXpMBXwOGXWmYx8Rv9bj2trJ-FS_VGgPmJbAh+evbaxNEw@mail.gmail.com","subject":"Re: [GSoC][PATCH 0/3] Teach cherry-pick/revert to skip commits","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2019-06-09T20:00:39Z","receivedAt":"2019-06-09T20:00:49Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"On 06/09, Rohit Ashiwal wrote:\n> > > PR: https://github.com/r1walz/git/pull/1\n> > > Reviewed-by: Elijah Newren <newren@gmail.com>\n> > > Reviewed-by: Thomas Gummerer <t.gummerer@gmail.com>\n> >\n> > Note that the 'Reviewed-by' footer is something that is \"given\" by the\n> > reviewers, and should only be added after they have explicitly given\n> > it for the patch/series in question.  Instead this should probably\n> > mention that Elijah and me reviewed this off-list in the PR you linked\n> > to above.\n> \n> Oh! But I read here, SubmittingPatches[1] docs, that it's nice to give\n> credits to those who helped you. Should we fix it in some way? I don't\n> know. Anyway, that is beyond the scope of this patch.\n\nRight, thanks for thinking about credit here.  The appropriate way to\ndo that would be to add a Helped-by trailer to the individual\ncommits, though especially for the first and last commit in the series\nwe probably don't deserve that much credit ;)  In past GSoC/Outreachy\nprojects I've also seen the Mentored-by trailer.\n\nOther than Helped-by, which I've commonly used seen for this they do\nseem to be (more or less) documented in SubmittingPatches [2].\n\n> Thanks for the review\n> Rohit\n> \n> [1]: https://github.com/git/git/blob/v2.22.0/Documentation/SubmittingPatches#L289-L291\n\n[2]: https://github.com/git/git/blob/b697d92f56511e804b8ba20ccbe7bdc85dc66810/Documentation/SubmittingPatches#L353-L365\n"},{"id":"376908","messageId":"20190610051313.16222-1-rohit.ashiwal265@gmail.com","threadId":"51269","inReplyTo":"2007ef79-1791-4f77-f9e4-34c59b4f0c36@gmail.com","subject":"Re: [GSoC][PATCH 1/3] sequencer: add advice for revert","fromName":"Rohit Ashiwal","fromEmail":"rohit.ashiwal265@gmail.com","sentAt":"2019-06-10T05:13:13Z","receivedAt":"2019-06-10T05:15:28Z","isPatch":true,"sender":{"key":"rohit.ashiwal265@gmail.com","avatar":"https://avatars.githubusercontent.com/u/31043830?v=4"},"body":"Hi Philip\n\nOn 2019-06-09 17:52 UTC Phillip Wood <phillip.wood123@gmail.com> wrote:\n>\n> Hi Rohit\n> \n> Congratulations on your first GSoC patch series!\n\nThank you very much :)\n\n> On 08/06/2019 20:19, Rohit Ashiwal wrote:\n> > [...]\n> > @@ -2655,6 +2655,7 @@ static int create_seq_dir(void)\n> >  \tif (file_exists(git_path_seq_dir())) {\n> >  \t\terror(_(\"a cherry-pick or revert is already in progress\"));\n> >  \t\tadvise(_(\"try \\\"git cherry-pick (--continue | --quit | --abort)\\\"\"));\n> > +\t\tadvise(_(\"or  \\\"git revert (--continue | --quit | --abort)\\\"\"));\n> \n> I agree that it's a good idea to add advice for revert as well, but it\n> would be better to call sequencer_get_last_command() to find out if\n> we're running cherry-pick or revert and tailor the advice appropriately.\n\nFirstly, signature of `create_seq_dir` doesn't allow us to call\n`sequencer_get_last_command()`. Changing that for the sake of a\nbetter error message is too much task for this patch as it is a\nsubject of discussion on its own. (Also changing signature only\nmakes sense if this patch series gets merged). FWIW, I think we\nshould left this to further discussions for now and decide what\nto do later on.\n\n> Best Wishes\n> \n> Phillip\n\nThanks\nRohit\n\n"},{"id":"376909","messageId":"20190610052823.17013-1-rohit.ashiwal265@gmail.com","threadId":"51269","inReplyTo":"61a8bfde-018c-5a69-5abd-89d4a332e39e@gmail.com","subject":"Re: [GSoC][PATCH 3/3] cherry-pick/revert: update hints","fromName":"Rohit Ashiwal","fromEmail":"rohit.ashiwal265@gmail.com","sentAt":"2019-06-10T05:28:23Z","receivedAt":"2019-06-10T05:30:35Z","isPatch":true,"sender":{"key":"rohit.ashiwal265@gmail.com","avatar":"https://avatars.githubusercontent.com/u/31043830?v=4"},"body":"Hey Phillip\n\nOn Sun, 9 Jun 2019 19:03:02 +0100 Phillip Wood <phillip.wood123@gmail.com> wrote:\n> \n> Hi Rohit\n> \n> On 08/06/2019 20:19, Rohit Ashiwal wrote:\n> > [...]\n> > @@ -2654,8 +2654,8 @@ static int create_seq_dir(void)\n> >  {\n> >  \tif (file_exists(git_path_seq_dir())) {\n> >  \t\terror(_(\"a cherry-pick or revert is already in progress\"));\n> > -\t\tadvise(_(\"try \\\"git cherry-pick (--continue | --quit | --abort)\\\"\"));\n> > -\t\tadvise(_(\"or  \\\"git revert (--continue | --quit | --abort)\\\"\"));\n> > +\t\tadvise(_(\"try \\\"git cherry-pick (--continue | --skip | --quit | --abort)\\\"\"));\n> > +\t\tadvise(_(\"or  \\\"git revert (--continue | --skip | --quit | --abort)\\\"\"));\n> \n> If the user has already committed the conflict resolution then we don't\n> want to recommend --skip as there is nothing to skip.\n\nI think it is more about suggesting what are all the possibilities\nyou can try and not about intelligently suggesting what you should\ndo. ofc, we can not use `revert --<option>` while cherry-picking.(\nwe should not be able to do so in ideal conditions, but the world\ndoes not work as we think it should). Still we are suggesting so\nhere.\n\nAlso, I think it is more reasonable to make \"this\" a part of patch\nwhich will cover \"tailored\" advice messages which is also a topic\nof discussion as I described here[1].\n\n> Best Wishes\n> \n> Phillip\n\nThanks\nRohit\n\n[1]: https://public-inbox.org/git/20190609200038.GD28007@hank.intra.tgummerer.com/T/#mbb071f6e29c69f291ecd9c61c71b889774ff33b2\n\n"},{"id":"376910","messageId":"20190610055719.19572-1-rohit.ashiwal265@gmail.com","threadId":"51269","inReplyTo":"0659a53e-0712-eb50-f15f-1c6a56fd3213@gmail.com","subject":"Re: [GSoC][PATCH 2/3] cherry-pick/revert: add --skip option","fromName":"Rohit Ashiwal","fromEmail":"rohit.ashiwal265@gmail.com","sentAt":"2019-06-10T05:57:19Z","receivedAt":"2019-06-10T05:59:31Z","isPatch":true,"sender":{"key":"rohit.ashiwal265@gmail.com","avatar":"https://avatars.githubusercontent.com/u/31043830?v=4"},"body":"Hey Phillip\n\nOn Sun, 9 Jun 2019 19:01:35 +0100 Phillip Wood <phillip.wood123@gmail.com> wrote:\n>\n> Hi Rohit\n> \n> --skip is definitely a useful addition to cherry-pick/revert\n> \n> On 08/06/2019 20:19, Rohit Ashiwal wrote:\n> >\n> > [...]\n> > @@ -2784,6 +2784,29 @@ int sequencer_rollback(struct repository *r, struct replay_opts *opts)\n> >  \treturn -1;\n> >  }\n> >  \n> > +int sequencer_skip(struct repository *r, struct replay_opts *opts)\n> > +{\n> > +\tswitch (opts->action) {\n> > +\tcase REPLAY_REVERT:\n> > +\t\tif (!file_exists(git_path_revert_head(r)))\n> > +\t\t\treturn error(_(\"no revert in progress\"));\n> \n> This error message is slightly misleading. If the user has already\n> committed a conflict resolution then REVERT_HEAD/CHERRY_PICK_HEAD will\n> not exist but it is possible that a cherry-pick/revert is in progress if\n> the user was picking a sequence of commits. It would be nice to give a\n> different error message or maybe just a warning in that case.\n> sequencer_get_last_command() should help with that.\n\nYes, .git/{REVERT|CHERRY_PICK}_HEAD will not exist in this case, but\nin case of cherry-picking/reverting:\n\n1. multiple commits:\n    sequencer dir will exist which will throw out the error listed\n    under `create_seq_dir`\n2. single commit:\n    Then ACTION is already over and there is nothing to do and the\n    error is correct.\n\n> > +\t\tbreak;\n> > +\tcase REPLAY_PICK:\n> > +\t\tif (!file_exists(git_path_cherry_pick_head(r)))\n> > +\t\t\treturn error(_(\"no cherry-pick in progress\"));\n> > +\t\tbreak;\n> > +\tdefault:\n> > +\t\tBUG(\"the control must not reach here.\");\n> > +\t}\n> > +\n> > +\tif (rollback_single_pick(r))\n> > +\t\treturn error(_(\"failed to skip the commit\"));\n> \n> If rollback_single_pick() sees that HEAD is the null oid then it gives\n> the error \"cannot abort from a branch yet to be born\". We're not\n> aborting and if we're picking a sequence of commits the skip ought\n> succeed, but it won't at the moment. If we're picking a single commit\n> then the skip should probably fail like abort but with an appropriate\n> message. Admittedly that's all a bit of a corner case.\n\nYes, you are right here. We could actually modify the advice there\nto be more like _(\"cannot perform the specified action, the branch\nis yet to be born\") and I think it should suffice this. What do you\nthink?\n\n> > [...]\n> > +test_expect_success 'skip a commit and check if rest of sequence is correct' '\n> > +\tpristine_detach initial &&\n> > +\techo e >expect &&\n> > +\tcat >expect.log <<-EOF &&\n> > +\tOBJID\n> > +\t:100644 100644 OBJID OBJID M\tfoo\n> > +\tOBJID\n> > +\t:100644 100644 OBJID OBJID M\tfoo\n> > +\tOBJID\n> > +\t:100644 100644 OBJID OBJID M\tunrelated\n> > +\tOBJID\n> > +\t:000000 100644 OBJID OBJID A\tfoo\n> > +\t:000000 100644 OBJID OBJID A\tunrelated\n> > +\tEOF\n> > +\ttest_must_fail git cherry-pick base..yetanotherpick &&\n> > +\ttest_must_fail git cherry-pick --skip &&\n> \n> It would be good to check that the cherry-pick has progressed since\n> --skip and didn't just fail without trying to pick another commit.\n\nThe overall test tests that only, if cherry-pick --skip \"failed\" then\nwe won't get 'e' inside of `foo` and `test_cmp expect foo` will also\nfail and if it skipped wrongly then expect.log will not match the\nactual.log and `test_cmp` will fail. Am I missing something here?\nPlease tell if so.\n \n> Best Wishes\n> \n> Phillip\n\nThanks\nRohit\n\n"},{"id":"376918","messageId":"d59c078c-61da-1c3a-d215-80c9e3d08896@gmail.com","threadId":"51269","inReplyTo":"20190610051313.16222-1-rohit.ashiwal265@gmail.com","subject":"Re: [GSoC][PATCH 1/3] sequencer: add advice for revert","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2019-06-10T10:39:58Z","receivedAt":"2019-06-10T10:39:53Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"Hi Rohit\n\nOn 10/06/2019 06:13, Rohit Ashiwal wrote:\n> Hi Philip\n> \n> On 2019-06-09 17:52 UTC Phillip Wood <phillip.wood123@gmail.com> wrote:\n>>\n>> Hi Rohit\n>>\n>> Congratulations on your first GSoC patch series!\n> \n> Thank you very much :)\n> \n>> On 08/06/2019 20:19, Rohit Ashiwal wrote:\n>>> [...]\n>>> @@ -2655,6 +2655,7 @@ static int create_seq_dir(void)\n>>>  \tif (file_exists(git_path_seq_dir())) {\n>>>  \t\terror(_(\"a cherry-pick or revert is already in progress\"));\n>>>  \t\tadvise(_(\"try \\\"git cherry-pick (--continue | --quit | --abort)\\\"\"));\n>>> +\t\tadvise(_(\"or  \\\"git revert (--continue | --quit | --abort)\\\"\"));\n>>\n>> I agree that it's a good idea to add advice for revert as well, but it\n>> would be better to call sequencer_get_last_command() to find out if\n>> we're running cherry-pick or revert and tailor the advice appropriately.\n> \n> Firstly, signature of `create_seq_dir` doesn't allow us to call\n> `sequencer_get_last_command()`. Changing that for the sake of a\n> better error message is too much task for this patch as it is a\n> subject of discussion on its own.\n\nThere is only one caller and it already has a struct repository pointer\nso it is a two line change, one of which is the insertion of a single\ncharacter to change create_seq_dir() so it can call\nsequencer_get_last_command(). It is normal to change function signatures\n(especially for static functions like this) when making changes, it is\npart of improving the code base. The quality of error messages is\nimportant to the overall user experience. It's when things go wrong that\nusers need accurate advice about what to do.\n\n> (Also changing signature only\n> makes sense if this patch series gets merged). FWIW, I think we\n> should left this to further discussions for now and decide what\n> to do later on.\n\nIt is only a small change so why not do it now rather than putting it\noff for another series which will be more work in the long run.\n\nBest Wishes\n\nPhillip\n\n> \n>> Best Wishes\n>>\n>> Phillip\n> \n> Thanks\n> Rohit\n> \n\n"},{"id":"376919","messageId":"2488ef91-b9e5-1836-aeea-2aaf11c3c383@gmail.com","threadId":"51269","inReplyTo":"20190610055719.19572-1-rohit.ashiwal265@gmail.com","subject":"Re: [GSoC][PATCH 2/3] cherry-pick/revert: add --skip option","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2019-06-10T10:40:21Z","receivedAt":"2019-06-10T10:40:14Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"Hi Rohit\n\nOn 10/06/2019 06:57, Rohit Ashiwal wrote:\n> Hey Phillip\n> \n> On Sun, 9 Jun 2019 19:01:35 +0100 Phillip Wood <phillip.wood123@gmail.com> wrote:\n>>\n>> Hi Rohit\n>>\n>> --skip is definitely a useful addition to cherry-pick/revert\n>>\n>> On 08/06/2019 20:19, Rohit Ashiwal wrote:\n>>>\n>>> [...]\n>>> @@ -2784,6 +2784,29 @@ int sequencer_rollback(struct repository *r, struct replay_opts *opts)\n>>>  \treturn -1;\n>>>  }\n>>>  \n>>> +int sequencer_skip(struct repository *r, struct replay_opts *opts)\n>>> +{\n>>> +\tswitch (opts->action) {\n>>> +\tcase REPLAY_REVERT:\n>>> +\t\tif (!file_exists(git_path_revert_head(r)))\n>>> +\t\t\treturn error(_(\"no revert in progress\"));\n>>\n>> This error message is slightly misleading. If the user has already\n>> committed a conflict resolution then REVERT_HEAD/CHERRY_PICK_HEAD will\n>> not exist but it is possible that a cherry-pick/revert is in progress if\n>> the user was picking a sequence of commits. It would be nice to give a\n>> different error message or maybe just a warning in that case.\n>> sequencer_get_last_command() should help with that.\n\nIt's actually a bit more complicated as if the cherry-pick failed\nbecause it would have overwriten untracked files then CHERRY_PICK_HEAD\nwill not exist but we want to be able to skip that pick. So it should\nnot error out in that case either. (I think you may be able to use the\nabort safety file (see rollback_is_safe()) to distinguish the 'failed to\npick case' from the 'user committed a conflict resolution' case.)\n\n> Yes, .git/{REVERT|CHERRY_PICK}_HEAD will not exist in this case, but\n> in case of cherry-picking/reverting:\n> \n> 1. multiple commits:\n>     sequencer dir will exist which will throw out the error listed\n>     under `create_seq_dir`\n\nI don't understand. Wont it will error out here? Why would we call\ncreate_seq_dir() for --skip?\n\n> 2. single commit:\n>     Then ACTION is already over and there is nothing to do and the\n>     error is correct.\n> \n>>> +\t\tbreak;\n>>> +\tcase REPLAY_PICK:\n>>> +\t\tif (!file_exists(git_path_cherry_pick_head(r)))\n>>> +\t\t\treturn error(_(\"no cherry-pick in progress\"));\n>>> +\t\tbreak;\n>>> +\tdefault:\n>>> +\t\tBUG(\"the control must not reach here.\");\n>>> +\t}\n>>> +\n>>> +\tif (rollback_single_pick(r))\n>>> +\t\treturn error(_(\"failed to skip the commit\"));\n>>\n>> If rollback_single_pick() sees that HEAD is the null oid then it gives\n>> the error \"cannot abort from a branch yet to be born\". We're not\n>> aborting and if we're picking a sequence of commits the skip ought\n>> succeed, but it won't at the moment. If we're picking a single commit\n>> then the skip should probably fail like abort but with an appropriate\n>> message. Admittedly that's all a bit of a corner case.\n> \n> Yes, you are right here. We could actually modify the advice there\n> to be more like _(\"cannot perform the specified action, the branch\n> is yet to be born\") and I think it should suffice this. What do you\n> think?\n\nI think it should allow the user to skip if there are more commits to\npick . Just changing the error message does not fix that.\n\n> \n>>> [...]\n>>> +test_expect_success 'skip a commit and check if rest of sequence is correct' '\n>>> +\tpristine_detach initial &&\n>>> +\techo e >expect &&\n>>> +\tcat >expect.log <<-EOF &&\n>>> +\tOBJID\n>>> +\t:100644 100644 OBJID OBJID M\tfoo\n>>> +\tOBJID\n>>> +\t:100644 100644 OBJID OBJID M\tfoo\n>>> +\tOBJID\n>>> +\t:100644 100644 OBJID OBJID M\tunrelated\n>>> +\tOBJID\n>>> +\t:000000 100644 OBJID OBJID A\tfoo\n>>> +\t:000000 100644 OBJID OBJID A\tunrelated\n>>> +\tEOF\n>>> +\ttest_must_fail git cherry-pick base..yetanotherpick &&\n>>> +\ttest_must_fail git cherry-pick --skip &&\n>>\n>> It would be good to check that the cherry-pick has progressed since\n>> --skip and didn't just fail without trying to pick another commit.\n> \n> The overall test tests that only, if cherry-pick --skip \"failed\" then\n> we won't get 'e' inside of `foo` and `test_cmp expect foo` will also\n> fail and if it skipped wrongly then expect.log will not match the\n> actual.log and `test_cmp` will fail. Am I missing something here?\n> Please tell if so.\n\nYou're right that the tests at the end would probably pick up a failure,\nbut I'm concerned that there could be some obscure corner case we've not\nthought of so checking HEAD and the file contents here would be an\nadditional safety measure. It also makes it easier for someone tracking\ndown a test failure to see what happened. If they rely only on the test\nat the end they need to spend time to understand where the mismatched\ncontents came from.\n\nBest Wishes\n\nPhillip\n\n\n>  \n>> Best Wishes\n>>\n>> Phillip\n> \n> Thanks\n> Rohit\n> \n\n"},{"id":"376920","messageId":"72b44513-1182-8172-94aa-ca69730d9a22@gmail.com","threadId":"51269","inReplyTo":"20190610052823.17013-1-rohit.ashiwal265@gmail.com","subject":"Re: [GSoC][PATCH 3/3] cherry-pick/revert: update hints","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2019-06-10T10:40:30Z","receivedAt":"2019-06-10T10:40:21Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"Hi Rohit\n\nOn 10/06/2019 06:28, Rohit Ashiwal wrote:\n> Hey Phillip\n> \n> On Sun, 9 Jun 2019 19:03:02 +0100 Phillip Wood <phillip.wood123@gmail.com> wrote:\n>>\n>> Hi Rohit\n>>\n>> On 08/06/2019 20:19, Rohit Ashiwal wrote:\n>>> [...]\n>>> @@ -2654,8 +2654,8 @@ static int create_seq_dir(void)\n>>>  {\n>>>  \tif (file_exists(git_path_seq_dir())) {\n>>>  \t\terror(_(\"a cherry-pick or revert is already in progress\"));\n>>> -\t\tadvise(_(\"try \\\"git cherry-pick (--continue | --quit | --abort)\\\"\"));\n>>> -\t\tadvise(_(\"or  \\\"git revert (--continue | --quit | --abort)\\\"\"));\n>>> +\t\tadvise(_(\"try \\\"git cherry-pick (--continue | --skip | --quit | --abort)\\\"\"));\n>>> +\t\tadvise(_(\"or  \\\"git revert (--continue | --skip | --quit | --abort)\\\"\"));\n>>\n>> If the user has already committed the conflict resolution then we don't\n>> want to recommend --skip as there is nothing to skip.\n> I think it is more about suggesting what are all the possibilities\n> you can try and not about intelligently suggesting what you should\n> do.\n\nPreviously all the suggested options were viable, --skip is not\napplicable if the user has committed a conflict resolution. The idea of\nthe advice is to help the user, suggesting options that wont work is not\ngoing to help them.\n\n> ofc, we can not use `revert --<option>` while cherry-picking.(\n\nAs I suggested in patch 1 we should tailor the error message to the command.\n\n> we should not be able to do so in ideal conditions, but the world\n> does not work as we think it should). Still we are suggesting so\n> here.\n\nYes because you have the power to easily make that change. It is normal\nto try and improve the code base when we make related changes.\n\n> Also, I think it is more reasonable to make \"this\" a part of patch\n> which will cover \"tailored\" advice messages which is also a topic\n> of discussion as I described here[1].\n\nThat might make sense, but it is a pretty self contained change as part\nof this patch.\n\nBest Wishes\n\nPhillip\n\n> \n>> Best Wishes\n>>\n>> Phillip\n> \n> Thanks\n> Rohit\n> \n> [1]: https://public-inbox.org/git/20190609200038.GD28007@hank.intra.tgummerer.com/T/#mbb071f6e29c69f291ecd9c61c71b889774ff33b2\n> \n\n"},{"id":"376923","messageId":"20190610132509.7581-1-rohit.ashiwal265@gmail.com","threadId":"51269","inReplyTo":"d59c078c-61da-1c3a-d215-80c9e3d08896@gmail.com","subject":"Re: [GSoC][PATCH 1/3] sequencer: add advice for revert","fromName":"Rohit Ashiwal","fromEmail":"rohit.ashiwal265@gmail.com","sentAt":"2019-06-10T13:25:09Z","receivedAt":"2019-06-10T13:27:19Z","isPatch":true,"sender":{"key":"rohit.ashiwal265@gmail.com","avatar":"https://avatars.githubusercontent.com/u/31043830?v=4"},"body":"Hi Phillip\n\nOn 2019-06-10 10:39 UTC Phillip Wood <phillip.wood123@gmail.com> wrote:\n>\n>Hi Rohit\n>\n>On 10/06/2019 06:13, Rohit Ashiwal wrote:\n>>\n>> [...]\n>> Firstly, signature of `create_seq_dir` doesn't allow us to call\n>> `sequencer_get_last_command()`. Changing that for the sake of a\n>> better error message is too much task for this patch as it is a\n>> subject of discussion on its own.\n>\n> There is only one caller and it already has a struct repository pointer\n> so it is a two line change, one of which is the insertion of a single\n> character to change create_seq_dir() so it can call\n> sequencer_get_last_command(). It is normal to change function signatures\n> (especially for static functions like this) when making changes, it is\n> part of improving the code base. The quality of error messages is\n> important to the overall user experience. It's when things go wrong that\n> users need accurate advice about what to do.\n\nNice! I'll do this in next revision then.\n\n>> (Also changing signature only\n>> makes sense if this patch series gets merged). FWIW, I think we\n>> should left this to further discussions for now and decide what\n>> to do later on.\n>\n> It is only a small change so why not do it now rather than putting it\n> off for another series which will be more work in the long run.\n\nI'm fine with changing that here.\n\nThanks\nRohit\n\n"},{"id":"376925","messageId":"20190610133321.7901-1-rohit.ashiwal265@gmail.com","threadId":"51269","inReplyTo":"72b44513-1182-8172-94aa-ca69730d9a22@gmail.com","subject":"Re: [GSoC][PATCH 3/3] cherry-pick/revert: update hints","fromName":"Rohit Ashiwal","fromEmail":"rohit.ashiwal265@gmail.com","sentAt":"2019-06-10T13:33:21Z","receivedAt":"2019-06-10T13:35:29Z","isPatch":true,"sender":{"key":"rohit.ashiwal265@gmail.com","avatar":"https://avatars.githubusercontent.com/u/31043830?v=4"},"body":"Hi Phillip\n\nOn 2019-06-10 10:40 UTC Phillip Wood <phillip.wood123@gmail.com> wrote:\n>\n> Hi Rohit\n>\n> On 10/06/2019 06:28, Rohit Ashiwal wrote:\n>> Hey Phillip\n>>\n>> On Sun, 9 Jun 2019 19:03:02 +0100 Phillip Wood <phillip.wood123@gmail.com> wrote:\n>>>\n>>> Hi Rohit\n>> [...]\n>> I think it is more about suggesting what are all the possibilities\n>> you can try and not about intelligently suggesting what you should\n>> do.\n>\n> Previously all the suggested options were viable, --skip is not\n> applicable if the user has committed a conflict resolution. The idea of\n> the advice is to help the user, suggesting options that wont work is not\n> going to help them.\n\nNow that I know what I should do, I'll make the change and submit a\nbetter patch.\n\n>> ofc, we can not use `revert --<option>` while cherry-picking.(\n>\n> As I suggested in patch 1 we should tailor the error message to the command.\n\nYes, I'll tailor the messages based on which command was ran.\n\n>> we should not be able to do so in ideal conditions, but the world\n>> does not work as we think it should). Still we are suggesting so\n>> here.\n>\n> Yes because you have the power to easily make that change. It is normal\n> to try and improve the code base when we make related changes.\n\n:)\n\n>> Also, I think it is more reasonable to make \"this\" a part of patch\n>> which will cover \"tailored\" advice messages which is also a topic\n>> of discussion as I described here[1].\n>\n> That might make sense, but it is a pretty self contained change as part\n> of this patch.\n\nYes, this patch is the place where all changes should be made.\n\nThanks\nRohit\n\n"},{"id":"376926","messageId":"20190610134321.8203-1-rohit.ashiwal265@gmail.com","threadId":"51269","inReplyTo":"2488ef91-b9e5-1836-aeea-2aaf11c3c383@gmail.com","subject":"Re: [GSoC][PATCH 2/3] cherry-pick/revert: add --skip option","fromName":"Rohit Ashiwal","fromEmail":"rohit.ashiwal265@gmail.com","sentAt":"2019-06-10T13:43:21Z","receivedAt":"2019-06-10T13:45:30Z","isPatch":true,"sender":{"key":"rohit.ashiwal265@gmail.com","avatar":"https://avatars.githubusercontent.com/u/31043830?v=4"},"body":"Hi Phillip\n\nOn 2019-06-10 10:40 UTC Phillip Wood <phillip.wood123@gmail.com> wrote:\n>\n> [...]\n> It's actually a bit more complicated as if the cherry-pick failed\n> because it would have overwriten untracked files then CHERRY_PICK_HEAD\n> will not exist but we want to be able to skip that pick. So it should\n> not error out in that case either. (I think you may be able to use the\n> abort safety file (see rollback_is_safe()) to distinguish the 'failed to\n> pick case' from the 'user committed a conflict resolution' case.)\n\nOh! I was thinking about some other case. (spawing another cherry-pick,\nwhich is wrong since the topic is --skip). I'm sorry. \n\n>> Yes, .git/{REVERT|CHERRY_PICK}_HEAD will not exist in this case, but\n>> in case of cherry-picking/reverting:\n>> \n>> 1. multiple commits:\n>>     sequencer dir will exist which will throw out the error listed\n>>     under `create_seq_dir`\n>\n> I don't understand. Wont it will error out here? Why would we call\n> create_seq_dir() for --skip?\n\nNo, you are correct. This won't skip commit in this case. I'll change\nit to do the required.\n\n>>> If rollback_single_pick() sees that HEAD is the null oid then it gives\n>>> the error \"cannot abort from a branch yet to be born\". We're not\n>>> aborting and if we're picking a sequence of commits the skip ought\n>>> succeed, but it won't at the moment. If we're picking a single commit\n>>> then the skip should probably fail like abort but with an appropriate\n>>> message. Admittedly that's all a bit of a corner case.\n>> \n>> Yes, you are right here. We could actually modify the advice there\n>> to be more like _(\"cannot perform the specified action, the branch\n>> is yet to be born\") and I think it should suffice this. What do you\n>> think?\n>\n> I think it should allow the user to skip if there are more commits to\n> pick . Just changing the error message does not fix that.\n\nRight! I'll check what can be done here.\n\n>> The overall test tests that only, if cherry-pick --skip \"failed\" then\n>> we won't get 'e' inside of `foo` and `test_cmp expect foo` will also\n>> fail and if it skipped wrongly then expect.log will not match the\n>> actual.log and `test_cmp` will fail. Am I missing something here?\n>> Please tell if so.\n>\n> You're right that the tests at the end would probably pick up a failure,\n> but I'm concerned that there could be some obscure corner case we've not\n> thought of so checking HEAD and the file contents here would be an\n> additional safety measure. It also makes it easier for someone tracking\n> down a test failure to see what happened. If they rely only on the test\n> at the end they need to spend time to understand where the mismatched\n> contents came from.\n\nYes, it is worth checking here if HEAD after cherry-picking is in the\ncorrect position, same for the file foo. I'll change this test too.\nThanks for pointing out.\n\nThanks for the review\nRohit\n\n"},{"id":"376946","messageId":"xmqqk1dto0vo.fsf@gitster-ct.c.googlers.com","threadId":"51269","inReplyTo":"d59c078c-61da-1c3a-d215-80c9e3d08896@gmail.com","subject":"Re: [GSoC][PATCH 1/3] sequencer: add advice for revert","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-06-10T16:34:19Z","receivedAt":"2019-06-10T16:34:25Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Phillip Wood <phillip.wood123@gmail.com> writes:\n\n>> Firstly, signature of `create_seq_dir` doesn't allow us to call\n>> `sequencer_get_last_command()`. Changing that for the sake of a\n>> better error message is too much task for this patch as it is a\n>> subject of discussion on its own.\n>\n> There is only one caller and it already has a struct repository pointer\n> so it is a two line change, one of which is the insertion of a single\n> character to change create_seq_dir() so it can call\n> sequencer_get_last_command(). It is normal to change function signatures\n> (especially for static functions like this) when making changes, it is\n> part of improving the code base. The quality of error messages is\n> important to the overall user experience. It's when things go wrong that\n> users need accurate advice about what to do.\n\nThanks for guiding a new contributor in the right direction gently.\nVery much appreciated.\n"},{"id":"376954","messageId":"80217c99-8113-6320-e413-4a5646fd4ea5@gmail.com","threadId":"51269","inReplyTo":"20190610132509.7581-1-rohit.ashiwal265@gmail.com","subject":"Re: [GSoC][PATCH 1/3] sequencer: add advice for revert","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2019-06-10T17:46:50Z","receivedAt":"2019-06-10T17:46:43Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"Hi Rohit\n\nOn 10/06/2019 14:25, Rohit Ashiwal wrote:\n> Hi Phillip\n> \n> On 2019-06-10 10:39 UTC Phillip Wood <phillip.wood123@gmail.com> wrote:\n>>\n>> Hi Rohit\n>>\n>> On 10/06/2019 06:13, Rohit Ashiwal wrote:\n>>>\n>>> [...]\n>>> Firstly, signature of `create_seq_dir` doesn't allow us to call\n>>> `sequencer_get_last_command()`. Changing that for the sake of a\n>>> better error message is too much task for this patch as it is a\n>>> subject of discussion on its own.\n>>\n>> There is only one caller and it already has a struct repository pointer\n>> so it is a two line change, one of which is the insertion of a single\n>> character to change create_seq_dir() so it can call\n>> sequencer_get_last_command(). It is normal to change function signatures\n>> (especially for static functions like this) when making changes, it is\n>> part of improving the code base. The quality of error messages is\n>> important to the overall user experience. It's when things go wrong that\n>> users need accurate advice about what to do.\n> \n> Nice! I'll do this in next revision then.\n\nI'm glad that helped\n\n> \n>>> (Also changing signature only\n>>> makes sense if this patch series gets merged). FWIW, I think we\n>>> should left this to further discussions for now and decide what\n>>> to do later on.\n>>\n>> It is only a small change so why not do it now rather than putting it\n>> off for another series which will be more work in the long run.\n> \n> I'm fine with changing that here.\n\nThat's great\n\nBest Wishes\n\nPhillip\n\n> \n> Thanks\n> Rohit\n> \n\n"},{"id":"376955","messageId":"00733b69-7c9d-2aba-42e3-3a2f85f29007@gmail.com","threadId":"51269","inReplyTo":"20190610134321.8203-1-rohit.ashiwal265@gmail.com","subject":"Re: [GSoC][PATCH 2/3] cherry-pick/revert: add --skip option","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2019-06-10T17:47:00Z","receivedAt":"2019-06-10T17:46:53Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"Hi Rohit\n\nOn 10/06/2019 14:43, Rohit Ashiwal wrote:\n> Hi Phillip\n> \n> On 2019-06-10 10:40 UTC Phillip Wood <phillip.wood123@gmail.com> wrote:\n>>\n>> [...]\n>> It's actually a bit more complicated as if the cherry-pick failed\n>> because it would have overwriten untracked files then CHERRY_PICK_HEAD\n>> will not exist but we want to be able to skip that pick. So it should\n>> not error out in that case either. (I think you may be able to use the\n>> abort safety file (see rollback_is_safe()) to distinguish the 'failed to\n>> pick case' from the 'user committed a conflict resolution' case.)\n> \n> Oh! I was thinking about some other case. (spawing another cherry-pick,\n> which is wrong since the topic is --skip). I'm sorry. \n> \n>>> Yes, .git/{REVERT|CHERRY_PICK}_HEAD will not exist in this case, but\n>>> in case of cherry-picking/reverting:\n>>>\n>>> 1. multiple commits:\n>>>     sequencer dir will exist which will throw out the error listed\n>>>     under `create_seq_dir`\n>>\n>> I don't understand. Wont it will error out here? Why would we call\n>> create_seq_dir() for --skip?\n> \n> No, you are correct. This won't skip commit in this case. I'll change\n> it to do the required.\n\nShout if you get stuck. I think distinguishing the \"user committed a\nconflict resolution and so we don't want to skip\" from the \"the pick\nwould have overwritten an untracked file so we do want to skip\" cases\nshould be possible by calling rollback_is_safe(). It would be good to\nhave a test case for at least the \"pick would have overwritten an\nuntracked file case\" as that would be easy to break in the future\nwithout noticing as it's a rare situation.\n\n> \n>>>> If rollback_single_pick() sees that HEAD is the null oid then it gives\n>>>> the error \"cannot abort from a branch yet to be born\". We're not\n>>>> aborting and if we're picking a sequence of commits the skip ought\n>>>> succeed, but it won't at the moment. If we're picking a single commit\n>>>> then the skip should probably fail like abort but with an appropriate\n>>>> message. Admittedly that's all a bit of a corner case.\n>>>\n>>> Yes, you are right here. We could actually modify the advice there\n>>> to be more like _(\"cannot perform the specified action, the branch\n>>> is yet to be born\") and I think it should suffice this. What do you\n>>> think?\n>>\n>> I think it should allow the user to skip if there are more commits to\n>> pick . Just changing the error message does not fix that.\n> \n> Right! I'll check what can be done here.\n\nI think you can just pass a flag to rollback_single_pick() to tell it\nwhether it is rolling back for --skip or --abort so it can do the right\nthing.\n\nBest Wishes\n\nPhillip\n\n> \n>>> The overall test tests that only, if cherry-pick --skip \"failed\" then\n>>> we won't get 'e' inside of `foo` and `test_cmp expect foo` will also\n>>> fail and if it skipped wrongly then expect.log will not match the\n>>> actual.log and `test_cmp` will fail. Am I missing something here?\n>>> Please tell if so.\n>>\n>> You're right that the tests at the end would probably pick up a failure,\n>> but I'm concerned that there could be some obscure corner case we've not\n>> thought of so checking HEAD and the file contents here would be an\n>> additional safety measure. It also makes it easier for someone tracking\n>> down a test failure to see what happened. If they rely only on the test\n>> at the end they need to spend time to understand where the mismatched\n>> contents came from.\n> \n> Yes, it is worth checking here if HEAD after cherry-picking is in the\n> correct position, same for the file foo. I'll change this test too.\n> Thanks for pointing out.\n> \n> Thanks for the review\n> Rohit\n> \n\n"},{"id":"376956","messageId":"81dbc317-c11f-c3b4-f20f-cff20254d626@gmail.com","threadId":"51269","inReplyTo":"20190610133321.7901-1-rohit.ashiwal265@gmail.com","subject":"Re: [GSoC][PATCH 3/3] cherry-pick/revert: update hints","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2019-06-10T17:47:11Z","receivedAt":"2019-06-10T17:47:03Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"Hi Rohit\n\nOn 10/06/2019 14:33, Rohit Ashiwal wrote:\n> Hi Phillip\n> \n> On 2019-06-10 10:40 UTC Phillip Wood <phillip.wood123@gmail.com> wrote:\n>>\n>> Hi Rohit\n>>\n>> On 10/06/2019 06:28, Rohit Ashiwal wrote:\n>>> Hey Phillip\n>>>\n>>> On Sun, 9 Jun 2019 19:03:02 +0100 Phillip Wood <phillip.wood123@gmail.com> wrote:\n>>>>\n>>>> Hi Rohit\n>>> [...]\n>>> I think it is more about suggesting what are all the possibilities\n>>> you can try and not about intelligently suggesting what you should\n>>> do.\n>>\n>> Previously all the suggested options were viable, --skip is not\n>> applicable if the user has committed a conflict resolution. The idea of\n>> the advice is to help the user, suggesting options that wont work is not\n>> going to help them.\n> \n> Now that I know what I should do, I'll make the change and submit a\n> better patch.\n\n\nThat's great, thanks\n\nPhillip\n\n>>> ofc, we can not use `revert --<option>` while cherry-picking.(\n>>\n>> As I suggested in patch 1 we should tailor the error message to the command.\n> \n> Yes, I'll tailor the messages based on which command was ran.\n> \n>>> we should not be able to do so in ideal conditions, but the world\n>>> does not work as we think it should). Still we are suggesting so\n>>> here.\n>>\n>> Yes because you have the power to easily make that change. It is normal\n>> to try and improve the code base when we make related changes.\n> \n> :)\n> \n>>> Also, I think it is more reasonable to make \"this\" a part of patch\n>>> which will cover \"tailored\" advice messages which is also a topic\n>>> of discussion as I described here[1].\n>>\n>> That might make sense, but it is a pretty self contained change as part\n>> of this patch.\n> \n> Yes, this patch is the place where all changes should be made.\n> \n> Thanks\n> Rohit\n> \n\n"},{"id":"376993","messageId":"20190611073152.12214-1-rohit.ashiwal265@gmail.com","threadId":"51269","inReplyTo":"20190608191958.4593-1-rohit.ashiwal265@gmail.com","subject":"[GSoC][PATCH v2 0/3] Teach cherry-pick/revert to skip commits","fromName":"Rohit Ashiwal","fromEmail":"rohit.ashiwal265@gmail.com","sentAt":"2019-06-11T07:31:49Z","receivedAt":"2019-06-11T07:34:14Z","isPatch":true,"sender":{"key":"rohit.ashiwal265@gmail.com","avatar":"https://avatars.githubusercontent.com/u/31043830?v=4"},"body":"Adding a `--skip` option to make skipping commits easier for the user\nand to make the commands more consistent. This will serve as a small\nstep to the bigger goal which improving consistency of sequencer commands.\n\nRohit Ashiwal (3):\n  sequencer: add advice for revert\n  cherry-pick/revert: add --skip option\n  cherry-pick/revert: advise using --skip\n\n Documentation/git-cherry-pick.txt |   4 +-\n Documentation/git-revert.txt      |   4 +-\n Documentation/sequencer.txt       |   4 +\n builtin/commit.c                  |  13 ++--\n builtin/revert.c                  |   5 ++\n sequencer.c                       |  88 +++++++++++++++++++--\n sequencer.h                       |   1 +\n t/t3510-cherry-pick-sequence.sh   | 124 ++++++++++++++++++++++++++++++\n 8 files changed, 225 insertions(+), 18 deletions(-)\n\n-- \n2.21.0\n\n"},{"id":"376994","messageId":"20190611073152.12214-2-rohit.ashiwal265@gmail.com","threadId":"51269","inReplyTo":"20190611073152.12214-1-rohit.ashiwal265@gmail.com","subject":"[GSoC][PATCH v2 1/3] sequencer: add advice for revert","fromName":"Rohit Ashiwal","fromEmail":"rohit.ashiwal265@gmail.com","sentAt":"2019-06-11T07:31:50Z","receivedAt":"2019-06-11T07:34:20Z","isPatch":true,"sender":{"key":"rohit.ashiwal265@gmail.com","avatar":"https://avatars.githubusercontent.com/u/31043830?v=4"},"body":"In the case of merge conflicts, while performing a revert, we are\ncurrently advised to use `git cherry-pick --<sequencer-options>`\nof which --continue is incompatible for continuing the revert.\nIntroduce a separate advice message for `git revert`. Also change\nthe signature of `create_seq_dir` to handle which advice to display\nselectively.\n\nSigned-off-by: Rohit Ashiwal <rohit.ashiwal265@gmail.com>\n---\nwhat has changed:\n    Following Phillip's advice, I've changed the signature of `create_seq_dir`\n    to selectively handle which advice to display.\n\n sequencer.c | 29 ++++++++++++++++++++++-------\n 1 file changed, 22 insertions(+), 7 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex f88a97fb10..ffb0257f0f 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -2650,15 +2650,30 @@ static int walk_revs_populate_todo(struct todo_list *todo_list,\n \treturn 0;\n }\n \n-static int create_seq_dir(void)\n+static int create_seq_dir(struct repository *r)\n {\n-\tif (file_exists(git_path_seq_dir())) {\n-\t\terror(_(\"a cherry-pick or revert is already in progress\"));\n-\t\tadvise(_(\"try \\\"git cherry-pick (--continue | --quit | --abort)\\\"\"));\n-\t\treturn -1;\n-\t} else if (mkdir(git_path_seq_dir(), 0777) < 0)\n+\tenum replay_action action;\n+\n+\tif (!sequencer_get_last_command(r, &action)) {\n+\t\tswitch (action) {\n+\t\tcase REPLAY_REVERT:\n+\t\tcase REPLAY_PICK:\n+\t\t\terror(_(\"a %s is already in progress\"),\n+\t\t\t\t action == REPLAY_REVERT ?\n+\t\t\t\t \"revert\" : \"cherry-pick\");\n+\t\t\tadvise(_(\"try \\\"git %s (--continue | \"\n+\t\t\t\t \"--quit | --abort)\\\"\"),\n+\t\t\t\t action == REPLAY_REVERT ?\n+\t\t\t\t \"revert\" : \"cherry-pick\");\n+\t\t\treturn -1;\n+\t\tdefault:\n+\t\t\tBUG(_(\"the control must not reach here\"));\n+\t\t}\n+\t}\n+\tif (mkdir(git_path_seq_dir(), 0777) < 0)\n \t\treturn error_errno(_(\"could not create sequencer directory '%s'\"),\n \t\t\t\t   git_path_seq_dir());\n+\n \treturn 0;\n }\n \n@@ -4237,7 +4252,7 @@ int sequencer_pick_revisions(struct repository *r,\n \t */\n \n \tif (walk_revs_populate_todo(&todo_list, opts) ||\n-\t\t\tcreate_seq_dir() < 0)\n+\t\t\tcreate_seq_dir(r) < 0)\n \t\treturn -1;\n \tif (get_oid(\"HEAD\", &oid) && (opts->action == REPLAY_REVERT))\n \t\treturn error(_(\"can't revert as initial commit\"));\n-- \n2.21.0\n\n"},{"id":"376995","messageId":"20190611073152.12214-4-rohit.ashiwal265@gmail.com","threadId":"51269","inReplyTo":"20190611073152.12214-1-rohit.ashiwal265@gmail.com","subject":"[GSoC][PATCH v2 3/3] cherry-pick/revert: advise using --skip","fromName":"Rohit Ashiwal","fromEmail":"rohit.ashiwal265@gmail.com","sentAt":"2019-06-11T07:31:52Z","receivedAt":"2019-06-11T07:34:32Z","isPatch":true,"sender":{"key":"rohit.ashiwal265@gmail.com","avatar":"https://avatars.githubusercontent.com/u/31043830?v=4"},"body":"The previous commit introduced a --skip flag for cherry-pick and\nrevert. Update the advice messages, to tell users about this less\ncumbersome way of skipping commits. Also add tests to ensure\neverything is working fine.\n\nSigned-off-by: Rohit Ashiwal <rohit.ashiwal265@gmail.com>\n---\nchanges since last revision:\n    - selectively advice --skip\n    - add new test\n\n builtin/commit.c                | 13 ++++++++-----\n sequencer.c                     |  7 +++++--\n t/t3510-cherry-pick-sequence.sh | 20 ++++++++++++++++++++\n 3 files changed, 33 insertions(+), 7 deletions(-)\n\ndiff --git a/builtin/commit.c b/builtin/commit.c\nindex 1c9e8e2228..1f47c51bdc 100644\n--- a/builtin/commit.c\n+++ b/builtin/commit.c\n@@ -60,15 +60,18 @@ N_(\"The previous cherry-pick is now empty, possibly due to conflict resolution.\\\n \"\\n\");\n \n static const char empty_cherry_pick_advice_single[] =\n-N_(\"Otherwise, please use 'git reset'\\n\");\n+N_(\"Otherwise, please use 'git cherry-pick --skip'\\n\");\n \n static const char empty_cherry_pick_advice_multi[] =\n-N_(\"If you wish to skip this commit, use:\\n\"\n+N_(\"and then use:\\n\"\n \"\\n\"\n-\"    git reset\\n\"\n+\"    git cherry-pick --continue\\n\"\n \"\\n\"\n-\"Then \\\"git cherry-pick --continue\\\" will resume cherry-picking\\n\"\n-\"the remaining commits.\\n\");\n+\"to resume cherry-picking the remaining commits.\\n\"\n+\"If you wish to skip this commit, use:\\n\"\n+\"\\n\"\n+\"    git cherry-pick --skip\\n\"\n+\"\\n\");\n \n static const char *color_status_slots[] = {\n \t[WT_STATUS_HEADER]\t  = \"header\",\ndiff --git a/sequencer.c b/sequencer.c\nindex 93284cd7dd..ecf4be7e15 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -2661,10 +2661,13 @@ static int create_seq_dir(struct repository *r)\n \t\t\terror(_(\"a %s is already in progress\"),\n \t\t\t\t action == REPLAY_REVERT ?\n \t\t\t\t \"revert\" : \"cherry-pick\");\n-\t\t\tadvise(_(\"try \\\"git %s (--continue | \"\n+\t\t\tadvise(_(\"try \\\"git %s (--continue | %s\"\n \t\t\t\t \"--quit | --abort)\\\"\"),\n \t\t\t\t action == REPLAY_REVERT ?\n-\t\t\t\t \"revert\" : \"cherry-pick\");\n+\t\t\t\t \"revert\" : \"cherry-pick\",\n+\t\t\t\t !file_exists(git_path_revert_head(r)) ?\n+\t\t\t\t !file_exists(git_path_cherry_pick_head(r)) ? \"\"\n+\t\t\t\t : \"--skip | \" : \"--skip | \");\n \t\t\treturn -1;\n \t\tdefault:\n \t\t\tBUG(_(\"the control must not reach here\"));\ndiff --git a/t/t3510-cherry-pick-sequence.sh b/t/t3510-cherry-pick-sequence.sh\nindex 6c1903a735..f298f02cd0 100755\n--- a/t/t3510-cherry-pick-sequence.sh\n+++ b/t/t3510-cherry-pick-sequence.sh\n@@ -172,6 +172,26 @@ test_expect_success 'check advice when we move HEAD by committing' '\n \ttest_cmp expect advice\n '\n \n+test_expect_success 'selectively advise --skip while launching another sequence' '\n+\tpristine_detach initial &&\n+\tcat >expect <<-EOF &&\n+\terror: a cherry-pick is already in progress\n+\thint: try \"git cherry-pick (--continue | --skip | --quit | --abort)\"\n+\tfatal: cherry-pick failed\n+\tEOF\n+\ttest_must_fail git cherry-pick picked..yetanotherpick &&\n+\ttest_must_fail git cherry-pick picked..yetanotherpick 2>advice &&\n+\ttest_cmp expect advice &&\n+\tcat >expect <<-EOF &&\n+\terror: a cherry-pick is already in progress\n+\thint: try \"git cherry-pick (--continue | --quit | --abort)\"\n+\tfatal: cherry-pick failed\n+\tEOF\n+\tgit reset --merge &&\n+\ttest_must_fail git cherry-pick picked..yetanotherpick 2>advice &&\n+\ttest_cmp expect advice\n+'\n+\n test_expect_success 'allow skipping commit but not abort for a new history' '\n \tpristine_detach initial &&\n \tcat >expect <<-EOF &&\n-- \n2.21.0\n\n"},{"id":"376996","messageId":"20190611073152.12214-3-rohit.ashiwal265@gmail.com","threadId":"51269","inReplyTo":"20190611073152.12214-1-rohit.ashiwal265@gmail.com","subject":"[GSoC][PATCH v2 2/3] cherry-pick/revert: add --skip option","fromName":"Rohit Ashiwal","fromEmail":"rohit.ashiwal265@gmail.com","sentAt":"2019-06-11T07:31:51Z","receivedAt":"2019-06-11T07:34:52Z","isPatch":true,"sender":{"key":"rohit.ashiwal265@gmail.com","avatar":"https://avatars.githubusercontent.com/u/31043830?v=4"},"body":"git am or rebase have a --skip flag to skip the current commit if the\nuser wishes to do so. During a cherry-pick or revert a user could\nlikewise skip a commit, but needs to use 'git reset' (or in the case\nof conflicts 'git reset --merge'), followed by 'git (cherry-pick |\nrevert) --continue' to skip the commit. This is more annoying and\nsometimes confusing on the users' part. Add a `--skip` option to make\nskipping commits easier for the user and to make the commands more\nconsistent.\n\nIn the next commit, we will change the advice messages hence finishing\nthe process of teaching revert and cherry-pick \"how to skip commits.\"\n\nSigned-off-by: Rohit Ashiwal <rohit.ashiwal265@gmail.com>\n---\nI was not able to think what should I change in 'skip a commit and check\nif rest of sequence is correct' test. Please suggest how shall I fix this.\nBut I think test is fine as it is now (because I wrote it and have been\nlooking at it for a long time that I am out of ideas).\n\nchanges since last revision:\n    - introduce new function `reset_merge` which will eliminate the problem\n      of wrong error \"cannot abort from a branch yet to be born\" which occurs\n      when head is NULL, but we still can skip (but not abort)\n    - `sequencer_skip` now calls `reset_merge` instead of `rollback_single_pick`\n    - add more tests\n\n Documentation/git-cherry-pick.txt |   4 +-\n Documentation/git-revert.txt      |   4 +-\n Documentation/sequencer.txt       |   4 ++\n builtin/revert.c                  |   5 ++\n sequencer.c                       |  56 ++++++++++++++++\n sequencer.h                       |   1 +\n t/t3510-cherry-pick-sequence.sh   | 104 ++++++++++++++++++++++++++++++\n 7 files changed, 172 insertions(+), 6 deletions(-)\n\ndiff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt\nindex 754b16ce0c..955880ab88 100644\n--- a/Documentation/git-cherry-pick.txt\n+++ b/Documentation/git-cherry-pick.txt\n@@ -10,9 +10,7 @@ SYNOPSIS\n [verse]\n 'git cherry-pick' [--edit] [-n] [-m parent-number] [-s] [-x] [--ff]\n \t\t  [-S[<keyid>]] <commit>...\n-'git cherry-pick' --continue\n-'git cherry-pick' --quit\n-'git cherry-pick' --abort\n+'git cherry-pick' --continue | --skip | --abort | --quit\n \n DESCRIPTION\n -----------\ndiff --git a/Documentation/git-revert.txt b/Documentation/git-revert.txt\nindex 0c82ca5bc0..ffce98099c 100644\n--- a/Documentation/git-revert.txt\n+++ b/Documentation/git-revert.txt\n@@ -9,9 +9,7 @@ SYNOPSIS\n --------\n [verse]\n 'git revert' [--[no-]edit] [-n] [-m parent-number] [-s] [-S[<keyid>]] <commit>...\n-'git revert' --continue\n-'git revert' --quit\n-'git revert' --abort\n+'git revert' --continue | --skip | --abort | --quit\n \n DESCRIPTION\n -----------\ndiff --git a/Documentation/sequencer.txt b/Documentation/sequencer.txt\nindex 5a57c4a407..3bceb56474 100644\n--- a/Documentation/sequencer.txt\n+++ b/Documentation/sequencer.txt\n@@ -3,6 +3,10 @@\n \t`.git/sequencer`.  Can be used to continue after resolving\n \tconflicts in a failed cherry-pick or revert.\n \n+--skip::\n+\tSkip the current commit and continue with the rest of the\n+\tsequence.\n+\n --quit::\n \tForget about the current operation in progress.  Can be used\n \tto clear the sequencer state after a failed cherry-pick or\ndiff --git a/builtin/revert.c b/builtin/revert.c\nindex d4dcedbdc6..5dc5891ea2 100644\n--- a/builtin/revert.c\n+++ b/builtin/revert.c\n@@ -102,6 +102,7 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)\n \t\tOPT_CMDMODE(0, \"quit\", &cmd, N_(\"end revert or cherry-pick sequence\"), 'q'),\n \t\tOPT_CMDMODE(0, \"continue\", &cmd, N_(\"resume revert or cherry-pick sequence\"), 'c'),\n \t\tOPT_CMDMODE(0, \"abort\", &cmd, N_(\"cancel revert or cherry-pick sequence\"), 'a'),\n+\t\tOPT_CMDMODE(0, \"skip\", &cmd, N_(\"skip current commit and continue\"), 's'),\n \t\tOPT_CLEANUP(&cleanup_arg),\n \t\tOPT_BOOL('n', \"no-commit\", &opts->no_commit, N_(\"don't automatically commit\")),\n \t\tOPT_BOOL('e', \"edit\", &opts->edit, N_(\"edit the commit message\")),\n@@ -151,6 +152,8 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)\n \t\t\tthis_operation = \"--quit\";\n \t\telse if (cmd == 'c')\n \t\t\tthis_operation = \"--continue\";\n+\t\telse if (cmd == 's')\n+\t\t\tthis_operation = \"--skip\";\n \t\telse {\n \t\t\tassert(cmd == 'a');\n \t\t\tthis_operation = \"--abort\";\n@@ -210,6 +213,8 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)\n \t\treturn sequencer_continue(the_repository, opts);\n \tif (cmd == 'a')\n \t\treturn sequencer_rollback(the_repository, opts);\n+\tif (cmd == 's')\n+\t\treturn sequencer_skip(the_repository, opts);\n \treturn sequencer_pick_revisions(the_repository, opts);\n }\n \ndiff --git a/sequencer.c b/sequencer.c\nindex ffb0257f0f..93284cd7dd 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -2724,6 +2724,16 @@ static int rollback_is_safe(void)\n \treturn oideq(&actual_head, &expected_head);\n }\n \n+static int reset_merge(void) {\n+\tconst char *argv[3];\n+\n+\targv[0] = \"reset\";\n+\targv[1] = \"--merge\";\n+\targv[2] = NULL;\n+\n+\treturn run_command_v_opt(argv, RUN_GIT_CMD);\n+}\n+\n static int reset_for_rollback(const struct object_id *oid)\n {\n \tconst char *argv[4];\t/* reset --merge <arg> + NULL */\n@@ -2798,6 +2808,52 @@ int sequencer_rollback(struct repository *r, struct replay_opts *opts)\n \treturn -1;\n }\n \n+int sequencer_skip(struct repository *r, struct replay_opts *opts)\n+{\n+\tenum replay_action action = -1;\n+\tsequencer_get_last_command(r, &action);\n+\n+\tswitch (opts->action) {\n+\tcase REPLAY_REVERT:\n+\t\tif (!file_exists(git_path_revert_head(r))) {\n+\t\t\tif (action == REPLAY_REVERT) {\n+\t\t\t\tif (!rollback_is_safe())\n+\t\t\t\t\tgoto give_advice;\n+\t\t\t\telse\n+\t\t\t\t\tbreak;\n+\t\t\t}\n+\t\t\treturn error(_(\"no revert in progress\"));\n+\t\t}\n+\t\tbreak;\n+\tcase REPLAY_PICK:\n+\t\tif (!file_exists(git_path_cherry_pick_head(r))) {\n+\t\t\tif (action == REPLAY_PICK) {\n+\t\t\t\tif (!rollback_is_safe())\n+\t\t\t\t\tgoto give_advice;\n+\t\t\t\telse\n+\t\t\t\t\tbreak;\n+\t\t\t}\n+\t\t\treturn error(_(\"no cherry-pick in progress\"));\n+\t\t}\n+\t\tbreak;\n+\tdefault:\n+\t\tBUG(\"the control must not reach here\");\n+\t}\n+\n+\tif (reset_merge())\n+\t\treturn error(_(\"failed to skip the commit\"));\n+\tif (!is_directory(git_path_seq_dir()))\n+\t\treturn 0;\n+\n+\treturn sequencer_continue(r, opts);\n+\n+give_advice:\n+\tadvise(_(\"have you committed already?\\n\"\n+\t\t \"try \\\"git %s --continue\\\"\"),\n+\t\t action == REPLAY_REVERT ? \"revert\" : \"cherry-pick\");\n+\treturn error(_(\"there is nothing to skip\"));\n+}\n+\n static int save_todo(struct todo_list *todo_list, struct replay_opts *opts)\n {\n \tstruct lock_file todo_lock = LOCK_INIT;\ndiff --git a/sequencer.h b/sequencer.h\nindex 0c494b83d4..731b9853eb 100644\n--- a/sequencer.h\n+++ b/sequencer.h\n@@ -129,6 +129,7 @@ int sequencer_pick_revisions(struct repository *repo,\n \t\t\t     struct replay_opts *opts);\n int sequencer_continue(struct repository *repo, struct replay_opts *opts);\n int sequencer_rollback(struct repository *repo, struct replay_opts *opts);\n+int sequencer_skip(struct repository *repo, struct replay_opts *opts);\n int sequencer_remove_state(struct replay_opts *opts);\n \n #define TODO_LIST_KEEP_EMPTY (1U << 0)\ndiff --git a/t/t3510-cherry-pick-sequence.sh b/t/t3510-cherry-pick-sequence.sh\nindex 941d5026da..6c1903a735 100755\n--- a/t/t3510-cherry-pick-sequence.sh\n+++ b/t/t3510-cherry-pick-sequence.sh\n@@ -93,6 +93,110 @@ test_expect_success 'cherry-pick cleans up sequencer state upon success' '\n \ttest_path_is_missing .git/sequencer\n '\n \n+test_expect_success 'cherry-pick --skip requires cherry-pick in progress' '\n+\tpristine_detach initial &&\n+\ttest_must_fail git cherry-pick --skip\n+'\n+\n+test_expect_success 'revert --skip requires revert in progress' '\n+\tpristine_detach initial &&\n+\ttest_must_fail git revert --skip\n+'\n+\n+test_expect_success 'cherry-pick --skip to skip commit' '\n+\tpristine_detach initial &&\n+\ttest_must_fail git cherry-pick anotherpick &&\n+\ttest_must_fail git revert --skip &&\n+\tgit cherry-pick --skip &&\n+\ttest_cmp_rev initial HEAD &&\n+\ttest_path_is_missing .git/CHERRY_PICK_HEAD\n+'\n+\n+test_expect_success 'revert --skip to skip commit' '\n+\tpristine_detach anotherpick &&\n+\ttest_must_fail git revert anotherpick~1 &&\n+\ttest_must_fail git cherry-pick --skip &&\n+\tgit revert --skip &&\n+\ttest_cmp_rev anotherpick HEAD\n+'\n+\n+test_expect_success 'skip \"empty\" commit' '\n+\tpristine_detach picked &&\n+\ttest_commit dummy foo d &&\n+\ttest_must_fail git cherry-pick anotherpick &&\n+\tgit cherry-pick --skip &&\n+\ttest_cmp_rev dummy HEAD\n+'\n+\n+test_expect_success 'skip a commit and check if rest of sequence is correct' '\n+\tpristine_detach initial &&\n+\techo e >expect &&\n+\tcat >expect.log <<-EOF &&\n+\tOBJID\n+\t:100644 100644 OBJID OBJID M\tfoo\n+\tOBJID\n+\t:100644 100644 OBJID OBJID M\tfoo\n+\tOBJID\n+\t:100644 100644 OBJID OBJID M\tunrelated\n+\tOBJID\n+\t:000000 100644 OBJID OBJID A\tfoo\n+\t:000000 100644 OBJID OBJID A\tunrelated\n+\tEOF\n+\ttest_must_fail git cherry-pick base..yetanotherpick &&\n+\ttest_must_fail git cherry-pick --skip &&\n+\techo d >foo &&\n+\tgit add foo &&\n+\tgit cherry-pick --continue &&\n+\t{\n+\t\tgit rev-list HEAD |\n+\t\tgit diff-tree --root --stdin |\n+\t\tsed \"s/$OID_REGEX/OBJID/g\"\n+\t} >actual.log &&\n+\ttest_cmp expect foo &&\n+\ttest_cmp expect.log actual.log\n+'\n+\n+test_expect_success 'check advice when we move HEAD by committing' '\n+\tpristine_detach initial &&\n+\tcat >expect <<-EOF &&\n+\thint: have you committed already?\n+\thint: try \"git cherry-pick --continue\"\n+\terror: there is nothing to skip\n+\tfatal: cherry-pick failed\n+\tEOF\n+\ttest_must_fail git cherry-pick base..yetanotherpick &&\n+\techo c >foo &&\n+\tgit commit -a &&\n+\ttest_path_is_missing .git/CHERRY_PICK_HEAD &&\n+\ttest_must_fail git cherry-pick --skip 2>advice &&\n+\ttest_cmp expect advice\n+'\n+\n+test_expect_success 'allow skipping commit but not abort for a new history' '\n+\tpristine_detach initial &&\n+\tcat >expect <<-EOF &&\n+\terror: cannot abort from a branch yet to be born\n+\tfatal: cherry-pick failed\n+\tEOF\n+\tgit checkout --orphan new_disconnected &&\n+\tgit reset --hard &&\n+\ttest_must_fail git cherry-pick anotherpick &&\n+\ttest_must_fail git cherry-pick --abort 2>advice &&\n+\tgit cherry-pick --skip &&\n+\ttest_cmp expect advice\n+'\n+\n+test_expect_success 'allow skipping stopped cherry-pick because of untracked file modifications' '\n+\tpristine_detach initial &&\n+\tgit checkout --orphan new_disconnected &&\n+\tgit reset --hard &&\n+\ttest_commit new_disconnected foo a &&\n+\techo unrelated >unrelated &&\n+\ttest_must_fail git cherry-pick new_disconnected..base &&\n+\ttest_path_is_missing .git/CHERRY_PICK_HEAD &&\n+\tgit cherry-pick --skip\n+'\n+\n test_expect_success '--quit does not complain when no cherry-pick is in progress' '\n \tpristine_detach initial &&\n \tgit cherry-pick --quit\n-- \n2.21.0\n\n"},{"id":"377034","messageId":"xmqqr27zke5m.fsf@gitster-ct.c.googlers.com","threadId":"51269","inReplyTo":"20190611073152.12214-2-rohit.ashiwal265@gmail.com","subject":"Re: [GSoC][PATCH v2 1/3] sequencer: add advice for revert","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-06-11T21:25:41Z","receivedAt":"2019-06-11T21:25:46Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Rohit Ashiwal <rohit.ashiwal265@gmail.com> writes:\n\n> -static int create_seq_dir(void)\n> +static int create_seq_dir(struct repository *r)\n>  {\n> -\tif (file_exists(git_path_seq_dir())) {\n> -\t\terror(_(\"a cherry-pick or revert is already in progress\"));\n> -\t\tadvise(_(\"try \\\"git cherry-pick (--continue | --quit | --abort)\\\"\"));\n> -\t\treturn -1;\n> -\t} else if (mkdir(git_path_seq_dir(), 0777) < 0)\n> +\tenum replay_action action;\n> +\n> +\tif (!sequencer_get_last_command(r, &action)) {\n> +\t\tswitch (action) {\n> +\t\tcase REPLAY_REVERT:\n> +\t\tcase REPLAY_PICK:\n> +\t\t\terror(_(\"a %s is already in progress\"),\n> +\t\t\t\t action == REPLAY_REVERT ?\n> +\t\t\t\t \"revert\" : \"cherry-pick\");\n\nI wonder if this poses a challenge to translators (imagine an\nalternate world, in which the name of one of these subcommands began\nwith a vowel---your \"a %s is already ...\" would not be correct even\nwithout localization).\n\nThe same comment applies to the other one, too.\n\n> +\t\t\tadvise(_(\"try \\\"git %s (--continue | \"\n> +\t\t\t\t \"--quit | --abort)\\\"\"),\n> +\t\t\t\t action == REPLAY_REVERT ?\n> +\t\t\t\t \"revert\" : \"cherry-pick\");\n\nThis is horrible but it is not a fault of yours---you merely\ninherited it.  A call to advise() that is not behind any \"advise.*\"\nconfiguration variable like this one should be cleaned up before\nwe do anything else.\n\nThe obvious and straight-forward way to deal with it is to do\n\n\tconst char *in_progress_error;\n        const char *in_progress_advice;\n\n\tif (action == REPLAY_REVERT) {\n\t\tin_progress_error = _(\"a revert is already in progress\");\n\t\tin_progress_advise = _(\"try ...\");\n\t} else if (action == REPLAY_PICK) {\n\t\t... likewise ...\n\t} else {\n\t\tBUG(\"should not come here\");\n\t}\n\nand then do\n\n\terror(in_progress_error);\n\tif (advise_verbosely_how_to_continue_sequencing)\n\t\tadvise(in_progress_advise);\n\n\n\n> +\t\t\treturn -1;\n> +\tif (mkdir(git_path_seq_dir(), 0777) < 0)\n>  \t\treturn error_errno(_(\"could not create sequencer directory '%s'\"),\n>  \t\t\t\t   git_path_seq_dir());\n> +\n>  \treturn 0;\n>  }\n>  \n> @@ -4237,7 +4252,7 @@ int sequencer_pick_revisions(struct repository *r,\n>  \t */\n>  \n>  \tif (walk_revs_populate_todo(&todo_list, opts) ||\n> -\t\t\tcreate_seq_dir() < 0)\n> +\t\t\tcreate_seq_dir(r) < 0)\n>  \t\treturn -1;\n>  \tif (get_oid(\"HEAD\", &oid) && (opts->action == REPLAY_REVERT))\n>  \t\treturn error(_(\"can't revert as initial commit\"));\n"},{"id":"377075","messageId":"6d3c1c1e-6140-dd8c-c37f-8c625b04ddc9@gmail.com","threadId":"51269","inReplyTo":"20190611073152.12214-3-rohit.ashiwal265@gmail.com","subject":"Re: [GSoC][PATCH v2 2/3] cherry-pick/revert: add --skip option","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2019-06-12T13:31:53Z","receivedAt":"2019-06-12T13:32:06Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"Hi Rohit\n\nThanks for the new version, this is looking pretty good now, just a few \ncomments below\n\nOn 11/06/2019 08:31, Rohit Ashiwal wrote:\n> git am or rebase have a --skip flag to skip the current commit if the\n> user wishes to do so. During a cherry-pick or revert a user could\n> likewise skip a commit, but needs to use 'git reset' (or in the case\n> of conflicts 'git reset --merge'), followed by 'git (cherry-pick |\n> revert) --continue' to skip the commit. This is more annoying and\n> sometimes confusing on the users' part. Add a `--skip` option to make\n> skipping commits easier for the user and to make the commands more\n> consistent.\n> \n> In the next commit, we will change the advice messages hence finishing\n> the process of teaching revert and cherry-pick \"how to skip commits.\"\n> \n> Signed-off-by: Rohit Ashiwal <rohit.ashiwal265@gmail.com>\n> ---\n> I was not able to think what should I change in 'skip a commit and check\n> if rest of sequence is correct' test. Please suggest how shall I fix this.\n> But I think test is fine as it is now (because I wrote it and have been\n> looking at it for a long time that I am out of ideas).\n\nYou can call have_finished_the_last_pick() to see if you're skipping the \nlast pick. One way would be to modify rollback_single_pick() to take a \nflag for abort vs skip and call it from there.\n\n> \n> changes since last revision:\n>      - introduce new function `reset_merge` which will eliminate the problem\n>        of wrong error \"cannot abort from a branch yet to be born\" which occurs\n>        when head is NULL, but we still can skip (but not abort)\n>      - `sequencer_skip` now calls `reset_merge` instead of `rollback_single_pick`\n>      - add more tests\n\nKudos for the new tests, we can look at Stolee's weekly test coverage \nemail once these are merged to check that all the new code is being covered.\n\n> \n>   Documentation/git-cherry-pick.txt |   4 +-\n>   Documentation/git-revert.txt      |   4 +-\n>   Documentation/sequencer.txt       |   4 ++\n>   builtin/revert.c                  |   5 ++\n>   sequencer.c                       |  56 ++++++++++++++++\n>   sequencer.h                       |   1 +\n>   t/t3510-cherry-pick-sequence.sh   | 104 ++++++++++++++++++++++++++++++\n>   7 files changed, 172 insertions(+), 6 deletions(-)\n> \n> diff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt\n> index 754b16ce0c..955880ab88 100644\n> --- a/Documentation/git-cherry-pick.txt\n> +++ b/Documentation/git-cherry-pick.txt\n> @@ -10,9 +10,7 @@ SYNOPSIS\n>   [verse]\n>   'git cherry-pick' [--edit] [-n] [-m parent-number] [-s] [-x] [--ff]\n>   \t\t  [-S[<keyid>]] <commit>...\n> -'git cherry-pick' --continue\n> -'git cherry-pick' --quit\n> -'git cherry-pick' --abort\n> +'git cherry-pick' --continue | --skip | --abort | --quit\n>   \n>   DESCRIPTION\n>   -----------\n> diff --git a/Documentation/git-revert.txt b/Documentation/git-revert.txt\n> index 0c82ca5bc0..ffce98099c 100644\n> --- a/Documentation/git-revert.txt\n> +++ b/Documentation/git-revert.txt\n> @@ -9,9 +9,7 @@ SYNOPSIS\n>   --------\n>   [verse]\n>   'git revert' [--[no-]edit] [-n] [-m parent-number] [-s] [-S[<keyid>]] <commit>...\n> -'git revert' --continue\n> -'git revert' --quit\n> -'git revert' --abort\n> +'git revert' --continue | --skip | --abort | --quit\n>   \n>   DESCRIPTION\n>   -----------\n> diff --git a/Documentation/sequencer.txt b/Documentation/sequencer.txt\n> index 5a57c4a407..3bceb56474 100644\n> --- a/Documentation/sequencer.txt\n> +++ b/Documentation/sequencer.txt\n> @@ -3,6 +3,10 @@\n>   \t`.git/sequencer`.  Can be used to continue after resolving\n>   \tconflicts in a failed cherry-pick or revert.\n>   \n> +--skip::\n> +\tSkip the current commit and continue with the rest of the\n> +\tsequence.\n> +\n>   --quit::\n>   \tForget about the current operation in progress.  Can be used\n>   \tto clear the sequencer state after a failed cherry-pick or\n> diff --git a/builtin/revert.c b/builtin/revert.c\n> index d4dcedbdc6..5dc5891ea2 100644\n> --- a/builtin/revert.c\n> +++ b/builtin/revert.c\n> @@ -102,6 +102,7 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)\n>   \t\tOPT_CMDMODE(0, \"quit\", &cmd, N_(\"end revert or cherry-pick sequence\"), 'q'),\n>   \t\tOPT_CMDMODE(0, \"continue\", &cmd, N_(\"resume revert or cherry-pick sequence\"), 'c'),\n>   \t\tOPT_CMDMODE(0, \"abort\", &cmd, N_(\"cancel revert or cherry-pick sequence\"), 'a'),\n> +\t\tOPT_CMDMODE(0, \"skip\", &cmd, N_(\"skip current commit and continue\"), 's'),\n>   \t\tOPT_CLEANUP(&cleanup_arg),\n>   \t\tOPT_BOOL('n', \"no-commit\", &opts->no_commit, N_(\"don't automatically commit\")),\n>   \t\tOPT_BOOL('e', \"edit\", &opts->edit, N_(\"edit the commit message\")),\n> @@ -151,6 +152,8 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)\n>   \t\t\tthis_operation = \"--quit\";\n>   \t\telse if (cmd == 'c')\n>   \t\t\tthis_operation = \"--continue\";\n> +\t\telse if (cmd == 's')\n> +\t\t\tthis_operation = \"--skip\";\n>   \t\telse {\n>   \t\t\tassert(cmd == 'a');\n>   \t\t\tthis_operation = \"--abort\";\n> @@ -210,6 +213,8 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)\n>   \t\treturn sequencer_continue(the_repository, opts);\n>   \tif (cmd == 'a')\n>   \t\treturn sequencer_rollback(the_repository, opts);\n> +\tif (cmd == 's')\n> +\t\treturn sequencer_skip(the_repository, opts);\n>   \treturn sequencer_pick_revisions(the_repository, opts);\n>   }\n>   \n> diff --git a/sequencer.c b/sequencer.c\n> index ffb0257f0f..93284cd7dd 100644\n> --- a/sequencer.c\n> +++ b/sequencer.c\n> @@ -2724,6 +2724,16 @@ static int rollback_is_safe(void)\n>   \treturn oideq(&actual_head, &expected_head);\n>   }\n>   \n> +static int reset_merge(void) {\n> +\tconst char *argv[3];\n> +\n> +\targv[0] = \"reset\";\n> +\targv[1] = \"--merge\";\n> +\targv[2] = NULL;\n> +\n> +\treturn run_command_v_opt(argv, RUN_GIT_CMD);\n> +}\n\nThis is only slightly different from reset_for_rollback() if you decide \nto keep a separate code path for skip vs abort then I'd be tempted to \ncombine the two like this.\n\ndiff --git a/sequencer.c b/sequencer.c\nindex ecf4be7e15..b187b4222e 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -2740,11 +2740,13 @@ static int reset_merge(void) {\n  static int reset_for_rollback(const struct object_id *oid)\n  {\n         const char *argv[4];    /* reset --merge <arg> + NULL */\n+       size_t i = 0;\n\n-       argv[0] = \"reset\";\n-       argv[1] = \"--merge\";\n-       argv[2] = oid_to_hex(oid);\n-       argv[3] = NULL;\n+       argv[i++] = \"reset\";\n+       argv[i++] = \"--merge\";\n+       if (oid)\n+               argv[i++] = oid_to_hex(oid);\n+       argv[i] = NULL;\n         return run_command_v_opt(argv, RUN_GIT_CMD);\n  }\n\n\n> +\n>   static int reset_for_rollback(const struct object_id *oid)\n>   {\n>   \tconst char *argv[4];\t/* reset --merge <arg> + NULL */\n> @@ -2798,6 +2808,52 @@ int sequencer_rollback(struct repository *r, struct replay_opts *opts)\n>   \treturn -1;\n>   }\n>   \n> +int sequencer_skip(struct repository *r, struct replay_opts *opts)\n> +{\n> +\tenum replay_action action = -1;\n> +\tsequencer_get_last_command(r, &action);\n> +\n> +\tswitch (opts->action) {\n> +\tcase REPLAY_REVERT:\n> +\t\tif (!file_exists(git_path_revert_head(r))) {\n> +\t\t\tif (action == REPLAY_REVERT) {\n> +\t\t\t\tif (!rollback_is_safe())\n> +\t\t\t\t\tgoto give_advice;\n> +\t\t\t\telse\n> +\t\t\t\t\tbreak;\n> +\t\t\t}\n> +\t\t\treturn error(_(\"no revert in progress\"));\n> +\t\t}\n> +\t\tbreak;\n> +\tcase REPLAY_PICK:\n> +\t\tif (!file_exists(git_path_cherry_pick_head(r))) {\n> +\t\t\tif (action == REPLAY_PICK) {\n> +\t\t\t\tif (!rollback_is_safe())\n> +\t\t\t\t\tgoto give_advice;\n> +\t\t\t\telse\n> +\t\t\t\t\tbreak;\n> +\t\t\t}\n> +\t\t\treturn error(_(\"no cherry-pick in progress\"));\n> +\t\t}\n> +\t\tbreak;\n> +\tdefault:\n> +\t\tBUG(\"the control must not reach here\");\n> +\t}\n> +\n> +\tif (reset_merge())\n> +\t\treturn error(_(\"failed to skip the commit\"));\n> +\tif (!is_directory(git_path_seq_dir()))\n> +\t\treturn 0;\n> +\n> +\treturn sequencer_continue(r, opts);\n> +\n> +give_advice:\n> +\tadvise(_(\"have you committed already?\\n\"\n> +\t\t \"try \\\"git %s --continue\\\"\"),\n> +\t\t action == REPLAY_REVERT ? \"revert\" : \"cherry-pick\");\n> +\treturn error(_(\"there is nothing to skip\"));\n> +}\n> +\n\nthis looks fine now, it's really good to have specific error messages.\n\n>   static int save_todo(struct todo_list *todo_list, struct replay_opts *opts)\n>   {\n>   \tstruct lock_file todo_lock = LOCK_INIT;\n> diff --git a/sequencer.h b/sequencer.h\n> index 0c494b83d4..731b9853eb 100644\n> --- a/sequencer.h\n> +++ b/sequencer.h\n> @@ -129,6 +129,7 @@ int sequencer_pick_revisions(struct repository *repo,\n>   \t\t\t     struct replay_opts *opts);\n>   int sequencer_continue(struct repository *repo, struct replay_opts *opts);\n>   int sequencer_rollback(struct repository *repo, struct replay_opts *opts);\n> +int sequencer_skip(struct repository *repo, struct replay_opts *opts);\n>   int sequencer_remove_state(struct replay_opts *opts);\n>   \n>   #define TODO_LIST_KEEP_EMPTY (1U << 0)\n> diff --git a/t/t3510-cherry-pick-sequence.sh b/t/t3510-cherry-pick-sequence.sh\n> index 941d5026da..6c1903a735 100755\n> --- a/t/t3510-cherry-pick-sequence.sh\n> +++ b/t/t3510-cherry-pick-sequence.sh\n> @@ -93,6 +93,110 @@ test_expect_success 'cherry-pick cleans up sequencer state upon success' '\n>   \ttest_path_is_missing .git/sequencer\n>   '\n>   \n> +test_expect_success 'cherry-pick --skip requires cherry-pick in progress' '\n> +\tpristine_detach initial &&\n> +\ttest_must_fail git cherry-pick --skip\n> +'\n> +\n> +test_expect_success 'revert --skip requires revert in progress' '\n> +\tpristine_detach initial &&\n> +\ttest_must_fail git revert --skip\n> +'\n> +\n> +test_expect_success 'cherry-pick --skip to skip commit' '\n> +\tpristine_detach initial &&\n> +\ttest_must_fail git cherry-pick anotherpick &&\n> +\ttest_must_fail git revert --skip &&\n> +\tgit cherry-pick --skip &&\n> +\ttest_cmp_rev initial HEAD &&\n> +\ttest_path_is_missing .git/CHERRY_PICK_HEAD\n> +'\n> +\n> +test_expect_success 'revert --skip to skip commit' '\n> +\tpristine_detach anotherpick &&\n> +\ttest_must_fail git revert anotherpick~1 &&\n> +\ttest_must_fail git cherry-pick --skip &&\n> +\tgit revert --skip &&\n> +\ttest_cmp_rev anotherpick HEAD\n> +'\n> +\n> +test_expect_success 'skip \"empty\" commit' '\n> +\tpristine_detach picked &&\n> +\ttest_commit dummy foo d &&\n> +\ttest_must_fail git cherry-pick anotherpick &&\n> +\tgit cherry-pick --skip &&\n> +\ttest_cmp_rev dummy HEAD\n> +'\n> +\n> +test_expect_success 'skip a commit and check if rest of sequence is correct' '\n> +\tpristine_detach initial &&\n> +\techo e >expect &&\n> +\tcat >expect.log <<-EOF &&\n> +\tOBJID\n> +\t:100644 100644 OBJID OBJID M\tfoo\n> +\tOBJID\n> +\t:100644 100644 OBJID OBJID M\tfoo\n> +\tOBJID\n> +\t:100644 100644 OBJID OBJID M\tunrelated\n> +\tOBJID\n> +\t:000000 100644 OBJID OBJID A\tfoo\n> +\t:000000 100644 OBJID OBJID A\tunrelated\n> +\tEOF\n> +\ttest_must_fail git cherry-pick base..yetanotherpick &&\n> +\ttest_must_fail git cherry-pick --skip &&\n> +\techo d >foo &&\n> +\tgit add foo &&\n> +\tgit cherry-pick --continue &&\n> +\t{\n> +\t\tgit rev-list HEAD |\n> +\t\tgit diff-tree --root --stdin |\n> +\t\tsed \"s/$OID_REGEX/OBJID/g\"\n> +\t} >actual.log &&\n> +\ttest_cmp expect foo &&\n> +\ttest_cmp expect.log actual.log\n> +'\n> +\n> +test_expect_success 'check advice when we move HEAD by committing' '\n> +\tpristine_detach initial &&\n> +\tcat >expect <<-EOF &&\n> +\thint: have you committed already?\n> +\thint: try \"git cherry-pick --continue\"\n> +\terror: there is nothing to skip\n> +\tfatal: cherry-pick failed\n> +\tEOF\n> +\ttest_must_fail git cherry-pick base..yetanotherpick &&\n> +\techo c >foo &&\n> +\tgit commit -a &&\n> +\ttest_path_is_missing .git/CHERRY_PICK_HEAD &&\n> +\ttest_must_fail git cherry-pick --skip 2>advice &&\n> +\ttest_cmp expect advice\n> +'\n> +\n> +test_expect_success 'allow skipping commit but not abort for a new history' '\n> +\tpristine_detach initial &&\n> +\tcat >expect <<-EOF &&\n> +\terror: cannot abort from a branch yet to be born\n> +\tfatal: cherry-pick failed\n> +\tEOF\n> +\tgit checkout --orphan new_disconnected &&\n> +\tgit reset --hard &&\n> +\ttest_must_fail git cherry-pick anotherpick &&\n> +\ttest_must_fail git cherry-pick --abort 2>advice &&\n> +\tgit cherry-pick --skip &&\n\nIf we want to match the abort behavior (we should think if that is \nsensible - I'm not sure at the moment) then we only want to allow --skip \nif there is another pick pending so shouldn't this be failing?\n\n> +\ttest_cmp expect advice\n> +'\n> +\n> +test_expect_success 'allow skipping stopped cherry-pick because of untracked file modifications' '\n> +\tpristine_detach initial &&\n> +\tgit checkout --orphan new_disconnected &&\n\nThis gives a warning about new_disconnected being an ambiguous refname -\nit would be better use a different name from the previous test - I'm not \nsure if you're getting an orphaned branch or not as it stands. (and \nlooking more carefully I'm not sure why we want an orphan branch here in \nthe first place)\n\nBest Wishes\n\nPhillip\n\n> +\tgit reset --hard &&\n> +\ttest_commit new_disconnected foo a &&\n> +\techo unrelated >unrelated &&\n> +\ttest_must_fail git cherry-pick new_disconnected..base &&\n> +\ttest_path_is_missing .git/CHERRY_PICK_HEAD &&\n> +\tgit cherry-pick --skip\n> +'\n> +\n>   test_expect_success '--quit does not complain when no cherry-pick is in progress' '\n>   \tpristine_detach initial &&\n>   \tgit cherry-pick --quit\n> \n"},{"id":"377081","messageId":"3591ee0f-b302-23c8-dda5-00ff650887b8@gmail.com","threadId":"51269","inReplyTo":"20190611073152.12214-4-rohit.ashiwal265@gmail.com","subject":"Re: [GSoC][PATCH v2 3/3] cherry-pick/revert: advise using --skip","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2019-06-12T15:16:43Z","receivedAt":"2019-06-12T15:16:55Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"Hi Rohit\n\nOn 11/06/2019 08:31, Rohit Ashiwal wrote:\n> The previous commit introduced a --skip flag for cherry-pick and\n> revert. Update the advice messages, to tell users about this less\n> cumbersome way of skipping commits. Also add tests to ensure\n> everything is working fine.\n> \n> Signed-off-by: Rohit Ashiwal <rohit.ashiwal265@gmail.com>\n> ---\n> changes since last revision:\n>      - selectively advice --skip\n>      - add new test\n> \n>   builtin/commit.c                | 13 ++++++++-----\n>   sequencer.c                     |  7 +++++--\n>   t/t3510-cherry-pick-sequence.sh | 20 ++++++++++++++++++++\n>   3 files changed, 33 insertions(+), 7 deletions(-)\n> \n> diff --git a/builtin/commit.c b/builtin/commit.c\n> index 1c9e8e2228..1f47c51bdc 100644\n> --- a/builtin/commit.c\n> +++ b/builtin/commit.c\n> @@ -60,15 +60,18 @@ N_(\"The previous cherry-pick is now empty, possibly due to conflict resolution.\\\n>   \"\\n\");\n>   \n>   static const char empty_cherry_pick_advice_single[] =\n> -N_(\"Otherwise, please use 'git reset'\\n\");\n> +N_(\"Otherwise, please use 'git cherry-pick --skip'\\n\");\n>   \n>   static const char empty_cherry_pick_advice_multi[] =\n> -N_(\"If you wish to skip this commit, use:\\n\"\n> +N_(\"and then use:\\n\"\n>   \"\\n\"\n> -\"    git reset\\n\"\n> +\"    git cherry-pick --continue\\n\"\n>   \"\\n\"\n> -\"Then \\\"git cherry-pick --continue\\\" will resume cherry-picking\\n\"\n> -\"the remaining commits.\\n\");\n> +\"to resume cherry-picking the remaining commits.\\n\"\n> +\"If you wish to skip this commit, use:\\n\"\n> +\"\\n\"\n> +\"    git cherry-pick --skip\\n\"\n> +\"\\n\");\n>   \n>   static const char *color_status_slots[] = {\n>   \t[WT_STATUS_HEADER]\t  = \"header\",\n> diff --git a/sequencer.c b/sequencer.c\n> index 93284cd7dd..ecf4be7e15 100644\n> --- a/sequencer.c\n> +++ b/sequencer.c\n> @@ -2661,10 +2661,13 @@ static int create_seq_dir(struct repository *r)\n>   \t\t\terror(_(\"a %s is already in progress\"),\n>   \t\t\t\t action == REPLAY_REVERT ?\n>   \t\t\t\t \"revert\" : \"cherry-pick\");\n> -\t\t\tadvise(_(\"try \\\"git %s (--continue | \"\n> +\t\t\tadvise(_(\"try \\\"git %s (--continue | %s\"\n>   \t\t\t\t \"--quit | --abort)\\\"\"),\n>   \t\t\t\t action == REPLAY_REVERT ?\n> -\t\t\t\t \"revert\" : \"cherry-pick\");\n> +\t\t\t\t \"revert\" : \"cherry-pick\",\n> +\t\t\t\t !file_exists(git_path_revert_head(r)) ?\n> +\t\t\t\t !file_exists(git_path_cherry_pick_head(r)) ? \"\"\n> +\t\t\t\t : \"--skip | \" : \"--skip | \");\n\nThis could be simplified as\n\t(file_exists(git_path_revert_head(r) ||\n\tfile_exists(git_path_cherry_pick_head(r)) ?\n\t\"--skip | \" \"\"\n\nBest Wishes\n\nPhillip\n\n>   \t\t\treturn -1;\n>   \t\tdefault:\n>   \t\t\tBUG(_(\"the control must not reach here\"));\n> diff --git a/t/t3510-cherry-pick-sequence.sh b/t/t3510-cherry-pick-sequence.sh\n> index 6c1903a735..f298f02cd0 100755\n> --- a/t/t3510-cherry-pick-sequence.sh\n> +++ b/t/t3510-cherry-pick-sequence.sh\n> @@ -172,6 +172,26 @@ test_expect_success 'check advice when we move HEAD by committing' '\n>   \ttest_cmp expect advice\n>   '\n>   \n> +test_expect_success 'selectively advise --skip while launching another sequence' '\n> +\tpristine_detach initial &&\n> +\tcat >expect <<-EOF &&\n> +\terror: a cherry-pick is already in progress\n> +\thint: try \"git cherry-pick (--continue | --skip | --quit | --abort)\"\n> +\tfatal: cherry-pick failed\n> +\tEOF\n> +\ttest_must_fail git cherry-pick picked..yetanotherpick &&\n> +\ttest_must_fail git cherry-pick picked..yetanotherpick 2>advice && > +\ttest_cmp expect advice &&\n> +\tcat >expect <<-EOF &&\n> +\terror: a cherry-pick is already in progress\n> +\thint: try \"git cherry-pick (--continue | --quit | --abort)\"\n> +\tfatal: cherry-pick failed\n> +\tEOF\n> +\tgit reset --merge &&\n> +\ttest_must_fail git cherry-pick picked..yetanotherpick 2>advice &&\n> +\ttest_cmp expect advice\n> +'\n> +\n>   test_expect_success 'allow skipping commit but not abort for a new history' '\n>   \tpristine_detach initial &&\n>   \tcat >expect <<-EOF &&\n> \n"},{"id":"377098","messageId":"xmqqsgseisgu.fsf@gitster-ct.c.googlers.com","threadId":"51269","inReplyTo":"6d3c1c1e-6140-dd8c-c37f-8c625b04ddc9@gmail.com","subject":"Re: [GSoC][PATCH v2 2/3] cherry-pick/revert: add --skip option","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-06-12T18:11:45Z","receivedAt":"2019-06-12T18:11:51Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Phillip Wood <phillip.wood123@gmail.com> writes:\n\n> Thanks for the new version, this is looking pretty good now, just a\n> few comments below\n\nI agree that this step is looking pretty good now.\n\nI didn't check closely, but when 1/3 undergoes necessary polishing,\nit may have repercussions on this step, though (I did see that the\nchange in 3/3 would have overlaps with what was touched by 1/3 that\nneeds to be done differently).\n\nThanks for guiding Rohit's series forward.  \n\n> This is only slightly different from reset_for_rollback() if you\n> decide to keep a separate code path for skip vs abort then I'd be\n> tempted to combine the two like this.\n>\n> diff --git a/sequencer.c b/sequencer.c\n> index ecf4be7e15..b187b4222e 100644\n> --- a/sequencer.c\n> +++ b/sequencer.c\n> @@ -2740,11 +2740,13 @@ static int reset_merge(void) {\n>  static int reset_for_rollback(const struct object_id *oid)\n>  {\n>         const char *argv[4];    /* reset --merge <arg> + NULL */\n> +       size_t i = 0;\n\nThat size_t is, eh, \"unusual\".  For an index into a small local\narray of known size, just sticking to bog-standard-and-boring 'int'\nwould make it less distracting for future readers of the code.\n\nOr even better, perhaps use argv-array, so that you do not have to\nworry about sizing the local array sufficiently large in the first\nplace.\n\n> +       argv[i++] = \"reset\";\n> +       argv[i++] = \"--merge\";\n> +       if (oid)\n> +               argv[i++] = oid_to_hex(oid);\n> +       argv[i] = NULL;\n>         return run_command_v_opt(argv, RUN_GIT_CMD);\n>  }\n\n"},{"id":"377102","messageId":"5226cbc4-3dad-2fc8-b0b7-767119e40c64@gmail.com","threadId":"51269","inReplyTo":"xmqqsgseisgu.fsf@gitster-ct.c.googlers.com","subject":"Re: [GSoC][PATCH v2 2/3] cherry-pick/revert: add --skip option","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2019-06-12T18:57:41Z","receivedAt":"2019-06-12T18:57:47Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"On 12/06/2019 19:11, Junio C Hamano wrote:\n> Phillip Wood <phillip.wood123@gmail.com> writes:\n> \n>> Thanks for the new version, this is looking pretty good now, just a\n>> few comments below\n> \n> I agree that this step is looking pretty good now.\n> \n> I didn't check closely, but when 1/3 undergoes necessary polishing,\n> it may have repercussions on this step, though (I did see that the\n> change in 3/3 would have overlaps with what was touched by 1/3 that\n> needs to be done differently).\n> \n> Thanks for guiding Rohit's series forward.\n> \n>> This is only slightly different from reset_for_rollback() if you\n>> decide to keep a separate code path for skip vs abort then I'd be\n>> tempted to combine the two like this.\n>>\n>> diff --git a/sequencer.c b/sequencer.c\n>> index ecf4be7e15..b187b4222e 100644\n>> --- a/sequencer.c\n>> +++ b/sequencer.c\n>> @@ -2740,11 +2740,13 @@ static int reset_merge(void) {\n>>   static int reset_for_rollback(const struct object_id *oid)\n>>   {\n>>          const char *argv[4];    /* reset --merge <arg> + NULL */\n>> +       size_t i = 0;\n> \n> That size_t is, eh, \"unusual\".  For an index into a small local\n> array of known size, just sticking to bog-standard-and-boring 'int'\n> would make it less distracting for future readers of the code.\n\nYes size_t is overkill here, it tends to be my default \"array index\" \ntype but there's no need for it here.\n\n> Or even better, perhaps use argv-array, so that you do not have to\n> worry about sizing the local array sufficiently large in the first\n> place.\n\nThat would be a much better way of doing it, I was so focussed on the \nexisting code I didn't think of that.\n\nBest Wishes\n\nPhillip\n\n> \n>> +       argv[i++] = \"reset\";\n>> +       argv[i++] = \"--merge\";\n>> +       if (oid)\n>> +               argv[i++] = oid_to_hex(oid);\n>> +       argv[i] = NULL;\n>>          return run_command_v_opt(argv, RUN_GIT_CMD);\n>>   }\n> \n"},{"id":"377137","messageId":"20190613040504.32317-4-rohit.ashiwal265@gmail.com","threadId":"51269","inReplyTo":"20190613040504.32317-1-rohit.ashiwal265@gmail.com","subject":"[GSoC][PATCH v3 3/3] cherry-pick/revert: advise using --skip","fromName":"Rohit Ashiwal","fromEmail":"rohit.ashiwal265@gmail.com","sentAt":"2019-06-13T04:05:04Z","receivedAt":"2019-06-13T16:50:05Z","isPatch":true,"sender":{"key":"rohit.ashiwal265@gmail.com","avatar":"https://avatars.githubusercontent.com/u/31043830?v=4"},"body":"The previous commit introduced a --skip flag for cherry-pick and\nrevert. Update the advice messages, to tell users about this less\ncumbersome way of skipping commits. Also add tests to ensure\neverything is working fine.\n\nSigned-off-by: Rohit Ashiwal <rohit.ashiwal265@gmail.com>\n---\nchanges:\n    - No major changes, change slightly according to the previous commits\n\n builtin/commit.c                | 13 ++++++++-----\n sequencer.c                     | 11 ++++++++---\n t/t3510-cherry-pick-sequence.sh | 20 ++++++++++++++++++++\n 3 files changed, 36 insertions(+), 8 deletions(-)\n\ndiff --git a/builtin/commit.c b/builtin/commit.c\nindex 1c9e8e2228..1f47c51bdc 100644\n--- a/builtin/commit.c\n+++ b/builtin/commit.c\n@@ -60,15 +60,18 @@ N_(\"The previous cherry-pick is now empty, possibly due to conflict resolution.\\\n \"\\n\");\n \n static const char empty_cherry_pick_advice_single[] =\n-N_(\"Otherwise, please use 'git reset'\\n\");\n+N_(\"Otherwise, please use 'git cherry-pick --skip'\\n\");\n \n static const char empty_cherry_pick_advice_multi[] =\n-N_(\"If you wish to skip this commit, use:\\n\"\n+N_(\"and then use:\\n\"\n \"\\n\"\n-\"    git reset\\n\"\n+\"    git cherry-pick --continue\\n\"\n \"\\n\"\n-\"Then \\\"git cherry-pick --continue\\\" will resume cherry-picking\\n\"\n-\"the remaining commits.\\n\");\n+\"to resume cherry-picking the remaining commits.\\n\"\n+\"If you wish to skip this commit, use:\\n\"\n+\"\\n\"\n+\"    git cherry-pick --skip\\n\"\n+\"\\n\");\n \n static const char *color_status_slots[] = {\n \t[WT_STATUS_HEADER]\t  = \"header\",\ndiff --git a/sequencer.c b/sequencer.c\nindex 6b78a26920..5d189791ee 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -2655,18 +2655,20 @@ static int create_seq_dir(struct repository *r)\n \tenum replay_action action;\n \tconst char *in_progress_advice;\n \tconst char *in_progress_error = NULL;\n+\tunsigned int advise_skip = file_exists(git_path_revert_head(r)) ||\n+\t\t\t\tfile_exists(git_path_cherry_pick_head(r));\n \n \tif (!sequencer_get_last_command(r, &action)) {\n \t\tswitch (action) {\n \t\tcase REPLAY_REVERT:\n \t\t\tin_progress_error = _(\"revert is already in progress\");\n \t\t\tin_progress_advice =\n-\t\t\t_(\"try \\\"git revert (--continue | --abort | --quit)\\\"\");\n+\t\t\t_(\"try \\\"git revert (--continue | %s--abort | --quit)\\\"\");\n \t\t\tbreak;\n \t\tcase REPLAY_PICK:\n \t\t\tin_progress_error = _(\"cherry-pick is already in progress\");\n \t\t\tin_progress_advice =\n-\t\t\t_(\"try \\\"git cherry-pick (--continue | --abort | --quit)\\\"\");\n+\t\t\t_(\"try \\\"git cherry-pick (--continue | %s--abort | --quit)\\\"\");\n \t\t\tbreak;\n \t\tdefault:\n \t\t\tBUG(_(\"the control must not reach here\"));\n@@ -2674,7 +2676,10 @@ static int create_seq_dir(struct repository *r)\n \t}\n \tif (in_progress_error) {\n \t\terror(\"%s\", in_progress_error);\n-\t\tadvise(\"%s\", in_progress_advice);\n+\t\tif (advise_skip)\n+\t\t\tadvise(in_progress_advice, \"--skip | \");\n+\t\telse\n+\t\t\tadvise(in_progress_advice, \"\");\n \t\treturn -1;\n \t}\n \tif (mkdir(git_path_seq_dir(), 0777) < 0)\ndiff --git a/t/t3510-cherry-pick-sequence.sh b/t/t3510-cherry-pick-sequence.sh\nindex f85ef51cac..8672f0b2cd 100755\n--- a/t/t3510-cherry-pick-sequence.sh\n+++ b/t/t3510-cherry-pick-sequence.sh\n@@ -172,6 +172,26 @@ test_expect_success 'check advice when we move HEAD by committing' '\n \ttest_cmp expect advice\n '\n \n+test_expect_success 'selectively advise --skip while launching another sequence' '\n+\tpristine_detach initial &&\n+\tcat >expect <<-EOF &&\n+\terror: cherry-pick is already in progress\n+\thint: try \"git cherry-pick (--continue | --skip | --abort | --quit)\"\n+\tfatal: cherry-pick failed\n+\tEOF\n+\ttest_must_fail git cherry-pick picked..yetanotherpick &&\n+\ttest_must_fail git cherry-pick picked..yetanotherpick 2>advice &&\n+\ttest_cmp expect advice &&\n+\tcat >expect <<-EOF &&\n+\terror: cherry-pick is already in progress\n+\thint: try \"git cherry-pick (--continue | --abort | --quit)\"\n+\tfatal: cherry-pick failed\n+\tEOF\n+\tgit reset --merge &&\n+\ttest_must_fail git cherry-pick picked..yetanotherpick 2>advice &&\n+\ttest_cmp expect advice\n+'\n+\n test_expect_success 'allow skipping commit but not abort for a new history' '\n \tpristine_detach initial &&\n \tcat >expect <<-EOF &&\n-- \n2.21.0\n\n"},{"id":"377138","messageId":"20190613040504.32317-3-rohit.ashiwal265@gmail.com","threadId":"51269","inReplyTo":"20190613040504.32317-1-rohit.ashiwal265@gmail.com","subject":"[GSoC][PATCH v3 2/3] cherry-pick/revert: add --skip option","fromName":"Rohit Ashiwal","fromEmail":"rohit.ashiwal265@gmail.com","sentAt":"2019-06-13T04:05:03Z","receivedAt":"2019-06-13T16:50:18Z","isPatch":true,"sender":{"key":"rohit.ashiwal265@gmail.com","avatar":"https://avatars.githubusercontent.com/u/31043830?v=4"},"body":"git am or rebase have a --skip flag to skip the current commit if the\nuser wishes to do so. During a cherry-pick or revert a user could\nlikewise skip a commit, but needs to use 'git reset' (or in the case\nof conflicts 'git reset --merge'), followed by 'git (cherry-pick |\nrevert) --continue' to skip the commit. This is more annoying and\nsometimes confusing on the users' part. Add a `--skip` option to make\nskipping commits easier for the user and to make the commands more\nconsistent.\n\nIn the next commit, we will change the advice messages and some tests\nhence finishing the process of teaching revert and cherry-pick\n\"how to skip commits\".\n\nSigned-off-by: Rohit Ashiwal <rohit.ashiwal265@gmail.com>\n---\nchanges:\n    - Remove `reset_merge` from last revision[1] and modified `reset_for_rollback`\n      and signature of `rollback_single_pick` to handle if `--skip` flag\n    - Modify test which gave \"ambiguous refname\" warning[2]\n\n[1]: https://public-inbox.org/git/20190608191958.4593-1-rohit.ashiwal265@gmail.com/T/#m11a573a3b91dfd2fcfae40c6ecc2148f8c92e10c\n[2]: https://public-inbox.org/git/20190608191958.4593-1-rohit.ashiwal265@gmail.com/T/#m586cb8930cfcb737e4f19662f0eef3716b1e9d35\n\n Documentation/git-cherry-pick.txt |   4 +-\n Documentation/git-revert.txt      |   4 +-\n Documentation/sequencer.txt       |   4 ++\n builtin/revert.c                  |   5 ++\n sequencer.c                       |  67 +++++++++++++++++---\n sequencer.h                       |   1 +\n t/t3510-cherry-pick-sequence.sh   | 102 ++++++++++++++++++++++++++++++\n 7 files changed, 171 insertions(+), 16 deletions(-)\n\ndiff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt\nindex 754b16ce0c..955880ab88 100644\n--- a/Documentation/git-cherry-pick.txt\n+++ b/Documentation/git-cherry-pick.txt\n@@ -10,9 +10,7 @@ SYNOPSIS\n [verse]\n 'git cherry-pick' [--edit] [-n] [-m parent-number] [-s] [-x] [--ff]\n \t\t  [-S[<keyid>]] <commit>...\n-'git cherry-pick' --continue\n-'git cherry-pick' --quit\n-'git cherry-pick' --abort\n+'git cherry-pick' --continue | --skip | --abort | --quit\n \n DESCRIPTION\n -----------\ndiff --git a/Documentation/git-revert.txt b/Documentation/git-revert.txt\nindex 0c82ca5bc0..ffce98099c 100644\n--- a/Documentation/git-revert.txt\n+++ b/Documentation/git-revert.txt\n@@ -9,9 +9,7 @@ SYNOPSIS\n --------\n [verse]\n 'git revert' [--[no-]edit] [-n] [-m parent-number] [-s] [-S[<keyid>]] <commit>...\n-'git revert' --continue\n-'git revert' --quit\n-'git revert' --abort\n+'git revert' --continue | --skip | --abort | --quit\n \n DESCRIPTION\n -----------\ndiff --git a/Documentation/sequencer.txt b/Documentation/sequencer.txt\nindex 5a57c4a407..3bceb56474 100644\n--- a/Documentation/sequencer.txt\n+++ b/Documentation/sequencer.txt\n@@ -3,6 +3,10 @@\n \t`.git/sequencer`.  Can be used to continue after resolving\n \tconflicts in a failed cherry-pick or revert.\n \n+--skip::\n+\tSkip the current commit and continue with the rest of the\n+\tsequence.\n+\n --quit::\n \tForget about the current operation in progress.  Can be used\n \tto clear the sequencer state after a failed cherry-pick or\ndiff --git a/builtin/revert.c b/builtin/revert.c\nindex d4dcedbdc6..5dc5891ea2 100644\n--- a/builtin/revert.c\n+++ b/builtin/revert.c\n@@ -102,6 +102,7 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)\n \t\tOPT_CMDMODE(0, \"quit\", &cmd, N_(\"end revert or cherry-pick sequence\"), 'q'),\n \t\tOPT_CMDMODE(0, \"continue\", &cmd, N_(\"resume revert or cherry-pick sequence\"), 'c'),\n \t\tOPT_CMDMODE(0, \"abort\", &cmd, N_(\"cancel revert or cherry-pick sequence\"), 'a'),\n+\t\tOPT_CMDMODE(0, \"skip\", &cmd, N_(\"skip current commit and continue\"), 's'),\n \t\tOPT_CLEANUP(&cleanup_arg),\n \t\tOPT_BOOL('n', \"no-commit\", &opts->no_commit, N_(\"don't automatically commit\")),\n \t\tOPT_BOOL('e', \"edit\", &opts->edit, N_(\"edit the commit message\")),\n@@ -151,6 +152,8 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)\n \t\t\tthis_operation = \"--quit\";\n \t\telse if (cmd == 'c')\n \t\t\tthis_operation = \"--continue\";\n+\t\telse if (cmd == 's')\n+\t\t\tthis_operation = \"--skip\";\n \t\telse {\n \t\t\tassert(cmd == 'a');\n \t\t\tthis_operation = \"--abort\";\n@@ -210,6 +213,8 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)\n \t\treturn sequencer_continue(the_repository, opts);\n \tif (cmd == 'a')\n \t\treturn sequencer_rollback(the_repository, opts);\n+\tif (cmd == 's')\n+\t\treturn sequencer_skip(the_repository, opts);\n \treturn sequencer_pick_revisions(the_repository, opts);\n }\n \ndiff --git a/sequencer.c b/sequencer.c\nindex 918cb5d761..6b78a26920 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -2733,25 +2733,26 @@ static int rollback_is_safe(void)\n \n static int reset_for_rollback(const struct object_id *oid)\n {\n-\tconst char *argv[4];\t/* reset --merge <arg> + NULL */\n+\tstruct argv_array argv = ARGV_ARRAY_INIT;\t/* reset --merge <arg> + NULL */\n \n-\targv[0] = \"reset\";\n-\targv[1] = \"--merge\";\n-\targv[2] = oid_to_hex(oid);\n-\targv[3] = NULL;\n-\treturn run_command_v_opt(argv, RUN_GIT_CMD);\n+\targv_array_pushl(&argv, \"reset\", \"--merge\", NULL);\n+\n+\tif (!is_null_oid(oid))\n+\t\targv_array_push(&argv, oid_to_hex(oid));\n+\n+\treturn run_command_v_opt(argv.argv, RUN_GIT_CMD);\n }\n \n-static int rollback_single_pick(struct repository *r)\n+static int rollback_single_pick(struct repository *r, unsigned int is_skip)\n {\n \tstruct object_id head_oid;\n \n \tif (!file_exists(git_path_cherry_pick_head(r)) &&\n-\t    !file_exists(git_path_revert_head(r)))\n+\t    !file_exists(git_path_revert_head(r)) && !is_skip)\n \t\treturn error(_(\"no cherry-pick or revert in progress\"));\n \tif (read_ref_full(\"HEAD\", 0, &head_oid, NULL))\n \t\treturn error(_(\"cannot resolve HEAD\"));\n-\tif (is_null_oid(&head_oid))\n+\tif (is_null_oid(&head_oid) && !is_skip)\n \t\treturn error(_(\"cannot abort from a branch yet to be born\"));\n \treturn reset_for_rollback(&head_oid);\n }\n@@ -2770,7 +2771,7 @@ int sequencer_rollback(struct repository *r, struct replay_opts *opts)\n \t\t * If CHERRY_PICK_HEAD or REVERT_HEAD indicates\n \t\t * a single-cherry-pick in progress, abort that.\n \t\t */\n-\t\treturn rollback_single_pick(r);\n+\t\treturn rollback_single_pick(r, 0);\n \t}\n \tif (!f)\n \t\treturn error_errno(_(\"cannot open '%s'\"), git_path_head_file());\n@@ -2805,6 +2806,52 @@ int sequencer_rollback(struct repository *r, struct replay_opts *opts)\n \treturn -1;\n }\n \n+int sequencer_skip(struct repository *r, struct replay_opts *opts)\n+{\n+\tenum replay_action action = -1;\n+\tsequencer_get_last_command(r, &action);\n+\n+\tswitch (opts->action) {\n+\tcase REPLAY_REVERT:\n+\t\tif (!file_exists(git_path_revert_head(r))) {\n+\t\t\tif (action == REPLAY_REVERT) {\n+\t\t\t\tif (!rollback_is_safe())\n+\t\t\t\t\tgoto give_advice;\n+\t\t\t\telse\n+\t\t\t\t\tbreak;\n+\t\t\t}\n+\t\t\treturn error(_(\"no revert in progress\"));\n+\t\t}\n+\t\tbreak;\n+\tcase REPLAY_PICK:\n+\t\tif (!file_exists(git_path_cherry_pick_head(r))) {\n+\t\t\tif (action == REPLAY_PICK) {\n+\t\t\t\tif (!rollback_is_safe())\n+\t\t\t\t\tgoto give_advice;\n+\t\t\t\telse\n+\t\t\t\t\tbreak;\n+\t\t\t}\n+\t\t\treturn error(_(\"no cherry-pick in progress\"));\n+\t\t}\n+\t\tbreak;\n+\tdefault:\n+\t\tBUG(\"the control must not reach here\");\n+\t}\n+\n+\tif (rollback_single_pick(r, 1))\n+\t\treturn error(_(\"failed to skip the commit\"));\n+\tif (!is_directory(git_path_seq_dir()))\n+\t\treturn 0;\n+\n+\treturn sequencer_continue(r, opts);\n+\n+give_advice:\n+\tadvise(_(\"have you committed already?\\n\"\n+\t\t \"try \\\"git %s --continue\\\"\"),\n+\t\t action == REPLAY_REVERT ? \"revert\" : \"cherry-pick\");\n+\treturn error(_(\"there is nothing to skip\"));\n+}\n+\n static int save_todo(struct todo_list *todo_list, struct replay_opts *opts)\n {\n \tstruct lock_file todo_lock = LOCK_INIT;\ndiff --git a/sequencer.h b/sequencer.h\nindex 0c494b83d4..731b9853eb 100644\n--- a/sequencer.h\n+++ b/sequencer.h\n@@ -129,6 +129,7 @@ int sequencer_pick_revisions(struct repository *repo,\n \t\t\t     struct replay_opts *opts);\n int sequencer_continue(struct repository *repo, struct replay_opts *opts);\n int sequencer_rollback(struct repository *repo, struct replay_opts *opts);\n+int sequencer_skip(struct repository *repo, struct replay_opts *opts);\n int sequencer_remove_state(struct replay_opts *opts);\n \n #define TODO_LIST_KEEP_EMPTY (1U << 0)\ndiff --git a/t/t3510-cherry-pick-sequence.sh b/t/t3510-cherry-pick-sequence.sh\nindex 941d5026da..f85ef51cac 100755\n--- a/t/t3510-cherry-pick-sequence.sh\n+++ b/t/t3510-cherry-pick-sequence.sh\n@@ -93,6 +93,108 @@ test_expect_success 'cherry-pick cleans up sequencer state upon success' '\n \ttest_path_is_missing .git/sequencer\n '\n \n+test_expect_success 'cherry-pick --skip requires cherry-pick in progress' '\n+\tpristine_detach initial &&\n+\ttest_must_fail git cherry-pick --skip\n+'\n+\n+test_expect_success 'revert --skip requires revert in progress' '\n+\tpristine_detach initial &&\n+\ttest_must_fail git revert --skip\n+'\n+\n+test_expect_success 'cherry-pick --skip to skip commit' '\n+\tpristine_detach initial &&\n+\ttest_must_fail git cherry-pick anotherpick &&\n+\ttest_must_fail git revert --skip &&\n+\tgit cherry-pick --skip &&\n+\ttest_cmp_rev initial HEAD &&\n+\ttest_path_is_missing .git/CHERRY_PICK_HEAD\n+'\n+\n+test_expect_success 'revert --skip to skip commit' '\n+\tpristine_detach anotherpick &&\n+\ttest_must_fail git revert anotherpick~1 &&\n+\ttest_must_fail git cherry-pick --skip &&\n+\tgit revert --skip &&\n+\ttest_cmp_rev anotherpick HEAD\n+'\n+\n+test_expect_success 'skip \"empty\" commit' '\n+\tpristine_detach picked &&\n+\ttest_commit dummy foo d &&\n+\ttest_must_fail git cherry-pick anotherpick &&\n+\tgit cherry-pick --skip &&\n+\ttest_cmp_rev dummy HEAD\n+'\n+\n+test_expect_success 'skip a commit and check if rest of sequence is correct' '\n+\tpristine_detach initial &&\n+\techo e >expect &&\n+\tcat >expect.log <<-EOF &&\n+\tOBJID\n+\t:100644 100644 OBJID OBJID M\tfoo\n+\tOBJID\n+\t:100644 100644 OBJID OBJID M\tfoo\n+\tOBJID\n+\t:100644 100644 OBJID OBJID M\tunrelated\n+\tOBJID\n+\t:000000 100644 OBJID OBJID A\tfoo\n+\t:000000 100644 OBJID OBJID A\tunrelated\n+\tEOF\n+\ttest_must_fail git cherry-pick base..yetanotherpick &&\n+\ttest_must_fail git cherry-pick --skip &&\n+\techo d >foo &&\n+\tgit add foo &&\n+\tgit cherry-pick --continue &&\n+\t{\n+\t\tgit rev-list HEAD |\n+\t\tgit diff-tree --root --stdin |\n+\t\tsed \"s/$OID_REGEX/OBJID/g\"\n+\t} >actual.log &&\n+\ttest_cmp expect foo &&\n+\ttest_cmp expect.log actual.log\n+'\n+\n+test_expect_success 'check advice when we move HEAD by committing' '\n+\tpristine_detach initial &&\n+\tcat >expect <<-EOF &&\n+\thint: have you committed already?\n+\thint: try \"git cherry-pick --continue\"\n+\terror: there is nothing to skip\n+\tfatal: cherry-pick failed\n+\tEOF\n+\ttest_must_fail git cherry-pick base..yetanotherpick &&\n+\techo c >foo &&\n+\tgit commit -a &&\n+\ttest_path_is_missing .git/CHERRY_PICK_HEAD &&\n+\ttest_must_fail git cherry-pick --skip 2>advice &&\n+\ttest_cmp expect advice\n+'\n+\n+test_expect_success 'allow skipping commit but not abort for a new history' '\n+\tpristine_detach initial &&\n+\tcat >expect <<-EOF &&\n+\terror: cannot abort from a branch yet to be born\n+\tfatal: cherry-pick failed\n+\tEOF\n+\tgit checkout --orphan new_disconnected &&\n+\tgit reset --hard &&\n+\ttest_must_fail git cherry-pick anotherpick &&\n+\ttest_must_fail git cherry-pick --abort 2>advice &&\n+\tgit cherry-pick --skip &&\n+\ttest_cmp expect advice\n+'\n+\n+test_expect_success 'allow skipping stopped cherry-pick because of untracked file modifications' '\n+\tpristine_detach initial &&\n+\tgit rm --cached unrelated &&\n+\tgit commit -m \"untrack unrelated\" &&\n+\ttest_must_fail git cherry-pick initial base &&\n+\ttest_path_is_missing .git/CHERRY_PICK_HEAD &&\n+\tgit cherry-pick --skip\n+'\n+\n test_expect_success '--quit does not complain when no cherry-pick is in progress' '\n \tpristine_detach initial &&\n \tgit cherry-pick --quit\n-- \n2.21.0\n\n"},{"id":"377139","messageId":"20190613040504.32317-2-rohit.ashiwal265@gmail.com","threadId":"51269","inReplyTo":"20190613040504.32317-1-rohit.ashiwal265@gmail.com","subject":"[GSoC][PATCH v3 1/3] sequencer: add advice for revert","fromName":"Rohit Ashiwal","fromEmail":"rohit.ashiwal265@gmail.com","sentAt":"2019-06-13T04:05:02Z","receivedAt":"2019-06-13T16:50:22Z","isPatch":true,"sender":{"key":"rohit.ashiwal265@gmail.com","avatar":"https://avatars.githubusercontent.com/u/31043830?v=4"},"body":"In the case of merge conflicts, while performing a revert, we are\ncurrently advised to use `git cherry-pick --<sequencer-options>`\nof which --continue is incompatible for continuing the revert.\nIntroduce a separate advice message for `git revert`. Also change\nthe signature of `create_seq_dir` to handle which advice to display\nselectively.\n\nSigned-off-by: Rohit Ashiwal <rohit.ashiwal265@gmail.com>\n---\nchanges:\n    - Following Junio's advice[1], I've changed how we're handling error and\n      advice fundamentally.\n\n[1]: https://public-inbox.org/git/20190608191958.4593-1-rohit.ashiwal265@gmail.com/T/#mf8eefb068b7246c7c2a02cc8f7120a1a903a1eba\n\n sequencer.c | 34 ++++++++++++++++++++++++++++------\n 1 file changed, 28 insertions(+), 6 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex f88a97fb10..918cb5d761 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -2650,15 +2650,37 @@ static int walk_revs_populate_todo(struct todo_list *todo_list,\n \treturn 0;\n }\n \n-static int create_seq_dir(void)\n+static int create_seq_dir(struct repository *r)\n {\n-\tif (file_exists(git_path_seq_dir())) {\n-\t\terror(_(\"a cherry-pick or revert is already in progress\"));\n-\t\tadvise(_(\"try \\\"git cherry-pick (--continue | --quit | --abort)\\\"\"));\n+\tenum replay_action action;\n+\tconst char *in_progress_advice;\n+\tconst char *in_progress_error = NULL;\n+\n+\tif (!sequencer_get_last_command(r, &action)) {\n+\t\tswitch (action) {\n+\t\tcase REPLAY_REVERT:\n+\t\t\tin_progress_error = _(\"revert is already in progress\");\n+\t\t\tin_progress_advice =\n+\t\t\t_(\"try \\\"git revert (--continue | --abort | --quit)\\\"\");\n+\t\t\tbreak;\n+\t\tcase REPLAY_PICK:\n+\t\t\tin_progress_error = _(\"cherry-pick is already in progress\");\n+\t\t\tin_progress_advice =\n+\t\t\t_(\"try \\\"git cherry-pick (--continue | --abort | --quit)\\\"\");\n+\t\t\tbreak;\n+\t\tdefault:\n+\t\t\tBUG(_(\"the control must not reach here\"));\n+\t\t}\n+\t}\n+\tif (in_progress_error) {\n+\t\terror(\"%s\", in_progress_error);\n+\t\tadvise(\"%s\", in_progress_advice);\n \t\treturn -1;\n-\t} else if (mkdir(git_path_seq_dir(), 0777) < 0)\n+\t}\n+\tif (mkdir(git_path_seq_dir(), 0777) < 0)\n \t\treturn error_errno(_(\"could not create sequencer directory '%s'\"),\n \t\t\t\t   git_path_seq_dir());\n+\n \treturn 0;\n }\n \n@@ -4237,7 +4259,7 @@ int sequencer_pick_revisions(struct repository *r,\n \t */\n \n \tif (walk_revs_populate_todo(&todo_list, opts) ||\n-\t\t\tcreate_seq_dir() < 0)\n+\t\t\tcreate_seq_dir(r) < 0)\n \t\treturn -1;\n \tif (get_oid(\"HEAD\", &oid) && (opts->action == REPLAY_REVERT))\n \t\treturn error(_(\"can't revert as initial commit\"));\n-- \n2.21.0\n\n"},{"id":"377140","messageId":"20190613040504.32317-1-rohit.ashiwal265@gmail.com","threadId":"51269","inReplyTo":"20190608191958.4593-1-rohit.ashiwal265@gmail.com","subject":"[GSoC][PATCH v3 0/3] Teach cherry-pick/revert to skip commits","fromName":"Rohit Ashiwal","fromEmail":"rohit.ashiwal265@gmail.com","sentAt":"2019-06-13T04:05:01Z","receivedAt":"2019-06-13T16:50:29Z","isPatch":true,"sender":{"key":"rohit.ashiwal265@gmail.com","avatar":"https://avatars.githubusercontent.com/u/31043830?v=4"},"body":"Adding a `--skip` option to make skipping commits easier for the user\nand to make the commands more consistent. This will serve as a small\nstep to the bigger goal which improving consistency of sequencer commands,\ni.e., improving how command line arguments are handled, this will also\nlead to better user experience because of the precise advice provided.\n\nRohit Ashiwal (3):\n  sequencer: add advice for revert\n  cherry-pick/revert: add --skip option\n  cherry-pick/revert: advise using --skip\n\n Documentation/git-cherry-pick.txt |   4 +-\n Documentation/git-revert.txt      |   4 +-\n Documentation/sequencer.txt       |   4 +\n builtin/commit.c                  |  13 ++--\n builtin/revert.c                  |   5 ++\n sequencer.c                       | 106 ++++++++++++++++++++++----\n sequencer.h                       |   1 +\n t/t3510-cherry-pick-sequence.sh   | 122 ++++++++++++++++++++++++++++++\n 8 files changed, 232 insertions(+), 27 deletions(-)\n\n-- \n2.21.0\n\n"},{"id":"377162","messageId":"0333fe2f-d68a-4536-c736-ca2a356df34b@gmail.com","threadId":"51269","inReplyTo":"20190613040504.32317-2-rohit.ashiwal265@gmail.com","subject":"Re: [GSoC][PATCH v3 1/3] sequencer: add advice for revert","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2019-06-13T17:45:24Z","receivedAt":"2019-06-13T17:45:17Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"On 13/06/2019 05:05, Rohit Ashiwal wrote:\n> In the case of merge conflicts, while performing a revert, we are\n> currently advised to use `git cherry-pick --<sequencer-options>`\n> of which --continue is incompatible for continuing the revert.\n> Introduce a separate advice message for `git revert`. Also change\n> the signature of `create_seq_dir` to handle which advice to display\n> selectively.\n> \n> Signed-off-by: Rohit Ashiwal <rohit.ashiwal265@gmail.com>\n> ---\n> changes:\n>     - Following Junio's advice[1], I've changed how we're handling error and\n>       advice fundamentally.\n> \n> [1]: https://public-inbox.org/git/20190608191958.4593-1-rohit.ashiwal265@gmail.com/T/#mf8eefb068b7246c7c2a02cc8f7120a1a903a1eba\n> \n>  sequencer.c | 34 ++++++++++++++++++++++++++++------\n>  1 file changed, 28 insertions(+), 6 deletions(-)\n> \n> diff --git a/sequencer.c b/sequencer.c\n> index f88a97fb10..918cb5d761 100644\n> --- a/sequencer.c\n> +++ b/sequencer.c\n> @@ -2650,15 +2650,37 @@ static int walk_revs_populate_todo(struct todo_list *todo_list,\n>  \treturn 0;\n>  }\n>  \n> -static int create_seq_dir(void)\n> +static int create_seq_dir(struct repository *r)\n>  {\n> -\tif (file_exists(git_path_seq_dir())) {\n> -\t\terror(_(\"a cherry-pick or revert is already in progress\"));\n> -\t\tadvise(_(\"try \\\"git cherry-pick (--continue | --quit | --abort)\\\"\"));\n> +\tenum replay_action action;\n> +\tconst char *in_progress_advice;\n> +\tconst char *in_progress_error = NULL;\n> +\n> +\tif (!sequencer_get_last_command(r, &action)) {\n> +\t\tswitch (action) {\n> +\t\tcase REPLAY_REVERT:\n> +\t\t\tin_progress_error = _(\"revert is already in progress\");\n> +\t\t\tin_progress_advice =\n> +\t\t\t_(\"try \\\"git revert (--continue | --abort | --quit)\\\"\");\n> +\t\t\tbreak;\n> +\t\tcase REPLAY_PICK:\n> +\t\t\tin_progress_error = _(\"cherry-pick is already in progress\");\n> +\t\t\tin_progress_advice =\n> +\t\t\t_(\"try \\\"git cherry-pick (--continue | --abort | --quit)\\\"\");\n> +\t\t\tbreak;\n> +\t\tdefault:\n> +\t\t\tBUG(_(\"the control must not reach here\"));\n\nThis does not need to be translated as BUG() messages are not really for\nusers. Everything else looks fine to be now\n\nBest Wishes\n\nPhillip\n\n> +\t\t}\n> +\t}\n> +\tif (in_progress_error) {\n> +\t\terror(\"%s\", in_progress_error);\n> +\t\tadvise(\"%s\", in_progress_advice);\n>  \t\treturn -1;\n> -\t} else if (mkdir(git_path_seq_dir(), 0777) < 0)\n> +\t}\n> +\tif (mkdir(git_path_seq_dir(), 0777) < 0)\n>  \t\treturn error_errno(_(\"could not create sequencer directory '%s'\"),\n>  \t\t\t\t   git_path_seq_dir());\n> +\n>  \treturn 0;\n>  }\n>  \n> @@ -4237,7 +4259,7 @@ int sequencer_pick_revisions(struct repository *r,\n>  \t */\n>  \n>  \tif (walk_revs_populate_todo(&todo_list, opts) ||\n> -\t\t\tcreate_seq_dir() < 0)\n> +\t\t\tcreate_seq_dir(r) < 0)\n>  \t\treturn -1;\n>  \tif (get_oid(\"HEAD\", &oid) && (opts->action == REPLAY_REVERT))\n>  \t\treturn error(_(\"can't revert as initial commit\"));\n> \n\n"},{"id":"377165","messageId":"xmqqa7elwer9.fsf@gitster-ct.c.googlers.com","threadId":"51269","inReplyTo":"20190613040504.32317-3-rohit.ashiwal265@gmail.com","subject":"Re: [GSoC][PATCH v3 2/3] cherry-pick/revert: add --skip option","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-06-13T17:56:26Z","receivedAt":"2019-06-13T17:56:38Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Rohit Ashiwal <rohit.ashiwal265@gmail.com> writes:\n\n> diff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt\n> index 754b16ce0c..955880ab88 100644\n> --- a/Documentation/git-cherry-pick.txt\n> +++ b/Documentation/git-cherry-pick.txt\n> @@ -10,9 +10,7 @@ SYNOPSIS\n>  [verse]\n>  'git cherry-pick' [--edit] [-n] [-m parent-number] [-s] [-x] [--ff]\n>  \t\t  [-S[<keyid>]] <commit>...\n> -'git cherry-pick' --continue\n> -'git cherry-pick' --quit\n> -'git cherry-pick' --abort\n> +'git cherry-pick' --continue | --skip | --abort | --quit\n\nIs this correct, or do we need to enclose these choices inside (),\ni.e.\n\n\t'git cherry-pick' ( --continue | --skip | --abort | --quit )\n\n?  \n\n> -static int rollback_single_pick(struct repository *r)\n> +static int rollback_single_pick(struct repository *r, unsigned int is_skip)\n>  {\n>  \tstruct object_id head_oid;\n>  \n>  \tif (!file_exists(git_path_cherry_pick_head(r)) &&\n> -\t    !file_exists(git_path_revert_head(r)))\n> +\t    !file_exists(git_path_revert_head(r)) && !is_skip)\n>  \t\treturn error(_(\"no cherry-pick or revert in progress\"));\n>  \tif (read_ref_full(\"HEAD\", 0, &head_oid, NULL))\n>  \t\treturn error(_(\"cannot resolve HEAD\"));\n> -\tif (is_null_oid(&head_oid))\n> +\tif (is_null_oid(&head_oid) && !is_skip)\n>  \t\treturn error(_(\"cannot abort from a branch yet to be born\"));\n>  \treturn reset_for_rollback(&head_oid);\n>  }\n\nIt is unclear *why* the function (and more importantly, its callers)\nwould want to omit two sanity checks when is_skip is in effect.\n\nBefore this patch introduced such conditional behaviour, the name\nwas descriptive enough for this single-purpose function that is a\nfile-local helper, but it is no longer a case.  The function needs a\nbit of commentary before it.\n\nWhen &&-chaining error checks that are optional, check the condition\nthat makes the error checks optional first, i.e.\n\n\tif (!is_skip &&\n\t\t!file_exists(...) && !file_exists(...))\n\t\treturn error(...);\n\nThe same comment applies to the \"do not barf by checking is-null-oid\nunder is-skip mode, as that is a sign that we are on an unborn\nbranch and reset-for-rollback knows how to handle it now\".\n\nIt may even be a good idea to group the checks that are guarded by\nthe condition for readability, i.e.\n\n\tif (!is_skip &&\n\t\t(!file_exists(...) && !file_exists(...)))\n\t\treturn error(...);\n\n> +int sequencer_skip(struct repository *r, struct replay_opts *opts)\n> +{\n> +\tenum replay_action action = -1;\n> +\tsequencer_get_last_command(r, &action);\n> +\n> +\tswitch (opts->action) {\n> +\tcase REPLAY_REVERT:\n> +\t\tif (!file_exists(git_path_revert_head(r))) {\n> +\t\t\tif (action == REPLAY_REVERT) {\n> +\t\t\t\tif (!rollback_is_safe())\n> +\t\t\t\t\tgoto give_advice;\n> +\t\t\t\telse\n> +\t\t\t\t\tbreak;\n> +\t\t\t}\n> +\t\t\treturn error(_(\"no revert in progress\"));\n> +\t\t}\n\nThis part probably deserves a bit of in-code comment.  \n\n    The Git subcommand (i.e. opts->action) tells us that we are\n    asked to \"git revert --skip\".  When REVERT_HEAD is not there, we\n    look at the last command of the sequencer state and make sure it\n    is 'revert'; all other cases we barf.\n\nThat much we can read from the code.  But what are \"all other cases\"?\nDo we cover a single-revert case (i.e. \"git revert <commit>\" got\nconflict and the user is saying \"git revert --skip\")?  Was the user\nin the middle of \"git rebase -i\" and the last command before we gave\nthe control back was 'pick'?\n\n> +\t\tbreak;\n> +\tcase REPLAY_PICK:\n> +\t\tif (!file_exists(git_path_cherry_pick_head(r))) {\n> +\t\t\tif (action == REPLAY_PICK) {\n> +\t\t\t\tif (!rollback_is_safe())\n> +\t\t\t\t\tgoto give_advice;\n> +\t\t\t\telse\n> +\t\t\t\t\tbreak;\n> +\t\t\t}\n> +\t\t\treturn error(_(\"no cherry-pick in progress\"));\n> +\t\t}\n> +\t\tbreak;\n> +\tdefault:\n> +\t\tBUG(\"the control must not reach here\");\n> +\t}\n> +\n> +\tif (rollback_single_pick(r, 1))\n> +\t\treturn error(_(\"failed to skip the commit\"));\n\nAnd this takes us back to the previous comment.  By passing '1'\nhere, this caller is asking the callee to omit certain sanity check\nthe original version of the callee used to do.  What makes it an\nappropriate thing to do so here?  \"Because we reach at this point\nunder such and such condition, we would never have CHERRY_PICK_HEAD\nor REVERT_HEAD---we do not want it to barf\" is a good answer (and\nno, do not merely give answer to me in your response---write the\nanswer as in-code comment to help future readers of the code).\n\n\"Because when we come here, sometimes the XXX_HEAD must exist but\nsome other times XXX_HEAD may not exist, so insisting that either\nexists would make the function fail\" is *NOT* a good answer, on the\nother hand.  Somebody must still check that the necessary file\nexists when it must exist.\n\nThanks.\n"},{"id":"377166","messageId":"0d6272d8-44d1-06e3-8a7f-01c62aa224d5@gmail.com","threadId":"51269","inReplyTo":"20190613040504.32317-3-rohit.ashiwal265@gmail.com","subject":"Re: [GSoC][PATCH v3 2/3] cherry-pick/revert: add --skip option","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2019-06-13T17:59:49Z","receivedAt":"2019-06-13T17:59:43Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"Hi Rohit\n\nThis is definitely moving in the right direction.\n\nOn 13/06/2019 05:05, Rohit Ashiwal wrote:\n> git am or rebase have a --skip flag to skip the current commit if the\n> user wishes to do so. During a cherry-pick or revert a user could\n> likewise skip a commit, but needs to use 'git reset' (or in the case\n> of conflicts 'git reset --merge'), followed by 'git (cherry-pick |\n> revert) --continue' to skip the commit. This is more annoying and\n> sometimes confusing on the users' part. Add a `--skip` option to make\n> skipping commits easier for the user and to make the commands more\n> consistent.\n> \n> In the next commit, we will change the advice messages and some tests\n> hence finishing the process of teaching revert and cherry-pick\n> \"how to skip commits\".\n> \n> Signed-off-by: Rohit Ashiwal <rohit.ashiwal265@gmail.com>\n> ---\n> changes:\n>     - Remove `reset_merge` from last revision[1] and modified `reset_for_rollback`\n>       and signature of `rollback_single_pick` to handle if `--skip` flag\n>     - Modify test which gave \"ambiguous refname\" warning[2]\n> \n> [1]: https://public-inbox.org/git/20190608191958.4593-1-rohit.ashiwal265@gmail.com/T/#m11a573a3b91dfd2fcfae40c6ecc2148f8c92e10c\n> [2]: https://public-inbox.org/git/20190608191958.4593-1-rohit.ashiwal265@gmail.com/T/#m586cb8930cfcb737e4f19662f0eef3716b1e9d35\n> \n>  Documentation/git-cherry-pick.txt |   4 +-\n>  Documentation/git-revert.txt      |   4 +-\n>  Documentation/sequencer.txt       |   4 ++\n>  builtin/revert.c                  |   5 ++\n>  sequencer.c                       |  67 +++++++++++++++++---\n>  sequencer.h                       |   1 +\n>  t/t3510-cherry-pick-sequence.sh   | 102 ++++++++++++++++++++++++++++++\n>  7 files changed, 171 insertions(+), 16 deletions(-)\n> \n> diff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt\n> index 754b16ce0c..955880ab88 100644\n> --- a/Documentation/git-cherry-pick.txt\n> +++ b/Documentation/git-cherry-pick.txt\n> @@ -10,9 +10,7 @@ SYNOPSIS\n>  [verse]\n>  'git cherry-pick' [--edit] [-n] [-m parent-number] [-s] [-x] [--ff]\n>  \t\t  [-S[<keyid>]] <commit>...\n> -'git cherry-pick' --continue\n> -'git cherry-pick' --quit\n> -'git cherry-pick' --abort\n> +'git cherry-pick' --continue | --skip | --abort | --quit\n>  \n>  DESCRIPTION\n>  -----------\n> diff --git a/Documentation/git-revert.txt b/Documentation/git-revert.txt\n> index 0c82ca5bc0..ffce98099c 100644\n> --- a/Documentation/git-revert.txt\n> +++ b/Documentation/git-revert.txt\n> @@ -9,9 +9,7 @@ SYNOPSIS\n>  --------\n>  [verse]\n>  'git revert' [--[no-]edit] [-n] [-m parent-number] [-s] [-S[<keyid>]] <commit>...\n> -'git revert' --continue\n> -'git revert' --quit\n> -'git revert' --abort\n> +'git revert' --continue | --skip | --abort | --quit\n>  \n>  DESCRIPTION\n>  -----------\n> diff --git a/Documentation/sequencer.txt b/Documentation/sequencer.txt\n> index 5a57c4a407..3bceb56474 100644\n> --- a/Documentation/sequencer.txt\n> +++ b/Documentation/sequencer.txt\n> @@ -3,6 +3,10 @@\n>  \t`.git/sequencer`.  Can be used to continue after resolving\n>  \tconflicts in a failed cherry-pick or revert.\n>  \n> +--skip::\n> +\tSkip the current commit and continue with the rest of the\n> +\tsequence.\n> +\n>  --quit::\n>  \tForget about the current operation in progress.  Can be used\n>  \tto clear the sequencer state after a failed cherry-pick or\n> diff --git a/builtin/revert.c b/builtin/revert.c\n> index d4dcedbdc6..5dc5891ea2 100644\n> --- a/builtin/revert.c\n> +++ b/builtin/revert.c\n> @@ -102,6 +102,7 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)\n>  \t\tOPT_CMDMODE(0, \"quit\", &cmd, N_(\"end revert or cherry-pick sequence\"), 'q'),\n>  \t\tOPT_CMDMODE(0, \"continue\", &cmd, N_(\"resume revert or cherry-pick sequence\"), 'c'),\n>  \t\tOPT_CMDMODE(0, \"abort\", &cmd, N_(\"cancel revert or cherry-pick sequence\"), 'a'),\n> +\t\tOPT_CMDMODE(0, \"skip\", &cmd, N_(\"skip current commit and continue\"), 's'),\n>  \t\tOPT_CLEANUP(&cleanup_arg),\n>  \t\tOPT_BOOL('n', \"no-commit\", &opts->no_commit, N_(\"don't automatically commit\")),\n>  \t\tOPT_BOOL('e', \"edit\", &opts->edit, N_(\"edit the commit message\")),\n> @@ -151,6 +152,8 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)\n>  \t\t\tthis_operation = \"--quit\";\n>  \t\telse if (cmd == 'c')\n>  \t\t\tthis_operation = \"--continue\";\n> +\t\telse if (cmd == 's')\n> +\t\t\tthis_operation = \"--skip\";\n>  \t\telse {\n>  \t\t\tassert(cmd == 'a');\n>  \t\t\tthis_operation = \"--abort\";\n> @@ -210,6 +213,8 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)\n>  \t\treturn sequencer_continue(the_repository, opts);\n>  \tif (cmd == 'a')\n>  \t\treturn sequencer_rollback(the_repository, opts);\n> +\tif (cmd == 's')\n> +\t\treturn sequencer_skip(the_repository, opts);\n>  \treturn sequencer_pick_revisions(the_repository, opts);\n>  }\n>  \n> diff --git a/sequencer.c b/sequencer.c\n> index 918cb5d761..6b78a26920 100644\n> --- a/sequencer.c\n> +++ b/sequencer.c\n> @@ -2733,25 +2733,26 @@ static int rollback_is_safe(void)\n>  \n>  static int reset_for_rollback(const struct object_id *oid)\n>  {\n> -\tconst char *argv[4];\t/* reset --merge <arg> + NULL */\n> +\tstruct argv_array argv = ARGV_ARRAY_INIT;\t/* reset --merge <arg> + NULL */\n>  \n> -\targv[0] = \"reset\";\n> -\targv[1] = \"--merge\";\n> -\targv[2] = oid_to_hex(oid);\n> -\targv[3] = NULL;\n> -\treturn run_command_v_opt(argv, RUN_GIT_CMD);\n> +\targv_array_pushl(&argv, \"reset\", \"--merge\", NULL);\n> +\n> +\tif (!is_null_oid(oid))\n> +\t\targv_array_push(&argv, oid_to_hex(oid));\n> +\n\nargv_array_pushl() copies the strings so you need to call\nargv_array_clear() when you're done with it.\n\n> +\treturn run_command_v_opt(argv.argv, RUN_GIT_CMD);>  }\n>  \n> -static int rollback_single_pick(struct repository *r)\n> +static int rollback_single_pick(struct repository *r, unsigned int is_skip)\n>  {\n>  \tstruct object_id head_oid;\n>  \n>  \tif (!file_exists(git_path_cherry_pick_head(r)) &&\n> -\t    !file_exists(git_path_revert_head(r)))\n> +\t    !file_exists(git_path_revert_head(r)) && !is_skip)\n>  \t\treturn error(_(\"no cherry-pick or revert in progress\"));\n>  \tif (read_ref_full(\"HEAD\", 0, &head_oid, NULL))\n>  \t\treturn error(_(\"cannot resolve HEAD\"));\n> -\tif (is_null_oid(&head_oid))\n> +\tif (is_null_oid(&head_oid) && !is_skip)\n>  \t\treturn error(_(\"cannot abort from a branch yet to be born\"));\n\nThe changes here look good. One thing though - this still does not check\nif we're on the final pick or not. The more I think about it the more I\nthink it shouldn't matter but I'm bothered about why abort refuses to\nrun on the null oid. I've cc'd Jonathan in case he can remember why this\ncode is here. I looked at the discussion [1] of the patch [2] that\nintroduced this but that bit doesn't seem to have been discussed.\n\n[1]\nhttps://public-inbox.org/git/20111211195836.GA25482@elie.hsd1.il.comcast.net/T/#u\n\n[2]\nhttps://github.com/git/git/commit/539047c19ec040819b6f6af2d55714195b812abb\n\n>  \treturn reset_for_rollback(&head_oid);\n>  }\n> @@ -2770,7 +2771,7 @@ int sequencer_rollback(struct repository *r, struct replay_opts *opts)\n>  \t\t * If CHERRY_PICK_HEAD or REVERT_HEAD indicates\n>  \t\t * a single-cherry-pick in progress, abort that.\n>  \t\t */\n> -\t\treturn rollback_single_pick(r);\n> +\t\treturn rollback_single_pick(r, 0);\n>  \t}\n>  \tif (!f)\n>  \t\treturn error_errno(_(\"cannot open '%s'\"), git_path_head_file());\n> @@ -2805,6 +2806,52 @@ int sequencer_rollback(struct repository *r, struct replay_opts *opts)\n>  \treturn -1;\n>  }\n>  \n> +int sequencer_skip(struct repository *r, struct replay_opts *opts)\n> +{\n> +\tenum replay_action action = -1;\n> +\tsequencer_get_last_command(r, &action);\n> +\n> +\tswitch (opts->action) {\n> +\tcase REPLAY_REVERT:\n> +\t\tif (!file_exists(git_path_revert_head(r))) {\n> +\t\t\tif (action == REPLAY_REVERT) {\n> +\t\t\t\tif (!rollback_is_safe())\n> +\t\t\t\t\tgoto give_advice;\n> +\t\t\t\telse\n> +\t\t\t\t\tbreak;\n> +\t\t\t}\n> +\t\t\treturn error(_(\"no revert in progress\"));\n> +\t\t}\n> +\t\tbreak;\n> +\tcase REPLAY_PICK:\n> +\t\tif (!file_exists(git_path_cherry_pick_head(r))) {\n> +\t\t\tif (action == REPLAY_PICK) {\n> +\t\t\t\tif (!rollback_is_safe())\n> +\t\t\t\t\tgoto give_advice;\n> +\t\t\t\telse\n> +\t\t\t\t\tbreak;\n> +\t\t\t}\n> +\t\t\treturn error(_(\"no cherry-pick in progress\"));\n> +\t\t}\n> +\t\tbreak;\n> +\tdefault:\n> +\t\tBUG(\"the control must not reach here\");\n> +\t}\n> +\n> +\tif (rollback_single_pick(r, 1))\n> +\t\treturn error(_(\"failed to skip the commit\"));\n> +\tif (!is_directory(git_path_seq_dir()))\n> +\t\treturn 0;\n> +\n> +\treturn sequencer_continue(r, opts);\n> +\n> +give_advice:\n> +\tadvise(_(\"have you committed already?\\n\"\n> +\t\t \"try \\\"git %s --continue\\\"\"),\n> +\t\t action == REPLAY_REVERT ? \"revert\" : \"cherry-pick\");\n> +\treturn error(_(\"there is nothing to skip\"));\n> +}\n> +\n>  static int save_todo(struct todo_list *todo_list, struct replay_opts *opts)\n>  {\n>  \tstruct lock_file todo_lock = LOCK_INIT;\n> diff --git a/sequencer.h b/sequencer.h\n> index 0c494b83d4..731b9853eb 100644\n> --- a/sequencer.h\n> +++ b/sequencer.h\n> @@ -129,6 +129,7 @@ int sequencer_pick_revisions(struct repository *repo,\n>  \t\t\t     struct replay_opts *opts);\n>  int sequencer_continue(struct repository *repo, struct replay_opts *opts);\n>  int sequencer_rollback(struct repository *repo, struct replay_opts *opts);\n> +int sequencer_skip(struct repository *repo, struct replay_opts *opts);\n>  int sequencer_remove_state(struct replay_opts *opts);\n>  \n>  #define TODO_LIST_KEEP_EMPTY (1U << 0)\n> diff --git a/t/t3510-cherry-pick-sequence.sh b/t/t3510-cherry-pick-sequence.sh\n> index 941d5026da..f85ef51cac 100755\n> --- a/t/t3510-cherry-pick-sequence.sh\n> +++ b/t/t3510-cherry-pick-sequence.sh\n> @@ -93,6 +93,108 @@ test_expect_success 'cherry-pick cleans up sequencer state upon success' '\n>  \ttest_path_is_missing .git/sequencer\n>  '\n>  \n> +test_expect_success 'cherry-pick --skip requires cherry-pick in progress' '\n> +\tpristine_detach initial &&\n> +\ttest_must_fail git cherry-pick --skip\n> +'\n> +\n> +test_expect_success 'revert --skip requires revert in progress' '\n> +\tpristine_detach initial &&\n> +\ttest_must_fail git revert --skip\n> +'\n> +\n> +test_expect_success 'cherry-pick --skip to skip commit' '\n> +\tpristine_detach initial &&\n> +\ttest_must_fail git cherry-pick anotherpick &&\n> +\ttest_must_fail git revert --skip &&\n> +\tgit cherry-pick --skip &&\n> +\ttest_cmp_rev initial HEAD &&\n> +\ttest_path_is_missing .git/CHERRY_PICK_HEAD\n> +'\n> +\n> +test_expect_success 'revert --skip to skip commit' '\n> +\tpristine_detach anotherpick &&\n> +\ttest_must_fail git revert anotherpick~1 &&\n> +\ttest_must_fail git cherry-pick --skip &&\n> +\tgit revert --skip &&\n> +\ttest_cmp_rev anotherpick HEAD\n> +'\n> +\n> +test_expect_success 'skip \"empty\" commit' '\n> +\tpristine_detach picked &&\n> +\ttest_commit dummy foo d &&\n> +\ttest_must_fail git cherry-pick anotherpick &&\n> +\tgit cherry-pick --skip &&\n> +\ttest_cmp_rev dummy HEAD\n> +'\n> +\n> +test_expect_success 'skip a commit and check if rest of sequence is correct' '\n> +\tpristine_detach initial &&\n> +\techo e >expect &&\n> +\tcat >expect.log <<-EOF &&\n> +\tOBJID\n> +\t:100644 100644 OBJID OBJID M\tfoo\n> +\tOBJID\n> +\t:100644 100644 OBJID OBJID M\tfoo\n> +\tOBJID\n> +\t:100644 100644 OBJID OBJID M\tunrelated\n> +\tOBJID\n> +\t:000000 100644 OBJID OBJID A\tfoo\n> +\t:000000 100644 OBJID OBJID A\tunrelated\n> +\tEOF\n> +\ttest_must_fail git cherry-pick base..yetanotherpick &&\n> +\ttest_must_fail git cherry-pick --skip &&\n> +\techo d >foo &&\n> +\tgit add foo &&\n> +\tgit cherry-pick --continue &&\n> +\t{\n> +\t\tgit rev-list HEAD |\n> +\t\tgit diff-tree --root --stdin |\n> +\t\tsed \"s/$OID_REGEX/OBJID/g\"\n> +\t} >actual.log &&\n> +\ttest_cmp expect foo &&\n> +\ttest_cmp expect.log actual.log\n> +'\n> +\n> +test_expect_success 'check advice when we move HEAD by committing' '\n> +\tpristine_detach initial &&\n> +\tcat >expect <<-EOF &&\n> +\thint: have you committed already?\n> +\thint: try \"git cherry-pick --continue\"\n> +\terror: there is nothing to skip\n> +\tfatal: cherry-pick failed\n> +\tEOF\n> +\ttest_must_fail git cherry-pick base..yetanotherpick &&\n> +\techo c >foo &&\n> +\tgit commit -a &&\n> +\ttest_path_is_missing .git/CHERRY_PICK_HEAD &&\n> +\ttest_must_fail git cherry-pick --skip 2>advice &&\n> +\ttest_cmp expect advice\n\nWhen you compare a translated string you need to use test_i18ncmp to\navoid test breakages when running under GET_TEXT_POISON. The CI suite\nshows this up [3]. There are instructions for running tests under travis\nin Documentation/SubmittingPatches.txt or Johannes can advise you about\nusing his CI setup with pull requests on gitgitgadget (and maybe git.git?)\n\nBest Wishes\n\nPhillip\n\n\n[3] https://travis-ci.org/phillipwood/git/jobs/545251777\n\n> +'\n> +\n> +test_expect_success 'allow skipping commit but not abort for a new history' '\n> +\tpristine_detach initial &&\n> +\tcat >expect <<-EOF &&\n> +\terror: cannot abort from a branch yet to be born\n> +\tfatal: cherry-pick failed\n> +\tEOF\n> +\tgit checkout --orphan new_disconnected &&\n> +\tgit reset --hard &&\n> +\ttest_must_fail git cherry-pick anotherpick &&\n> +\ttest_must_fail git cherry-pick --abort 2>advice &&\n> +\tgit cherry-pick --skip &&\n> +\ttest_cmp expect advice\n> +'\n> +\n> +test_expect_success 'allow skipping stopped cherry-pick because of untracked file modifications' '\n> +\tpristine_detach initial &&\n> +\tgit rm --cached unrelated &&\n> +\tgit commit -m \"untrack unrelated\" &&\n> +\ttest_must_fail git cherry-pick initial base &&\n> +\ttest_path_is_missing .git/CHERRY_PICK_HEAD &&\n> +\tgit cherry-pick --skip\n> +'\n> +\n>  test_expect_success '--quit does not complain when no cherry-pick is in progress' '\n>  \tpristine_detach initial &&\n>  \tgit cherry-pick --quit\n> \n\n"},{"id":"377181","messageId":"CAN0heSp_XDZTviwGDpOuXhuh+8k-BA7Ld6z9gSHA9My+16BnbQ@mail.gmail.com","threadId":"51269","inReplyTo":"0333fe2f-d68a-4536-c736-ca2a356df34b@gmail.com","subject":"Re: [GSoC][PATCH v3 1/3] sequencer: add advice for revert","fromName":"Martin Ågren","fromEmail":"martin.agren@gmail.com","sentAt":"2019-06-13T19:21:27Z","receivedAt":"2019-06-13T19:21:41Z","isPatch":true,"sender":{"key":"martin.agren@gmail.com","avatar":null},"body":"Hi Rohit,\n\nOn Thu, 13 Jun 2019 at 19:46, Phillip Wood <phillip.wood123@gmail.com> wrote:\n>\n> On 13/06/2019 05:05, Rohit Ashiwal wrote:\n> > -static int create_seq_dir(void)\n> > +static int create_seq_dir(struct repository *r)\n> >  {\n> > -     if (file_exists(git_path_seq_dir())) {\n> > -             error(_(\"a cherry-pick or revert is already in progress\"));\n> > -             advise(_(\"try \\\"git cherry-pick (--continue | --quit | --abort)\\\"\"));\n> > +     enum replay_action action;\n> > +     const char *in_progress_advice;\n> > +     const char *in_progress_error = NULL;\n\nThe assigning vs not assigning is a bit inconsistent, but that's a very\nminor nit, and not why I started replying. Only noticed it just now. :-)\n\n> > +     if (!sequencer_get_last_command(r, &action)) {\n> > +             switch (action) {\n> > +             case REPLAY_REVERT:\n> > +                     in_progress_error = _(\"revert is already in progress\");\n> > +                     in_progress_advice =\n> > +                     _(\"try \\\"git revert (--continue | --abort | --quit)\\\"\");\n> > +                     break;\n> > +             case REPLAY_PICK:\n> > +                     in_progress_error = _(\"cherry-pick is already in progress\");\n> > +                     in_progress_advice =\n> > +                     _(\"try \\\"git cherry-pick (--continue | --abort | --quit)\\\"\");\n> > +                     break;\n> > +             default:\n> > +                     BUG(_(\"the control must not reach here\"));\n>\n> This does not need to be translated as BUG() messages are not really for\n> users. Everything else looks fine to be now\n\nI agree 100% with Phillip, but I'll also note that \"the control must not\nreach here\" doesn't tell me anything that BUG() doesn't already. That\nis, the point of BUG() is to document that, indeed, we shouldn't get\nhere and to alert if we do anyway.\n\nAn obvious alternative would be\n\n        BUG(\"action is neither revert nor pick\");\n\nbut that doesn't say much more than the code already says quite clearly,\nplus it risks getting outdated. I'd probably settle on something like\n\n        BUG(\"unexpected action in create_seq_dir\");\n\nwhich should give us a good clue even if all we have is this message (so\nno file, no line number), but I am sure there are other good choices\nhere. :-)\n\nThanks Rohit for your work on this. I'm impressed by how you've polished\nthis series.\n\n\nMartin\n"},{"id":"377185","messageId":"xmqqtvctuul6.fsf@gitster-ct.c.googlers.com","threadId":"51269","inReplyTo":"xmqqa7elwer9.fsf@gitster-ct.c.googlers.com","subject":"Re: [GSoC][PATCH v3 2/3] cherry-pick/revert: add --skip option","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-06-13T19:57:25Z","receivedAt":"2019-06-13T19:57:31Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n>> -static int rollback_single_pick(struct repository *r)\n>> +static int rollback_single_pick(struct repository *r, unsigned int is_skip)\n>>  {\n>> ...\n>> +\tif (is_null_oid(&head_oid) && !is_skip)\n>>  \t\treturn error(_(\"cannot abort from a branch yet to be born\"));\n>>  \treturn reset_for_rollback(&head_oid);\n>>  }\n>\n> It is unclear *why* the function (and more importantly, its callers)\n> would want to omit two sanity checks when is_skip is in effect.\n> ...\n>> +\tdefault:\n>> +\t\tBUG(\"the control must not reach here\");\n>> +\t}\n>> +\n>> +\tif (rollback_single_pick(r, 1))\n>> +\t\treturn error(_(\"failed to skip the commit\"));\n>\n> And this takes us back to the previous comment.  By passing '1'\n> here, this caller is asking the callee to omit certain sanity check\n> the original version of the callee used to do.  What makes it an\n> appropriate thing to do so here?\n\nI think my earlier comments would lead to a wrong direction, i.e. to\njustify the change made to rollback_single_pick(), so let's step\nback a bit.  Perhaps the change is unjustifiable and that is why I\nhad trouble reading it and trying to make sense out of it.\n\nIs it possible that the new callsite that passes is_skip==1 should\nnot be calling it (while castrating many parts of the callee) in the\nfirst place?  Perhaps it is doing something _different_ from being\ncalled \"rollback single pick\" (or perhaps the name of the function\nis not specific enough to describe what its existing caller, i.e. the\none that passes is_skip==0 after your patch, calls it for)?  IOW,\nwould it lead to a better code structure if you left the original\nrollback_single_pick() helper and its caller alone (perhaps rename\nit to make it clearer what it does), and *add* a new helper around\nthe underlying reset_for_rollback() function and call it from here?\n\nPerhaps it is not rolling back but is skipping, so the new function\nneeds to be called skip_single_pick() or something, and the existing\none is named correctly and there is no need for even renaming?\n"},{"id":"377187","messageId":"xmqqlfy5urox.fsf@gitster-ct.c.googlers.com","threadId":"51269","inReplyTo":"CAN0heSp_XDZTviwGDpOuXhuh+8k-BA7Ld6z9gSHA9My+16BnbQ@mail.gmail.com","subject":"Re: [GSoC][PATCH v3 1/3] sequencer: add advice for revert","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-06-13T20:59:58Z","receivedAt":"2019-06-13T21:00:07Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Martin Ågren <martin.agren@gmail.com> writes:\n\n> ...\n> I agree 100% with Phillip, but I'll also note that \"the control must not\n> reach here\" doesn't tell me anything that BUG() doesn't already. That\n> is,...\n\nThanks, all of you involved in this topic, for excellent mentorship.\n"},{"id":"377209","messageId":"20190614034356.19073-1-rohit.ashiwal265@gmail.com","threadId":"51269","inReplyTo":"0333fe2f-d68a-4536-c736-ca2a356df34b@gmail.com","subject":"Re: [GSoC][PATCH v3 1/3] sequencer: add advice for revert","fromName":"Rohit Ashiwal","fromEmail":"rohit.ashiwal265@gmail.com","sentAt":"2019-06-14T03:43:56Z","receivedAt":"2019-06-14T03:46:10Z","isPatch":true,"sender":{"key":"rohit.ashiwal265@gmail.com","avatar":"https://avatars.githubusercontent.com/u/31043830?v=4"},"body":"Hi Phillip\n\nOn 2019-06-13 17:45 UTC Phillip Wood <phillip.wood123@gmail.com> wrote:\n>\n>> +\t\t\tbreak;\n>> +\t\tdefault:\n>> +\t\t\tBUG(_(\"the control must not reach here\"));\n>\n> This does not need to be translated as BUG() messages are not really for\n> users. Everything else looks fine to be now\n\nI know this is not intended for the users, but seeing a message like\nthis a user might think to report it to the team with the steps for\nreproducing the BUG. Yes, I agree this needs a little bit of re-wording.\n\n> Best Wishes\n> \n> Phillip\n\nThanks\nRohit\n\n"},{"id":"377210","messageId":"20190614034457.19183-1-rohit.ashiwal265@gmail.com","threadId":"51269","inReplyTo":"CAN0heSp_XDZTviwGDpOuXhuh+8k-BA7Ld6z9gSHA9My+16BnbQ@mail.gmail.com","subject":"Re: [GSoC][PATCH v3 1/3] sequencer: add advice for revert","fromName":"Rohit Ashiwal","fromEmail":"rohit.ashiwal265@gmail.com","sentAt":"2019-06-14T03:44:57Z","receivedAt":"2019-06-14T03:47:09Z","isPatch":true,"sender":{"key":"rohit.ashiwal265@gmail.com","avatar":"https://avatars.githubusercontent.com/u/31043830?v=4"},"body":"Hi Martin\n\nOn 2019-06-13 19:21 UTC Martin Ågren <martin.agren@gmail.com> wrote:\n> \n> > > +     const char *in_progress_advice;\n> > > +     const char *in_progress_error = NULL;\n> \n> The assigning vs not assigning is a bit inconsistent, but that's a very\n> minor nit, and not why I started replying. Only noticed it just now. :-)\n\nLet's make both NULL then.\n\n> I agree 100% with Phillip, but I'll also note that \"the control must not\n> reach here\" doesn't tell me anything that BUG() doesn't already. That\n> is, the point of BUG() is to document that, indeed, we shouldn't get\n> here and to alert if we do anyway.\n\nAgreed.\n\n> An obvious alternative would be\n> \n>         BUG(\"action is neither revert nor pick\");\n> \n> but that doesn't say much more than the code already says quite clearly,\n> plus it risks getting outdated. I'd probably settle on something like\n> \n>         BUG(\"unexpected action in create_seq_dir\");\n\nYeah, now that I know more about what BUG is truly intended for, I\nthink you are right here. We should change it.\n\n> which should give us a good clue even if all we have is this message (so\n> no file, no line number), but I am sure there are other good choices\n> here. :-)\n> \n> Thanks Rohit for your work on this. I'm impressed by how you've polished\n> this series.\n\nThank you very much Martin. Appreciations like these help us developers\nkeep going and working even harder.\n\nThanks\nRohit\n\n"},{"id":"377211","messageId":"20190614034554.19364-1-rohit.ashiwal265@gmail.com","threadId":"51269","inReplyTo":"xmqqa7elwer9.fsf@gitster-ct.c.googlers.com","subject":"Re: [GSoC][PATCH v3 2/3] cherry-pick/revert: add --skip option","fromName":"Rohit Ashiwal","fromEmail":"rohit.ashiwal265@gmail.com","sentAt":"2019-06-14T03:45:54Z","receivedAt":"2019-06-14T03:48:06Z","isPatch":true,"sender":{"key":"rohit.ashiwal265@gmail.com","avatar":"https://avatars.githubusercontent.com/u/31043830?v=4"},"body":"Hi Junio\n\nOn 2019-06-13 17:56 UTC Junio C Hamano <gitster@pobox.com> wrote:\n> \n> > +'git cherry-pick' --continue | --skip | --abort | --quit\n> \n> Is this correct, or do we need to enclose these choices inside (),\n> i.e.\n> \n> \t'git cherry-pick' ( --continue | --skip | --abort | --quit )\n> \n> ?\n\nDocumentation of `git rebase` also lists these options without the\n'('s so, I thought to make it similar to that.\n \n> It is unclear *why* the function (and more importantly, its callers)\n> would want to omit two sanity checks when is_skip is in effect.\n> \n> Before this patch introduced such conditional behaviour, the name\n> was descriptive enough for this single-purpose function that is a\n> file-local helper, but it is no longer a case.  The function needs a\n> bit of commentary before it.\n> \n> When &&-chaining error checks that are optional, check the condition\n> that makes the error checks optional first, i.e.\n> \n> \tif (!is_skip &&\n> \t\t!file_exists(...) && !file_exists(...))\n> \t\treturn error(...);\n> \n> [...]\n> \n> no, do not merely give answer to me in your response---write the\n> answer as in-code comment to help future readers of the code).\n> \n> \"Because when we come here, sometimes the XXX_HEAD must exist but\n> some other times XXX_HEAD may not exist, so insisting that either\n> exists would make the function fail\" is *NOT* a good answer, on the\n> other hand.  Somebody must still check that the necessary file\n> exists when it must exist.\n\nYes, I should have added some comments. I'll add them in next revision.\n\nThanks\nRohit\n\n"},{"id":"377212","messageId":"20190614034808.19667-1-rohit.ashiwal265@gmail.com","threadId":"51269","inReplyTo":"xmqqtvctuul6.fsf@gitster-ct.c.googlers.com","subject":"Re: [GSoC][PATCH v3 2/3] cherry-pick/revert: add --skip option","fromName":"Rohit Ashiwal","fromEmail":"rohit.ashiwal265@gmail.com","sentAt":"2019-06-14T03:48:08Z","receivedAt":"2019-06-14T03:50:20Z","isPatch":true,"sender":{"key":"rohit.ashiwal265@gmail.com","avatar":"https://avatars.githubusercontent.com/u/31043830?v=4"},"body":"Hi Junio\n\nOn 2019-06-13 19:57 UTC Junio C Hamano <gitster@pobox.com> wrote:\n> \n> I think my earlier comments would lead to a wrong direction, i.e. to\n> justify the change made to rollback_single_pick(), so let's step\n> back a bit.  Perhaps the change is unjustifiable and that is why I\n> had trouble reading it and trying to make sense out of it.\n> \n> Is it possible that the new callsite that passes is_skip==1 should\n> not be calling it (while castrating many parts of the callee) in the\n> first place?  Perhaps it is doing something _different_ from being\n> called \"rollback single pick\" (or perhaps the name of the function\n> is not specific enough to describe what its existing caller, i.e. the\n> one that passes is_skip==0 after your patch, calls it for)?  IOW,\n> would it lead to a better code structure if you left the original\n> rollback_single_pick() helper and its caller alone (perhaps rename\n> it to make it clearer what it does), and *add* a new helper around\n> the underlying reset_for_rollback() function and call it from here?\n\nThat is why I added a new function, but I was not super sure if it\nwas a good idea to begin with, since it only introduced small changes\nto `reset_for_rollback` (also Phillip[1] discouraged it so, I stopped\nthinking in that direction).\n\n> Perhaps it is not rolling back but is skipping, so the new function\n> needs to be called skip_single_pick() or something, and the existing\n> one is named correctly and there is no need for even renaming?\n\nWe could have a wrapper function to `reset_for_rollback` and better\nrename it to `reset_merge` since we *are* resetting a merge which\ntranslates to rolling-back in reality?\n\nThanks\nRohit\n\n[1]: https://public-inbox.org/git/6d3c1c1e-6140-dd8c-c37f-8c625b04ddc9@gmail.com/\n\n"},{"id":"377240","messageId":"xmqqd0jgupkj.fsf@gitster-ct.c.googlers.com","threadId":"51269","inReplyTo":"20190614034554.19364-1-rohit.ashiwal265@gmail.com","subject":"Re: [GSoC][PATCH v3 2/3] cherry-pick/revert: add --skip option","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-06-14T15:58:04Z","receivedAt":"2019-06-14T15:58:13Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Rohit Ashiwal <rohit.ashiwal265@gmail.com> writes:\n\n>> Is this correct, or do we need to enclose these choices inside (),\n>> i.e.\n>> \n>> \t'git cherry-pick' ( --continue | --skip | --abort | --quit )\n>> \n>> ?\n>\n> Documentation of `git rebase` also lists these options without the\n> '('s so, I thought to make it similar to that.\n\nAs long as you picked the ones that correctly spell their SYNOPSIS,\nit is OK to model yours after them.\n\nSeeing how \"git-am.txt\", \"git-cat-file.txt\", \"git-checkout.txt\", ...\n\"git-var.txt\" etc. all use\n\n\t( choice1 | choice2 | choice3 )\n\nwhen one among the choices MUST be chosen, contrasting with\n\n\t[ choice1 | choice2 | choice3 ]\n\nwhen one can be chosen but not using any is also OK, I am not sure\nif the documentation for \"git rebase\" is done right and should be\nused as a model, though.\n"},{"id":"377311","messageId":"20190616070334.8834-1-rohit.ashiwal265@gmail.com","threadId":"51269","inReplyTo":"xmqqa7elwer9.fsf@gitster-ct.c.googlers.com","subject":"Re: [GSoC][PATCH v3 2/3] cherry-pick/revert: add --skip option","fromName":"Rohit Ashiwal","fromEmail":"rohit.ashiwal265@gmail.com","sentAt":"2019-06-16T07:03:34Z","receivedAt":"2019-06-16T07:05:56Z","isPatch":true,"sender":{"key":"rohit.ashiwal265@gmail.com","avatar":"https://avatars.githubusercontent.com/u/31043830?v=4"},"body":"Hi Junio\n\nI am sorry, I missed to reply to these.\n\nOn 2019-06-13 17:56 UTC Junio C Hamano <gitster@pobox.com> wrote:\n>\n> > +int sequencer_skip(struct repository *r, struct replay_opts *opts)\n> > +{\n> > +\tenum replay_action action = -1;\n> > +\tsequencer_get_last_command(r, &action);\n> > +\n> > +\tswitch (opts->action) {\n> > +\tcase REPLAY_REVERT:\n> > +\t\tif (!file_exists(git_path_revert_head(r))) {\n> > +\t\t\tif (action == REPLAY_REVERT) {\n> > +\t\t\t\tif (!rollback_is_safe())\n> > +\t\t\t\t\tgoto give_advice;\n> > +\t\t\t\telse\n> > +\t\t\t\t\tbreak;\n> > +\t\t\t}\n> > +\t\t\treturn error(_(\"no revert in progress\"));\n> > +\t\t}\n> \n> This part probably deserves a bit of in-code comment.\n> \n>     The Git subcommand (i.e. opts->action) tells us that we are\n>     asked to \"git revert --skip\".  When REVERT_HEAD is not there, we\n>     look at the last command of the sequencer state and make sure it\n>     is 'revert'; all other cases we barf.\n> \n> That much we can read from the code.  But what are \"all other cases\"?\n> Do we cover a single-revert case (i.e. \"git revert <commit>\" got\n> conflict and the user is saying \"git revert --skip\")?\n\nYes, we actually cover the single-revert case. Let's say there were\nsome conflicts then either .git/REVERT_HEAD will exist allowing\n`git revert --skip` it's way or the user has already dealt with it\nand committed his way in which case .git/REVERT_HEAD will be removed\nand reverting ends (as it should).\n\n> Was the user\n> in the middle of \"git rebase -i\" and the last command before we gave\n> the control back was 'pick'?\n\nrebase -i creates different directories so, we are sure that --skip\ndoes not skip in middle of a rebase. Am I right?\n\nHope these answers your questions\n-- Rohit\n\n"},{"id":"377312","messageId":"20190616082040.9440-1-rohit.ashiwal265@gmail.com","threadId":"51269","inReplyTo":"20190608191958.4593-1-rohit.ashiwal265@gmail.com","subject":"[GSoC][PATCH v4 0/4] [GSoC][PATCH 0/3] Teach cherry-pick/revert to skip commits","fromName":"Rohit Ashiwal","fromEmail":"rohit.ashiwal265@gmail.com","sentAt":"2019-06-16T08:20:36Z","receivedAt":"2019-06-16T08:23:32Z","isPatch":true,"sender":{"key":"rohit.ashiwal265@gmail.com","avatar":"https://avatars.githubusercontent.com/u/31043830?v=4"},"body":"Yet another iteration of my patch. We have changed the series a little bit. We\nnow have a commit that rename `reset_for_rollback` to `reset_merge`. A lot of\nnit-picks were handled in this revision.\n\nThanks\nRohit\n\nRohit Ashiwal (4):\n  sequencer: add advice for revert\n  sequencer: rename reset_for_rollback to reset_merge\n  cherry-pick/revert: add --skip option\n  cherry-pick/revert: advise using --skip\n\n Documentation/git-cherry-pick.txt |   4 +-\n Documentation/git-revert.txt      |   4 +-\n Documentation/sequencer.txt       |   4 +\n builtin/commit.c                  |  13 +--\n builtin/revert.c                  |   5 ++\n sequencer.c                       | 139 ++++++++++++++++++++++++++----\n sequencer.h                       |   1 +\n t/t3510-cherry-pick-sequence.sh   | 122 ++++++++++++++++++++++++++\n 8 files changed, 266 insertions(+), 26 deletions(-)\n\n-- \n2.21.0\n\n"},{"id":"377313","messageId":"20190616082040.9440-2-rohit.ashiwal265@gmail.com","threadId":"51269","inReplyTo":"20190616082040.9440-1-rohit.ashiwal265@gmail.com","subject":"[GSoC][PATCH v4 1/4] sequencer: add advice for revert","fromName":"Rohit Ashiwal","fromEmail":"rohit.ashiwal265@gmail.com","sentAt":"2019-06-16T08:20:37Z","receivedAt":"2019-06-16T08:23:37Z","isPatch":true,"sender":{"key":"rohit.ashiwal265@gmail.com","avatar":"https://avatars.githubusercontent.com/u/31043830?v=4"},"body":"In the case of merge conflicts, while performing a revert, we are\ncurrently advised to use `git cherry-pick --<sequencer-options>`\nof which --continue is incompatible for continuing the revert.\nIntroduce a separate advice message for `git revert`. Also change\nthe signature of `create_seq_dir` to handle which advice to display\nselectively.\n\nSigned-off-by: Rohit Ashiwal <rohit.ashiwal265@gmail.com>\n---\nchanges:\n    - change BUG()'s message under create_seq_dir\n\n sequencer.c | 34 ++++++++++++++++++++++++++++------\n 1 file changed, 28 insertions(+), 6 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex f88a97fb10..d80e1c3fbb 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -2650,15 +2650,37 @@ static int walk_revs_populate_todo(struct todo_list *todo_list,\n \treturn 0;\n }\n \n-static int create_seq_dir(void)\n+static int create_seq_dir(struct repository *r)\n {\n-\tif (file_exists(git_path_seq_dir())) {\n-\t\terror(_(\"a cherry-pick or revert is already in progress\"));\n-\t\tadvise(_(\"try \\\"git cherry-pick (--continue | --quit | --abort)\\\"\"));\n+\tenum replay_action action;\n+\tconst char *in_progress_error = NULL;\n+\tconst char *in_progress_advice = NULL;\n+\n+\tif (!sequencer_get_last_command(r, &action)) {\n+\t\tswitch (action) {\n+\t\tcase REPLAY_REVERT:\n+\t\t\tin_progress_error = _(\"revert is already in progress\");\n+\t\t\tin_progress_advice =\n+\t\t\t_(\"try \\\"git revert (--continue | --abort | --quit)\\\"\");\n+\t\t\tbreak;\n+\t\tcase REPLAY_PICK:\n+\t\t\tin_progress_error = _(\"cherry-pick is already in progress\");\n+\t\t\tin_progress_advice =\n+\t\t\t_(\"try \\\"git cherry-pick (--continue | --abort | --quit)\\\"\");\n+\t\t\tbreak;\n+\t\tdefault:\n+\t\t\tBUG(_(\"unexpected action in create_seq_dir\"));\n+\t\t}\n+\t}\n+\tif (in_progress_error) {\n+\t\terror(\"%s\", in_progress_error);\n+\t\tadvise(\"%s\", in_progress_advice);\n \t\treturn -1;\n-\t} else if (mkdir(git_path_seq_dir(), 0777) < 0)\n+\t}\n+\tif (mkdir(git_path_seq_dir(), 0777) < 0)\n \t\treturn error_errno(_(\"could not create sequencer directory '%s'\"),\n \t\t\t\t   git_path_seq_dir());\n+\n \treturn 0;\n }\n \n@@ -4237,7 +4259,7 @@ int sequencer_pick_revisions(struct repository *r,\n \t */\n \n \tif (walk_revs_populate_todo(&todo_list, opts) ||\n-\t\t\tcreate_seq_dir() < 0)\n+\t\t\tcreate_seq_dir(r) < 0)\n \t\treturn -1;\n \tif (get_oid(\"HEAD\", &oid) && (opts->action == REPLAY_REVERT))\n \t\treturn error(_(\"can't revert as initial commit\"));\n-- \n2.21.0\n\n"},{"id":"377314","messageId":"20190616082040.9440-3-rohit.ashiwal265@gmail.com","threadId":"51269","inReplyTo":"20190616082040.9440-1-rohit.ashiwal265@gmail.com","subject":"[GSoC][PATCH v4 2/4] sequencer: rename reset_for_rollback to reset_merge","fromName":"Rohit Ashiwal","fromEmail":"rohit.ashiwal265@gmail.com","sentAt":"2019-06-16T08:20:38Z","receivedAt":"2019-06-16T08:23:41Z","isPatch":true,"sender":{"key":"rohit.ashiwal265@gmail.com","avatar":"https://avatars.githubusercontent.com/u/31043830?v=4"},"body":"We are on a path to teach cherry-pick/revert how to skip commits. To\nachieve this, we could really make use of existing functions.\nreset_for_rollback is one such function, but the name does not\nintuitively suggest to use it to reset a merge, which it was born to\nperform, see 539047c (\"revert: introduce --abort to cancel a failed\ncherry-pick\", 2011-11-23). Change the name to reset_merge to make\nit more intuitive.\n\nSigned-off-by: Rohit Ashiwal <rohit.ashiwal265@gmail.com>\n---\n sequencer.c | 6 +++---\n 1 file changed, 3 insertions(+), 3 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex d80e1c3fbb..408643f88a 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -2731,7 +2731,7 @@ static int rollback_is_safe(void)\n \treturn oideq(&actual_head, &expected_head);\n }\n \n-static int reset_for_rollback(const struct object_id *oid)\n+static int reset_merge(const struct object_id *oid)\n {\n \tconst char *argv[4];\t/* reset --merge <arg> + NULL */\n \n@@ -2753,7 +2753,7 @@ static int rollback_single_pick(struct repository *r)\n \t\treturn error(_(\"cannot resolve HEAD\"));\n \tif (is_null_oid(&head_oid))\n \t\treturn error(_(\"cannot abort from a branch yet to be born\"));\n-\treturn reset_for_rollback(&head_oid);\n+\treturn reset_merge(&head_oid);\n }\n \n int sequencer_rollback(struct repository *r, struct replay_opts *opts)\n@@ -2796,7 +2796,7 @@ int sequencer_rollback(struct repository *r, struct replay_opts *opts)\n \t\twarning(_(\"You seem to have moved HEAD. \"\n \t\t\t  \"Not rewinding, check your HEAD!\"));\n \t} else\n-\tif (reset_for_rollback(&oid))\n+\tif (reset_merge(&oid))\n \t\tgoto fail;\n \tstrbuf_release(&buf);\n \treturn sequencer_remove_state(opts);\n-- \n2.21.0\n\n"},{"id":"377315","messageId":"20190616082040.9440-4-rohit.ashiwal265@gmail.com","threadId":"51269","inReplyTo":"20190616082040.9440-1-rohit.ashiwal265@gmail.com","subject":"[GSoC][PATCH v4 3/4] cherry-pick/revert: add --skip option","fromName":"Rohit Ashiwal","fromEmail":"rohit.ashiwal265@gmail.com","sentAt":"2019-06-16T08:20:39Z","receivedAt":"2019-06-16T08:23:47Z","isPatch":true,"sender":{"key":"rohit.ashiwal265@gmail.com","avatar":"https://avatars.githubusercontent.com/u/31043830?v=4"},"body":"git am or rebase have a --skip flag to skip the current commit if the\nuser wishes to do so. During a cherry-pick or revert a user could\nlikewise skip a commit, but needs to use 'git reset' (or in the case\nof conflicts 'git reset --merge'), followed by 'git (cherry-pick |\nrevert) --continue' to skip the commit. This is more annoying and\nsometimes confusing on the users' part. Add a `--skip` option to make\nskipping commits easier for the user and to make the commands more\nconsistent.\n\nIn the next commit, we will change the advice messages and some tests\nhence finishing the process of teaching revert and cherry-pick\n\"how to skip commits\".\n\nSigned-off-by: Rohit Ashiwal <rohit.ashiwal265@gmail.com>\n---\nchanges:\n    - Introduce '('s around documentation/help\n    - Introduce a wrapper function skip_single_pick to reset_merge\n    - Add comments to sequencer_skip\n    - Change tests to use test_i18ncmp instead of test_cmp to not fail under\n      GETTEXT_POISON\n\n Documentation/git-cherry-pick.txt |   4 +-\n Documentation/git-revert.txt      |   4 +-\n Documentation/sequencer.txt       |   4 ++\n builtin/revert.c                  |   5 ++\n sequencer.c                       |  94 +++++++++++++++++++++++++--\n sequencer.h                       |   1 +\n t/t3510-cherry-pick-sequence.sh   | 102 ++++++++++++++++++++++++++++++\n 7 files changed, 202 insertions(+), 12 deletions(-)\n\ndiff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt\nindex 754b16ce0c..83ce51aedf 100644\n--- a/Documentation/git-cherry-pick.txt\n+++ b/Documentation/git-cherry-pick.txt\n@@ -10,9 +10,7 @@ SYNOPSIS\n [verse]\n 'git cherry-pick' [--edit] [-n] [-m parent-number] [-s] [-x] [--ff]\n \t\t  [-S[<keyid>]] <commit>...\n-'git cherry-pick' --continue\n-'git cherry-pick' --quit\n-'git cherry-pick' --abort\n+'git cherry-pick' (--continue | --skip | --abort | --quit)\n \n DESCRIPTION\n -----------\ndiff --git a/Documentation/git-revert.txt b/Documentation/git-revert.txt\nindex 0c82ca5bc0..665e065ee3 100644\n--- a/Documentation/git-revert.txt\n+++ b/Documentation/git-revert.txt\n@@ -9,9 +9,7 @@ SYNOPSIS\n --------\n [verse]\n 'git revert' [--[no-]edit] [-n] [-m parent-number] [-s] [-S[<keyid>]] <commit>...\n-'git revert' --continue\n-'git revert' --quit\n-'git revert' --abort\n+'git revert' (--continue | --skip | --abort | --quit)\n \n DESCRIPTION\n -----------\ndiff --git a/Documentation/sequencer.txt b/Documentation/sequencer.txt\nindex 5a57c4a407..3bceb56474 100644\n--- a/Documentation/sequencer.txt\n+++ b/Documentation/sequencer.txt\n@@ -3,6 +3,10 @@\n \t`.git/sequencer`.  Can be used to continue after resolving\n \tconflicts in a failed cherry-pick or revert.\n \n+--skip::\n+\tSkip the current commit and continue with the rest of the\n+\tsequence.\n+\n --quit::\n \tForget about the current operation in progress.  Can be used\n \tto clear the sequencer state after a failed cherry-pick or\ndiff --git a/builtin/revert.c b/builtin/revert.c\nindex d4dcedbdc6..5dc5891ea2 100644\n--- a/builtin/revert.c\n+++ b/builtin/revert.c\n@@ -102,6 +102,7 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)\n \t\tOPT_CMDMODE(0, \"quit\", &cmd, N_(\"end revert or cherry-pick sequence\"), 'q'),\n \t\tOPT_CMDMODE(0, \"continue\", &cmd, N_(\"resume revert or cherry-pick sequence\"), 'c'),\n \t\tOPT_CMDMODE(0, \"abort\", &cmd, N_(\"cancel revert or cherry-pick sequence\"), 'a'),\n+\t\tOPT_CMDMODE(0, \"skip\", &cmd, N_(\"skip current commit and continue\"), 's'),\n \t\tOPT_CLEANUP(&cleanup_arg),\n \t\tOPT_BOOL('n', \"no-commit\", &opts->no_commit, N_(\"don't automatically commit\")),\n \t\tOPT_BOOL('e', \"edit\", &opts->edit, N_(\"edit the commit message\")),\n@@ -151,6 +152,8 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)\n \t\t\tthis_operation = \"--quit\";\n \t\telse if (cmd == 'c')\n \t\t\tthis_operation = \"--continue\";\n+\t\telse if (cmd == 's')\n+\t\t\tthis_operation = \"--skip\";\n \t\telse {\n \t\t\tassert(cmd == 'a');\n \t\t\tthis_operation = \"--abort\";\n@@ -210,6 +213,8 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)\n \t\treturn sequencer_continue(the_repository, opts);\n \tif (cmd == 'a')\n \t\treturn sequencer_rollback(the_repository, opts);\n+\tif (cmd == 's')\n+\t\treturn sequencer_skip(the_repository, opts);\n \treturn sequencer_pick_revisions(the_repository, opts);\n }\n \ndiff --git a/sequencer.c b/sequencer.c\nindex 408643f88a..95fa19a118 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -2733,13 +2733,18 @@ static int rollback_is_safe(void)\n \n static int reset_merge(const struct object_id *oid)\n {\n-\tconst char *argv[4];\t/* reset --merge <arg> + NULL */\n+\tint ret;\n+\tstruct argv_array argv = ARGV_ARRAY_INIT;\n \n-\targv[0] = \"reset\";\n-\targv[1] = \"--merge\";\n-\targv[2] = oid_to_hex(oid);\n-\targv[3] = NULL;\n-\treturn run_command_v_opt(argv, RUN_GIT_CMD);\n+\targv_array_pushl(&argv, \"reset\", \"--merge\", NULL);\n+\n+\tif (!is_null_oid(oid))\n+\t\targv_array_push(&argv, oid_to_hex(oid));\n+\n+\tret = run_command_v_opt(argv.argv, RUN_GIT_CMD);\n+\targv_array_clear(&argv);\n+\n+\treturn ret;\n }\n \n static int rollback_single_pick(struct repository *r)\n@@ -2756,6 +2761,15 @@ static int rollback_single_pick(struct repository *r)\n \treturn reset_merge(&head_oid);\n }\n \n+static int skip_single_pick(void)\n+{\n+\tstruct object_id head;\n+\n+\tif (read_ref_full(\"HEAD\", 0, &head, NULL))\n+\t\treturn error(_(\"cannot resolve HEAD\"));\n+\treturn reset_merge(&head);\n+}\n+\n int sequencer_rollback(struct repository *r, struct replay_opts *opts)\n {\n \tFILE *f;\n@@ -2805,6 +2819,74 @@ int sequencer_rollback(struct repository *r, struct replay_opts *opts)\n \treturn -1;\n }\n \n+int sequencer_skip(struct repository *r, struct replay_opts *opts)\n+{\n+\tenum replay_action action = -1;\n+\tsequencer_get_last_command(r, &action);\n+\n+\t/*\n+\t * opts->action tells us which subcommand requested to skip\n+\t * the commit.\n+\t */\n+\tswitch (opts->action) {\n+\tcase REPLAY_REVERT:\n+\t\t/*\n+\t\t * If .git/REVERT_HEAD exists then we are sure that we are in\n+\t\t * the middle of a revert and we allow to skip the commit.\n+\t\t */\n+\t\tif (!file_exists(git_path_revert_head(r))) {\n+\t\t\t/*\n+\t\t\t * Check if the last instruction executed was related to\n+\t\t\t * revert. If so, we are sure that a revert is in progress.\n+\t\t\t *\n+\t\t\t * NB: single commit revert is also counted in this\n+\t\t\t * definition of \"progress\" (and was dealt with in the\n+\t\t\t * previous check).\n+\t\t\t */\n+\t\t\tif (action == REPLAY_REVERT) {\n+\t\t\t\t/*\n+\t\t\t\t * Check if the user has moved the HEAD, i.e.,\n+\t\t\t\t * already committed. In this case, we would like\n+\t\t\t\t * to advise instead of skipping.\n+\t\t\t\t */\n+\t\t\t\tif (!rollback_is_safe())\n+\t\t\t\t\tgoto give_advice;\n+\t\t\t\telse\n+\t\t\t\t\t/* skip commit :) */\n+\t\t\t\t\tbreak;\n+\t\t\t}\n+\t\t\treturn error(_(\"no revert in progress\"));\n+\t\t}\n+\t\tbreak;\n+\tcase REPLAY_PICK:\n+\t\tif (!file_exists(git_path_cherry_pick_head(r))) {\n+\t\t\tif (action == REPLAY_PICK) {\n+\t\t\t\tif (!rollback_is_safe())\n+\t\t\t\t\tgoto give_advice;\n+\t\t\t\telse\n+\t\t\t\t\tbreak;\n+\t\t\t}\n+\t\t\treturn error(_(\"no cherry-pick in progress\"));\n+\t\t}\n+\t\tbreak;\n+\tdefault:\n+\t\tBUG(\"unexpected action in sequencer_skip\");\n+\t}\n+\n+\tif (skip_single_pick())\n+\t\treturn error(_(\"failed to skip the commit\"));\n+\tif (!is_directory(git_path_seq_dir()))\n+\t\treturn 0;\n+\n+\treturn sequencer_continue(r, opts);\n+\n+give_advice:\n+\tadvise(_(\"have you committed already?\\n\"\n+\t\t \"try \\\"git %s --continue\\\"\"),\n+\t\t action == REPLAY_REVERT ? \"revert\" : \"cherry-pick\");\n+\treturn error(_(\"there is nothing to skip\"));\n+}\n+\n static int save_todo(struct todo_list *todo_list, struct replay_opts *opts)\n {\n \tstruct lock_file todo_lock = LOCK_INIT;\ndiff --git a/sequencer.h b/sequencer.h\nindex 0c494b83d4..731b9853eb 100644\n--- a/sequencer.h\n+++ b/sequencer.h\n@@ -129,6 +129,7 @@ int sequencer_pick_revisions(struct repository *repo,\n \t\t\t     struct replay_opts *opts);\n int sequencer_continue(struct repository *repo, struct replay_opts *opts);\n int sequencer_rollback(struct repository *repo, struct replay_opts *opts);\n+int sequencer_skip(struct repository *repo, struct replay_opts *opts);\n int sequencer_remove_state(struct replay_opts *opts);\n \n #define TODO_LIST_KEEP_EMPTY (1U << 0)\ndiff --git a/t/t3510-cherry-pick-sequence.sh b/t/t3510-cherry-pick-sequence.sh\nindex 941d5026da..dc0ac8343c 100755\n--- a/t/t3510-cherry-pick-sequence.sh\n+++ b/t/t3510-cherry-pick-sequence.sh\n@@ -93,6 +93,108 @@ test_expect_success 'cherry-pick cleans up sequencer state upon success' '\n \ttest_path_is_missing .git/sequencer\n '\n \n+test_expect_success 'cherry-pick --skip requires cherry-pick in progress' '\n+\tpristine_detach initial &&\n+\ttest_must_fail git cherry-pick --skip\n+'\n+\n+test_expect_success 'revert --skip requires revert in progress' '\n+\tpristine_detach initial &&\n+\ttest_must_fail git revert --skip\n+'\n+\n+test_expect_success 'cherry-pick --skip to skip commit' '\n+\tpristine_detach initial &&\n+\ttest_must_fail git cherry-pick anotherpick &&\n+\ttest_must_fail git revert --skip &&\n+\tgit cherry-pick --skip &&\n+\ttest_cmp_rev initial HEAD &&\n+\ttest_path_is_missing .git/CHERRY_PICK_HEAD\n+'\n+\n+test_expect_success 'revert --skip to skip commit' '\n+\tpristine_detach anotherpick &&\n+\ttest_must_fail git revert anotherpick~1 &&\n+\ttest_must_fail git cherry-pick --skip &&\n+\tgit revert --skip &&\n+\ttest_cmp_rev anotherpick HEAD\n+'\n+\n+test_expect_success 'skip \"empty\" commit' '\n+\tpristine_detach picked &&\n+\ttest_commit dummy foo d &&\n+\ttest_must_fail git cherry-pick anotherpick &&\n+\tgit cherry-pick --skip &&\n+\ttest_cmp_rev dummy HEAD\n+'\n+\n+test_expect_success 'skip a commit and check if rest of sequence is correct' '\n+\tpristine_detach initial &&\n+\techo e >expect &&\n+\tcat >expect.log <<-EOF &&\n+\tOBJID\n+\t:100644 100644 OBJID OBJID M\tfoo\n+\tOBJID\n+\t:100644 100644 OBJID OBJID M\tfoo\n+\tOBJID\n+\t:100644 100644 OBJID OBJID M\tunrelated\n+\tOBJID\n+\t:000000 100644 OBJID OBJID A\tfoo\n+\t:000000 100644 OBJID OBJID A\tunrelated\n+\tEOF\n+\ttest_must_fail git cherry-pick base..yetanotherpick &&\n+\ttest_must_fail git cherry-pick --skip &&\n+\techo d >foo &&\n+\tgit add foo &&\n+\tgit cherry-pick --continue &&\n+\t{\n+\t\tgit rev-list HEAD |\n+\t\tgit diff-tree --root --stdin |\n+\t\tsed \"s/$OID_REGEX/OBJID/g\"\n+\t} >actual.log &&\n+\ttest_cmp expect foo &&\n+\ttest_cmp expect.log actual.log\n+'\n+\n+test_expect_success 'check advice when we move HEAD by committing' '\n+\tpristine_detach initial &&\n+\tcat >expect <<-EOF &&\n+\thint: have you committed already?\n+\thint: try \"git cherry-pick --continue\"\n+\terror: there is nothing to skip\n+\tfatal: cherry-pick failed\n+\tEOF\n+\ttest_must_fail git cherry-pick base..yetanotherpick &&\n+\techo c >foo &&\n+\tgit commit -a &&\n+\ttest_path_is_missing .git/CHERRY_PICK_HEAD &&\n+\ttest_must_fail git cherry-pick --skip 2>advice &&\n+\ttest_i18ncmp expect advice\n+'\n+\n+test_expect_success 'allow skipping commit but not abort for a new history' '\n+\tpristine_detach initial &&\n+\tcat >expect <<-EOF &&\n+\terror: cannot abort from a branch yet to be born\n+\tfatal: cherry-pick failed\n+\tEOF\n+\tgit checkout --orphan new_disconnected &&\n+\tgit reset --hard &&\n+\ttest_must_fail git cherry-pick anotherpick &&\n+\ttest_must_fail git cherry-pick --abort 2>advice &&\n+\tgit cherry-pick --skip &&\n+\ttest_i18ncmp expect advice\n+'\n+\n+test_expect_success 'allow skipping stopped cherry-pick because of untracked file modifications' '\n+\tpristine_detach initial &&\n+\tgit rm --cached unrelated &&\n+\tgit commit -m \"untrack unrelated\" &&\n+\ttest_must_fail git cherry-pick initial base &&\n+\ttest_path_is_missing .git/CHERRY_PICK_HEAD &&\n+\tgit cherry-pick --skip\n+'\n+\n test_expect_success '--quit does not complain when no cherry-pick is in progress' '\n \tpristine_detach initial &&\n \tgit cherry-pick --quit\n-- \n2.21.0\n\n"},{"id":"377316","messageId":"20190616082040.9440-5-rohit.ashiwal265@gmail.com","threadId":"51269","inReplyTo":"20190616082040.9440-1-rohit.ashiwal265@gmail.com","subject":"[GSoC][PATCH v4 4/4] cherry-pick/revert: advise using --skip","fromName":"Rohit Ashiwal","fromEmail":"rohit.ashiwal265@gmail.com","sentAt":"2019-06-16T08:20:40Z","receivedAt":"2019-06-16T08:23:51Z","isPatch":true,"sender":{"key":"rohit.ashiwal265@gmail.com","avatar":"https://avatars.githubusercontent.com/u/31043830?v=4"},"body":"The previous commit introduced a --skip flag for cherry-pick and\nrevert. Update the advice messages, to tell users about this less\ncumbersome way of skipping commits. Also add tests to ensure\neverything is working fine.\n\nSigned-off-by: Rohit Ashiwal <rohit.ashiwal265@gmail.com>\n---\nchanges:\n    - Use test_i18ncmp instead of tmp_cmp\n\n builtin/commit.c                | 13 ++++++++-----\n sequencer.c                     | 11 ++++++++---\n t/t3510-cherry-pick-sequence.sh | 20 ++++++++++++++++++++\n 3 files changed, 36 insertions(+), 8 deletions(-)\n\ndiff --git a/builtin/commit.c b/builtin/commit.c\nindex 1c9e8e2228..1f47c51bdc 100644\n--- a/builtin/commit.c\n+++ b/builtin/commit.c\n@@ -60,15 +60,18 @@ N_(\"The previous cherry-pick is now empty, possibly due to conflict resolution.\\\n \"\\n\");\n \n static const char empty_cherry_pick_advice_single[] =\n-N_(\"Otherwise, please use 'git reset'\\n\");\n+N_(\"Otherwise, please use 'git cherry-pick --skip'\\n\");\n \n static const char empty_cherry_pick_advice_multi[] =\n-N_(\"If you wish to skip this commit, use:\\n\"\n+N_(\"and then use:\\n\"\n \"\\n\"\n-\"    git reset\\n\"\n+\"    git cherry-pick --continue\\n\"\n \"\\n\"\n-\"Then \\\"git cherry-pick --continue\\\" will resume cherry-picking\\n\"\n-\"the remaining commits.\\n\");\n+\"to resume cherry-picking the remaining commits.\\n\"\n+\"If you wish to skip this commit, use:\\n\"\n+\"\\n\"\n+\"    git cherry-pick --skip\\n\"\n+\"\\n\");\n \n static const char *color_status_slots[] = {\n \t[WT_STATUS_HEADER]\t  = \"header\",\ndiff --git a/sequencer.c b/sequencer.c\nindex 95fa19a118..6e8afe8f22 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -2655,18 +2655,20 @@ static int create_seq_dir(struct repository *r)\n \tenum replay_action action;\n \tconst char *in_progress_error = NULL;\n \tconst char *in_progress_advice = NULL;\n+\tunsigned int advise_skip = file_exists(git_path_revert_head(r)) ||\n+\t\t\t\tfile_exists(git_path_cherry_pick_head(r));\n \n \tif (!sequencer_get_last_command(r, &action)) {\n \t\tswitch (action) {\n \t\tcase REPLAY_REVERT:\n \t\t\tin_progress_error = _(\"revert is already in progress\");\n \t\t\tin_progress_advice =\n-\t\t\t_(\"try \\\"git revert (--continue | --abort | --quit)\\\"\");\n+\t\t\t_(\"try \\\"git revert (--continue | %s--abort | --quit)\\\"\");\n \t\t\tbreak;\n \t\tcase REPLAY_PICK:\n \t\t\tin_progress_error = _(\"cherry-pick is already in progress\");\n \t\t\tin_progress_advice =\n-\t\t\t_(\"try \\\"git cherry-pick (--continue | --abort | --quit)\\\"\");\n+\t\t\t_(\"try \\\"git cherry-pick (--continue | %s--abort | --quit)\\\"\");\n \t\t\tbreak;\n \t\tdefault:\n \t\t\tBUG(_(\"unexpected action in create_seq_dir\"));\n@@ -2674,7 +2676,10 @@ static int create_seq_dir(struct repository *r)\n \t}\n \tif (in_progress_error) {\n \t\terror(\"%s\", in_progress_error);\n-\t\tadvise(\"%s\", in_progress_advice);\n+\t\tif (advise_skip)\n+\t\t\tadvise(in_progress_advice, \"--skip | \");\n+\t\telse\n+\t\t\tadvise(in_progress_advice, \"\");\n \t\treturn -1;\n \t}\n \tif (mkdir(git_path_seq_dir(), 0777) < 0)\ndiff --git a/t/t3510-cherry-pick-sequence.sh b/t/t3510-cherry-pick-sequence.sh\nindex dc0ac8343c..0e8adc95fc 100755\n--- a/t/t3510-cherry-pick-sequence.sh\n+++ b/t/t3510-cherry-pick-sequence.sh\n@@ -172,6 +172,26 @@ test_expect_success 'check advice when we move HEAD by committing' '\n \ttest_i18ncmp expect advice\n '\n \n+test_expect_success 'selectively advise --skip while launching another sequence' '\n+\tpristine_detach initial &&\n+\tcat >expect <<-EOF &&\n+\terror: cherry-pick is already in progress\n+\thint: try \"git cherry-pick (--continue | --skip | --abort | --quit)\"\n+\tfatal: cherry-pick failed\n+\tEOF\n+\ttest_must_fail git cherry-pick picked..yetanotherpick &&\n+\ttest_must_fail git cherry-pick picked..yetanotherpick 2>advice &&\n+\ttest_i18ncmp expect advice &&\n+\tcat >expect <<-EOF &&\n+\terror: cherry-pick is already in progress\n+\thint: try \"git cherry-pick (--continue | --abort | --quit)\"\n+\tfatal: cherry-pick failed\n+\tEOF\n+\tgit reset --merge &&\n+\ttest_must_fail git cherry-pick picked..yetanotherpick 2>advice &&\n+\ttest_i18ncmp expect advice\n+'\n+\n test_expect_success 'allow skipping commit but not abort for a new history' '\n \tpristine_detach initial &&\n \tcat >expect <<-EOF &&\n-- \n2.21.0\n\n"},{"id":"377346","messageId":"20190617055142.GD11340@hank.intra.tgummerer.com","threadId":"51269","inReplyTo":"20190616082040.9440-2-rohit.ashiwal265@gmail.com","subject":"Re: [GSoC][PATCH v4 1/4] sequencer: add advice for revert","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2019-06-17T05:51:42Z","receivedAt":"2019-06-17T05:51:51Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"On 06/16, Rohit Ashiwal wrote:\n> In the case of merge conflicts, while performing a revert, we are\n> currently advised to use `git cherry-pick --<sequencer-options>`\n> of which --continue is incompatible for continuing the revert.\n> Introduce a separate advice message for `git revert`. Also change\n> the signature of `create_seq_dir` to handle which advice to display\n> selectively.\n> \n> Signed-off-by: Rohit Ashiwal <rohit.ashiwal265@gmail.com>\n> ---\n> changes:\n>     - change BUG()'s message under create_seq_dir\n> \n>  sequencer.c | 34 ++++++++++++++++++++++++++++------\n>  1 file changed, 28 insertions(+), 6 deletions(-)\n> \n> diff --git a/sequencer.c b/sequencer.c\n> index f88a97fb10..d80e1c3fbb 100644\n> --- a/sequencer.c\n> +++ b/sequencer.c\n> @@ -2650,15 +2650,37 @@ static int walk_revs_populate_todo(struct todo_list *todo_list,\n>  \treturn 0;\n>  }\n>  \n> -static int create_seq_dir(void)\n> +static int create_seq_dir(struct repository *r)\n>  {\n> -\tif (file_exists(git_path_seq_dir())) {\n> -\t\terror(_(\"a cherry-pick or revert is already in progress\"));\n> -\t\tadvise(_(\"try \\\"git cherry-pick (--continue | --quit | --abort)\\\"\"));\n> +\tenum replay_action action;\n> +\tconst char *in_progress_error = NULL;\n> +\tconst char *in_progress_advice = NULL;\n> +\n> +\tif (!sequencer_get_last_command(r, &action)) {\n> +\t\tswitch (action) {\n> +\t\tcase REPLAY_REVERT:\n> +\t\t\tin_progress_error = _(\"revert is already in progress\");\n> +\t\t\tin_progress_advice =\n> +\t\t\t_(\"try \\\"git revert (--continue | --abort | --quit)\\\"\");\n> +\t\t\tbreak;\n> +\t\tcase REPLAY_PICK:\n> +\t\t\tin_progress_error = _(\"cherry-pick is already in progress\");\n> +\t\t\tin_progress_advice =\n> +\t\t\t_(\"try \\\"git cherry-pick (--continue | --abort | --quit)\\\"\");\n> +\t\t\tbreak;\n> +\t\tdefault:\n> +\t\t\tBUG(_(\"unexpected action in create_seq_dir\"));\n\nAs Phillip mentioned in the previous round, this doesn't need to be\ntranslated.  I'd go one step further and say this should not be\ntranslated.  Translating it just adds extra work for translators for a\nmessage that the user will (hopefully) never see.\n\nIn fact if we look through the rest of the codebase, BUG() messages\nare never translated anywhere, and neither is the one in 3/4.\n\n> +\t\t}\n> +\t}\n> +\tif (in_progress_error) {\n> +\t\terror(\"%s\", in_progress_error);\n> +\t\tadvise(\"%s\", in_progress_advice);\n>  \t\treturn -1;\n> -\t} else if (mkdir(git_path_seq_dir(), 0777) < 0)\n> +\t}\n> +\tif (mkdir(git_path_seq_dir(), 0777) < 0)\n>  \t\treturn error_errno(_(\"could not create sequencer directory '%s'\"),\n>  \t\t\t\t   git_path_seq_dir());\n> +\n>  \treturn 0;\n>  }\n>  \n> @@ -4237,7 +4259,7 @@ int sequencer_pick_revisions(struct repository *r,\n>  \t */\n>  \n>  \tif (walk_revs_populate_todo(&todo_list, opts) ||\n> -\t\t\tcreate_seq_dir() < 0)\n> +\t\t\tcreate_seq_dir(r) < 0)\n>  \t\treturn -1;\n>  \tif (get_oid(\"HEAD\", &oid) && (opts->action == REPLAY_REVERT))\n>  \t\treturn error(_(\"can't revert as initial commit\"));\n> -- \n> 2.21.0\n> \n"},{"id":"377349","messageId":"20190617083004.GA15217@hank.intra.tgummerer.com","threadId":"51269","inReplyTo":"20190616082040.9440-4-rohit.ashiwal265@gmail.com","subject":"Re: [GSoC][PATCH v4 3/4] cherry-pick/revert: add --skip option","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2019-06-17T08:30:04Z","receivedAt":"2019-06-17T08:30:23Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"On 06/16, Rohit Ashiwal wrote:\n> git am or rebase have a --skip flag to skip the current commit if the\n> user wishes to do so. During a cherry-pick or revert a user could\n> likewise skip a commit, but needs to use 'git reset' (or in the case\n> of conflicts 'git reset --merge'), followed by 'git (cherry-pick |\n> revert) --continue' to skip the commit. This is more annoying and\n> sometimes confusing on the users' part. Add a `--skip` option to make\n> skipping commits easier for the user and to make the commands more\n> consistent.\n> \n> In the next commit, we will change the advice messages and some tests\n> hence finishing the process of teaching revert and cherry-pick\n> \"how to skip commits\".\n\nChanging the advice messages and some tests sounds to me like we're\nnot changing the tests here even though we should.  I know that is not\nthe case, and in fact we're only adding another test for something\nthat we're introducing in the next patch.\n\nI think this whole paragraph could be dropped, but at least the \"and\nsome tests\" part should be, as it's slightly misleading imo.\n\n> Signed-off-by: Rohit Ashiwal <rohit.ashiwal265@gmail.com>\n> ---\n> changes:\n>     - Introduce '('s around documentation/help\n>     - Introduce a wrapper function skip_single_pick to reset_merge\n>     - Add comments to sequencer_skip\n>     - Change tests to use test_i18ncmp instead of test_cmp to not fail under\n>       GETTEXT_POISON\n> \n>  Documentation/git-cherry-pick.txt |   4 +-\n>  Documentation/git-revert.txt      |   4 +-\n>  Documentation/sequencer.txt       |   4 ++\n>  builtin/revert.c                  |   5 ++\n>  sequencer.c                       |  94 +++++++++++++++++++++++++--\n>  sequencer.h                       |   1 +\n>  t/t3510-cherry-pick-sequence.sh   | 102 ++++++++++++++++++++++++++++++\n>  7 files changed, 202 insertions(+), 12 deletions(-)\n> \n> diff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt\n> index 754b16ce0c..83ce51aedf 100644\n> --- a/Documentation/git-cherry-pick.txt\n> +++ b/Documentation/git-cherry-pick.txt\n> @@ -10,9 +10,7 @@ SYNOPSIS\n>  [verse]\n>  'git cherry-pick' [--edit] [-n] [-m parent-number] [-s] [-x] [--ff]\n>  \t\t  [-S[<keyid>]] <commit>...\n> -'git cherry-pick' --continue\n> -'git cherry-pick' --quit\n> -'git cherry-pick' --abort\n> +'git cherry-pick' (--continue | --skip | --abort | --quit)\n>  \n>  DESCRIPTION\n>  -----------\n> diff --git a/Documentation/git-revert.txt b/Documentation/git-revert.txt\n> index 0c82ca5bc0..665e065ee3 100644\n> --- a/Documentation/git-revert.txt\n> +++ b/Documentation/git-revert.txt\n> @@ -9,9 +9,7 @@ SYNOPSIS\n>  --------\n>  [verse]\n>  'git revert' [--[no-]edit] [-n] [-m parent-number] [-s] [-S[<keyid>]] <commit>...\n> -'git revert' --continue\n> -'git revert' --quit\n> -'git revert' --abort\n> +'git revert' (--continue | --skip | --abort | --quit)\n>  \n>  DESCRIPTION\n>  -----------\n> diff --git a/Documentation/sequencer.txt b/Documentation/sequencer.txt\n> index 5a57c4a407..3bceb56474 100644\n> --- a/Documentation/sequencer.txt\n> +++ b/Documentation/sequencer.txt\n> @@ -3,6 +3,10 @@\n>  \t`.git/sequencer`.  Can be used to continue after resolving\n>  \tconflicts in a failed cherry-pick or revert.\n>  \n> +--skip::\n> +\tSkip the current commit and continue with the rest of the\n> +\tsequence.\n> +\n>  --quit::\n>  \tForget about the current operation in progress.  Can be used\n>  \tto clear the sequencer state after a failed cherry-pick or\n> diff --git a/builtin/revert.c b/builtin/revert.c\n> index d4dcedbdc6..5dc5891ea2 100644\n> --- a/builtin/revert.c\n> +++ b/builtin/revert.c\n> @@ -102,6 +102,7 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)\n>  \t\tOPT_CMDMODE(0, \"quit\", &cmd, N_(\"end revert or cherry-pick sequence\"), 'q'),\n>  \t\tOPT_CMDMODE(0, \"continue\", &cmd, N_(\"resume revert or cherry-pick sequence\"), 'c'),\n>  \t\tOPT_CMDMODE(0, \"abort\", &cmd, N_(\"cancel revert or cherry-pick sequence\"), 'a'),\n> +\t\tOPT_CMDMODE(0, \"skip\", &cmd, N_(\"skip current commit and continue\"), 's'),\n>  \t\tOPT_CLEANUP(&cleanup_arg),\n>  \t\tOPT_BOOL('n', \"no-commit\", &opts->no_commit, N_(\"don't automatically commit\")),\n>  \t\tOPT_BOOL('e', \"edit\", &opts->edit, N_(\"edit the commit message\")),\n> @@ -151,6 +152,8 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)\n>  \t\t\tthis_operation = \"--quit\";\n>  \t\telse if (cmd == 'c')\n>  \t\t\tthis_operation = \"--continue\";\n> +\t\telse if (cmd == 's')\n> +\t\t\tthis_operation = \"--skip\";\n>  \t\telse {\n>  \t\t\tassert(cmd == 'a');\n>  \t\t\tthis_operation = \"--abort\";\n> @@ -210,6 +213,8 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)\n>  \t\treturn sequencer_continue(the_repository, opts);\n>  \tif (cmd == 'a')\n>  \t\treturn sequencer_rollback(the_repository, opts);\n> +\tif (cmd == 's')\n> +\t\treturn sequencer_skip(the_repository, opts);\n>  \treturn sequencer_pick_revisions(the_repository, opts);\n>  }\n>  \n> diff --git a/sequencer.c b/sequencer.c\n> index 408643f88a..95fa19a118 100644\n> --- a/sequencer.c\n> +++ b/sequencer.c\n> @@ -2733,13 +2733,18 @@ static int rollback_is_safe(void)\n>  \n>  static int reset_merge(const struct object_id *oid)\n>  {\n> -\tconst char *argv[4];\t/* reset --merge <arg> + NULL */\n> +\tint ret;\n> +\tstruct argv_array argv = ARGV_ARRAY_INIT;\n>  \n> -\targv[0] = \"reset\";\n> -\targv[1] = \"--merge\";\n> -\targv[2] = oid_to_hex(oid);\n> -\targv[3] = NULL;\n> -\treturn run_command_v_opt(argv, RUN_GIT_CMD);\n> +\targv_array_pushl(&argv, \"reset\", \"--merge\", NULL);\n> +\n> +\tif (!is_null_oid(oid))\n> +\t\targv_array_push(&argv, oid_to_hex(oid));\n> +\n> +\tret = run_command_v_opt(argv.argv, RUN_GIT_CMD);\n> +\targv_array_clear(&argv);\n> +\n> +\treturn ret;\n\nChanging this function to use argv_array could potentially be a\nseparate commit, which would make the changes in this commit a bit\nsimpler.\n\n>  }\n>  \n>  static int rollback_single_pick(struct repository *r)\n> @@ -2756,6 +2761,15 @@ static int rollback_single_pick(struct repository *r)\n>  \treturn reset_merge(&head_oid);\n>  }\n>  \n> +static int skip_single_pick(void)\n> +{\n> +\tstruct object_id head;\n> +\n> +\tif (read_ref_full(\"HEAD\", 0, &head, NULL))\n> +\t\treturn error(_(\"cannot resolve HEAD\"));\n> +\treturn reset_merge(&head);\n> +}\n> +\n>  int sequencer_rollback(struct repository *r, struct replay_opts *opts)\n>  {\n>  \tFILE *f;\n> @@ -2805,6 +2819,74 @@ int sequencer_rollback(struct repository *r, struct replay_opts *opts)\n>  \treturn -1;\n>  }\n>  \n> +int sequencer_skip(struct repository *r, struct replay_opts *opts)\n> +{\n> +\tenum replay_action action = -1;\n> +\tsequencer_get_last_command(r, &action);\n> +\n> +\t/*\n> +\t * opts->action tells us which subcommand requested to skip\n> +\t * the commit.\n> +\t */\n> +\tswitch (opts->action) {\n> +\tcase REPLAY_REVERT:\n> +\t\t/*\n> +\t\t * If .git/REVERT_HEAD exists then we are sure that we are in\n> +\t\t * the middle of a revert and we allow to skip the commit.\n> +\t\t */\n> +\t\tif (!file_exists(git_path_revert_head(r))) {\n> +\t\t\t/*\n> +\t\t\t * Check if the last instruction executed was related to\n> +\t\t\t * revert. If so, we are sure that a revert is in progress.\n> +\t\t\t *\n> +\t\t\t * NB: single commit revert is also counted in this\n> +\t\t\t * definition of \"progress\" (and was dealt with in the\n> +\t\t\t * previous check).\n> +\t\t\t */\n> +\t\t\tif (action == REPLAY_REVERT) {\n> +\t\t\t\t/*\n> +\t\t\t\t * Check if the user has moved the HEAD, i.e.,\n> +\t\t\t\t * already committed. In this case, we would like\n> +\t\t\t\t * to advise instead of skipping.\n> +\t\t\t\t */\n> +\t\t\t\tif (!rollback_is_safe())\n> +\t\t\t\t\tgoto give_advice;\n> +\t\t\t\telse\n> +\t\t\t\t\t/* skip commit :) */\n> +\t\t\t\t\tbreak;\n> +\t\t\t}\n> +\t\t\treturn error(_(\"no revert in progress\"));\n> +\t\t}\n> +\t\tbreak;\n> +\tcase REPLAY_PICK:\n> +\t\tif (!file_exists(git_path_cherry_pick_head(r))) {\n> +\t\t\tif (action == REPLAY_PICK) {\n> +\t\t\t\tif (!rollback_is_safe())\n> +\t\t\t\t\tgoto give_advice;\n> +\t\t\t\telse\n> +\t\t\t\t\tbreak;\n> +\t\t\t}\n> +\t\t\treturn error(_(\"no cherry-pick in progress\"));\n> +\t\t}\n> +\t\tbreak;\n> +\tdefault:\n> +\t\tBUG(\"unexpected action in sequencer_skip\");\n> +\t}\n\nI know it's a bit late, and this switch/case has existed for a few\niterations now.  However, especially seeing it with all the comments\nnow, I was wondering if it could be simplified a bit, especially\nbecause it gets a bit unsymmetric between the revert and the\ncherry-pick case.  This is what I came up with:\n\n\tif (opts->action != REPLAY_REVERT && opts->action != REPLAY_PICK)\n\t\tBUG(\"unexpected action in sequencer_skip\");\n\t/*\n\t * Check whether the subcommand requested to skip the commit\n\t * is actually in progress, and that it's safe to skip the\n\t * commit.\n\t *\n\t * opts->action tells us which subcommand requested to skip\n\t * the commit.  If the corresponding .git/<ACTION>_HEAD\n\t * exists, we know that the action is in progress, and we can\n\t * skip the commit.\n\t *\n\t * Otherwise we check that the last instruction was related to\n\t * the particular subcommand we're trying to execute, and\n\t * error out if that's not the case.  \n\t *\n\t * Finally we check that the rollback is safe. It isn't safe\n\t * if the user has already committed.  We only need to check\n\t * that when .git/<ACTION>_HEAD doesn't exist, because it gets\n\t * removed when the user commits, so if it still exists we're\n\t * sure the user can't have committed before.\n\t */\n\tsequencer_get_last_command(r, &action);\n\tif (opts->action == REPLAY_REVERT && !file_exists(git_path_revert_head(r))) {\n\t\tif (action != REPLAY_REVERT)\n\t\t\treturn error(_(\"no revert in progress\"));\n\t\tif (!rollback_is_safe())\n\t\t\tgoto give_advice;\n\t} else if (opts->action == REPLAY_PICK && !file_exists(git_path_cherry_pick_head(r))) {\n\t\tif (action != REPLAY_PICK)\n\t\t\treturn error(_(\"no cherry-pick in progress\"));\n\t\tif (!rollback_is_safe())\n\t\t\tgoto give_advice;\n\t}\n\nI think we could similarly simplify the switch/case a bit if we want\nto stick with that, demonstrated only for the cherry-pick case here\n(though this is not even compile tested):\n\n\tcase REPLAY_PICK:\n\t\tif (!file_exists(git_path_cherry_pick_head(r))) {\n\t\t\tif (action != REPLAY_PICK)\n\t\t\t\treturn error(_(\"no cherry-pick in progress\"));\n\t\t\tif (!rollback_is_safe())\n\t\t\t\tgoto give_advice;\n\t\t}\n\t\tbreak;\n\n> +\n> +\tif (skip_single_pick())\n> +\t\treturn error(_(\"failed to skip the commit\"));\n> +\tif (!is_directory(git_path_seq_dir()))\n> +\t\treturn 0;\n> +\n> +\treturn sequencer_continue(r, opts);\n> +\n> +give_advice:\n> +\tadvise(_(\"have you committed already?\\n\"\n> +\t\t \"try \\\"git %s --continue\\\"\"),\n> +\t\t action == REPLAY_REVERT ? \"revert\" : \"cherry-pick\");\n> +\treturn error(_(\"there is nothing to skip\"));\n> +}\n> +\n>  static int save_todo(struct todo_list *todo_list, struct replay_opts *opts)\n>  {\n>  \tstruct lock_file todo_lock = LOCK_INIT;\n> diff --git a/sequencer.h b/sequencer.h\n> index 0c494b83d4..731b9853eb 100644\n> --- a/sequencer.h\n> +++ b/sequencer.h\n> @@ -129,6 +129,7 @@ int sequencer_pick_revisions(struct repository *repo,\n>  \t\t\t     struct replay_opts *opts);\n>  int sequencer_continue(struct repository *repo, struct replay_opts *opts);\n>  int sequencer_rollback(struct repository *repo, struct replay_opts *opts);\n> +int sequencer_skip(struct repository *repo, struct replay_opts *opts);\n>  int sequencer_remove_state(struct replay_opts *opts);\n>  \n>  #define TODO_LIST_KEEP_EMPTY (1U << 0)\n> diff --git a/t/t3510-cherry-pick-sequence.sh b/t/t3510-cherry-pick-sequence.sh\n> index 941d5026da..dc0ac8343c 100755\n> --- a/t/t3510-cherry-pick-sequence.sh\n> +++ b/t/t3510-cherry-pick-sequence.sh\n> @@ -93,6 +93,108 @@ test_expect_success 'cherry-pick cleans up sequencer state upon success' '\n>  \ttest_path_is_missing .git/sequencer\n>  '\n>  \n> +test_expect_success 'cherry-pick --skip requires cherry-pick in progress' '\n> +\tpristine_detach initial &&\n> +\ttest_must_fail git cherry-pick --skip\n> +'\n> +\n> +test_expect_success 'revert --skip requires revert in progress' '\n> +\tpristine_detach initial &&\n> +\ttest_must_fail git revert --skip\n> +'\n> +\n> +test_expect_success 'cherry-pick --skip to skip commit' '\n> +\tpristine_detach initial &&\n> +\ttest_must_fail git cherry-pick anotherpick &&\n> +\ttest_must_fail git revert --skip &&\n> +\tgit cherry-pick --skip &&\n> +\ttest_cmp_rev initial HEAD &&\n> +\ttest_path_is_missing .git/CHERRY_PICK_HEAD\n> +'\n> +\n> +test_expect_success 'revert --skip to skip commit' '\n> +\tpristine_detach anotherpick &&\n> +\ttest_must_fail git revert anotherpick~1 &&\n> +\ttest_must_fail git cherry-pick --skip &&\n> +\tgit revert --skip &&\n> +\ttest_cmp_rev anotherpick HEAD\n> +'\n> +\n> +test_expect_success 'skip \"empty\" commit' '\n> +\tpristine_detach picked &&\n> +\ttest_commit dummy foo d &&\n> +\ttest_must_fail git cherry-pick anotherpick &&\n> +\tgit cherry-pick --skip &&\n> +\ttest_cmp_rev dummy HEAD\n> +'\n> +\n> +test_expect_success 'skip a commit and check if rest of sequence is correct' '\n> +\tpristine_detach initial &&\n> +\techo e >expect &&\n> +\tcat >expect.log <<-EOF &&\n> +\tOBJID\n> +\t:100644 100644 OBJID OBJID M\tfoo\n> +\tOBJID\n> +\t:100644 100644 OBJID OBJID M\tfoo\n> +\tOBJID\n> +\t:100644 100644 OBJID OBJID M\tunrelated\n> +\tOBJID\n> +\t:000000 100644 OBJID OBJID A\tfoo\n> +\t:000000 100644 OBJID OBJID A\tunrelated\n> +\tEOF\n> +\ttest_must_fail git cherry-pick base..yetanotherpick &&\n> +\ttest_must_fail git cherry-pick --skip &&\n> +\techo d >foo &&\n> +\tgit add foo &&\n> +\tgit cherry-pick --continue &&\n> +\t{\n> +\t\tgit rev-list HEAD |\n> +\t\tgit diff-tree --root --stdin |\n> +\t\tsed \"s/$OID_REGEX/OBJID/g\"\n> +\t} >actual.log &&\n> +\ttest_cmp expect foo &&\n> +\ttest_cmp expect.log actual.log\n> +'\n> +\n> +test_expect_success 'check advice when we move HEAD by committing' '\n> +\tpristine_detach initial &&\n> +\tcat >expect <<-EOF &&\n> +\thint: have you committed already?\n> +\thint: try \"git cherry-pick --continue\"\n> +\terror: there is nothing to skip\n> +\tfatal: cherry-pick failed\n> +\tEOF\n> +\ttest_must_fail git cherry-pick base..yetanotherpick &&\n> +\techo c >foo &&\n> +\tgit commit -a &&\n> +\ttest_path_is_missing .git/CHERRY_PICK_HEAD &&\n> +\ttest_must_fail git cherry-pick --skip 2>advice &&\n> +\ttest_i18ncmp expect advice\n> +'\n> +\n> +test_expect_success 'allow skipping commit but not abort for a new history' '\n> +\tpristine_detach initial &&\n> +\tcat >expect <<-EOF &&\n> +\terror: cannot abort from a branch yet to be born\n> +\tfatal: cherry-pick failed\n> +\tEOF\n> +\tgit checkout --orphan new_disconnected &&\n> +\tgit reset --hard &&\n> +\ttest_must_fail git cherry-pick anotherpick &&\n> +\ttest_must_fail git cherry-pick --abort 2>advice &&\n> +\tgit cherry-pick --skip &&\n> +\ttest_i18ncmp expect advice\n> +'\n> +\n> +test_expect_success 'allow skipping stopped cherry-pick because of untracked file modifications' '\n> +\tpristine_detach initial &&\n> +\tgit rm --cached unrelated &&\n> +\tgit commit -m \"untrack unrelated\" &&\n> +\ttest_must_fail git cherry-pick initial base &&\n> +\ttest_path_is_missing .git/CHERRY_PICK_HEAD &&\n> +\tgit cherry-pick --skip\n> +'\n> +\n>  test_expect_success '--quit does not complain when no cherry-pick is in progress' '\n>  \tpristine_detach initial &&\n>  \tgit cherry-pick --quit\n> -- \n> 2.21.0\n> \n"},{"id":"377350","messageId":"20190617083909.GB15217@hank.intra.tgummerer.com","threadId":"51269","inReplyTo":"20190616082040.9440-1-rohit.ashiwal265@gmail.com","subject":"Re: [GSoC][PATCH v4 0/4] [GSoC][PATCH 0/3] Teach cherry-pick/revert to skip commits","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2019-06-17T08:39:09Z","receivedAt":"2019-06-17T08:39:17Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"On 06/16, Rohit Ashiwal wrote:\n> Yet another iteration of my patch. We have changed the series a little bit. We\n> now have a commit that rename `reset_for_rollback` to `reset_merge`. A lot of\n> nit-picks were handled in this revision.\n\nThanks for your work!  I allowed myself to nitpick a bit more at this\nstage :)\n\nOne other thing I wanted to point out here is range-diff, which can be\nhelpful to include for the benefit of reviewers that saw this series\nbefore.  See 'man git-range-diff' or the --range-diff flag in 'git\nformat-patch' for more info on how it works.  It helps seeing at a\nglance what changed between versions of a series.\n\nFor the benefit of other reviewers that might find it helpful, here's\none I generated between v3 and v4 of the series::\n\n1:  8f29142755 ! 1:  99279e617c sequencer: add advice for revert\n    @@ -25,8 +25,8 @@\n     -\t\terror(_(\"a cherry-pick or revert is already in progress\"));\n     -\t\tadvise(_(\"try \\\"git cherry-pick (--continue | --quit | --abort)\\\"\"));\n     +\tenum replay_action action;\n    -+\tconst char *in_progress_advice;\n     +\tconst char *in_progress_error = NULL;\n    ++\tconst char *in_progress_advice = NULL;\n     +\n     +\tif (!sequencer_get_last_command(r, &action)) {\n     +\t\tswitch (action) {\n    @@ -41,7 +41,7 @@\n     +\t\t\t_(\"try \\\"git cherry-pick (--continue | --abort | --quit)\\\"\");\n     +\t\t\tbreak;\n     +\t\tdefault:\n    -+\t\t\tBUG(_(\"the control must not reach here\"));\n    ++\t\t\tBUG(_(\"unexpected action in create_seq_dir\"));\n     +\t\t}\n     +\t}\n     +\tif (in_progress_error) {\n-:  ---------- > 2:  c64aabf2d2 sequencer: rename reset_for_rollback to reset_merge\n2:  3bc8678df4 ! 3:  8b483815ca cherry-pick/revert: add --skip option\n    @@ -27,7 +27,7 @@\n     -'git cherry-pick' --continue\n     -'git cherry-pick' --quit\n     -'git cherry-pick' --abort\n    -+'git cherry-pick' --continue | --skip | --abort | --quit\n    ++'git cherry-pick' (--continue | --skip | --abort | --quit)\n      \n      DESCRIPTION\n      -----------\n    @@ -42,7 +42,7 @@\n     -'git revert' --continue\n     -'git revert' --quit\n     -'git revert' --abort\n    -+'git revert' --continue | --skip | --abort | --quit\n    ++'git revert' (--continue | --skip | --abort | --quit)\n      \n      DESCRIPTION\n      -----------\n    @@ -97,10 +97,11 @@\n      +++ b/sequencer.c\n     @@\n      \n    - static int reset_for_rollback(const struct object_id *oid)\n    + static int reset_merge(const struct object_id *oid)\n      {\n     -\tconst char *argv[4];\t/* reset --merge <arg> + NULL */\n    -+\tstruct argv_array argv = ARGV_ARRAY_INIT;\t/* reset --merge <arg> + NULL */\n    ++\tint ret;\n    ++\tstruct argv_array argv = ARGV_ARRAY_INIT;\n      \n     -\targv[0] = \"reset\";\n     -\targv[1] = \"--merge\";\n    @@ -112,34 +113,29 @@\n     +\tif (!is_null_oid(oid))\n     +\t\targv_array_push(&argv, oid_to_hex(oid));\n     +\n    -+\treturn run_command_v_opt(argv.argv, RUN_GIT_CMD);\n    ++\tret = run_command_v_opt(argv.argv, RUN_GIT_CMD);\n    ++\targv_array_clear(&argv);\n    ++\n    ++\treturn ret;\n      }\n      \n    --static int rollback_single_pick(struct repository *r)\n    -+static int rollback_single_pick(struct repository *r, unsigned int is_skip)\n    - {\n    - \tstruct object_id head_oid;\n    - \n    - \tif (!file_exists(git_path_cherry_pick_head(r)) &&\n    --\t    !file_exists(git_path_revert_head(r)))\n    -+\t    !file_exists(git_path_revert_head(r)) && !is_skip)\n    - \t\treturn error(_(\"no cherry-pick or revert in progress\"));\n    - \tif (read_ref_full(\"HEAD\", 0, &head_oid, NULL))\n    - \t\treturn error(_(\"cannot resolve HEAD\"));\n    --\tif (is_null_oid(&head_oid))\n    -+\tif (is_null_oid(&head_oid) && !is_skip)\n    - \t\treturn error(_(\"cannot abort from a branch yet to be born\"));\n    - \treturn reset_for_rollback(&head_oid);\n    - }\n    + static int rollback_single_pick(struct repository *r)\n     @@\n    - \t\t * If CHERRY_PICK_HEAD or REVERT_HEAD indicates\n    - \t\t * a single-cherry-pick in progress, abort that.\n    - \t\t */\n    --\t\treturn rollback_single_pick(r);\n    -+\t\treturn rollback_single_pick(r, 0);\n    - \t}\n    - \tif (!f)\n    - \t\treturn error_errno(_(\"cannot open '%s'\"), git_path_head_file());\n    + \treturn reset_merge(&head_oid);\n    + }\n    + \n    ++static int skip_single_pick(void)\n    ++{\n    ++\tstruct object_id head;\n    ++\n    ++\tif (read_ref_full(\"HEAD\", 0, &head, NULL))\n    ++\t\treturn error(_(\"cannot resolve HEAD\"));\n    ++\treturn reset_merge(&head);\n    ++}\n    ++\n    + int sequencer_rollback(struct repository *r, struct replay_opts *opts)\n    + {\n    + \tFILE *f;\n     @@\n      \treturn -1;\n      }\n    @@ -149,13 +145,35 @@\n     +\tenum replay_action action = -1;\n     +\tsequencer_get_last_command(r, &action);\n     +\n    ++\t/*\n    ++\t * opts->action tells us which subcommand requested to skip\n    ++\t * the commit.\n    ++\t */\n     +\tswitch (opts->action) {\n     +\tcase REPLAY_REVERT:\n    ++\t\t/*\n    ++\t\t * If .git/REVERT_HEAD exists then we are sure that we are in\n    ++\t\t * the middle of a revert and we allow to skip the commit.\n    ++\t\t */\n     +\t\tif (!file_exists(git_path_revert_head(r))) {\n    ++\t\t\t/*\n    ++\t\t\t * Check if the last instruction executed was related to\n    ++\t\t\t * revert. If so, we are sure that a revert is in progress.\n    ++\t\t\t *\n    ++\t\t\t * NB: single commit revert is also counted in this\n    ++\t\t\t * definition of \"progress\" (and was dealt with in the\n    ++\t\t\t * previous check).\n    ++\t\t\t */\n     +\t\t\tif (action == REPLAY_REVERT) {\n    ++\t\t\t\t/*\n    ++\t\t\t\t * Check if the user has moved the HEAD, i.e.,\n    ++\t\t\t\t * already committed. In this case, we would like\n    ++\t\t\t\t * to advise instead of skipping.\n    ++\t\t\t\t */\n     +\t\t\t\tif (!rollback_is_safe())\n     +\t\t\t\t\tgoto give_advice;\n     +\t\t\t\telse\n    ++\t\t\t\t\t/* skip commit :) */\n     +\t\t\t\t\tbreak;\n     +\t\t\t}\n     +\t\t\treturn error(_(\"no revert in progress\"));\n    @@ -173,10 +191,10 @@\n     +\t\t}\n     +\t\tbreak;\n     +\tdefault:\n    -+\t\tBUG(\"the control must not reach here\");\n    ++\t\tBUG(\"unexpected action in sequencer_skip\");\n     +\t}\n     +\n    -+\tif (rollback_single_pick(r, 1))\n    ++\tif (skip_single_pick())\n     +\t\treturn error(_(\"failed to skip the commit\"));\n     +\tif (!is_directory(git_path_seq_dir()))\n     +\t\treturn 0;\n    @@ -289,7 +307,7 @@\n     +\tgit commit -a &&\n     +\ttest_path_is_missing .git/CHERRY_PICK_HEAD &&\n     +\ttest_must_fail git cherry-pick --skip 2>advice &&\n    -+\ttest_cmp expect advice\n    ++\ttest_i18ncmp expect advice\n     +'\n     +\n     +test_expect_success 'allow skipping commit but not abort for a new history' '\n    @@ -303,7 +321,7 @@\n     +\ttest_must_fail git cherry-pick anotherpick &&\n     +\ttest_must_fail git cherry-pick --abort 2>advice &&\n     +\tgit cherry-pick --skip &&\n    -+\ttest_cmp expect advice\n    ++\ttest_i18ncmp expect advice\n     +'\n     +\n     +test_expect_success 'allow skipping stopped cherry-pick because of untracked file modifications' '\n3:  a3cd17540b ! 4:  98618e08f4 cherry-pick/revert: advise using --skip\n    @@ -42,8 +42,8 @@\n      +++ b/sequencer.c\n     @@\n      \tenum replay_action action;\n    - \tconst char *in_progress_advice;\n      \tconst char *in_progress_error = NULL;\n    + \tconst char *in_progress_advice = NULL;\n     +\tunsigned int advise_skip = file_exists(git_path_revert_head(r)) ||\n     +\t\t\t\tfile_exists(git_path_cherry_pick_head(r));\n      \n    @@ -62,7 +62,7 @@\n     +\t\t\t_(\"try \\\"git cherry-pick (--continue | %s--abort | --quit)\\\"\");\n      \t\t\tbreak;\n      \t\tdefault:\n    - \t\t\tBUG(_(\"the control must not reach here\"));\n    + \t\t\tBUG(_(\"unexpected action in create_seq_dir\"));\n     @@\n      \t}\n      \tif (in_progress_error) {\n    @@ -80,7 +80,7 @@\n      --- a/t/t3510-cherry-pick-sequence.sh\n      +++ b/t/t3510-cherry-pick-sequence.sh\n     @@\n    - \ttest_cmp expect advice\n    + \ttest_i18ncmp expect advice\n      '\n      \n     +test_expect_success 'selectively advise --skip while launching another sequence' '\n    @@ -92,7 +92,7 @@\n     +\tEOF\n     +\ttest_must_fail git cherry-pick picked..yetanotherpick &&\n     +\ttest_must_fail git cherry-pick picked..yetanotherpick 2>advice &&\n    -+\ttest_cmp expect advice &&\n    ++\ttest_i18ncmp expect advice &&\n     +\tcat >expect <<-EOF &&\n     +\terror: cherry-pick is already in progress\n     +\thint: try \"git cherry-pick (--continue | --abort | --quit)\"\n    @@ -100,7 +100,7 @@\n     +\tEOF\n     +\tgit reset --merge &&\n     +\ttest_must_fail git cherry-pick picked..yetanotherpick 2>advice &&\n    -+\ttest_cmp expect advice\n    ++\ttest_i18ncmp expect advice\n     +'\n     +\n      test_expect_success 'allow skipping commit but not abort for a new history' '\n\n> Rohit Ashiwal (4):\n>   sequencer: add advice for revert\n>   sequencer: rename reset_for_rollback to reset_merge\n>   cherry-pick/revert: add --skip option\n>   cherry-pick/revert: advise using --skip\n> \n>  Documentation/git-cherry-pick.txt |   4 +-\n>  Documentation/git-revert.txt      |   4 +-\n>  Documentation/sequencer.txt       |   4 +\n>  builtin/commit.c                  |  13 +--\n>  builtin/revert.c                  |   5 ++\n>  sequencer.c                       | 139 ++++++++++++++++++++++++++----\n>  sequencer.h                       |   1 +\n>  t/t3510-cherry-pick-sequence.sh   | 122 ++++++++++++++++++++++++++\n>  8 files changed, 266 insertions(+), 26 deletions(-)\n> \n> -- \n> 2.21.0\n> \n"},{"id":"377421","messageId":"20190618170650.22721-1-rohit.ashiwal265@gmail.com","threadId":"51269","inReplyTo":"20190608191958.4593-1-rohit.ashiwal265@gmail.com","subject":"[GSoC][PATCH v5 0/5] Teach cherry-pick/revert to skip commits","fromName":"Rohit Ashiwal","fromEmail":"rohit.ashiwal265@gmail.com","sentAt":"2019-06-18T17:06:45Z","receivedAt":"2019-06-18T17:09:13Z","isPatch":true,"sender":{"key":"rohit.ashiwal265@gmail.com","avatar":"https://avatars.githubusercontent.com/u/31043830?v=4"},"body":"Here is another round of my patch, hopefully I have addressed all the changes.\n  - I have introduced a separate commit which changes `reset_merge` to use\n    `argv_array` instead of a manual `char *argv`. This will avoid specifying\n    array size and index and make code easier to read and extend\n  - Removed _() from BUG() messages\n  - Rearrange comments under `sequencer_skip`. I have not changed switch-case to\n    if-else since the former looked better to me\n\nThanks\n\nRohit Ashiwal (5):\n  sequencer: add advice for revert\n  sequencer: rename reset_for_rollback to reset_merge\n  sequencer: use argv_array in reset_merge\n  cherry-pick/revert: add --skip option\n  cherry-pick/revert: advise using --skip\n\n Documentation/git-cherry-pick.txt |   4 +-\n Documentation/git-revert.txt      |   4 +-\n Documentation/sequencer.txt       |   4 +\n builtin/commit.c                  |  13 +--\n builtin/revert.c                  |   5 ++\n sequencer.c                       | 131 ++++++++++++++++++++++++++----\n sequencer.h                       |   1 +\n t/t3510-cherry-pick-sequence.sh   | 122 ++++++++++++++++++++++++++++\n 8 files changed, 258 insertions(+), 26 deletions(-)\n\nRange-diff:\n1:  59fa13c4d8 ! 1:  67c212090d sequencer: add advice for revert\n    @@ -41,7 +41,7 @@\n     +\t\t\t_(\"try \\\"git cherry-pick (--continue | --abort | --quit)\\\"\");\n     +\t\t\tbreak;\n     +\t\tdefault:\n    -+\t\t\tBUG(_(\"unexpected action in create_seq_dir\"));\n    ++\t\t\tBUG(\"unexpected action in create_seq_dir\");\n     +\t\t}\n     +\t}\n     +\tif (in_progress_error) {\n2:  dea4582591 = 2:  300d6f64f0 sequencer: rename reset_for_rollback to reset_merge\n-:  ---------- > 3:  edc35f6a4c sequencer: use argv_array in reset_merge\n3:  29686d828f ! 4:  825486c22d cherry-pick/revert: add --skip option\n    @@ -11,9 +11,8 @@\n         skipping commits easier for the user and to make the commands more\n         consistent.\n     \n    -    In the next commit, we will change the advice messages and some tests\n    -    hence finishing the process of teaching revert and cherry-pick\n    -    \"how to skip commits\".\n    +    In the next commit, we will change the advice messages hence finishing\n    +    the process of teaching revert and cherry-pick \"how to skip commits\".\n     \n         Signed-off-by: Rohit Ashiwal <rohit.ashiwal265@gmail.com>\n     \n    @@ -96,31 +95,6 @@\n      --- a/sequencer.c\n      +++ b/sequencer.c\n     @@\n    - \n    - static int reset_merge(const struct object_id *oid)\n    - {\n    --\tconst char *argv[4];\t/* reset --merge <arg> + NULL */\n    -+\tint ret;\n    -+\tstruct argv_array argv = ARGV_ARRAY_INIT;\n    - \n    --\targv[0] = \"reset\";\n    --\targv[1] = \"--merge\";\n    --\targv[2] = oid_to_hex(oid);\n    --\targv[3] = NULL;\n    --\treturn run_command_v_opt(argv, RUN_GIT_CMD);\n    -+\targv_array_pushl(&argv, \"reset\", \"--merge\", NULL);\n    -+\n    -+\tif (!is_null_oid(oid))\n    -+\t\targv_array_push(&argv, oid_to_hex(oid));\n    -+\n    -+\tret = run_command_v_opt(argv.argv, RUN_GIT_CMD);\n    -+\targv_array_clear(&argv);\n    -+\n    -+\treturn ret;\n    - }\n    - \n    - static int rollback_single_pick(struct repository *r)\n    -@@\n      \treturn reset_merge(&head_oid);\n      }\n      \n    @@ -146,48 +120,40 @@\n     +\tsequencer_get_last_command(r, &action);\n     +\n     +\t/*\n    -+\t * opts->action tells us which subcommand requested to skip\n    -+\t * the commit.\n    ++\t * Check whether the subcommand requested to skip the commit is actually\n    ++\t * in progress and that it's safe to skip the commit.\n    ++\t *\n    ++\t * opts->action tells us which subcommand requested to skip the commit.\n    ++\t * If the corresponding .git/<ACTION>_HEAD exists, we know that the\n    ++\t * action is in progress and we can skip the commit.\n    ++\t *\n    ++\t * Otherwise we check that the last instruction was related to the\n    ++\t * particular subcommand we're trying to execute and barf if that's not\n    ++\t * the case.\n    ++\t *\n    ++\t * Finally we check that the rollback is \"safe\", i.e., has the HEAD\n    ++\t * moved? In this case, it doesn't make sense to \"reset the merge\" and\n    ++\t * \"skip the commit\" as the user already handled this by committing. But\n    ++\t * we'd not want to barf here, instead give advice on how to proceed. We\n    ++\t * only need to check that when .git/<ACTION>_HEAD doesn't exist because\n    ++\t * it gets removed when the user commits, so if it still exists we're\n    ++\t * sure the user can't have committed before.\n     +\t */\n     +\tswitch (opts->action) {\n     +\tcase REPLAY_REVERT:\n    -+\t\t/*\n    -+\t\t * If .git/REVERT_HEAD exists then we are sure that we are in\n    -+\t\t * the middle of a revert and we allow to skip the commit.\n    -+\t\t */\n     +\t\tif (!file_exists(git_path_revert_head(r))) {\n    -+\t\t\t/*\n    -+\t\t\t * Check if the last instruction executed was related to\n    -+\t\t\t * revert. If so, we are sure that a revert is in progress.\n    -+\t\t\t *\n    -+\t\t\t * NB: single commit revert is also counted in this\n    -+\t\t\t * definition of \"progress\" (and was dealt with in the\n    -+\t\t\t * previous check).\n    -+\t\t\t */\n    -+\t\t\tif (action == REPLAY_REVERT) {\n    -+\t\t\t\t/*\n    -+\t\t\t\t * Check if the user has moved the HEAD, i.e.,\n    -+\t\t\t\t * already committed. In this case, we would like\n    -+\t\t\t\t * to advise instead of skipping.\n    -+\t\t\t\t */\n    -+\t\t\t\tif (!rollback_is_safe())\n    -+\t\t\t\t\tgoto give_advice;\n    -+\t\t\t\telse\n    -+\t\t\t\t\t/* skip commit :) */\n    -+\t\t\t\t\tbreak;\n    -+\t\t\t}\n    -+\t\t\treturn error(_(\"no revert in progress\"));\n    ++\t\t\tif (action != REPLAY_REVERT)\n    ++\t\t\t\treturn error(_(\"no revert in progress\"));\n    ++\t\t\tif (!rollback_is_safe())\n    ++\t\t\t\tgoto give_advice;\n     +\t\t}\n     +\t\tbreak;\n     +\tcase REPLAY_PICK:\n     +\t\tif (!file_exists(git_path_cherry_pick_head(r))) {\n    -+\t\t\tif (action == REPLAY_PICK) {\n    -+\t\t\t\tif (!rollback_is_safe())\n    -+\t\t\t\t\tgoto give_advice;\n    -+\t\t\t\telse\n    -+\t\t\t\t\tbreak;\n    -+\t\t\t}\n    -+\t\t\treturn error(_(\"no cherry-pick in progress\"));\n    ++\t\t\tif (action != REPLAY_PICK)\n    ++\t\t\t\treturn error(_(\"no cherry-pick in progress\"));\n    ++\t\t\tif (!rollback_is_safe())\n    ++\t\t\t\tgoto give_advice;\n     +\t\t}\n     +\t\tbreak;\n     +\tdefault:\n4:  941e73b654 ! 5:  63dbc11ab1 cherry-pick/revert: advise using --skip\n    @@ -62,7 +62,7 @@\n     +\t\t\t_(\"try \\\"git cherry-pick (--continue | %s--abort | --quit)\\\"\");\n      \t\t\tbreak;\n      \t\tdefault:\n    - \t\t\tBUG(_(\"unexpected action in create_seq_dir\"));\n    + \t\t\tBUG(\"unexpected action in create_seq_dir\");\n     @@\n      \t}\n      \tif (in_progress_error) {\n-- \n2.21.0\n\n"},{"id":"377422","messageId":"20190618170650.22721-2-rohit.ashiwal265@gmail.com","threadId":"51269","inReplyTo":"20190618170650.22721-1-rohit.ashiwal265@gmail.com","subject":"[GSoC][PATCH v5 1/5] sequencer: add advice for revert","fromName":"Rohit Ashiwal","fromEmail":"rohit.ashiwal265@gmail.com","sentAt":"2019-06-18T17:06:46Z","receivedAt":"2019-06-18T17:09:16Z","isPatch":true,"sender":{"key":"rohit.ashiwal265@gmail.com","avatar":"https://avatars.githubusercontent.com/u/31043830?v=4"},"body":"In the case of merge conflicts, while performing a revert, we are\ncurrently advised to use `git cherry-pick --<sequencer-options>`\nof which --continue is incompatible for continuing the revert.\nIntroduce a separate advice message for `git revert`. Also change\nthe signature of `create_seq_dir` to handle which advice to display\nselectively.\n\nSigned-off-by: Rohit Ashiwal <rohit.ashiwal265@gmail.com>\n---\n sequencer.c | 34 ++++++++++++++++++++++++++++------\n 1 file changed, 28 insertions(+), 6 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex f88a97fb10..c644368b54 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -2650,15 +2650,37 @@ static int walk_revs_populate_todo(struct todo_list *todo_list,\n \treturn 0;\n }\n \n-static int create_seq_dir(void)\n+static int create_seq_dir(struct repository *r)\n {\n-\tif (file_exists(git_path_seq_dir())) {\n-\t\terror(_(\"a cherry-pick or revert is already in progress\"));\n-\t\tadvise(_(\"try \\\"git cherry-pick (--continue | --quit | --abort)\\\"\"));\n+\tenum replay_action action;\n+\tconst char *in_progress_error = NULL;\n+\tconst char *in_progress_advice = NULL;\n+\n+\tif (!sequencer_get_last_command(r, &action)) {\n+\t\tswitch (action) {\n+\t\tcase REPLAY_REVERT:\n+\t\t\tin_progress_error = _(\"revert is already in progress\");\n+\t\t\tin_progress_advice =\n+\t\t\t_(\"try \\\"git revert (--continue | --abort | --quit)\\\"\");\n+\t\t\tbreak;\n+\t\tcase REPLAY_PICK:\n+\t\t\tin_progress_error = _(\"cherry-pick is already in progress\");\n+\t\t\tin_progress_advice =\n+\t\t\t_(\"try \\\"git cherry-pick (--continue | --abort | --quit)\\\"\");\n+\t\t\tbreak;\n+\t\tdefault:\n+\t\t\tBUG(\"unexpected action in create_seq_dir\");\n+\t\t}\n+\t}\n+\tif (in_progress_error) {\n+\t\terror(\"%s\", in_progress_error);\n+\t\tadvise(\"%s\", in_progress_advice);\n \t\treturn -1;\n-\t} else if (mkdir(git_path_seq_dir(), 0777) < 0)\n+\t}\n+\tif (mkdir(git_path_seq_dir(), 0777) < 0)\n \t\treturn error_errno(_(\"could not create sequencer directory '%s'\"),\n \t\t\t\t   git_path_seq_dir());\n+\n \treturn 0;\n }\n \n@@ -4237,7 +4259,7 @@ int sequencer_pick_revisions(struct repository *r,\n \t */\n \n \tif (walk_revs_populate_todo(&todo_list, opts) ||\n-\t\t\tcreate_seq_dir() < 0)\n+\t\t\tcreate_seq_dir(r) < 0)\n \t\treturn -1;\n \tif (get_oid(\"HEAD\", &oid) && (opts->action == REPLAY_REVERT))\n \t\treturn error(_(\"can't revert as initial commit\"));\n-- \n2.21.0\n\n"},{"id":"377423","messageId":"20190618170650.22721-3-rohit.ashiwal265@gmail.com","threadId":"51269","inReplyTo":"20190618170650.22721-1-rohit.ashiwal265@gmail.com","subject":"[GSoC][PATCH v5 2/5] sequencer: rename reset_for_rollback to reset_merge","fromName":"Rohit Ashiwal","fromEmail":"rohit.ashiwal265@gmail.com","sentAt":"2019-06-18T17:06:47Z","receivedAt":"2019-06-18T17:09:19Z","isPatch":true,"sender":{"key":"rohit.ashiwal265@gmail.com","avatar":"https://avatars.githubusercontent.com/u/31043830?v=4"},"body":"We are on a path to teach cherry-pick/revert how to skip commits. To\nachieve this, we could really make use of existing functions.\nreset_for_rollback is one such function, but the name does not\nintuitively suggest to use it to reset a merge, which it was born to\nperform see 539047c (\"revert: introduce --abort to cancel a failed\ncherry-pick\", 2011-11-23). Change the name to reset_merge to make\nit more intuitive.\n\nSigned-off-by: Rohit Ashiwal <rohit.ashiwal265@gmail.com>\n---\n sequencer.c | 6 +++---\n 1 file changed, 3 insertions(+), 3 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex c644368b54..12f2605ded 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -2731,7 +2731,7 @@ static int rollback_is_safe(void)\n \treturn oideq(&actual_head, &expected_head);\n }\n \n-static int reset_for_rollback(const struct object_id *oid)\n+static int reset_merge(const struct object_id *oid)\n {\n \tconst char *argv[4];\t/* reset --merge <arg> + NULL */\n \n@@ -2753,7 +2753,7 @@ static int rollback_single_pick(struct repository *r)\n \t\treturn error(_(\"cannot resolve HEAD\"));\n \tif (is_null_oid(&head_oid))\n \t\treturn error(_(\"cannot abort from a branch yet to be born\"));\n-\treturn reset_for_rollback(&head_oid);\n+\treturn reset_merge(&head_oid);\n }\n \n int sequencer_rollback(struct repository *r, struct replay_opts *opts)\n@@ -2796,7 +2796,7 @@ int sequencer_rollback(struct repository *r, struct replay_opts *opts)\n \t\twarning(_(\"You seem to have moved HEAD. \"\n \t\t\t  \"Not rewinding, check your HEAD!\"));\n \t} else\n-\tif (reset_for_rollback(&oid))\n+\tif (reset_merge(&oid))\n \t\tgoto fail;\n \tstrbuf_release(&buf);\n \treturn sequencer_remove_state(opts);\n-- \n2.21.0\n\n"},{"id":"377424","messageId":"20190618170650.22721-4-rohit.ashiwal265@gmail.com","threadId":"51269","inReplyTo":"20190618170650.22721-1-rohit.ashiwal265@gmail.com","subject":"[GSoC][PATCH v5 3/5] sequencer: use argv_array in reset_merge","fromName":"Rohit Ashiwal","fromEmail":"rohit.ashiwal265@gmail.com","sentAt":"2019-06-18T17:06:48Z","receivedAt":"2019-06-18T17:09:22Z","isPatch":true,"sender":{"key":"rohit.ashiwal265@gmail.com","avatar":"https://avatars.githubusercontent.com/u/31043830?v=4"},"body":"Avoid using magic numbers for array size and index under `reset_merge`\nfunction. Use `argv_array` instead. This will make code shorter and\neasier to extend.\n\nSigned-off-by: Rohit Ashiwal <rohit.ashiwal265@gmail.com>\n---\n sequencer.c | 17 +++++++++++------\n 1 file changed, 11 insertions(+), 6 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 12f2605ded..6762a5f485 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -2733,13 +2733,18 @@ static int rollback_is_safe(void)\n \n static int reset_merge(const struct object_id *oid)\n {\n-\tconst char *argv[4];\t/* reset --merge <arg> + NULL */\n+\tint ret;\n+\tstruct argv_array argv = ARGV_ARRAY_INIT;\n \n-\targv[0] = \"reset\";\n-\targv[1] = \"--merge\";\n-\targv[2] = oid_to_hex(oid);\n-\targv[3] = NULL;\n-\treturn run_command_v_opt(argv, RUN_GIT_CMD);\n+\targv_array_pushl(&argv, \"reset\", \"--merge\", NULL);\n+\n+\tif (!is_null_oid(oid))\n+\t\targv_array_push(&argv, oid_to_hex(oid));\n+\n+\tret = run_command_v_opt(argv.argv, RUN_GIT_CMD);\n+\targv_array_clear(&argv);\n+\n+\treturn ret;\n }\n \n static int rollback_single_pick(struct repository *r)\n-- \n2.21.0\n\n"},{"id":"377425","messageId":"20190618170650.22721-5-rohit.ashiwal265@gmail.com","threadId":"51269","inReplyTo":"20190618170650.22721-1-rohit.ashiwal265@gmail.com","subject":"[GSoC][PATCH v5 4/5] cherry-pick/revert: add --skip option","fromName":"Rohit Ashiwal","fromEmail":"rohit.ashiwal265@gmail.com","sentAt":"2019-06-18T17:06:49Z","receivedAt":"2019-06-18T17:09:26Z","isPatch":true,"sender":{"key":"rohit.ashiwal265@gmail.com","avatar":"https://avatars.githubusercontent.com/u/31043830?v=4"},"body":"git am or rebase have a --skip flag to skip the current commit if the\nuser wishes to do so. During a cherry-pick or revert a user could\nlikewise skip a commit, but needs to use 'git reset' (or in the case\nof conflicts 'git reset --merge'), followed by 'git (cherry-pick |\nrevert) --continue' to skip the commit. This is more annoying and\nsometimes confusing on the users' part. Add a `--skip` option to make\nskipping commits easier for the user and to make the commands more\nconsistent.\n\nIn the next commit, we will change the advice messages hence finishing\nthe process of teaching revert and cherry-pick \"how to skip commits\".\n\nSigned-off-by: Rohit Ashiwal <rohit.ashiwal265@gmail.com>\n---\n Documentation/git-cherry-pick.txt |   4 +-\n Documentation/git-revert.txt      |   4 +-\n Documentation/sequencer.txt       |   4 ++\n builtin/revert.c                  |   5 ++\n sequencer.c                       |  69 ++++++++++++++++++++\n sequencer.h                       |   1 +\n t/t3510-cherry-pick-sequence.sh   | 102 ++++++++++++++++++++++++++++++\n 7 files changed, 183 insertions(+), 6 deletions(-)\n\ndiff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt\nindex 754b16ce0c..83ce51aedf 100644\n--- a/Documentation/git-cherry-pick.txt\n+++ b/Documentation/git-cherry-pick.txt\n@@ -10,9 +10,7 @@ SYNOPSIS\n [verse]\n 'git cherry-pick' [--edit] [-n] [-m parent-number] [-s] [-x] [--ff]\n \t\t  [-S[<keyid>]] <commit>...\n-'git cherry-pick' --continue\n-'git cherry-pick' --quit\n-'git cherry-pick' --abort\n+'git cherry-pick' (--continue | --skip | --abort | --quit)\n \n DESCRIPTION\n -----------\ndiff --git a/Documentation/git-revert.txt b/Documentation/git-revert.txt\nindex 0c82ca5bc0..665e065ee3 100644\n--- a/Documentation/git-revert.txt\n+++ b/Documentation/git-revert.txt\n@@ -9,9 +9,7 @@ SYNOPSIS\n --------\n [verse]\n 'git revert' [--[no-]edit] [-n] [-m parent-number] [-s] [-S[<keyid>]] <commit>...\n-'git revert' --continue\n-'git revert' --quit\n-'git revert' --abort\n+'git revert' (--continue | --skip | --abort | --quit)\n \n DESCRIPTION\n -----------\ndiff --git a/Documentation/sequencer.txt b/Documentation/sequencer.txt\nindex 5a57c4a407..3bceb56474 100644\n--- a/Documentation/sequencer.txt\n+++ b/Documentation/sequencer.txt\n@@ -3,6 +3,10 @@\n \t`.git/sequencer`.  Can be used to continue after resolving\n \tconflicts in a failed cherry-pick or revert.\n \n+--skip::\n+\tSkip the current commit and continue with the rest of the\n+\tsequence.\n+\n --quit::\n \tForget about the current operation in progress.  Can be used\n \tto clear the sequencer state after a failed cherry-pick or\ndiff --git a/builtin/revert.c b/builtin/revert.c\nindex d4dcedbdc6..5dc5891ea2 100644\n--- a/builtin/revert.c\n+++ b/builtin/revert.c\n@@ -102,6 +102,7 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)\n \t\tOPT_CMDMODE(0, \"quit\", &cmd, N_(\"end revert or cherry-pick sequence\"), 'q'),\n \t\tOPT_CMDMODE(0, \"continue\", &cmd, N_(\"resume revert or cherry-pick sequence\"), 'c'),\n \t\tOPT_CMDMODE(0, \"abort\", &cmd, N_(\"cancel revert or cherry-pick sequence\"), 'a'),\n+\t\tOPT_CMDMODE(0, \"skip\", &cmd, N_(\"skip current commit and continue\"), 's'),\n \t\tOPT_CLEANUP(&cleanup_arg),\n \t\tOPT_BOOL('n', \"no-commit\", &opts->no_commit, N_(\"don't automatically commit\")),\n \t\tOPT_BOOL('e', \"edit\", &opts->edit, N_(\"edit the commit message\")),\n@@ -151,6 +152,8 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)\n \t\t\tthis_operation = \"--quit\";\n \t\telse if (cmd == 'c')\n \t\t\tthis_operation = \"--continue\";\n+\t\telse if (cmd == 's')\n+\t\t\tthis_operation = \"--skip\";\n \t\telse {\n \t\t\tassert(cmd == 'a');\n \t\t\tthis_operation = \"--abort\";\n@@ -210,6 +213,8 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)\n \t\treturn sequencer_continue(the_repository, opts);\n \tif (cmd == 'a')\n \t\treturn sequencer_rollback(the_repository, opts);\n+\tif (cmd == 's')\n+\t\treturn sequencer_skip(the_repository, opts);\n \treturn sequencer_pick_revisions(the_repository, opts);\n }\n \ndiff --git a/sequencer.c b/sequencer.c\nindex 6762a5f485..5720cd1c85 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -2761,6 +2761,15 @@ static int rollback_single_pick(struct repository *r)\n \treturn reset_merge(&head_oid);\n }\n \n+static int skip_single_pick(void)\n+{\n+\tstruct object_id head;\n+\n+\tif (read_ref_full(\"HEAD\", 0, &head, NULL))\n+\t\treturn error(_(\"cannot resolve HEAD\"));\n+\treturn reset_merge(&head);\n+}\n+\n int sequencer_rollback(struct repository *r, struct replay_opts *opts)\n {\n \tFILE *f;\n@@ -2810,6 +2819,66 @@ int sequencer_rollback(struct repository *r, struct replay_opts *opts)\n \treturn -1;\n }\n \n+int sequencer_skip(struct repository *r, struct replay_opts *opts)\n+{\n+\tenum replay_action action = -1;\n+\tsequencer_get_last_command(r, &action);\n+\n+\t/*\n+\t * Check whether the subcommand requested to skip the commit is actually\n+\t * in progress and that it's safe to skip the commit.\n+\t *\n+\t * opts->action tells us which subcommand requested to skip the commit.\n+\t * If the corresponding .git/<ACTION>_HEAD exists, we know that the\n+\t * action is in progress and we can skip the commit.\n+\t *\n+\t * Otherwise we check that the last instruction was related to the\n+\t * particular subcommand we're trying to execute and barf if that's not\n+\t * the case.\n+\t *\n+\t * Finally we check that the rollback is \"safe\", i.e., has the HEAD\n+\t * moved? In this case, it doesn't make sense to \"reset the merge\" and\n+\t * \"skip the commit\" as the user already handled this by committing. But\n+\t * we'd not want to barf here, instead give advice on how to proceed. We\n+\t * only need to check that when .git/<ACTION>_HEAD doesn't exist because\n+\t * it gets removed when the user commits, so if it still exists we're\n+\t * sure the user can't have committed before.\n+\t */\n+\tswitch (opts->action) {\n+\tcase REPLAY_REVERT:\n+\t\tif (!file_exists(git_path_revert_head(r))) {\n+\t\t\tif (action != REPLAY_REVERT)\n+\t\t\t\treturn error(_(\"no revert in progress\"));\n+\t\t\tif (!rollback_is_safe())\n+\t\t\t\tgoto give_advice;\n+\t\t}\n+\t\tbreak;\n+\tcase REPLAY_PICK:\n+\t\tif (!file_exists(git_path_cherry_pick_head(r))) {\n+\t\t\tif (action != REPLAY_PICK)\n+\t\t\t\treturn error(_(\"no cherry-pick in progress\"));\n+\t\t\tif (!rollback_is_safe())\n+\t\t\t\tgoto give_advice;\n+\t\t}\n+\t\tbreak;\n+\tdefault:\n+\t\tBUG(\"unexpected action in sequencer_skip\");\n+\t}\n+\n+\tif (skip_single_pick())\n+\t\treturn error(_(\"failed to skip the commit\"));\n+\tif (!is_directory(git_path_seq_dir()))\n+\t\treturn 0;\n+\n+\treturn sequencer_continue(r, opts);\n+\n+give_advice:\n+\tadvise(_(\"have you committed already?\\n\"\n+\t\t \"try \\\"git %s --continue\\\"\"),\n+\t\t action == REPLAY_REVERT ? \"revert\" : \"cherry-pick\");\n+\treturn error(_(\"there is nothing to skip\"));\n+}\n+\n static int save_todo(struct todo_list *todo_list, struct replay_opts *opts)\n {\n \tstruct lock_file todo_lock = LOCK_INIT;\ndiff --git a/sequencer.h b/sequencer.h\nindex 0c494b83d4..731b9853eb 100644\n--- a/sequencer.h\n+++ b/sequencer.h\n@@ -129,6 +129,7 @@ int sequencer_pick_revisions(struct repository *repo,\n \t\t\t     struct replay_opts *opts);\n int sequencer_continue(struct repository *repo, struct replay_opts *opts);\n int sequencer_rollback(struct repository *repo, struct replay_opts *opts);\n+int sequencer_skip(struct repository *repo, struct replay_opts *opts);\n int sequencer_remove_state(struct replay_opts *opts);\n \n #define TODO_LIST_KEEP_EMPTY (1U << 0)\ndiff --git a/t/t3510-cherry-pick-sequence.sh b/t/t3510-cherry-pick-sequence.sh\nindex 941d5026da..dc0ac8343c 100755\n--- a/t/t3510-cherry-pick-sequence.sh\n+++ b/t/t3510-cherry-pick-sequence.sh\n@@ -93,6 +93,108 @@ test_expect_success 'cherry-pick cleans up sequencer state upon success' '\n \ttest_path_is_missing .git/sequencer\n '\n \n+test_expect_success 'cherry-pick --skip requires cherry-pick in progress' '\n+\tpristine_detach initial &&\n+\ttest_must_fail git cherry-pick --skip\n+'\n+\n+test_expect_success 'revert --skip requires revert in progress' '\n+\tpristine_detach initial &&\n+\ttest_must_fail git revert --skip\n+'\n+\n+test_expect_success 'cherry-pick --skip to skip commit' '\n+\tpristine_detach initial &&\n+\ttest_must_fail git cherry-pick anotherpick &&\n+\ttest_must_fail git revert --skip &&\n+\tgit cherry-pick --skip &&\n+\ttest_cmp_rev initial HEAD &&\n+\ttest_path_is_missing .git/CHERRY_PICK_HEAD\n+'\n+\n+test_expect_success 'revert --skip to skip commit' '\n+\tpristine_detach anotherpick &&\n+\ttest_must_fail git revert anotherpick~1 &&\n+\ttest_must_fail git cherry-pick --skip &&\n+\tgit revert --skip &&\n+\ttest_cmp_rev anotherpick HEAD\n+'\n+\n+test_expect_success 'skip \"empty\" commit' '\n+\tpristine_detach picked &&\n+\ttest_commit dummy foo d &&\n+\ttest_must_fail git cherry-pick anotherpick &&\n+\tgit cherry-pick --skip &&\n+\ttest_cmp_rev dummy HEAD\n+'\n+\n+test_expect_success 'skip a commit and check if rest of sequence is correct' '\n+\tpristine_detach initial &&\n+\techo e >expect &&\n+\tcat >expect.log <<-EOF &&\n+\tOBJID\n+\t:100644 100644 OBJID OBJID M\tfoo\n+\tOBJID\n+\t:100644 100644 OBJID OBJID M\tfoo\n+\tOBJID\n+\t:100644 100644 OBJID OBJID M\tunrelated\n+\tOBJID\n+\t:000000 100644 OBJID OBJID A\tfoo\n+\t:000000 100644 OBJID OBJID A\tunrelated\n+\tEOF\n+\ttest_must_fail git cherry-pick base..yetanotherpick &&\n+\ttest_must_fail git cherry-pick --skip &&\n+\techo d >foo &&\n+\tgit add foo &&\n+\tgit cherry-pick --continue &&\n+\t{\n+\t\tgit rev-list HEAD |\n+\t\tgit diff-tree --root --stdin |\n+\t\tsed \"s/$OID_REGEX/OBJID/g\"\n+\t} >actual.log &&\n+\ttest_cmp expect foo &&\n+\ttest_cmp expect.log actual.log\n+'\n+\n+test_expect_success 'check advice when we move HEAD by committing' '\n+\tpristine_detach initial &&\n+\tcat >expect <<-EOF &&\n+\thint: have you committed already?\n+\thint: try \"git cherry-pick --continue\"\n+\terror: there is nothing to skip\n+\tfatal: cherry-pick failed\n+\tEOF\n+\ttest_must_fail git cherry-pick base..yetanotherpick &&\n+\techo c >foo &&\n+\tgit commit -a &&\n+\ttest_path_is_missing .git/CHERRY_PICK_HEAD &&\n+\ttest_must_fail git cherry-pick --skip 2>advice &&\n+\ttest_i18ncmp expect advice\n+'\n+\n+test_expect_success 'allow skipping commit but not abort for a new history' '\n+\tpristine_detach initial &&\n+\tcat >expect <<-EOF &&\n+\terror: cannot abort from a branch yet to be born\n+\tfatal: cherry-pick failed\n+\tEOF\n+\tgit checkout --orphan new_disconnected &&\n+\tgit reset --hard &&\n+\ttest_must_fail git cherry-pick anotherpick &&\n+\ttest_must_fail git cherry-pick --abort 2>advice &&\n+\tgit cherry-pick --skip &&\n+\ttest_i18ncmp expect advice\n+'\n+\n+test_expect_success 'allow skipping stopped cherry-pick because of untracked file modifications' '\n+\tpristine_detach initial &&\n+\tgit rm --cached unrelated &&\n+\tgit commit -m \"untrack unrelated\" &&\n+\ttest_must_fail git cherry-pick initial base &&\n+\ttest_path_is_missing .git/CHERRY_PICK_HEAD &&\n+\tgit cherry-pick --skip\n+'\n+\n test_expect_success '--quit does not complain when no cherry-pick is in progress' '\n \tpristine_detach initial &&\n \tgit cherry-pick --quit\n-- \n2.21.0\n\n"},{"id":"377426","messageId":"20190618170650.22721-6-rohit.ashiwal265@gmail.com","threadId":"51269","inReplyTo":"20190618170650.22721-1-rohit.ashiwal265@gmail.com","subject":"[GSoC][PATCH v5 5/5] cherry-pick/revert: advise using --skip","fromName":"Rohit Ashiwal","fromEmail":"rohit.ashiwal265@gmail.com","sentAt":"2019-06-18T17:06:50Z","receivedAt":"2019-06-18T17:09:30Z","isPatch":true,"sender":{"key":"rohit.ashiwal265@gmail.com","avatar":"https://avatars.githubusercontent.com/u/31043830?v=4"},"body":"The previous commit introduced a --skip flag for cherry-pick and\nrevert. Update the advice messages, to tell users about this less\ncumbersome way of skipping commits. Also add tests to ensure\neverything is working fine.\n\nSigned-off-by: Rohit Ashiwal <rohit.ashiwal265@gmail.com>\n---\n builtin/commit.c                | 13 ++++++++-----\n sequencer.c                     | 11 ++++++++---\n t/t3510-cherry-pick-sequence.sh | 20 ++++++++++++++++++++\n 3 files changed, 36 insertions(+), 8 deletions(-)\n\ndiff --git a/builtin/commit.c b/builtin/commit.c\nindex 1c9e8e2228..1f47c51bdc 100644\n--- a/builtin/commit.c\n+++ b/builtin/commit.c\n@@ -60,15 +60,18 @@ N_(\"The previous cherry-pick is now empty, possibly due to conflict resolution.\\\n \"\\n\");\n \n static const char empty_cherry_pick_advice_single[] =\n-N_(\"Otherwise, please use 'git reset'\\n\");\n+N_(\"Otherwise, please use 'git cherry-pick --skip'\\n\");\n \n static const char empty_cherry_pick_advice_multi[] =\n-N_(\"If you wish to skip this commit, use:\\n\"\n+N_(\"and then use:\\n\"\n \"\\n\"\n-\"    git reset\\n\"\n+\"    git cherry-pick --continue\\n\"\n \"\\n\"\n-\"Then \\\"git cherry-pick --continue\\\" will resume cherry-picking\\n\"\n-\"the remaining commits.\\n\");\n+\"to resume cherry-picking the remaining commits.\\n\"\n+\"If you wish to skip this commit, use:\\n\"\n+\"\\n\"\n+\"    git cherry-pick --skip\\n\"\n+\"\\n\");\n \n static const char *color_status_slots[] = {\n \t[WT_STATUS_HEADER]\t  = \"header\",\ndiff --git a/sequencer.c b/sequencer.c\nindex 5720cd1c85..cc7f6219e7 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -2655,18 +2655,20 @@ static int create_seq_dir(struct repository *r)\n \tenum replay_action action;\n \tconst char *in_progress_error = NULL;\n \tconst char *in_progress_advice = NULL;\n+\tunsigned int advise_skip = file_exists(git_path_revert_head(r)) ||\n+\t\t\t\tfile_exists(git_path_cherry_pick_head(r));\n \n \tif (!sequencer_get_last_command(r, &action)) {\n \t\tswitch (action) {\n \t\tcase REPLAY_REVERT:\n \t\t\tin_progress_error = _(\"revert is already in progress\");\n \t\t\tin_progress_advice =\n-\t\t\t_(\"try \\\"git revert (--continue | --abort | --quit)\\\"\");\n+\t\t\t_(\"try \\\"git revert (--continue | %s--abort | --quit)\\\"\");\n \t\t\tbreak;\n \t\tcase REPLAY_PICK:\n \t\t\tin_progress_error = _(\"cherry-pick is already in progress\");\n \t\t\tin_progress_advice =\n-\t\t\t_(\"try \\\"git cherry-pick (--continue | --abort | --quit)\\\"\");\n+\t\t\t_(\"try \\\"git cherry-pick (--continue | %s--abort | --quit)\\\"\");\n \t\t\tbreak;\n \t\tdefault:\n \t\t\tBUG(\"unexpected action in create_seq_dir\");\n@@ -2674,7 +2676,10 @@ static int create_seq_dir(struct repository *r)\n \t}\n \tif (in_progress_error) {\n \t\terror(\"%s\", in_progress_error);\n-\t\tadvise(\"%s\", in_progress_advice);\n+\t\tif (advise_skip)\n+\t\t\tadvise(in_progress_advice, \"--skip | \");\n+\t\telse\n+\t\t\tadvise(in_progress_advice, \"\");\n \t\treturn -1;\n \t}\n \tif (mkdir(git_path_seq_dir(), 0777) < 0)\ndiff --git a/t/t3510-cherry-pick-sequence.sh b/t/t3510-cherry-pick-sequence.sh\nindex dc0ac8343c..0e8adc95fc 100755\n--- a/t/t3510-cherry-pick-sequence.sh\n+++ b/t/t3510-cherry-pick-sequence.sh\n@@ -172,6 +172,26 @@ test_expect_success 'check advice when we move HEAD by committing' '\n \ttest_i18ncmp expect advice\n '\n \n+test_expect_success 'selectively advise --skip while launching another sequence' '\n+\tpristine_detach initial &&\n+\tcat >expect <<-EOF &&\n+\terror: cherry-pick is already in progress\n+\thint: try \"git cherry-pick (--continue | --skip | --abort | --quit)\"\n+\tfatal: cherry-pick failed\n+\tEOF\n+\ttest_must_fail git cherry-pick picked..yetanotherpick &&\n+\ttest_must_fail git cherry-pick picked..yetanotherpick 2>advice &&\n+\ttest_i18ncmp expect advice &&\n+\tcat >expect <<-EOF &&\n+\terror: cherry-pick is already in progress\n+\thint: try \"git cherry-pick (--continue | --abort | --quit)\"\n+\tfatal: cherry-pick failed\n+\tEOF\n+\tgit reset --merge &&\n+\ttest_must_fail git cherry-pick picked..yetanotherpick 2>advice &&\n+\ttest_i18ncmp expect advice\n+'\n+\n test_expect_success 'allow skipping commit but not abort for a new history' '\n \tpristine_detach initial &&\n \tcat >expect <<-EOF &&\n-- \n2.21.0\n\n"},{"id":"377606","messageId":"xmqqr27oq5z1.fsf@gitster-ct.c.googlers.com","threadId":"51269","inReplyTo":"20190618170650.22721-5-rohit.ashiwal265@gmail.com","subject":"Re: [GSoC][PATCH v5 4/5] cherry-pick/revert: add --skip option","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-06-20T03:40:50Z","receivedAt":"2019-06-20T03:40:55Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Rohit Ashiwal <rohit.ashiwal265@gmail.com> writes:\n\n> +give_advice:\n> +\tadvise(_(\"have you committed already?\\n\"\n> +\t\t \"try \\\"git %s --continue\\\"\"),\n> +\t\t action == REPLAY_REVERT ? \"revert\" : \"cherry-pick\");\n> +\treturn error(_(\"there is nothing to skip\"));\n> +}\n\nTwo comments.\n\nThe places touched by patch 1/5 emitted the error followed by an\nadvice message; this new one breaks the pattern by giving the \"hint:\"\nfirst and then error.  Be consistent by swapping these two (and\nreturn -1, as \"error() that returns -1\" will no longer be the last\nthing executed in this function.\n\nThis one, and the in_progress_advice emitted from the patch 1/5, are\nboth bad in that they make calls to advise() without guarding it\nwith an advice.* configuration variable. This does not allow the\nuser to say say \"I've learned this part of Git enough; do not tell\nme verbosely.\"\n\nPick a random global variable that is defined near the top of\nadvice.c, and learn how they are set (to true by default, allowing\nconfiguration to flip it off) and how they are used in order to\nprevent a call to advise() getting made.  Then mimick that to guard\nthese calls to advise().\n\nThanks.\n"},{"id":"377636","messageId":"20190620094627.22401-1-rohit.ashiwal265@gmail.com","threadId":"51269","inReplyTo":"xmqqr27oq5z1.fsf@gitster-ct.c.googlers.com","subject":"Re: [GSoC][PATCH v5 4/5] cherry-pick/revert: add --skip option","fromName":"Rohit Ashiwal","fromEmail":"rohit.ashiwal265@gmail.com","sentAt":"2019-06-20T09:46:27Z","receivedAt":"2019-06-20T09:48:47Z","isPatch":true,"sender":{"key":"rohit.ashiwal265@gmail.com","avatar":"https://avatars.githubusercontent.com/u/31043830?v=4"},"body":"Hi Junio\n\nOn Wed, 19 Jun 2019 20:40:50 -0700 Junio C Hamano <gitster@pobox.com> wrote:\n>\n> Two comments.\n>\n> The places touched by patch 1/5 emitted the error followed by an\n> advice message; this new one breaks the pattern by giving the \"hint:\"\n> first and then error.  Be consistent by swapping these two (and\n> return -1, as \"error() that returns -1\" will no longer be the last\n> thing executed in this function.\n\nYes, it also makes sense otherwise, but this will be more consistent.\n\n> This one, and the in_progress_advice emitted from the patch 1/5, are\n> both bad in that they make calls to advise() without guarding it\n> with an advice.* configuration variable. This does not allow the\n> user to say say \"I've learned this part of Git enough; do not tell\n> me verbosely.\"\n\nOh~ I was missing this point from the start. I'll make proper changes\nto my patch.\n\n> Pick a random global variable that is defined near the top of\n> advice.c, and learn how they are set (to true by default, allowing\n> configuration to flip it off) and how they are used in order to\n> prevent a call to advise() getting made.  Then mimick that to guard\n> these calls to advise().\n\nOk, I'll look into it and change accordingly.\n\n> Thanks.\n\nThanks\nRohit\n\n"},{"id":"377642","messageId":"76359a86-0eb1-dd87-c36f-7bd2df8b0ae5@gmail.com","threadId":"51269","inReplyTo":"xmqqr27oq5z1.fsf@gitster-ct.c.googlers.com","subject":"Re: [GSoC][PATCH v5 4/5] cherry-pick/revert: add --skip option","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2019-06-20T09:57:44Z","receivedAt":"2019-06-20T09:57:49Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"On 20/06/2019 04:40, Junio C Hamano wrote:\n> Rohit Ashiwal <rohit.ashiwal265@gmail.com> writes:\n> \n>> +give_advice:\n>> +\tadvise(_(\"have you committed already?\\n\"\n>> +\t\t \"try \\\"git %s --continue\\\"\"),\n>> +\t\t action == REPLAY_REVERT ? \"revert\" : \"cherry-pick\");\n>> +\treturn error(_(\"there is nothing to skip\"));\n>> +}\n> \n> Two comments.\n> \n> The places touched by patch 1/5 emitted the error followed by an\n> advice message; this new one breaks the pattern by giving the \"hint:\"\n> first and then error.  Be consistent by swapping these two (and\n> return -1, as \"error() that returns -1\" will no longer be the last\n> thing executed in this function.\n> \n> This one, and the in_progress_advice emitted from the patch 1/5, are\n> both bad in that they make calls to advise() without guarding it\n> with an advice.* configuration variable.\n\nI'm not sure we have one for cherry-pick/revert/rebase. At the moment \nthey print advice advice for a failed pick unconditionally (the caller \nof `print_advice()` sets `show_hint` based on the result of the merge \nrather than user preference) it would be nice to fix that. Maybe that \nshould be checking advice.resolveConflict though. I'm also not sure if \nthat is really within the scope of this patch series.\n\nBest Wishes\n\nPhillip\n\n\n> This does not allow the\n> user to say say \"I've learned this part of Git enough; do not tell\n> me verbosely.\"\n> \n> Pick a random global variable that is defined near the top of\n> advice.c, and learn how they are set (to true by default, allowing\n> configuration to flip it off) and how they are used in order to\n> prevent a call to advise() getting made.  Then mimick that to guard\n> these calls to advise().\n> \n> Thanks.\n> \n"},{"id":"377643","messageId":"0047b8c6-8a58-7546-2ae8-19c4ab668fa3@gmail.com","threadId":"51269","inReplyTo":"20190618170650.22721-5-rohit.ashiwal265@gmail.com","subject":"Re: [GSoC][PATCH v5 4/5] cherry-pick/revert: add --skip option","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2019-06-20T10:02:22Z","receivedAt":"2019-06-20T10:02:29Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"Hi Rohit\n\nOn 18/06/2019 18:06, Rohit Ashiwal wrote:\n> git am or rebase have a --skip flag to skip the current commit if the\n> user wishes to do so. During a cherry-pick or revert a user could\n> likewise skip a commit, but needs to use 'git reset' (or in the case\n> of conflicts 'git reset --merge'), followed by 'git (cherry-pick |\n> revert) --continue' to skip the commit. This is more annoying and\n> sometimes confusing on the users' part. Add a `--skip` option to make\n> skipping commits easier for the user and to make the commands more\n> consistent.\n> \n> In the next commit, we will change the advice messages hence finishing\n> the process of teaching revert and cherry-pick \"how to skip commits\".\n> \n> Signed-off-by: Rohit Ashiwal <rohit.ashiwal265@gmail.com>\n> ---\n>   Documentation/git-cherry-pick.txt |   4 +-\n>   Documentation/git-revert.txt      |   4 +-\n>   Documentation/sequencer.txt       |   4 ++\n>   builtin/revert.c                  |   5 ++\n>   sequencer.c                       |  69 ++++++++++++++++++++\n>   sequencer.h                       |   1 +\n>   t/t3510-cherry-pick-sequence.sh   | 102 ++++++++++++++++++++++++++++++\n>   7 files changed, 183 insertions(+), 6 deletions(-)\n> \n> diff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt\n> index 754b16ce0c..83ce51aedf 100644\n> --- a/Documentation/git-cherry-pick.txt\n> +++ b/Documentation/git-cherry-pick.txt\n> @@ -10,9 +10,7 @@ SYNOPSIS\n>   [verse]\n>   'git cherry-pick' [--edit] [-n] [-m parent-number] [-s] [-x] [--ff]\n>   \t\t  [-S[<keyid>]] <commit>...\n> -'git cherry-pick' --continue\n> -'git cherry-pick' --quit\n> -'git cherry-pick' --abort\n> +'git cherry-pick' (--continue | --skip | --abort | --quit)\n>   \n>   DESCRIPTION\n>   -----------\n> diff --git a/Documentation/git-revert.txt b/Documentation/git-revert.txt\n> index 0c82ca5bc0..665e065ee3 100644\n> --- a/Documentation/git-revert.txt\n> +++ b/Documentation/git-revert.txt\n> @@ -9,9 +9,7 @@ SYNOPSIS\n>   --------\n>   [verse]\n>   'git revert' [--[no-]edit] [-n] [-m parent-number] [-s] [-S[<keyid>]] <commit>...\n> -'git revert' --continue\n> -'git revert' --quit\n> -'git revert' --abort\n> +'git revert' (--continue | --skip | --abort | --quit)\n>   \n>   DESCRIPTION\n>   -----------\n> diff --git a/Documentation/sequencer.txt b/Documentation/sequencer.txt\n> index 5a57c4a407..3bceb56474 100644\n> --- a/Documentation/sequencer.txt\n> +++ b/Documentation/sequencer.txt\n> @@ -3,6 +3,10 @@\n>   \t`.git/sequencer`.  Can be used to continue after resolving\n>   \tconflicts in a failed cherry-pick or revert.\n>   \n> +--skip::\n> +\tSkip the current commit and continue with the rest of the\n> +\tsequence.\n> +\n>   --quit::\n>   \tForget about the current operation in progress.  Can be used\n>   \tto clear the sequencer state after a failed cherry-pick or\n> diff --git a/builtin/revert.c b/builtin/revert.c\n> index d4dcedbdc6..5dc5891ea2 100644\n> --- a/builtin/revert.c\n> +++ b/builtin/revert.c\n> @@ -102,6 +102,7 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)\n>   \t\tOPT_CMDMODE(0, \"quit\", &cmd, N_(\"end revert or cherry-pick sequence\"), 'q'),\n>   \t\tOPT_CMDMODE(0, \"continue\", &cmd, N_(\"resume revert or cherry-pick sequence\"), 'c'),\n>   \t\tOPT_CMDMODE(0, \"abort\", &cmd, N_(\"cancel revert or cherry-pick sequence\"), 'a'),\n> +\t\tOPT_CMDMODE(0, \"skip\", &cmd, N_(\"skip current commit and continue\"), 's'),\n>   \t\tOPT_CLEANUP(&cleanup_arg),\n>   \t\tOPT_BOOL('n', \"no-commit\", &opts->no_commit, N_(\"don't automatically commit\")),\n>   \t\tOPT_BOOL('e', \"edit\", &opts->edit, N_(\"edit the commit message\")),\n> @@ -151,6 +152,8 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)\n>   \t\t\tthis_operation = \"--quit\";\n>   \t\telse if (cmd == 'c')\n>   \t\t\tthis_operation = \"--continue\";\n> +\t\telse if (cmd == 's')\n> +\t\t\tthis_operation = \"--skip\";\n>   \t\telse {\n>   \t\t\tassert(cmd == 'a');\n>   \t\t\tthis_operation = \"--abort\";\n> @@ -210,6 +213,8 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)\n>   \t\treturn sequencer_continue(the_repository, opts);\n>   \tif (cmd == 'a')\n>   \t\treturn sequencer_rollback(the_repository, opts);\n> +\tif (cmd == 's')\n> +\t\treturn sequencer_skip(the_repository, opts);\n>   \treturn sequencer_pick_revisions(the_repository, opts);\n>   }\n>   \n> diff --git a/sequencer.c b/sequencer.c\n> index 6762a5f485..5720cd1c85 100644\n> --- a/sequencer.c\n> +++ b/sequencer.c\n> @@ -2761,6 +2761,15 @@ static int rollback_single_pick(struct repository *r)\n>   \treturn reset_merge(&head_oid);\n>   }\n>   \n> +static int skip_single_pick(void)\n> +{\n> +\tstruct object_id head;\n> +\n> +\tif (read_ref_full(\"HEAD\", 0, &head, NULL))\n> +\t\treturn error(_(\"cannot resolve HEAD\"));\n> +\treturn reset_merge(&head);\n> +}\n> +\n>   int sequencer_rollback(struct repository *r, struct replay_opts *opts)\n>   {\n>   \tFILE *f;\n> @@ -2810,6 +2819,66 @@ int sequencer_rollback(struct repository *r, struct replay_opts *opts)\n>   \treturn -1;\n>   }\n>   \n> +int sequencer_skip(struct repository *r, struct replay_opts *opts)\n> +{\n> +\tenum replay_action action = -1;\n> +\tsequencer_get_last_command(r, &action);\n> +\n> +\t/*\n> +\t * Check whether the subcommand requested to skip the commit is actually\n> +\t * in progress and that it's safe to skip the commit.\n> +\t *\n> +\t * opts->action tells us which subcommand requested to skip the commit.\n> +\t * If the corresponding .git/<ACTION>_HEAD exists, we know that the\n> +\t * action is in progress and we can skip the commit.\n> +\t *\n> +\t * Otherwise we check that the last instruction was related to the\n> +\t * particular subcommand we're trying to execute and barf if that's not\n> +\t * the case.\n> +\t *\n> +\t * Finally we check that the rollback is \"safe\", i.e., has the HEAD\n> +\t * moved? In this case, it doesn't make sense to \"reset the merge\" and\n> +\t * \"skip the commit\" as the user already handled this by committing. But\n> +\t * we'd not want to barf here, instead give advice on how to proceed. We\n> +\t * only need to check that when .git/<ACTION>_HEAD doesn't exist because\n> +\t * it gets removed when the user commits, so if it still exists we're\n> +\t * sure the user can't have committed before.\n> +\t */\n\nThanks for updating the comment, I think it is easier to follow now \n(Thanks to Thomas for suggesting it as well)\n\n> +\tswitch (opts->action) {\n> +\tcase REPLAY_REVERT:\n> +\t\tif (!file_exists(git_path_revert_head(r))) {\n> +\t\t\tif (action != REPLAY_REVERT)\n> +\t\t\t\treturn error(_(\"no revert in progress\"));\n> +\t\t\tif (!rollback_is_safe())\n> +\t\t\t\tgoto give_advice;\n> +\t\t}\n> +\t\tbreak;\n> +\tcase REPLAY_PICK:\n> +\t\tif (!file_exists(git_path_cherry_pick_head(r))) {\n> +\t\t\tif (action != REPLAY_PICK)\n> +\t\t\t\treturn error(_(\"no cherry-pick in progress\"));\n> +\t\t\tif (!rollback_is_safe())\n> +\t\t\t\tgoto give_advice;\n> +\t\t}\n> +\t\tbreak;\n> +\tdefault:\n> +\t\tBUG(\"unexpected action in sequencer_skip\");\n> +\t}\n> +\n> +\tif (skip_single_pick())\n> +\t\treturn error(_(\"failed to skip the commit\"));\n> +\tif (!is_directory(git_path_seq_dir()))\n> +\t\treturn 0;\n> +\n> +\treturn sequencer_continue(r, opts);\n> +\n> +give_advice:\n> +\tadvise(_(\"have you committed already?\\n\"\n> +\t\t \"try \\\"git %s --continue\\\"\"),\n> +\t\t action == REPLAY_REVERT ? \"revert\" : \"cherry-pick\");\n> +\treturn error(_(\"there is nothing to skip\"));\n> +}\n> +\n>   static int save_todo(struct todo_list *todo_list, struct replay_opts *opts)\n>   {\n>   \tstruct lock_file todo_lock = LOCK_INIT;\n> diff --git a/sequencer.h b/sequencer.h\n> index 0c494b83d4..731b9853eb 100644\n> --- a/sequencer.h\n> +++ b/sequencer.h\n> @@ -129,6 +129,7 @@ int sequencer_pick_revisions(struct repository *repo,\n>   \t\t\t     struct replay_opts *opts);\n>   int sequencer_continue(struct repository *repo, struct replay_opts *opts);\n>   int sequencer_rollback(struct repository *repo, struct replay_opts *opts);\n> +int sequencer_skip(struct repository *repo, struct replay_opts *opts);\n>   int sequencer_remove_state(struct replay_opts *opts);\n>   \n>   #define TODO_LIST_KEEP_EMPTY (1U << 0)\n> diff --git a/t/t3510-cherry-pick-sequence.sh b/t/t3510-cherry-pick-sequence.sh\n> index 941d5026da..dc0ac8343c 100755\n> --- a/t/t3510-cherry-pick-sequence.sh\n> +++ b/t/t3510-cherry-pick-sequence.sh\n> @@ -93,6 +93,108 @@ test_expect_success 'cherry-pick cleans up sequencer state upon success' '\n>   \ttest_path_is_missing .git/sequencer\n>   '\n>   \n> +test_expect_success 'cherry-pick --skip requires cherry-pick in progress' '\n> +\tpristine_detach initial &&\n> +\ttest_must_fail git cherry-pick --skip\n> +'\n> +\n> +test_expect_success 'revert --skip requires revert in progress' '\n> +\tpristine_detach initial &&\n> +\ttest_must_fail git revert --skip\n> +'\n> +\n> +test_expect_success 'cherry-pick --skip to skip commit' '\n> +\tpristine_detach initial &&\n> +\ttest_must_fail git cherry-pick anotherpick &&\n> +\ttest_must_fail git revert --skip &&\n> +\tgit cherry-pick --skip &&\n> +\ttest_cmp_rev initial HEAD &&\n> +\ttest_path_is_missing .git/CHERRY_PICK_HEAD\n> +'\n> +\n> +test_expect_success 'revert --skip to skip commit' '\n> +\tpristine_detach anotherpick &&\n> +\ttest_must_fail git revert anotherpick~1 &&\n> +\ttest_must_fail git cherry-pick --skip &&\n> +\tgit revert --skip &&\n> +\ttest_cmp_rev anotherpick HEAD\n> +'\n> +\n> +test_expect_success 'skip \"empty\" commit' '\n> +\tpristine_detach picked &&\n> +\ttest_commit dummy foo d &&\n> +\ttest_must_fail git cherry-pick anotherpick &&\n> +\tgit cherry-pick --skip &&\n> +\ttest_cmp_rev dummy HEAD\n> +'\n> +\n> +test_expect_success 'skip a commit and check if rest of sequence is correct' '\n> +\tpristine_detach initial &&\n> +\techo e >expect &&\n> +\tcat >expect.log <<-EOF &&\n> +\tOBJID\n> +\t:100644 100644 OBJID OBJID M\tfoo\n> +\tOBJID\n> +\t:100644 100644 OBJID OBJID M\tfoo\n> +\tOBJID\n> +\t:100644 100644 OBJID OBJID M\tunrelated\n> +\tOBJID\n> +\t:000000 100644 OBJID OBJID A\tfoo\n> +\t:000000 100644 OBJID OBJID A\tunrelated\n> +\tEOF\n> +\ttest_must_fail git cherry-pick base..yetanotherpick &&\n> +\ttest_must_fail git cherry-pick --skip &&\n> +\techo d >foo &&\n> +\tgit add foo &&\n> +\tgit cherry-pick --continue &&\n> +\t{\n> +\t\tgit rev-list HEAD |\n> +\t\tgit diff-tree --root --stdin |\n> +\t\tsed \"s/$OID_REGEX/OBJID/g\"\n> +\t} >actual.log &&\n> +\ttest_cmp expect foo &&\n> +\ttest_cmp expect.log actual.log\n> +'\n> +\n> +test_expect_success 'check advice when we move HEAD by committing' '\n> +\tpristine_detach initial &&\n> +\tcat >expect <<-EOF &&\n> +\thint: have you committed already?\n> +\thint: try \"git cherry-pick --continue\"\n> +\terror: there is nothing to skip\n> +\tfatal: cherry-pick failed\n> +\tEOF\n> +\ttest_must_fail git cherry-pick base..yetanotherpick &&\n> +\techo c >foo &&\n> +\tgit commit -a &&\n> +\ttest_path_is_missing .git/CHERRY_PICK_HEAD &&\n> +\ttest_must_fail git cherry-pick --skip 2>advice &&\n> +\ttest_i18ncmp expect advice\n> +'\n> +\n> +test_expect_success 'allow skipping commit but not abort for a new history' '\n> +\tpristine_detach initial &&\n> +\tcat >expect <<-EOF &&\n> +\terror: cannot abort from a branch yet to be born\n> +\tfatal: cherry-pick failed\n> +\tEOF\n> +\tgit checkout --orphan new_disconnected &&\n> +\tgit reset --hard &&\n> +\ttest_must_fail git cherry-pick anotherpick &&\n> +\ttest_must_fail git cherry-pick --abort 2>advice &&\n> +\tgit cherry-pick --skip &&\n> +\ttest_i18ncmp expect advice\n> +'\n> +\n> +test_expect_success 'allow skipping stopped cherry-pick because of untracked file modifications' '\n> +\tpristine_detach initial &&\n> +\tgit rm --cached unrelated &&\n> +\tgit commit -m \"untrack unrelated\" &&\n> +\ttest_must_fail git cherry-pick initial base &&\n> +\ttest_path_is_missing .git/CHERRY_PICK_HEAD &&\n> +\tgit cherry-pick --skip\n\nIf you change this to --continue rather than --skip the test also \npasses! I think we could fix this by checking if HEAD has changed if \nCHERRY_PICK_HEAD/REVERT_HEAD is missing and not dropping the last \ncommand in the todo list in that case when we continue.\n\nBest Wishes\n\nPhillip\n\n> +'\n> +\n>   test_expect_success '--quit does not complain when no cherry-pick is in progress' '\n>   \tpristine_detach initial &&\n>   \tgit cherry-pick --quit\n> \n"},{"id":"377648","messageId":"20190620103401.29654-1-rohit.ashiwal265@gmail.com","threadId":"51269","inReplyTo":"0047b8c6-8a58-7546-2ae8-19c4ab668fa3@gmail.com","subject":"Re: [GSoC][PATCH v5 4/5] cherry-pick/revert: add --skip option","fromName":"Rohit Ashiwal","fromEmail":"rohit.ashiwal265@gmail.com","sentAt":"2019-06-20T10:34:01Z","receivedAt":"2019-06-20T10:36:20Z","isPatch":true,"sender":{"key":"rohit.ashiwal265@gmail.com","avatar":"https://avatars.githubusercontent.com/u/31043830?v=4"},"body":"Hi Phillip\n\nOn 2019-06-20 10:02 UTC Phillip Wood <phillip.wood123@gmail.com> wrote:\n>\n> > +test_expect_success 'allow skipping stopped cherry-pick because of untracked file modifications' '\n> > +\tpristine_detach initial &&\n> > +\tgit rm --cached unrelated &&\n> > +\tgit commit -m \"untrack unrelated\" &&\n> > +\ttest_must_fail git cherry-pick initial base &&\n> > +\ttest_path_is_missing .git/CHERRY_PICK_HEAD &&\n> > +\tgit cherry-pick --skip\n>\n> If you change this to --continue rather than --skip the test also\n> passes! I think we could fix this by checking if HEAD has changed if\n> CHERRY_PICK_HEAD/REVERT_HEAD is missing and not dropping the last\n> command in the todo list in that case when we continue.\n\nI don't think I fully understood this. At this point --skip is essentially\n--continue. How is checking unmoved HEAD and unchanged todo uniquely related\nto --skip flag (or for that matter any _flag_)?\n\nThanks\nRohit\n\n"},{"id":"377651","messageId":"b6cf26b0-51b7-0c63-fb1c-4da1eb3666cb@gmail.com","threadId":"51269","inReplyTo":"20190620103401.29654-1-rohit.ashiwal265@gmail.com","subject":"Re: [GSoC][PATCH v5 4/5] cherry-pick/revert: add --skip option","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2019-06-20T11:42:52Z","receivedAt":"2019-06-20T11:42:58Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"Hi Rohit\n\nOn 20/06/2019 11:34, Rohit Ashiwal wrote:\n> Hi Phillip\n> \n> On 2019-06-20 10:02 UTC Phillip Wood <phillip.wood123@gmail.com> wrote:\n>>\n>>> +test_expect_success 'allow skipping stopped cherry-pick because of untracked file modifications' '\n>>> +\tpristine_detach initial &&\n>>> +\tgit rm --cached unrelated &&\n>>> +\tgit commit -m \"untrack unrelated\" &&\n>>> +\ttest_must_fail git cherry-pick initial base &&\n>>> +\ttest_path_is_missing .git/CHERRY_PICK_HEAD &&\n>>> +\tgit cherry-pick --skip\n>>\n>> If you change this to --continue rather than --skip the test also\n>> passes! I think we could fix this by checking if HEAD has changed if\n>> CHERRY_PICK_HEAD/REVERT_HEAD is missing and not dropping the last\n>> command in the todo list in that case when we continue.\n> \n> I don't think I fully understood this. At this point --skip is essentially\n> --continue. How is checking unmoved HEAD and unchanged todo uniquely related\n> to --skip flag (or for that matter any _flag_)?\n\nMy point is that --continue should reschedule the failed pick and try to \npick it again - it should not silently skip a failed pick and  --skip \nshould skip it.\n\nBest Wishes\n\nPhillip\n> \n> Thanks\n> Rohit\n> \n"},{"id":"377696","messageId":"xmqqimt0m31x.fsf@gitster-ct.c.googlers.com","threadId":"51269","inReplyTo":"76359a86-0eb1-dd87-c36f-7bd2df8b0ae5@gmail.com","subject":"Re: [GSoC][PATCH v5 4/5] cherry-pick/revert: add --skip option","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-06-20T20:09:46Z","receivedAt":"2019-06-20T20:09:51Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Phillip Wood <phillip.wood123@gmail.com> writes:\n\n>> This one, and the in_progress_advice emitted from the patch 1/5, are\n>> both bad in that they make calls to advise() without guarding it\n>> with an advice.* configuration variable.\n>\n> I'm not sure we have one for cherry-pick/revert/rebase. At the moment\n> they print advice advice for a failed pick unconditionally...\n\nYes, 1/5 does not introduce a new problem; it just makes it worse by\nallowing the misdesign survive another update.  The one introduced\nby 4/5 is genuinely new.\n\n> ... Maybe that\n> should be checking advice.resolveConflict though.\n\nI think that is a sensible one, rather than inventing a new knob.\n\n"},{"id":"377718","messageId":"20190621074704.6870-1-rohit.ashiwal265@gmail.com","threadId":"51269","inReplyTo":"b6cf26b0-51b7-0c63-fb1c-4da1eb3666cb@gmail.com","subject":"Re: [GSoC][PATCH v5 4/5] cherry-pick/revert: add --skip option","fromName":"Rohit Ashiwal","fromEmail":"rohit.ashiwal265@gmail.com","sentAt":"2019-06-21T07:47:04Z","receivedAt":"2019-06-21T07:49:28Z","isPatch":true,"sender":{"key":"rohit.ashiwal265@gmail.com","avatar":"https://avatars.githubusercontent.com/u/31043830?v=4"},"body":"Hi Phillip\n\nOn 2019-06-20 11:42 UTC Phillip Wood <phillip.wood123@gmail.com> wrote:\n>\n> Hi Rohit\n>\n> On 20/06/2019 11:34, Rohit Ashiwal wrote:\n>> Hi Phillip\n>>\n>> On 2019-06-20 10:02 UTC Phillip Wood <phillip.wood123@gmail.com> wrote:\n>>>\n>>>> +test_expect_success 'allow skipping stopped cherry-pick because of untracked file modifications' '\n>>>> +\tpristine_detach initial &&\n>>>> +\tgit rm --cached unrelated &&\n>>>> +\tgit commit -m \"untrack unrelated\" &&\n>>>> +\ttest_must_fail git cherry-pick initial base &&\n>>>> +\ttest_path_is_missing .git/CHERRY_PICK_HEAD &&\n>>>> +\tgit cherry-pick --skip\n>>>\n>>> If you change this to --continue rather than --skip the test also\n>>> passes! I think we could fix this by checking if HEAD has changed if\n>>> CHERRY_PICK_HEAD/REVERT_HEAD is missing and not dropping the last\n>>> command in the todo list in that case when we continue.\n>>\n>> I don't think I fully understood this. At this point --skip is essentially\n>> --continue. How is checking unmoved HEAD and unchanged todo uniquely related\n>> to --skip flag (or for that matter any _flag_)?\n>\n> My point is that --continue should reschedule the failed pick and try to\n> pick it again - it should not silently skip a failed pick and  --skip\n> should skip it.\n\nSo, this is a flaw in the --continue, I guess? Fixing that is beyond the\nscope of this patch. May be we can launch another series in which we fix\nthis and decouple skip and continue?\n\nThanks\nRohit\n\n"},{"id":"377722","messageId":"20190621091800.17686-1-rohit.ashiwal265@gmail.com","threadId":"51269","inReplyTo":"20190608191958.4593-1-rohit.ashiwal265@gmail.com","subject":"[GSoC][PATCH v6 0/5] Teach cherry-pick/revert to skip commits","fromName":"Rohit Ashiwal","fromEmail":"rohit.ashiwal265@gmail.com","sentAt":"2019-06-21T09:17:55Z","receivedAt":"2019-06-21T09:20:23Z","isPatch":true,"sender":{"key":"rohit.ashiwal265@gmail.com","avatar":"https://avatars.githubusercontent.com/u/31043830?v=4"},"body":"I've covered the advice message behind `advice_resolve_conflict` variable and\nchanged the order of error and advice to match that of 1/5. I believe that we\ndon't have any advice variable appropriate for advice in 1/5.\n\nRohit Ashiwal (5):\n  sequencer: add advice for revert\n  sequencer: rename reset_for_rollback to reset_merge\n  sequencer: use argv_array in reset_merge\n  cherry-pick/revert: add --skip option\n  cherry-pick/revert: advise using --skip\n\n Documentation/git-cherry-pick.txt |   4 +-\n Documentation/git-revert.txt      |   4 +-\n Documentation/sequencer.txt       |   4 +\n builtin/commit.c                  |  13 +--\n builtin/revert.c                  |   5 ++\n sequencer.c                       | 135 ++++++++++++++++++++++++++----\n sequencer.h                       |   1 +\n t/t3510-cherry-pick-sequence.sh   | 122 +++++++++++++++++++++++++++\n 8 files changed, 262 insertions(+), 26 deletions(-)\n\nRange-diff:\n1:  825486c22d ! 1:  2b16d7ea4d cherry-pick/revert: add --skip option\n    @@ -168,10 +168,14 @@\n     +\treturn sequencer_continue(r, opts);\n     +\n     +give_advice:\n    -+\tadvise(_(\"have you committed already?\\n\"\n    -+\t\t \"try \\\"git %s --continue\\\"\"),\n    -+\t\t action == REPLAY_REVERT ? \"revert\" : \"cherry-pick\");\n    -+\treturn error(_(\"there is nothing to skip\"));\n    ++\terror(_(\"there is nothing to skip\"));\n    ++\n    ++\tif (advice_resolve_conflict) {\n    ++\t\tadvise(_(\"have you committed already?\\n\"\n    ++\t\t\t \"try \\\"git %s --continue\\\"\"),\n    ++\t\t\t action == REPLAY_REVERT ? \"revert\" : \"cherry-pick\");\n    ++\t}\n    ++\treturn -1;\n     +}\n     +\n      static int save_todo(struct todo_list *todo_list, struct replay_opts *opts)\n    @@ -263,9 +267,9 @@\n     +test_expect_success 'check advice when we move HEAD by committing' '\n     +\tpristine_detach initial &&\n     +\tcat >expect <<-EOF &&\n    ++\terror: there is nothing to skip\n     +\thint: have you committed already?\n     +\thint: try \"git cherry-pick --continue\"\n    -+\terror: there is nothing to skip\n     +\tfatal: cherry-pick failed\n     +\tEOF\n     +\ttest_must_fail git cherry-pick base..yetanotherpick &&\n2:  63dbc11ab1 = 2:  8f278b5139 cherry-pick/revert: advise using --skip\n-- \n2.21.0\n\n"},{"id":"377723","messageId":"20190621091800.17686-2-rohit.ashiwal265@gmail.com","threadId":"51269","inReplyTo":"20190621091800.17686-1-rohit.ashiwal265@gmail.com","subject":"[GSoC][PATCH v6 1/5] sequencer: add advice for revert","fromName":"Rohit Ashiwal","fromEmail":"rohit.ashiwal265@gmail.com","sentAt":"2019-06-21T09:17:56Z","receivedAt":"2019-06-21T09:20:27Z","isPatch":true,"sender":{"key":"rohit.ashiwal265@gmail.com","avatar":"https://avatars.githubusercontent.com/u/31043830?v=4"},"body":"In the case of merge conflicts, while performing a revert, we are\ncurrently advised to use `git cherry-pick --<sequencer-options>`\nof which --continue is incompatible for continuing the revert.\nIntroduce a separate advice message for `git revert`. Also change\nthe signature of `create_seq_dir` to handle which advice to display\nselectively.\n\nSigned-off-by: Rohit Ashiwal <rohit.ashiwal265@gmail.com>\n---\n sequencer.c | 34 ++++++++++++++++++++++++++++------\n 1 file changed, 28 insertions(+), 6 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex f88a97fb10..c644368b54 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -2650,15 +2650,37 @@ static int walk_revs_populate_todo(struct todo_list *todo_list,\n \treturn 0;\n }\n \n-static int create_seq_dir(void)\n+static int create_seq_dir(struct repository *r)\n {\n-\tif (file_exists(git_path_seq_dir())) {\n-\t\terror(_(\"a cherry-pick or revert is already in progress\"));\n-\t\tadvise(_(\"try \\\"git cherry-pick (--continue | --quit | --abort)\\\"\"));\n+\tenum replay_action action;\n+\tconst char *in_progress_error = NULL;\n+\tconst char *in_progress_advice = NULL;\n+\n+\tif (!sequencer_get_last_command(r, &action)) {\n+\t\tswitch (action) {\n+\t\tcase REPLAY_REVERT:\n+\t\t\tin_progress_error = _(\"revert is already in progress\");\n+\t\t\tin_progress_advice =\n+\t\t\t_(\"try \\\"git revert (--continue | --abort | --quit)\\\"\");\n+\t\t\tbreak;\n+\t\tcase REPLAY_PICK:\n+\t\t\tin_progress_error = _(\"cherry-pick is already in progress\");\n+\t\t\tin_progress_advice =\n+\t\t\t_(\"try \\\"git cherry-pick (--continue | --abort | --quit)\\\"\");\n+\t\t\tbreak;\n+\t\tdefault:\n+\t\t\tBUG(\"unexpected action in create_seq_dir\");\n+\t\t}\n+\t}\n+\tif (in_progress_error) {\n+\t\terror(\"%s\", in_progress_error);\n+\t\tadvise(\"%s\", in_progress_advice);\n \t\treturn -1;\n-\t} else if (mkdir(git_path_seq_dir(), 0777) < 0)\n+\t}\n+\tif (mkdir(git_path_seq_dir(), 0777) < 0)\n \t\treturn error_errno(_(\"could not create sequencer directory '%s'\"),\n \t\t\t\t   git_path_seq_dir());\n+\n \treturn 0;\n }\n \n@@ -4237,7 +4259,7 @@ int sequencer_pick_revisions(struct repository *r,\n \t */\n \n \tif (walk_revs_populate_todo(&todo_list, opts) ||\n-\t\t\tcreate_seq_dir() < 0)\n+\t\t\tcreate_seq_dir(r) < 0)\n \t\treturn -1;\n \tif (get_oid(\"HEAD\", &oid) && (opts->action == REPLAY_REVERT))\n \t\treturn error(_(\"can't revert as initial commit\"));\n-- \n2.21.0\n\n"},{"id":"377724","messageId":"20190621091800.17686-3-rohit.ashiwal265@gmail.com","threadId":"51269","inReplyTo":"20190621091800.17686-1-rohit.ashiwal265@gmail.com","subject":"[GSoC][PATCH v6 2/5] sequencer: rename reset_for_rollback to reset_merge","fromName":"Rohit Ashiwal","fromEmail":"rohit.ashiwal265@gmail.com","sentAt":"2019-06-21T09:17:57Z","receivedAt":"2019-06-21T09:20:31Z","isPatch":true,"sender":{"key":"rohit.ashiwal265@gmail.com","avatar":"https://avatars.githubusercontent.com/u/31043830?v=4"},"body":"We are on a path to teach cherry-pick/revert how to skip commits. To\nachieve this, we could really make use of existing functions.\nreset_for_rollback is one such function, but the name does not\nintuitively suggest to use it to reset a merge, which it was born to\nperform see 539047c (\"revert: introduce --abort to cancel a failed\ncherry-pick\", 2011-11-23). Change the name to reset_merge to make\nit more intuitive.\n\nSigned-off-by: Rohit Ashiwal <rohit.ashiwal265@gmail.com>\n---\n sequencer.c | 6 +++---\n 1 file changed, 3 insertions(+), 3 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex c644368b54..12f2605ded 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -2731,7 +2731,7 @@ static int rollback_is_safe(void)\n \treturn oideq(&actual_head, &expected_head);\n }\n \n-static int reset_for_rollback(const struct object_id *oid)\n+static int reset_merge(const struct object_id *oid)\n {\n \tconst char *argv[4];\t/* reset --merge <arg> + NULL */\n \n@@ -2753,7 +2753,7 @@ static int rollback_single_pick(struct repository *r)\n \t\treturn error(_(\"cannot resolve HEAD\"));\n \tif (is_null_oid(&head_oid))\n \t\treturn error(_(\"cannot abort from a branch yet to be born\"));\n-\treturn reset_for_rollback(&head_oid);\n+\treturn reset_merge(&head_oid);\n }\n \n int sequencer_rollback(struct repository *r, struct replay_opts *opts)\n@@ -2796,7 +2796,7 @@ int sequencer_rollback(struct repository *r, struct replay_opts *opts)\n \t\twarning(_(\"You seem to have moved HEAD. \"\n \t\t\t  \"Not rewinding, check your HEAD!\"));\n \t} else\n-\tif (reset_for_rollback(&oid))\n+\tif (reset_merge(&oid))\n \t\tgoto fail;\n \tstrbuf_release(&buf);\n \treturn sequencer_remove_state(opts);\n-- \n2.21.0\n\n"},{"id":"377725","messageId":"20190621091800.17686-4-rohit.ashiwal265@gmail.com","threadId":"51269","inReplyTo":"20190621091800.17686-1-rohit.ashiwal265@gmail.com","subject":"[GSoC][PATCH v6 3/5] sequencer: use argv_array in reset_merge","fromName":"Rohit Ashiwal","fromEmail":"rohit.ashiwal265@gmail.com","sentAt":"2019-06-21T09:17:58Z","receivedAt":"2019-06-21T09:20:36Z","isPatch":true,"sender":{"key":"rohit.ashiwal265@gmail.com","avatar":"https://avatars.githubusercontent.com/u/31043830?v=4"},"body":"Avoid using magic numbers for array size and index under `reset_merge`\nfunction. Use `argv_array` instead. This will make code shorter and\neasier to extend.\n\nSigned-off-by: Rohit Ashiwal <rohit.ashiwal265@gmail.com>\n---\n sequencer.c | 17 +++++++++++------\n 1 file changed, 11 insertions(+), 6 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 12f2605ded..6762a5f485 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -2733,13 +2733,18 @@ static int rollback_is_safe(void)\n \n static int reset_merge(const struct object_id *oid)\n {\n-\tconst char *argv[4];\t/* reset --merge <arg> + NULL */\n+\tint ret;\n+\tstruct argv_array argv = ARGV_ARRAY_INIT;\n \n-\targv[0] = \"reset\";\n-\targv[1] = \"--merge\";\n-\targv[2] = oid_to_hex(oid);\n-\targv[3] = NULL;\n-\treturn run_command_v_opt(argv, RUN_GIT_CMD);\n+\targv_array_pushl(&argv, \"reset\", \"--merge\", NULL);\n+\n+\tif (!is_null_oid(oid))\n+\t\targv_array_push(&argv, oid_to_hex(oid));\n+\n+\tret = run_command_v_opt(argv.argv, RUN_GIT_CMD);\n+\targv_array_clear(&argv);\n+\n+\treturn ret;\n }\n \n static int rollback_single_pick(struct repository *r)\n-- \n2.21.0\n\n"},{"id":"377726","messageId":"20190621091800.17686-5-rohit.ashiwal265@gmail.com","threadId":"51269","inReplyTo":"20190621091800.17686-1-rohit.ashiwal265@gmail.com","subject":"[GSoC][PATCH v6 4/5] cherry-pick/revert: add --skip option","fromName":"Rohit Ashiwal","fromEmail":"rohit.ashiwal265@gmail.com","sentAt":"2019-06-21T09:17:59Z","receivedAt":"2019-06-21T09:20:40Z","isPatch":true,"sender":{"key":"rohit.ashiwal265@gmail.com","avatar":"https://avatars.githubusercontent.com/u/31043830?v=4"},"body":"git am or rebase have a --skip flag to skip the current commit if the\nuser wishes to do so. During a cherry-pick or revert a user could\nlikewise skip a commit, but needs to use 'git reset' (or in the case\nof conflicts 'git reset --merge'), followed by 'git (cherry-pick |\nrevert) --continue' to skip the commit. This is more annoying and\nsometimes confusing on the users' part. Add a `--skip` option to make\nskipping commits easier for the user and to make the commands more\nconsistent.\n\nIn the next commit, we will change the advice messages hence finishing\nthe process of teaching revert and cherry-pick \"how to skip commits\".\n\nSigned-off-by: Rohit Ashiwal <rohit.ashiwal265@gmail.com>\n---\n Documentation/git-cherry-pick.txt |   4 +-\n Documentation/git-revert.txt      |   4 +-\n Documentation/sequencer.txt       |   4 ++\n builtin/revert.c                  |   5 ++\n sequencer.c                       |  73 +++++++++++++++++++++\n sequencer.h                       |   1 +\n t/t3510-cherry-pick-sequence.sh   | 102 ++++++++++++++++++++++++++++++\n 7 files changed, 187 insertions(+), 6 deletions(-)\n\ndiff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt\nindex 754b16ce0c..83ce51aedf 100644\n--- a/Documentation/git-cherry-pick.txt\n+++ b/Documentation/git-cherry-pick.txt\n@@ -10,9 +10,7 @@ SYNOPSIS\n [verse]\n 'git cherry-pick' [--edit] [-n] [-m parent-number] [-s] [-x] [--ff]\n \t\t  [-S[<keyid>]] <commit>...\n-'git cherry-pick' --continue\n-'git cherry-pick' --quit\n-'git cherry-pick' --abort\n+'git cherry-pick' (--continue | --skip | --abort | --quit)\n \n DESCRIPTION\n -----------\ndiff --git a/Documentation/git-revert.txt b/Documentation/git-revert.txt\nindex 0c82ca5bc0..665e065ee3 100644\n--- a/Documentation/git-revert.txt\n+++ b/Documentation/git-revert.txt\n@@ -9,9 +9,7 @@ SYNOPSIS\n --------\n [verse]\n 'git revert' [--[no-]edit] [-n] [-m parent-number] [-s] [-S[<keyid>]] <commit>...\n-'git revert' --continue\n-'git revert' --quit\n-'git revert' --abort\n+'git revert' (--continue | --skip | --abort | --quit)\n \n DESCRIPTION\n -----------\ndiff --git a/Documentation/sequencer.txt b/Documentation/sequencer.txt\nindex 5a57c4a407..3bceb56474 100644\n--- a/Documentation/sequencer.txt\n+++ b/Documentation/sequencer.txt\n@@ -3,6 +3,10 @@\n \t`.git/sequencer`.  Can be used to continue after resolving\n \tconflicts in a failed cherry-pick or revert.\n \n+--skip::\n+\tSkip the current commit and continue with the rest of the\n+\tsequence.\n+\n --quit::\n \tForget about the current operation in progress.  Can be used\n \tto clear the sequencer state after a failed cherry-pick or\ndiff --git a/builtin/revert.c b/builtin/revert.c\nindex d4dcedbdc6..5dc5891ea2 100644\n--- a/builtin/revert.c\n+++ b/builtin/revert.c\n@@ -102,6 +102,7 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)\n \t\tOPT_CMDMODE(0, \"quit\", &cmd, N_(\"end revert or cherry-pick sequence\"), 'q'),\n \t\tOPT_CMDMODE(0, \"continue\", &cmd, N_(\"resume revert or cherry-pick sequence\"), 'c'),\n \t\tOPT_CMDMODE(0, \"abort\", &cmd, N_(\"cancel revert or cherry-pick sequence\"), 'a'),\n+\t\tOPT_CMDMODE(0, \"skip\", &cmd, N_(\"skip current commit and continue\"), 's'),\n \t\tOPT_CLEANUP(&cleanup_arg),\n \t\tOPT_BOOL('n', \"no-commit\", &opts->no_commit, N_(\"don't automatically commit\")),\n \t\tOPT_BOOL('e', \"edit\", &opts->edit, N_(\"edit the commit message\")),\n@@ -151,6 +152,8 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)\n \t\t\tthis_operation = \"--quit\";\n \t\telse if (cmd == 'c')\n \t\t\tthis_operation = \"--continue\";\n+\t\telse if (cmd == 's')\n+\t\t\tthis_operation = \"--skip\";\n \t\telse {\n \t\t\tassert(cmd == 'a');\n \t\t\tthis_operation = \"--abort\";\n@@ -210,6 +213,8 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)\n \t\treturn sequencer_continue(the_repository, opts);\n \tif (cmd == 'a')\n \t\treturn sequencer_rollback(the_repository, opts);\n+\tif (cmd == 's')\n+\t\treturn sequencer_skip(the_repository, opts);\n \treturn sequencer_pick_revisions(the_repository, opts);\n }\n \ndiff --git a/sequencer.c b/sequencer.c\nindex 6762a5f485..c62f7a33aa 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -2761,6 +2761,15 @@ static int rollback_single_pick(struct repository *r)\n \treturn reset_merge(&head_oid);\n }\n \n+static int skip_single_pick(void)\n+{\n+\tstruct object_id head;\n+\n+\tif (read_ref_full(\"HEAD\", 0, &head, NULL))\n+\t\treturn error(_(\"cannot resolve HEAD\"));\n+\treturn reset_merge(&head);\n+}\n+\n int sequencer_rollback(struct repository *r, struct replay_opts *opts)\n {\n \tFILE *f;\n@@ -2810,6 +2819,70 @@ int sequencer_rollback(struct repository *r, struct replay_opts *opts)\n \treturn -1;\n }\n \n+int sequencer_skip(struct repository *r, struct replay_opts *opts)\n+{\n+\tenum replay_action action = -1;\n+\tsequencer_get_last_command(r, &action);\n+\n+\t/*\n+\t * Check whether the subcommand requested to skip the commit is actually\n+\t * in progress and that it's safe to skip the commit.\n+\t *\n+\t * opts->action tells us which subcommand requested to skip the commit.\n+\t * If the corresponding .git/<ACTION>_HEAD exists, we know that the\n+\t * action is in progress and we can skip the commit.\n+\t *\n+\t * Otherwise we check that the last instruction was related to the\n+\t * particular subcommand we're trying to execute and barf if that's not\n+\t * the case.\n+\t *\n+\t * Finally we check that the rollback is \"safe\", i.e., has the HEAD\n+\t * moved? In this case, it doesn't make sense to \"reset the merge\" and\n+\t * \"skip the commit\" as the user already handled this by committing. But\n+\t * we'd not want to barf here, instead give advice on how to proceed. We\n+\t * only need to check that when .git/<ACTION>_HEAD doesn't exist because\n+\t * it gets removed when the user commits, so if it still exists we're\n+\t * sure the user can't have committed before.\n+\t */\n+\tswitch (opts->action) {\n+\tcase REPLAY_REVERT:\n+\t\tif (!file_exists(git_path_revert_head(r))) {\n+\t\t\tif (action != REPLAY_REVERT)\n+\t\t\t\treturn error(_(\"no revert in progress\"));\n+\t\t\tif (!rollback_is_safe())\n+\t\t\t\tgoto give_advice;\n+\t\t}\n+\t\tbreak;\n+\tcase REPLAY_PICK:\n+\t\tif (!file_exists(git_path_cherry_pick_head(r))) {\n+\t\t\tif (action != REPLAY_PICK)\n+\t\t\t\treturn error(_(\"no cherry-pick in progress\"));\n+\t\t\tif (!rollback_is_safe())\n+\t\t\t\tgoto give_advice;\n+\t\t}\n+\t\tbreak;\n+\tdefault:\n+\t\tBUG(\"unexpected action in sequencer_skip\");\n+\t}\n+\n+\tif (skip_single_pick())\n+\t\treturn error(_(\"failed to skip the commit\"));\n+\tif (!is_directory(git_path_seq_dir()))\n+\t\treturn 0;\n+\n+\treturn sequencer_continue(r, opts);\n+\n+give_advice:\n+\terror(_(\"there is nothing to skip\"));\n+\n+\tif (advice_resolve_conflict) {\n+\t\tadvise(_(\"have you committed already?\\n\"\n+\t\t\t \"try \\\"git %s --continue\\\"\"),\n+\t\t\t action == REPLAY_REVERT ? \"revert\" : \"cherry-pick\");\n+\t}\n+\treturn -1;\n+}\n+\n static int save_todo(struct todo_list *todo_list, struct replay_opts *opts)\n {\n \tstruct lock_file todo_lock = LOCK_INIT;\ndiff --git a/sequencer.h b/sequencer.h\nindex 0c494b83d4..731b9853eb 100644\n--- a/sequencer.h\n+++ b/sequencer.h\n@@ -129,6 +129,7 @@ int sequencer_pick_revisions(struct repository *repo,\n \t\t\t     struct replay_opts *opts);\n int sequencer_continue(struct repository *repo, struct replay_opts *opts);\n int sequencer_rollback(struct repository *repo, struct replay_opts *opts);\n+int sequencer_skip(struct repository *repo, struct replay_opts *opts);\n int sequencer_remove_state(struct replay_opts *opts);\n \n #define TODO_LIST_KEEP_EMPTY (1U << 0)\ndiff --git a/t/t3510-cherry-pick-sequence.sh b/t/t3510-cherry-pick-sequence.sh\nindex 941d5026da..20515ea37b 100755\n--- a/t/t3510-cherry-pick-sequence.sh\n+++ b/t/t3510-cherry-pick-sequence.sh\n@@ -93,6 +93,108 @@ test_expect_success 'cherry-pick cleans up sequencer state upon success' '\n \ttest_path_is_missing .git/sequencer\n '\n \n+test_expect_success 'cherry-pick --skip requires cherry-pick in progress' '\n+\tpristine_detach initial &&\n+\ttest_must_fail git cherry-pick --skip\n+'\n+\n+test_expect_success 'revert --skip requires revert in progress' '\n+\tpristine_detach initial &&\n+\ttest_must_fail git revert --skip\n+'\n+\n+test_expect_success 'cherry-pick --skip to skip commit' '\n+\tpristine_detach initial &&\n+\ttest_must_fail git cherry-pick anotherpick &&\n+\ttest_must_fail git revert --skip &&\n+\tgit cherry-pick --skip &&\n+\ttest_cmp_rev initial HEAD &&\n+\ttest_path_is_missing .git/CHERRY_PICK_HEAD\n+'\n+\n+test_expect_success 'revert --skip to skip commit' '\n+\tpristine_detach anotherpick &&\n+\ttest_must_fail git revert anotherpick~1 &&\n+\ttest_must_fail git cherry-pick --skip &&\n+\tgit revert --skip &&\n+\ttest_cmp_rev anotherpick HEAD\n+'\n+\n+test_expect_success 'skip \"empty\" commit' '\n+\tpristine_detach picked &&\n+\ttest_commit dummy foo d &&\n+\ttest_must_fail git cherry-pick anotherpick &&\n+\tgit cherry-pick --skip &&\n+\ttest_cmp_rev dummy HEAD\n+'\n+\n+test_expect_success 'skip a commit and check if rest of sequence is correct' '\n+\tpristine_detach initial &&\n+\techo e >expect &&\n+\tcat >expect.log <<-EOF &&\n+\tOBJID\n+\t:100644 100644 OBJID OBJID M\tfoo\n+\tOBJID\n+\t:100644 100644 OBJID OBJID M\tfoo\n+\tOBJID\n+\t:100644 100644 OBJID OBJID M\tunrelated\n+\tOBJID\n+\t:000000 100644 OBJID OBJID A\tfoo\n+\t:000000 100644 OBJID OBJID A\tunrelated\n+\tEOF\n+\ttest_must_fail git cherry-pick base..yetanotherpick &&\n+\ttest_must_fail git cherry-pick --skip &&\n+\techo d >foo &&\n+\tgit add foo &&\n+\tgit cherry-pick --continue &&\n+\t{\n+\t\tgit rev-list HEAD |\n+\t\tgit diff-tree --root --stdin |\n+\t\tsed \"s/$OID_REGEX/OBJID/g\"\n+\t} >actual.log &&\n+\ttest_cmp expect foo &&\n+\ttest_cmp expect.log actual.log\n+'\n+\n+test_expect_success 'check advice when we move HEAD by committing' '\n+\tpristine_detach initial &&\n+\tcat >expect <<-EOF &&\n+\terror: there is nothing to skip\n+\thint: have you committed already?\n+\thint: try \"git cherry-pick --continue\"\n+\tfatal: cherry-pick failed\n+\tEOF\n+\ttest_must_fail git cherry-pick base..yetanotherpick &&\n+\techo c >foo &&\n+\tgit commit -a &&\n+\ttest_path_is_missing .git/CHERRY_PICK_HEAD &&\n+\ttest_must_fail git cherry-pick --skip 2>advice &&\n+\ttest_i18ncmp expect advice\n+'\n+\n+test_expect_success 'allow skipping commit but not abort for a new history' '\n+\tpristine_detach initial &&\n+\tcat >expect <<-EOF &&\n+\terror: cannot abort from a branch yet to be born\n+\tfatal: cherry-pick failed\n+\tEOF\n+\tgit checkout --orphan new_disconnected &&\n+\tgit reset --hard &&\n+\ttest_must_fail git cherry-pick anotherpick &&\n+\ttest_must_fail git cherry-pick --abort 2>advice &&\n+\tgit cherry-pick --skip &&\n+\ttest_i18ncmp expect advice\n+'\n+\n+test_expect_success 'allow skipping stopped cherry-pick because of untracked file modifications' '\n+\tpristine_detach initial &&\n+\tgit rm --cached unrelated &&\n+\tgit commit -m \"untrack unrelated\" &&\n+\ttest_must_fail git cherry-pick initial base &&\n+\ttest_path_is_missing .git/CHERRY_PICK_HEAD &&\n+\tgit cherry-pick --skip\n+'\n+\n test_expect_success '--quit does not complain when no cherry-pick is in progress' '\n \tpristine_detach initial &&\n \tgit cherry-pick --quit\n-- \n2.21.0\n\n"},{"id":"377727","messageId":"20190621091800.17686-6-rohit.ashiwal265@gmail.com","threadId":"51269","inReplyTo":"20190621091800.17686-1-rohit.ashiwal265@gmail.com","subject":"[GSoC][PATCH v6 5/5] cherry-pick/revert: advise using --skip","fromName":"Rohit Ashiwal","fromEmail":"rohit.ashiwal265@gmail.com","sentAt":"2019-06-21T09:18:00Z","receivedAt":"2019-06-21T09:20:44Z","isPatch":true,"sender":{"key":"rohit.ashiwal265@gmail.com","avatar":"https://avatars.githubusercontent.com/u/31043830?v=4"},"body":"The previous commit introduced a --skip flag for cherry-pick and\nrevert. Update the advice messages, to tell users about this less\ncumbersome way of skipping commits. Also add tests to ensure\neverything is working fine.\n\nSigned-off-by: Rohit Ashiwal <rohit.ashiwal265@gmail.com>\n---\n builtin/commit.c                | 13 ++++++++-----\n sequencer.c                     | 11 ++++++++---\n t/t3510-cherry-pick-sequence.sh | 20 ++++++++++++++++++++\n 3 files changed, 36 insertions(+), 8 deletions(-)\n\ndiff --git a/builtin/commit.c b/builtin/commit.c\nindex 1c9e8e2228..1f47c51bdc 100644\n--- a/builtin/commit.c\n+++ b/builtin/commit.c\n@@ -60,15 +60,18 @@ N_(\"The previous cherry-pick is now empty, possibly due to conflict resolution.\\\n \"\\n\");\n \n static const char empty_cherry_pick_advice_single[] =\n-N_(\"Otherwise, please use 'git reset'\\n\");\n+N_(\"Otherwise, please use 'git cherry-pick --skip'\\n\");\n \n static const char empty_cherry_pick_advice_multi[] =\n-N_(\"If you wish to skip this commit, use:\\n\"\n+N_(\"and then use:\\n\"\n \"\\n\"\n-\"    git reset\\n\"\n+\"    git cherry-pick --continue\\n\"\n \"\\n\"\n-\"Then \\\"git cherry-pick --continue\\\" will resume cherry-picking\\n\"\n-\"the remaining commits.\\n\");\n+\"to resume cherry-picking the remaining commits.\\n\"\n+\"If you wish to skip this commit, use:\\n\"\n+\"\\n\"\n+\"    git cherry-pick --skip\\n\"\n+\"\\n\");\n \n static const char *color_status_slots[] = {\n \t[WT_STATUS_HEADER]\t  = \"header\",\ndiff --git a/sequencer.c b/sequencer.c\nindex c62f7a33aa..98f3537dfc 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -2655,18 +2655,20 @@ static int create_seq_dir(struct repository *r)\n \tenum replay_action action;\n \tconst char *in_progress_error = NULL;\n \tconst char *in_progress_advice = NULL;\n+\tunsigned int advise_skip = file_exists(git_path_revert_head(r)) ||\n+\t\t\t\tfile_exists(git_path_cherry_pick_head(r));\n \n \tif (!sequencer_get_last_command(r, &action)) {\n \t\tswitch (action) {\n \t\tcase REPLAY_REVERT:\n \t\t\tin_progress_error = _(\"revert is already in progress\");\n \t\t\tin_progress_advice =\n-\t\t\t_(\"try \\\"git revert (--continue | --abort | --quit)\\\"\");\n+\t\t\t_(\"try \\\"git revert (--continue | %s--abort | --quit)\\\"\");\n \t\t\tbreak;\n \t\tcase REPLAY_PICK:\n \t\t\tin_progress_error = _(\"cherry-pick is already in progress\");\n \t\t\tin_progress_advice =\n-\t\t\t_(\"try \\\"git cherry-pick (--continue | --abort | --quit)\\\"\");\n+\t\t\t_(\"try \\\"git cherry-pick (--continue | %s--abort | --quit)\\\"\");\n \t\t\tbreak;\n \t\tdefault:\n \t\t\tBUG(\"unexpected action in create_seq_dir\");\n@@ -2674,7 +2676,10 @@ static int create_seq_dir(struct repository *r)\n \t}\n \tif (in_progress_error) {\n \t\terror(\"%s\", in_progress_error);\n-\t\tadvise(\"%s\", in_progress_advice);\n+\t\tif (advise_skip)\n+\t\t\tadvise(in_progress_advice, \"--skip | \");\n+\t\telse\n+\t\t\tadvise(in_progress_advice, \"\");\n \t\treturn -1;\n \t}\n \tif (mkdir(git_path_seq_dir(), 0777) < 0)\ndiff --git a/t/t3510-cherry-pick-sequence.sh b/t/t3510-cherry-pick-sequence.sh\nindex 20515ea37b..793bcc7fe3 100755\n--- a/t/t3510-cherry-pick-sequence.sh\n+++ b/t/t3510-cherry-pick-sequence.sh\n@@ -172,6 +172,26 @@ test_expect_success 'check advice when we move HEAD by committing' '\n \ttest_i18ncmp expect advice\n '\n \n+test_expect_success 'selectively advise --skip while launching another sequence' '\n+\tpristine_detach initial &&\n+\tcat >expect <<-EOF &&\n+\terror: cherry-pick is already in progress\n+\thint: try \"git cherry-pick (--continue | --skip | --abort | --quit)\"\n+\tfatal: cherry-pick failed\n+\tEOF\n+\ttest_must_fail git cherry-pick picked..yetanotherpick &&\n+\ttest_must_fail git cherry-pick picked..yetanotherpick 2>advice &&\n+\ttest_i18ncmp expect advice &&\n+\tcat >expect <<-EOF &&\n+\terror: cherry-pick is already in progress\n+\thint: try \"git cherry-pick (--continue | --abort | --quit)\"\n+\tfatal: cherry-pick failed\n+\tEOF\n+\tgit reset --merge &&\n+\ttest_must_fail git cherry-pick picked..yetanotherpick 2>advice &&\n+\ttest_i18ncmp expect advice\n+'\n+\n test_expect_success 'allow skipping commit but not abort for a new history' '\n \tpristine_detach initial &&\n \tcat >expect <<-EOF &&\n-- \n2.21.0\n\n"},{"id":"377764","messageId":"xmqqd0j6kb66.fsf@gitster-ct.c.googlers.com","threadId":"51269","inReplyTo":"20190621091800.17686-1-rohit.ashiwal265@gmail.com","subject":"Re: [GSoC][PATCH v6 0/5] Teach cherry-pick/revert to skip commits","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-06-21T19:09:37Z","receivedAt":"2019-06-21T19:09:45Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Rohit Ashiwal <rohit.ashiwal265@gmail.com> writes:\n\n> I've covered the advice message behind `advice_resolve_conflict` variable and\n> changed the order of error and advice to match that of 1/5.\n\nI think the updated text reads much better, i.e. taking from your\nrange-diff:\n\n>      +\tcat >expect <<-EOF &&\n>     ++\terror: there is nothing to skip\n>      +\thint: have you committed already?\n>      +\thint: try \"git cherry-pick --continue\"\n>     -+\terror: there is nothing to skip\n>      +\tfatal: cherry-pick failed\n>      +\tEOF\n\nwe say \"why we failed\" upfront with \"error\", and then for those who\nwould need more clues, we give \"how you might want to proceed\" as an\nadditionao \"hint\".  That looks more logical, besides being more\nconsistent with how advice messages are given in other codepaths.\n\n> I believe that we\n> don't have any advice variable appropriate for advice in 1/5.\n\nIf there is nothing, perhaps you would need to invent one.  Perhaps\n\"advice_sequencer_in_use\" or something?\n\nOther than that, looks quite good.  Will (re-)queue.\n\n"},{"id":"377832","messageId":"20190623200338.17144-1-rohit.ashiwal265@gmail.com","threadId":"51269","inReplyTo":"20190608191958.4593-1-rohit.ashiwal265@gmail.com","subject":"[GSoC][PATCH v7 0/6] Teach cherry-pick/revert to skip commits","fromName":"Rohit Ashiwal","fromEmail":"rohit.ashiwal265@gmail.com","sentAt":"2019-06-23T20:03:32Z","receivedAt":"2019-06-23T20:06:01Z","isPatch":true,"sender":{"key":"rohit.ashiwal265@gmail.com","avatar":"https://avatars.githubusercontent.com/u/31043830?v=4"},"body":"Tied all loose ends. Add an advice config variable to guard advise() call\nin 2/6.\n\nRohit Ashiwal (6):\n  advice: add sequencerInUse config variable\n  sequencer: add advice for revert\n  sequencer: rename reset_for_rollback to reset_merge\n  sequencer: use argv_array in reset_merge\n  cherry-pick/revert: add --skip option\n  cherry-pick/revert: advise using --skip\n\n Documentation/config/advice.txt   |   2 +\n Documentation/git-cherry-pick.txt |   4 +-\n Documentation/git-revert.txt      |   4 +-\n Documentation/sequencer.txt       |   4 +\n advice.c                          |   2 +\n advice.h                          |   1 +\n builtin/commit.c                  |  13 +--\n builtin/revert.c                  |   5 ++\n sequencer.c                       | 134 ++++++++++++++++++++++++++----\n sequencer.h                       |   1 +\n t/t3510-cherry-pick-sequence.sh   | 122 +++++++++++++++++++++++++++\n 11 files changed, 266 insertions(+), 26 deletions(-)\n\nRange-diff:\n-:  ---------- > 1:  207042a895 advice: add sequencerInUse config variable\n1:  67c212090d ! 2:  d7c603d47f sequencer: add advice for revert\n    @@ -46,7 +46,8 @@\n     +\t}\n     +\tif (in_progress_error) {\n     +\t\terror(\"%s\", in_progress_error);\n    -+\t\tadvise(\"%s\", in_progress_advice);\n    ++\t\tif (advice_sequencer_in_use)\n    ++\t\t\tadvise(\"%s\", in_progress_advice);\n      \t\treturn -1;\n     -\t} else if (mkdir(git_path_seq_dir(), 0777) < 0)\n     +\t}\n2:  300d6f64f0 = 3:  b70299c572 sequencer: rename reset_for_rollback to reset_merge\n3:  edc35f6a4c = 4:  569122c861 sequencer: use argv_array in reset_merge\n4:  2b16d7ea4d = 5:  4580f0e5af cherry-pick/revert: add --skip option\n5:  8f278b5139 ! 6:  f6f21b055b cherry-pick/revert: advise using --skip\n    @@ -64,14 +64,12 @@\n      \t\tdefault:\n      \t\t\tBUG(\"unexpected action in create_seq_dir\");\n     @@\n    - \t}\n      \tif (in_progress_error) {\n      \t\terror(\"%s\", in_progress_error);\n    --\t\tadvise(\"%s\", in_progress_advice);\n    -+\t\tif (advise_skip)\n    -+\t\t\tadvise(in_progress_advice, \"--skip | \");\n    -+\t\telse\n    -+\t\t\tadvise(in_progress_advice, \"\");\n    + \t\tif (advice_sequencer_in_use)\n    +-\t\t\tadvise(\"%s\", in_progress_advice);\n    ++\t\t\tadvise(in_progress_advice,\n    ++\t\t\t\tadvise_skip ? \"--skip | \" : \"\");\n      \t\treturn -1;\n      \t}\n      \tif (mkdir(git_path_seq_dir(), 0777) < 0)\n-- \n2.21.0\n\n"},{"id":"377833","messageId":"20190623200338.17144-2-rohit.ashiwal265@gmail.com","threadId":"51269","inReplyTo":"20190623200338.17144-1-rohit.ashiwal265@gmail.com","subject":"[GSoC][PATCH v7 1/6] advice: add sequencerInUse config variable","fromName":"Rohit Ashiwal","fromEmail":"rohit.ashiwal265@gmail.com","sentAt":"2019-06-23T20:03:33Z","receivedAt":"2019-06-23T20:06:15Z","isPatch":true,"sender":{"key":"rohit.ashiwal265@gmail.com","avatar":"https://avatars.githubusercontent.com/u/31043830?v=4"},"body":"Calls to advise() which are not guarded by advice.* config variables\nare \"bad\" as they do not let the user say, \"I've learned this part\nof Git enough, please don't tell me what to do verbosely.\". Add a\nconfiguration variable \"sequencerInUse\" which controls whether to\ndisplay advice when any sequencer command is in progress.\n\nSigned-off-by: Rohit Ashiwal <rohit.ashiwal265@gmail.com>\n---\n Documentation/config/advice.txt | 2 ++\n advice.c                        | 2 ++\n advice.h                        | 1 +\n 3 files changed, 5 insertions(+)\n\ndiff --git a/Documentation/config/advice.txt b/Documentation/config/advice.txt\nindex ec4f6ae658..1cd9096c98 100644\n--- a/Documentation/config/advice.txt\n+++ b/Documentation/config/advice.txt\n@@ -57,6 +57,8 @@ advice.*::\n \tresolveConflict::\n \t\tAdvice shown by various commands when conflicts\n \t\tprevent the operation from being performed.\n+\tsequencerInUse::\n+\t\tAdvice shown when a sequencer command is already in progress.\n \timplicitIdentity::\n \t\tAdvice on how to set your identity configuration when\n \t\tyour information is guessed from the system username and\ndiff --git a/advice.c b/advice.c\nindex ce5f374ecd..b101f0c264 100644\n--- a/advice.c\n+++ b/advice.c\n@@ -15,6 +15,7 @@ int advice_status_u_option = 1;\n int advice_commit_before_merge = 1;\n int advice_reset_quiet_warning = 1;\n int advice_resolve_conflict = 1;\n+int advice_sequencer_in_use = 1;\n int advice_implicit_identity = 1;\n int advice_detached_head = 1;\n int advice_set_upstream_failure = 1;\n@@ -71,6 +72,7 @@ static struct {\n \t{ \"commitBeforeMerge\", &advice_commit_before_merge },\n \t{ \"resetQuiet\", &advice_reset_quiet_warning },\n \t{ \"resolveConflict\", &advice_resolve_conflict },\n+\t{ \"sequencerInUse\", &advice_sequencer_in_use },\n \t{ \"implicitIdentity\", &advice_implicit_identity },\n \t{ \"detachedHead\", &advice_detached_head },\n \t{ \"setupStreamFailure\", &advice_set_upstream_failure },\ndiff --git a/advice.h b/advice.h\nindex e50f02cdfe..ebc838d7bc 100644\n--- a/advice.h\n+++ b/advice.h\n@@ -15,6 +15,7 @@ extern int advice_status_u_option;\n extern int advice_commit_before_merge;\n extern int advice_reset_quiet_warning;\n extern int advice_resolve_conflict;\n+extern int advice_sequencer_in_use;\n extern int advice_implicit_identity;\n extern int advice_detached_head;\n extern int advice_set_upstream_failure;\n-- \n2.21.0\n\n"},{"id":"377834","messageId":"20190623200338.17144-5-rohit.ashiwal265@gmail.com","threadId":"51269","inReplyTo":"20190623200338.17144-1-rohit.ashiwal265@gmail.com","subject":"[GSoC][PATCH v7 4/6] sequencer: use argv_array in reset_merge","fromName":"Rohit Ashiwal","fromEmail":"rohit.ashiwal265@gmail.com","sentAt":"2019-06-23T20:03:36Z","receivedAt":"2019-06-23T20:06:15Z","isPatch":true,"sender":{"key":"rohit.ashiwal265@gmail.com","avatar":"https://avatars.githubusercontent.com/u/31043830?v=4"},"body":"Avoid using magic numbers for array size and index under `reset_merge`\nfunction. Use `argv_array` instead. This will make code shorter and\neasier to extend.\n\nSigned-off-by: Rohit Ashiwal <rohit.ashiwal265@gmail.com>\n---\n sequencer.c | 17 +++++++++++------\n 1 file changed, 11 insertions(+), 6 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex cb856bcfc3..70efe36ee8 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -2734,13 +2734,18 @@ static int rollback_is_safe(void)\n \n static int reset_merge(const struct object_id *oid)\n {\n-\tconst char *argv[4];\t/* reset --merge <arg> + NULL */\n+\tint ret;\n+\tstruct argv_array argv = ARGV_ARRAY_INIT;\n \n-\targv[0] = \"reset\";\n-\targv[1] = \"--merge\";\n-\targv[2] = oid_to_hex(oid);\n-\targv[3] = NULL;\n-\treturn run_command_v_opt(argv, RUN_GIT_CMD);\n+\targv_array_pushl(&argv, \"reset\", \"--merge\", NULL);\n+\n+\tif (!is_null_oid(oid))\n+\t\targv_array_push(&argv, oid_to_hex(oid));\n+\n+\tret = run_command_v_opt(argv.argv, RUN_GIT_CMD);\n+\targv_array_clear(&argv);\n+\n+\treturn ret;\n }\n \n static int rollback_single_pick(struct repository *r)\n-- \n2.21.0\n\n"},{"id":"377835","messageId":"20190623200338.17144-3-rohit.ashiwal265@gmail.com","threadId":"51269","inReplyTo":"20190623200338.17144-1-rohit.ashiwal265@gmail.com","subject":"[GSoC][PATCH v7 2/6] sequencer: add advice for revert","fromName":"Rohit Ashiwal","fromEmail":"rohit.ashiwal265@gmail.com","sentAt":"2019-06-23T20:03:34Z","receivedAt":"2019-06-23T20:06:15Z","isPatch":true,"sender":{"key":"rohit.ashiwal265@gmail.com","avatar":"https://avatars.githubusercontent.com/u/31043830?v=4"},"body":"In the case of merge conflicts, while performing a revert, we are\ncurrently advised to use `git cherry-pick --<sequencer-options>`\nof which --continue is incompatible for continuing the revert.\nIntroduce a separate advice message for `git revert`. Also change\nthe signature of `create_seq_dir` to handle which advice to display\nselectively.\n\nSigned-off-by: Rohit Ashiwal <rohit.ashiwal265@gmail.com>\n---\n sequencer.c | 35 +++++++++++++++++++++++++++++------\n 1 file changed, 29 insertions(+), 6 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex f88a97fb10..0ef2622a69 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -2650,15 +2650,38 @@ static int walk_revs_populate_todo(struct todo_list *todo_list,\n \treturn 0;\n }\n \n-static int create_seq_dir(void)\n+static int create_seq_dir(struct repository *r)\n {\n-\tif (file_exists(git_path_seq_dir())) {\n-\t\terror(_(\"a cherry-pick or revert is already in progress\"));\n-\t\tadvise(_(\"try \\\"git cherry-pick (--continue | --quit | --abort)\\\"\"));\n+\tenum replay_action action;\n+\tconst char *in_progress_error = NULL;\n+\tconst char *in_progress_advice = NULL;\n+\n+\tif (!sequencer_get_last_command(r, &action)) {\n+\t\tswitch (action) {\n+\t\tcase REPLAY_REVERT:\n+\t\t\tin_progress_error = _(\"revert is already in progress\");\n+\t\t\tin_progress_advice =\n+\t\t\t_(\"try \\\"git revert (--continue | --abort | --quit)\\\"\");\n+\t\t\tbreak;\n+\t\tcase REPLAY_PICK:\n+\t\t\tin_progress_error = _(\"cherry-pick is already in progress\");\n+\t\t\tin_progress_advice =\n+\t\t\t_(\"try \\\"git cherry-pick (--continue | --abort | --quit)\\\"\");\n+\t\t\tbreak;\n+\t\tdefault:\n+\t\t\tBUG(\"unexpected action in create_seq_dir\");\n+\t\t}\n+\t}\n+\tif (in_progress_error) {\n+\t\terror(\"%s\", in_progress_error);\n+\t\tif (advice_sequencer_in_use)\n+\t\t\tadvise(\"%s\", in_progress_advice);\n \t\treturn -1;\n-\t} else if (mkdir(git_path_seq_dir(), 0777) < 0)\n+\t}\n+\tif (mkdir(git_path_seq_dir(), 0777) < 0)\n \t\treturn error_errno(_(\"could not create sequencer directory '%s'\"),\n \t\t\t\t   git_path_seq_dir());\n+\n \treturn 0;\n }\n \n@@ -4237,7 +4260,7 @@ int sequencer_pick_revisions(struct repository *r,\n \t */\n \n \tif (walk_revs_populate_todo(&todo_list, opts) ||\n-\t\t\tcreate_seq_dir() < 0)\n+\t\t\tcreate_seq_dir(r) < 0)\n \t\treturn -1;\n \tif (get_oid(\"HEAD\", &oid) && (opts->action == REPLAY_REVERT))\n \t\treturn error(_(\"can't revert as initial commit\"));\n-- \n2.21.0\n\n"},{"id":"377836","messageId":"20190623200338.17144-4-rohit.ashiwal265@gmail.com","threadId":"51269","inReplyTo":"20190623200338.17144-1-rohit.ashiwal265@gmail.com","subject":"[GSoC][PATCH v7 3/6] sequencer: rename reset_for_rollback to reset_merge","fromName":"Rohit Ashiwal","fromEmail":"rohit.ashiwal265@gmail.com","sentAt":"2019-06-23T20:03:35Z","receivedAt":"2019-06-23T20:06:15Z","isPatch":true,"sender":{"key":"rohit.ashiwal265@gmail.com","avatar":"https://avatars.githubusercontent.com/u/31043830?v=4"},"body":"We are on a path to teach cherry-pick/revert how to skip commits. To\nachieve this, we could really make use of existing functions.\nreset_for_rollback is one such function, but the name does not\nintuitively suggest to use it to reset a merge, which it was born to\nperform see 539047c (\"revert: introduce --abort to cancel a failed\ncherry-pick\", 2011-11-23). Change the name to reset_merge to make\nit more intuitive.\n\nSigned-off-by: Rohit Ashiwal <rohit.ashiwal265@gmail.com>\n---\n sequencer.c | 6 +++---\n 1 file changed, 3 insertions(+), 3 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 0ef2622a69..cb856bcfc3 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -2732,7 +2732,7 @@ static int rollback_is_safe(void)\n \treturn oideq(&actual_head, &expected_head);\n }\n \n-static int reset_for_rollback(const struct object_id *oid)\n+static int reset_merge(const struct object_id *oid)\n {\n \tconst char *argv[4];\t/* reset --merge <arg> + NULL */\n \n@@ -2754,7 +2754,7 @@ static int rollback_single_pick(struct repository *r)\n \t\treturn error(_(\"cannot resolve HEAD\"));\n \tif (is_null_oid(&head_oid))\n \t\treturn error(_(\"cannot abort from a branch yet to be born\"));\n-\treturn reset_for_rollback(&head_oid);\n+\treturn reset_merge(&head_oid);\n }\n \n int sequencer_rollback(struct repository *r, struct replay_opts *opts)\n@@ -2797,7 +2797,7 @@ int sequencer_rollback(struct repository *r, struct replay_opts *opts)\n \t\twarning(_(\"You seem to have moved HEAD. \"\n \t\t\t  \"Not rewinding, check your HEAD!\"));\n \t} else\n-\tif (reset_for_rollback(&oid))\n+\tif (reset_merge(&oid))\n \t\tgoto fail;\n \tstrbuf_release(&buf);\n \treturn sequencer_remove_state(opts);\n-- \n2.21.0\n\n"},{"id":"377837","messageId":"20190623200338.17144-6-rohit.ashiwal265@gmail.com","threadId":"51269","inReplyTo":"20190623200338.17144-1-rohit.ashiwal265@gmail.com","subject":"[GSoC][PATCH v7 5/6] cherry-pick/revert: add --skip option","fromName":"Rohit Ashiwal","fromEmail":"rohit.ashiwal265@gmail.com","sentAt":"2019-06-23T20:03:37Z","receivedAt":"2019-06-23T20:06:19Z","isPatch":true,"sender":{"key":"rohit.ashiwal265@gmail.com","avatar":"https://avatars.githubusercontent.com/u/31043830?v=4"},"body":"git am or rebase have a --skip flag to skip the current commit if the\nuser wishes to do so. During a cherry-pick or revert a user could\nlikewise skip a commit, but needs to use 'git reset' (or in the case\nof conflicts 'git reset --merge'), followed by 'git (cherry-pick |\nrevert) --continue' to skip the commit. This is more annoying and\nsometimes confusing on the users' part. Add a `--skip` option to make\nskipping commits easier for the user and to make the commands more\nconsistent.\n\nIn the next commit, we will change the advice messages hence finishing\nthe process of teaching revert and cherry-pick \"how to skip commits\".\n\nSigned-off-by: Rohit Ashiwal <rohit.ashiwal265@gmail.com>\n---\n Documentation/git-cherry-pick.txt |   4 +-\n Documentation/git-revert.txt      |   4 +-\n Documentation/sequencer.txt       |   4 ++\n builtin/revert.c                  |   5 ++\n sequencer.c                       |  73 +++++++++++++++++++++\n sequencer.h                       |   1 +\n t/t3510-cherry-pick-sequence.sh   | 102 ++++++++++++++++++++++++++++++\n 7 files changed, 187 insertions(+), 6 deletions(-)\n\ndiff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt\nindex 754b16ce0c..83ce51aedf 100644\n--- a/Documentation/git-cherry-pick.txt\n+++ b/Documentation/git-cherry-pick.txt\n@@ -10,9 +10,7 @@ SYNOPSIS\n [verse]\n 'git cherry-pick' [--edit] [-n] [-m parent-number] [-s] [-x] [--ff]\n \t\t  [-S[<keyid>]] <commit>...\n-'git cherry-pick' --continue\n-'git cherry-pick' --quit\n-'git cherry-pick' --abort\n+'git cherry-pick' (--continue | --skip | --abort | --quit)\n \n DESCRIPTION\n -----------\ndiff --git a/Documentation/git-revert.txt b/Documentation/git-revert.txt\nindex 0c82ca5bc0..665e065ee3 100644\n--- a/Documentation/git-revert.txt\n+++ b/Documentation/git-revert.txt\n@@ -9,9 +9,7 @@ SYNOPSIS\n --------\n [verse]\n 'git revert' [--[no-]edit] [-n] [-m parent-number] [-s] [-S[<keyid>]] <commit>...\n-'git revert' --continue\n-'git revert' --quit\n-'git revert' --abort\n+'git revert' (--continue | --skip | --abort | --quit)\n \n DESCRIPTION\n -----------\ndiff --git a/Documentation/sequencer.txt b/Documentation/sequencer.txt\nindex 5a57c4a407..3bceb56474 100644\n--- a/Documentation/sequencer.txt\n+++ b/Documentation/sequencer.txt\n@@ -3,6 +3,10 @@\n \t`.git/sequencer`.  Can be used to continue after resolving\n \tconflicts in a failed cherry-pick or revert.\n \n+--skip::\n+\tSkip the current commit and continue with the rest of the\n+\tsequence.\n+\n --quit::\n \tForget about the current operation in progress.  Can be used\n \tto clear the sequencer state after a failed cherry-pick or\ndiff --git a/builtin/revert.c b/builtin/revert.c\nindex d4dcedbdc6..5dc5891ea2 100644\n--- a/builtin/revert.c\n+++ b/builtin/revert.c\n@@ -102,6 +102,7 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)\n \t\tOPT_CMDMODE(0, \"quit\", &cmd, N_(\"end revert or cherry-pick sequence\"), 'q'),\n \t\tOPT_CMDMODE(0, \"continue\", &cmd, N_(\"resume revert or cherry-pick sequence\"), 'c'),\n \t\tOPT_CMDMODE(0, \"abort\", &cmd, N_(\"cancel revert or cherry-pick sequence\"), 'a'),\n+\t\tOPT_CMDMODE(0, \"skip\", &cmd, N_(\"skip current commit and continue\"), 's'),\n \t\tOPT_CLEANUP(&cleanup_arg),\n \t\tOPT_BOOL('n', \"no-commit\", &opts->no_commit, N_(\"don't automatically commit\")),\n \t\tOPT_BOOL('e', \"edit\", &opts->edit, N_(\"edit the commit message\")),\n@@ -151,6 +152,8 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)\n \t\t\tthis_operation = \"--quit\";\n \t\telse if (cmd == 'c')\n \t\t\tthis_operation = \"--continue\";\n+\t\telse if (cmd == 's')\n+\t\t\tthis_operation = \"--skip\";\n \t\telse {\n \t\t\tassert(cmd == 'a');\n \t\t\tthis_operation = \"--abort\";\n@@ -210,6 +213,8 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)\n \t\treturn sequencer_continue(the_repository, opts);\n \tif (cmd == 'a')\n \t\treturn sequencer_rollback(the_repository, opts);\n+\tif (cmd == 's')\n+\t\treturn sequencer_skip(the_repository, opts);\n \treturn sequencer_pick_revisions(the_repository, opts);\n }\n \ndiff --git a/sequencer.c b/sequencer.c\nindex 70efe36ee8..f5e3d60878 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -2762,6 +2762,15 @@ static int rollback_single_pick(struct repository *r)\n \treturn reset_merge(&head_oid);\n }\n \n+static int skip_single_pick(void)\n+{\n+\tstruct object_id head;\n+\n+\tif (read_ref_full(\"HEAD\", 0, &head, NULL))\n+\t\treturn error(_(\"cannot resolve HEAD\"));\n+\treturn reset_merge(&head);\n+}\n+\n int sequencer_rollback(struct repository *r, struct replay_opts *opts)\n {\n \tFILE *f;\n@@ -2811,6 +2820,70 @@ int sequencer_rollback(struct repository *r, struct replay_opts *opts)\n \treturn -1;\n }\n \n+int sequencer_skip(struct repository *r, struct replay_opts *opts)\n+{\n+\tenum replay_action action = -1;\n+\tsequencer_get_last_command(r, &action);\n+\n+\t/*\n+\t * Check whether the subcommand requested to skip the commit is actually\n+\t * in progress and that it's safe to skip the commit.\n+\t *\n+\t * opts->action tells us which subcommand requested to skip the commit.\n+\t * If the corresponding .git/<ACTION>_HEAD exists, we know that the\n+\t * action is in progress and we can skip the commit.\n+\t *\n+\t * Otherwise we check that the last instruction was related to the\n+\t * particular subcommand we're trying to execute and barf if that's not\n+\t * the case.\n+\t *\n+\t * Finally we check that the rollback is \"safe\", i.e., has the HEAD\n+\t * moved? In this case, it doesn't make sense to \"reset the merge\" and\n+\t * \"skip the commit\" as the user already handled this by committing. But\n+\t * we'd not want to barf here, instead give advice on how to proceed. We\n+\t * only need to check that when .git/<ACTION>_HEAD doesn't exist because\n+\t * it gets removed when the user commits, so if it still exists we're\n+\t * sure the user can't have committed before.\n+\t */\n+\tswitch (opts->action) {\n+\tcase REPLAY_REVERT:\n+\t\tif (!file_exists(git_path_revert_head(r))) {\n+\t\t\tif (action != REPLAY_REVERT)\n+\t\t\t\treturn error(_(\"no revert in progress\"));\n+\t\t\tif (!rollback_is_safe())\n+\t\t\t\tgoto give_advice;\n+\t\t}\n+\t\tbreak;\n+\tcase REPLAY_PICK:\n+\t\tif (!file_exists(git_path_cherry_pick_head(r))) {\n+\t\t\tif (action != REPLAY_PICK)\n+\t\t\t\treturn error(_(\"no cherry-pick in progress\"));\n+\t\t\tif (!rollback_is_safe())\n+\t\t\t\tgoto give_advice;\n+\t\t}\n+\t\tbreak;\n+\tdefault:\n+\t\tBUG(\"unexpected action in sequencer_skip\");\n+\t}\n+\n+\tif (skip_single_pick())\n+\t\treturn error(_(\"failed to skip the commit\"));\n+\tif (!is_directory(git_path_seq_dir()))\n+\t\treturn 0;\n+\n+\treturn sequencer_continue(r, opts);\n+\n+give_advice:\n+\terror(_(\"there is nothing to skip\"));\n+\n+\tif (advice_resolve_conflict) {\n+\t\tadvise(_(\"have you committed already?\\n\"\n+\t\t\t \"try \\\"git %s --continue\\\"\"),\n+\t\t\t action == REPLAY_REVERT ? \"revert\" : \"cherry-pick\");\n+\t}\n+\treturn -1;\n+}\n+\n static int save_todo(struct todo_list *todo_list, struct replay_opts *opts)\n {\n \tstruct lock_file todo_lock = LOCK_INIT;\ndiff --git a/sequencer.h b/sequencer.h\nindex 0c494b83d4..731b9853eb 100644\n--- a/sequencer.h\n+++ b/sequencer.h\n@@ -129,6 +129,7 @@ int sequencer_pick_revisions(struct repository *repo,\n \t\t\t     struct replay_opts *opts);\n int sequencer_continue(struct repository *repo, struct replay_opts *opts);\n int sequencer_rollback(struct repository *repo, struct replay_opts *opts);\n+int sequencer_skip(struct repository *repo, struct replay_opts *opts);\n int sequencer_remove_state(struct replay_opts *opts);\n \n #define TODO_LIST_KEEP_EMPTY (1U << 0)\ndiff --git a/t/t3510-cherry-pick-sequence.sh b/t/t3510-cherry-pick-sequence.sh\nindex 941d5026da..20515ea37b 100755\n--- a/t/t3510-cherry-pick-sequence.sh\n+++ b/t/t3510-cherry-pick-sequence.sh\n@@ -93,6 +93,108 @@ test_expect_success 'cherry-pick cleans up sequencer state upon success' '\n \ttest_path_is_missing .git/sequencer\n '\n \n+test_expect_success 'cherry-pick --skip requires cherry-pick in progress' '\n+\tpristine_detach initial &&\n+\ttest_must_fail git cherry-pick --skip\n+'\n+\n+test_expect_success 'revert --skip requires revert in progress' '\n+\tpristine_detach initial &&\n+\ttest_must_fail git revert --skip\n+'\n+\n+test_expect_success 'cherry-pick --skip to skip commit' '\n+\tpristine_detach initial &&\n+\ttest_must_fail git cherry-pick anotherpick &&\n+\ttest_must_fail git revert --skip &&\n+\tgit cherry-pick --skip &&\n+\ttest_cmp_rev initial HEAD &&\n+\ttest_path_is_missing .git/CHERRY_PICK_HEAD\n+'\n+\n+test_expect_success 'revert --skip to skip commit' '\n+\tpristine_detach anotherpick &&\n+\ttest_must_fail git revert anotherpick~1 &&\n+\ttest_must_fail git cherry-pick --skip &&\n+\tgit revert --skip &&\n+\ttest_cmp_rev anotherpick HEAD\n+'\n+\n+test_expect_success 'skip \"empty\" commit' '\n+\tpristine_detach picked &&\n+\ttest_commit dummy foo d &&\n+\ttest_must_fail git cherry-pick anotherpick &&\n+\tgit cherry-pick --skip &&\n+\ttest_cmp_rev dummy HEAD\n+'\n+\n+test_expect_success 'skip a commit and check if rest of sequence is correct' '\n+\tpristine_detach initial &&\n+\techo e >expect &&\n+\tcat >expect.log <<-EOF &&\n+\tOBJID\n+\t:100644 100644 OBJID OBJID M\tfoo\n+\tOBJID\n+\t:100644 100644 OBJID OBJID M\tfoo\n+\tOBJID\n+\t:100644 100644 OBJID OBJID M\tunrelated\n+\tOBJID\n+\t:000000 100644 OBJID OBJID A\tfoo\n+\t:000000 100644 OBJID OBJID A\tunrelated\n+\tEOF\n+\ttest_must_fail git cherry-pick base..yetanotherpick &&\n+\ttest_must_fail git cherry-pick --skip &&\n+\techo d >foo &&\n+\tgit add foo &&\n+\tgit cherry-pick --continue &&\n+\t{\n+\t\tgit rev-list HEAD |\n+\t\tgit diff-tree --root --stdin |\n+\t\tsed \"s/$OID_REGEX/OBJID/g\"\n+\t} >actual.log &&\n+\ttest_cmp expect foo &&\n+\ttest_cmp expect.log actual.log\n+'\n+\n+test_expect_success 'check advice when we move HEAD by committing' '\n+\tpristine_detach initial &&\n+\tcat >expect <<-EOF &&\n+\terror: there is nothing to skip\n+\thint: have you committed already?\n+\thint: try \"git cherry-pick --continue\"\n+\tfatal: cherry-pick failed\n+\tEOF\n+\ttest_must_fail git cherry-pick base..yetanotherpick &&\n+\techo c >foo &&\n+\tgit commit -a &&\n+\ttest_path_is_missing .git/CHERRY_PICK_HEAD &&\n+\ttest_must_fail git cherry-pick --skip 2>advice &&\n+\ttest_i18ncmp expect advice\n+'\n+\n+test_expect_success 'allow skipping commit but not abort for a new history' '\n+\tpristine_detach initial &&\n+\tcat >expect <<-EOF &&\n+\terror: cannot abort from a branch yet to be born\n+\tfatal: cherry-pick failed\n+\tEOF\n+\tgit checkout --orphan new_disconnected &&\n+\tgit reset --hard &&\n+\ttest_must_fail git cherry-pick anotherpick &&\n+\ttest_must_fail git cherry-pick --abort 2>advice &&\n+\tgit cherry-pick --skip &&\n+\ttest_i18ncmp expect advice\n+'\n+\n+test_expect_success 'allow skipping stopped cherry-pick because of untracked file modifications' '\n+\tpristine_detach initial &&\n+\tgit rm --cached unrelated &&\n+\tgit commit -m \"untrack unrelated\" &&\n+\ttest_must_fail git cherry-pick initial base &&\n+\ttest_path_is_missing .git/CHERRY_PICK_HEAD &&\n+\tgit cherry-pick --skip\n+'\n+\n test_expect_success '--quit does not complain when no cherry-pick is in progress' '\n \tpristine_detach initial &&\n \tgit cherry-pick --quit\n-- \n2.21.0\n\n"},{"id":"377838","messageId":"20190623200338.17144-7-rohit.ashiwal265@gmail.com","threadId":"51269","inReplyTo":"20190623200338.17144-1-rohit.ashiwal265@gmail.com","subject":"[GSoC][PATCH v7 6/6] cherry-pick/revert: advise using --skip","fromName":"Rohit Ashiwal","fromEmail":"rohit.ashiwal265@gmail.com","sentAt":"2019-06-23T20:03:38Z","receivedAt":"2019-06-23T20:06:22Z","isPatch":true,"sender":{"key":"rohit.ashiwal265@gmail.com","avatar":"https://avatars.githubusercontent.com/u/31043830?v=4"},"body":"The previous commit introduced a --skip flag for cherry-pick and\nrevert. Update the advice messages, to tell users about this less\ncumbersome way of skipping commits. Also add tests to ensure\neverything is working fine.\n\nSigned-off-by: Rohit Ashiwal <rohit.ashiwal265@gmail.com>\n---\n builtin/commit.c                | 13 ++++++++-----\n sequencer.c                     |  9 ++++++---\n t/t3510-cherry-pick-sequence.sh | 20 ++++++++++++++++++++\n 3 files changed, 34 insertions(+), 8 deletions(-)\n\ndiff --git a/builtin/commit.c b/builtin/commit.c\nindex 1c9e8e2228..1f47c51bdc 100644\n--- a/builtin/commit.c\n+++ b/builtin/commit.c\n@@ -60,15 +60,18 @@ N_(\"The previous cherry-pick is now empty, possibly due to conflict resolution.\\\n \"\\n\");\n \n static const char empty_cherry_pick_advice_single[] =\n-N_(\"Otherwise, please use 'git reset'\\n\");\n+N_(\"Otherwise, please use 'git cherry-pick --skip'\\n\");\n \n static const char empty_cherry_pick_advice_multi[] =\n-N_(\"If you wish to skip this commit, use:\\n\"\n+N_(\"and then use:\\n\"\n \"\\n\"\n-\"    git reset\\n\"\n+\"    git cherry-pick --continue\\n\"\n \"\\n\"\n-\"Then \\\"git cherry-pick --continue\\\" will resume cherry-picking\\n\"\n-\"the remaining commits.\\n\");\n+\"to resume cherry-picking the remaining commits.\\n\"\n+\"If you wish to skip this commit, use:\\n\"\n+\"\\n\"\n+\"    git cherry-pick --skip\\n\"\n+\"\\n\");\n \n static const char *color_status_slots[] = {\n \t[WT_STATUS_HEADER]\t  = \"header\",\ndiff --git a/sequencer.c b/sequencer.c\nindex f5e3d60878..2e7b16b75f 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -2655,18 +2655,20 @@ static int create_seq_dir(struct repository *r)\n \tenum replay_action action;\n \tconst char *in_progress_error = NULL;\n \tconst char *in_progress_advice = NULL;\n+\tunsigned int advise_skip = file_exists(git_path_revert_head(r)) ||\n+\t\t\t\tfile_exists(git_path_cherry_pick_head(r));\n \n \tif (!sequencer_get_last_command(r, &action)) {\n \t\tswitch (action) {\n \t\tcase REPLAY_REVERT:\n \t\t\tin_progress_error = _(\"revert is already in progress\");\n \t\t\tin_progress_advice =\n-\t\t\t_(\"try \\\"git revert (--continue | --abort | --quit)\\\"\");\n+\t\t\t_(\"try \\\"git revert (--continue | %s--abort | --quit)\\\"\");\n \t\t\tbreak;\n \t\tcase REPLAY_PICK:\n \t\t\tin_progress_error = _(\"cherry-pick is already in progress\");\n \t\t\tin_progress_advice =\n-\t\t\t_(\"try \\\"git cherry-pick (--continue | --abort | --quit)\\\"\");\n+\t\t\t_(\"try \\\"git cherry-pick (--continue | %s--abort | --quit)\\\"\");\n \t\t\tbreak;\n \t\tdefault:\n \t\t\tBUG(\"unexpected action in create_seq_dir\");\n@@ -2675,7 +2677,8 @@ static int create_seq_dir(struct repository *r)\n \tif (in_progress_error) {\n \t\terror(\"%s\", in_progress_error);\n \t\tif (advice_sequencer_in_use)\n-\t\t\tadvise(\"%s\", in_progress_advice);\n+\t\t\tadvise(in_progress_advice,\n+\t\t\t\tadvise_skip ? \"--skip | \" : \"\");\n \t\treturn -1;\n \t}\n \tif (mkdir(git_path_seq_dir(), 0777) < 0)\ndiff --git a/t/t3510-cherry-pick-sequence.sh b/t/t3510-cherry-pick-sequence.sh\nindex 20515ea37b..793bcc7fe3 100755\n--- a/t/t3510-cherry-pick-sequence.sh\n+++ b/t/t3510-cherry-pick-sequence.sh\n@@ -172,6 +172,26 @@ test_expect_success 'check advice when we move HEAD by committing' '\n \ttest_i18ncmp expect advice\n '\n \n+test_expect_success 'selectively advise --skip while launching another sequence' '\n+\tpristine_detach initial &&\n+\tcat >expect <<-EOF &&\n+\terror: cherry-pick is already in progress\n+\thint: try \"git cherry-pick (--continue | --skip | --abort | --quit)\"\n+\tfatal: cherry-pick failed\n+\tEOF\n+\ttest_must_fail git cherry-pick picked..yetanotherpick &&\n+\ttest_must_fail git cherry-pick picked..yetanotherpick 2>advice &&\n+\ttest_i18ncmp expect advice &&\n+\tcat >expect <<-EOF &&\n+\terror: cherry-pick is already in progress\n+\thint: try \"git cherry-pick (--continue | --abort | --quit)\"\n+\tfatal: cherry-pick failed\n+\tEOF\n+\tgit reset --merge &&\n+\ttest_must_fail git cherry-pick picked..yetanotherpick 2>advice &&\n+\ttest_i18ncmp expect advice\n+'\n+\n test_expect_success 'allow skipping commit but not abort for a new history' '\n \tpristine_detach initial &&\n \tcat >expect <<-EOF &&\n-- \n2.21.0\n\n"},{"id":"377950","messageId":"20190625091822.GB2423@hank.intra.tgummerer.com","threadId":"51269","inReplyTo":"20190623200338.17144-2-rohit.ashiwal265@gmail.com","subject":"Re: [GSoC][PATCH v7 1/6] advice: add sequencerInUse config variable","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2019-06-25T09:18:22Z","receivedAt":"2019-06-25T09:18:30Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"On 06/24, Rohit Ashiwal wrote:\n> Calls to advise() which are not guarded by advice.* config variables\n> are \"bad\" as they do not let the user say, \"I've learned this part\n> of Git enough, please don't tell me what to do verbosely.\". Add a\n> configuration variable \"sequencerInUse\" which controls whether to\n> display advice when any sequencer command is in progress.\n\nIt would be nice if this patch not only introduced this config\nvariable, but also started making use of it.  That would make it\nimmediately clear why this variable is useful.  Otherwise the commit\nmessage should state that this is only useful in a future commit.\n\nNot sure that's worth a reroll by itself though.\n\n> Signed-off-by: Rohit Ashiwal <rohit.ashiwal265@gmail.com>\n> ---\n>  Documentation/config/advice.txt | 2 ++\n>  advice.c                        | 2 ++\n>  advice.h                        | 1 +\n>  3 files changed, 5 insertions(+)\n> \n> diff --git a/Documentation/config/advice.txt b/Documentation/config/advice.txt\n> index ec4f6ae658..1cd9096c98 100644\n> --- a/Documentation/config/advice.txt\n> +++ b/Documentation/config/advice.txt\n> @@ -57,6 +57,8 @@ advice.*::\n>  \tresolveConflict::\n>  \t\tAdvice shown by various commands when conflicts\n>  \t\tprevent the operation from being performed.\n> +\tsequencerInUse::\n> +\t\tAdvice shown when a sequencer command is already in progress.\n>  \timplicitIdentity::\n>  \t\tAdvice on how to set your identity configuration when\n>  \t\tyour information is guessed from the system username and\n> diff --git a/advice.c b/advice.c\n> index ce5f374ecd..b101f0c264 100644\n> --- a/advice.c\n> +++ b/advice.c\n> @@ -15,6 +15,7 @@ int advice_status_u_option = 1;\n>  int advice_commit_before_merge = 1;\n>  int advice_reset_quiet_warning = 1;\n>  int advice_resolve_conflict = 1;\n> +int advice_sequencer_in_use = 1;\n>  int advice_implicit_identity = 1;\n>  int advice_detached_head = 1;\n>  int advice_set_upstream_failure = 1;\n> @@ -71,6 +72,7 @@ static struct {\n>  \t{ \"commitBeforeMerge\", &advice_commit_before_merge },\n>  \t{ \"resetQuiet\", &advice_reset_quiet_warning },\n>  \t{ \"resolveConflict\", &advice_resolve_conflict },\n> +\t{ \"sequencerInUse\", &advice_sequencer_in_use },\n>  \t{ \"implicitIdentity\", &advice_implicit_identity },\n>  \t{ \"detachedHead\", &advice_detached_head },\n>  \t{ \"setupStreamFailure\", &advice_set_upstream_failure },\n> diff --git a/advice.h b/advice.h\n> index e50f02cdfe..ebc838d7bc 100644\n> --- a/advice.h\n> +++ b/advice.h\n> @@ -15,6 +15,7 @@ extern int advice_status_u_option;\n>  extern int advice_commit_before_merge;\n>  extern int advice_reset_quiet_warning;\n>  extern int advice_resolve_conflict;\n> +extern int advice_sequencer_in_use;\n>  extern int advice_implicit_identity;\n>  extern int advice_detached_head;\n>  extern int advice_set_upstream_failure;\n> -- \n> 2.21.0\n> \n"},{"id":"378325","messageId":"5ae3461e-7c83-2eeb-552c-ffe838bb03b6@gmail.com","threadId":"51269","inReplyTo":"20190623200338.17144-3-rohit.ashiwal265@gmail.com","subject":"Re: [GSoC][PATCH v7 2/6] sequencer: add advice for revert","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2019-06-29T14:05:36Z","receivedAt":"2019-06-29T14:05:47Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"Hi Rohit\n\nOn 23/06/2019 21:03, Rohit Ashiwal wrote:\n> In the case of merge conflicts, while performing a revert, we are\n> currently advised to use `git cherry-pick --<sequencer-options>`\n> of which --continue is incompatible for continuing the revert.\n\nI'm not sure why this says we cannot use --continue with revert, I think \nit should work fine. Also below your new advice recommends `revert \n--continue` as an option which contradicts this part of the commit message.\n\nOh do you mean `cherry-pick --abort` and `cherry-pick --quit` work with \na revert but `cherry-pick --continue` does not? If so that's a quirk of \nthe implementation that should be fixed. If that's the case I'm think \nmentioning it just confuses the commit message. Just say the advice for \nrevert should say revert.\n\nI'd also squash the first patch into this one so the new variable is \nused when it is introduced\n\nBest Wishes\n\nPhillip\n\n> Introduce a separate advice message for `git revert`. Also change\n> the signature of `create_seq_dir` to handle which advice to display\n> selectively.\n> \n> Signed-off-by: Rohit Ashiwal <rohit.ashiwal265@gmail.com>\n> ---\n>   sequencer.c | 35 +++++++++++++++++++++++++++++------\n>   1 file changed, 29 insertions(+), 6 deletions(-)\n> \n> diff --git a/sequencer.c b/sequencer.c\n> index f88a97fb10..0ef2622a69 100644\n> --- a/sequencer.c\n> +++ b/sequencer.c\n> @@ -2650,15 +2650,38 @@ static int walk_revs_populate_todo(struct todo_list *todo_list,\n>   \treturn 0;\n>   }\n>   \n> -static int create_seq_dir(void)\n> +static int create_seq_dir(struct repository *r)\n>   {\n> -\tif (file_exists(git_path_seq_dir())) {\n> -\t\terror(_(\"a cherry-pick or revert is already in progress\"));\n> -\t\tadvise(_(\"try \\\"git cherry-pick (--continue | --quit | --abort)\\\"\"));\n> +\tenum replay_action action;\n> +\tconst char *in_progress_error = NULL;\n> +\tconst char *in_progress_advice = NULL;\n> +\n> +\tif (!sequencer_get_last_command(r, &action)) {\n> +\t\tswitch (action) {\n> +\t\tcase REPLAY_REVERT:\n> +\t\t\tin_progress_error = _(\"revert is already in progress\");\n> +\t\t\tin_progress_advice =\n> +\t\t\t_(\"try \\\"git revert (--continue | --abort | --quit)\\\"\");\n> +\t\t\tbreak;\n> +\t\tcase REPLAY_PICK:\n> +\t\t\tin_progress_error = _(\"cherry-pick is already in progress\");\n> +\t\t\tin_progress_advice =\n> +\t\t\t_(\"try \\\"git cherry-pick (--continue | --abort | --quit)\\\"\");\n> +\t\t\tbreak;\n> +\t\tdefault:\n> +\t\t\tBUG(\"unexpected action in create_seq_dir\");\n> +\t\t}\n> +\t}\n> +\tif (in_progress_error) {\n> +\t\terror(\"%s\", in_progress_error);\n> +\t\tif (advice_sequencer_in_use)\n> +\t\t\tadvise(\"%s\", in_progress_advice);\n>   \t\treturn -1;\n> -\t} else if (mkdir(git_path_seq_dir(), 0777) < 0)\n> +\t}\n> +\tif (mkdir(git_path_seq_dir(), 0777) < 0)\n>   \t\treturn error_errno(_(\"could not create sequencer directory '%s'\"),\n>   \t\t\t\t   git_path_seq_dir());\n> +\n>   \treturn 0;\n>   }\n>   \n> @@ -4237,7 +4260,7 @@ int sequencer_pick_revisions(struct repository *r,\n>   \t */\n>   \n>   \tif (walk_revs_populate_todo(&todo_list, opts) ||\n> -\t\t\tcreate_seq_dir() < 0)\n> +\t\t\tcreate_seq_dir(r) < 0)\n>   \t\treturn -1;\n>   \tif (get_oid(\"HEAD\", &oid) && (opts->action == REPLAY_REVERT))\n>   \t\treturn error(_(\"can't revert as initial commit\"));\n> \n"},{"id":"378477","messageId":"20190702091129.7531-1-rohit.ashiwal265@gmail.com","threadId":"51269","inReplyTo":"20190608191958.4593-1-rohit.ashiwal265@gmail.com","subject":"[GSoC][PATCH v8 0/5] Teach cherry-pick/revert to skip commits","fromName":"Rohit Ashiwal","fromEmail":"rohit.ashiwal265@gmail.com","sentAt":"2019-07-02T09:11:24Z","receivedAt":"2019-07-02T09:14:15Z","isPatch":true,"sender":{"key":"rohit.ashiwal265@gmail.com","avatar":"https://avatars.githubusercontent.com/u/31043830?v=4"},"body":"Another revision of my patch which takes care of all the nits.\n\nRohit Ashiwal (5):\n  sequencer: add advice for revert\n  sequencer: rename reset_for_rollback to reset_merge\n  sequencer: use argv_array in reset_merge\n  cherry-pick/revert: add --skip option\n  cherry-pick/revert: advise using --skip\n\n Documentation/config/advice.txt   |   2 +\n Documentation/git-cherry-pick.txt |   4 +-\n Documentation/git-revert.txt      |   4 +-\n Documentation/sequencer.txt       |   4 +\n advice.c                          |   2 +\n advice.h                          |   1 +\n builtin/commit.c                  |  13 +--\n builtin/revert.c                  |   5 ++\n sequencer.c                       | 134 ++++++++++++++++++++++++++----\n sequencer.h                       |   1 +\n t/t3510-cherry-pick-sequence.sh   | 122 +++++++++++++++++++++++++++\n 11 files changed, 266 insertions(+), 26 deletions(-)\n\nRange-diff:\n1:  207042a895 < -:  ---------- advice: add sequencerInUse config variable\n2:  d7c603d47f ! 1:  91d3949b69 sequencer: add advice for revert\n    @@ -3,14 +3,58 @@\n         sequencer: add advice for revert\n     \n         In the case of merge conflicts, while performing a revert, we are\n    -    currently advised to use `git cherry-pick --<sequencer-options>`\n    -    of which --continue is incompatible for continuing the revert.\n    +    currently advised to use `git cherry-pick --<sequencer-options>`.\n         Introduce a separate advice message for `git revert`. Also change\n         the signature of `create_seq_dir` to handle which advice to display\n         selectively.\n     \n         Signed-off-by: Rohit Ashiwal <rohit.ashiwal265@gmail.com>\n     \n    + diff --git a/Documentation/config/advice.txt b/Documentation/config/advice.txt\n    + --- a/Documentation/config/advice.txt\n    + +++ b/Documentation/config/advice.txt\n    +@@\n    + \tresolveConflict::\n    + \t\tAdvice shown by various commands when conflicts\n    + \t\tprevent the operation from being performed.\n    ++\tsequencerInUse::\n    ++\t\tAdvice shown when a sequencer command is already in progress.\n    + \timplicitIdentity::\n    + \t\tAdvice on how to set your identity configuration when\n    + \t\tyour information is guessed from the system username and\n    +\n    + diff --git a/advice.c b/advice.c\n    + --- a/advice.c\n    + +++ b/advice.c\n    +@@\n    + int advice_commit_before_merge = 1;\n    + int advice_reset_quiet_warning = 1;\n    + int advice_resolve_conflict = 1;\n    ++int advice_sequencer_in_use = 1;\n    + int advice_implicit_identity = 1;\n    + int advice_detached_head = 1;\n    + int advice_set_upstream_failure = 1;\n    +@@\n    + \t{ \"commitBeforeMerge\", &advice_commit_before_merge },\n    + \t{ \"resetQuiet\", &advice_reset_quiet_warning },\n    + \t{ \"resolveConflict\", &advice_resolve_conflict },\n    ++\t{ \"sequencerInUse\", &advice_sequencer_in_use },\n    + \t{ \"implicitIdentity\", &advice_implicit_identity },\n    + \t{ \"detachedHead\", &advice_detached_head },\n    + \t{ \"setupStreamFailure\", &advice_set_upstream_failure },\n    +\n    + diff --git a/advice.h b/advice.h\n    + --- a/advice.h\n    + +++ b/advice.h\n    +@@\n    + extern int advice_commit_before_merge;\n    + extern int advice_reset_quiet_warning;\n    + extern int advice_resolve_conflict;\n    ++extern int advice_sequencer_in_use;\n    + extern int advice_implicit_identity;\n    + extern int advice_detached_head;\n    + extern int advice_set_upstream_failure;\n    +\n      diff --git a/sequencer.c b/sequencer.c\n      --- a/sequencer.c\n      +++ b/sequencer.c\n3:  b70299c572 ! 2:  189ef90318 sequencer: rename reset_for_rollback to reset_merge\n    @@ -6,7 +6,7 @@\n         achieve this, we could really make use of existing functions.\n         reset_for_rollback is one such function, but the name does not\n         intuitively suggest to use it to reset a merge, which it was born to\n    -    perform see 539047c (\"revert: introduce --abort to cancel a failed\n    +    perform, see 539047c (\"revert: introduce --abort to cancel a failed\n         cherry-pick\", 2011-11-23). Change the name to reset_merge to make\n         it more intuitive.\n     \n4:  569122c861 = 3:  2b237e3174 sequencer: use argv_array in reset_merge\n5:  4580f0e5af = 4:  5d64faf501 cherry-pick/revert: add --skip option\n6:  f6f21b055b = 5:  807a344eb1 cherry-pick/revert: advise using --skip\n-- \n2.21.0\n\n"},{"id":"378478","messageId":"20190702091129.7531-2-rohit.ashiwal265@gmail.com","threadId":"51269","inReplyTo":"20190702091129.7531-1-rohit.ashiwal265@gmail.com","subject":"[GSoC][PATCH v8 1/5] sequencer: add advice for revert","fromName":"Rohit Ashiwal","fromEmail":"rohit.ashiwal265@gmail.com","sentAt":"2019-07-02T09:11:25Z","receivedAt":"2019-07-02T09:14:20Z","isPatch":true,"sender":{"key":"rohit.ashiwal265@gmail.com","avatar":"https://avatars.githubusercontent.com/u/31043830?v=4"},"body":"In the case of merge conflicts, while performing a revert, we are\ncurrently advised to use `git cherry-pick --<sequencer-options>`.\nIntroduce a separate advice message for `git revert`. Also change\nthe signature of `create_seq_dir` to handle which advice to display\nselectively.\n\nSigned-off-by: Rohit Ashiwal <rohit.ashiwal265@gmail.com>\n---\n Documentation/config/advice.txt |  2 ++\n advice.c                        |  2 ++\n advice.h                        |  1 +\n sequencer.c                     | 35 +++++++++++++++++++++++++++------\n 4 files changed, 34 insertions(+), 6 deletions(-)\n\ndiff --git a/Documentation/config/advice.txt b/Documentation/config/advice.txt\nindex ec4f6ae658..1cd9096c98 100644\n--- a/Documentation/config/advice.txt\n+++ b/Documentation/config/advice.txt\n@@ -57,6 +57,8 @@ advice.*::\n \tresolveConflict::\n \t\tAdvice shown by various commands when conflicts\n \t\tprevent the operation from being performed.\n+\tsequencerInUse::\n+\t\tAdvice shown when a sequencer command is already in progress.\n \timplicitIdentity::\n \t\tAdvice on how to set your identity configuration when\n \t\tyour information is guessed from the system username and\ndiff --git a/advice.c b/advice.c\nindex ce5f374ecd..b101f0c264 100644\n--- a/advice.c\n+++ b/advice.c\n@@ -15,6 +15,7 @@ int advice_status_u_option = 1;\n int advice_commit_before_merge = 1;\n int advice_reset_quiet_warning = 1;\n int advice_resolve_conflict = 1;\n+int advice_sequencer_in_use = 1;\n int advice_implicit_identity = 1;\n int advice_detached_head = 1;\n int advice_set_upstream_failure = 1;\n@@ -71,6 +72,7 @@ static struct {\n \t{ \"commitBeforeMerge\", &advice_commit_before_merge },\n \t{ \"resetQuiet\", &advice_reset_quiet_warning },\n \t{ \"resolveConflict\", &advice_resolve_conflict },\n+\t{ \"sequencerInUse\", &advice_sequencer_in_use },\n \t{ \"implicitIdentity\", &advice_implicit_identity },\n \t{ \"detachedHead\", &advice_detached_head },\n \t{ \"setupStreamFailure\", &advice_set_upstream_failure },\ndiff --git a/advice.h b/advice.h\nindex e50f02cdfe..ebc838d7bc 100644\n--- a/advice.h\n+++ b/advice.h\n@@ -15,6 +15,7 @@ extern int advice_status_u_option;\n extern int advice_commit_before_merge;\n extern int advice_reset_quiet_warning;\n extern int advice_resolve_conflict;\n+extern int advice_sequencer_in_use;\n extern int advice_implicit_identity;\n extern int advice_detached_head;\n extern int advice_set_upstream_failure;\ndiff --git a/sequencer.c b/sequencer.c\nindex f88a97fb10..0ef2622a69 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -2650,15 +2650,38 @@ static int walk_revs_populate_todo(struct todo_list *todo_list,\n \treturn 0;\n }\n \n-static int create_seq_dir(void)\n+static int create_seq_dir(struct repository *r)\n {\n-\tif (file_exists(git_path_seq_dir())) {\n-\t\terror(_(\"a cherry-pick or revert is already in progress\"));\n-\t\tadvise(_(\"try \\\"git cherry-pick (--continue | --quit | --abort)\\\"\"));\n+\tenum replay_action action;\n+\tconst char *in_progress_error = NULL;\n+\tconst char *in_progress_advice = NULL;\n+\n+\tif (!sequencer_get_last_command(r, &action)) {\n+\t\tswitch (action) {\n+\t\tcase REPLAY_REVERT:\n+\t\t\tin_progress_error = _(\"revert is already in progress\");\n+\t\t\tin_progress_advice =\n+\t\t\t_(\"try \\\"git revert (--continue | --abort | --quit)\\\"\");\n+\t\t\tbreak;\n+\t\tcase REPLAY_PICK:\n+\t\t\tin_progress_error = _(\"cherry-pick is already in progress\");\n+\t\t\tin_progress_advice =\n+\t\t\t_(\"try \\\"git cherry-pick (--continue | --abort | --quit)\\\"\");\n+\t\t\tbreak;\n+\t\tdefault:\n+\t\t\tBUG(\"unexpected action in create_seq_dir\");\n+\t\t}\n+\t}\n+\tif (in_progress_error) {\n+\t\terror(\"%s\", in_progress_error);\n+\t\tif (advice_sequencer_in_use)\n+\t\t\tadvise(\"%s\", in_progress_advice);\n \t\treturn -1;\n-\t} else if (mkdir(git_path_seq_dir(), 0777) < 0)\n+\t}\n+\tif (mkdir(git_path_seq_dir(), 0777) < 0)\n \t\treturn error_errno(_(\"could not create sequencer directory '%s'\"),\n \t\t\t\t   git_path_seq_dir());\n+\n \treturn 0;\n }\n \n@@ -4237,7 +4260,7 @@ int sequencer_pick_revisions(struct repository *r,\n \t */\n \n \tif (walk_revs_populate_todo(&todo_list, opts) ||\n-\t\t\tcreate_seq_dir() < 0)\n+\t\t\tcreate_seq_dir(r) < 0)\n \t\treturn -1;\n \tif (get_oid(\"HEAD\", &oid) && (opts->action == REPLAY_REVERT))\n \t\treturn error(_(\"can't revert as initial commit\"));\n-- \n2.21.0\n\n"},{"id":"378479","messageId":"20190702091129.7531-3-rohit.ashiwal265@gmail.com","threadId":"51269","inReplyTo":"20190702091129.7531-1-rohit.ashiwal265@gmail.com","subject":"[GSoC][PATCH v8 2/5] sequencer: rename reset_for_rollback to reset_merge","fromName":"Rohit Ashiwal","fromEmail":"rohit.ashiwal265@gmail.com","sentAt":"2019-07-02T09:11:26Z","receivedAt":"2019-07-02T09:14:23Z","isPatch":true,"sender":{"key":"rohit.ashiwal265@gmail.com","avatar":"https://avatars.githubusercontent.com/u/31043830?v=4"},"body":"We are on a path to teach cherry-pick/revert how to skip commits. To\nachieve this, we could really make use of existing functions.\nreset_for_rollback is one such function, but the name does not\nintuitively suggest to use it to reset a merge, which it was born to\nperform, see 539047c (\"revert: introduce --abort to cancel a failed\ncherry-pick\", 2011-11-23). Change the name to reset_merge to make\nit more intuitive.\n\nSigned-off-by: Rohit Ashiwal <rohit.ashiwal265@gmail.com>\n---\n sequencer.c | 6 +++---\n 1 file changed, 3 insertions(+), 3 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 0ef2622a69..cb856bcfc3 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -2732,7 +2732,7 @@ static int rollback_is_safe(void)\n \treturn oideq(&actual_head, &expected_head);\n }\n \n-static int reset_for_rollback(const struct object_id *oid)\n+static int reset_merge(const struct object_id *oid)\n {\n \tconst char *argv[4];\t/* reset --merge <arg> + NULL */\n \n@@ -2754,7 +2754,7 @@ static int rollback_single_pick(struct repository *r)\n \t\treturn error(_(\"cannot resolve HEAD\"));\n \tif (is_null_oid(&head_oid))\n \t\treturn error(_(\"cannot abort from a branch yet to be born\"));\n-\treturn reset_for_rollback(&head_oid);\n+\treturn reset_merge(&head_oid);\n }\n \n int sequencer_rollback(struct repository *r, struct replay_opts *opts)\n@@ -2797,7 +2797,7 @@ int sequencer_rollback(struct repository *r, struct replay_opts *opts)\n \t\twarning(_(\"You seem to have moved HEAD. \"\n \t\t\t  \"Not rewinding, check your HEAD!\"));\n \t} else\n-\tif (reset_for_rollback(&oid))\n+\tif (reset_merge(&oid))\n \t\tgoto fail;\n \tstrbuf_release(&buf);\n \treturn sequencer_remove_state(opts);\n-- \n2.21.0\n\n"},{"id":"378480","messageId":"20190702091129.7531-4-rohit.ashiwal265@gmail.com","threadId":"51269","inReplyTo":"20190702091129.7531-1-rohit.ashiwal265@gmail.com","subject":"[GSoC][PATCH v8 3/5] sequencer: use argv_array in reset_merge","fromName":"Rohit Ashiwal","fromEmail":"rohit.ashiwal265@gmail.com","sentAt":"2019-07-02T09:11:27Z","receivedAt":"2019-07-02T09:14:27Z","isPatch":true,"sender":{"key":"rohit.ashiwal265@gmail.com","avatar":"https://avatars.githubusercontent.com/u/31043830?v=4"},"body":"Avoid using magic numbers for array size and index under `reset_merge`\nfunction. Use `argv_array` instead. This will make code shorter and\neasier to extend.\n\nSigned-off-by: Rohit Ashiwal <rohit.ashiwal265@gmail.com>\n---\n sequencer.c | 17 +++++++++++------\n 1 file changed, 11 insertions(+), 6 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex cb856bcfc3..70efe36ee8 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -2734,13 +2734,18 @@ static int rollback_is_safe(void)\n \n static int reset_merge(const struct object_id *oid)\n {\n-\tconst char *argv[4];\t/* reset --merge <arg> + NULL */\n+\tint ret;\n+\tstruct argv_array argv = ARGV_ARRAY_INIT;\n \n-\targv[0] = \"reset\";\n-\targv[1] = \"--merge\";\n-\targv[2] = oid_to_hex(oid);\n-\targv[3] = NULL;\n-\treturn run_command_v_opt(argv, RUN_GIT_CMD);\n+\targv_array_pushl(&argv, \"reset\", \"--merge\", NULL);\n+\n+\tif (!is_null_oid(oid))\n+\t\targv_array_push(&argv, oid_to_hex(oid));\n+\n+\tret = run_command_v_opt(argv.argv, RUN_GIT_CMD);\n+\targv_array_clear(&argv);\n+\n+\treturn ret;\n }\n \n static int rollback_single_pick(struct repository *r)\n-- \n2.21.0\n\n"},{"id":"378481","messageId":"20190702091129.7531-5-rohit.ashiwal265@gmail.com","threadId":"51269","inReplyTo":"20190702091129.7531-1-rohit.ashiwal265@gmail.com","subject":"[GSoC][PATCH v8 4/5] cherry-pick/revert: add --skip option","fromName":"Rohit Ashiwal","fromEmail":"rohit.ashiwal265@gmail.com","sentAt":"2019-07-02T09:11:28Z","receivedAt":"2019-07-02T09:14:32Z","isPatch":true,"sender":{"key":"rohit.ashiwal265@gmail.com","avatar":"https://avatars.githubusercontent.com/u/31043830?v=4"},"body":"git am or rebase have a --skip flag to skip the current commit if the\nuser wishes to do so. During a cherry-pick or revert a user could\nlikewise skip a commit, but needs to use 'git reset' (or in the case\nof conflicts 'git reset --merge'), followed by 'git (cherry-pick |\nrevert) --continue' to skip the commit. This is more annoying and\nsometimes confusing on the users' part. Add a `--skip` option to make\nskipping commits easier for the user and to make the commands more\nconsistent.\n\nIn the next commit, we will change the advice messages hence finishing\nthe process of teaching revert and cherry-pick \"how to skip commits\".\n\nSigned-off-by: Rohit Ashiwal <rohit.ashiwal265@gmail.com>\n---\n Documentation/git-cherry-pick.txt |   4 +-\n Documentation/git-revert.txt      |   4 +-\n Documentation/sequencer.txt       |   4 ++\n builtin/revert.c                  |   5 ++\n sequencer.c                       |  73 +++++++++++++++++++++\n sequencer.h                       |   1 +\n t/t3510-cherry-pick-sequence.sh   | 102 ++++++++++++++++++++++++++++++\n 7 files changed, 187 insertions(+), 6 deletions(-)\n\ndiff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt\nindex 754b16ce0c..83ce51aedf 100644\n--- a/Documentation/git-cherry-pick.txt\n+++ b/Documentation/git-cherry-pick.txt\n@@ -10,9 +10,7 @@ SYNOPSIS\n [verse]\n 'git cherry-pick' [--edit] [-n] [-m parent-number] [-s] [-x] [--ff]\n \t\t  [-S[<keyid>]] <commit>...\n-'git cherry-pick' --continue\n-'git cherry-pick' --quit\n-'git cherry-pick' --abort\n+'git cherry-pick' (--continue | --skip | --abort | --quit)\n \n DESCRIPTION\n -----------\ndiff --git a/Documentation/git-revert.txt b/Documentation/git-revert.txt\nindex 0c82ca5bc0..665e065ee3 100644\n--- a/Documentation/git-revert.txt\n+++ b/Documentation/git-revert.txt\n@@ -9,9 +9,7 @@ SYNOPSIS\n --------\n [verse]\n 'git revert' [--[no-]edit] [-n] [-m parent-number] [-s] [-S[<keyid>]] <commit>...\n-'git revert' --continue\n-'git revert' --quit\n-'git revert' --abort\n+'git revert' (--continue | --skip | --abort | --quit)\n \n DESCRIPTION\n -----------\ndiff --git a/Documentation/sequencer.txt b/Documentation/sequencer.txt\nindex 5a57c4a407..3bceb56474 100644\n--- a/Documentation/sequencer.txt\n+++ b/Documentation/sequencer.txt\n@@ -3,6 +3,10 @@\n \t`.git/sequencer`.  Can be used to continue after resolving\n \tconflicts in a failed cherry-pick or revert.\n \n+--skip::\n+\tSkip the current commit and continue with the rest of the\n+\tsequence.\n+\n --quit::\n \tForget about the current operation in progress.  Can be used\n \tto clear the sequencer state after a failed cherry-pick or\ndiff --git a/builtin/revert.c b/builtin/revert.c\nindex d4dcedbdc6..5dc5891ea2 100644\n--- a/builtin/revert.c\n+++ b/builtin/revert.c\n@@ -102,6 +102,7 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)\n \t\tOPT_CMDMODE(0, \"quit\", &cmd, N_(\"end revert or cherry-pick sequence\"), 'q'),\n \t\tOPT_CMDMODE(0, \"continue\", &cmd, N_(\"resume revert or cherry-pick sequence\"), 'c'),\n \t\tOPT_CMDMODE(0, \"abort\", &cmd, N_(\"cancel revert or cherry-pick sequence\"), 'a'),\n+\t\tOPT_CMDMODE(0, \"skip\", &cmd, N_(\"skip current commit and continue\"), 's'),\n \t\tOPT_CLEANUP(&cleanup_arg),\n \t\tOPT_BOOL('n', \"no-commit\", &opts->no_commit, N_(\"don't automatically commit\")),\n \t\tOPT_BOOL('e', \"edit\", &opts->edit, N_(\"edit the commit message\")),\n@@ -151,6 +152,8 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)\n \t\t\tthis_operation = \"--quit\";\n \t\telse if (cmd == 'c')\n \t\t\tthis_operation = \"--continue\";\n+\t\telse if (cmd == 's')\n+\t\t\tthis_operation = \"--skip\";\n \t\telse {\n \t\t\tassert(cmd == 'a');\n \t\t\tthis_operation = \"--abort\";\n@@ -210,6 +213,8 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)\n \t\treturn sequencer_continue(the_repository, opts);\n \tif (cmd == 'a')\n \t\treturn sequencer_rollback(the_repository, opts);\n+\tif (cmd == 's')\n+\t\treturn sequencer_skip(the_repository, opts);\n \treturn sequencer_pick_revisions(the_repository, opts);\n }\n \ndiff --git a/sequencer.c b/sequencer.c\nindex 70efe36ee8..f5e3d60878 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -2762,6 +2762,15 @@ static int rollback_single_pick(struct repository *r)\n \treturn reset_merge(&head_oid);\n }\n \n+static int skip_single_pick(void)\n+{\n+\tstruct object_id head;\n+\n+\tif (read_ref_full(\"HEAD\", 0, &head, NULL))\n+\t\treturn error(_(\"cannot resolve HEAD\"));\n+\treturn reset_merge(&head);\n+}\n+\n int sequencer_rollback(struct repository *r, struct replay_opts *opts)\n {\n \tFILE *f;\n@@ -2811,6 +2820,70 @@ int sequencer_rollback(struct repository *r, struct replay_opts *opts)\n \treturn -1;\n }\n \n+int sequencer_skip(struct repository *r, struct replay_opts *opts)\n+{\n+\tenum replay_action action = -1;\n+\tsequencer_get_last_command(r, &action);\n+\n+\t/*\n+\t * Check whether the subcommand requested to skip the commit is actually\n+\t * in progress and that it's safe to skip the commit.\n+\t *\n+\t * opts->action tells us which subcommand requested to skip the commit.\n+\t * If the corresponding .git/<ACTION>_HEAD exists, we know that the\n+\t * action is in progress and we can skip the commit.\n+\t *\n+\t * Otherwise we check that the last instruction was related to the\n+\t * particular subcommand we're trying to execute and barf if that's not\n+\t * the case.\n+\t *\n+\t * Finally we check that the rollback is \"safe\", i.e., has the HEAD\n+\t * moved? In this case, it doesn't make sense to \"reset the merge\" and\n+\t * \"skip the commit\" as the user already handled this by committing. But\n+\t * we'd not want to barf here, instead give advice on how to proceed. We\n+\t * only need to check that when .git/<ACTION>_HEAD doesn't exist because\n+\t * it gets removed when the user commits, so if it still exists we're\n+\t * sure the user can't have committed before.\n+\t */\n+\tswitch (opts->action) {\n+\tcase REPLAY_REVERT:\n+\t\tif (!file_exists(git_path_revert_head(r))) {\n+\t\t\tif (action != REPLAY_REVERT)\n+\t\t\t\treturn error(_(\"no revert in progress\"));\n+\t\t\tif (!rollback_is_safe())\n+\t\t\t\tgoto give_advice;\n+\t\t}\n+\t\tbreak;\n+\tcase REPLAY_PICK:\n+\t\tif (!file_exists(git_path_cherry_pick_head(r))) {\n+\t\t\tif (action != REPLAY_PICK)\n+\t\t\t\treturn error(_(\"no cherry-pick in progress\"));\n+\t\t\tif (!rollback_is_safe())\n+\t\t\t\tgoto give_advice;\n+\t\t}\n+\t\tbreak;\n+\tdefault:\n+\t\tBUG(\"unexpected action in sequencer_skip\");\n+\t}\n+\n+\tif (skip_single_pick())\n+\t\treturn error(_(\"failed to skip the commit\"));\n+\tif (!is_directory(git_path_seq_dir()))\n+\t\treturn 0;\n+\n+\treturn sequencer_continue(r, opts);\n+\n+give_advice:\n+\terror(_(\"there is nothing to skip\"));\n+\n+\tif (advice_resolve_conflict) {\n+\t\tadvise(_(\"have you committed already?\\n\"\n+\t\t\t \"try \\\"git %s --continue\\\"\"),\n+\t\t\t action == REPLAY_REVERT ? \"revert\" : \"cherry-pick\");\n+\t}\n+\treturn -1;\n+}\n+\n static int save_todo(struct todo_list *todo_list, struct replay_opts *opts)\n {\n \tstruct lock_file todo_lock = LOCK_INIT;\ndiff --git a/sequencer.h b/sequencer.h\nindex 0c494b83d4..731b9853eb 100644\n--- a/sequencer.h\n+++ b/sequencer.h\n@@ -129,6 +129,7 @@ int sequencer_pick_revisions(struct repository *repo,\n \t\t\t     struct replay_opts *opts);\n int sequencer_continue(struct repository *repo, struct replay_opts *opts);\n int sequencer_rollback(struct repository *repo, struct replay_opts *opts);\n+int sequencer_skip(struct repository *repo, struct replay_opts *opts);\n int sequencer_remove_state(struct replay_opts *opts);\n \n #define TODO_LIST_KEEP_EMPTY (1U << 0)\ndiff --git a/t/t3510-cherry-pick-sequence.sh b/t/t3510-cherry-pick-sequence.sh\nindex 941d5026da..20515ea37b 100755\n--- a/t/t3510-cherry-pick-sequence.sh\n+++ b/t/t3510-cherry-pick-sequence.sh\n@@ -93,6 +93,108 @@ test_expect_success 'cherry-pick cleans up sequencer state upon success' '\n \ttest_path_is_missing .git/sequencer\n '\n \n+test_expect_success 'cherry-pick --skip requires cherry-pick in progress' '\n+\tpristine_detach initial &&\n+\ttest_must_fail git cherry-pick --skip\n+'\n+\n+test_expect_success 'revert --skip requires revert in progress' '\n+\tpristine_detach initial &&\n+\ttest_must_fail git revert --skip\n+'\n+\n+test_expect_success 'cherry-pick --skip to skip commit' '\n+\tpristine_detach initial &&\n+\ttest_must_fail git cherry-pick anotherpick &&\n+\ttest_must_fail git revert --skip &&\n+\tgit cherry-pick --skip &&\n+\ttest_cmp_rev initial HEAD &&\n+\ttest_path_is_missing .git/CHERRY_PICK_HEAD\n+'\n+\n+test_expect_success 'revert --skip to skip commit' '\n+\tpristine_detach anotherpick &&\n+\ttest_must_fail git revert anotherpick~1 &&\n+\ttest_must_fail git cherry-pick --skip &&\n+\tgit revert --skip &&\n+\ttest_cmp_rev anotherpick HEAD\n+'\n+\n+test_expect_success 'skip \"empty\" commit' '\n+\tpristine_detach picked &&\n+\ttest_commit dummy foo d &&\n+\ttest_must_fail git cherry-pick anotherpick &&\n+\tgit cherry-pick --skip &&\n+\ttest_cmp_rev dummy HEAD\n+'\n+\n+test_expect_success 'skip a commit and check if rest of sequence is correct' '\n+\tpristine_detach initial &&\n+\techo e >expect &&\n+\tcat >expect.log <<-EOF &&\n+\tOBJID\n+\t:100644 100644 OBJID OBJID M\tfoo\n+\tOBJID\n+\t:100644 100644 OBJID OBJID M\tfoo\n+\tOBJID\n+\t:100644 100644 OBJID OBJID M\tunrelated\n+\tOBJID\n+\t:000000 100644 OBJID OBJID A\tfoo\n+\t:000000 100644 OBJID OBJID A\tunrelated\n+\tEOF\n+\ttest_must_fail git cherry-pick base..yetanotherpick &&\n+\ttest_must_fail git cherry-pick --skip &&\n+\techo d >foo &&\n+\tgit add foo &&\n+\tgit cherry-pick --continue &&\n+\t{\n+\t\tgit rev-list HEAD |\n+\t\tgit diff-tree --root --stdin |\n+\t\tsed \"s/$OID_REGEX/OBJID/g\"\n+\t} >actual.log &&\n+\ttest_cmp expect foo &&\n+\ttest_cmp expect.log actual.log\n+'\n+\n+test_expect_success 'check advice when we move HEAD by committing' '\n+\tpristine_detach initial &&\n+\tcat >expect <<-EOF &&\n+\terror: there is nothing to skip\n+\thint: have you committed already?\n+\thint: try \"git cherry-pick --continue\"\n+\tfatal: cherry-pick failed\n+\tEOF\n+\ttest_must_fail git cherry-pick base..yetanotherpick &&\n+\techo c >foo &&\n+\tgit commit -a &&\n+\ttest_path_is_missing .git/CHERRY_PICK_HEAD &&\n+\ttest_must_fail git cherry-pick --skip 2>advice &&\n+\ttest_i18ncmp expect advice\n+'\n+\n+test_expect_success 'allow skipping commit but not abort for a new history' '\n+\tpristine_detach initial &&\n+\tcat >expect <<-EOF &&\n+\terror: cannot abort from a branch yet to be born\n+\tfatal: cherry-pick failed\n+\tEOF\n+\tgit checkout --orphan new_disconnected &&\n+\tgit reset --hard &&\n+\ttest_must_fail git cherry-pick anotherpick &&\n+\ttest_must_fail git cherry-pick --abort 2>advice &&\n+\tgit cherry-pick --skip &&\n+\ttest_i18ncmp expect advice\n+'\n+\n+test_expect_success 'allow skipping stopped cherry-pick because of untracked file modifications' '\n+\tpristine_detach initial &&\n+\tgit rm --cached unrelated &&\n+\tgit commit -m \"untrack unrelated\" &&\n+\ttest_must_fail git cherry-pick initial base &&\n+\ttest_path_is_missing .git/CHERRY_PICK_HEAD &&\n+\tgit cherry-pick --skip\n+'\n+\n test_expect_success '--quit does not complain when no cherry-pick is in progress' '\n \tpristine_detach initial &&\n \tgit cherry-pick --quit\n-- \n2.21.0\n\n"},{"id":"378482","messageId":"20190702091129.7531-6-rohit.ashiwal265@gmail.com","threadId":"51269","inReplyTo":"20190702091129.7531-1-rohit.ashiwal265@gmail.com","subject":"[GSoC][PATCH v8 5/5] cherry-pick/revert: advise using --skip","fromName":"Rohit Ashiwal","fromEmail":"rohit.ashiwal265@gmail.com","sentAt":"2019-07-02T09:11:29Z","receivedAt":"2019-07-02T09:14:35Z","isPatch":true,"sender":{"key":"rohit.ashiwal265@gmail.com","avatar":"https://avatars.githubusercontent.com/u/31043830?v=4"},"body":"The previous commit introduced a --skip flag for cherry-pick and\nrevert. Update the advice messages, to tell users about this less\ncumbersome way of skipping commits. Also add tests to ensure\neverything is working fine.\n\nSigned-off-by: Rohit Ashiwal <rohit.ashiwal265@gmail.com>\n---\n builtin/commit.c                | 13 ++++++++-----\n sequencer.c                     |  9 ++++++---\n t/t3510-cherry-pick-sequence.sh | 20 ++++++++++++++++++++\n 3 files changed, 34 insertions(+), 8 deletions(-)\n\ndiff --git a/builtin/commit.c b/builtin/commit.c\nindex 1c9e8e2228..1f47c51bdc 100644\n--- a/builtin/commit.c\n+++ b/builtin/commit.c\n@@ -60,15 +60,18 @@ N_(\"The previous cherry-pick is now empty, possibly due to conflict resolution.\\\n \"\\n\");\n \n static const char empty_cherry_pick_advice_single[] =\n-N_(\"Otherwise, please use 'git reset'\\n\");\n+N_(\"Otherwise, please use 'git cherry-pick --skip'\\n\");\n \n static const char empty_cherry_pick_advice_multi[] =\n-N_(\"If you wish to skip this commit, use:\\n\"\n+N_(\"and then use:\\n\"\n \"\\n\"\n-\"    git reset\\n\"\n+\"    git cherry-pick --continue\\n\"\n \"\\n\"\n-\"Then \\\"git cherry-pick --continue\\\" will resume cherry-picking\\n\"\n-\"the remaining commits.\\n\");\n+\"to resume cherry-picking the remaining commits.\\n\"\n+\"If you wish to skip this commit, use:\\n\"\n+\"\\n\"\n+\"    git cherry-pick --skip\\n\"\n+\"\\n\");\n \n static const char *color_status_slots[] = {\n \t[WT_STATUS_HEADER]\t  = \"header\",\ndiff --git a/sequencer.c b/sequencer.c\nindex f5e3d60878..2e7b16b75f 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -2655,18 +2655,20 @@ static int create_seq_dir(struct repository *r)\n \tenum replay_action action;\n \tconst char *in_progress_error = NULL;\n \tconst char *in_progress_advice = NULL;\n+\tunsigned int advise_skip = file_exists(git_path_revert_head(r)) ||\n+\t\t\t\tfile_exists(git_path_cherry_pick_head(r));\n \n \tif (!sequencer_get_last_command(r, &action)) {\n \t\tswitch (action) {\n \t\tcase REPLAY_REVERT:\n \t\t\tin_progress_error = _(\"revert is already in progress\");\n \t\t\tin_progress_advice =\n-\t\t\t_(\"try \\\"git revert (--continue | --abort | --quit)\\\"\");\n+\t\t\t_(\"try \\\"git revert (--continue | %s--abort | --quit)\\\"\");\n \t\t\tbreak;\n \t\tcase REPLAY_PICK:\n \t\t\tin_progress_error = _(\"cherry-pick is already in progress\");\n \t\t\tin_progress_advice =\n-\t\t\t_(\"try \\\"git cherry-pick (--continue | --abort | --quit)\\\"\");\n+\t\t\t_(\"try \\\"git cherry-pick (--continue | %s--abort | --quit)\\\"\");\n \t\t\tbreak;\n \t\tdefault:\n \t\t\tBUG(\"unexpected action in create_seq_dir\");\n@@ -2675,7 +2677,8 @@ static int create_seq_dir(struct repository *r)\n \tif (in_progress_error) {\n \t\terror(\"%s\", in_progress_error);\n \t\tif (advice_sequencer_in_use)\n-\t\t\tadvise(\"%s\", in_progress_advice);\n+\t\t\tadvise(in_progress_advice,\n+\t\t\t\tadvise_skip ? \"--skip | \" : \"\");\n \t\treturn -1;\n \t}\n \tif (mkdir(git_path_seq_dir(), 0777) < 0)\ndiff --git a/t/t3510-cherry-pick-sequence.sh b/t/t3510-cherry-pick-sequence.sh\nindex 20515ea37b..793bcc7fe3 100755\n--- a/t/t3510-cherry-pick-sequence.sh\n+++ b/t/t3510-cherry-pick-sequence.sh\n@@ -172,6 +172,26 @@ test_expect_success 'check advice when we move HEAD by committing' '\n \ttest_i18ncmp expect advice\n '\n \n+test_expect_success 'selectively advise --skip while launching another sequence' '\n+\tpristine_detach initial &&\n+\tcat >expect <<-EOF &&\n+\terror: cherry-pick is already in progress\n+\thint: try \"git cherry-pick (--continue | --skip | --abort | --quit)\"\n+\tfatal: cherry-pick failed\n+\tEOF\n+\ttest_must_fail git cherry-pick picked..yetanotherpick &&\n+\ttest_must_fail git cherry-pick picked..yetanotherpick 2>advice &&\n+\ttest_i18ncmp expect advice &&\n+\tcat >expect <<-EOF &&\n+\terror: cherry-pick is already in progress\n+\thint: try \"git cherry-pick (--continue | --abort | --quit)\"\n+\tfatal: cherry-pick failed\n+\tEOF\n+\tgit reset --merge &&\n+\ttest_must_fail git cherry-pick picked..yetanotherpick 2>advice &&\n+\ttest_i18ncmp expect advice\n+'\n+\n test_expect_success 'allow skipping commit but not abort for a new history' '\n \tpristine_detach initial &&\n \tcat >expect <<-EOF &&\n-- \n2.21.0\n\n"},{"id":"378499","messageId":"64b16b96-8c87-8010-9355-2d13c55f9d2f@gmail.com","threadId":"51269","inReplyTo":"20190702091129.7531-1-rohit.ashiwal265@gmail.com","subject":"Re: [GSoC][PATCH v8 0/5] Teach cherry-pick/revert to skip commits","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2019-07-02T15:26:27Z","receivedAt":"2019-07-02T15:26:34Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"Hi Rohit\n\nThanks for re-rolling again (and bearing with all the review rounds), I \nthink the range-diff looks good. These are ready for next as far as I'm \nconcerned.\n\nBest Wishes\n\nPhillip\n\nOn 02/07/2019 10:11, Rohit Ashiwal wrote:\n> Another revision of my patch which takes care of all the nits.\n> \n> Rohit Ashiwal (5):\n>    sequencer: add advice for revert\n>    sequencer: rename reset_for_rollback to reset_merge\n>    sequencer: use argv_array in reset_merge\n>    cherry-pick/revert: add --skip option\n>    cherry-pick/revert: advise using --skip\n> \n>   Documentation/config/advice.txt   |   2 +\n>   Documentation/git-cherry-pick.txt |   4 +-\n>   Documentation/git-revert.txt      |   4 +-\n>   Documentation/sequencer.txt       |   4 +\n>   advice.c                          |   2 +\n>   advice.h                          |   1 +\n>   builtin/commit.c                  |  13 +--\n>   builtin/revert.c                  |   5 ++\n>   sequencer.c                       | 134 ++++++++++++++++++++++++++----\n>   sequencer.h                       |   1 +\n>   t/t3510-cherry-pick-sequence.sh   | 122 +++++++++++++++++++++++++++\n>   11 files changed, 266 insertions(+), 26 deletions(-)\n> \n> Range-diff:\n> 1:  207042a895 < -:  ---------- advice: add sequencerInUse config variable\n> 2:  d7c603d47f ! 1:  91d3949b69 sequencer: add advice for revert\n>      @@ -3,14 +3,58 @@\n>           sequencer: add advice for revert\n>       \n>           In the case of merge conflicts, while performing a revert, we are\n>      -    currently advised to use `git cherry-pick --<sequencer-options>`\n>      -    of which --continue is incompatible for continuing the revert.\n>      +    currently advised to use `git cherry-pick --<sequencer-options>`.\n>           Introduce a separate advice message for `git revert`. Also change\n>           the signature of `create_seq_dir` to handle which advice to display\n>           selectively.\n>       \n>           Signed-off-by: Rohit Ashiwal <rohit.ashiwal265@gmail.com>\n>       \n>      + diff --git a/Documentation/config/advice.txt b/Documentation/config/advice.txt\n>      + --- a/Documentation/config/advice.txt\n>      + +++ b/Documentation/config/advice.txt\n>      +@@\n>      + \tresolveConflict::\n>      + \t\tAdvice shown by various commands when conflicts\n>      + \t\tprevent the operation from being performed.\n>      ++\tsequencerInUse::\n>      ++\t\tAdvice shown when a sequencer command is already in progress.\n>      + \timplicitIdentity::\n>      + \t\tAdvice on how to set your identity configuration when\n>      + \t\tyour information is guessed from the system username and\n>      +\n>      + diff --git a/advice.c b/advice.c\n>      + --- a/advice.c\n>      + +++ b/advice.c\n>      +@@\n>      + int advice_commit_before_merge = 1;\n>      + int advice_reset_quiet_warning = 1;\n>      + int advice_resolve_conflict = 1;\n>      ++int advice_sequencer_in_use = 1;\n>      + int advice_implicit_identity = 1;\n>      + int advice_detached_head = 1;\n>      + int advice_set_upstream_failure = 1;\n>      +@@\n>      + \t{ \"commitBeforeMerge\", &advice_commit_before_merge },\n>      + \t{ \"resetQuiet\", &advice_reset_quiet_warning },\n>      + \t{ \"resolveConflict\", &advice_resolve_conflict },\n>      ++\t{ \"sequencerInUse\", &advice_sequencer_in_use },\n>      + \t{ \"implicitIdentity\", &advice_implicit_identity },\n>      + \t{ \"detachedHead\", &advice_detached_head },\n>      + \t{ \"setupStreamFailure\", &advice_set_upstream_failure },\n>      +\n>      + diff --git a/advice.h b/advice.h\n>      + --- a/advice.h\n>      + +++ b/advice.h\n>      +@@\n>      + extern int advice_commit_before_merge;\n>      + extern int advice_reset_quiet_warning;\n>      + extern int advice_resolve_conflict;\n>      ++extern int advice_sequencer_in_use;\n>      + extern int advice_implicit_identity;\n>      + extern int advice_detached_head;\n>      + extern int advice_set_upstream_failure;\n>      +\n>        diff --git a/sequencer.c b/sequencer.c\n>        --- a/sequencer.c\n>        +++ b/sequencer.c\n> 3:  b70299c572 ! 2:  189ef90318 sequencer: rename reset_for_rollback to reset_merge\n>      @@ -6,7 +6,7 @@\n>           achieve this, we could really make use of existing functions.\n>           reset_for_rollback is one such function, but the name does not\n>           intuitively suggest to use it to reset a merge, which it was born to\n>      -    perform see 539047c (\"revert: introduce --abort to cancel a failed\n>      +    perform, see 539047c (\"revert: introduce --abort to cancel a failed\n>           cherry-pick\", 2011-11-23). Change the name to reset_merge to make\n>           it more intuitive.\n>       \n> 4:  569122c861 = 3:  2b237e3174 sequencer: use argv_array in reset_merge\n> 5:  4580f0e5af = 4:  5d64faf501 cherry-pick/revert: add --skip option\n> 6:  f6f21b055b = 5:  807a344eb1 cherry-pick/revert: advise using --skip\n> \n"}]}