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

Re: [PATCH v2 2/4] am: support --always option to am empty commits

From
Junio C Hamano <gitster@pobox.com>
Date
Nov 12, 2021, 22:23 UTC
Message-ID
<xmqq4k8hovy3.fsf@gitster.g>
In-Reply-To
<59b1417da3754add11e72692ec11c09e486269e4.1636700040.git.gitgitgadget@gmail.com>
"Aleen via GitGitGadget" <gitgitgadget@gmail.com> writes:
> From: Aleen <aleen42@vip.qq.com>
> Subject: Re: [PATCH v2 2/4] am: support --always option to am empty commits

As the inventor of "format-patch" and "am", I probably should wish that "to am" were by now a valid verb, but no, it is not.

More importantly, when an empty patch comes, there can be many different ways for the "am" command to handle it. "to am empty commits" does not say how the patch chooses to so and does not make a very useful title for this commit.

Right now, we error out, simply because it is an easy mistake to save a non-patch e-mail to the mailbox when intending to save a series of patches belonging to a topic, and the user is expected to say "git am --skip" to skip over it when it happens. The above "Subject:" can be read to mean that the new option instead allows such an empty message to be skipped without stopping and forcing the user to say "am --skip", which may be a useful thing to do. Or it may mean that the new option creates an empty commit, using the contents of the e-mail as the commit log message. Does this patch offer both behaviour? If so, "to am", even though it does not convey a bit of information, might be an acceptable compromise. If the patch implements only one of the behaviours, then we should say so. Either one of these two:

    am: --always option skips empty patches
    am: --always option records empty patches as empty commits

Also, I thought that the previous round saw a conclusion that --always is a bad name for the option. If we are making the second round, let's not start with a bad name and the "fix the mistake" of starting with a bad name in a later step. Just start with the final name from the beginning.

> +--always::
> +	Apply patches of commits with detailed commit messages,
> +	even if they emit no changes. (see linkgit:git-format-patch[1])
Almost the same comment as 1/4 applies to the above description.
    --empty-patch=(skip|asis|die)::
	The command usually errors out when seeing an input e-mail
	message that lacks a patch.  When this option is set to
	'skip', skip such an e-mail message without erroring out.
	When this option is set to 'asis', create an empty commit,
	recording the contents of the e-mail message as its log.
	'die' is the default.

perhaps? Assuming that 'skip' would make a useful addition to the mix in the future.

Show 9 quoted lines
> diff --git a/builtin/am.c b/builtin/am.c
> index 8677ea2348a..d11efc16f92 100644
> --- a/builtin/am.c
> +++ b/builtin/am.c
> @@ -124,6 +124,8 @@ struct am_state {
>  	int ignore_date;
>  	int allow_rerere_autoupdate;
>  	const char *sign_commit;
> +	int always;

OK, so here is where the parse_options() records the command line option.

> +	int empty_commit;

I do not think this addtion of empty_commit member to this structure is welcome or necessary.

>  	int rebasing;
>  };
> @@ -1249,8 +1251,12 @@ static int parse_mail(struct am_state *state, const char *mail)
>  	}
Show 10 quoted lines
>  	if (is_empty_or_missing_file(am_path(state, "patch"))) {
> -		printf_ln(_("Patch is empty."));
> -		die_user_resolve(state);
> +		if (state->always) {
> +			state->empty_commit = 1;
> +		} else {
> +			printf_ln(_("Patch is empty."));
> +			die_user_resolve(state);
> +		}
>  	}

I am only thinking aloud, but I suspect that the whole "if 'patch' is empty, do something special" code logically belongs to the caller. Perhaps we should remove this block altogether and let the code continue the rest of this function. And return 0, as this is not like mail-system-internal-data that we want to pretend did not even exist, and have the caller check if "patch" file is empty and act accordingly.

Show 7 quoted lines
> @@ -1792,6 +1798,9 @@ static void am_run(struct am_state *state, int resume)
>  		if (state->interactive && do_interactive(state))
>  			goto next;
>  
> +		if (state->empty_commit)
> +			goto commit;
> +

This is probably a wrong place to jump from. You are bypassing applypatch-msg-hook that may be serving as a gate to catch typos if you are going to create a commit.

So, perhaps check if "patch" is empty here, using the code you'd lift from parse_mail(), and if it is empty then:

  - if --empty-commit is set to die (or left default), do the
    printf_ln(_("Patch is empty.")) followed by a call to
    die_user_resolve(state), just like before.
  - if it is set to skip, jump to "next", just like when
    parse_mail() returned 1.
  - otherwise (i.e. you are told to create an empty commit),
    remember the fact that current e-mail has no patch, but continue
    to the next step to run the hook.
>  		if (run_applypatch_msg_hook(state))
>  			exit(1);

And after passing the hook, if your earlier check says that there is no patch and you are to create an empty commit, jump to "commit" label from here.

Show 23 quoted lines
> diff --git a/t/t4150-am.sh b/t/t4150-am.sh
> index 2aaaa0d7ded..5b3617857a8 100755
> --- a/t/t4150-am.sh
> +++ b/t/t4150-am.sh
> @@ -196,6 +196,12 @@ 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 &&
> +	git format-patch --always --stdout empty-commit^ >empty-commit.patch &&
> +
>  	# reset time
>  	sane_unset test_tick &&
>  	test_tick
> @@ -1152,4 +1158,23 @@ test_expect_success 'apply binary blob in partial clone' '
>  	git -C client am ../patch
>  '
>  
> +test_expect_success 'am a real empty patch with the --always option' '
> +	rm -fr .git/rebase-apply &&

What is this one about? If this is trying to clean up the cruft the previous step made, it may be better to do the clean-up in the previous step using test_when_finished.

Show 5 quoted lines
> +	git reset --hard &&
> +	test_must_fail git am --always empty.patch 2>actual &&
> +	echo Patch format detection failed. >expected &&
> +	test_cmp expected actual
> +'

It is curious that the error message the patch touched said "Patch is empty." but the test checks for a different message. Are we testing the right failure mode?

> +test_expect_success 'am a patch with empty commits' '
> +	grep "empty commit" empty-commit.patch &&

What is this testing? If it is checking the sanity of test data we created earlier, shouldn't we do so where we generated the data (i.e. the "setup" block that we earlier saw)?

> +	rm -fr .git/rebase-apply &&
> +	git reset --hard &&

These are trying to clean up the cruft the previous step (added by this patch) may have left. Perhaps these should be done inside test_when_finished of the previous step?

> +	git checkout empty-commit^ &&
> +	git am --always empty-commit.patch &&
> +	test_path_is_missing .git/rebase-apply &&

We should trust "git am"'s exit status here, I would think, rather than be so intimate with the internal implementation detail like the name of the temporary directory the command uses.

> +	git cat-file commit HEAD >actual &&
> +	test_i18ngrep "empty commit" actual
test_i18ngrep -> grep

The input (i.e. the commit that resulted in this empty patch) said. "empty commit", and we are making sure that string appears, but we are not making sure that is the only string appears in the log message. Is it because we will later enhance the command to automatically extend the single-liner "empty patch" log message into a lot more detailed one? I doubt it ;-)

More importantly, the above checks if (part of) the log message is recorded, but does not check if the resulting commit is what is expected, i.e. an empty one.

Perhaps checking with "grep" is way too loose a test. Shouldn't we do something like

	git show -1 --format='%B' >actual

and compare it with expected "the log is recorded as-is, and there is no change between HEAD^ and HEAD"?

> +'
> +
>  test_done
Thanks.
Previous: Aleen via GitGitGadgetNext: Aleen via GitGitGadget
Message 14 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.