git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Re: [PATCH v6 2/3] am: support --empty option to handle empty patches

From
Junio C Hamano <gitster@pobox.com>
Date
Nov 19, 2021, 00:56 UTC
Message-ID
<xmqqwnl5rmi3.fsf@gitster.g>
In-Reply-To
<96d8573dc808bc32990842675ca32a0d1e8a8cef.1637232636.git.gitgitgadget@gmail.com>
"Aleen via GitGitGadget" <gitgitgadget@gmail.com> writes:
> From: Aleen <aleen42@vip.qq.com>

Here is a place to explain to readers what it exactly means to "support --empty option to handle empty patches". You know what you meant, I happen to know what you meant because I haven't forgotten yet, but we are writing for developers in the future who need to fix bugs in 6 months down the road to decide if this commit is involved in the bug in "git am" they are hunting.

Show 27 quoted lines
> Signed-off-by: Aleen <aleen42@vip.qq.com>
> ---
>  Documentation/git-am.txt |  9 +++++
>  builtin/am.c             | 48 +++++++++++++++++++++++---
>  t/t4150-am.sh            | 73 ++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 125 insertions(+), 5 deletions(-)
>
> diff --git a/Documentation/git-am.txt b/Documentation/git-am.txt
> index 0a4a984dfde..665bc89ca9f 100644
> --- a/Documentation/git-am.txt
> +++ b/Documentation/git-am.txt
> @@ -16,6 +16,7 @@ SYNOPSIS
>  	 [--exclude=<path>] [--include=<path>] [--reject] [-q | --quiet]
>  	 [--[no-]scissors] [-S[<keyid>]] [--patch-format=<format>]
>  	 [--quoted-cr=<action>]
> +	 [--empty=(die|drop|keep)]
>  	 [(<mbox> | <Maildir>)...]
>  'git am' (--continue | --skip | --abort | --quit | --show-current-patch[=(diff|raw)])
>  
> @@ -63,6 +64,14 @@ OPTIONS
>  --quoted-cr=<action>::
>  	This flag will be passed down to 'git mailinfo' (see linkgit:git-mailinfo[1]).
>  
> +--empty-commit=(die|drop|keep)::
> +	The command usually errors out when seeing an input e-mail
> +	message that lacks a patch. When this option is set to
> +	'drop', skip such an e-mail message without outputting error.
"without outputting error" -> "instead".

The first sentence used "to error" as a verb to mean "stop the operation in the middle with a message that diagnoses what is wrong". Saying "outputting error" to use the same word as a noun is not a good idea, especially the use of verb "to output", as it makes the word "error" look as if it is only the "message" part, and it becomes unclear if the "stopping due to an error" is also skipped.

I actually think it makes sense to give a notice/info message when "drop" skips an empty patch, unless "--quiet" is given.

> +	When this option is set to 'keep', create an empty commit,
> +	recording the contents of the e-mail message as its log.
> +	'die' is specified by default.

"is specified by default" sounds a bit strange. Perhaps lose the last sentence, and update the first line like so:

    By default, or when the option is set to 'die', the command
    errors out on an input e-mail message that lacks a patch.
Show 11 quoted lines
> diff --git a/builtin/am.c b/builtin/am.c
> index 8677ea2348a..1a3ed87b445 100644
> --- a/builtin/am.c
> +++ b/builtin/am.c
> @@ -87,6 +87,12 @@ enum show_patch_type {
>  	SHOW_PATCH_DIFF = 1,
>  };
>  
> +enum empty_action {
> +	DIE_EMPTY_COMMIT = 0,  /* output errors */
> +	DROP_EMPTY_COMMIT,     /* skip without outputting errors */
I think the user deserves "info:" (unless "--quiet").
Show 34 quoted lines
> +	KEEP_EMPTY_COMMIT      /* keep recording as empty commits */
> +};
> +
>  struct am_state {
>  	/* state directory path */
>  	char *dir;
> @@ -118,6 +124,7 @@ struct am_state {
>  	int message_id;
>  	int scissors; /* enum scissors_type */
>  	int quoted_cr; /* enum quoted_cr_action */
> +	int empty_type; /* enum empty_action */
>  	struct strvec git_apply_opts;
>  	const char *resolvemsg;
>  	int committer_date_is_author_date;
> @@ -178,6 +185,23 @@ static int am_option_parse_quoted_cr(const struct option *opt,
>  	return 0;
>  }
>  
> +static int am_option_parse_empty_commit(const struct option *opt,
> +				     const char *arg, int unset)
> +{
> +	int *opt_value = opt->value;
> +
> +	if (unset || !strcmp(arg, "die"))
> +		*opt_value = DIE_EMPTY_COMMIT;
> +	else if (!strcmp(arg, "drop"))
> +		*opt_value = DROP_EMPTY_COMMIT;
> +	else if (!strcmp(arg, "keep"))
> +		*opt_value = KEEP_EMPTY_COMMIT;
> +	else
> +		return error(_("Invalid value for --empty: %s"), arg);
> +
> +	return 0;
> +}
OK.
Show 12 quoted lines
> @@ -1792,6 +1811,20 @@ static void am_run(struct am_state *state, int resume)
>  		if (state->interactive && do_interactive(state))
>  			goto next;
>  
> +		if (is_empty_or_missing_file(am_path(state, "patch"))) {
> +			if (state->empty_type == DROP_EMPTY_COMMIT)
> +				goto next;
> +			else if (state->empty_type == KEEP_EMPTY_COMMIT) {
> +				if (run_applypatch_msg_hook(state))
> +					exit(1);
> +				else
> +					goto commit;
It probably is easier to read without "else", i.e.
			else if (state->empty_type == KEEP_EMPTY_COMMIT) {
				if (run_applypatch_msg_hook(state))
					exit(1);
				goto commit;

Running hook here and outside this if() block a bit ugly. Can't we instead set a flag variable or something and let the existing call to run_applypatch_msg_hook() used?

> +			} else if (state->empty_type == DIE_EMPTY_COMMIT) {
> +				printf_ln(_("Patch is empty."));
> +				die_user_resolve(state);
> +			}
Also, if developers ever add another possible value for the
state->empty_type member (by the way, "empty" in its name is good,
but "type" is iffy), it would be a bug if they do not consider what
should happen inside this "if (is_empty_or_missing_file())" block,
no?  In such a case, instead of if/else if/... cascade, consider
using switch().  Taking them together.
 
	while (state->cur <= state->last) {
        	const char *mail = am_path(state, msgnum(state));
		int apply_status;
		int to_keep;
		...
		to_keep = 0;
		if (is_empty_or_missing_file(am_path(state, "patch"))) {
			switch (state->empty_type) {
			case DROP_EMPTY_COMMIT:
                                say(state, stdout, _("Skipping empty patch '%.*s",
					linelen(state->msg0, state->msg);
				goto next;
				break;
			case KEEP_EMPTY_COMMIT:
				to_keep = 1;
				break;
			case DIE_EMPTY_COMMIT:
				pritnf_ln(_("Patch is empty."));
				die_user_resolve(state);
				break;
			}
		}
		if (run_applypatch_msg_hook(state))
			exit(1);
		if (to_keep)
			goto commit; /* empty: just record a message */
or something like that.
Show 12 quoted lines
> diff --git a/t/t4150-am.sh b/t/t4150-am.sh
> index 2aaaa0d7ded..3119556884d 100755
> --- a/t/t4150-am.sh
> +++ b/t/t4150-am.sh
> @@ -196,6 +196,13 @@ test_expect_success setup '
>  
>  	git format-patch -M --stdout lorem^ >rename-add.patch &&
>  
> +	git checkout -b empty-commit &&
> +	git commit -m "empty commit" --allow-empty &&
> +
> +	git format-patch --stdout empty-commit^ >empty.patch &&

Unless this is a test for "format-patch" command to make sure that the above command will not output a single byte, I would rather see the above line written like this:

	: >empty.patch &&
> +	git format-patch --stdout --cover-letter empty-commit^ >cover-letter.patch &&

This only creates a cover letter without anything, which sort of looks like an empty commit.

> +	git format-patch --always --stdout empty-commit^ >empty-commit.patch &&
And this gives another empty patch with only a message.
I would sort-of understand if there is
	git format-patch --stdout --always --cover-letter HEAD^ >both.patch

that has two e-mail messages in it, but what's the significance of testing both cover-letter.patch and empty-commit.patch?

The receiving end would not care what's in the actual e-mail message, as long as it lacks the patch part, no? Or am I missing some subtle reason why we want to test both?

Show 6 quoted lines
> @@ -1152,4 +1159,70 @@ test_expect_success 'apply binary blob in partial clone' '
>  	git -C client am ../patch
>  '
>  
> +test_expect_success 'still output error with --empty when meeting empty files' '
> +	test_must_fail git am --empty=drop empty.patch 2>actual &&

Nobody will understand "still", unless they know it used to be unconditionally a failure to feed an e-mail message that lacks a patch.

test_expect_success 'An empty input file is error regardless of --empty option' '
or something like that?
Show 10 quoted lines
> +	echo Patch format detection failed. >expected &&
> +	test_cmp expected actual
> +'
> +
> +test_expect_success 'error when meeting e-mail message that lacks a patch by default' '
> +	git checkout empty-commit^ &&
> +	test_must_fail git am empty-commit.patch >err &&
> +	test_path_is_dir .git/rebase-apply &&
> +	test_i18ngrep "Patch is empty." err &&
> +	rm -fr .git/rebase-apply &&
If any command before "rm" fails, it won't be cleaned up.
    test_expect_success 'a message without a patch is an error (default)' '
	test_when_finished "git am --abort || :" &&
	git checkout --detach empty-commit^ &&
	test_must_fail git am empty-commit.patch >err &&
	grep "Patch is empty" err
    '

or something like that. The title says it tests the default case, so do not test --empty=die case in the same test. Use a separate test to do the same for the case where an explicit "--empty=die" is given.

As I said, I do not quite see the point of testing with both empty-commit.patch and cover-letter.patch (unless the latter has an empty commit and a cover letter, totally in two messages).

Show 13 quoted lines
> +	test_must_fail git am --empty=die empty-commit.patch >err &&
> +	test_path_is_dir .git/rebase-apply &&
> +	test_i18ngrep "Patch is empty." err &&
> +	rm -fr .git/rebase-apply &&
> +
> +	test_must_fail git am --empty=die cover-letter.patch >err &&
> +	test_path_is_dir .git/rebase-apply &&
> +	test_i18ngrep "Patch is empty." err &&
> +	rm -fr .git/rebase-apply
> +'
> +
> +test_expect_success 'skip without error when meeting e-mail message that lacks a patch' '
> +	git am --empty=drop empty-commit.patch >err &&

The output 'err' is used by nobody; do not redirect it and just leave the standard output alone.

> +	test_path_is_missing .git/rebase-apply &&

Don't test this condition when testing success or failure from "am". That is too much implementation detail.

> +	git rev-parse empty-commit^ >expected &&
> +	git rev-parse HEAD >actual &&
> +	test_cmp expected actual &&
OK, we make sure that HEAD does not move.
> +	git am --empty=drop cover-letter.patch >err &&
> +	test_path_is_missing .git/rebase-apply &&
> +	test_cmp_rev empty-commit^ HEAD

Lose this one? As I said, I may be missing some subtle reason why both need to be tested---and if it is the case, test it in a separate test, not 2 of them in a single test like this.

Show 8 quoted lines
> +'
> +
> +test_expect_success 'record as an empty commit when meeting e-mail message that lacks a patch' '
> +	git am --empty=keep empty-commit.patch &&
> +	test_path_is_missing .git/rebase-apply &&
> +	{
> +		git show empty-commit --format="%B" &&
> +		echo "--" &&

Did this test pass? Without a trailing whitespace after double-dash, I do not think this shell snippet reproduces a patch e-mail correctly

In any case, don't do this. Imagine a future developer may want to improve the patch output by adding other things after the "-- " signature line, in addition to the "git version". Or perhaps the "git version" trailer gets removed by default for privacy concerns.

Should such changes be prevented from being made, only because this test expects exact output we have today? No.

Verify what we _care_, e.g. "does the title of the resulting commit reproduce the one-liner message given to '-m' when the empty commit was made?" is a sensible question to ask.

> +		git version | sed -e "s/^git version //" &&
> +		echo
Show 17 quoted lines
> +	} >expected &&
> +	git show HEAD --format="%B" >actual &&
> +	test_cmp actual expected &&
> +
> +	git am --empty=keep cover-letter.patch &&
> +	test_path_is_missing .git/rebase-apply &&
> +	{
> +		echo "*** SUBJECT HERE ***" &&
> +		echo &&
> +		echo "*** BLURB HERE ***" &&
> +		echo &&
> +		echo "A U Thor (1):" &&
> +		printf "  " &&
> +		git show empty-commit --format="%B" &&
> +		echo "--" &&
> +		git version | sed -e "s/^git version //" &&
> +		echo

Don't do this. Imagine a future developer may want to improve the cover letter template. Should that change be prevented from being made, because this test expects exact output we have today? No.

Show 6 quoted lines
> +	} >expected &&
> +	git show HEAD --format="%B" >actual &&
> +	test_cmp actual expected
> +'
> +
>  test_done
Thanks.
Previous: Aleen via GitGitGadgetNext: Bagas Sanjaya
Message 33 of 129 in “am: support --always option to am empty commits”
  1. 0/2 am: support --always option to am empty commitsAleen via GitGitGadget, Nov 12, 2021
  2. 1/2 doc: git-format-patch: specify the option --alwaysAleen via GitGitGadget, Nov 12, 2021
  3. 2/2 am: support --always option to am empty commitsAleen via GitGitGadget, Nov 12, 2021
  4. René ScharfeNov 12, 2021
  5. Junio C HamanoNov 12, 2021
  6. Aleen 徐沛文Nov 12, 2021
  7. René ScharfeNov 12, 2021
  8. Junio C HamanoNov 12, 2021
  9. AleenNov 12, 2021
  10. 0/4 am: support --allow-empty option to am empty commitsAleen via GitGitGadget, Nov 12, 2021
  11. 1/4 doc: git-format-patch: specify the option --alwaysAleen via GitGitGadget, Nov 12, 2021
  12. Junio C HamanoNov 12, 2021
  13. 2/4 am: support --always option to am empty commitsAleen via GitGitGadget, Nov 12, 2021
  14. Junio C HamanoNov 12, 2021
  15. 3/4 test: am: add the case when not passing the --always optionAleen via GitGitGadget, Nov 12, 2021
  16. 4/4 chore: am: rename the --always option to --allow-emptyAleen via GitGitGadget, Nov 12, 2021
  17. 0/2 am: support --empty-commit=(die|skip|asis) option to am empty commitsAleen via GitGitGadget, Nov 15, 2021
  18. 1/2 doc: git-format-patch: describe the option --alwaysAleen via GitGitGadget, Nov 15, 2021
  19. 2/2 am: support --empty-commit option to handle empty patchesAleen via GitGitGadget, Nov 15, 2021
  20. Aleen 徐沛文Nov 15, 2021
  21. 0/2 am: support --empty-commit=(die|skip|asis) option to am empty commitsAleen via GitGitGadget, Nov 16, 2021
  22. 1/2 doc: git-format-patch: describe the option --alwaysAleen via GitGitGadget, Nov 16, 2021
  23. 2/2 am: support --empty-commit option to handle empty patchesAleen via GitGitGadget, Nov 16, 2021
  24. Phillip WoodNov 16, 2021
  25. Aleen 徐沛文Nov 16, 2021
  26. Junio C HamanoNov 17, 2021
  27. 0/2 am: support --empty-commit=(die|skip|asis) option to am empty commitsAleen via GitGitGadget, Nov 17, 2021
  28. 1/2 doc: git-format-patch: describe the option --alwaysAleen via GitGitGadget, Nov 17, 2021
  29. 2/2 am: support --empty option to handle empty patchesAleen via GitGitGadget, Nov 17, 2021
  30. 0/3 am: support --empty=(die|drop|keep) option to handle empty patchesAleen via GitGitGadget, Nov 18, 2021
  31. 1/3 doc: git-format-patch: describe the option --alwaysAleen via GitGitGadget, Nov 18, 2021
  32. 2/3 am: support --empty option to handle empty patchesAleen via GitGitGadget, Nov 18, 2021
  33. Junio C HamanoNov 19, 2021
  34. Bagas SanjayaNov 19, 2021
  35. Ævar Arnfjörð BjarmasonNov 19, 2021
  36. Eric SunshineNov 19, 2021
  37. Junio C HamanoNov 19, 2021
  38. Junio C HamanoNov 19, 2021
  39. 3/3 am: throw an error when passing --empty option without valueAleen via GitGitGadget, Nov 18, 2021
  40. Junio C HamanoNov 19, 2021
  41. Aleen 徐沛文Nov 19, 2021
  42. Junio C HamanoNov 18, 2021
  43. Aleen 徐沛文Nov 19, 2021
  44. Junio C HamanoNov 19, 2021
  45. Aleen 徐沛文Nov 19, 2021
  46. AleenNov 19, 2021
  47. Junio C HamanoNov 19, 2021
  48. Aleen 徐沛文Nov 19, 2021
  49. Junio C HamanoNov 19, 2021
  50. Johannes SchindelinNov 22, 2021
  51. Aleen 徐沛文Nov 19, 2021
  52. 0/2 am: support --empty=(die|drop|keep) option to handle empty patchesAleen via GitGitGadget, Nov 19, 2021
  53. 1/2 doc: git-format-patch: describe the option --alwaysAleen via GitGitGadget, Nov 19, 2021
  54. 2/2 am: support --empty=<option> to handle empty patchesAleen via GitGitGadget, Nov 19, 2021
  55. Junio C HamanoNov 19, 2021
  56. Junio C HamanoNov 19, 2021
  57. 0/2 am: support --empty=(die|drop|keep) option to handle empty patchesAleen via GitGitGadget, Nov 22, 2021
  58. 1/2 doc: git-format-patch: describe the option --alwaysAleen via GitGitGadget, Nov 22, 2021
  59. 2/2 am: support --empty=<option> to handle empty patchesAleen via GitGitGadget, Nov 22, 2021
  60. Junio C HamanoNov 22, 2021
  61. Aleen 徐沛文Nov 22, 2021
  62. 0/2 am: support --empty=(die|drop|keep) option to handle empty patchesAleen via GitGitGadget, Nov 22, 2021
  63. 1/2 doc: git-format-patch: describe the option --alwaysAleen 徐沛文 via GitGitGadget, Nov 22, 2021
  64. 2/2 am: support --empty=<option> to handle empty patchesAleen 徐沛文 via GitGitGadget, Nov 22, 2021
  65. Aleen 徐沛文Nov 22, 2021
  66. 0/2 am: support --empty=(die|drop|keep) option to handle empty patchesAleen via GitGitGadget, Nov 22, 2021
  67. 1/2 doc: git-format-patch: describe the option --alwaysAleen via GitGitGadget, Nov 22, 2021
  68. Johannes SchindelinNov 22, 2021
  69. Aleen 徐沛文Nov 23, 2021
  70. Johannes SchindelinNov 23, 2021
  71. 2/2 am: support --empty=<option> to handle empty patchesAleen via GitGitGadget, Nov 22, 2021
  72. 0/2 am: support --empty=(die|drop|keep) option to handle empty patchesAleen via GitGitGadget, Nov 23, 2021
  73. 1/2 doc: git-format-patch: describe the option --always徐沛文 (Aleen) via GitGitGadget, Nov 23, 2021
  74. Johannes SchindelinNov 23, 2021
  75. Junio C HamanoNov 23, 2021
  76. 2/2 am: support --empty=<option> to handle empty patches徐沛文 (Aleen) via GitGitGadget, Nov 23, 2021
  77. Elijah NewrenNov 26, 2021
  78. Aleen 徐沛文Nov 29, 2021
  79. Aleen 徐沛文Nov 29, 2021
  80. Elijah NewrenNov 29, 2021
  81. Aleen 徐沛文Nov 30, 2021
  82. Junio C HamanoNov 29, 2021
  83. Elijah NewrenNov 29, 2021
  84. 0/3 am: support --empty=(die|drop|keep) option and --allow-empty option to handle empty patchesAleen via GitGitGadget, Nov 30, 2021
  85. 1/3 doc: git-format-patch: describe the option --always徐沛文 (Aleen) via GitGitGadget, Nov 30, 2021
  86. 2/3 am: support --empty=<option> to handle empty patches徐沛文 (Aleen) via GitGitGadget, Nov 30, 2021
  87. 3/3 am: support --allow-empty to record specific empty patches徐沛文 (Aleen) via GitGitGadget, Nov 30, 2021
  88. Junio C HamanoNov 30, 2021
  89. 0/3 am: support --empty=(die|drop|keep) option and --allow-empty option to handle empty patchesAleen via GitGitGadget, Nov 30, 2021
  90. 1/3 doc: git-format-patch: describe the option --always徐沛文 (Aleen) via GitGitGadget, Nov 30, 2021
  91. 2/3 am: support --empty=<option> to handle empty patches徐沛文 (Aleen) via GitGitGadget, Nov 30, 2021
  92. 3/3 am: support --allow-empty to record specific empty patches徐沛文 (Aleen) via GitGitGadget, Nov 30, 2021
  93. 0/3 am: support --empty=(die|drop|keep) option and --allow-empty option to handle empty patchesAleen via GitGitGadget, Dec 1, 2021
  94. 1/3 doc: git-format-patch: describe the option --always徐沛文 (Aleen) via GitGitGadget, Dec 1, 2021
  95. 2/3 am: support --empty=<option> to handle empty patches徐沛文 (Aleen) via GitGitGadget, Dec 1, 2021
  96. Johannes SchindelinDec 3, 2021
  97. 3/3 am: support --allow-empty to record specific empty patches徐沛文 (Aleen) via GitGitGadget, Dec 1, 2021
  98. Junio C HamanoDec 2, 2021
  99. Aleen 徐沛文Dec 6, 2021
  100. 0/3 am: support --empty=(die|drop|keep) option and --allow-empty option to handle empty patchesAleen via GitGitGadget, Dec 6, 2021
  101. 1/3 doc: git-format-patch: describe the option --always徐沛文 (Aleen) via GitGitGadget, Dec 6, 2021
  102. 2/3 am: support --empty=<option> to handle empty patches徐沛文 (Aleen) via GitGitGadget, Dec 6, 2021
  103. 3/3 am: support --allow-empty to record specific empty patches徐沛文 (Aleen) via GitGitGadget, Dec 6, 2021
  104. 0/3 am: support --empty=(die|drop|keep) option and --allow-empty option to handle empty patchesAleen via GitGitGadget, Dec 7, 2021
  105. 1/3 doc: git-format-patch: describe the option --always徐沛文 (Aleen) via GitGitGadget, Dec 7, 2021
  106. 2/3 am: support --empty=<option> to handle empty patches徐沛文 (Aleen) via GitGitGadget, Dec 7, 2021
  107. 3/3 am: support --allow-empty to record specific empty patches徐沛文 (Aleen) via GitGitGadget, Dec 7, 2021
  108. 0/3 am: support --empty=(die|drop|keep) option and --allow-empty option to handle empty patchesAleen via GitGitGadget, Dec 7, 2021
  109. 1/3 doc: git-format-patch: describe the option --always徐沛文 (Aleen) via GitGitGadget, Dec 7, 2021
  110. 2/3 am: support --empty=<option> to handle empty patches徐沛文 (Aleen) via GitGitGadget, Dec 7, 2021
  111. Junio C HamanoDec 7, 2021
  112. 3/3 am: support --allow-empty to record specific empty patches徐沛文 (Aleen) via GitGitGadget, Dec 7, 2021
  113. Junio C HamanoDec 7, 2021
  114. Junio C HamanoDec 7, 2021
  115. 0/3 am: support --empty=(die|drop|keep) option and --allow-empty option to handle empty patchesAleen via GitGitGadget, Dec 8, 2021
  116. 1/3 doc: git-format-patch: describe the option --always徐沛文 (Aleen) via GitGitGadget, Dec 8, 2021
  117. 2/3 am: support --empty=<option> to handle empty patches徐沛文 (Aleen) via GitGitGadget, Dec 8, 2021
  118. 3/3 am: support --allow-empty to record specific empty patches徐沛文 (Aleen) via GitGitGadget, Dec 8, 2021
  119. Junio C HamanoDec 8, 2021
  120. Aleen 徐沛文Dec 8, 2021
  121. Junio C HamanoDec 8, 2021
  122. 0/3 am: support --empty=(die|drop|keep) option and --allow-empty option to handle empty patchesAleen via GitGitGadget, Dec 9, 2021
  123. 1/3 doc: git-format-patch: describe the option --always徐沛文 (Aleen) via GitGitGadget, Dec 9, 2021
  124. Bagas SanjayaDec 9, 2021
  125. Aleen 徐沛文Dec 10, 2021
  126. Bagas SanjayaDec 10, 2021
  127. Junio C HamanoDec 11, 2021
  128. 2/3 am: support --empty=<option> to handle empty patches徐沛文 (Aleen) via GitGitGadget, Dec 9, 2021
  129. 3/3 am: support --allow-empty to record specific empty patches徐沛文 (Aleen) via GitGitGadget, Dec 9, 2021

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.