threads / discuss / 43045

Re: git cherry-pick conflict error message is deceptive when cherry-picking multiple commits

Subject: Re: git cherry-pick conflict error message is deceptive when cherry-picking multiple commits

## tl;dr

8 messages between Aug 10, 2016 and Aug 18, 2016.

replies: 7people: 5as markdown or json

Stephen Morton· Aug 10, 2016, 19:21 UTC · lore

On Mon, Aug 1, 2016 at 5:12 AM, Johannes Schindelin <Johannes.Schindelin@gmx.de> wrote:

Show 46 quoted lines
> Hi Stephen,
>
> On Wed, 27 Jul  2016, Stephen Morton wrote:
>
>> On Wed, Jul  27, 2016 at 11:03 AM, Johannes Schindelin
>>  <Johannes.Schindelin@gmx.de> wrote:
>> >
>> > On Wed,  27 Jul 2016, Stephen Morton wrote:
>> >
>> >>  diff --git a/sequencer.c b/sequencer.c
>> >>  index cdfac82..ce06876 100644
>> >> ---  a/sequencer.c
>> >> +++  b/sequencer.c
>> >> @@  -176,7 +176,8 @@ static void print_advice(int show_hint, struct
>> >>  replay_opts *opts)
>> >>             else
>> >>                     advise(_("after resolving the conflicts, mark
>> >> the  corrected paths\n"
>> >>                              "with 'git add <paths>' or 'git rm <paths>'\n"
>> >> -                              "and commit the result with 'git commit'"));
>> >> +                              "then continue the %s with 'git %s
>> >>  --continue'\n"
>> >> +                              "or cancel the %s operation with 'git
>> >> %s  --abort'" ),  action_name(opts), action_name(opts),
>> >>  action_name(opts), action_name(opts));
>> >
>> > That is  an awful lot of repetition right there, with an added
>> >  inconsistency that the action is referred to by its name alone in the
>> >  "--continue" case, but with "operation" added in the "--abort" case.
>> >
>> > And  additionally, in the most common case (one commit to cherry-pick), the
>> > advice  now suggests a more complicated operation than necessary: a simply
>> > `git  commit` would be enough, then.
>> >
>> > Can't  we have a test whether this is the last of the commits to be
>> >  cherry-picked, and if so, have the simpler advice again?
>>
>> Ok, knowing  that I'm not on the last element of the sequencer is
>> beyond my  git code knowledge.
>
> Oh, my mistake:  I meant to say that this information could be easily
> provided by  `pick_commits()` if it passed it to `print_advice()` via
>  `do_pick_commit()`.
>
> Ciao,
> Johannes

Formatting on previous email was terrible, plus the diff wasn't performed against origin. Re-sending.

(Finally getting back to this.)
Something like the diff below, then Johannes?

(I intentionally print the '--continue' hint even in the case whereit's last of n commits that fails.)

Stephen
~/ws/extern/git (maint *%>) > git diff @{u}
diff --git a/sequencer.c b/sequencer.c
index c6362d6..e0071aa 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -154,7 +154,7 @@ static void free_message(struct commit *commit, 
struct commit_message *msg)
         unuse_commit_buffer(commit, msg->message);
  }

-static void print_advice(int show_hint, struct replay_opts *opts)
+static void print_advice(int show_hint, int multiple_commits, struct 
replay_opts *opts)
  {
         char *msg = getenv("GIT_CHERRY_PICK_HELP");

@@ -174,9 +174,14 @@ static void print_advice(int show_hint, struct 
replay_opts *opts)
                         advise(_("after resolving the conflicts, mark 
the corrected paths\n"
                                  "with 'git add <paths>' or 'git rm 
<paths>'"));
                 else
-                       advise(_("after resolving the conflicts, mark 
the corrected paths\n"
-                                "with 'git add <paths>' or 'git rm 
<paths>'\n"
-                                "and commit the result with 'git 
commit'"));
+                        if  (multiple_commits)
+                               advise(_("after resolving the conflicts, 
mark the corrected paths with 'git add <paths>' or 'git rm <paths>'\n"
+                                        "then continue with 'git %s 
--continue'\n"
+                                        "or cancel with 'git %s 
--abort'" ), action_name(opts), action_name(opts));
+                        else
+                                advise(_("after resolving the 
conflicts, mark the corrected paths\n"
+                                        "with 'git add <paths>' or 'git 
rm <paths>'\n"
+                                        "and commit the result with 
'git commit'"));
         }
  }

@@ -440,7 +445,7 @@ static int allow_empty(struct replay_opts *opts, 
struct commit *commit)
                 return 1;
  }

-static int do_pick_commit(struct commit *commit, struct replay_opts *opts)
+static int do_pick_commit(struct commit *commit, struct replay_opts 
*opts, int multiple_commits)
  {
         unsigned char head[20];
         struct commit *base, *next, *parent;
@@ -595,7 +600,7 @@ static int do_pick_commit(struct commit *commit, 
struct replay_opts *opts)
                       : _("could not apply %s... %s"),
                       find_unique_abbrev(commit->object.oid.hash, 
DEFAULT_ABBREV),
                       msg.subject);
-               print_advice(res == 1, opts);
+               print_advice(res == 1, multiple_commits, opts);
                 rerere(opts->allow_rerere_auto);
                 goto leave;
         }
@@ -959,6 +964,7 @@ static int pick_commits(struct commit_list 
*todo_list, struct replay_opts *opts)
  {
         struct commit_list *cur;
         int res;
+    int multiple_commits = (todo_list->next) != NULL;

         setenv(GIT_REFLOG_ACTION, action_name(opts), 0);
         if (opts->allow_ff)
@@ -968,7 +974,7 @@ static int pick_commits(struct commit_list 
*todo_list, struct replay_opts *opts)

         for (cur = todo_list; cur; cur = cur->next) {
                 save_todo(cur, opts);
-               res = do_pick_commit(cur->item, opts);
+               res = do_pick_commit(cur->item, opts, multiple_commits);
                 if (res)
                         return res;
         }
@@ -1016,7 +1022,7 @@ static int sequencer_continue(struct replay_opts 
*opts)
  static int single_pick(struct commit *cmit, struct replay_opts *opts)
  {
         setenv(GIT_REFLOG_ACTION, action_name(opts), 0);
-       return do_pick_commit(cmit, opts);
+       return do_pick_commit(cmit, opts, 0);
  }

  int sequencer_pick_revisions(struct replay_opts *opts)
-- 
Stephen Morton, 7750 SR Product Group, SW Development Tools/DevOps
w: +1-613-784-6026 (int: 2-825-6026) m: +1-613-302-2589 | EST Time Zone
Christian Couder· Aug 14, 2016, 11:44 UTC · re: Stephen Morton · lore
Hi Stephen,

On Wed, Aug 10, 2016 at 9:21 PM, Stephen Morton <stephen.morton@nokia.com> wrote:

>
> Formatting on previous email was terrible, plus the diff wasn't performed
> against origin. Re-sending.
Thanks for working on this...
> (Finally getting back to this.)
>
> Something like the diff below, then Johannes?
...but please try to send a real patch.

There is https://github.com/git/git/blob/master/Documentation/SubmittingPatches and also SubmitGit that can help you do that.

Show 20 quoted lines
> (I intentionally print the '--continue' hint even in the case whereit's last
> of n commits that fails.)
>
>
> Stephen
>
>
> ~/ws/extern/git (maint *%>) > git diff @{u}
> diff --git a/sequencer.c b/sequencer.c
> index c6362d6..e0071aa 100644
> --- a/sequencer.c
> +++ b/sequencer.c
> @@ -154,7 +154,7 @@ static void free_message(struct commit *commit, struct
> commit_message *msg)
>         unuse_commit_buffer(commit, msg->message);
>  }
>
> -static void print_advice(int show_hint, struct replay_opts *opts)
> +static void print_advice(int show_hint, int multiple_commits, struct
> replay_opts *opts)
Here multiple_commits is not the last argument...
Show 41 quoted lines
>  {
>         char *msg = getenv("GIT_CHERRY_PICK_HELP");
>
> @@ -174,9 +174,14 @@ static void print_advice(int show_hint, struct
> replay_opts *opts)
>                         advise(_("after resolving the conflicts, mark the
> corrected paths\n"
>                                  "with 'git add <paths>' or 'git rm
> <paths>'"));
>                 else
> -                       advise(_("after resolving the conflicts, mark the
> corrected paths\n"
> -                                "with 'git add <paths>' or 'git rm
> <paths>'\n"
> -                                "and commit the result with 'git
> commit'"));
> +                        if  (multiple_commits)
> +                               advise(_("after resolving the conflicts,
> mark the corrected paths with 'git add <paths>' or 'git rm <paths>'\n"
> +                                        "then continue with 'git %s
> --continue'\n"
> +                                        "or cancel with 'git %s --abort'"
> ), action_name(opts), action_name(opts));
> +                        else
> +                                advise(_("after resolving the conflicts,
> mark the corrected paths\n"
> +                                        "with 'git add <paths>' or 'git rm
> <paths>'\n"
> +                                        "and commit the result with 'git
> commit'"));
>         }
>  }
>
> @@ -440,7 +445,7 @@ static int allow_empty(struct replay_opts *opts, struct
> commit *commit)
>                 return 1;
>  }
>
> -static int do_pick_commit(struct commit *commit, struct replay_opts *opts)
> +static int do_pick_commit(struct commit *commit, struct replay_opts *opts,
> int multiple_commits)

... but here multiple_commits is the last argument. It would be better if it was more consistent.

Show 20 quoted lines
>  {
>         unsigned char head[20];
>         struct commit *base, *next, *parent;
> @@ -595,7 +600,7 @@ static int do_pick_commit(struct commit *commit, struct
> replay_opts *opts)
>                       : _("could not apply %s... %s"),
>                       find_unique_abbrev(commit->object.oid.hash,
> DEFAULT_ABBREV),
>                       msg.subject);
> -               print_advice(res == 1, opts);
> +               print_advice(res == 1, multiple_commits, opts);
>                 rerere(opts->allow_rerere_auto);
>                 goto leave;
>         }
> @@ -959,6 +964,7 @@ static int pick_commits(struct commit_list *todo_list,
> struct replay_opts *opts)
>  {
>         struct commit_list *cur;
>         int res;
> +    int multiple_commits = (todo_list->next) != NULL;
Why not "last_commit" instead of "multiple_commits"?

Thanks, Christian.

Stephen Morton· Aug 17, 2016, 13:42 UTC · re: Christian Couder · lore
Responding to a few comments...
On 2016-08-14 7:44 AM, Christian Couder wrote:
> multiple_commits)
> ... but here multiple_commits is the last argument.
> It would be better if it was more consistent.

(Johannes made the same comment.) Yes. Will do.

>
> multiple_commits = (todo_list->next) != NULL;
> Why not "last_commit" instead of "multiple_commits"?
>

Because it *isn't*. You can see that in pick_commits(), I set multiple_commits outside of the `for todo_list` loop. It is not re-evaluated at every iteration of the loop. As per my comment when emailing the patch "I intentionally print the '--continue' hint even in the case where it's last of n commits that fails. " I think it makes much more sense that "this is the message you always get when cherry-picking multiple commits as opposed to "this is the message you sometimes get, except when it's the last one". (Yes, the careful observer will realize that if when cherry-picking multiple commits, there are conflicts in the second-last and last then the --continue from the second-last will result in multiple_commits being set to 0. I can live with that.)

On 2016-08-16 4:44 AM, Remi Galan Alfonso wrote:
Show 32 quoted lines
> Hi Stephen,
>
> Stephen Morton <stephen.morton@nokia.com> writes:
>> +                        if  (multiple_commits)
>> +                               advise(_("after resolving the conflicts,
>> mark the corrected paths with 'git add <paths>' or 'git rm <paths>'\n"
>> +                                        "then continue with 'git %s
>> --continue'\n"
>> +                                        "or cancel with 'git %s
>> --abort'" ), action_name(opts), action_name(opts));
>> +                        else
>> +                                advise(_("after resolving the
>> conflicts, mark the corrected paths\n"
>> +                                        "with 'git add <paths>' or 'git
>> rm <paths>'\n"
>> +                                        "and commit the result with
>> 'git commit'"));
> In both cases (multiple_commits or not), the beginning of the advise
> is nearly the same, with only a '\n' in the middle being the
> difference:
>
> multiple_commits:
>   "after resolving the conflicts, mark the corrected paths with 'git
>   add <paths>' or 'git rm <paths>'\n"
>
> !multiple_commits:
>   "after resolving the conflicts, mark the corrected paths\n with 'git
>   add <paths>' or 'git rm <paths>'\n"
>                                                    ~~~~~~~^
>
> In 'multiple_commits' case the advise is more than 80 characters long,
> did you forget the '\n' in that case?

A previous comment had indicated that having 4 lines was too many. And I tend to agree. So I tried to squash it into 3. Back in xterm days, 80 characters was sacrosanct, but is it really a big deal to exceed it now?

On 2016-08-14 7:44 AM, Christian Couder wrote:
> ...but please try to send a real patch.
>
> There is https://github.com/git/git/blob/master/Documentation/SubmittingPatches
> and also SubmitGit that can help you do that.

Agreed. I just want to send a patch that stands a reasonable chance of getting accepted.

Stephen
-- 
Stephen Morton, 7750 SR Product Group, SW Development Tools/DevOps
w: +1-613-784-6026 (int: 2-825-6026) m: +1-613-302-2589 | EST Time Zone
Remi Galan Alfonso· Aug 17, 2016, 14:24 UTC · re: Stephen Morton · lore
Stephen Morton <stephen.morton@nokia.com> writes:
Show 37 quoted lines
> [snip]
> On 2016-08-16 4:44 AM, Remi Galan Alfonso wrote:
>> Hi Stephen,
>>
>> Stephen Morton <stephen.morton@nokia.com> writes:
>>> +                        if  (multiple_commits)
>>> +                               advise(_("after resolving the conflicts,
>>> mark the corrected paths with 'git add <paths>' or 'git rm <paths>'\n"
>>> +                                        "then continue with 'git %s
>>> --continue'\n"
>>> +                                        "or cancel with 'git %s
>>> --abort'" ), action_name(opts), action_name(opts));
>>> +                        else
>>> +                                advise(_("after resolving the
>>> conflicts, mark the corrected paths\n"
>>> +                                        "with 'git add <paths>' or 'git
>>> rm <paths>'\n"
>>> +                                        "and commit the result with
>>> 'git commit'"));
>> In both cases (multiple_commits or not), the beginning of the advise
>> is nearly the same, with only a '\n' in the middle being the
>> difference:
>>
>> multiple_commits:
>>   "after resolving the conflicts, mark the corrected paths with 'git
>>   add <paths>' or 'git rm <paths>'\n"
>>
>> !multiple_commits:
>>   "after resolving the conflicts, mark the corrected paths\n with 'git
>>   add <paths>' or 'git rm <paths>'\n"
>>                                                    ~~~~~~~^
>>
>> In 'multiple_commits' case the advise is more than 80 characters long,
>> did you forget the '\n' in that case?
> A previous comment had indicated that having 4 lines was too many. And I
> tend to agree. So I tried to squash it into 3. Back in xterm days, 80
> characters was sacrosanct, but is it really a big deal to exceed it now?

Either way (3 or 4 lines) I find it strange to have both advices start in the same way except that one is split and not the other.

I cannot tell if it's a big deal or not to exceed 80 characters but FWIW most of my stuff (terminal and emacs) is 80 columns long, and I haven't known the "xterm days".

Thanks, Rémi

Johannes Schindelin· Aug 18, 2016, 14:15 UTC · re: Stephen Morton · lore
Hi Stephen,
On Wed, 17 Aug 2016, Stephen Morton wrote:
> > multiple_commits = (todo_list->next) != NULL;
> > Why not "last_commit" instead of "multiple_commits"?
> 
> Because it *isn't*.

Personally, I do prefer to have the simpler instruction if the commit happens to be the last one cherry-picked.

I do not follow your argument that it makes sense to decide based on the total number of commits that were to be cherry-picked whether to use the more cumbersome or the easier command.

Instead, I think the user should be given the simplest advice that gets them out of the fix most quickly. And if `git commit --amend` is good enough, we should not advise to use `git cherry-pick --continue`, and that is that.

Ciao, Johannes

Remi Galan Alfonso· Aug 16, 2016, 08:44 UTC · re: Stephen Morton · lore
Hi Stephen,
Stephen Morton <stephen.morton@nokia.com> writes:
Show 14 quoted lines
> +                        if  (multiple_commits)
> +                               advise(_("after resolving the conflicts,
> mark the corrected paths with 'git add <paths>' or 'git rm <paths>'\n"
> +                                        "then continue with 'git %s
> --continue'\n"
> +                                        "or cancel with 'git %s
> --abort'" ), action_name(opts), action_name(opts));
> +                        else
> +                                advise(_("after resolving the
> conflicts, mark the corrected paths\n"
> +                                        "with 'git add <paths>' or 'git
> rm <paths>'\n"
> +                                        "and commit the result with
> 'git commit'"));

In both cases (multiple_commits or not), the beginning of the advise is nearly the same, with only a '\n' in the middle being the difference:

multiple_commits:
 "after resolving the conflicts, mark the corrected paths with 'git
 add <paths>' or 'git rm <paths>'\n"
!multiple_commits:
 "after resolving the conflicts, mark the corrected paths\n with 'git
 add <paths>' or 'git rm <paths>'\n"
                                                  ~~~~~~~^

In 'multiple_commits' case the advise is more than 80 characters long, did you forget the '\n' in that case?

If you end up using the same beginning of advice, maybe it's possible to give it before the 'if(multiple_commits)' and avoid duplication of the lines.

Thanks, Rémi

Johannes Schindelin· Aug 17, 2016, 09:13 UTC · re: Remi Galan Alfonso · lore
Hi,
On Tue, 16 Aug 2016, Remi Galan Alfonso wrote:
Show 35 quoted lines
> Stephen Morton <stephen.morton@nokia.com> writes:
> > +                        if  (multiple_commits)
> > +                               advise(_("after resolving the conflicts,
> > mark the corrected paths with 'git add <paths>' or 'git rm <paths>'\n"
> > +                                        "then continue with 'git %s
> > --continue'\n"
> > +                                        "or cancel with 'git %s
> > --abort'" ), action_name(opts), action_name(opts));
> > +                        else
> > +                                advise(_("after resolving the
> > conflicts, mark the corrected paths\n"
> > +                                        "with 'git add <paths>' or 'git
> > rm <paths>'\n"
> > +                                        "and commit the result with
> > 'git commit'"));
> 
> In both cases (multiple_commits or not), the beginning of the advise
> is nearly the same, with only a '\n' in the middle being the
> difference:
> 
> multiple_commits:
>  "after resolving the conflicts, mark the corrected paths with 'git
>  add <paths>' or 'git rm <paths>'\n"
> 
> !multiple_commits:
>  "after resolving the conflicts, mark the corrected paths\n with 'git
>  add <paths>' or 'git rm <paths>'\n"
>                                                   ~~~~~~~^
> 
> In 'multiple_commits' case the advise is more than 80 characters long,
> did you forget the '\n' in that case?
> 
> If you end up using the same beginning of advice, maybe it's possible
> to give it before the 'if(multiple_commits)' and avoid duplication of
> the lines.

I concur with this, and also with Christian's advice to append the parameter consistently as last one, and also with renaming it to "last_commit".

Ciao, Johannes

← back to recent threads