From: 徐沛文 (Aleen) via GitGitGadget <hidden> Date: 2021-12-06 09:41:50
From: =?UTF-8?q?=E5=BE=90=E6=B2=9B=E6=96=87=20=28Aleen=29?=
[off-list ref]
This option helps to record specific empty patches in the middle
of an am session. However, it is a valid resume value only when:
1. index has not changed
2. lacking a branch
Signed-off-by: 徐沛文 (Aleen) <redacted>
---
Documentation/git-am.txt | 7 +++++-
builtin/am.c | 42 ++++++++++++++++++++++++-------
t/t4150-am.sh | 53 ++++++++++++++++++++++++++++++++++++++++
t/t7512-status-help.sh | 1 +
wt-status.c | 3 +++
5 files changed, 96 insertions(+), 10 deletions(-)
@@ -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,+ the user can still record the empty patch as an empty commit with+ the contents of the e-mail message as its log.+ DISCUSSION ----------
@@ -1830,7 +1830,8 @@ static void am_run(struct am_state *state, int resume)die(_("Patch is empty."));break;caseERR_EMPTY_COMMIT:-printf_ln(_("Patch is empty."));+printf_ln(_("Patch is empty.\n"+"If you want to record it as an empty commit, run \"git am --allow-empty\"."));die_user_resolve(state);break;}
@@ -1903,21 +1904,39 @@ next:/***Resumethecurrentamsessionafterpatchapplicationfailure.Theuserdid*allthehardwork,andwedonothavetodoanypatchapplication.Just-*trustandcommitwhattheuserhasintheindexandworkingtree.+*trustandcommitwhattheuserhasintheindexandworkingtree.If`allow_empty`+*istrue,commitasanemptycommitwhenthereisnochanges.*/-staticvoidam_resolve(structam_state*state)+staticvoidam_resolve(structam_state*state,intallow_empty){+intindex_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."));+/**+*"--allow-empty"isavalidresumevalueonlywhen:+*1.indexhasnotchanged+*2.lackingapatch+*/+index_changed=repo_index_has_changes(the_repository,NULL,NULL);+if(allow_empty&&(index_changed||!is_empty_or_missing_file(am_path(state,"patch")))){+printf_ln(_("Invalid resume value."));die_user_resolve(state);}+if(!index_changed){+if(allow_empty)+printf_ln(_("No changes - record 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()){printf_ln(_("You still have unmerged paths in your index.\n""You should 'git add' each file with resolved conflicts to mark them as such.\n"
@@ -2395,6 +2415,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")),
@@ -1202,4 +1202,57 @@ test_expect_success 'record as an empty commit when meeting e-mail message thattest_cmpactualexpected'+test_expect_success'skip an empty patch in the middle of an am session''+gitcheckoutempty-commit^&&+test_must_failgitamempty-commit.patch>err&&+grep"Patch is empty."err&&+grep"If you want to record it as an empty commit, run \"git am --allow-empty\"."err&&+gitam--skip&&+test_path_is_missing.git/rebase-apply&&+gitrev-parseempty-commit^>expected&&+gitrev-parseHEAD>actual&&+test_cmpexpectedactual+'++test_expect_success'record an empty patch as an empty commit in the middle of an am session''+gitcheckoutempty-commit^&&+test_must_failgitamempty-commit.patch>err&&+grep"Patch is empty."err&&+grep"If you want to record it as an empty commit, run \"git am --allow-empty\"."err&&+gitam--allow-empty&&+test_path_is_missing.git/rebase-apply&&+gitshowempty-commit--format="%s">expected&&+gitshowHEAD--format="%s">actual&&+test_cmpactualexpected+'++test_expect_success'cannot create empty commits when the index is changed''+gitcheckoutempty-commit^&&+test_must_failgitamempty-commit.patch>err&&+:>empty-file&&+gitaddempty-file&&+test_must_failgitam--allow-empty>err&&+grep"Invalid resume value."err+'++test_expect_success'cannot create empty commits when there is a clean index due to merge conflicts''+test_when_finished"git am --abort || :"&&+gitrev-parseHEAD>expected&&+test_must_failgitamseq.patch&&+test_must_failgitam--allow-empty>err&&+grep"Invalid resume value."err&&+gitrev-parseHEAD>actual&&+test_cmpactualexpected+'++test_expect_success'cannot create empty commits when there is unmerged index due to merge conflicts''+test_when_finished"git am --abort || :"&&+gitrev-parseHEAD>expected&&+test_must_failgitam-3seq.patch&&+test_must_failgitam--allow-empty>err&&+grep"Invalid resume value."err&&+gitrev-parseHEAD>actual&&+test_cmpactualexpected+'+ test_done
@@ -658,6 +658,7 @@ test_expect_success 'status in an am session: empty patch' ' Onbrancham_empty Youareinthemiddleofanamsession. Thecurrentpatchisempty.+(use"git am --allow-empty"torecordthispatchasanemptycommit)(use"git am --skip"toskipthispatch)(use"git am --abort"torestoretheoriginalbranch)
@@ -1227,6 +1227,9 @@ static void show_am_in_progress(struct wt_status *s,if(!s->state.am_empty_patch)status_printf_ln(s,color,_(" (fix conflicts and then run \"git am --continue\")"));+else+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 --skip\" to skip this patch)"));status_printf_ln(s,color,
From: Aleen via GitGitGadget <hidden> Date: 2021-12-07 05:01:41
Since that git has supported the --always option for the git-format-patch
command to create a patch with an empty commit message, git-am should
support applying and committing with empty patches.
----------------------------------------------------------------------------
Changes since v1:
1. add a case when not passing the --always option.
2. rename the --always option to --allow-empty.
----------------------------------------------------------------------------
Changes since v2:
1. rename the --allow-empty option to --empty-commit.
2. introduce three different strategies (die|skip|asis) when trying to
record empty patches as empty commits.
----------------------------------------------------------------------------
Changes since v3:
1. generate the missed file for test cases.
2. grep -f cannot be used under Mac OS.
----------------------------------------------------------------------------
Changes since v4:
1. rename the --empty-commit option to --empty.
2. rename three different strategies (die|skip|asis) to die, drop and keep
correspondingly.
----------------------------------------------------------------------------
Changes since v5:
1. throw an error when passing --empty option without value.
----------------------------------------------------------------------------
Changes since v6:
1. add i18n resources.
----------------------------------------------------------------------------
Changes since v7:
1. update code according to the seen branch.
2. fix the wrong document of git-am.
3. sign off commits by a real name.
----------------------------------------------------------------------------
Changes since v8:
1. update the committer's name with my real name to fix DCO of GGG.
----------------------------------------------------------------------------
Changes since v9:
1. imitate the signed name format of
https://lore.kernel.org/git/pull.1143.git.git.1637347813367.gitgitgadget@gmail.com
.
----------------------------------------------------------------------------
Changes since v11:
1. introduce an interactive option --allow-empty for git-am to record empty
patches in the middle of an am session.
----------------------------------------------------------------------------
Changes since v12:
1. record the empty patch as an empty commit only when there are no
changes.
2. fix indentation problems.
3. simplify "to keep recording" to "to record".
4. add a test case for skipping empty patches via the --skip option.
----------------------------------------------------------------------------
Changes since v13:
1. add an additional description about the 'die' value.
----------------------------------------------------------------------------
Changes since v14:
1. reimplement the 'die' value and stop the whole session. (Expected a
reroll)
2. the --allow-empty option is a valid resume value only when: (Expected a
reroll)
* index has not changed
* lacking a patch
----------------------------------------------------------------------------
Changes since v15:
1. rename "die" to "stop".
徐沛文 (Aleen) (3):
doc: git-format-patch: describe the option --always
am: support --empty=<option> to handle empty patches
am: support --allow-empty to record specific empty patches
Documentation/git-am.txt | 16 ++++-
Documentation/git-format-patch.txt | 6 +-
builtin/am.c | 90 +++++++++++++++++++++----
t/t4150-am.sh | 102 +++++++++++++++++++++++++++++
t/t7512-status-help.sh | 1 +
wt-status.c | 3 +
6 files changed, 203 insertions(+), 15 deletions(-)
base-commit: abe6bb3905392d5eb6b01fa6e54d7e784e0522aa
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-1076%2Faleen42%2Fnext-v16
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-1076/aleen42/next-v16
Pull-Request: https://github.com/gitgitgadget/git/pull/1076
Range-diff vs v15:
1: a524ca6adfa = 1: a524ca6adfa doc: git-format-patch: describe the option --always
2: 8ec8e212672 ! 2: b9e03f2342b am: support --empty=<option> to handle empty patches
@@ Commit message
commits that emit no changes, the 'git-am' command should also
support an option, named as '--empty', to specify how to handle
those empty patches. In this commit, we have implemented three
- valid options ('die', 'drop' and 'keep').
+ valid options ('stop', 'drop' and 'keep').
Signed-off-by: 徐沛文 (Aleen) [off-list ref]
@@ Documentation/git-am.txt: SYNOPSIS
[--exclude=<path>] [--include=<path>] [--reject] [-q | --quiet]
[--[no-]scissors] [-S[<keyid>]] [--patch-format=<format>]
[--quoted-cr=<action>]
-+ [--empty=(die|drop|keep)]
++ [--empty=(stop|drop|keep)]
[(<mbox> | <Maildir>)...]
'git am' (--continue | --skip | --abort | --quit | --show-current-patch[=(diff|raw)])
@@ Documentation/git-am.txt: OPTIONS
--quoted-cr=<action>::
This flag will be passed down to 'git mailinfo' (see linkgit:git-mailinfo[1]).
-+--empty=(die|drop|keep)::
-+ By default, the command errors out on an input e-mail message
-+ lacking a patch and stops into the middle of the current am session.
-+ When this option is set to 'die', the whole session dies with error.
-+ When this option is set to 'drop', skip such an e-mail message instead.
++--empty=(stop|drop|keep)::
++ By default, or when the option is set to 'stop', the command
++ errors out on an input e-mail message lacking a patch
++ and stops into the middle of the current am session. When this
++ option is set to 'drop', skip such an e-mail message instead.
+ When this option is set to 'keep', create an empty commit,
+ recording the contents of the e-mail message as its log.
+
@@ builtin/am.c: enum show_patch_type {
};
+enum empty_action {
-+ ERR_EMPTY_COMMIT = 0, /* output errors and stop in the middle of an am session */
-+ DIE_EMPTY_COMMIT, /* output errors and stop the whole am session */
-+ DROP_EMPTY_COMMIT, /* skip with a notice message, unless "--quiet" has been passed */
-+ KEEP_EMPTY_COMMIT /* keep recording as empty commits */
++ STOP_ON_EMPTY_COMMIT = 0, /* output errors and stop in the middle of an am session */
++ DROP_EMPTY_COMMIT, /* skip with a notice message, unless "--quiet" has been passed */
++ KEEP_EMPTY_COMMIT /* keep recording as empty commits */
+};
+
struct am_state {
@@ builtin/am.c: static int am_option_parse_quoted_cr(const struct option *opt,
+
+ BUG_ON_OPT_NEG(unset);
+
-+ if (!strcmp(arg, "die"))
-+ *opt_value = DIE_EMPTY_COMMIT;
++ if (!strcmp(arg, "stop"))
++ *opt_value = STOP_ON_EMPTY_COMMIT;
+ else if (!strcmp(arg, "drop"))
+ *opt_value = DROP_EMPTY_COMMIT;
+ else if (!strcmp(arg, "keep"))
@@ builtin/am.c: static void am_run(struct am_state *state, int resume)
+ case KEEP_EMPTY_COMMIT:
+ to_keep = 1;
+ break;
-+ case DIE_EMPTY_COMMIT:
-+ am_destroy(state);
-+ die(_("Patch is empty."));
-+ break;
-+ case ERR_EMPTY_COMMIT:
++ case STOP_ON_EMPTY_COMMIT:
+ printf_ln(_("Patch is empty."));
+ die_user_resolve(state);
+ break;
@@ builtin/am.c: int cmd_am(int argc, const char **argv, const char *prefix)
{ OPTION_STRING, 'S', "gpg-sign", &state.sign_commit, N_("key-id"),
N_("GPG-sign commits"),
PARSE_OPT_OPTARG, NULL, (intptr_t) "" },
-+ OPT_CALLBACK_F(ERR_EMPTY_COMMIT, "empty", &state.empty_type, "{die,drop,keep}",
++ OPT_CALLBACK_F(STOP_ON_EMPTY_COMMIT, "empty", &state.empty_type, "{stop,drop,keep}",
+ N_("how to handle empty patches"),
+ PARSE_OPT_NONEG, am_option_parse_empty),
OPT_HIDDEN_BOOL(0, "rebasing", &state.rebasing,
@@ t/t4150-am.sh: test_expect_success 'apply binary blob in partial clone' '
+ test_cmp expected err
+'
+
-+test_expect_success 'a message without a patch is an error and stop in the middle of an am session (default)' '
++test_expect_success 'a message without a patch is an error (default)' '
+ test_when_finished "git am --abort || :" &&
+ test_must_fail git am empty-commit.patch >err &&
-+ test_path_is_dir .git/rebase-apply &&
+ grep "Patch is empty" err
+'
+
-+test_expect_success 'a message without a patch is an error and exit where an explicit "--empty=die" is given' '
-+ test_must_fail git am --empty=die empty-commit.patch 2>err &&
-+ test_path_is_missing .git/rebase-apply &&
-+ grep "fatal: Patch is empty." err
++test_expect_success 'a message without a patch is an error where an explicit "--empty=stop" is given' '
++ test_when_finished "git am --abort || :" &&
++ test_must_fail git am --empty=stop empty-commit.patch >err &&
++ grep "Patch is empty." err
+'
+
+test_expect_success 'a message without a patch will be skipped when "--empty=drop" is given' '
3: d669406a312 ! 3: abcdfa1b375 am: support --allow-empty to record specific empty patches
@@ Commit message
## Documentation/git-am.txt ##
@@ Documentation/git-am.txt: SYNOPSIS
[--quoted-cr=<action>]
- [--empty=(die|drop|keep)]
+ [--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)
@@ Documentation/git-am.txt: default. You can use `--no-utf8` to override this.
## builtin/am.c ##
@@ builtin/am.c: static void am_run(struct am_state *state, int resume)
- die(_("Patch is empty."));
+ to_keep = 1;
break;
- case ERR_EMPTY_COMMIT:
+ case STOP_ON_EMPTY_COMMIT:
- printf_ln(_("Patch is empty."));
+ printf_ln(_("Patch is empty.\n"
+ "If you want to record it as an empty commit, run \"git am --allow-empty\"."));
@@ builtin/am.c: next:
* 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 there is no changes.
++ * is true, commit as an empty commit when index had 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)
@@ builtin/am.c: next:
- 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."));
-+ /**
-+ * "--allow-empty" is a valid resume value only when:
-+ * 1. index has not changed
-+ * 2. lacking a 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")))) {
+ printf_ln(_("Invalid resume value."));
--
gitgitgadget
From: 徐沛文 (Aleen) via GitGitGadget <hidden> Date: 2021-12-07 05:01:44
From: =?UTF-8?q?=E5=BE=90=E6=B2=9B=E6=96=87=20=28Aleen=29?=
[off-list ref]
This commit has described how to use '--always' option in the command
'git-format-patch' to include patches for commits that emit no changes.
Signed-off-by: 徐沛文 (Aleen) <redacted>
---
Documentation/git-format-patch.txt | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
@@ -192,6 +192,10 @@ will want to ensure that threading is disabled for `git send-email`. patches being generated, and any patch that matches is ignored.+--always::+ Include patches for commits that do not introduce any change,+ which are omitted by default.+ --cover-from-description=<mode>:: Controls which parts of the cover letter will be automatically populated using the branch's description.
From: 徐沛文 (Aleen) via GitGitGadget <hidden> Date: 2021-12-07 05:01:44
From: =?UTF-8?q?=E5=BE=90=E6=B2=9B=E6=96=87=20=28Aleen=29?=
[off-list ref]
Since that the command 'git-format-patch' can include patches of
commits that emit no changes, the 'git-am' command should also
support an option, named as '--empty', to specify how to handle
those empty patches. In this commit, we have implemented three
valid options ('stop', 'drop' and 'keep').
Signed-off-by: 徐沛文 (Aleen) <redacted>
---
Documentation/git-am.txt | 9 +++++++
builtin/am.c | 55 ++++++++++++++++++++++++++++++++++++----
t/t4150-am.sh | 49 +++++++++++++++++++++++++++++++++++
3 files changed, 108 insertions(+), 5 deletions(-)
@@ -63,6 +64,14 @@ OPTIONS --quoted-cr=<action>:: This flag will be passed down to 'git mailinfo' (see linkgit:git-mailinfo[1]).+--empty=(stop|drop|keep)::+ By default, or when the option is set to 'stop', the command+ errors out on an input e-mail message lacking a patch+ and stops into the middle of the current am session. When this+ option is set to 'drop', skip such an e-mail message instead.+ When this option is set to 'keep', create an empty commit,+ recording the contents of the e-mail message as its log.+ -m:: --message-id:: Pass the `-m` flag to 'git mailinfo' (see linkgit:git-mailinfo[1]),
@@ -87,6 +87,12 @@ enum show_patch_type {SHOW_PATCH_DIFF=1,};+enumempty_action{+STOP_ON_EMPTY_COMMIT=0,/* output errors and stop in the middle of an am session */+DROP_EMPTY_COMMIT,/* skip with a notice message, unless "--quiet" has been passed */+KEEP_EMPTY_COMMIT/* keep recording as empty commits */+};+structam_state{/* state directory path */char*dir;
@@ -178,6 +185,25 @@ static int am_option_parse_quoted_cr(const struct option *opt,return0;}+staticintam_option_parse_empty(conststructoption*opt,+constchar*arg,intunset)+{+int*opt_value=opt->value;++BUG_ON_OPT_NEG(unset);++if(!strcmp(arg,"stop"))+*opt_value=STOP_ON_EMPTY_COMMIT;+elseif(!strcmp(arg,"drop"))+*opt_value=DROP_EMPTY_COMMIT;+elseif(!strcmp(arg,"keep"))+*opt_value=KEEP_EMPTY_COMMIT;+else+returnerror(_("Invalid value for --empty: %s"),arg);++return0;+}+/***Returnspathrelativetotheam_statedirectory.*/
@@ -1248,11 +1274,6 @@ static int parse_mail(struct am_state *state, const char *mail)gotofinish;}-if(is_empty_or_missing_file(am_path(state,"patch"))){-printf_ln(_("Patch is empty."));-die_user_resolve(state);-}-strbuf_addstr(&msg,"\n\n");strbuf_addbuf(&msg,&mi.log_message);strbuf_stripspace(&msg,0);
@@ -1152,4 +1158,47 @@ test_expect_success 'apply binary blob in partial clone' 'git-Cclientam../patch'+test_expect_success'an empty input file is error regardless of --empty option''+test_when_finished"git am --abort || :"&&+test_must_failgitam--empty=dropempty.patch2>actual&&+echo"Patch format detection failed.">expected&&+test_cmpexpectedactual+'++test_expect_success'invalid when passing the --empty option alone''+test_when_finished"git am --abort || :"&&+gitcheckoutempty-commit^&&+test_must_failgitam--emptyempty-commit.patch2>err&&+echo"error: Invalid value for --empty: empty-commit.patch">expected&&+test_cmpexpectederr+'++test_expect_success'a message without a patch is an error (default)''+test_when_finished"git am --abort || :"&&+test_must_failgitamempty-commit.patch>err&&+grep"Patch is empty"err+'++test_expect_success'a message without a patch is an error where an explicit "--empty=stop" is given''+test_when_finished"git am --abort || :"&&+test_must_failgitam--empty=stopempty-commit.patch>err&&+grep"Patch is empty."err+'++test_expect_success'a message without a patch will be skipped when "--empty=drop" is given''+gitam--empty=dropempty-commit.patch>output&&+gitrev-parseempty-commit^>expected&&+gitrev-parseHEAD>actual&&+test_cmpexpectedactual&&+grep"Skipping: empty commit"output+'++test_expect_success'record as an empty commit when meeting e-mail message that lacks a patch''+gitam--empty=keepempty-commit.patch&&+test_path_is_missing.git/rebase-apply&&+gitshowempty-commit--format="%s">expected&&+gitshowHEAD--format="%s">actual&&+test_cmpactualexpected+'+ test_done
From: 徐沛文 (Aleen) via GitGitGadget <hidden> Date: 2021-12-07 05:01:48
From: =?UTF-8?q?=E5=BE=90=E6=B2=9B=E6=96=87=20=28Aleen=29?=
[off-list ref]
This option helps to record specific empty patches in the middle
of an am session. However, it is a valid resume value only when:
1. index has not changed
2. lacking a branch
Signed-off-by: 徐沛文 (Aleen) <redacted>
---
Documentation/git-am.txt | 7 +++++-
builtin/am.c | 37 +++++++++++++++++++++-------
t/t4150-am.sh | 53 ++++++++++++++++++++++++++++++++++++++++
t/t7512-status-help.sh | 1 +
wt-status.c | 3 +++
5 files changed, 91 insertions(+), 10 deletions(-)
@@ -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,+ the user can still record the empty patch as an empty commit with+ the contents of the e-mail message as its log.+ DISCUSSION ----------
@@ -1825,7 +1825,8 @@ static void am_run(struct am_state *state, int resume)to_keep=1;break;caseSTOP_ON_EMPTY_COMMIT:-printf_ln(_("Patch is empty."));+printf_ln(_("Patch is empty.\n"+"If you want to record it as an empty commit, run \"git am --allow-empty\"."));die_user_resolve(state);break;}
@@ -1898,21 +1899,34 @@ next:/***Resumethecurrentamsessionafterpatchapplicationfailure.Theuserdid*allthehardwork,andwedonothavetodoanypatchapplication.Just-*trustandcommitwhattheuserhasintheindexandworkingtree.+*trustandcommitwhattheuserhasintheindexandworkingtree.If`allow_empty`+*istrue,commitasanemptycommitwhenindexhadnotchangedandlackingapatch.*/-staticvoidam_resolve(structam_state*state)+staticvoidam_resolve(structam_state*state,intallow_empty){+intindex_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")))){+printf_ln(_("Invalid resume value."));die_user_resolve(state);}+if(!index_changed){+if(allow_empty)+printf_ln(_("No changes - record 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()){printf_ln(_("You still have unmerged paths in your index.\n""You should 'git add' each file with resolved conflicts to mark them as such.\n"
@@ -2390,6 +2405,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")),
@@ -1201,4 +1201,57 @@ test_expect_success 'record as an empty commit when meeting e-mail message thattest_cmpactualexpected'+test_expect_success'skip an empty patch in the middle of an am session''+gitcheckoutempty-commit^&&+test_must_failgitamempty-commit.patch>err&&+grep"Patch is empty."err&&+grep"If you want to record it as an empty commit, run \"git am --allow-empty\"."err&&+gitam--skip&&+test_path_is_missing.git/rebase-apply&&+gitrev-parseempty-commit^>expected&&+gitrev-parseHEAD>actual&&+test_cmpexpectedactual+'++test_expect_success'record an empty patch as an empty commit in the middle of an am session''+gitcheckoutempty-commit^&&+test_must_failgitamempty-commit.patch>err&&+grep"Patch is empty."err&&+grep"If you want to record it as an empty commit, run \"git am --allow-empty\"."err&&+gitam--allow-empty&&+test_path_is_missing.git/rebase-apply&&+gitshowempty-commit--format="%s">expected&&+gitshowHEAD--format="%s">actual&&+test_cmpactualexpected+'++test_expect_success'cannot create empty commits when the index is changed''+gitcheckoutempty-commit^&&+test_must_failgitamempty-commit.patch>err&&+:>empty-file&&+gitaddempty-file&&+test_must_failgitam--allow-empty>err&&+grep"Invalid resume value."err+'++test_expect_success'cannot create empty commits when there is a clean index due to merge conflicts''+test_when_finished"git am --abort || :"&&+gitrev-parseHEAD>expected&&+test_must_failgitamseq.patch&&+test_must_failgitam--allow-empty>err&&+grep"Invalid resume value."err&&+gitrev-parseHEAD>actual&&+test_cmpactualexpected+'++test_expect_success'cannot create empty commits when there is unmerged index due to merge conflicts''+test_when_finished"git am --abort || :"&&+gitrev-parseHEAD>expected&&+test_must_failgitam-3seq.patch&&+test_must_failgitam--allow-empty>err&&+grep"Invalid resume value."err&&+gitrev-parseHEAD>actual&&+test_cmpactualexpected+'+ test_done
@@ -658,6 +658,7 @@ test_expect_success 'status in an am session: empty patch' ' Onbrancham_empty Youareinthemiddleofanamsession. Thecurrentpatchisempty.+(use"git am --allow-empty"torecordthispatchasanemptycommit)(use"git am --skip"toskipthispatch)(use"git am --abort"torestoretheoriginalbranch)
@@ -1227,6 +1227,9 @@ static void show_am_in_progress(struct wt_status *s,if(!s->state.am_empty_patch)status_printf_ln(s,color,_(" (fix conflicts and then run \"git am --continue\")"));+else+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 --skip\" to skip this patch)"));status_printf_ln(s,color,
From: Aleen via GitGitGadget <hidden> Date: 2021-12-07 08:31:59
Since that git has supported the --always option for the git-format-patch
command to create a patch with an empty commit message, git-am should
support applying and committing with empty patches.
----------------------------------------------------------------------------
Changes since v1:
1. add a case when not passing the --always option.
2. rename the --always option to --allow-empty.
----------------------------------------------------------------------------
Changes since v2:
1. rename the --allow-empty option to --empty-commit.
2. introduce three different strategies (die|skip|asis) when trying to
record empty patches as empty commits.
----------------------------------------------------------------------------
Changes since v3:
1. generate the missed file for test cases.
2. grep -f cannot be used under Mac OS.
----------------------------------------------------------------------------
Changes since v4:
1. rename the --empty-commit option to --empty.
2. rename three different strategies (die|skip|asis) to die, drop and keep
correspondingly.
----------------------------------------------------------------------------
Changes since v5:
1. throw an error when passing --empty option without value.
----------------------------------------------------------------------------
Changes since v6:
1. add i18n resources.
----------------------------------------------------------------------------
Changes since v7:
1. update code according to the seen branch.
2. fix the wrong document of git-am.
3. sign off commits by a real name.
----------------------------------------------------------------------------
Changes since v8:
1. update the committer's name with my real name to fix DCO of GGG.
----------------------------------------------------------------------------
Changes since v9:
1. imitate the signed name format of
https://lore.kernel.org/git/pull.1143.git.git.1637347813367.gitgitgadget@gmail.com
.
----------------------------------------------------------------------------
Changes since v11:
1. introduce an interactive option --allow-empty for git-am to record empty
patches in the middle of an am session.
----------------------------------------------------------------------------
Changes since v12:
1. record the empty patch as an empty commit only when there are no
changes.
2. fix indentation problems.
3. simplify "to keep recording" to "to record".
4. add a test case for skipping empty patches via the --skip option.
----------------------------------------------------------------------------
Changes since v13:
1. add an additional description about the 'die' value.
----------------------------------------------------------------------------
Changes since v14:
1. reimplement the 'die' value and stop the whole session. (Expected a
reroll)
2. the --allow-empty option is a valid resume value only when: (Expected a
reroll)
* index has not changed
* lacking a patch
----------------------------------------------------------------------------
Changes since v15:
1. rename "die" to "stop".
----------------------------------------------------------------------------
Changes since v16:
1. fix typo from "had" to "has" in the comment.
徐沛文 (Aleen) (3):
doc: git-format-patch: describe the option --always
am: support --empty=<option> to handle empty patches
am: support --allow-empty to record specific empty patches
Documentation/git-am.txt | 16 ++++-
Documentation/git-format-patch.txt | 6 +-
builtin/am.c | 90 +++++++++++++++++++++----
t/t4150-am.sh | 102 +++++++++++++++++++++++++++++
t/t7512-status-help.sh | 1 +
wt-status.c | 3 +
6 files changed, 203 insertions(+), 15 deletions(-)
base-commit: abe6bb3905392d5eb6b01fa6e54d7e784e0522aa
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-1076%2Faleen42%2Fnext-v17
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-1076/aleen42/next-v17
Pull-Request: https://github.com/gitgitgadget/git/pull/1076
Range-diff vs v16:
1: a524ca6adfa = 1: a524ca6adfa doc: git-format-patch: describe the option --always
2: b9e03f2342b = 2: b9e03f2342b am: support --empty=<option> to handle empty patches
3: abcdfa1b375 ! 3: ea2dc088b37 am: support --allow-empty to record specific empty patches
@@ builtin/am.c: next:
* 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 had not changed and lacking a patch.
++ * 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)
--
gitgitgadget
From: 徐沛文 (Aleen) via GitGitGadget <hidden> Date: 2021-12-07 08:32:00
From: =?UTF-8?q?=E5=BE=90=E6=B2=9B=E6=96=87=20=28Aleen=29?=
[off-list ref]
This commit has described how to use '--always' option in the command
'git-format-patch' to include patches for commits that emit no changes.
Signed-off-by: 徐沛文 (Aleen) <redacted>
---
Documentation/git-format-patch.txt | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
@@ -192,6 +192,10 @@ will want to ensure that threading is disabled for `git send-email`. patches being generated, and any patch that matches is ignored.+--always::+ Include patches for commits that do not introduce any change,+ which are omitted by default.+ --cover-from-description=<mode>:: Controls which parts of the cover letter will be automatically populated using the branch's description.
From: 徐沛文 (Aleen) via GitGitGadget <hidden> Date: 2021-12-07 08:32:00
From: =?UTF-8?q?=E5=BE=90=E6=B2=9B=E6=96=87=20=28Aleen=29?=
[off-list ref]
Since that the command 'git-format-patch' can include patches of
commits that emit no changes, the 'git-am' command should also
support an option, named as '--empty', to specify how to handle
those empty patches. In this commit, we have implemented three
valid options ('stop', 'drop' and 'keep').
Signed-off-by: 徐沛文 (Aleen) <redacted>
---
Documentation/git-am.txt | 9 +++++++
builtin/am.c | 55 ++++++++++++++++++++++++++++++++++++----
t/t4150-am.sh | 49 +++++++++++++++++++++++++++++++++++
3 files changed, 108 insertions(+), 5 deletions(-)
@@ -63,6 +64,14 @@ OPTIONS --quoted-cr=<action>:: This flag will be passed down to 'git mailinfo' (see linkgit:git-mailinfo[1]).+--empty=(stop|drop|keep)::+ By default, or when the option is set to 'stop', the command+ errors out on an input e-mail message lacking a patch+ and stops into the middle of the current am session. When this+ option is set to 'drop', skip such an e-mail message instead.+ When this option is set to 'keep', create an empty commit,+ recording the contents of the e-mail message as its log.+ -m:: --message-id:: Pass the `-m` flag to 'git mailinfo' (see linkgit:git-mailinfo[1]),
@@ -87,6 +87,12 @@ enum show_patch_type {SHOW_PATCH_DIFF=1,};+enumempty_action{+STOP_ON_EMPTY_COMMIT=0,/* output errors and stop in the middle of an am session */+DROP_EMPTY_COMMIT,/* skip with a notice message, unless "--quiet" has been passed */+KEEP_EMPTY_COMMIT/* keep recording as empty commits */+};+structam_state{/* state directory path */char*dir;
@@ -178,6 +185,25 @@ static int am_option_parse_quoted_cr(const struct option *opt,return0;}+staticintam_option_parse_empty(conststructoption*opt,+constchar*arg,intunset)+{+int*opt_value=opt->value;++BUG_ON_OPT_NEG(unset);++if(!strcmp(arg,"stop"))+*opt_value=STOP_ON_EMPTY_COMMIT;+elseif(!strcmp(arg,"drop"))+*opt_value=DROP_EMPTY_COMMIT;+elseif(!strcmp(arg,"keep"))+*opt_value=KEEP_EMPTY_COMMIT;+else+returnerror(_("Invalid value for --empty: %s"),arg);++return0;+}+/***Returnspathrelativetotheam_statedirectory.*/
@@ -1248,11 +1274,6 @@ static int parse_mail(struct am_state *state, const char *mail)gotofinish;}-if(is_empty_or_missing_file(am_path(state,"patch"))){-printf_ln(_("Patch is empty."));-die_user_resolve(state);-}-strbuf_addstr(&msg,"\n\n");strbuf_addbuf(&msg,&mi.log_message);strbuf_stripspace(&msg,0);
@@ -1152,4 +1158,47 @@ test_expect_success 'apply binary blob in partial clone' 'git-Cclientam../patch'+test_expect_success'an empty input file is error regardless of --empty option''+test_when_finished"git am --abort || :"&&+test_must_failgitam--empty=dropempty.patch2>actual&&+echo"Patch format detection failed.">expected&&+test_cmpexpectedactual+'++test_expect_success'invalid when passing the --empty option alone''+test_when_finished"git am --abort || :"&&+gitcheckoutempty-commit^&&+test_must_failgitam--emptyempty-commit.patch2>err&&+echo"error: Invalid value for --empty: empty-commit.patch">expected&&+test_cmpexpectederr+'++test_expect_success'a message without a patch is an error (default)''+test_when_finished"git am --abort || :"&&+test_must_failgitamempty-commit.patch>err&&+grep"Patch is empty"err+'++test_expect_success'a message without a patch is an error where an explicit "--empty=stop" is given''+test_when_finished"git am --abort || :"&&+test_must_failgitam--empty=stopempty-commit.patch>err&&+grep"Patch is empty."err+'++test_expect_success'a message without a patch will be skipped when "--empty=drop" is given''+gitam--empty=dropempty-commit.patch>output&&+gitrev-parseempty-commit^>expected&&+gitrev-parseHEAD>actual&&+test_cmpexpectedactual&&+grep"Skipping: empty commit"output+'++test_expect_success'record as an empty commit when meeting e-mail message that lacks a patch''+gitam--empty=keepempty-commit.patch&&+test_path_is_missing.git/rebase-apply&&+gitshowempty-commit--format="%s">expected&&+gitshowHEAD--format="%s">actual&&+test_cmpactualexpected+'+ test_done
From: 徐沛文 (Aleen) via GitGitGadget <hidden> Date: 2021-12-07 08:32:07
From: =?UTF-8?q?=E5=BE=90=E6=B2=9B=E6=96=87=20=28Aleen=29?=
[off-list ref]
This option helps to record specific empty patches in the middle
of an am session. However, it is a valid resume value only when:
1. index has not changed
2. lacking a branch
Signed-off-by: 徐沛文 (Aleen) <redacted>
---
Documentation/git-am.txt | 7 +++++-
builtin/am.c | 37 +++++++++++++++++++++-------
t/t4150-am.sh | 53 ++++++++++++++++++++++++++++++++++++++++
t/t7512-status-help.sh | 1 +
wt-status.c | 3 +++
5 files changed, 91 insertions(+), 10 deletions(-)
@@ -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,+ the user can still record the empty patch as an empty commit with+ the contents of the e-mail message as its log.+ DISCUSSION ----------
@@ -1825,7 +1825,8 @@ static void am_run(struct am_state *state, int resume)to_keep=1;break;caseSTOP_ON_EMPTY_COMMIT:-printf_ln(_("Patch is empty."));+printf_ln(_("Patch is empty.\n"+"If you want to record it as an empty commit, run \"git am --allow-empty\"."));die_user_resolve(state);break;}
@@ -1898,21 +1899,34 @@ next:/***Resumethecurrentamsessionafterpatchapplicationfailure.Theuserdid*allthehardwork,andwedonothavetodoanypatchapplication.Just-*trustandcommitwhattheuserhasintheindexandworkingtree.+*trustandcommitwhattheuserhasintheindexandworkingtree.If`allow_empty`+*istrue,commitasanemptycommitwhenindexhasnotchangedandlackingapatch.*/-staticvoidam_resolve(structam_state*state)+staticvoidam_resolve(structam_state*state,intallow_empty){+intindex_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")))){+printf_ln(_("Invalid resume value."));die_user_resolve(state);}+if(!index_changed){+if(allow_empty)+printf_ln(_("No changes - record 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()){printf_ln(_("You still have unmerged paths in your index.\n""You should 'git add' each file with resolved conflicts to mark them as such.\n"
@@ -2390,6 +2405,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")),
@@ -1201,4 +1201,57 @@ test_expect_success 'record as an empty commit when meeting e-mail message thattest_cmpactualexpected'+test_expect_success'skip an empty patch in the middle of an am session''+gitcheckoutempty-commit^&&+test_must_failgitamempty-commit.patch>err&&+grep"Patch is empty."err&&+grep"If you want to record it as an empty commit, run \"git am --allow-empty\"."err&&+gitam--skip&&+test_path_is_missing.git/rebase-apply&&+gitrev-parseempty-commit^>expected&&+gitrev-parseHEAD>actual&&+test_cmpexpectedactual+'++test_expect_success'record an empty patch as an empty commit in the middle of an am session''+gitcheckoutempty-commit^&&+test_must_failgitamempty-commit.patch>err&&+grep"Patch is empty."err&&+grep"If you want to record it as an empty commit, run \"git am --allow-empty\"."err&&+gitam--allow-empty&&+test_path_is_missing.git/rebase-apply&&+gitshowempty-commit--format="%s">expected&&+gitshowHEAD--format="%s">actual&&+test_cmpactualexpected+'++test_expect_success'cannot create empty commits when the index is changed''+gitcheckoutempty-commit^&&+test_must_failgitamempty-commit.patch>err&&+:>empty-file&&+gitaddempty-file&&+test_must_failgitam--allow-empty>err&&+grep"Invalid resume value."err+'++test_expect_success'cannot create empty commits when there is a clean index due to merge conflicts''+test_when_finished"git am --abort || :"&&+gitrev-parseHEAD>expected&&+test_must_failgitamseq.patch&&+test_must_failgitam--allow-empty>err&&+grep"Invalid resume value."err&&+gitrev-parseHEAD>actual&&+test_cmpactualexpected+'++test_expect_success'cannot create empty commits when there is unmerged index due to merge conflicts''+test_when_finished"git am --abort || :"&&+gitrev-parseHEAD>expected&&+test_must_failgitam-3seq.patch&&+test_must_failgitam--allow-empty>err&&+grep"Invalid resume value."err&&+gitrev-parseHEAD>actual&&+test_cmpactualexpected+'+ test_done
@@ -658,6 +658,7 @@ test_expect_success 'status in an am session: empty patch' ' Onbrancham_empty Youareinthemiddleofanamsession. Thecurrentpatchisempty.+(use"git am --allow-empty"torecordthispatchasanemptycommit)(use"git am --skip"toskipthispatch)(use"git am --abort"torestoretheoriginalbranch)
@@ -1227,6 +1227,9 @@ static void show_am_in_progress(struct wt_status *s,if(!s->state.am_empty_patch)status_printf_ln(s,color,_(" (fix conflicts and then run \"git am --continue\")"));+else+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 --skip\" to skip this patch)"));status_printf_ln(s,color,
From: Junio C Hamano <hidden> Date: 2021-12-07 18:12:44
""徐沛文 (Aleen)" via GitGitGadget" [off-list ref]
writes:
This step look mostly good and well done, except for just a few
things that remain.
+enum empty_action {
+ STOP_ON_EMPTY_COMMIT = 0, /* output errors and stop in the middle of an am session */
+ DROP_EMPTY_COMMIT, /* skip with a notice message, unless "--quiet" has been passed */
+ KEEP_EMPTY_COMMIT /* keep recording as empty commits */
+};
It is friendly to future developers to end the last item in enum
with a comma, unless the current last item MUST stay to be the last
one even when they add new ones. I.e.
KEEP_EMPTY_COMMIT, /* keep recording as empty commits */
quoted hunk
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 */
Mental note. After this series graduates to 'master', at some point
in the future, we should clean these members up to be of their
respective enum types, not "int".
quoted hunk
@@ -1763,6 +1784,7 @@ static void am_run(struct am_state *state, int resume) while (state->cur <= state->last) { const char *mail = am_path(state, msgnum(state)); int apply_status;+ int to_keep; reset_ident_date();
@@ -1792,8 +1814,27 @@ static void am_run(struct am_state *state, int resume) if (state->interactive && do_interactive(state)) goto next;+ 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: %.*s"), linelen(state->msg), state->msg);+ goto next;+ break;+ case KEEP_EMPTY_COMMIT:+ to_keep = 1;
This causes the code that produces the "Applying" message jumped
over, so the user will not see anything done for this step.
I think we want to mimic the above case arm and do something like
say(state, stdout, _("Creating an empty commit: %.*s"),
linelen(state->msg), state->msg);
to avoid being mum about what was done in this step.
quoted hunk
+ break;
+ case STOP_ON_EMPTY_COMMIT:
+ printf_ln(_("Patch is empty."));
+ die_user_resolve(state);
+ break;
+ }
+ }
+
if (run_applypatch_msg_hook(state))
exit(1);
+ if (to_keep)
+ goto commit;
say(state, stdout, _("Applying: %.*s"), linelen(state->msg), state->msg);
+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="%s" >expected &&
+ git show HEAD --format="%s" >actual &&
For the test data prepared by the earlier part of this patch, this
does not make a difference, but by using %B instead of %s, I think
you can catch a future bug that only keeps the subject intact while
munging the body of the message.
Other than these, looking quite good.
Thanks.
From: Aleen via GitGitGadget <hidden> Date: 2021-12-08 05:05:57
Since that git has supported the --always option for the git-format-patch
command to create a patch with an empty commit message, git-am should
support applying and committing with empty patches.
----------------------------------------------------------------------------
Changes since v1:
1. add a case when not passing the --always option.
2. rename the --always option to --allow-empty.
----------------------------------------------------------------------------
Changes since v2:
1. rename the --allow-empty option to --empty-commit.
2. introduce three different strategies (die|skip|asis) when trying to
record empty patches as empty commits.
----------------------------------------------------------------------------
Changes since v3:
1. generate the missed file for test cases.
2. grep -f cannot be used under Mac OS.
----------------------------------------------------------------------------
Changes since v4:
1. rename the --empty-commit option to --empty.
2. rename three different strategies (die|skip|asis) to die, drop and keep
correspondingly.
----------------------------------------------------------------------------
Changes since v5:
1. throw an error when passing --empty option without value.
----------------------------------------------------------------------------
Changes since v6:
1. add i18n resources.
----------------------------------------------------------------------------
Changes since v7:
1. update code according to the seen branch.
2. fix the wrong document of git-am.
3. sign off commits by a real name.
----------------------------------------------------------------------------
Changes since v8:
1. update the committer's name with my real name to fix DCO of GGG.
----------------------------------------------------------------------------
Changes since v9:
1. imitate the signed name format of
https://lore.kernel.org/git/pull.1143.git.git.1637347813367.gitgitgadget@gmail.com
.
----------------------------------------------------------------------------
Changes since v11:
1. introduce an interactive option --allow-empty for git-am to record empty
patches in the middle of an am session.
----------------------------------------------------------------------------
Changes since v12:
1. record the empty patch as an empty commit only when there are no
changes.
2. fix indentation problems.
3. simplify "to keep recording" to "to record".
4. add a test case for skipping empty patches via the --skip option.
----------------------------------------------------------------------------
Changes since v13:
1. add an additional description about the 'die' value.
----------------------------------------------------------------------------
Changes since v14:
1. reimplement the 'die' value and stop the whole session. (Expected a
reroll)
2. the --allow-empty option is a valid resume value only when: (Expected a
reroll)
* index has not changed
* lacking a patch
----------------------------------------------------------------------------
Changes since v15:
1. rename "die" to "stop".
----------------------------------------------------------------------------
Changes since v16:
1. fix the typo from "had" to "has" in the comment.
----------------------------------------------------------------------------
Changes since v17:
1. add trailing comma, show tips of creating an empty commit, and use "%B"
to construct test cases.
2. remove the error "Invalid resume value.".
3. hint "--allow-empty" after "--skip".
徐沛文 (Aleen) (3):
doc: git-format-patch: describe the option --always
am: support --empty=<option> to handle empty patches
am: support --allow-empty to record specific empty patches
Documentation/git-am.txt | 16 ++++-
Documentation/git-format-patch.txt | 6 +-
builtin/am.c | 96 ++++++++++++++++++++++----
t/t4150-am.sh | 104 +++++++++++++++++++++++++++++
t/t7512-status-help.sh | 1 +
wt-status.c | 8 ++-
6 files changed, 215 insertions(+), 16 deletions(-)
base-commit: abe6bb3905392d5eb6b01fa6e54d7e784e0522aa
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-1076%2Faleen42%2Fnext-v18
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-1076/aleen42/next-v18
Pull-Request: https://github.com/gitgitgadget/git/pull/1076
Range-diff vs v17:
1: a524ca6adfa = 1: a524ca6adfa doc: git-format-patch: describe the option --always
2: b9e03f2342b ! 2: 56953d416d9 am: support --empty=<option> to handle empty patches
@@ builtin/am.c: enum show_patch_type {
+enum empty_action {
+ STOP_ON_EMPTY_COMMIT = 0, /* output errors and stop in the middle of an am session */
+ DROP_EMPTY_COMMIT, /* skip with a notice message, unless "--quiet" has been passed */
-+ KEEP_EMPTY_COMMIT /* keep recording as empty commits */
++ KEEP_EMPTY_COMMIT, /* keep recording as empty commits */
+};
+
struct am_state {
@@ builtin/am.c: static void am_run(struct am_state *state, int resume)
+ break;
+ case KEEP_EMPTY_COMMIT:
+ to_keep = 1;
++ say(state, stdout, _("Creating an empty commit: %.*s"),
++ linelen(state->msg), state->msg);
+ break;
+ case STOP_ON_EMPTY_COMMIT:
+ printf_ln(_("Patch is empty."));
@@ t/t4150-am.sh: test_expect_success 'apply binary blob in partial clone' '
+'
+
+test_expect_success 'record as an empty commit when meeting e-mail message that lacks a patch' '
-+ git am --empty=keep empty-commit.patch &&
++ git am --empty=keep empty-commit.patch >output &&
+ test_path_is_missing .git/rebase-apply &&
-+ git show empty-commit --format="%s" >expected &&
-+ git show HEAD --format="%s" >actual &&
-+ test_cmp actual expected
++ git show empty-commit --format="%B" >expected &&
++ git show HEAD --format="%B" >actual &&
++ grep -f actual expected &&
++ grep "Creating an empty commit: empty commit" output
+'
+
test_done
3: ea2dc088b37 ! 3: 4c3077f9384 am: support --allow-empty to record specific empty patches
@@ Commit message
am: support --allow-empty to record specific empty patches
This option helps to record specific empty patches in the middle
- of an am session. However, it is a valid resume value only when:
+ of an am session, which does create empty commits only when:
1. index has not changed
2. lacking a branch
@@ Documentation/git-am.txt: default. You can use `--no-utf8` to override this.
+--allow-empty::
+ After a patch failure on an input e-mail message lacking a patch,
-+ the user can still record the empty patch as an empty commit with
-+ the contents of the e-mail message as its log.
++ create an empty commit with the contents of the e-mail message
++ as its log message.
+
DISCUSSION
----------
## builtin/am.c ##
-@@ builtin/am.c: static void am_run(struct am_state *state, int resume)
- to_keep = 1;
- break;
- case STOP_ON_EMPTY_COMMIT:
-- printf_ln(_("Patch is empty."));
-+ printf_ln(_("Patch is empty.\n"
-+ "If you want to record it as an empty commit, run \"git am --allow-empty\"."));
- die_user_resolve(state);
- break;
- }
+@@ builtin/am.c: 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);
+ }
+
@@ builtin/am.c: next:
/**
* Resume the current am session after patch application failure. The user did
@@ builtin/am.c: next:
- "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")))) {
-+ printf_ln(_("Invalid resume value."));
++ 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 - record it as an empty commit."));
-+ else {
++ 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()) {
- printf_ln(_("You still have unmerged paths in your index.\n"
- "You should 'git add' each file with resolved conflicts to mark them as such.\n"
@@ builtin/am.c: enum resume_type {
RESUME_SKIP,
RESUME_ABORT,
RESUME_QUIT,
- RESUME_SHOW_PATCH
+ RESUME_SHOW_PATCH,
-+ RESUME_ALLOW_EMPTY
++ RESUME_ALLOW_EMPTY,
};
struct resume_mode {
@@ builtin/am.c: int cmd_am(int argc, const char **argv, const char *prefix)
## t/t4150-am.sh ##
@@ t/t4150-am.sh: test_expect_success 'record as an empty commit when meeting e-mail message that
- test_cmp actual expected
+ 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 "If you want to record it as an empty commit, run \"git am --allow-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 &&
@@ t/t4150-am.sh: test_expect_success 'record as an empty commit when meeting e-mai
+ git checkout empty-commit^ &&
+ test_must_fail git am empty-commit.patch >err &&
+ grep "Patch is empty." err &&
-+ grep "If you want to record it as an empty commit, run \"git am --allow-empty\"." err &&
-+ git am --allow-empty &&
++ 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="%s" >expected &&
-+ git show HEAD --format="%s" >actual &&
-+ test_cmp actual expected
++ 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' '
@@ t/t4150-am.sh: test_expect_success 'record as an empty commit when meeting e-mai
+ : >empty-file &&
+ git add empty-file &&
+ test_must_fail git am --allow-empty >err &&
-+ grep "Invalid resume value." 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' '
@@ t/t4150-am.sh: test_expect_success 'record as an empty commit when meeting e-mai
+ git rev-parse HEAD >expected &&
+ test_must_fail git am seq.patch &&
+ test_must_fail git am --allow-empty >err &&
-+ grep "Invalid resume value." 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
+'
@@ t/t4150-am.sh: test_expect_success 'record as an empty commit when meeting e-mai
+ git rev-parse HEAD >expected &&
+ test_must_fail git am -3 seq.patch &&
+ test_must_fail git am --allow-empty >err &&
-+ grep "Invalid resume value." 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
+'
@@ t/t4150-am.sh: test_expect_success 'record as an empty commit when meeting e-mai
test_done
## t/t7512-status-help.sh ##
-@@ t/t7512-status-help.sh: test_expect_success 'status in an am session: empty patch' '
- On branch am_empty
+@@ t/t7512-status-help.sh: On branch am_empty
You are in the middle of an am session.
The current patch is empty.
-+ (use "git am --allow-empty" to record this patch as an empty commit)
(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)
## wt-status.c ##
-@@ wt-status.c: static void show_am_in_progress(struct wt_status *s,
- if (!s->state.am_empty_patch)
+@@ wt-status.c: 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\")"));
-+ else
-+ 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 --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
From: 徐沛文 (Aleen) via GitGitGadget <hidden> Date: 2021-12-08 05:05:58
From: =?UTF-8?q?=E5=BE=90=E6=B2=9B=E6=96=87=20=28Aleen=29?=
[off-list ref]
This commit has described how to use '--always' option in the command
'git-format-patch' to include patches for commits that emit no changes.
Signed-off-by: 徐沛文 (Aleen) <redacted>
---
Documentation/git-format-patch.txt | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
@@ -192,6 +192,10 @@ will want to ensure that threading is disabled for `git send-email`. patches being generated, and any patch that matches is ignored.+--always::+ Include patches for commits that do not introduce any change,+ which are omitted by default.+ --cover-from-description=<mode>:: Controls which parts of the cover letter will be automatically populated using the branch's description.
From: 徐沛文 (Aleen) via GitGitGadget <hidden> Date: 2021-12-08 05:05:59
From: =?UTF-8?q?=E5=BE=90=E6=B2=9B=E6=96=87=20=28Aleen=29?=
[off-list ref]
Since that the command 'git-format-patch' can include patches of
commits that emit no changes, the 'git-am' command should also
support an option, named as '--empty', to specify how to handle
those empty patches. In this commit, we have implemented three
valid options ('stop', 'drop' and 'keep').
Signed-off-by: 徐沛文 (Aleen) <redacted>
---
Documentation/git-am.txt | 9 +++++++
builtin/am.c | 57 ++++++++++++++++++++++++++++++++++++----
t/t4150-am.sh | 50 +++++++++++++++++++++++++++++++++++
3 files changed, 111 insertions(+), 5 deletions(-)
@@ -63,6 +64,14 @@ OPTIONS --quoted-cr=<action>:: This flag will be passed down to 'git mailinfo' (see linkgit:git-mailinfo[1]).+--empty=(stop|drop|keep)::+ By default, or when the option is set to 'stop', the command+ errors out on an input e-mail message lacking a patch+ and stops into the middle of the current am session. When this+ option is set to 'drop', skip such an e-mail message instead.+ When this option is set to 'keep', create an empty commit,+ recording the contents of the e-mail message as its log.+ -m:: --message-id:: Pass the `-m` flag to 'git mailinfo' (see linkgit:git-mailinfo[1]),
@@ -87,6 +87,12 @@ enum show_patch_type {SHOW_PATCH_DIFF=1,};+enumempty_action{+STOP_ON_EMPTY_COMMIT=0,/* output errors and stop in the middle of an am session */+DROP_EMPTY_COMMIT,/* skip with a notice message, unless "--quiet" has been passed */+KEEP_EMPTY_COMMIT,/* keep recording as empty commits */+};+structam_state{/* state directory path */char*dir;
@@ -178,6 +185,25 @@ static int am_option_parse_quoted_cr(const struct option *opt,return0;}+staticintam_option_parse_empty(conststructoption*opt,+constchar*arg,intunset)+{+int*opt_value=opt->value;++BUG_ON_OPT_NEG(unset);++if(!strcmp(arg,"stop"))+*opt_value=STOP_ON_EMPTY_COMMIT;+elseif(!strcmp(arg,"drop"))+*opt_value=DROP_EMPTY_COMMIT;+elseif(!strcmp(arg,"keep"))+*opt_value=KEEP_EMPTY_COMMIT;+else+returnerror(_("Invalid value for --empty: %s"),arg);++return0;+}+/***Returnspathrelativetotheam_statedirectory.*/
@@ -1248,11 +1274,6 @@ static int parse_mail(struct am_state *state, const char *mail)gotofinish;}-if(is_empty_or_missing_file(am_path(state,"patch"))){-printf_ln(_("Patch is empty."));-die_user_resolve(state);-}-strbuf_addstr(&msg,"\n\n");strbuf_addbuf(&msg,&mi.log_message);strbuf_stripspace(&msg,0);
@@ -1152,4 +1158,48 @@ test_expect_success 'apply binary blob in partial clone' 'git-Cclientam../patch'+test_expect_success'an empty input file is error regardless of --empty option''+test_when_finished"git am --abort || :"&&+test_must_failgitam--empty=dropempty.patch2>actual&&+echo"Patch format detection failed.">expected&&+test_cmpexpectedactual+'++test_expect_success'invalid when passing the --empty option alone''+test_when_finished"git am --abort || :"&&+gitcheckoutempty-commit^&&+test_must_failgitam--emptyempty-commit.patch2>err&&+echo"error: Invalid value for --empty: empty-commit.patch">expected&&+test_cmpexpectederr+'++test_expect_success'a message without a patch is an error (default)''+test_when_finished"git am --abort || :"&&+test_must_failgitamempty-commit.patch>err&&+grep"Patch is empty"err+'++test_expect_success'a message without a patch is an error where an explicit "--empty=stop" is given''+test_when_finished"git am --abort || :"&&+test_must_failgitam--empty=stopempty-commit.patch>err&&+grep"Patch is empty."err+'++test_expect_success'a message without a patch will be skipped when "--empty=drop" is given''+gitam--empty=dropempty-commit.patch>output&&+gitrev-parseempty-commit^>expected&&+gitrev-parseHEAD>actual&&+test_cmpexpectedactual&&+grep"Skipping: empty commit"output+'++test_expect_success'record as an empty commit when meeting e-mail message that lacks a patch''+gitam--empty=keepempty-commit.patch>output&&+test_path_is_missing.git/rebase-apply&&+gitshowempty-commit--format="%B">expected&&+gitshowHEAD--format="%B">actual&&+grep-factualexpected&&+grep"Creating an empty commit: empty commit"output+'+ test_done
From: 徐沛文 (Aleen) via GitGitGadget <hidden> Date: 2021-12-08 05:06:00
From: =?UTF-8?q?=E5=BE=90=E6=B2=9B=E6=96=87=20=28Aleen=29?=
[off-list ref]
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) <redacted>
---
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(-)
@@ -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 ----------
@@ -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:/***Resumethecurrentamsessionafterpatchapplicationfailure.Theuserdid*allthehardwork,andwedonothavetodoanypatchapplication.Just-*trustandcommitwhattheuserhasintheindexandworkingtree.+*trustandcommitwhattheuserhasintheindexandworkingtree.If`allow_empty`+*istrue,commitasanemptycommitwhenindexhasnotchangedandlackingapatch.*/-staticvoidam_resolve(structam_state*state)+staticvoidam_resolve(structam_state*state,intallow_empty){+intindex_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()){
@@ -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")),
@@ -1202,4 +1202,58 @@ test_expect_success 'record as an empty commit when meeting e-mail message thatgrep"Creating an empty commit: empty commit"output'+test_expect_success'skip an empty patch in the middle of an am session''+gitcheckoutempty-commit^&&+test_must_failgitamempty-commit.patch>err&&+grep"Patch is empty."err&&+grep"To record the empty patch as an empty commit, run \"git am --allow-empty\"."err&&+gitam--skip&&+test_path_is_missing.git/rebase-apply&&+gitrev-parseempty-commit^>expected&&+gitrev-parseHEAD>actual&&+test_cmpexpectedactual+'++test_expect_success'record an empty patch as an empty commit in the middle of an am session''+gitcheckoutempty-commit^&&+test_must_failgitamempty-commit.patch>err&&+grep"Patch is empty."err&&+grep"To record the empty patch as an empty commit, run \"git am --allow-empty\"."err&&+gitam--allow-empty>output&&+grep"No changes - recorded it as an empty commit."output&&+test_path_is_missing.git/rebase-apply&&+gitshowempty-commit--format="%B">expected&&+gitshowHEAD--format="%B">actual&&+grep-factualexpected+'++test_expect_success'cannot create empty commits when the index is changed''+gitcheckoutempty-commit^&&+test_must_failgitamempty-commit.patch>err&&+:>empty-file&&+gitaddempty-file&&+test_must_failgitam--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 || :"&&+gitrev-parseHEAD>expected&&+test_must_failgitamseq.patch&&+test_must_failgitam--allow-empty>err&&+!grep"To record the empty patch as an empty commit, run \"git am --allow-empty\"."err&&+gitrev-parseHEAD>actual&&+test_cmpactualexpected+'++test_expect_success'cannot create empty commits when there is unmerged index due to merge conflicts''+test_when_finished"git am --abort || :"&&+gitrev-parseHEAD>expected&&+test_must_failgitam-3seq.patch&&+test_must_failgitam--allow-empty>err&&+!grep"To record the empty patch as an empty commit, run \"git am --allow-empty\"."err&&+gitrev-parseHEAD>actual&&+test_cmpactualexpected+'+ test_done
@@ -659,6 +659,7 @@ On branch am_empty Youareinthemiddleofanamsession. Thecurrentpatchisempty.(use"git am --skip"toskipthispatch)+(use"git am --allow-empty"torecordthispatchasanemptycommit)(use"git am --abort"torestoretheoriginalbranch) nothingtocommit(use-utoshowuntrackedfiles)
@@ -1218,17 +1218,23 @@ static void show_merge_in_progress(struct wt_status *s,staticvoidshow_am_in_progress(structwt_status*s,constchar*color){+intam_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)"));}
From: Aleen via GitGitGadget <hidden> Date: 2021-12-09 07:26:00
Since that git has supported the --always option for the git-format-patch
command to create a patch with an empty commit message, git-am should
support applying and committing with empty patches.
----------------------------------------------------------------------------
Changes since v1:
1. add a case when not passing the --always option.
2. rename the --always option to --allow-empty.
----------------------------------------------------------------------------
Changes since v2:
1. rename the --allow-empty option to --empty-commit.
2. introduce three different strategies (die|skip|asis) when trying to
record empty patches as empty commits.
----------------------------------------------------------------------------
Changes since v3:
1. generate the missed file for test cases.
2. grep -f cannot be used under Mac OS.
----------------------------------------------------------------------------
Changes since v4:
1. rename the --empty-commit option to --empty.
2. rename three different strategies (die|skip|asis) to die, drop and keep
correspondingly.
----------------------------------------------------------------------------
Changes since v5:
1. throw an error when passing --empty option without value.
----------------------------------------------------------------------------
Changes since v6:
1. add i18n resources.
----------------------------------------------------------------------------
Changes since v7:
1. update code according to the seen branch.
2. fix the wrong document of git-am.
3. sign off commits by a real name.
----------------------------------------------------------------------------
Changes since v8:
1. update the committer's name with my real name to fix DCO of GGG.
----------------------------------------------------------------------------
Changes since v9:
1. imitate the signed name format of
https://lore.kernel.org/git/pull.1143.git.git.1637347813367.gitgitgadget@gmail.com
.
----------------------------------------------------------------------------
Changes since v11:
1. introduce an interactive option --allow-empty for git-am to record empty
patches in the middle of an am session.
----------------------------------------------------------------------------
Changes since v12:
1. record the empty patch as an empty commit only when there are no
changes.
2. fix indentation problems.
3. simplify "to keep recording" to "to record".
4. add a test case for skipping empty patches via the --skip option.
----------------------------------------------------------------------------
Changes since v13:
1. add an additional description about the 'die' value.
----------------------------------------------------------------------------
Changes since v14:
1. reimplement the 'die' value and stop the whole session. (Expected a
reroll)
2. the --allow-empty option is a valid resume value only when: (Expected a
reroll)
* index has not changed
* lacking a patch
----------------------------------------------------------------------------
Changes since v15:
1. rename "die" to "stop".
----------------------------------------------------------------------------
Changes since v16:
1. fix the typo from "had" to "has" in the comment.
----------------------------------------------------------------------------
Changes since v17:
1. add trailing comma, show tips of creating an empty commit, and use "%B"
to construct test cases.
2. remove the error "Invalid resume value.".
3. hint "--allow-empty" after "--skip".
----------------------------------------------------------------------------
Changes since v18:
1. remove strict checking of "--allow-empty".
徐沛文 (Aleen) (3):
doc: git-format-patch: describe the option --always
am: support --empty=<option> to handle empty patches
am: support --allow-empty to record specific empty patches
Documentation/git-am.txt | 16 ++++-
Documentation/git-format-patch.txt | 6 +-
builtin/am.c | 89 ++++++++++++++++++++----
t/t4150-am.sh | 107 +++++++++++++++++++++++++++++
t/t7512-status-help.sh | 1 +
wt-status.c | 8 ++-
6 files changed, 211 insertions(+), 16 deletions(-)
base-commit: abe6bb3905392d5eb6b01fa6e54d7e784e0522aa
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-1076%2Faleen42%2Fnext-v19
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-1076/aleen42/next-v19
Pull-Request: https://github.com/gitgitgadget/git/pull/1076
Range-diff vs v18:
1: a524ca6adfa = 1: a524ca6adfa doc: git-format-patch: describe the option --always
2: 56953d416d9 = 2: 56953d416d9 am: support --empty=<option> to handle empty patches
3: 4c3077f9384 ! 3: 37875e8d313 am: support --allow-empty to record specific empty patches
@@ Commit message
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
+ 1. the index has not changed
2. lacking a branch
+ When the index has changed, "--allow-empty" will create a non-empty
+ commit like passing "--continue" or "--resolved".
+
Signed-off-by: 徐沛文 (Aleen) [off-list ref]
## Documentation/git-am.txt ##
@@ builtin/am.c: next:
-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)) {
+ 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) {
+- die_user_resolve(state);
++ if (allow_empty && is_empty_or_missing_file(am_path(state, "patch"))) {
+ printf_ln(_("No changes - recorded it as an empty commit."));
+ } else {
+ printf_ln(_("No changes - did you forget to use 'git add'?\n"
@@ t/t4150-am.sh: test_expect_success 'record as an empty commit when meeting e-mai
+ grep -f actual expected
+'
+
-+test_expect_success 'cannot create empty commits when the index is changed' '
++test_expect_success 'create an non-empty commit when the index IS changed though "--allow-empty" is given' '
+ 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
++ git am --allow-empty &&
++ git show empty-commit --format="%B" >expected &&
++ git show HEAD --format="%B" >actual &&
++ grep -f actual expected &&
++ git diff HEAD^..HEAD --name-only
+'
+
+test_expect_success 'cannot create empty commits when there is a clean index due to merge conflicts' '
--
gitgitgadget
From: 徐沛文 (Aleen) via GitGitGadget <hidden> Date: 2021-12-09 07:26:02
From: =?UTF-8?q?=E5=BE=90=E6=B2=9B=E6=96=87=20=28Aleen=29?=
[off-list ref]
This commit has described how to use '--always' option in the command
'git-format-patch' to include patches for commits that emit no changes.
Signed-off-by: 徐沛文 (Aleen) <redacted>
---
Documentation/git-format-patch.txt | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
@@ -192,6 +192,10 @@ will want to ensure that threading is disabled for `git send-email`. patches being generated, and any patch that matches is ignored.+--always::+ Include patches for commits that do not introduce any change,+ which are omitted by default.+ --cover-from-description=<mode>:: Controls which parts of the cover letter will be automatically populated using the branch's description.
From: 徐沛文 (Aleen) via GitGitGadget <hidden> Date: 2021-12-09 07:26:03
From: =?UTF-8?q?=E5=BE=90=E6=B2=9B=E6=96=87=20=28Aleen=29?=
[off-list ref]
Since that the command 'git-format-patch' can include patches of
commits that emit no changes, the 'git-am' command should also
support an option, named as '--empty', to specify how to handle
those empty patches. In this commit, we have implemented three
valid options ('stop', 'drop' and 'keep').
Signed-off-by: 徐沛文 (Aleen) <redacted>
---
Documentation/git-am.txt | 9 +++++++
builtin/am.c | 57 ++++++++++++++++++++++++++++++++++++----
t/t4150-am.sh | 50 +++++++++++++++++++++++++++++++++++
3 files changed, 111 insertions(+), 5 deletions(-)
@@ -63,6 +64,14 @@ OPTIONS --quoted-cr=<action>:: This flag will be passed down to 'git mailinfo' (see linkgit:git-mailinfo[1]).+--empty=(stop|drop|keep)::+ By default, or when the option is set to 'stop', the command+ errors out on an input e-mail message lacking a patch+ and stops into the middle of the current am session. When this+ option is set to 'drop', skip such an e-mail message instead.+ When this option is set to 'keep', create an empty commit,+ recording the contents of the e-mail message as its log.+ -m:: --message-id:: Pass the `-m` flag to 'git mailinfo' (see linkgit:git-mailinfo[1]),
@@ -87,6 +87,12 @@ enum show_patch_type {SHOW_PATCH_DIFF=1,};+enumempty_action{+STOP_ON_EMPTY_COMMIT=0,/* output errors and stop in the middle of an am session */+DROP_EMPTY_COMMIT,/* skip with a notice message, unless "--quiet" has been passed */+KEEP_EMPTY_COMMIT,/* keep recording as empty commits */+};+structam_state{/* state directory path */char*dir;
@@ -178,6 +185,25 @@ static int am_option_parse_quoted_cr(const struct option *opt,return0;}+staticintam_option_parse_empty(conststructoption*opt,+constchar*arg,intunset)+{+int*opt_value=opt->value;++BUG_ON_OPT_NEG(unset);++if(!strcmp(arg,"stop"))+*opt_value=STOP_ON_EMPTY_COMMIT;+elseif(!strcmp(arg,"drop"))+*opt_value=DROP_EMPTY_COMMIT;+elseif(!strcmp(arg,"keep"))+*opt_value=KEEP_EMPTY_COMMIT;+else+returnerror(_("Invalid value for --empty: %s"),arg);++return0;+}+/***Returnspathrelativetotheam_statedirectory.*/
@@ -1248,11 +1274,6 @@ static int parse_mail(struct am_state *state, const char *mail)gotofinish;}-if(is_empty_or_missing_file(am_path(state,"patch"))){-printf_ln(_("Patch is empty."));-die_user_resolve(state);-}-strbuf_addstr(&msg,"\n\n");strbuf_addbuf(&msg,&mi.log_message);strbuf_stripspace(&msg,0);
@@ -1152,4 +1158,48 @@ test_expect_success 'apply binary blob in partial clone' 'git-Cclientam../patch'+test_expect_success'an empty input file is error regardless of --empty option''+test_when_finished"git am --abort || :"&&+test_must_failgitam--empty=dropempty.patch2>actual&&+echo"Patch format detection failed.">expected&&+test_cmpexpectedactual+'++test_expect_success'invalid when passing the --empty option alone''+test_when_finished"git am --abort || :"&&+gitcheckoutempty-commit^&&+test_must_failgitam--emptyempty-commit.patch2>err&&+echo"error: Invalid value for --empty: empty-commit.patch">expected&&+test_cmpexpectederr+'++test_expect_success'a message without a patch is an error (default)''+test_when_finished"git am --abort || :"&&+test_must_failgitamempty-commit.patch>err&&+grep"Patch is empty"err+'++test_expect_success'a message without a patch is an error where an explicit "--empty=stop" is given''+test_when_finished"git am --abort || :"&&+test_must_failgitam--empty=stopempty-commit.patch>err&&+grep"Patch is empty."err+'++test_expect_success'a message without a patch will be skipped when "--empty=drop" is given''+gitam--empty=dropempty-commit.patch>output&&+gitrev-parseempty-commit^>expected&&+gitrev-parseHEAD>actual&&+test_cmpexpectedactual&&+grep"Skipping: empty commit"output+'++test_expect_success'record as an empty commit when meeting e-mail message that lacks a patch''+gitam--empty=keepempty-commit.patch>output&&+test_path_is_missing.git/rebase-apply&&+gitshowempty-commit--format="%B">expected&&+gitshowHEAD--format="%B">actual&&+grep-factualexpected&&+grep"Creating an empty commit: empty commit"output+'+ test_done
From: 徐沛文 (Aleen) via GitGitGadget <hidden> Date: 2021-12-09 07:26:05
From: =?UTF-8?q?=E5=BE=90=E6=B2=9B=E6=96=87=20=28Aleen=29?=
[off-list ref]
This option helps to record specific empty patches in the middle
of an am session, which does create empty commits only when:
1. the index has not changed
2. lacking a branch
When the index has changed, "--allow-empty" will create a non-empty
commit like passing "--continue" or "--resolved".
Signed-off-by: 徐沛文 (Aleen) <redacted>
---
Documentation/git-am.txt | 7 ++++-
builtin/am.c | 32 ++++++++++++++++------
t/t4150-am.sh | 57 ++++++++++++++++++++++++++++++++++++++++
t/t7512-status-help.sh | 1 +
wt-status.c | 8 +++++-
5 files changed, 95 insertions(+), 10 deletions(-)
@@ -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 ----------
@@ -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,24 @@ next:/***Resumethecurrentamsessionafterpatchapplicationfailure.Theuserdid*allthehardwork,andwedonothavetodoanypatchapplication.Just-*trustandcommitwhattheuserhasintheindexandworkingtree.+*trustandcommitwhattheuserhasintheindexandworkingtree.If`allow_empty`+*istrue,commitasanemptycommitwhenindexhasnotchangedandlackingapatch.*/-staticvoidam_resolve(structam_state*state)+staticvoidam_resolve(structam_state*state,intallow_empty){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."));-die_user_resolve(state);+if(allow_empty&&is_empty_or_missing_file(am_path(state,"patch"))){+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()){
@@ -2392,6 +2404,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")),
@@ -1202,4 +1202,61 @@ test_expect_success 'record as an empty commit when meeting e-mail message thatgrep"Creating an empty commit: empty commit"output'+test_expect_success'skip an empty patch in the middle of an am session''+gitcheckoutempty-commit^&&+test_must_failgitamempty-commit.patch>err&&+grep"Patch is empty."err&&+grep"To record the empty patch as an empty commit, run \"git am --allow-empty\"."err&&+gitam--skip&&+test_path_is_missing.git/rebase-apply&&+gitrev-parseempty-commit^>expected&&+gitrev-parseHEAD>actual&&+test_cmpexpectedactual+'++test_expect_success'record an empty patch as an empty commit in the middle of an am session''+gitcheckoutempty-commit^&&+test_must_failgitamempty-commit.patch>err&&+grep"Patch is empty."err&&+grep"To record the empty patch as an empty commit, run \"git am --allow-empty\"."err&&+gitam--allow-empty>output&&+grep"No changes - recorded it as an empty commit."output&&+test_path_is_missing.git/rebase-apply&&+gitshowempty-commit--format="%B">expected&&+gitshowHEAD--format="%B">actual&&+grep-factualexpected+'++test_expect_success'create an non-empty commit when the index IS changed though "--allow-empty" is given''+gitcheckoutempty-commit^&&+test_must_failgitamempty-commit.patch>err&&+:>empty-file&&+gitaddempty-file&&+gitam--allow-empty&&+gitshowempty-commit--format="%B">expected&&+gitshowHEAD--format="%B">actual&&+grep-factualexpected&&+gitdiffHEAD^..HEAD--name-only+'++test_expect_success'cannot create empty commits when there is a clean index due to merge conflicts''+test_when_finished"git am --abort || :"&&+gitrev-parseHEAD>expected&&+test_must_failgitamseq.patch&&+test_must_failgitam--allow-empty>err&&+!grep"To record the empty patch as an empty commit, run \"git am --allow-empty\"."err&&+gitrev-parseHEAD>actual&&+test_cmpactualexpected+'++test_expect_success'cannot create empty commits when there is unmerged index due to merge conflicts''+test_when_finished"git am --abort || :"&&+gitrev-parseHEAD>expected&&+test_must_failgitam-3seq.patch&&+test_must_failgitam--allow-empty>err&&+!grep"To record the empty patch as an empty commit, run \"git am --allow-empty\"."err&&+gitrev-parseHEAD>actual&&+test_cmpactualexpected+'+ test_done
@@ -659,6 +659,7 @@ On branch am_empty Youareinthemiddleofanamsession. Thecurrentpatchisempty.(use"git am --skip"toskipthispatch)+(use"git am --allow-empty"torecordthispatchasanemptycommit)(use"git am --abort"torestoretheoriginalbranch) nothingtocommit(use-utoshowuntrackedfiles)
@@ -1218,17 +1218,23 @@ static void show_merge_in_progress(struct wt_status *s,staticvoidshow_am_in_progress(structwt_status*s,constchar*color){+intam_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)"));}
@@ -193,8 +193,8 @@ will want to ensure that threading is disabled for `git send-email`. ignored. --always::- Include patches for commits that do not introduce any change,- which are omitted by default.+ Always generate patches, even if there are empty-change commits.+ Default is to omit such commits. --cover-from-description=<mode>:: Controls which parts of the cover letter will be automatically
--
An old man doll... just what I always wanted! - Clara
@@ -193,8 +193,8 @@ will want to ensure that threading is disabled for `git send-email`. ignored. --always::- Include patches for commits that do not introduce any change,- which are omitted by default.+ Always generate patches, even if there are empty-change commits.+ Default is to omit such commits. --cover-from-description=<mode>:: Controls which parts of the cover letter will be automatically
--
An old man doll... just what I always wanted! - Clara
Dears Sanjaya,
Thanks for your suggestion. I don't see the actual difference between
the two sentences, and do you want to enhance the word "always"?
If you do, how about just describing the option as "Always include patches..."?
Aleen
Dears Sanjaya,
Thanks for your suggestion. I don't see the actual difference between
the two sentences, and do you want to enhance the word "always"?
If you do, how about just describing the option as "Always include patches..."?
Aleen
Semantically speaking, I choose "generate" because git format-patch **generates**
patches from the specified commits.
--
An old man doll... just what I always wanted! - Clara
From: Junio C Hamano <hidden> Date: 2021-12-11 09:22:45
Bagas Sanjaya [off-list ref] writes:
On 10/12/21 08.26, Aleen 徐沛文 wrote:
quoted
Dears Sanjaya,
Thanks for your suggestion. I don't see the actual difference
between
the two sentences, and do you want to enhance the word "always"?
If you do, how about just describing the option as "Always include patches..."?
Aleen
Semantically speaking, I choose "generate" because git format-patch **generates**
patches from the specified commits.
But the given commit is empty and does not result in a patch at
all, which is the whole point of having this option, no? A typical
format-patch output message consists of the message part and the
patch part, and calling an output created for an empty commit a
"patch" leads to confusion, I am afraid.
So, between the two sentences, I do not see much difference either
way.