{"thread":{"id":"55356","subject":"[PATCH 0/2] [GSOC] interpret-trailer: easy parse trailer value","startedAt":"2021-03-20T14:42:47Z","lastAt":"2021-03-23T05:05:10Z","messageCount":23,"participants":["ZheNing Hu via GitGitGadget","Junio C Hamano","ZheNing Hu","Bagas Sanjaya","Christian Couder"],"isPatch":true,"patchVersion":1,"patchTotal":2},"messages":[{"id":"419772","messageId":"pull.911.git.1616251299.gitgitgadget@gmail.com","threadId":"55356","inReplyTo":null,"subject":"[PATCH 0/2] [GSOC] interpret-trailer: easy parse trailer value","fromName":"ZheNing Hu via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2021-03-20T14:41:36Z","receivedAt":"2021-03-20T14:42:47Z","isPatch":true,"sender":{"key":"adlternative@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58138461?v=4"},"body":"Hope this can help commit --trailer more useful!\n\nBase on https://github.com/gitgitgadget/git/pull/901, The original patch\nseries was too long so now split it into two.\n\nHelped by Junio and Jeff, Thanks.\n\nZheNing Hu (2):\n  [GSOC] commit: add --trailer option\n  [GSOC] interpret-trailer: easy parse trailer value\n\n Documentation/git-commit.txt             |  14 +-\n Documentation/git-interpret-trailers.txt |  23 ++\n builtin/commit.c                         |  55 ++--\n commit.c                                 |  34 +++\n commit.h                                 |   2 +\n t/t7502-commit-porcelain.sh              | 319 +++++++++++++++++++++++\n t/t7513-interpret-trailers.sh            |  23 ++\n trailer.c                                |  13 +-\n 8 files changed, 448 insertions(+), 35 deletions(-)\n\n\nbase-commit: 13d7ab6b5d7929825b626f050b62a11241ea4945\nPublished-As: https://github.com/gitgitgadget/git/releases/tag/pr-911%2Fadlternative%2Ftrailer-easy-ident-v1\nFetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-911/adlternative/trailer-easy-ident-v1\nPull-Request: https://github.com/gitgitgadget/git/pull/911\n-- \ngitgitgadget\n"},{"id":"419773","messageId":"2378e3b4c1ae2a38b6cf7d11eea16c5d3c55da74.1616251299.git.gitgitgadget@gmail.com","threadId":"55356","inReplyTo":"pull.911.git.1616251299.gitgitgadget@gmail.com","subject":"[PATCH 1/2] [GSOC] commit: add --trailer option","fromName":"ZheNing Hu via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2021-03-20T14:41:37Z","receivedAt":"2021-03-20T14:42:47Z","isPatch":true,"sender":{"key":"adlternative@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58138461?v=4"},"body":"From: ZheNing Hu <adlternative@gmail.com>\n\nHistorically, Git has supported the 'Signed-off-by' commit trailer\nusing the '--signoff' and the '-s' option from the command line.\nBut users may need to provide other trailer information from the\ncommand line such as \"Helped-by\", \"Reported-by\", \"Mentored-by\",\n\nNow implement a new `--trailer <token>[(=|:)<value>]` option to pass\nother trailers to `interpret-trailers` and insert them into commit\nmessages.\n\nSigned-off-by: ZheNing Hu <adlternative@gmail.com>\n---\n Documentation/git-commit.txt |  14 +-\n builtin/commit.c             |  22 +++\n t/t7502-commit-porcelain.sh  | 291 +++++++++++++++++++++++++++++++++++\n 3 files changed, 326 insertions(+), 1 deletion(-)\n\ndiff --git a/Documentation/git-commit.txt b/Documentation/git-commit.txt\nindex 17150fa7eabe..3fe7ef33cb07 100644\n--- a/Documentation/git-commit.txt\n+++ b/Documentation/git-commit.txt\n@@ -14,7 +14,8 @@ SYNOPSIS\n \t   [--allow-empty-message] [--no-verify] [-e] [--author=<author>]\n \t   [--date=<date>] [--cleanup=<mode>] [--[no-]status]\n \t   [-i | -o] [--pathspec-from-file=<file> [--pathspec-file-nul]]\n-\t   [-S[<keyid>]] [--] [<pathspec>...]\n+\t   [(--trailer <token>[(=|:)<value>])...] [-S[<keyid>]]\n+\t   [--] [<pathspec>...]\n \n DESCRIPTION\n -----------\n@@ -166,6 +167,17 @@ The `-m` option is mutually exclusive with `-c`, `-C`, and `-F`.\n \n include::signoff-option.txt[]\n \n+--trailer <token>[(=|:)<value>]::\n+\tSpecify a (<token>, <value>) pair that should be applied as a\n+\ttrailer. (e.g. `git commit --trailer \"Signed-off-by:C O Mitter \\\n+\t<committer@example.com>\" --trailer \"Helped-by:C O Mitter \\\n+\t<committer@example.com>\"` will add the \"Signed-off-by\" trailer\n+\tand the \"Helped-by\" trailer to the commit message.)\n+\tThe `trailer.*` configuration variables\n+\t(linkgit:git-interpret-trailers[1]) can be used to define if\n+\ta duplicated trailer is omitted, where in the run of trailers\n+\teach trailer would appear, and other details.\n+\n -n::\n --no-verify::\n \tThis option bypasses the pre-commit and commit-msg hooks.\ndiff --git a/builtin/commit.c b/builtin/commit.c\nindex 739110c5a7f6..4b06672bd07d 100644\n--- a/builtin/commit.c\n+++ b/builtin/commit.c\n@@ -113,6 +113,7 @@ static int config_commit_verbose = -1; /* unspecified */\n static int no_post_rewrite, allow_empty_message, pathspec_file_nul;\n static char *untracked_files_arg, *force_date, *ignore_submodule_arg, *ignored_arg;\n static char *sign_commit, *pathspec_from_file;\n+static struct strvec trailer_args = STRVEC_INIT;\n \n /*\n  * The default commit message cleanup mode will remove the lines\n@@ -131,6 +132,14 @@ static struct strbuf message = STRBUF_INIT;\n \n static enum wt_status_format status_format = STATUS_FORMAT_UNSPECIFIED;\n \n+static int opt_pass_trailer(const struct option *opt, const char *arg, int unset)\n+{\n+\tBUG_ON_OPT_NEG(unset);\n+\n+\tstrvec_pushl(&trailer_args, \"--trailer\", arg, NULL);\n+\treturn 0;\n+}\n+\n static int opt_parse_porcelain(const struct option *opt, const char *arg, int unset)\n {\n \tenum wt_status_format *value = (enum wt_status_format *)opt->value;\n@@ -958,6 +967,18 @@ static int prepare_to_commit(const char *index_file, const char *prefix,\n \n \tfclose(s->fp);\n \n+\tif (trailer_args.nr) {\n+\t\tstruct child_process run_trailer = CHILD_PROCESS_INIT;\n+\n+\t\tstrvec_pushl(&run_trailer.args, \"interpret-trailers\",\n+\t\t\t     \"--in-place\", git_path_commit_editmsg(), NULL);\n+\t\tstrvec_pushv(&run_trailer.args, trailer_args.v);\n+\t\trun_trailer.git_cmd = 1;\n+\t\tif (run_command(&run_trailer))\n+\t\t\tdie(_(\"unable to pass trailers to --trailers\"));\n+\t\tstrvec_clear(&trailer_args);\n+\t}\n+\n \t/*\n \t * Reject an attempt to record a non-merge empty commit without\n \t * explicit --allow-empty. In the cherry-pick case, it may be\n@@ -1507,6 +1528,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)\n \t\tOPT_STRING(0, \"fixup\", &fixup_message, N_(\"commit\"), N_(\"use autosquash formatted message to fixup specified commit\")),\n \t\tOPT_STRING(0, \"squash\", &squash_message, N_(\"commit\"), N_(\"use autosquash formatted message to squash specified commit\")),\n \t\tOPT_BOOL(0, \"reset-author\", &renew_authorship, N_(\"the commit is authored by me now (used with -C/-c/--amend)\")),\n+\t\tOPT_CALLBACK_F(0, \"trailer\", NULL, N_(\"trailer\"), N_(\"add custom trailer(s)\"), PARSE_OPT_NONEG, opt_pass_trailer),\n \t\tOPT_BOOL('s', \"signoff\", &signoff, N_(\"add a Signed-off-by trailer\")),\n \t\tOPT_FILENAME('t', \"template\", &template_file, N_(\"use specified template file\")),\n \t\tOPT_BOOL('e', \"edit\", &edit_flag, N_(\"force edit of commit\")),\ndiff --git a/t/t7502-commit-porcelain.sh b/t/t7502-commit-porcelain.sh\nindex 6396897cc818..74b1602c0ce6 100755\n--- a/t/t7502-commit-porcelain.sh\n+++ b/t/t7502-commit-porcelain.sh\n@@ -38,6 +38,16 @@ check_summary_oneline() {\n \ttest_cmp exp act\n }\n \n+trailer_commit_base () {\n+\techo \"fun\" >>file &&\n+\tgit add file &&\n+\tgit commit -s --trailer \"Signed-off-by=C1 E1 \" \\\n+\t\t--trailer \"Helped-by:C2 E2 \" \\\n+\t\t--trailer \"Reported-by=C3 E3\" \\\n+\t\t--trailer \"Mentored-by:C4 E4\" \\\n+\t\t-m \"hello\"\n+}\n+\n test_expect_success 'output summary format' '\n \n \techo new >file1 &&\n@@ -154,6 +164,287 @@ test_expect_success 'sign off' '\n \n '\n \n+test_expect_success 'commit --trailer with \"=\"' '\n+\ttrailer_commit_base &&\n+\tcat >expected <<-\\EOF &&\n+\thello\n+\n+\tSigned-off-by: C O Mitter <committer@example.com>\n+\tSigned-off-by: C1 E1\n+\tHelped-by: C2 E2\n+\tReported-by: C3 E3\n+\tMentored-by: C4 E4\n+\tEOF\n+\tgit cat-file commit HEAD >commit.msg &&\n+\tsed -e \"1,/^\\$/d\" commit.msg >actual &&\n+\ttest_cmp expected actual\n+'\n+\n+test_expect_success 'commit --trailer with -c and \"replace\" as ifexists' '\n+\ttrailer_commit_base &&\n+\tcat >expected <<-\\EOF &&\n+\thello\n+\n+\tSigned-off-by: C O Mitter <committer@example.com>\n+\tSigned-off-by: C1 E1\n+\tReported-by: C3 E3\n+\tMentored-by: C4 E4\n+\tHelped-by: C3 E3\n+\tEOF\n+\tgit -c trailer.ifexists=\"replace\" \\\n+\t\tcommit --trailer \"Mentored-by: C4 E4\" \\\n+\t\t --trailer \"Helped-by: C3 E3\" \\\n+\t\t--amend &&\n+\tgit cat-file commit HEAD >commit.msg &&\n+\tsed -e \"1,/^\\$/d\"  commit.msg >actual &&\n+\ttest_cmp expected actual\n+'\n+\n+test_expect_success 'commit --trailer with -c and \"add\" as ifexists' '\n+\ttrailer_commit_base &&\n+\tcat >expected <<-\\EOF &&\n+\thello\n+\n+\tSigned-off-by: C O Mitter <committer@example.com>\n+\tSigned-off-by: C1 E1\n+\tHelped-by: C2 E2\n+\tReported-by: C3 E3\n+\tMentored-by: C4 E4\n+\tReported-by: C3 E3\n+\tMentored-by: C4 E4\n+\tEOF\n+\tgit -c trailer.ifexists=\"add\" \\\n+\t\tcommit --trailer \"Reported-by: C3 E3\" \\\n+\t\t--trailer \"Mentored-by: C4 E4\" \\\n+\t\t--amend &&\n+\tgit cat-file commit HEAD >commit.msg &&\n+\tsed -e \"1,/^\\$/d\"  commit.msg >actual &&\n+\ttest_cmp expected actual\n+'\n+\n+test_expect_success 'commit --trailer with -c and \"donothing\" as ifexists' '\n+\ttrailer_commit_base &&\n+\tcat >expected <<-\\EOF &&\n+\thello\n+\n+\tSigned-off-by: C O Mitter <committer@example.com>\n+\tSigned-off-by: C1 E1\n+\tHelped-by: C2 E2\n+\tReported-by: C3 E3\n+\tMentored-by: C4 E4\n+\tReviewed-by: C6 E6\n+\tEOF\n+\tgit -c trailer.ifexists=\"donothing\" \\\n+\t\tcommit --trailer \"Mentored-by: C5 E5\" \\\n+\t\t--trailer \"Reviewed-by: C6 E6\" \\\n+\t\t--amend &&\n+\tgit cat-file commit HEAD >commit.msg &&\n+\tsed -e \"1,/^\\$/d\"  commit.msg >actual &&\n+\ttest_cmp expected actual\n+'\n+\n+test_expect_success 'commit --trailer with -c and \"addIfDifferent\" as ifexists' '\n+\ttrailer_commit_base &&\n+\tcat >expected <<-\\EOF &&\n+\thello\n+\n+\tSigned-off-by: C O Mitter <committer@example.com>\n+\tSigned-off-by: C1 E1\n+\tHelped-by: C2 E2\n+\tReported-by: C3 E3\n+\tMentored-by: C4 E4\n+\tMentored-by: C5 E5\n+\tEOF\n+\tgit -c trailer.ifexists=\"addIfDifferent\" \\\n+\t\tcommit --trailer \"Reported-by: C3 E3\" \\\n+\t\t--trailer \"Mentored-by: C5 E5\" \\\n+\t\t--amend &&\n+\tgit cat-file commit HEAD >commit.msg &&\n+\tsed -e \"1,/^\\$/d\"  commit.msg >actual &&\n+\ttest_cmp expected actual\n+'\n+\n+test_expect_success 'commit --trailer with -c and \"addIfDifferentNeighbor\" as ifexists' '\n+\ttrailer_commit_base &&\n+\tcat >expected <<-\\EOF &&\n+\thello\n+\n+\tSigned-off-by: C O Mitter <committer@example.com>\n+\tSigned-off-by: C1 E1\n+\tHelped-by: C2 E2\n+\tReported-by: C3 E3\n+\tMentored-by: C4 E4\n+\tReported-by: C3 E3\n+\tEOF\n+\tgit -c trailer.ifexists=\"addIfDifferentNeighbor\" \\\n+\t\tcommit --trailer \"Mentored-by: C4 E4\" \\\n+\t\t--trailer \"Reported-by: C3 E3\" \\\n+\t\t--amend &&\n+\tgit cat-file commit HEAD >commit.msg &&\n+\tsed -e \"1,/^\\$/d\"  commit.msg >actual &&\n+\ttest_cmp expected actual\n+'\n+\n+test_expect_success 'commit --trailer with -c and \"end\" as where' '\n+\ttrailer_commit_base &&\n+\tcat >expected <<-\\EOF &&\n+\thello\n+\n+\tSigned-off-by: C O Mitter <committer@example.com>\n+\tSigned-off-by: C1 E1\n+\tHelped-by: C2 E2\n+\tReported-by: C3 E3\n+\tMentored-by: C4 E4\n+\tReported-by: C3 E3\n+\tMentored-by: C4 E4\n+\tEOF\n+\tgit -c trailer.where=\"end\" \\\n+\t\tcommit --trailer \"Reported-by: C3 E3\" \\\n+\t\t--trailer \"Mentored-by: C4 E4\" \\\n+\t\t--amend &&\n+\tgit cat-file commit HEAD >commit.msg &&\n+\tsed -e \"1,/^\\$/d\" commit.msg >actual &&\n+\ttest_cmp expected actual\n+'\n+\n+test_expect_success 'commit --trailer with -c and \"start\" as where' '\n+\ttrailer_commit_base &&\n+\tcat >expected <<-\\EOF &&\n+\thello\n+\n+\tSigned-off-by: C1 E1\n+\tSigned-off-by: C O Mitter <committer@example.com>\n+\tSigned-off-by: C1 E1\n+\tHelped-by: C2 E2\n+\tReported-by: C3 E3\n+\tMentored-by: C4 E4\n+\tEOF\n+\tgit -c trailer.where=\"start\" \\\n+\t\tcommit --trailer \"Signed-off-by: C O Mitter <committer@example.com>\" \\\n+\t\t--trailer \"Signed-off-by: C1 E1\" \\\n+\t\t--amend &&\n+\tgit cat-file commit HEAD >commit.msg &&\n+\tsed -e \"1,/^\\$/d\" commit.msg >actual &&\n+\ttest_cmp expected actual\n+'\n+\n+test_expect_success 'commit --trailer with -c and \"after\" as where' '\n+\ttrailer_commit_base &&\n+\tcat >expected <<-\\EOF &&\n+\thello\n+\n+\tSigned-off-by: C O Mitter <committer@example.com>\n+\tSigned-off-by: C1 E1\n+\tHelped-by: C2 E2\n+\tReported-by: C3 E3\n+\tMentored-by: C4 E4\n+\tMentored-by: C5 E5\n+\tEOF\n+\tgit -c trailer.where=\"after\" \\\n+\t\tcommit --trailer \"Mentored-by: C4 E4\" \\\n+\t\t--trailer \"Mentored-by: C5 E5\" \\\n+\t\t--amend &&\n+\tgit cat-file commit HEAD >commit.msg &&\n+\tsed -e \"1,/^\\$/d\" commit.msg >actual &&\n+\ttest_cmp expected actual\n+'\n+\n+test_expect_success 'commit --trailer with -c and \"before\" as where' '\n+\ttrailer_commit_base &&\n+\tcat >expected <<-\\EOF &&\n+\thello\n+\n+\tSigned-off-by: C O Mitter <committer@example.com>\n+\tSigned-off-by: C1 E1\n+\tHelped-by: C2 E2\n+\tReported-by: C3 E3\n+\tMentored-by: C2 E2\n+\tMentored-by: C3 E3\n+\tMentored-by: C4 E4\n+\tEOF\n+\tgit -c trailer.where=\"before\" \\\n+\t\tcommit --trailer \"Mentored-by: C3 E3\" \\\n+\t\t--trailer \"Mentored-by: C2 E2\" \\\n+\t\t--amend &&\n+\tgit cat-file commit HEAD >commit.msg &&\n+\tsed -e \"1,/^\\$/d\" commit.msg >actual &&\n+\ttest_cmp expected actual\n+'\n+\n+test_expect_success 'commit --trailer with -c and \"donothing\" as ifmissing' '\n+\ttrailer_commit_base &&\n+\tcat >expected <<-\\EOF &&\n+\thello\n+\n+\tSigned-off-by: C O Mitter <committer@example.com>\n+\tSigned-off-by: C1 E1\n+\tHelped-by: C2 E2\n+\tReported-by: C3 E3\n+\tMentored-by: C4 E4\n+\tHelped-by: C5 E5\n+\tEOF\n+\tgit -c trailer.ifmissing=\"donothing\" \\\n+\t\tcommit --trailer \"Helped-by: C5 E5\" \\\n+\t\t--trailer \"Based-by: C6 E6\" \\\n+\t\t--amend &&\n+\tgit cat-file commit HEAD >commit.msg &&\n+\tsed -e \"1,/^\\$/d\" commit.msg >actual &&\n+\ttest_cmp expected actual\n+'\n+\n+test_expect_success 'commit --trailer with -c and \"add\" as ifmissing' '\n+\ttrailer_commit_base &&\n+\tcat >expected <<-\\EOF &&\n+\thello\n+\n+\tSigned-off-by: C O Mitter <committer@example.com>\n+\tSigned-off-by: C1 E1\n+\tHelped-by: C2 E2\n+\tReported-by: C3 E3\n+\tMentored-by: C4 E4\n+\tHelped-by: C5 E5\n+\tBased-by: C6 E6\n+\tEOF\n+\tgit -c trailer.ifmissing=\"add\" \\\n+\t\tcommit --trailer \"Helped-by: C5 E5\" \\\n+\t\t--trailer \"Based-by: C6 E6\" \\\n+\t\t--amend &&\n+\tgit cat-file commit HEAD >commit.msg &&\n+\tsed -e \"1,/^\\$/d\" commit.msg >actual &&\n+\ttest_cmp expected actual\n+'\n+\n+test_expect_success 'commit --trailer with -c ack.key ' '\n+\techo \"fun\" >>file1 &&\n+\tgit add file1 &&\n+\tcat >expected <<-\\EOF &&\n+\t\thello\n+\n+\t\tAcked-by: Peff\n+\tEOF\n+\tgit -c trailer.ack.key=\"Acked-by\" \\\n+\t\tcommit --trailer \"ack = Peff\" -m \"hello\" &&\n+\tgit cat-file commit HEAD >commit.msg &&\n+\tsed -e \"1,/^\\$/d\" commit.msg >actual &&\n+\ttest_cmp expected actual\n+'\n+\n+test_expect_success 'commit --trailer with -c and \":=#\" as separators' '\n+\techo \"fun\" >>file1 &&\n+\tgit add file1 &&\n+\tcat >expected <<-\\EOF &&\n+\t\tI hate bug\n+\n+\t\tBug #42\n+\tEOF\n+\tgit -c trailer.separators=\":=#\" \\\n+\t\t-c trailer.bug.key=\"Bug #\" \\\n+\t\tcommit --trailer \"bug = 42\" -m \"I hate bug\" &&\n+\tgit cat-file commit HEAD >commit.msg &&\n+\tsed -e \"1,/^\\$/d\" commit.msg >actual &&\n+\ttest_cmp expected actual\n+'\n+\n test_expect_success 'multiple -m' '\n \n \t>negative &&\n-- \ngitgitgadget\n\n"},{"id":"419774","messageId":"ca521d3c01d652e09e716fb447b0b26da1a014e8.1616251299.git.gitgitgadget@gmail.com","threadId":"55356","inReplyTo":"pull.911.git.1616251299.gitgitgadget@gmail.com","subject":"[PATCH 2/2] [GSOC] interpret-trailer: easy parse trailer value","fromName":"ZheNing Hu via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2021-03-20T14:41:38Z","receivedAt":"2021-03-20T14:42:47Z","isPatch":true,"sender":{"key":"adlternative@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58138461?v=4"},"body":"From: ZheNing Hu <adlternative@gmail.com>\n\nThe original `-trailer` adding some trailers like\n\"Signed-off-by:C O <Mister@email.com>\" is often too\nverbose and error-prone.\n\nNow add the syntax parse for the value of `--trailer`:\ne.g. \"Signed-off-by:@Junio\", git will fuzzy search in the\ncommit history to find the latest one commit which matches\n`--author=Junio`, and get the \"author <email>\" pair\n`Junio C Hamano <gitster@pobox.com>` as the value of\n`--trailer`, it will be a easy way to add trailers.\ngit commit --trailer` can also benefit from this.\n\nSigned-off-by: ZheNing Hu <adlternative@gmail.com>\nHelped-by: Junio C Hamano <gitster@pobox.com>\nHelped-by: Jeff King <peff@peff.net>\n---\n Documentation/git-interpret-trailers.txt | 23 ++++++++++++++++\n builtin/commit.c                         | 33 -----------------------\n commit.c                                 | 34 ++++++++++++++++++++++++\n commit.h                                 |  2 ++\n t/t7502-commit-porcelain.sh              | 28 +++++++++++++++++++\n t/t7513-interpret-trailers.sh            | 23 ++++++++++++++++\n trailer.c                                | 13 ++++++++-\n 7 files changed, 122 insertions(+), 34 deletions(-)\n\ndiff --git a/Documentation/git-interpret-trailers.txt b/Documentation/git-interpret-trailers.txt\nindex 96ec6499f001..33e76f2a58fb 100644\n--- a/Documentation/git-interpret-trailers.txt\n+++ b/Documentation/git-interpret-trailers.txt\n@@ -69,6 +69,29 @@ Note that 'trailers' do not follow and are not intended to follow many\n rules for RFC 822 headers. For example they do not follow\n the encoding rules and probably many other rules.\n \n+Support to replace the value in the form of `@nickname`, provided that the\n+commit with nickname as the author can be found in the your repository's git\n+log. For example, in git's source code repository you can use commands:\n+\n+`git log --author=\"Junio\"  --pretty=\"%an <%ae>\" | sort |uniq `\n+\n+to find Junio's \"name <email>\" pair:\n+\n+Junio C Hamano <gitster@pobox.com>\n+Junio C Hamano <junio@hera.kernel.org>\n+Junio C Hamano <junio@kernel.org>\n+Junio C Hamano <junio@pobox.com>\n+...\n+\n+If you want to add a `Helped-by` trailer with Junio \"name <email>\" pair,\n+you can use:\n+\n+`git commit --trailers \"Helped-by:@Junio\"`\n+\n+to insert the trailer to your commit messages:\n+\n+Helped-by: Junio C Hamano <gitster@pobox.com>\n+\n OPTIONS\n -------\n --in-place::\ndiff --git a/builtin/commit.c b/builtin/commit.c\nindex 4b06672bd07d..58c020e3cfbf 100644\n--- a/builtin/commit.c\n+++ b/builtin/commit.c\n@@ -1043,39 +1043,6 @@ static int prepare_to_commit(const char *index_file, const char *prefix,\n \treturn 1;\n }\n \n-static const char *find_author_by_nickname(const char *name)\n-{\n-\tstruct rev_info revs;\n-\tstruct commit *commit;\n-\tstruct strbuf buf = STRBUF_INIT;\n-\tstruct string_list mailmap = STRING_LIST_INIT_NODUP;\n-\tconst char *av[20];\n-\tint ac = 0;\n-\n-\trepo_init_revisions(the_repository, &revs, NULL);\n-\tstrbuf_addf(&buf, \"--author=%s\", name);\n-\tav[++ac] = \"--all\";\n-\tav[++ac] = \"-i\";\n-\tav[++ac] = buf.buf;\n-\tav[++ac] = NULL;\n-\tsetup_revisions(ac, av, &revs, NULL);\n-\trevs.mailmap = &mailmap;\n-\tread_mailmap(revs.mailmap);\n-\n-\tif (prepare_revision_walk(&revs))\n-\t\tdie(_(\"revision walk setup failed\"));\n-\tcommit = get_revision(&revs);\n-\tif (commit) {\n-\t\tstruct pretty_print_context ctx = {0};\n-\t\tctx.date_mode.type = DATE_NORMAL;\n-\t\tstrbuf_release(&buf);\n-\t\tformat_commit_message(commit, \"%aN <%aE>\", &buf, &ctx);\n-\t\tclear_mailmap(&mailmap);\n-\t\treturn strbuf_detach(&buf, NULL);\n-\t}\n-\tdie(_(\"--author '%s' is not 'Name <email>' and matches no existing author\"), name);\n-}\n-\n static void handle_ignored_arg(struct wt_status *s)\n {\n \tif (!ignored_arg)\ndiff --git a/commit.c b/commit.c\nindex 6ccd774841c6..e1aad52d2c4f 100644\n--- a/commit.c\n+++ b/commit.c\n@@ -21,6 +21,7 @@\n #include \"commit-reach.h\"\n #include \"run-command.h\"\n #include \"shallow.h\"\n+#include \"mailmap.h\"\n \n static struct commit_extra_header *read_commit_extra_header_lines(const char *buf, size_t len, const char **);\n \n@@ -1703,3 +1704,36 @@ int run_commit_hook(int editor_is_used, const char *index_file,\n \n \treturn ret;\n }\n+\n+const char *find_author_by_nickname(const char *name)\n+{\n+\tstruct rev_info revs;\n+\tstruct commit *commit;\n+\tstruct strbuf buf = STRBUF_INIT;\n+\tstruct string_list mailmap = STRING_LIST_INIT_NODUP;\n+\tconst char *av[20];\n+\tint ac = 0;\n+\n+\trepo_init_revisions(the_repository, &revs, NULL);\n+\tstrbuf_addf(&buf, \"--author=%s\", name);\n+\tav[++ac] = \"--all\";\n+\tav[++ac] = \"-i\";\n+\tav[++ac] = buf.buf;\n+\tav[++ac] = NULL;\n+\tsetup_revisions(ac, av, &revs, NULL);\n+\trevs.mailmap = &mailmap;\n+\tread_mailmap(revs.mailmap);\n+\n+\tif (prepare_revision_walk(&revs))\n+\t\tdie(_(\"revision walk setup failed\"));\n+\tcommit = get_revision(&revs);\n+\tif (commit) {\n+\t\tstruct pretty_print_context ctx = {0};\n+\t\tctx.date_mode.type = DATE_NORMAL;\n+\t\tstrbuf_release(&buf);\n+\t\tformat_commit_message(commit, \"%aN <%aE>\", &buf, &ctx);\n+\t\tclear_mailmap(&mailmap);\n+\t\treturn strbuf_detach(&buf, NULL);\n+\t}\n+\tdie(_(\"--author '%s' is not 'Name <email>' and matches no existing author\"), name);\n+}\ndiff --git a/commit.h b/commit.h\nindex 49c0f503964e..970a73ccd5be 100644\n--- a/commit.h\n+++ b/commit.h\n@@ -371,4 +371,6 @@ int parse_buffer_signed_by_header(const char *buffer,\n \t\t\t\t  struct strbuf *signature,\n \t\t\t\t  const struct git_hash_algo *algop);\n \n+const char *find_author_by_nickname(const char *name);\n+\n #endif /* COMMIT_H */\ndiff --git a/t/t7502-commit-porcelain.sh b/t/t7502-commit-porcelain.sh\nindex 74b1602c0ce6..143690e2833c 100755\n--- a/t/t7502-commit-porcelain.sh\n+++ b/t/t7502-commit-porcelain.sh\n@@ -445,6 +445,34 @@ test_expect_success 'commit --trailer with -c and \":=#\" as separators' '\n \ttest_cmp expected actual\n '\n \n+\n+test_expect_success 'commit --trailer parse @nickname' '\n+\techo \"I love git\" >file1 &&\n+\tgit add file1 &&\n+\tgit commit -m \"yly\" --author=\"batman <email1>\" &&\n+\techo \"I love git\" >file2 &&\n+\tgit add file2 &&\n+\tgit commit -m \"yly\" --author=\"jocker <email2>\" &&\n+\techo \"I love git\" >file3 &&\n+\tgit add file3 &&\n+\tgit commit -m \"yly\" \\\n+\t--trailer \"Reviewed-by:@bat\" \\\n+\t--trailer \"Signed-off-by:@jock\" \\\n+\t--trailer \"Helped-by:@email1\" \\\n+\t--trailer \"Mentored-by:@email2\" &&\n+\tgit cat-file commit HEAD >commit.msg &&\n+\tsed -e \"1,/^\\$/d\" commit.msg >actual &&\n+\tcat >expected <<-\\EOF &&\n+\tyly\n+\n+\tReviewed-by: batman <email1>\n+\tSigned-off-by: jocker <email2>\n+\tHelped-by: batman <email1>\n+\tMentored-by: jocker <email2>\n+\tEOF\n+\ttest_cmp expected actual\n+'\n+\n test_expect_success 'multiple -m' '\n \n \t>negative &&\ndiff --git a/t/t7513-interpret-trailers.sh b/t/t7513-interpret-trailers.sh\nindex 6602790b5f4c..f2f1ae3b2faf 100755\n--- a/t/t7513-interpret-trailers.sh\n+++ b/t/t7513-interpret-trailers.sh\n@@ -63,6 +63,29 @@ test_expect_success 'without config' '\n \ttest_cmp expected actual\n '\n \n+test_expect_success 'trailer parse @nickname' '\n+\techo \"I love git\" >file1 &&\n+\tgit add file1 &&\n+\tgit commit -m \"yly\" --author=\"batman <email1>\" &&\n+\techo \"I love git\" >file2 &&\n+\tgit add file2 &&\n+\tgit commit -m \"yly\" --author=\"jocker <email2>\" &&\n+\tgit interpret-trailers \\\n+\t--trailer \"Reviewed-by:@bat\" \\\n+\t--trailer \"Signed-off-by:@jock\" \\\n+\t--trailer \"Helped-by:@email1\" \\\n+\t--trailer \"Mentored-by:@email2\" \\\n+\tempty >actual &&\n+\tcat >expected <<-\\EOF &&\n+\n+\tReviewed-by: batman <email1>\n+\tSigned-off-by: jocker <email2>\n+\tHelped-by: batman <email1>\n+\tMentored-by: jocker <email2>\n+\tEOF\n+\ttest_cmp expected actual\n+'\n+\n test_expect_success 'without config in another order' '\n \tsed -e \"s/ Z\\$/ /\" >expected <<-\\EOF &&\n \ndiff --git a/trailer.c b/trailer.c\nindex 249ed618ed8e..21f367e7b761 100644\n--- a/trailer.c\n+++ b/trailer.c\n@@ -6,6 +6,7 @@\n #include \"tempfile.h\"\n #include \"trailer.h\"\n #include \"list.h\"\n+#include \"revision.h\"\n /*\n  * Copyright (c) 2013, 2014 Christian Couder <chriscool@tuxfamily.org>\n  */\n@@ -633,11 +634,21 @@ static void parse_trailer(struct strbuf *tok, struct strbuf *val,\n \tstruct arg_item *item;\n \tsize_t tok_len;\n \tstruct list_head *pos;\n+\tconst char *ae = NULL;\n \n \tif (separator_pos != -1) {\n \t\tstrbuf_add(tok, trailer, separator_pos);\n \t\tstrbuf_trim(tok);\n-\t\tstrbuf_addstr(val, trailer + separator_pos + 1);\n+\t\tif (trailer[separator_pos + 1] == '@') {\n+\t\t\tae = find_author_by_nickname(trailer + separator_pos + 2);\n+\t\t\treset_revision_walk();\n+\t\t\tif (ae) {\n+\t\t\t\tstrbuf_addstr(val, ae);\n+\t\t\t\tfree((char*)ae);\n+\t\t\t} else\n+\t\t\t\tstrbuf_addstr(val, trailer + separator_pos + 1);\n+\t\t} else\n+\t\t\tstrbuf_addstr(val, trailer + separator_pos + 1);\n \t\tstrbuf_trim(val);\n \t} else {\n \t\tstrbuf_addstr(tok, trailer);\n-- \ngitgitgadget\n"},{"id":"419780","messageId":"xmqqft0pk018.fsf@gitster.g","threadId":"55356","inReplyTo":"ca521d3c01d652e09e716fb447b0b26da1a014e8.1616251299.git.gitgitgadget@gmail.com","subject":"Re: [PATCH 2/2] [GSOC] interpret-trailer: easy parse trailer value","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2021-03-20T21:06:27Z","receivedAt":"2021-03-20T21:07:09Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\"ZheNing Hu via GitGitGadget\" <gitgitgadget@gmail.com> writes:\n\n> diff --git a/commit.h b/commit.h\n> index 49c0f503964e..970a73ccd5be 100644\n> --- a/commit.h\n> +++ b/commit.h\n> @@ -371,4 +371,6 @@ int parse_buffer_signed_by_header(const char *buffer,\n>  \t\t\t\t  struct strbuf *signature,\n>  \t\t\t\t  const struct git_hash_algo *algop);\n>  \n> +const char *find_author_by_nickname(const char *name);\n> +\n>  #endif /* COMMIT_H */\n\nAs I already said, we do not want to pretend that this is a\ngenerally reusable helper function.  We should at least have a\ncomment to tell people to never add new callers to this function,\nwith explanation of the reason.\n"},{"id":"419830","messageId":"CAOLTT8Q7yNscYrYHWJQcsGn67MjWe15nd7SnCEd5QVUG0A6dRg@mail.gmail.com","threadId":"55356","inReplyTo":"xmqqft0pk018.fsf@gitster.g","subject":"Re: [PATCH 2/2] [GSOC] interpret-trailer: easy parse trailer value","fromName":"ZheNing Hu","fromEmail":"adlternative@gmail.com","sentAt":"2021-03-21T03:29:46Z","receivedAt":"2021-03-21T03:31:39Z","isPatch":true,"sender":{"key":"adlternative@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58138461?v=4"},"body":"Junio C Hamano <gitster@pobox.com> 于2021年3月21日周日 上午5:06写道：\n>\n> \"ZheNing Hu via GitGitGadget\" <gitgitgadget@gmail.com> writes:\n>\n> > diff --git a/commit.h b/commit.h\n> > index 49c0f503964e..970a73ccd5be 100644\n> > --- a/commit.h\n> > +++ b/commit.h\n> > @@ -371,4 +371,6 @@ int parse_buffer_signed_by_header(const char *buffer,\n> >                                 struct strbuf *signature,\n> >                                 const struct git_hash_algo *algop);\n> >\n> > +const char *find_author_by_nickname(const char *name);\n> > +\n> >  #endif /* COMMIT_H */\n>\n> As I already said, we do not want to pretend that this is a\n> generally reusable helper function.  We should at least have a\n> comment to tell people to never add new callers to this function,\n> with explanation of the reason.\n\nDo you think this is appropriate?\n\n@@ -370,5 +370,15 @@ int parse_buffer_signed_by_header(const char *buffer,\n                                  struct strbuf *payload,\n                                  struct strbuf *signature,\n                                  const struct git_hash_algo *algop);\n+/*\n+ * Calling `find_author_by_nickname` to find the \"author <email>\" pair\n+ * in the most recent commit which matches \"--author=name\".\n+ *\n+ * Note that `find_author_by_nickname` is not reusable, because it haven't\n+ * reset flags for parsed objects. The only safe way to use\n`find_author_by_nickname`\n+ * (without rewriting the revision traversal machinery) is to spawn a\n+ * subprocess and do find_author_by_nickname() in it.\n+ */\n+const char *find_author_by_nickname(const char *name);\n\nThanks.\n"},{"id":"419840","messageId":"pull.911.v2.git.1616317134.gitgitgadget@gmail.com","threadId":"55356","inReplyTo":"pull.911.git.1616251299.gitgitgadget@gmail.com","subject":"[PATCH v2 0/2] [GSOC] interpret-trailer: easy parse trailer value","fromName":"ZheNing Hu via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2021-03-21T08:58:52Z","receivedAt":"2021-03-21T08:59:51Z","isPatch":true,"sender":{"key":"adlternative@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58138461?v=4"},"body":"Hope this can help commit --trailer more useful!\n\nBase on https://github.com/gitgitgadget/git/pull/901, The original patch\nseries was too long so now split it into two.\n\nHelped by Junio and Jeff, Thanks.\n\nZheNing Hu (2):\n  [GSOC] commit: add --trailer option\n  [GSOC] interpret-trailer: easy parse trailer value\n\n Documentation/git-commit.txt             |  14 +-\n Documentation/git-interpret-trailers.txt |  23 ++\n builtin/commit.c                         |  55 ++--\n commit.c                                 |  34 +++\n commit.h                                 |  10 +\n t/t7502-commit-porcelain.sh              | 319 +++++++++++++++++++++++\n t/t7513-interpret-trailers.sh            |  23 ++\n trailer.c                                |  13 +-\n 8 files changed, 456 insertions(+), 35 deletions(-)\n\n\nbase-commit: 13d7ab6b5d7929825b626f050b62a11241ea4945\nPublished-As: https://github.com/gitgitgadget/git/releases/tag/pr-911%2Fadlternative%2Ftrailer-easy-ident-v2\nFetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-911/adlternative/trailer-easy-ident-v2\nPull-Request: https://github.com/gitgitgadget/git/pull/911\n\nRange-diff vs v1:\n\n 1:  2378e3b4c1ae = 1:  2378e3b4c1ae [GSOC] commit: add --trailer option\n 2:  ca521d3c01d6 ! 2:  8b8b236a4ffb [GSOC] interpret-trailer: easy parse trailer value\n     @@ commit.c: int run_commit_hook(int editor_is_used, const char *index_file,\n      \n       ## commit.h ##\n      @@ commit.h: int parse_buffer_signed_by_header(const char *buffer,\n     + \t\t\t\t  struct strbuf *payload,\n       \t\t\t\t  struct strbuf *signature,\n       \t\t\t\t  const struct git_hash_algo *algop);\n     - \n     ++/*\n     ++ * Calling `find_author_by_nickname` to find the \"author <email>\" pair\n     ++ * in the most recent commit which matches \"--author=name\".\n     ++ *\n     ++ * Note that `find_author_by_nickname` is not reusable, because it haven't\n     ++ * reset flags for parsed objects. The only safe way to use `find_author_by_nickname`\n     ++ * (without rewriting the revision traversal machinery) is to spawn a\n     ++ * subprocess and do find_author_by_nickname() in it.\n     ++ */\n      +const char *find_author_by_nickname(const char *name);\n     -+\n     + \n       #endif /* COMMIT_H */\n      \n       ## t/t7502-commit-porcelain.sh ##\n\n-- \ngitgitgadget\n"},{"id":"419841","messageId":"8b8b236a4ffb81a8c6be3f320b878cea1d0f9d7a.1616317135.git.gitgitgadget@gmail.com","threadId":"55356","inReplyTo":"pull.911.v2.git.1616317134.gitgitgadget@gmail.com","subject":"[PATCH v2 2/2] [GSOC] interpret-trailer: easy parse trailer value","fromName":"ZheNing Hu via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2021-03-21T08:58:54Z","receivedAt":"2021-03-21T08:59:51Z","isPatch":true,"sender":{"key":"adlternative@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58138461?v=4"},"body":"From: ZheNing Hu <adlternative@gmail.com>\n\nThe original `-trailer` adding some trailers like\n\"Signed-off-by:C O <Mister@email.com>\" is often too\nverbose and error-prone.\n\nNow add the syntax parse for the value of `--trailer`:\ne.g. \"Signed-off-by:@Junio\", git will fuzzy search in the\ncommit history to find the latest one commit which matches\n`--author=Junio`, and get the \"author <email>\" pair\n`Junio C Hamano <gitster@pobox.com>` as the value of\n`--trailer`, it will be a easy way to add trailers.\ngit commit --trailer` can also benefit from this.\n\nSigned-off-by: ZheNing Hu <adlternative@gmail.com>\nHelped-by: Junio C Hamano <gitster@pobox.com>\nHelped-by: Jeff King <peff@peff.net>\n---\n Documentation/git-interpret-trailers.txt | 23 ++++++++++++++++\n builtin/commit.c                         | 33 -----------------------\n commit.c                                 | 34 ++++++++++++++++++++++++\n commit.h                                 | 10 +++++++\n t/t7502-commit-porcelain.sh              | 28 +++++++++++++++++++\n t/t7513-interpret-trailers.sh            | 23 ++++++++++++++++\n trailer.c                                | 13 ++++++++-\n 7 files changed, 130 insertions(+), 34 deletions(-)\n\ndiff --git a/Documentation/git-interpret-trailers.txt b/Documentation/git-interpret-trailers.txt\nindex 96ec6499f001..33e76f2a58fb 100644\n--- a/Documentation/git-interpret-trailers.txt\n+++ b/Documentation/git-interpret-trailers.txt\n@@ -69,6 +69,29 @@ Note that 'trailers' do not follow and are not intended to follow many\n rules for RFC 822 headers. For example they do not follow\n the encoding rules and probably many other rules.\n \n+Support to replace the value in the form of `@nickname`, provided that the\n+commit with nickname as the author can be found in the your repository's git\n+log. For example, in git's source code repository you can use commands:\n+\n+`git log --author=\"Junio\"  --pretty=\"%an <%ae>\" | sort |uniq `\n+\n+to find Junio's \"name <email>\" pair:\n+\n+Junio C Hamano <gitster@pobox.com>\n+Junio C Hamano <junio@hera.kernel.org>\n+Junio C Hamano <junio@kernel.org>\n+Junio C Hamano <junio@pobox.com>\n+...\n+\n+If you want to add a `Helped-by` trailer with Junio \"name <email>\" pair,\n+you can use:\n+\n+`git commit --trailers \"Helped-by:@Junio\"`\n+\n+to insert the trailer to your commit messages:\n+\n+Helped-by: Junio C Hamano <gitster@pobox.com>\n+\n OPTIONS\n -------\n --in-place::\ndiff --git a/builtin/commit.c b/builtin/commit.c\nindex 4b06672bd07d..58c020e3cfbf 100644\n--- a/builtin/commit.c\n+++ b/builtin/commit.c\n@@ -1043,39 +1043,6 @@ static int prepare_to_commit(const char *index_file, const char *prefix,\n \treturn 1;\n }\n \n-static const char *find_author_by_nickname(const char *name)\n-{\n-\tstruct rev_info revs;\n-\tstruct commit *commit;\n-\tstruct strbuf buf = STRBUF_INIT;\n-\tstruct string_list mailmap = STRING_LIST_INIT_NODUP;\n-\tconst char *av[20];\n-\tint ac = 0;\n-\n-\trepo_init_revisions(the_repository, &revs, NULL);\n-\tstrbuf_addf(&buf, \"--author=%s\", name);\n-\tav[++ac] = \"--all\";\n-\tav[++ac] = \"-i\";\n-\tav[++ac] = buf.buf;\n-\tav[++ac] = NULL;\n-\tsetup_revisions(ac, av, &revs, NULL);\n-\trevs.mailmap = &mailmap;\n-\tread_mailmap(revs.mailmap);\n-\n-\tif (prepare_revision_walk(&revs))\n-\t\tdie(_(\"revision walk setup failed\"));\n-\tcommit = get_revision(&revs);\n-\tif (commit) {\n-\t\tstruct pretty_print_context ctx = {0};\n-\t\tctx.date_mode.type = DATE_NORMAL;\n-\t\tstrbuf_release(&buf);\n-\t\tformat_commit_message(commit, \"%aN <%aE>\", &buf, &ctx);\n-\t\tclear_mailmap(&mailmap);\n-\t\treturn strbuf_detach(&buf, NULL);\n-\t}\n-\tdie(_(\"--author '%s' is not 'Name <email>' and matches no existing author\"), name);\n-}\n-\n static void handle_ignored_arg(struct wt_status *s)\n {\n \tif (!ignored_arg)\ndiff --git a/commit.c b/commit.c\nindex 6ccd774841c6..e1aad52d2c4f 100644\n--- a/commit.c\n+++ b/commit.c\n@@ -21,6 +21,7 @@\n #include \"commit-reach.h\"\n #include \"run-command.h\"\n #include \"shallow.h\"\n+#include \"mailmap.h\"\n \n static struct commit_extra_header *read_commit_extra_header_lines(const char *buf, size_t len, const char **);\n \n@@ -1703,3 +1704,36 @@ int run_commit_hook(int editor_is_used, const char *index_file,\n \n \treturn ret;\n }\n+\n+const char *find_author_by_nickname(const char *name)\n+{\n+\tstruct rev_info revs;\n+\tstruct commit *commit;\n+\tstruct strbuf buf = STRBUF_INIT;\n+\tstruct string_list mailmap = STRING_LIST_INIT_NODUP;\n+\tconst char *av[20];\n+\tint ac = 0;\n+\n+\trepo_init_revisions(the_repository, &revs, NULL);\n+\tstrbuf_addf(&buf, \"--author=%s\", name);\n+\tav[++ac] = \"--all\";\n+\tav[++ac] = \"-i\";\n+\tav[++ac] = buf.buf;\n+\tav[++ac] = NULL;\n+\tsetup_revisions(ac, av, &revs, NULL);\n+\trevs.mailmap = &mailmap;\n+\tread_mailmap(revs.mailmap);\n+\n+\tif (prepare_revision_walk(&revs))\n+\t\tdie(_(\"revision walk setup failed\"));\n+\tcommit = get_revision(&revs);\n+\tif (commit) {\n+\t\tstruct pretty_print_context ctx = {0};\n+\t\tctx.date_mode.type = DATE_NORMAL;\n+\t\tstrbuf_release(&buf);\n+\t\tformat_commit_message(commit, \"%aN <%aE>\", &buf, &ctx);\n+\t\tclear_mailmap(&mailmap);\n+\t\treturn strbuf_detach(&buf, NULL);\n+\t}\n+\tdie(_(\"--author '%s' is not 'Name <email>' and matches no existing author\"), name);\n+}\ndiff --git a/commit.h b/commit.h\nindex 49c0f503964e..cb9f7cd13f09 100644\n--- a/commit.h\n+++ b/commit.h\n@@ -370,5 +370,15 @@ int parse_buffer_signed_by_header(const char *buffer,\n \t\t\t\t  struct strbuf *payload,\n \t\t\t\t  struct strbuf *signature,\n \t\t\t\t  const struct git_hash_algo *algop);\n+/*\n+ * Calling `find_author_by_nickname` to find the \"author <email>\" pair\n+ * in the most recent commit which matches \"--author=name\".\n+ *\n+ * Note that `find_author_by_nickname` is not reusable, because it haven't\n+ * reset flags for parsed objects. The only safe way to use `find_author_by_nickname`\n+ * (without rewriting the revision traversal machinery) is to spawn a\n+ * subprocess and do find_author_by_nickname() in it.\n+ */\n+const char *find_author_by_nickname(const char *name);\n \n #endif /* COMMIT_H */\ndiff --git a/t/t7502-commit-porcelain.sh b/t/t7502-commit-porcelain.sh\nindex 74b1602c0ce6..143690e2833c 100755\n--- a/t/t7502-commit-porcelain.sh\n+++ b/t/t7502-commit-porcelain.sh\n@@ -445,6 +445,34 @@ test_expect_success 'commit --trailer with -c and \":=#\" as separators' '\n \ttest_cmp expected actual\n '\n \n+\n+test_expect_success 'commit --trailer parse @nickname' '\n+\techo \"I love git\" >file1 &&\n+\tgit add file1 &&\n+\tgit commit -m \"yly\" --author=\"batman <email1>\" &&\n+\techo \"I love git\" >file2 &&\n+\tgit add file2 &&\n+\tgit commit -m \"yly\" --author=\"jocker <email2>\" &&\n+\techo \"I love git\" >file3 &&\n+\tgit add file3 &&\n+\tgit commit -m \"yly\" \\\n+\t--trailer \"Reviewed-by:@bat\" \\\n+\t--trailer \"Signed-off-by:@jock\" \\\n+\t--trailer \"Helped-by:@email1\" \\\n+\t--trailer \"Mentored-by:@email2\" &&\n+\tgit cat-file commit HEAD >commit.msg &&\n+\tsed -e \"1,/^\\$/d\" commit.msg >actual &&\n+\tcat >expected <<-\\EOF &&\n+\tyly\n+\n+\tReviewed-by: batman <email1>\n+\tSigned-off-by: jocker <email2>\n+\tHelped-by: batman <email1>\n+\tMentored-by: jocker <email2>\n+\tEOF\n+\ttest_cmp expected actual\n+'\n+\n test_expect_success 'multiple -m' '\n \n \t>negative &&\ndiff --git a/t/t7513-interpret-trailers.sh b/t/t7513-interpret-trailers.sh\nindex 6602790b5f4c..f2f1ae3b2faf 100755\n--- a/t/t7513-interpret-trailers.sh\n+++ b/t/t7513-interpret-trailers.sh\n@@ -63,6 +63,29 @@ test_expect_success 'without config' '\n \ttest_cmp expected actual\n '\n \n+test_expect_success 'trailer parse @nickname' '\n+\techo \"I love git\" >file1 &&\n+\tgit add file1 &&\n+\tgit commit -m \"yly\" --author=\"batman <email1>\" &&\n+\techo \"I love git\" >file2 &&\n+\tgit add file2 &&\n+\tgit commit -m \"yly\" --author=\"jocker <email2>\" &&\n+\tgit interpret-trailers \\\n+\t--trailer \"Reviewed-by:@bat\" \\\n+\t--trailer \"Signed-off-by:@jock\" \\\n+\t--trailer \"Helped-by:@email1\" \\\n+\t--trailer \"Mentored-by:@email2\" \\\n+\tempty >actual &&\n+\tcat >expected <<-\\EOF &&\n+\n+\tReviewed-by: batman <email1>\n+\tSigned-off-by: jocker <email2>\n+\tHelped-by: batman <email1>\n+\tMentored-by: jocker <email2>\n+\tEOF\n+\ttest_cmp expected actual\n+'\n+\n test_expect_success 'without config in another order' '\n \tsed -e \"s/ Z\\$/ /\" >expected <<-\\EOF &&\n \ndiff --git a/trailer.c b/trailer.c\nindex 249ed618ed8e..21f367e7b761 100644\n--- a/trailer.c\n+++ b/trailer.c\n@@ -6,6 +6,7 @@\n #include \"tempfile.h\"\n #include \"trailer.h\"\n #include \"list.h\"\n+#include \"revision.h\"\n /*\n  * Copyright (c) 2013, 2014 Christian Couder <chriscool@tuxfamily.org>\n  */\n@@ -633,11 +634,21 @@ static void parse_trailer(struct strbuf *tok, struct strbuf *val,\n \tstruct arg_item *item;\n \tsize_t tok_len;\n \tstruct list_head *pos;\n+\tconst char *ae = NULL;\n \n \tif (separator_pos != -1) {\n \t\tstrbuf_add(tok, trailer, separator_pos);\n \t\tstrbuf_trim(tok);\n-\t\tstrbuf_addstr(val, trailer + separator_pos + 1);\n+\t\tif (trailer[separator_pos + 1] == '@') {\n+\t\t\tae = find_author_by_nickname(trailer + separator_pos + 2);\n+\t\t\treset_revision_walk();\n+\t\t\tif (ae) {\n+\t\t\t\tstrbuf_addstr(val, ae);\n+\t\t\t\tfree((char*)ae);\n+\t\t\t} else\n+\t\t\t\tstrbuf_addstr(val, trailer + separator_pos + 1);\n+\t\t} else\n+\t\t\tstrbuf_addstr(val, trailer + separator_pos + 1);\n \t\tstrbuf_trim(val);\n \t} else {\n \t\tstrbuf_addstr(tok, trailer);\n-- \ngitgitgadget\n"},{"id":"419842","messageId":"2378e3b4c1ae2a38b6cf7d11eea16c5d3c55da74.1616317134.git.gitgitgadget@gmail.com","threadId":"55356","inReplyTo":"pull.911.v2.git.1616317134.gitgitgadget@gmail.com","subject":"[PATCH v2 1/2] [GSOC] commit: add --trailer option","fromName":"ZheNing Hu via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2021-03-21T08:58:53Z","receivedAt":"2021-03-21T08:59:51Z","isPatch":true,"sender":{"key":"adlternative@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58138461?v=4"},"body":"From: ZheNing Hu <adlternative@gmail.com>\n\nHistorically, Git has supported the 'Signed-off-by' commit trailer\nusing the '--signoff' and the '-s' option from the command line.\nBut users may need to provide other trailer information from the\ncommand line such as \"Helped-by\", \"Reported-by\", \"Mentored-by\",\n\nNow implement a new `--trailer <token>[(=|:)<value>]` option to pass\nother trailers to `interpret-trailers` and insert them into commit\nmessages.\n\nSigned-off-by: ZheNing Hu <adlternative@gmail.com>\n---\n Documentation/git-commit.txt |  14 +-\n builtin/commit.c             |  22 +++\n t/t7502-commit-porcelain.sh  | 291 +++++++++++++++++++++++++++++++++++\n 3 files changed, 326 insertions(+), 1 deletion(-)\n\ndiff --git a/Documentation/git-commit.txt b/Documentation/git-commit.txt\nindex 17150fa7eabe..3fe7ef33cb07 100644\n--- a/Documentation/git-commit.txt\n+++ b/Documentation/git-commit.txt\n@@ -14,7 +14,8 @@ SYNOPSIS\n \t   [--allow-empty-message] [--no-verify] [-e] [--author=<author>]\n \t   [--date=<date>] [--cleanup=<mode>] [--[no-]status]\n \t   [-i | -o] [--pathspec-from-file=<file> [--pathspec-file-nul]]\n-\t   [-S[<keyid>]] [--] [<pathspec>...]\n+\t   [(--trailer <token>[(=|:)<value>])...] [-S[<keyid>]]\n+\t   [--] [<pathspec>...]\n \n DESCRIPTION\n -----------\n@@ -166,6 +167,17 @@ The `-m` option is mutually exclusive with `-c`, `-C`, and `-F`.\n \n include::signoff-option.txt[]\n \n+--trailer <token>[(=|:)<value>]::\n+\tSpecify a (<token>, <value>) pair that should be applied as a\n+\ttrailer. (e.g. `git commit --trailer \"Signed-off-by:C O Mitter \\\n+\t<committer@example.com>\" --trailer \"Helped-by:C O Mitter \\\n+\t<committer@example.com>\"` will add the \"Signed-off-by\" trailer\n+\tand the \"Helped-by\" trailer to the commit message.)\n+\tThe `trailer.*` configuration variables\n+\t(linkgit:git-interpret-trailers[1]) can be used to define if\n+\ta duplicated trailer is omitted, where in the run of trailers\n+\teach trailer would appear, and other details.\n+\n -n::\n --no-verify::\n \tThis option bypasses the pre-commit and commit-msg hooks.\ndiff --git a/builtin/commit.c b/builtin/commit.c\nindex 739110c5a7f6..4b06672bd07d 100644\n--- a/builtin/commit.c\n+++ b/builtin/commit.c\n@@ -113,6 +113,7 @@ static int config_commit_verbose = -1; /* unspecified */\n static int no_post_rewrite, allow_empty_message, pathspec_file_nul;\n static char *untracked_files_arg, *force_date, *ignore_submodule_arg, *ignored_arg;\n static char *sign_commit, *pathspec_from_file;\n+static struct strvec trailer_args = STRVEC_INIT;\n \n /*\n  * The default commit message cleanup mode will remove the lines\n@@ -131,6 +132,14 @@ static struct strbuf message = STRBUF_INIT;\n \n static enum wt_status_format status_format = STATUS_FORMAT_UNSPECIFIED;\n \n+static int opt_pass_trailer(const struct option *opt, const char *arg, int unset)\n+{\n+\tBUG_ON_OPT_NEG(unset);\n+\n+\tstrvec_pushl(&trailer_args, \"--trailer\", arg, NULL);\n+\treturn 0;\n+}\n+\n static int opt_parse_porcelain(const struct option *opt, const char *arg, int unset)\n {\n \tenum wt_status_format *value = (enum wt_status_format *)opt->value;\n@@ -958,6 +967,18 @@ static int prepare_to_commit(const char *index_file, const char *prefix,\n \n \tfclose(s->fp);\n \n+\tif (trailer_args.nr) {\n+\t\tstruct child_process run_trailer = CHILD_PROCESS_INIT;\n+\n+\t\tstrvec_pushl(&run_trailer.args, \"interpret-trailers\",\n+\t\t\t     \"--in-place\", git_path_commit_editmsg(), NULL);\n+\t\tstrvec_pushv(&run_trailer.args, trailer_args.v);\n+\t\trun_trailer.git_cmd = 1;\n+\t\tif (run_command(&run_trailer))\n+\t\t\tdie(_(\"unable to pass trailers to --trailers\"));\n+\t\tstrvec_clear(&trailer_args);\n+\t}\n+\n \t/*\n \t * Reject an attempt to record a non-merge empty commit without\n \t * explicit --allow-empty. In the cherry-pick case, it may be\n@@ -1507,6 +1528,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)\n \t\tOPT_STRING(0, \"fixup\", &fixup_message, N_(\"commit\"), N_(\"use autosquash formatted message to fixup specified commit\")),\n \t\tOPT_STRING(0, \"squash\", &squash_message, N_(\"commit\"), N_(\"use autosquash formatted message to squash specified commit\")),\n \t\tOPT_BOOL(0, \"reset-author\", &renew_authorship, N_(\"the commit is authored by me now (used with -C/-c/--amend)\")),\n+\t\tOPT_CALLBACK_F(0, \"trailer\", NULL, N_(\"trailer\"), N_(\"add custom trailer(s)\"), PARSE_OPT_NONEG, opt_pass_trailer),\n \t\tOPT_BOOL('s', \"signoff\", &signoff, N_(\"add a Signed-off-by trailer\")),\n \t\tOPT_FILENAME('t', \"template\", &template_file, N_(\"use specified template file\")),\n \t\tOPT_BOOL('e', \"edit\", &edit_flag, N_(\"force edit of commit\")),\ndiff --git a/t/t7502-commit-porcelain.sh b/t/t7502-commit-porcelain.sh\nindex 6396897cc818..74b1602c0ce6 100755\n--- a/t/t7502-commit-porcelain.sh\n+++ b/t/t7502-commit-porcelain.sh\n@@ -38,6 +38,16 @@ check_summary_oneline() {\n \ttest_cmp exp act\n }\n \n+trailer_commit_base () {\n+\techo \"fun\" >>file &&\n+\tgit add file &&\n+\tgit commit -s --trailer \"Signed-off-by=C1 E1 \" \\\n+\t\t--trailer \"Helped-by:C2 E2 \" \\\n+\t\t--trailer \"Reported-by=C3 E3\" \\\n+\t\t--trailer \"Mentored-by:C4 E4\" \\\n+\t\t-m \"hello\"\n+}\n+\n test_expect_success 'output summary format' '\n \n \techo new >file1 &&\n@@ -154,6 +164,287 @@ test_expect_success 'sign off' '\n \n '\n \n+test_expect_success 'commit --trailer with \"=\"' '\n+\ttrailer_commit_base &&\n+\tcat >expected <<-\\EOF &&\n+\thello\n+\n+\tSigned-off-by: C O Mitter <committer@example.com>\n+\tSigned-off-by: C1 E1\n+\tHelped-by: C2 E2\n+\tReported-by: C3 E3\n+\tMentored-by: C4 E4\n+\tEOF\n+\tgit cat-file commit HEAD >commit.msg &&\n+\tsed -e \"1,/^\\$/d\" commit.msg >actual &&\n+\ttest_cmp expected actual\n+'\n+\n+test_expect_success 'commit --trailer with -c and \"replace\" as ifexists' '\n+\ttrailer_commit_base &&\n+\tcat >expected <<-\\EOF &&\n+\thello\n+\n+\tSigned-off-by: C O Mitter <committer@example.com>\n+\tSigned-off-by: C1 E1\n+\tReported-by: C3 E3\n+\tMentored-by: C4 E4\n+\tHelped-by: C3 E3\n+\tEOF\n+\tgit -c trailer.ifexists=\"replace\" \\\n+\t\tcommit --trailer \"Mentored-by: C4 E4\" \\\n+\t\t --trailer \"Helped-by: C3 E3\" \\\n+\t\t--amend &&\n+\tgit cat-file commit HEAD >commit.msg &&\n+\tsed -e \"1,/^\\$/d\"  commit.msg >actual &&\n+\ttest_cmp expected actual\n+'\n+\n+test_expect_success 'commit --trailer with -c and \"add\" as ifexists' '\n+\ttrailer_commit_base &&\n+\tcat >expected <<-\\EOF &&\n+\thello\n+\n+\tSigned-off-by: C O Mitter <committer@example.com>\n+\tSigned-off-by: C1 E1\n+\tHelped-by: C2 E2\n+\tReported-by: C3 E3\n+\tMentored-by: C4 E4\n+\tReported-by: C3 E3\n+\tMentored-by: C4 E4\n+\tEOF\n+\tgit -c trailer.ifexists=\"add\" \\\n+\t\tcommit --trailer \"Reported-by: C3 E3\" \\\n+\t\t--trailer \"Mentored-by: C4 E4\" \\\n+\t\t--amend &&\n+\tgit cat-file commit HEAD >commit.msg &&\n+\tsed -e \"1,/^\\$/d\"  commit.msg >actual &&\n+\ttest_cmp expected actual\n+'\n+\n+test_expect_success 'commit --trailer with -c and \"donothing\" as ifexists' '\n+\ttrailer_commit_base &&\n+\tcat >expected <<-\\EOF &&\n+\thello\n+\n+\tSigned-off-by: C O Mitter <committer@example.com>\n+\tSigned-off-by: C1 E1\n+\tHelped-by: C2 E2\n+\tReported-by: C3 E3\n+\tMentored-by: C4 E4\n+\tReviewed-by: C6 E6\n+\tEOF\n+\tgit -c trailer.ifexists=\"donothing\" \\\n+\t\tcommit --trailer \"Mentored-by: C5 E5\" \\\n+\t\t--trailer \"Reviewed-by: C6 E6\" \\\n+\t\t--amend &&\n+\tgit cat-file commit HEAD >commit.msg &&\n+\tsed -e \"1,/^\\$/d\"  commit.msg >actual &&\n+\ttest_cmp expected actual\n+'\n+\n+test_expect_success 'commit --trailer with -c and \"addIfDifferent\" as ifexists' '\n+\ttrailer_commit_base &&\n+\tcat >expected <<-\\EOF &&\n+\thello\n+\n+\tSigned-off-by: C O Mitter <committer@example.com>\n+\tSigned-off-by: C1 E1\n+\tHelped-by: C2 E2\n+\tReported-by: C3 E3\n+\tMentored-by: C4 E4\n+\tMentored-by: C5 E5\n+\tEOF\n+\tgit -c trailer.ifexists=\"addIfDifferent\" \\\n+\t\tcommit --trailer \"Reported-by: C3 E3\" \\\n+\t\t--trailer \"Mentored-by: C5 E5\" \\\n+\t\t--amend &&\n+\tgit cat-file commit HEAD >commit.msg &&\n+\tsed -e \"1,/^\\$/d\"  commit.msg >actual &&\n+\ttest_cmp expected actual\n+'\n+\n+test_expect_success 'commit --trailer with -c and \"addIfDifferentNeighbor\" as ifexists' '\n+\ttrailer_commit_base &&\n+\tcat >expected <<-\\EOF &&\n+\thello\n+\n+\tSigned-off-by: C O Mitter <committer@example.com>\n+\tSigned-off-by: C1 E1\n+\tHelped-by: C2 E2\n+\tReported-by: C3 E3\n+\tMentored-by: C4 E4\n+\tReported-by: C3 E3\n+\tEOF\n+\tgit -c trailer.ifexists=\"addIfDifferentNeighbor\" \\\n+\t\tcommit --trailer \"Mentored-by: C4 E4\" \\\n+\t\t--trailer \"Reported-by: C3 E3\" \\\n+\t\t--amend &&\n+\tgit cat-file commit HEAD >commit.msg &&\n+\tsed -e \"1,/^\\$/d\"  commit.msg >actual &&\n+\ttest_cmp expected actual\n+'\n+\n+test_expect_success 'commit --trailer with -c and \"end\" as where' '\n+\ttrailer_commit_base &&\n+\tcat >expected <<-\\EOF &&\n+\thello\n+\n+\tSigned-off-by: C O Mitter <committer@example.com>\n+\tSigned-off-by: C1 E1\n+\tHelped-by: C2 E2\n+\tReported-by: C3 E3\n+\tMentored-by: C4 E4\n+\tReported-by: C3 E3\n+\tMentored-by: C4 E4\n+\tEOF\n+\tgit -c trailer.where=\"end\" \\\n+\t\tcommit --trailer \"Reported-by: C3 E3\" \\\n+\t\t--trailer \"Mentored-by: C4 E4\" \\\n+\t\t--amend &&\n+\tgit cat-file commit HEAD >commit.msg &&\n+\tsed -e \"1,/^\\$/d\" commit.msg >actual &&\n+\ttest_cmp expected actual\n+'\n+\n+test_expect_success 'commit --trailer with -c and \"start\" as where' '\n+\ttrailer_commit_base &&\n+\tcat >expected <<-\\EOF &&\n+\thello\n+\n+\tSigned-off-by: C1 E1\n+\tSigned-off-by: C O Mitter <committer@example.com>\n+\tSigned-off-by: C1 E1\n+\tHelped-by: C2 E2\n+\tReported-by: C3 E3\n+\tMentored-by: C4 E4\n+\tEOF\n+\tgit -c trailer.where=\"start\" \\\n+\t\tcommit --trailer \"Signed-off-by: C O Mitter <committer@example.com>\" \\\n+\t\t--trailer \"Signed-off-by: C1 E1\" \\\n+\t\t--amend &&\n+\tgit cat-file commit HEAD >commit.msg &&\n+\tsed -e \"1,/^\\$/d\" commit.msg >actual &&\n+\ttest_cmp expected actual\n+'\n+\n+test_expect_success 'commit --trailer with -c and \"after\" as where' '\n+\ttrailer_commit_base &&\n+\tcat >expected <<-\\EOF &&\n+\thello\n+\n+\tSigned-off-by: C O Mitter <committer@example.com>\n+\tSigned-off-by: C1 E1\n+\tHelped-by: C2 E2\n+\tReported-by: C3 E3\n+\tMentored-by: C4 E4\n+\tMentored-by: C5 E5\n+\tEOF\n+\tgit -c trailer.where=\"after\" \\\n+\t\tcommit --trailer \"Mentored-by: C4 E4\" \\\n+\t\t--trailer \"Mentored-by: C5 E5\" \\\n+\t\t--amend &&\n+\tgit cat-file commit HEAD >commit.msg &&\n+\tsed -e \"1,/^\\$/d\" commit.msg >actual &&\n+\ttest_cmp expected actual\n+'\n+\n+test_expect_success 'commit --trailer with -c and \"before\" as where' '\n+\ttrailer_commit_base &&\n+\tcat >expected <<-\\EOF &&\n+\thello\n+\n+\tSigned-off-by: C O Mitter <committer@example.com>\n+\tSigned-off-by: C1 E1\n+\tHelped-by: C2 E2\n+\tReported-by: C3 E3\n+\tMentored-by: C2 E2\n+\tMentored-by: C3 E3\n+\tMentored-by: C4 E4\n+\tEOF\n+\tgit -c trailer.where=\"before\" \\\n+\t\tcommit --trailer \"Mentored-by: C3 E3\" \\\n+\t\t--trailer \"Mentored-by: C2 E2\" \\\n+\t\t--amend &&\n+\tgit cat-file commit HEAD >commit.msg &&\n+\tsed -e \"1,/^\\$/d\" commit.msg >actual &&\n+\ttest_cmp expected actual\n+'\n+\n+test_expect_success 'commit --trailer with -c and \"donothing\" as ifmissing' '\n+\ttrailer_commit_base &&\n+\tcat >expected <<-\\EOF &&\n+\thello\n+\n+\tSigned-off-by: C O Mitter <committer@example.com>\n+\tSigned-off-by: C1 E1\n+\tHelped-by: C2 E2\n+\tReported-by: C3 E3\n+\tMentored-by: C4 E4\n+\tHelped-by: C5 E5\n+\tEOF\n+\tgit -c trailer.ifmissing=\"donothing\" \\\n+\t\tcommit --trailer \"Helped-by: C5 E5\" \\\n+\t\t--trailer \"Based-by: C6 E6\" \\\n+\t\t--amend &&\n+\tgit cat-file commit HEAD >commit.msg &&\n+\tsed -e \"1,/^\\$/d\" commit.msg >actual &&\n+\ttest_cmp expected actual\n+'\n+\n+test_expect_success 'commit --trailer with -c and \"add\" as ifmissing' '\n+\ttrailer_commit_base &&\n+\tcat >expected <<-\\EOF &&\n+\thello\n+\n+\tSigned-off-by: C O Mitter <committer@example.com>\n+\tSigned-off-by: C1 E1\n+\tHelped-by: C2 E2\n+\tReported-by: C3 E3\n+\tMentored-by: C4 E4\n+\tHelped-by: C5 E5\n+\tBased-by: C6 E6\n+\tEOF\n+\tgit -c trailer.ifmissing=\"add\" \\\n+\t\tcommit --trailer \"Helped-by: C5 E5\" \\\n+\t\t--trailer \"Based-by: C6 E6\" \\\n+\t\t--amend &&\n+\tgit cat-file commit HEAD >commit.msg &&\n+\tsed -e \"1,/^\\$/d\" commit.msg >actual &&\n+\ttest_cmp expected actual\n+'\n+\n+test_expect_success 'commit --trailer with -c ack.key ' '\n+\techo \"fun\" >>file1 &&\n+\tgit add file1 &&\n+\tcat >expected <<-\\EOF &&\n+\t\thello\n+\n+\t\tAcked-by: Peff\n+\tEOF\n+\tgit -c trailer.ack.key=\"Acked-by\" \\\n+\t\tcommit --trailer \"ack = Peff\" -m \"hello\" &&\n+\tgit cat-file commit HEAD >commit.msg &&\n+\tsed -e \"1,/^\\$/d\" commit.msg >actual &&\n+\ttest_cmp expected actual\n+'\n+\n+test_expect_success 'commit --trailer with -c and \":=#\" as separators' '\n+\techo \"fun\" >>file1 &&\n+\tgit add file1 &&\n+\tcat >expected <<-\\EOF &&\n+\t\tI hate bug\n+\n+\t\tBug #42\n+\tEOF\n+\tgit -c trailer.separators=\":=#\" \\\n+\t\t-c trailer.bug.key=\"Bug #\" \\\n+\t\tcommit --trailer \"bug = 42\" -m \"I hate bug\" &&\n+\tgit cat-file commit HEAD >commit.msg &&\n+\tsed -e \"1,/^\\$/d\" commit.msg >actual &&\n+\ttest_cmp expected actual\n+'\n+\n test_expect_success 'multiple -m' '\n \n \t>negative &&\n-- \ngitgitgadget\n\n"},{"id":"419844","messageId":"1722fbad-6ff3-444f-ad3f-59e37b640fc7@gmail.com","threadId":"55356","inReplyTo":"8b8b236a4ffb81a8c6be3f320b878cea1d0f9d7a.1616317135.git.gitgitgadget@gmail.com","subject":"Re: [PATCH v2 2/2] [GSOC] interpret-trailer: easy parse trailer value","fromName":"Bagas Sanjaya","fromEmail":"bagasdotme@gmail.com","sentAt":"2021-03-21T09:17:37Z","receivedAt":"2021-03-21T09:18:31Z","isPatch":true,"sender":{"key":"bagasdotme@gmail.com","avatar":"https://avatars.githubusercontent.com/u/40219486?v=4"},"body":"\nOn 21/03/21 15.58, ZheNing Hu via GitGitGadget wrote:\n> +test_expect_success 'commit --trailer parse @nickname' '\n> +\techo \"I love git\" >file1 &&\n> +\tgit add file1 &&\n> +\tgit commit -m \"yly\" --author=\"batman <email1>\" &&\n> +\techo \"I love git\" >file2 &&\n> +\tgit add file2 &&\n> +\tgit commit -m \"yly\" --author=\"jocker <email2>\" &&\n> +\techo \"I love git\" >file3 &&\n> +\tgit add file3 &&\n> +\tgit commit -m \"yly\" \\\n> +\t--trailer \"Reviewed-by:@bat\" \\\n> +\t--trailer \"Signed-off-by:@jock\" \\\n> +\t--trailer \"Helped-by:@email1\" \\\n> +\t--trailer \"Mentored-by:@email2\" &&\n> +\tgit cat-file commit HEAD >commit.msg &&\n> +\tsed -e \"1,/^\\$/d\" commit.msg >actual &&\n> +\tcat >expected <<-\\EOF &&\n> +\tyly\n> +\n> +\tReviewed-by: batman <email1>\n> +\tSigned-off-by: jocker <email2>\n> +\tHelped-by: batman <email1>\n> +\tMentored-by: jocker <email2>\n> +\tEOF\n> +\ttest_cmp expected actual\n> +'\n> +\n>   test_expect_success 'multiple -m' '\n>   \n>   \t>negative &&\n> +test_expect_success 'trailer parse @nickname' '\n> +\techo \"I love git\" >file1 &&\n> +\tgit add file1 &&\n> +\tgit commit -m \"yly\" --author=\"batman <email1>\" &&\n> +\techo \"I love git\" >file2 &&\n> +\tgit add file2 &&\n> +\tgit commit -m \"yly\" --author=\"jocker <email2>\" &&\n> +\tgit interpret-trailers \\\n> +\t--trailer \"Reviewed-by:@bat\" \\\n> +\t--trailer \"Signed-off-by:@jock\" \\\n> +\t--trailer \"Helped-by:@email1\" \\\n> +\t--trailer \"Mentored-by:@email2\" \\\n> +\tempty >actual &&\n> +\tcat >expected <<-\\EOF &&\n> +\n> +\tReviewed-by: batman <email1>\n> +\tSigned-off-by: jocker <email2>\n> +\tHelped-by: batman <email1>\n> +\tMentored-by: jocker <email2>\n> +\tEOF\n> +\ttest_cmp expected actual\n> +'\n> +\n>   test_expect_success 'without config in another order' '\n>   \tsed -e \"s/ Z\\$/ /\" >expected <<-\\EOF &&\nI think please consider this case: When I add --trailer \"Reviewed-by:@bat\", and there are two\nidentity pairs that match (`batman <email1>` and `batman <email2>`), I need to choose one that\nwill be in the trailer (for example because <email1> is primary email). So a disambiguation\nprompt should be added, something like:\n\n```\nThere are <N> identities that match, please choose one that will be added to the trailer:\n1) batman <email1>\n2) batman <email2>\n...\nn) batman <emailn>\n```\n\nThe prompt can be repeated for each trailer values that are non-unique.\n\nThanks\n\n-- \nAn old man doll... just what I always wanted! - Clara\n"},{"id":"419854","messageId":"CAP8UFD1Oo-eWmoV-1mh1M=pA8+yRUYHy1wg8NvN3bthmCHBfvQ@mail.gmail.com","threadId":"55356","inReplyTo":"8b8b236a4ffb81a8c6be3f320b878cea1d0f9d7a.1616317135.git.gitgitgadget@gmail.com","subject":"Re: [PATCH v2 2/2] [GSOC] interpret-trailer: easy parse trailer value","fromName":"Christian Couder","fromEmail":"christian.couder@gmail.com","sentAt":"2021-03-21T13:15:11Z","receivedAt":"2021-03-21T13:16:42Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"On Sun, Mar 21, 2021 at 9:58 AM ZheNing Hu via GitGitGadget\n<gitgitgadget@gmail.com> wrote:\n>\n> From: ZheNing Hu <adlternative@gmail.com>\n>\n> The original `-trailer` adding some trailers like\n\ns/-trailer/--trailer/\n\n> \"Signed-off-by:C O <Mister@email.com>\" is often too\n> verbose and error-prone.\n\nThe 'trailer.<token>.command' config option can already be used to\nhelp with that, for example:\n\n-------\n$ git config trailer.sign.key \"Signed-off-by: \"\n$ git config trailer.sign.ifexists replace\n$ git config trailer.sign.command \"git log --author='\\$ARG' -1\n--format='format:%aN <%aE>'\"\n$ git interpret-trailers --trailer sign=Linus<<EOF\nsubject\n\nbody\nEOF\nsubject\n\nbody\n\nSigned-off-by: Linus Torvalds <torvalds@linux-foundation.org>\n-------\n\nSo even without this patch, after your first patch that implements\n`git commit --trailer ...`, it should be easy to setup something less\nverbose and less error-prone.\n"},{"id":"419855","messageId":"CAOLTT8TnWdOgxJSza3oiPt3jk478XQ_gSHH-iAAEYtyC7RLdoQ@mail.gmail.com","threadId":"55356","inReplyTo":"CAP8UFD1Oo-eWmoV-1mh1M=pA8+yRUYHy1wg8NvN3bthmCHBfvQ@mail.gmail.com","subject":"Re: [PATCH v2 2/2] [GSOC] interpret-trailer: easy parse trailer value","fromName":"ZheNing Hu","fromEmail":"adlternative@gmail.com","sentAt":"2021-03-21T13:49:56Z","receivedAt":"2021-03-21T13:50:59Z","isPatch":true,"sender":{"key":"adlternative@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58138461?v=4"},"body":"Christian Couder <christian.couder@gmail.com> 于2021年3月21日周日 下午9:15写道：\n>\n> On Sun, Mar 21, 2021 at 9:58 AM ZheNing Hu via GitGitGadget\n> <gitgitgadget@gmail.com> wrote:\n> >\n> > From: ZheNing Hu <adlternative@gmail.com>\n> >\n> > The original `-trailer` adding some trailers like\n>\n> s/-trailer/--trailer/\n>\n> > \"Signed-off-by:C O <Mister@email.com>\" is often too\n> > verbose and error-prone.\n>\n> The 'trailer.<token>.command' config option can already be used to\n> help with that, for example:\n>\n> -------\n> $ git config trailer.sign.key \"Signed-off-by: \"\n> $ git config trailer.sign.ifexists replace\n> $ git config trailer.sign.command \"git log --author='\\$ARG' -1\n> --format='format:%aN <%aE>'\"\n> $ git interpret-trailers --trailer sign=Linus<<EOF\n> subject\n>\n> body\n> EOF\n> subject\n>\n> body\n>\n> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>\n> -------\n>\n> So even without this patch, after your first patch that implements\n> `git commit --trailer ...`, it should be easy to setup something less\n> verbose and less error-prone.\n\nHey, Christian,\n`@nickname` can provides a \"quick\" way for those users\nwho haven't config as you mention. I hope I am not wrong.\n\n--\nZheNing Hu\n"},{"id":"419856","messageId":"xmqq5z1kd2z1.fsf@gitster.g","threadId":"55356","inReplyTo":"CAOLTT8Q7yNscYrYHWJQcsGn67MjWe15nd7SnCEd5QVUG0A6dRg@mail.gmail.com","subject":"Re: [PATCH 2/2] [GSOC] interpret-trailer: easy parse trailer value","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2021-03-21T13:57:06Z","receivedAt":"2021-03-21T13:57:43Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"ZheNing Hu <adlternative@gmail.com> writes:\n\n> Do you think this is appropriate?\n>\n> @@ -370,5 +370,15 @@ int parse_buffer_signed_by_header(const char *buffer,\n>                                   struct strbuf *payload,\n>                                   struct strbuf *signature,\n>                                   const struct git_hash_algo *algop);\n> +/*\n> + * Calling `find_author_by_nickname` to find the \"author <email>\" pair\n> + * in the most recent commit which matches \"--author=name\".\n> + *\n> + * Note that `find_author_by_nickname` is not reusable, because it haven't\n> + * reset flags for parsed objects. The only safe way to use\n> `find_author_by_nickname`\n> + * (without rewriting the revision traversal machinery) is to spawn a\n> + * subprocess and do find_author_by_nickname() in it.\n> + */\n\nTelling people not to add any new caller is good, but everything\nafter \"because\" does not make sense to me.\n\nI do not think calling find_author_by_nickname() in a subprocess\nalone would not help somebody who wants to do this, either.  We'd be\ndoing a moral equivalent of that call, but the result has to be\ncommunicated back to the parent process,\n\nIn the longer term, we'd probably want to have a pre-computed table\nof contributors, like we have precomputed files for reachability\nbitmaps, commit DAG topology, and such, but that is obviously far\noutside of the scope of this series.\n\n> +const char *find_author_by_nickname(const char *name);\n"},{"id":"419857","messageId":"CAOLTT8Tnt_Ai9xyXSYQ9dt4Vh1iViiihiMNEY0fzSGk=Xgw6cA@mail.gmail.com","threadId":"55356","inReplyTo":"1722fbad-6ff3-444f-ad3f-59e37b640fc7@gmail.com","subject":"Re: [PATCH v2 2/2] [GSOC] interpret-trailer: easy parse trailer value","fromName":"ZheNing Hu","fromEmail":"adlternative@gmail.com","sentAt":"2021-03-21T14:04:54Z","receivedAt":"2021-03-21T14:06:13Z","isPatch":true,"sender":{"key":"adlternative@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58138461?v=4"},"body":"> I think please consider this case: When I add --trailer \"Reviewed-by:@bat\", and there are two\n> identity pairs that match (`batman <email1>` and `batman <email2>`), I need to choose one that\n> will be in the trailer (for example because <email1> is primary email). So a disambiguation\n> prompt should be added, something like:\n>\n> ```\n> There are <N> identities that match, please choose one that will be added to the trailer:\n> 1) batman <email1>\n> 2) batman <email2>\n> ...\n> n) batman <emailn>\n> ```\n>\nHi,\n\nI think this kind of prompt will be beneficial to users, temporarily\nadopt the method of\n`find_author_by_nickname()` to get the last match commit \"name <eamil>\" pair.\nIf I want to find all these matched \"name <eamil>\" pairs and exclude\nduplicates, I may need to\nthink about it for a while.\n\n> The prompt can be repeated for each trailer values that are non-unique.\n>\n> Thanks\n>\n> --\n> An old man doll... just what I always wanted! - Clara\n\nThanks.\n--\nZheNing Hu\n"},{"id":"419858","messageId":"CAOLTT8SMUg+gmz84HM-XhGJYJMhYTtZaU5D5GSW34Fxn4o_6TQ@mail.gmail.com","threadId":"55356","inReplyTo":"xmqq5z1kd2z1.fsf@gitster.g","subject":"Re: [PATCH 2/2] [GSOC] interpret-trailer: easy parse trailer value","fromName":"ZheNing Hu","fromEmail":"adlternative@gmail.com","sentAt":"2021-03-21T14:12:57Z","receivedAt":"2021-03-21T14:13:59Z","isPatch":true,"sender":{"key":"adlternative@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58138461?v=4"},"body":"Junio C Hamano <gitster@pobox.com> 于2021年3月21日周日 下午9:57写道：\n>\n> ZheNing Hu <adlternative@gmail.com> writes:\n>\n> > Do you think this is appropriate?\n> >\n> > @@ -370,5 +370,15 @@ int parse_buffer_signed_by_header(const char *buffer,\n> >                                   struct strbuf *payload,\n> >                                   struct strbuf *signature,\n> >                                   const struct git_hash_algo *algop);\n> > +/*\n> > + * Calling `find_author_by_nickname` to find the \"author <email>\" pair\n> > + * in the most recent commit which matches \"--author=name\".\n> > + *\n> > + * Note that `find_author_by_nickname` is not reusable, because it haven't\n> > + * reset flags for parsed objects. The only safe way to use\n> > `find_author_by_nickname`\n> > + * (without rewriting the revision traversal machinery) is to spawn a\n> > + * subprocess and do find_author_by_nickname() in it.\n> > + */\n>\n> Telling people not to add any new caller is good, but everything\n> after \"because\" does not make sense to me.\n>\n> I do not think calling find_author_by_nickname() in a subprocess\n> alone would not help somebody who wants to do this, either.  We'd be\n> doing a moral equivalent of that call, but the result has to be\n> communicated back to the parent process,\n>\n\nWhat I am thinking about here is that `commit --trailer` itself jumps to a\nsub-process to do this, but this does depend on the fact that\n`interpret-trailers`\n itself does not have a traversal, and indeed should not be arbitrarily call it.\n\n> In the longer term, we'd probably want to have a pre-computed table\n> of contributors, like we have precomputed files for reachability\n> bitmaps, commit DAG topology, and such, but that is obviously far\n> outside of the scope of this series.\n>\n\nIndeed this will be a very big project. But `.mailmap` always makes me\nfeel similar.\n\n> > +const char *find_author_by_nickname(const char *name);\n"},{"id":"419860","messageId":"xmqq1rc8cv01.fsf@gitster.g","threadId":"55356","inReplyTo":"1722fbad-6ff3-444f-ad3f-59e37b640fc7@gmail.com","subject":"Re: [PATCH v2 2/2] [GSOC] interpret-trailer: easy parse trailer value","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2021-03-21T16:49:18Z","receivedAt":"2021-03-21T16:50:31Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Bagas Sanjaya <bagasdotme@gmail.com> writes:\n\n> will be in the trailer (for example because <email1> is primary email). So a disambiguation\n> prompt should be added, something like:\n\nNo, it just should error out without going interactive.\n"},{"id":"419861","messageId":"xmqqwnu0bga9.fsf@gitster.g","threadId":"55356","inReplyTo":"CAP8UFD1Oo-eWmoV-1mh1M=pA8+yRUYHy1wg8NvN3bthmCHBfvQ@mail.gmail.com","subject":"Re: [PATCH v2 2/2] [GSOC] interpret-trailer: easy parse trailer value","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2021-03-21T16:52:30Z","receivedAt":"2021-03-21T16:53:15Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Christian Couder <christian.couder@gmail.com> writes:\n\n>> \"Signed-off-by:C O <Mister@email.com>\" is often too\n>> verbose and error-prone.\n>\n> The 'trailer.<token>.command' config option can already be used to\n> help with that, for example:\n>\n> -------\n> $ git config trailer.sign.key \"Signed-off-by: \"\n> $ git config trailer.sign.ifexists replace\n> $ git config trailer.sign.command \"git log --author='\\$ARG' -1\n> --format='format:%aN <%aE>'\"\n> $ git interpret-trailers --trailer sign=Linus<<EOF\n> subject\n>\n> body\n> EOF\n> subject\n>\n> body\n>\n> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>\n> -------\n>\n> So even without this patch, after your first patch that implements\n> `git commit --trailer ...`, it should be easy to setup something less\n> verbose and less error-prone.\n\nIt is nice that it makes the complexity of 2/2 unnecessary ;-)\n"},{"id":"419898","messageId":"CAOLTT8TU+XwLmDQRROHW6iumFgMKok9mi+_OBmN4FbvgWkNb7Q@mail.gmail.com","threadId":"55356","inReplyTo":"xmqqwnu0bga9.fsf@gitster.g","subject":"Re: [PATCH v2 2/2] [GSOC] interpret-trailer: easy parse trailer value","fromName":"ZheNing Hu","fromEmail":"adlternative@gmail.com","sentAt":"2021-03-22T00:39:08Z","receivedAt":"2021-03-22T00:40:25Z","isPatch":true,"sender":{"key":"adlternative@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58138461?v=4"},"body":"Junio C Hamano <gitster@pobox.com> 于2021年3月22日周一 上午12:52写道：\n>\n> Christian Couder <christian.couder@gmail.com> writes:\n>\n> >> \"Signed-off-by:C O <Mister@email.com>\" is often too\n> >> verbose and error-prone.\n> >\n> > The 'trailer.<token>.command' config option can already be used to\n> > help with that, for example:\n> >\n> > -------\n> > $ git config trailer.sign.key \"Signed-off-by: \"\n> > $ git config trailer.sign.ifexists replace\n> > $ git config trailer.sign.command \"git log --author='\\$ARG' -1\n> > --format='format:%aN <%aE>'\"\n> > $ git interpret-trailers --trailer sign=Linus<<EOF\n> > subject\n> >\n> > body\n> > EOF\n> > subject\n> >\n> > body\n> >\n> > Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>\n> > -------\n> >\n> > So even without this patch, after your first patch that implements\n> > `git commit --trailer ...`, it should be easy to setup something less\n> > verbose and less error-prone.\n>\n> It is nice that it makes the complexity of 2/2 unnecessary ;-)\n\nA little frustrated, both `--own-identity` and `@nickname` seem to be\n rejected. I will roll back to the first patch.\n"},{"id":"419908","messageId":"47e8a13f-ce96-f3f3-0f8e-efd685f58e60@gmail.com","threadId":"55356","inReplyTo":"xmqq1rc8cv01.fsf@gitster.g","subject":"Re: [PATCH v2 2/2] [GSOC] interpret-trailer: easy parse trailer value","fromName":"Bagas Sanjaya","fromEmail":"bagasdotme@gmail.com","sentAt":"2021-03-22T06:01:58Z","receivedAt":"2021-03-22T06:03:04Z","isPatch":true,"sender":{"key":"bagasdotme@gmail.com","avatar":"https://avatars.githubusercontent.com/u/40219486?v=4"},"body":"On 21/03/21 23.49, Junio C Hamano wrote:\n> Bagas Sanjaya <bagasdotme@gmail.com> writes:\n> \n>> will be in the trailer (for example because <email1> is primary email). So a disambiguation\n>> prompt should be added, something like:\n> \n> No, it just should error out without going interactive.\n>\n\nI mean the error should be:\n\n```\nerror: @batman match multiple identities:\n1) batman <email1>\n2) batman <email2>\n...\nn) batman <emailn>\n\nPlease disambiguate by running \"git commit --trailer\" with full identity, like:\n     git commit --trailer=\"<someone> <<email>>\" <options>...\n\n```\n\n-- \nAn old man doll... just what I always wanted! - Clara\n"},{"id":"419910","messageId":"CAP8UFD0TKFhpQkAk5apUXpEg=tEhHdZxL9USjfxVSiSyYzLT=w@mail.gmail.com","threadId":"55356","inReplyTo":"CAOLTT8TU+XwLmDQRROHW6iumFgMKok9mi+_OBmN4FbvgWkNb7Q@mail.gmail.com","subject":"Re: [PATCH v2 2/2] [GSOC] interpret-trailer: easy parse trailer value","fromName":"Christian Couder","fromEmail":"christian.couder@gmail.com","sentAt":"2021-03-22T07:26:32Z","receivedAt":"2021-03-22T07:27:41Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"On Mon, Mar 22, 2021 at 1:39 AM ZheNing Hu <adlternative@gmail.com> wrote:\n>\n> Junio C Hamano <gitster@pobox.com> 于2021年3月22日周一 上午12:52写道：\n> >\n> > Christian Couder <christian.couder@gmail.com> writes:\n\n> > > So even without this patch, after your first patch that implements\n> > > `git commit --trailer ...`, it should be easy to setup something less\n> > > verbose and less error-prone.\n> >\n> > It is nice that it makes the complexity of 2/2 unnecessary ;-)\n>\n> A little frustrated, both `--own-identity` and `@nickname` seem to be\n>  rejected. I will roll back to the first patch.\n\nIt's good to want to implement new features, and to come up quickly\nwith patches, but it's also good to give people time on this list to\ndiscuss the goals you would like to achieve, and which features are\nalready available or should be implement to achieve the goals.\n\nThanks for working on this topic anyway!\n"},{"id":"419912","messageId":"CAOLTT8TyEiLXsLAkpO2C+CzWz=uCmtOa0K30Rzx_zydZZ1mBpw@mail.gmail.com","threadId":"55356","inReplyTo":"CAP8UFD0TKFhpQkAk5apUXpEg=tEhHdZxL9USjfxVSiSyYzLT=w@mail.gmail.com","subject":"Re: [PATCH v2 2/2] [GSOC] interpret-trailer: easy parse trailer value","fromName":"ZheNing Hu","fromEmail":"adlternative@gmail.com","sentAt":"2021-03-22T08:28:14Z","receivedAt":"2021-03-22T08:29:17Z","isPatch":true,"sender":{"key":"adlternative@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58138461?v=4"},"body":"Christian Couder <christian.couder@gmail.com> 于2021年3月22日周一 下午3:26写道：\n>\n> On Mon, Mar 22, 2021 at 1:39 AM ZheNing Hu <adlternative@gmail.com> wrote:\n> >\n> > Junio C Hamano <gitster@pobox.com> 于2021年3月22日周一 上午12:52写道：\n> > >\n> > > Christian Couder <christian.couder@gmail.com> writes:\n>\n> > > > So even without this patch, after your first patch that implements\n> > > > `git commit --trailer ...`, it should be easy to setup something less\n> > > > verbose and less error-prone.\n> > >\n> > > It is nice that it makes the complexity of 2/2 unnecessary ;-)\n> >\n> > A little frustrated, both `--own-identity` and `@nickname` seem to be\n> >  rejected. I will roll back to the first patch.\n>\n> It's good to want to implement new features, and to come up quickly\n> with patches, but it's also good to give people time on this list to\n> discuss the goals you would like to achieve, and which features are\n> already available or should be implement to achieve the goals.\n>\n\nI basically started coding after receiving the first reviewer's comment.\nIt seems that I should be more patient.\n\n> Thanks for working on this topic anyway!\n\nThanks, Christian.\n"},{"id":"419959","messageId":"xmqqv99j6rt1.fsf@gitster.g","threadId":"55356","inReplyTo":"CAOLTT8TU+XwLmDQRROHW6iumFgMKok9mi+_OBmN4FbvgWkNb7Q@mail.gmail.com","subject":"Re: [PATCH v2 2/2] [GSOC] interpret-trailer: easy parse trailer value","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2021-03-22T17:07:06Z","receivedAt":"2021-03-22T17:07:47Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"ZheNing Hu <adlternative@gmail.com> writes:\n\n> Junio C Hamano <gitster@pobox.com> 于2021年3月22日周一 上午12:52写道：\n>>\n>> Christian Couder <christian.couder@gmail.com> writes:\n>> ...\n>> > So even without this patch, after your first patch that implements\n>> > `git commit --trailer ...`, it should be easy to setup something less\n>> > verbose and less error-prone.\n>>\n>> It is nice that it makes the complexity of 2/2 unnecessary ;-)\n>\n> A little frustrated, both `--own-identity` and `@nickname` seem to be\n>  rejected. I will roll back to the first patch.\n\nIf existing functionality can be used to achieve the same end result\nwithout any extra effort by end-users, that's a happy endgame, isn't\nit?  There isn't a reason to be frustrated---the users benefit with\nthe new --trailer option without adding (hence having to learn) new\nextra features like --own-ident or @name, which is a big plus.\n\n\n"},{"id":"419970","messageId":"xmqq5z1j6n9e.fsf@gitster.g","threadId":"55356","inReplyTo":"47e8a13f-ce96-f3f3-0f8e-efd685f58e60@gmail.com","subject":"Re: [PATCH v2 2/2] [GSOC] interpret-trailer: easy parse trailer value","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2021-03-22T18:45:17Z","receivedAt":"2021-03-22T18:46:06Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Bagas Sanjaya <bagasdotme@gmail.com> writes:\n\n> I mean the error should be:\n>\n> ```\n> error: @batman match multiple identities:\n> 1) batman <email1>\n> 2) batman <email2>\n> ...\n> n) batman <emailn>\n>\n> Please disambiguate by running \"git commit --trailer\" with full identity, like:\n>     git commit --trailer=\"<someone> <<email>>\" <options>...\n>\n> ```\n\nDetecting error alone is probably prohibitively expensive, as it\ntakes you to scan _all_ commits down to the beginning of time to\npruve that a given pattern matches one and only one author ident.\n\nAssuming that we would pay that cost (I doubt we would want to,\nthough), additional cost to show all possible hits would be small\nand manageable, I think.\n\n"},{"id":"419985","messageId":"CAOLTT8SRbe8bked2X9uOVexPQPLW6E+ON=Fs66fPDLp9eOWn5g@mail.gmail.com","threadId":"55356","inReplyTo":"xmqqv99j6rt1.fsf@gitster.g","subject":"Re: [PATCH v2 2/2] [GSOC] interpret-trailer: easy parse trailer value","fromName":"ZheNing Hu","fromEmail":"adlternative@gmail.com","sentAt":"2021-03-23T05:04:01Z","receivedAt":"2021-03-23T05:05:10Z","isPatch":true,"sender":{"key":"adlternative@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58138461?v=4"},"body":"Junio C Hamano <gitster@pobox.com> 于2021年3月23日周二 上午1:07写道：\n>\n> ZheNing Hu <adlternative@gmail.com> writes:\n>\n> > Junio C Hamano <gitster@pobox.com> 于2021年3月22日周一 上午12:52写道：\n> >>\n> >> Christian Couder <christian.couder@gmail.com> writes:\n> >> ...\n> >> > So even without this patch, after your first patch that implements\n> >> > `git commit --trailer ...`, it should be easy to setup something less\n> >> > verbose and less error-prone.\n> >>\n> >> It is nice that it makes the complexity of 2/2 unnecessary ;-)\n> >\n> > A little frustrated, both `--own-identity` and `@nickname` seem to be\n> >  rejected. I will roll back to the first patch.\n>\n> If existing functionality can be used to achieve the same end result\n> without any extra effort by end-users, that's a happy endgame, isn't\n> it?  There isn't a reason to be frustrated---the users benefit with\n> the new --trailer option without adding (hence having to learn) new\n> extra features like --own-ident or @name, which is a big plus.\n>\n>\n\nThanks, Junio, you are right :)\n"}]}