Subject: Re: bug/defaults: COMMIT_EDITMSG not reused after a failed commit

From: Junio C Hamano <[email-masked]>
Date: Thu, 25 Jul 2024 08:21:18 -0700

Jeff King <[email-masked]> writes:

> It just told you about COMMIT_EDITMSG, making it your responsibility to
> recover it before running "git commit" again. Your (1) makes it a little
> nicer, in that you can run "git commit" and then pull the content from
> the other file into your editor. Or we could even provide an option to
> pre-populate the message with it.
>
> Junio was lukewarm on the original, so I'm not sure why I've been
> holding on to it all these years. But maybe it would help as a guide for
> anybody who wants to work on what you've proposed above.

I think it was only me being allergic of the use of atexit() for a
narrow single purpose, and perhaps I was hoping that we might be
able to come up with a bit more generalized interface, possibly
based on atexit(), to register common cleanup "hooks", as back then
we only had a handful of calls to atexit() in mid 2012, and I was
worried that we may add a lot more of them in an uncontrolled way.

> -- >8 --
> From: Jeff King <[email-masked]>
> Date: Mon, 23 Jul 2012 14:52:18 -0400
> Subject: [PATCH] commit: give a hint when a commit message has been abandoned
>
> If we launch an editor for the user to create a commit
> message, they may put significant work into doing so.
> Typically we try to check common mistakes that could cause
> the commit to fail early, so that we die before the user
> goes to the trouble.
>
> We may still experience some errors afterwards, though; in
> this case, the user is given no hint that their commit
> message has been saved. Let's tell them where it is.
>
> Signed-off-by: Jeff King <[email-masked]>
> ---
>  builtin/commit.c                          | 15 +++++++++++++++
>  t/t7500-commit-template-squash-signoff.sh |  3 +--
>  2 files changed, 16 insertions(+), 2 deletions(-)
>
> diff --git a/builtin/commit.c b/builtin/commit.c
> index dec78dfb86..42fefaa0e3 100644
> --- a/builtin/commit.c
> +++ b/builtin/commit.c
> @@ -160,6 +160,16 @@ static int opt_parse_porcelain(const struct option *opt, const char *arg, int un
>  	return 0;
>  }
>  
> +static int mention_abandoned_message;
> +static void maybe_mention_abandoned_message(void)
> +{
> +	if (!mention_abandoned_message)
> +		return;
> +	advise(_("Your commit message has been saved in '%s' and will be\n"
> +		 "overwritten by the next invocation of \"git commit\"."),
> +	       git_path_commit_editmsg());
> +}
> +
>  static int opt_parse_m(const struct option *opt, const char *arg, int unset)
>  {
>  	struct strbuf *buf = opt->value;
> @@ -1090,6 +1100,8 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
>  			exit(1);
>  		}
>  		strvec_clear(&env);
> +		atexit(maybe_mention_abandoned_message);
> +		mention_abandoned_message = 1;
>  	}
>  
>  	if (!no_verify &&
> @@ -1813,11 +1825,13 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
>  	if (message_is_empty(&sb, cleanup_mode) && !allow_empty_message) {
>  		rollback_index_files();
>  		fprintf(stderr, _("Aborting commit due to empty commit message.\n"));
> +		mention_abandoned_message = 0;
>  		exit(1);
>  	}
>  	if (template_untouched(&sb, template_file, cleanup_mode) && !allow_empty_message) {
>  		rollback_index_files();
>  		fprintf(stderr, _("Aborting commit; you did not edit the message.\n"));
> +		mention_abandoned_message = 0;
>  		exit(1);
>  	}
>  
> @@ -1855,6 +1869,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
>  		die("%s", err.buf);
>  	}
>  
> +	mention_abandoned_message = 0;
>  	sequencer_post_commit_cleanup(the_repository, 0);
>  	unlink(git_path_merge_head(the_repository));
>  	unlink(git_path_merge_msg(the_repository));
> diff --git a/t/t7500-commit-template-squash-signoff.sh b/t/t7500-commit-template-squash-signoff.sh
> index 4dca8d97a7..c476a26235 100755
> --- a/t/t7500-commit-template-squash-signoff.sh
> +++ b/t/t7500-commit-template-squash-signoff.sh
> @@ -396,13 +396,12 @@ test_expect_success 'consecutive amend! commits remove amend! line from commit m
>  
>  test_expect_success 'deny to create amend! commit if its commit msg body is empty' '
>  	commit_for_rebase_autosquash_setup &&
> -	echo "Aborting commit due to empty commit message body." >expected &&
>  	(
>  		set_fake_editor &&
>  		test_must_fail env FAKE_COMMIT_MESSAGE="amend! target message subject line" \
>  			git commit --fixup=amend:HEAD~ 2>actual
>  	) &&
> -	test_cmp expected actual
> +	grep "Aborting commit due to empty commit message body" actual
>  '
>  
>  test_expect_success 'amend! commit allows empty commit msg body with --allow-empty-message' '