Skip to content

[Outreachy] commit: display advice hints when commit fails #495

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 12 additions & 6 deletions builtin/commit.c
Original file line number Diff line number Diff line change
Expand Up @@ -811,12 +811,6 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
old_display_comment_prefix = s->display_comment_prefix;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On the Git mailing list, Junio C Hamano wrote (reply to this):

"Heba Waly via GitGitGadget" <[email protected]> writes:

> diff --git a/builtin/commit.c b/builtin/commit.c
> index e48c1fd90a..868c0d7819 100644
> --- a/builtin/commit.c
> +++ b/builtin/commit.c
> @@ -811,12 +811,6 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
>  	old_display_comment_prefix = s->display_comment_prefix;
>  	s->display_comment_prefix = 1;
>  
> -	/*
> -	 * Most hints are counter-productive when the commit has
> -	 * already started.
> -	 */
> -	s->hints = 0;
> -

Hmm.

> @@ -837,6 +831,12 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
>  		int saved_color_setting;
>  		struct ident_split ci, ai;
>  
> +		/*
> +		 * Most hints are counter-productive when displayed in
> +		 * the commit message editor.
> +		 */
> +		s->hints = 0;
> +

We no longer drop s->hints when we are not using editor and not
including status (i.e. the "else" side) because these lines are
moved inside "if".  As this change is not about that "no editor"
side, I am not 100% convinced that this is a good change.

> @@ -912,6 +912,12 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
>  		saved_color_setting = s->use_color;
>  		s->use_color = 0;
>  		committable = run_status(s->fp, index_file, prefix, 1, s);
> +		if(!committable)

Style: SP between "if" and "(".

> +			/*
> +			 Status is to be printed to stdout, so hints will be useful to the
> +			 user. Reset s->hints to what the user configured
> +			 */
> +			s->hints = advice_status_hints;

The "if" side has been changed to flip s->hints to the configured
advice hints value when !committable here.  The "else" side
(i.e. when we are not using editor and not including status) does
not do anything to s->hints after finding out if committable after
this change.  Because "s->hints = 0" was moved to "if" with this
patch, the "else" side no longer drops s->hints at all.

So the final run_status() called when the attempt to commit is
rejected will feed s->hints that is not cleared with this change.

Is that intended?  Is the updated behaviour checked with a test?

>  		s->use_color = saved_color_setting;
>  		string_list_clear(&s->change, 1);
>  	} else {

This fix was about "we do not want to unconditionally drop the
advice messages when we reject the attempt to commit and show the
output like 'git status'", wasn't it?  The earlier single-liner fix
in v1 that flips s->hints just before calling run_status() before
rejecting the attempt to commit was a lot easier to reason about, as
the fix was very focused and to the point.  Why are we seeing this
many (seemingly unrelated) changes?

Puzzled...

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On the Git mailing list, Junio C Hamano wrote (reply to this):

Junio C Hamano <[email protected]> writes:

> This fix was about "we do not want to unconditionally drop the
> advice messages when we reject the attempt to commit and show the
> output like 'git status'", wasn't it?  The earlier single-liner fix
> in v1 that flips s->hints just before calling run_status() before
> rejecting the attempt to commit was a lot easier to reason about, as
> the fix was very focused and to the point.  Why are we seeing this
> many (seemingly unrelated) changes?

In any case, here is what I tentatively have in my tree (with heavy
rewrite to the proposed log message).

-- >8 --
From: Heba Waly <[email protected]>
Date: Tue, 17 Dec 2019 09:17:22 +0000
Subject: [PATCH] commit: honor advice.statusHints when rejecting an empty
 commit

In ea9882bfc4 (commit: disable status hints when writing to
COMMIT_EDITMSG, 2013-09-12) the intent was to disable status hints
when writing to COMMIT_EDITMSG, because giving the hints in the "git
status" like output in the commit message template are too late to
be useful (they say things like "'git add' to stage", but that is
only possible after aborting the current "git commit" session).

But there is one case that the hints can be useful: When the current
attempt to commit is rejected because no change is recorded in the
index.  The message is given and "git commit" errors out, so the
hints can immediately be followed by the user.  Teach the codepath
to honor the configuration variable.

Signed-off-by: Heba Waly <[email protected]>
Signed-off-by: Junio C Hamano <[email protected]>
---
 builtin/commit.c                          | 1 +
 t/t7500-commit-template-squash-signoff.sh | 9 +++++++++
 2 files changed, 10 insertions(+)

diff --git a/builtin/commit.c b/builtin/commit.c
index e588bc6ad3..0078faf117 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -944,6 +944,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
 	 */
 	if (!committable && whence != FROM_MERGE && !allow_empty &&
 	    !(amend && is_a_merge(current_head))) {
+		s->hints = advice_status_hints;
 		s->display_comment_prefix = old_display_comment_prefix;
 		run_status(stdout, index_file, prefix, 0, s);
 		if (amend)
diff --git a/t/t7500-commit-template-squash-signoff.sh b/t/t7500-commit-template-squash-signoff.sh
index 46a5cd4b73..a8179e4074 100755
--- a/t/t7500-commit-template-squash-signoff.sh
+++ b/t/t7500-commit-template-squash-signoff.sh
@@ -382,4 +382,13 @@ test_expect_success 'check commit with unstaged rename and copy' '
 	)
 '
 
+test_expect_success 'commit without staging files fails and displays hints' '
+	echo "initial" >>file &&
+	git add file &&
+	git commit -m initial &&
+	echo "changes" >>file &&
+	test_must_fail git commit -m update >actual &&
+	test_i18ngrep "no changes added to commit (use \"git add\" and/or \"git commit -a\")" actual
+'
+
 test_done
-- 
2.24.1-732-ga9f9d4909c

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On the Git mailing list, Eric Sunshine wrote (reply to this):

On Thu, Dec 19, 2019 at 2:22 PM Junio C Hamano <[email protected]> wrote:
> In any case, here is what I tentatively have in my tree (with heavy
> rewrite to the proposed log message).
>
> +test_expect_success 'commit without staging files fails and displays hints' '
> +       echo "initial" >>file &&

The use of '>>' here rather than '>' feels wrong, especially when
"initial" is used for both the file body and the commit message,
causing a reader of the test to wonder if this test somehow depends
upon earlier tests.

> +       git add file &&
> +       git commit -m initial &&
> +       echo "changes" >>file &&
> +       test_must_fail git commit -m update >actual &&
> +       test_i18ngrep "no changes added to commit (use \"git add\" and/or \"git commit -a\")" actual
> +'

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On the Git mailing list, Junio C Hamano wrote (reply to this):

Eric Sunshine <[email protected]> writes:

> On Thu, Dec 19, 2019 at 2:22 PM Junio C Hamano <[email protected]> wrote:
>> In any case, here is what I tentatively have in my tree (with heavy
>> rewrite to the proposed log message).
>>
>> +test_expect_success 'commit without staging files fails and displays hints' '
>> +       echo "initial" >>file &&
>
> The use of '>>' here rather than '>' feels wrong, especially when
> "initial" is used for both the file body and the commit message,
> causing a reader of the test to wonder if this test somehow depends
> upon earlier tests.

Yeah, makes sense.  This was verbatim from v1 but I think starting
the file from scratch like you suggest makes it clearer what is
going on.


>
>> +       git add file &&
>> +       git commit -m initial &&
>> +       echo "changes" >>file &&
>> +       test_must_fail git commit -m update >actual &&
>> +       test_i18ngrep "no changes added to commit (use \"git add\" and/or \"git commit -a\")" actual
>> +'

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On the Git mailing list, Emily Shaffer wrote (reply to this):

On Thu, Dec 19, 2019 at 11:22:38AM -0800, Junio C Hamano wrote:
> Junio C Hamano <[email protected]> writes:
> 
> > This fix was about "we do not want to unconditionally drop the
> > advice messages when we reject the attempt to commit and show the
> > output like 'git status'", wasn't it?  The earlier single-liner fix
> > in v1 that flips s->hints just before calling run_status() before
> > rejecting the attempt to commit was a lot easier to reason about, as
> > the fix was very focused and to the point.  Why are we seeing this
> > many (seemingly unrelated) changes?
> 
> In any case, here is what I tentatively have in my tree (with heavy
> rewrite to the proposed log message).

Hm. I'm surprised to see this feedback come in the form of a local
change when making the topic branch, rather than in a reply to the v1
patch. What's the reasoning? (Or is this scissors patch intended to be
the feedback?)

I ask because out of all of us, it seems the Outreachy interns can
benefit the most from advice on how and why to write their commit
messages - that is, part of the point of an internship is to learn best
practices and cultural norms in addition to coding practice. (Plus, I
find being asked to rewrite a commit message tends to force me to
understand my own change even better than before.)

I'll go ahead and look through the changes to the commit message so I
can learn what you're looking for too :)

> 
> -- >8 --
> From: Heba Waly <[email protected]>
> Date: Tue, 17 Dec 2019 09:17:22 +0000
> Subject: [PATCH] commit: honor advice.statusHints when rejecting an empty
>  commit
> 
> In ea9882bfc4 (commit: disable status hints when writing to
> COMMIT_EDITMSG, 2013-09-12) the intent was to disable status hints
> when writing to COMMIT_EDITMSG, because giving the hints in the "git
> status" like output in the commit message template are too late to
> be useful (they say things like "'git add' to stage", but that is
> only possible after aborting the current "git commit" session).

More context on why the previous change was made - "by the time the
editor was open, it was too late to apply hints anyways". Sure.

> 
> But there is one case that the hints can be useful: When the current
> attempt to commit is rejected because no change is recorded in the
> index.  The message is given and "git commit" errors out, so the
> hints can immediately be followed by the user.  Teach the codepath
> to honor the configuration variable.

Expanding the "but" to supply the specific story this commit touches,
including "what happens instead" and "how are we gonna fix it".

And the copy-paste of the output before and the output now is different.
For me, I don't particularly see why we'd want to be rid of it - it sort
of feels like "a picture is worth a thousand words" to include the
actual use case in the commit message. Is there style guidance
suggesting not to do that that I missed?

 - Emily

> 
> Signed-off-by: Heba Waly <[email protected]>
> Signed-off-by: Junio C Hamano <[email protected]>
> ---
>  builtin/commit.c                          | 1 +
>  t/t7500-commit-template-squash-signoff.sh | 9 +++++++++
>  2 files changed, 10 insertions(+)
> 
> diff --git a/builtin/commit.c b/builtin/commit.c
> index e588bc6ad3..0078faf117 100644
> --- a/builtin/commit.c
> +++ b/builtin/commit.c
> @@ -944,6 +944,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
>  	 */
>  	if (!committable && whence != FROM_MERGE && !allow_empty &&
>  	    !(amend && is_a_merge(current_head))) {
> +		s->hints = advice_status_hints;
>  		s->display_comment_prefix = old_display_comment_prefix;
>  		run_status(stdout, index_file, prefix, 0, s);
>  		if (amend)
> diff --git a/t/t7500-commit-template-squash-signoff.sh b/t/t7500-commit-template-squash-signoff.sh
> index 46a5cd4b73..a8179e4074 100755
> --- a/t/t7500-commit-template-squash-signoff.sh
> +++ b/t/t7500-commit-template-squash-signoff.sh
> @@ -382,4 +382,13 @@ test_expect_success 'check commit with unstaged rename and copy' '
>  	)
>  '
>  
> +test_expect_success 'commit without staging files fails and displays hints' '
> +	echo "initial" >>file &&
> +	git add file &&
> +	git commit -m initial &&
> +	echo "changes" >>file &&
> +	test_must_fail git commit -m update >actual &&
> +	test_i18ngrep "no changes added to commit (use \"git add\" and/or \"git commit -a\")" actual
> +'
> +
>  test_done
> -- 
> 2.24.1-732-ga9f9d4909c
> 

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On the Git mailing list, Junio C Hamano wrote (reply to this):

Emily Shaffer <[email protected]> writes:

> Hm. I'm surprised to see this feedback come in the form of a local
> change when making the topic branch, rather than in a reply to the v1
> patch. What's the reasoning? (Or is this scissors patch intended to be
> the feedback?)

You haven't seen a suggestion in the form of counter-proposal?

> I ask because out of all of us, it seems the Outreachy interns can
> benefit the most from advice on how and why to write their commit
> messages - that is, part of the point of an internship is to learn best
> practices and cultural norms in addition to coding practice. (Plus, I
> find being asked to rewrite a commit message tends to force me to
> understand my own change even better than before.)

It's something Mentors can help doing (I do not necessarily have
time for that myself), and you're welcome to use the "tenatively
queued" version as an example.

> I'll go ahead and look through the changes to the commit message so I
> can learn what you're looking for too :)

Nice.

One thing you missed in your review of the "tentatively queued"
version is the reversal of the order of presentation.  Instead of
starting with "I decided to do this" without explanation, give the
picture of status quo to set the stage, explain what issue exists in
the current behaviour, and then describe what approach was chosen to
solve the issue.

> For me, I don't particularly see why we'd want to be rid of it - it sort
> of feels like "a picture is worth a thousand words" to include the
> actual use case in the commit message.

Output coming from commands and/or options that are used only in a
bit more advanced workflow and the ones that are rarely seen, I do
agree that showing example is a good way to illustrate exactly what
you are talking about.

On the other hand, for behaviour of basic local commands like "git
add", "git commit", "git diff", ..., I do not necessarily agree, as
these should be obvious and clear to all the intended audiences,
which would be "anybody who has used Git for say more than two
weeks.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On the Git mailing list, Emily Shaffer wrote (reply to this):

On Fri, Dec 20, 2019 at 10:34:28AM -0800, Junio C Hamano wrote:
> Emily Shaffer <[email protected]> writes:
> 
> > Hm. I'm surprised to see this feedback come in the form of a local
> > change when making the topic branch, rather than in a reply to the v1
> > patch. What's the reasoning? (Or is this scissors patch intended to be
> > the feedback?)
> 
> You haven't seen a suggestion in the form of counter-proposal?

I actually have only seen the scissors-patch as a "yes, and" in
practice. I think this is a sign I should be doing more reviews ;)

> 
> > I ask because out of all of us, it seems the Outreachy interns can
> > benefit the most from advice on how and why to write their commit
> > messages - that is, part of the point of an internship is to learn best
> > practices and cultural norms in addition to coding practice. (Plus, I
> > find being asked to rewrite a commit message tends to force me to
> > understand my own change even better than before.)
> 
> It's something Mentors can help doing (I do not necessarily have
> time for that myself), and you're welcome to use the "tenatively
> queued" version as an example.
> 
> > I'll go ahead and look through the changes to the commit message so I
> > can learn what you're looking for too :)
> 
> Nice.
> 
> One thing you missed in your review of the "tentatively queued"
> version is the reversal of the order of presentation.  Instead of
> starting with "I decided to do this" without explanation, give the
> picture of status quo to set the stage, explain what issue exists in
> the current behaviour, and then describe what approach was chosen to
> solve the issue.

Thanks for explaining this - that's a good point for me to take home.

> 
> > For me, I don't particularly see why we'd want to be rid of it - it sort
> > of feels like "a picture is worth a thousand words" to include the
> > actual use case in the commit message.
> 
> Output coming from commands and/or options that are used only in a
> bit more advanced workflow and the ones that are rarely seen, I do
> agree that showing example is a good way to illustrate exactly what
> you are talking about.
> 
> On the other hand, for behaviour of basic local commands like "git
> add", "git commit", "git diff", ..., I do not necessarily agree, as
> these should be obvious and clear to all the intended audiences,
> which would be "anybody who has used Git for say more than two
> weeks.

Hm, I see. Thanks for clarifying.

 - Emily

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On the Git mailing list, Jonathan Tan wrote (reply to this):

> > This fix was about "we do not want to unconditionally drop the
> > advice messages when we reject the attempt to commit and show the
> > output like 'git status'", wasn't it?  The earlier single-liner fix
> > in v1 that flips s->hints just before calling run_status() before
> > rejecting the attempt to commit was a lot easier to reason about, as
> > the fix was very focused and to the point.  Why are we seeing this
> > many (seemingly unrelated) changes?
> 
> In any case, here is what I tentatively have in my tree (with heavy
> rewrite to the proposed log message).

Junio, what are your plans over what you have in your tree? If you'd
like to hear Heba's opinion on it, then she can chime in; if you'd like
a review, then I think it's good to go in.

I think the main area of discussion is whether we should go with Heba's
attempt to address Emily's comment [1]:

> I think the intent of that commit was to not put hints into the editor,
> so does it make sense to instead wrap this guy:
> 
>   /*                                                                       
>    * Most hints are counter-productive when the commit has                 
>    * already started.                                                      
>    */                                                                      
>   s->hints = 0;  
> 
> in "if (use_editor)"?
> 
> I didn't try it on my end. Maybe it won't help much, because we think
> we're going to use the editor right up until we realize it's not
> committable?

And I think the answer to that is "s" is used throughout the function in
various ways (in particular, used to print statuses both to stdout and
to the message template) so any wrapping or corralling of scope would
just make things more complicated. In particular, the way Heba did it in
v2 is more unclear - at the time of setting s->hints = 0, it's done
within a "if (use_editor && include_status)" block, but (as far as I can
tell) the commit message template might also be used when there is no
editor - for example, as input to a hook. And more importantly, when
s->hints is reset to the config, we don't know at that point that the
next status is going to stdout. So I think it's better just to use the
v1 way.

The second area of discussion I see is in the commit message. Commit
messages have to balance brevity and comprehensiveness, and this can be
a subjective matter, but I think Junio's strikes a good balance.

[1] https://lore.kernel.org/git/[email protected]/

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On the Git mailing list, Junio C Hamano wrote (reply to this):

Jonathan Tan <[email protected]> writes:

>> In any case, here is what I tentatively have in my tree (with heavy
>> rewrite to the proposed log message).
>
> Junio, what are your plans over what you have in your tree? If you'd
> like to hear Heba's opinion on it, then she can chime in; if you'd like
> a review, then I think it's good to go in.

On hold until anything like those happens ;-) 

A random reviewer mentioning something on a patch (either in a
line-by-line critique form or "how about doing it this way instead"
counterproposal form) without getting followed up by others
(including the original author) is a stall review thread, and it
does not change the equation if the random reviewer happens to be me.

>> I didn't try it on my end. Maybe it won't help much, because we think
>> we're going to use the editor right up until we realize it's not
>> committable?
>
> And I think the answer to that is "s" is used throughout the function in
> various ways (in particular, used to print statuses both to stdout and
> to the message template) so any wrapping or corralling of scope would
> just make things more complicated. In particular, the way Heba did it in
> v2 is more unclear - at the time of setting s->hints = 0, it's done

You mean "less clear" (just double checking if I got the negation right)?

> within a "if (use_editor && include_status)" block, but (as far as I can
> tell) the commit message template might also be used when there is no
> editor - for example, as input to a hook. And more importantly, when
> s->hints is reset to the config, we don't know at that point that the
> next status is going to stdout. So I think it's better just to use the
> v1 way.

Yeah, thanks for going back to compare v1 and v2, and I agree with
your assessment.

> The second area of discussion I see is in the commit message. Commit
> messages have to balance brevity and comprehensiveness, and this can be
> a subjective matter, but I think Junio's strikes a good balance.

As one side of the comparison is my own, I won't be a good judge on
this, but yes I tried to strick a good balance as much as possible.

I think I've merged it to 'next' yesterday, but it does not mean
that much as we are in -rc and it is not such an urgent "oops we
broke it in this cycle, let's fix it" issue.  If we see a v3 that
improves it, I do not mind at all reverting what I merged to 'next'
and use the updated one instead (either way, it will be in 'master'
during the next cycle at the earliest).

Thanks.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On the Git mailing list, Jonathan Tan wrote (reply to this):

> > Junio, what are your plans over what you have in your tree? If you'd
> > like to hear Heba's opinion on it, then she can chime in; if you'd like
> > a review, then I think it's good to go in.
> 
> On hold until anything like those happens ;-) 
> 
> A random reviewer mentioning something on a patch (either in a
> line-by-line critique form or "how about doing it this way instead"
> counterproposal form) without getting followed up by others
> (including the original author) is a stall review thread, and it
> does not change the equation if the random reviewer happens to be me.

OK :-)

> > And I think the answer to that is "s" is used throughout the function in
> > various ways (in particular, used to print statuses both to stdout and
> > to the message template) so any wrapping or corralling of scope would
> > just make things more complicated. In particular, the way Heba did it in
> > v2 is more unclear - at the time of setting s->hints = 0, it's done
> 
> You mean "less clear" (just double checking if I got the negation right)?

Yes, less clear - v2 is less clear than v1.

> I think I've merged it to 'next' yesterday, but it does not mean
> that much as we are in -rc and it is not such an urgent "oops we
> broke it in this cycle, let's fix it" issue.  If we see a v3 that
> improves it, I do not mind at all reverting what I merged to 'next'
> and use the updated one instead (either way, it will be in 'master'
> during the next cycle at the earliest).

Sounds good - thanks.

s->display_comment_prefix = 1;

/*
* Most hints are counter-productive when the commit has
* already started.
*/
s->hints = 0;

if (clean_message_contents)
strbuf_stripspace(&sb, 0);

Expand All @@ -837,6 +831,12 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
int saved_color_setting;
struct ident_split ci, ai;

/*
* Most hints are counter-productive when displayed in
* the commit message editor.
*/
s->hints = 0;

if (whence != FROM_COMMIT) {
if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS &&
!merge_contains_scissors)
Expand Down Expand Up @@ -912,6 +912,12 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
saved_color_setting = s->use_color;
s->use_color = 0;
committable = run_status(s->fp, index_file, prefix, 1, s);
if(!committable)
/*
Status is to be printed to stdout, so hints will be useful to the
user. Reset s->hints to what the user configured
*/
s->hints = advice_status_hints;
s->use_color = saved_color_setting;
string_list_clear(&s->change, 1);
} else {
Expand Down
9 changes: 9 additions & 0 deletions t/t7500-commit-template-squash-signoff.sh
Original file line number Diff line number Diff line change
Expand Up @@ -382,4 +382,13 @@ test_expect_success 'check commit with unstaged rename and copy' '
)
'

test_expect_success 'commit without staging files fails and displays hints' '
echo "initial" >>file &&
git add file &&
git commit -m initial &&
echo "changes" >>file &&
test_must_fail git commit -m update >actual &&
test_i18ngrep "no changes added to commit (use \"git add\" and/or \"git commit -a\")" actual
'

test_done