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

[PATCH v18 3/3] am: support --allow-empty to record specific empty patches

From
徐G徐沛文 (Aleen) via GitGitGadget <gitgitgadget@gmail.com>
Date
Dec 8, 2021, 05:05 UTC
Message-ID
<4c3077f938435508850727e05ad514035f09bebb.1638939946.git.gitgitgadget@gmail.com>
In-Reply-To
<pull.1076.v18.git.1638939946.gitgitgadget@gmail.com>
From: =?UTF-8?q?=E5=BE=90=E6=B2=9B=E6=96=87=20=28Aleen=29?=
 <aleen42@vip.qq.com>

This option helps to record specific empty patches in the middle of an am session, which does create empty commits only when:

    1. index has not changed
    2. lacking a branch
Signed-off-by: 徐沛文 (Aleen) <aleen42@vip.qq.com>
---
 Documentation/git-am.txt |  7 +++++-
 builtin/am.c             | 39 +++++++++++++++++++++++------
 t/t4150-am.sh            | 54 ++++++++++++++++++++++++++++++++++++++++
 t/t7512-status-help.sh   |  1 +
 wt-status.c              |  8 +++++-
 5 files changed, 99 insertions(+), 10 deletions(-)
diff --git a/Documentation/git-am.txt b/Documentation/git-am.txt
index 7676bd58ae7..09107fb1067 100644
--- a/Documentation/git-am.txt
+++ b/Documentation/git-am.txt
@@ -18,7 +18,7 @@ SYNOPSIS
 	 [--quoted-cr=<action>]
 	 [--empty=(stop|drop|keep)]
 	 [(<mbox> | <Maildir>)...]
-'git am' (--continue | --skip | --abort | --quit | --show-current-patch[=(diff|raw)])
+'git am' (--continue | --skip | --abort | --quit | --show-current-patch[=(diff|raw)] | --allow-empty)
 
 DESCRIPTION
 -----------
@@ -200,6 +200,11 @@ default.   You can use `--no-utf8` to override this.
 	the e-mail message; if `diff`, show the diff portion only.
 	Defaults to `raw`.
 
+--allow-empty::
+	After a patch failure on an input e-mail message lacking a patch,
+	create an empty commit with the contents of the e-mail message
+	as its log message.
+
 DISCUSSION
 ----------
 
diff --git a/builtin/am.c b/builtin/am.c
index 7a66ad23737..d73e415bbb0 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -1152,6 +1152,12 @@ static void NORETURN die_user_resolve(const struct am_state *state)
 
 		printf_ln(_("When you have resolved this problem, run \"%s --continue\"."), cmdline);
 		printf_ln(_("If you prefer to skip this patch, run \"%s --skip\" instead."), cmdline);
+
+		if (advice_enabled(ADVICE_AM_WORK_DIR) &&
+		    is_empty_or_missing_file(am_path(state, "patch")) &&
+		    !repo_index_has_changes(the_repository, NULL, NULL))
+			printf_ln(_("To record the empty patch as an empty commit, run \"%s --allow-empty\"."), cmdline);
+
 		printf_ln(_("To restore the original branch and stop patching, run \"%s --abort\"."), cmdline);
 	}
 
@@ -1900,19 +1906,31 @@ next:
 /**
  * Resume the current am session after patch application failure. The user did
  * all the hard work, and we do not have to do any patch application. Just
- * trust and commit what the user has in the index and working tree.
+ * trust and commit what the user has in the index and working tree. If `allow_empty`
+ * is true, commit as an empty commit when index has not changed and lacking a patch.
  */
-static void am_resolve(struct am_state *state)
+static void am_resolve(struct am_state *state, int allow_empty)
 {
+	int index_changed;
+
 	validate_resume_state(state);
 
 	say(state, stdout, _("Applying: %.*s"), linelen(state->msg), state->msg);
 
-	if (!repo_index_has_changes(the_repository, NULL, NULL)) {
-		printf_ln(_("No changes - did you forget to use 'git add'?\n"
-			"If there is nothing left to stage, chances are that something else\n"
-			"already introduced the same changes; you might want to skip this patch."));
+	index_changed = repo_index_has_changes(the_repository, NULL, NULL);
+	if (allow_empty &&
+	    !(!index_changed && is_empty_or_missing_file(am_path(state, "patch"))))
 		die_user_resolve(state);
+
+	if (!index_changed) {
+		if (allow_empty) {
+			printf_ln(_("No changes - recorded it as an empty commit."));
+		} else {
+			printf_ln(_("No changes - did you forget to use 'git add'?\n"
+				    "If there is nothing left to stage, chances are that something else\n"
+				    "already introduced the same changes; you might want to skip this patch."));
+			die_user_resolve(state);
+		}
 	}
 
 	if (unmerged_cache()) {
@@ -2239,7 +2257,8 @@ enum resume_type {
 	RESUME_SKIP,
 	RESUME_ABORT,
 	RESUME_QUIT,
-	RESUME_SHOW_PATCH
+	RESUME_SHOW_PATCH,
+	RESUME_ALLOW_EMPTY,
 };
 
 struct resume_mode {
@@ -2392,6 +2411,9 @@ int cmd_am(int argc, const char **argv, const char *prefix)
 		  N_("show the patch being applied"),
 		  PARSE_OPT_CMDMODE | PARSE_OPT_OPTARG | PARSE_OPT_NONEG | PARSE_OPT_LITERAL_ARGHELP,
 		  parse_opt_show_current_patch, RESUME_SHOW_PATCH },
+		OPT_CMDMODE(0, "allow-empty", &resume.mode,
+			N_("record the empty patch as an empty commit"),
+			RESUME_ALLOW_EMPTY),
 		OPT_BOOL(0, "committer-date-is-author-date",
 			&state.committer_date_is_author_date,
 			N_("lie about committer date")),
@@ -2500,7 +2522,8 @@ int cmd_am(int argc, const char **argv, const char *prefix)
 		am_run(&state, 1);
 		break;
 	case RESUME_RESOLVED:
-		am_resolve(&state);
+	case RESUME_ALLOW_EMPTY:
+		am_resolve(&state, resume.mode == RESUME_ALLOW_EMPTY ? 1 : 0);
 		break;
 	case RESUME_SKIP:
 		am_skip(&state);
diff --git a/t/t4150-am.sh b/t/t4150-am.sh
index f2a7a68eda0..6b23384685b 100755
--- a/t/t4150-am.sh
+++ b/t/t4150-am.sh
@@ -1202,4 +1202,58 @@ test_expect_success 'record as an empty commit when meeting e-mail message that
 	grep "Creating an empty commit: empty commit" output
 '
 
+test_expect_success 'skip an empty patch in the middle of an am session' '
+	git checkout empty-commit^ &&
+	test_must_fail git am empty-commit.patch >err &&
+	grep "Patch is empty." err &&
+	grep "To record the empty patch as an empty commit, run \"git am --allow-empty\"." err &&
+	git am --skip &&
+	test_path_is_missing .git/rebase-apply &&
+	git rev-parse empty-commit^ >expected &&
+	git rev-parse HEAD >actual &&
+	test_cmp expected actual
+'
+
+test_expect_success 'record an empty patch as an empty commit in the middle of an am session' '
+	git checkout empty-commit^ &&
+	test_must_fail git am empty-commit.patch >err &&
+	grep "Patch is empty." err &&
+	grep "To record the empty patch as an empty commit, run \"git am --allow-empty\"." err &&
+	git am --allow-empty >output &&
+	grep "No changes - recorded it as an empty commit." output &&
+	test_path_is_missing .git/rebase-apply &&
+	git show empty-commit --format="%B" >expected &&
+	git show HEAD --format="%B" >actual &&
+	grep -f actual expected
+'
+
+test_expect_success 'cannot create empty commits when the index is changed' '
+	git checkout empty-commit^ &&
+	test_must_fail git am empty-commit.patch >err &&
+	: >empty-file &&
+	git add empty-file &&
+	test_must_fail git am --allow-empty >err &&
+	! grep "To record the empty patch as an empty commit, run \"git am --allow-empty\"." err
+'
+
+test_expect_success 'cannot create empty commits when there is a clean index due to merge conflicts' '
+	test_when_finished "git am --abort || :" &&
+	git rev-parse HEAD >expected &&
+	test_must_fail git am seq.patch &&
+	test_must_fail git am --allow-empty >err &&
+	! grep "To record the empty patch as an empty commit, run \"git am --allow-empty\"." err &&
+	git rev-parse HEAD >actual &&
+	test_cmp actual expected
+'
+
+test_expect_success 'cannot create empty commits when there is unmerged index due to merge conflicts' '
+	test_when_finished "git am --abort || :" &&
+	git rev-parse HEAD >expected &&
+	test_must_fail git am -3 seq.patch &&
+	test_must_fail git am --allow-empty >err &&
+	! grep "To record the empty patch as an empty commit, run \"git am --allow-empty\"." err &&
+	git rev-parse HEAD >actual &&
+	test_cmp actual expected
+'
+
 test_done
diff --git a/t/t7512-status-help.sh b/t/t7512-status-help.sh
index 7f2956d77ad..2f16d5787ed 100755
--- a/t/t7512-status-help.sh
+++ b/t/t7512-status-help.sh
@@ -659,6 +659,7 @@ On branch am_empty
 You are in the middle of an am session.
 The current patch is empty.
   (use "git am --skip" to skip this patch)
+  (use "git am --allow-empty" to record this patch as an empty commit)
   (use "git am --abort" to restore the original branch)
 
 nothing to commit (use -u to show untracked files)
diff --git a/wt-status.c b/wt-status.c
index 5d215f4e4f1..335e723a71e 100644
--- a/wt-status.c
+++ b/wt-status.c
@@ -1218,17 +1218,23 @@ static void show_merge_in_progress(struct wt_status *s,
 static void show_am_in_progress(struct wt_status *s,
 				const char *color)
 {
+	int am_empty_patch;
+
 	status_printf_ln(s, color,
 		_("You are in the middle of an am session."));
 	if (s->state.am_empty_patch)
 		status_printf_ln(s, color,
 			_("The current patch is empty."));
 	if (s->hints) {
-		if (!s->state.am_empty_patch)
+		am_empty_patch = s->state.am_empty_patch;
+		if (!am_empty_patch)
 			status_printf_ln(s, color,
 				_("  (fix conflicts and then run \"git am --continue\")"));
 		status_printf_ln(s, color,
 			_("  (use \"git am --skip\" to skip this patch)"));
+		if (am_empty_patch)
+			status_printf_ln(s, color,
+				_("  (use \"git am --allow-empty\" to record this patch as an empty commit)"));
 		status_printf_ln(s, color,
 			_("  (use \"git am --abort\" to restore the original branch)"));
 	}
-- 
gitgitgadget
Previous: 徐沛文 (Aleen) via GitGitGadgetNext: Junio C Hamano
Message 118 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.