{"thread":{"id":"58088","subject":"[PATCH 0/3] Add support for mailmap in cat-file","startedAt":"2022-06-30T14:35:59Z","lastAt":"2022-07-30T07:52:22Z","messageCount":68,"participants":["Siddharth Asthana","Phillip Wood","Đoàn Trần Công Danh","Christian Couder","Junio C Hamano","Ævar Arnfjörð Bjarmason","Johannes Schindelin"],"isPatch":true,"patchVersion":1,"patchTotal":3},"messages":[{"id":"458191","messageId":"20220630142444.651948-1-siddharthasthana31@gmail.com","threadId":"58088","inReplyTo":null,"subject":"[PATCH 0/3] Add support for mailmap in cat-file","fromName":"Siddharth Asthana","fromEmail":"siddharthasthana31@gmail.com","sentAt":"2022-06-30T14:24:41Z","receivedAt":"2022-06-30T14:35:59Z","isPatch":true,"sender":{"key":"siddharthasthana31@gmail.com","avatar":"https://avatars.githubusercontent.com/u/53316982?v=4"},"body":"Hi Everyone!\n\nI am working as a GSoC mentee with GitLab organization. My project is\nto add mailmap support in GitLab. GitLab uses git cat-file to get\ncommit and tag contents that are then displayed to the users. This\ncontent which has author, committer or tagger information, could benefit\nfrom passing through the mailmap mechanism, before being sent or\ndisplayed.\n\nSo, this patch series adds mailmap support to the git cat-file command.\nIt does that by adding --[no-]use-mailmap command line option to the\ngit cat-file command. It also adds --[no-]mailmap option as an alias to\n--[no-]use-mailmap.\n\nI would like to thank my mentors, Christian Couder and John Cai, for all\nof their help!\nLooking forward to the reviews!\n\nSiddharth Asthana (3):\n  ident: move commit_rewrite_person() to ident.c\n  ident: rename commit_rewrite_person() to rewrite_ident_line()\n  cat-file: add mailmap support\n\n Documentation/git-cat-file.txt |  6 +++++\n builtin/cat-file.c             | 32 +++++++++++++++++++++-\n cache.h                        |  8 ++++++\n ident.c                        | 45 +++++++++++++++++++++++++++++++\n revision.c                     | 49 ++--------------------------------\n t/t4203-mailmap.sh             | 30 +++++++++++++++++++++\n 6 files changed, 122 insertions(+), 48 deletions(-)\n\n\nbase-commit: e4a4b31577c7419497ac30cebe30d755b97752c5\n-- \n2.37.0.3.g2093cce7fe.dirty\n\n"},{"id":"458192","messageId":"20220630142444.651948-3-siddharthasthana31@gmail.com","threadId":"58088","inReplyTo":"20220630142444.651948-1-siddharthasthana31@gmail.com","subject":"[PATCH 2/3] ident: rename commit_rewrite_person() to rewrite_ident_line()","fromName":"Siddharth Asthana","fromEmail":"siddharthasthana31@gmail.com","sentAt":"2022-06-30T14:24:43Z","receivedAt":"2022-06-30T14:36:02Z","isPatch":true,"sender":{"key":"siddharthasthana31@gmail.com","avatar":"https://avatars.githubusercontent.com/u/53316982?v=4"},"body":"We will be using commit_rewrite_person() in git-cat-file to rewrite\nident line in commit/tag object buffers.\n\nFollowing are the reason for renaming commit_rewrite_person():\n- the function can be used not only on a commit buffer, but also on a\n  tag object buffer, so having \"commit\" in its name is misleading.\n- the function works on the ident line in the commit/tag object buffers,\n  just like \"split_ident_line()\". Since these functions are related they\n  should have similar terms for uniformity.\n\nSigned-off-by: Siddharth Asthana <siddharthasthana31@gmail.com>\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: John Cai <johncai86@gmail.com>\n---\n cache.h    | 2 +-\n ident.c    | 2 +-\n revision.c | 4 ++--\n 3 files changed, 4 insertions(+), 4 deletions(-)\n\ndiff --git a/cache.h b/cache.h\nindex 442bfe5f6a..c8a98d8a80 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -1694,7 +1694,7 @@ int split_ident_line(struct ident_split *, const char *, int);\n  * name and email using mailmap mechanism. Signals a success with\n  * 1 and failure with a 0.\n  */\n-int commit_rewrite_person(struct strbuf *buf, const char *what, struct string_list *mailmap);\n+int rewrite_ident_line(struct strbuf *buf, const char *what, struct string_list *mailmap);\n \n /*\n  * Compare split idents for equality or strict ordering. Note that we\ndiff --git a/ident.c b/ident.c\nindex 8c890bd474..d15f579fd5 100644\n--- a/ident.c\n+++ b/ident.c\n@@ -347,7 +347,7 @@ int split_ident_line(struct ident_split *split, const char *line, int len)\n \treturn 0;\n }\n \n-int commit_rewrite_person(struct strbuf *buf, const char *what, struct string_list *mailmap)\n+int rewrite_ident_line(struct strbuf *buf, const char *what, struct string_list *mailmap)\n {\n \tchar *person, *endp;\n \tsize_t len, namelen, maillen;\ndiff --git a/revision.c b/revision.c\nindex da49e73cd6..0c8243a8e0 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -3790,8 +3790,8 @@ static int commit_match(struct commit *commit, struct rev_info *opt)\n \t\tif (!buf.len)\n \t\t\tstrbuf_addstr(&buf, message);\n \n-\t\tcommit_rewrite_person(&buf, \"\\nauthor \", opt->mailmap);\n-\t\tcommit_rewrite_person(&buf, \"\\ncommitter \", opt->mailmap);\n+\t\trewrite_ident_line(&buf, \"\\nauthor \", opt->mailmap);\n+\t\trewrite_ident_line(&buf, \"\\ncommitter \", opt->mailmap);\n \t}\n \n \t/* Append \"fake\" message parts as needed */\n-- \n2.37.0.3.g2093cce7fe.dirty\n\n"},{"id":"458193","messageId":"20220630142444.651948-2-siddharthasthana31@gmail.com","threadId":"58088","inReplyTo":"20220630142444.651948-1-siddharthasthana31@gmail.com","subject":"[PATCH 1/3] ident: move commit_rewrite_person() to ident.c","fromName":"Siddharth Asthana","fromEmail":"siddharthasthana31@gmail.com","sentAt":"2022-06-30T14:24:42Z","receivedAt":"2022-06-30T14:36:04Z","isPatch":true,"sender":{"key":"siddharthasthana31@gmail.com","avatar":"https://avatars.githubusercontent.com/u/53316982?v=4"},"body":"commit_rewrite_person() is a static function defined in revision.c.\nAs the name suggests, this function can be used to replace author's,\ncommitter's or tagger's name in the commit/tag object buffer.\n\nThis patch moves this function from revision.c to ident.c which contains\nmany other functions related to identification like split_ident_line. By\nmoving this function to ident.c, we intend to use it in git-cat-file to\nreplace committer's, author's and tagger's names and emails with their\ncanonical name and email using the mailmap mechanism. The function\nis moved as is for now to make it clear that there are no other changes,\nbut will be renamed in a following commit.\n\nSigned-off-by: Siddharth Asthana <siddharthasthana31@gmail.com>\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: John Cai <johncai86@gmail.com>\n---\n cache.h    |  8 ++++++++\n ident.c    | 45 +++++++++++++++++++++++++++++++++++++++++++++\n revision.c | 45 ---------------------------------------------\n 3 files changed, 53 insertions(+), 45 deletions(-)\n\ndiff --git a/cache.h b/cache.h\nindex ac5ab4ef9d..442bfe5f6a 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -1688,6 +1688,14 @@ struct ident_split {\n  */\n int split_ident_line(struct ident_split *, const char *, int);\n \n+/*\n+ * Given a commit or tag object buffer, replaces the person's\n+ * (author/committer/tagger) name and email with their canonical\n+ * name and email using mailmap mechanism. Signals a success with\n+ * 1 and failure with a 0.\n+ */\n+int commit_rewrite_person(struct strbuf *buf, const char *what, struct string_list *mailmap);\n+\n /*\n  * Compare split idents for equality or strict ordering. Note that we\n  * compare only the ident part of the line, ignoring any timestamp.\ndiff --git a/ident.c b/ident.c\nindex 89ca5b4700..8c890bd474 100644\n--- a/ident.c\n+++ b/ident.c\n@@ -8,6 +8,7 @@\n #include \"cache.h\"\n #include \"config.h\"\n #include \"date.h\"\n+#include \"mailmap.h\"\n \n static struct strbuf git_default_name = STRBUF_INIT;\n static struct strbuf git_default_email = STRBUF_INIT;\n@@ -346,6 +347,50 @@ int split_ident_line(struct ident_split *split, const char *line, int len)\n \treturn 0;\n }\n \n+int commit_rewrite_person(struct strbuf *buf, const char *what, struct string_list *mailmap)\n+{\n+\tchar *person, *endp;\n+\tsize_t len, namelen, maillen;\n+\tconst char *name;\n+\tconst char *mail;\n+\tstruct ident_split ident;\n+\n+\tperson = strstr(buf->buf, what);\n+\tif (!person)\n+\t\treturn 0;\n+\n+\tperson += strlen(what);\n+\tendp = strchr(person, '\\n');\n+\tif (!endp)\n+\t\treturn 0;\n+\n+\tlen = endp - person;\n+\n+\tif (split_ident_line(&ident, person, len))\n+\t\treturn 0;\n+\n+\tmail = ident.mail_begin;\n+\tmaillen = ident.mail_end - ident.mail_begin;\n+\tname = ident.name_begin;\n+\tnamelen = ident.name_end - ident.name_begin;\n+\n+\tif (map_user(mailmap, &mail, &maillen, &name, &namelen)) {\n+\t\tstruct strbuf namemail = STRBUF_INIT;\n+\n+\t\tstrbuf_addf(&namemail, \"%.*s <%.*s>\",\n+\t\t\t    (int)namelen, name, (int)maillen, mail);\n+\n+\t\tstrbuf_splice(buf, ident.name_begin - buf->buf,\n+\t\t\t      ident.mail_end - ident.name_begin + 1,\n+\t\t\t      namemail.buf, namemail.len);\n+\n+\t\tstrbuf_release(&namemail);\n+\n+\t\treturn 1;\n+\t}\n+\n+\treturn 0;\n+}\n \n static void ident_env_hint(enum want_ident whose_ident)\n {\ndiff --git a/revision.c b/revision.c\nindex 211352795c..da49e73cd6 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -3755,51 +3755,6 @@ int rewrite_parents(struct rev_info *revs, struct commit *commit,\n \treturn 0;\n }\n \n-static int commit_rewrite_person(struct strbuf *buf, const char *what, struct string_list *mailmap)\n-{\n-\tchar *person, *endp;\n-\tsize_t len, namelen, maillen;\n-\tconst char *name;\n-\tconst char *mail;\n-\tstruct ident_split ident;\n-\n-\tperson = strstr(buf->buf, what);\n-\tif (!person)\n-\t\treturn 0;\n-\n-\tperson += strlen(what);\n-\tendp = strchr(person, '\\n');\n-\tif (!endp)\n-\t\treturn 0;\n-\n-\tlen = endp - person;\n-\n-\tif (split_ident_line(&ident, person, len))\n-\t\treturn 0;\n-\n-\tmail = ident.mail_begin;\n-\tmaillen = ident.mail_end - ident.mail_begin;\n-\tname = ident.name_begin;\n-\tnamelen = ident.name_end - ident.name_begin;\n-\n-\tif (map_user(mailmap, &mail, &maillen, &name, &namelen)) {\n-\t\tstruct strbuf namemail = STRBUF_INIT;\n-\n-\t\tstrbuf_addf(&namemail, \"%.*s <%.*s>\",\n-\t\t\t    (int)namelen, name, (int)maillen, mail);\n-\n-\t\tstrbuf_splice(buf, ident.name_begin - buf->buf,\n-\t\t\t      ident.mail_end - ident.name_begin + 1,\n-\t\t\t      namemail.buf, namemail.len);\n-\n-\t\tstrbuf_release(&namemail);\n-\n-\t\treturn 1;\n-\t}\n-\n-\treturn 0;\n-}\n-\n static int commit_match(struct commit *commit, struct rev_info *opt)\n {\n \tint retval;\n-- \n2.37.0.3.g2093cce7fe.dirty\n\n"},{"id":"458194","messageId":"20220630142444.651948-4-siddharthasthana31@gmail.com","threadId":"58088","inReplyTo":"20220630142444.651948-1-siddharthasthana31@gmail.com","subject":"[PATCH 3/3] cat-file: add mailmap support","fromName":"Siddharth Asthana","fromEmail":"siddharthasthana31@gmail.com","sentAt":"2022-06-30T14:24:44Z","receivedAt":"2022-06-30T14:36:06Z","isPatch":true,"sender":{"key":"siddharthasthana31@gmail.com","avatar":"https://avatars.githubusercontent.com/u/53316982?v=4"},"body":"git cat-file is not a plumbing command anymore, especially as it gained\nmore and more high level features like its `--batch-command` mode. So\ntools do use it to get commit and tag contents that are then displayed\nto users. This content which has author, committer or tagger\ninformation, could benefit from passing through the mailmap mechanism,\nbefore being sent or displayed.\n\nThis patch adds --[no-]use-mailmap command line option to the git\ncat-file command. It also adds --[no-]mailmap option as an alias to\n--[no-]use-mailmap.\n\nAt this time, this patch only adds a command line\noption, but perhaps a `cat-file.mailmap` config option could be added as\nwell in the same way as for `git log`.\n\nSigned-off-by: Siddharth Asthana <siddharthasthana31@gmail.com>\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: John Cai <johncai86@gmail.com>\n---\n Documentation/git-cat-file.txt |  6 ++++++\n builtin/cat-file.c             | 32 +++++++++++++++++++++++++++++++-\n t/t4203-mailmap.sh             | 30 ++++++++++++++++++++++++++++++\n 3 files changed, 67 insertions(+), 1 deletion(-)\n\ndiff --git a/Documentation/git-cat-file.txt b/Documentation/git-cat-file.txt\nindex 24a811f0ef..887739c41f 100644\n--- a/Documentation/git-cat-file.txt\n+++ b/Documentation/git-cat-file.txt\n@@ -63,6 +63,12 @@ OPTIONS\n \tor to ask for a \"blob\" with `<object>` being a tag object that\n \tpoints at it.\n \n+--[no-]mailmap::\n+--[no-]use-mailmap::\n+\tUse mailmap file to map author, committer and tagger names\n+\tand email addresses to canonical real names and email addresses.\n+\tSee linkgit:git-shortlog[1].\n+\n --textconv::\n \tShow the content as transformed by a textconv filter. In this case,\n \t`<object>` has to be of the form `<tree-ish>:<path>`, or `:<path>` in\ndiff --git a/builtin/cat-file.c b/builtin/cat-file.c\nindex 50cf38999d..fc02b9f487 100644\n--- a/builtin/cat-file.c\n+++ b/builtin/cat-file.c\n@@ -16,6 +16,7 @@\n #include \"packfile.h\"\n #include \"object-store.h\"\n #include \"promisor-remote.h\"\n+#include \"mailmap.h\"\n \n enum batch_mode {\n \tBATCH_MODE_CONTENTS,\n@@ -36,6 +37,20 @@ struct batch_options {\n \n static const char *force_path;\n \n+static struct string_list mailmap = STRING_LIST_INIT_NODUP;\n+static int use_mailmap;\n+\n+char *replace_idents_using_mailmap(char *object_buf, size_t *size)\n+{\n+\tstruct strbuf sb = STRBUF_INIT;\n+\tstrbuf_attach(&sb, object_buf, *size, *size + 1);\n+\trewrite_ident_line(&sb, \"\\nauthor \", &mailmap);\n+\trewrite_ident_line(&sb, \"\\ncommitter \", &mailmap);\n+\trewrite_ident_line(&sb, \"\\ntagger \", &mailmap);\n+\t*size = sb.len;\n+\treturn strbuf_detach(&sb, NULL);\n+}\n+\n static int filter_object(const char *path, unsigned mode,\n \t\t\t const struct object_id *oid,\n \t\t\t char **buf, unsigned long *size)\n@@ -152,6 +167,9 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,\n \t\tif (!buf)\n \t\t\tdie(\"Cannot read object %s\", obj_name);\n \n+\t\tif (use_mailmap)\n+\t\t\tbuf = replace_idents_using_mailmap(buf, &size);\n+\n \t\t/* otherwise just spit out the data */\n \t\tbreak;\n \n@@ -183,6 +201,9 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,\n \t\t}\n \t\tbuf = read_object_with_reference(the_repository, &oid,\n \t\t\t\t\t\t exp_type_id, &size, NULL);\n+\n+\t\tif (use_mailmap)\n+\t\t\tbuf = replace_idents_using_mailmap(buf, &size);\n \t\tbreak;\n \t}\n \tdefault:\n@@ -348,11 +369,15 @@ static void print_object_or_die(struct batch_options *opt, struct expand_data *d\n \t\tvoid *contents;\n \n \t\tcontents = read_object_file(oid, &type, &size);\n+\n+\t\tif (use_mailmap)\n+\t\t\tcontents = replace_idents_using_mailmap(contents, &size);\n+\n \t\tif (!contents)\n \t\t\tdie(\"object %s disappeared\", oid_to_hex(oid));\n \t\tif (type != data->type)\n \t\t\tdie(\"object %s changed type!?\", oid_to_hex(oid));\n-\t\tif (data->info.sizep && size != data->size)\n+\t\tif (data->info.sizep && size != data->size && !use_mailmap)\n \t\t\tdie(\"object %s changed size!?\", oid_to_hex(oid));\n \n \t\tbatch_write(opt, contents, size);\n@@ -843,6 +868,8 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix)\n \t\tOPT_CMDMODE('s', NULL, &opt, N_(\"show object size\"), 's'),\n \t\tOPT_BOOL(0, \"allow-unknown-type\", &unknown_type,\n \t\t\t  N_(\"allow -s and -t to work with broken/corrupt objects\")),\n+\t\tOPT_BOOL(0, \"use-mailmap\", &use_mailmap, N_(\"use mail map file\")),\n+\t\tOPT_ALIAS(0, \"mailmap\", \"use-mailmap\"),\n \t\t/* Batch mode */\n \t\tOPT_GROUP(N_(\"Batch objects requested on stdin (or --batch-all-objects)\")),\n \t\tOPT_CALLBACK_F(0, \"batch\", &batch, N_(\"format\"),\n@@ -885,6 +912,9 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix)\n \topt_cw = (opt == 'c' || opt == 'w');\n \topt_epts = (opt == 'e' || opt == 'p' || opt == 't' || opt == 's');\n \n+\tif (use_mailmap)\n+\t\tread_mailmap(&mailmap);\n+\n \t/* --batch-all-objects? */\n \tif (opt == 'b')\n \t\tbatch.all_objects = 1;\ndiff --git a/t/t4203-mailmap.sh b/t/t4203-mailmap.sh\nindex 0b2d21ec55..bfddc35d9d 100755\n--- a/t/t4203-mailmap.sh\n+++ b/t/t4203-mailmap.sh\n@@ -963,4 +963,34 @@ test_expect_success SYMLINKS 'symlinks not respected in-tree' '\n \ttest_cmp expect actual\n '\n \n+test_expect_success '--no-use-mailmap disables mailmap in cat-file' '\n+\ttest_when_finished \"rm .mailmap\" &&\n+\tcat >.mailmap <<-EOF &&\n+\tA U Thor <author@example.com> Orig <orig@example.com>\n+\tEOF\n+\tcat >expect <<-EOF &&\n+\tauthor Orig <orig@example.com>\n+\tEOF\n+\tgit cat-file --no-use-mailmap commit HEAD >log &&\n+\tgrep author log >actual &&\n+\tsed -e \"/^author/q\" actual >log &&\n+\tsed -e \"s/ [0-9][0-9]* [-+][0-9][0-9][0-9][0-9]$//\" log >actual &&\n+\ttest_cmp expect actual\n+'\n+\n+test_expect_success '--use-mailmap enables mailmap in cat-file' '\n+\ttest_when_finished \"rm .mailmap\" &&\n+\tcat >.mailmap <<-EOF &&\n+\tA U Thor <author@example.com> Orig <orig@example.com>\n+\tEOF\n+\tcat >expect <<-EOF &&\n+\tauthor A U Thor <author@example.com>\n+\tEOF\n+\tgit cat-file --use-mailmap commit HEAD >log &&\n+\tgrep author log >actual &&\n+\tsed -e \"/^author/q\" actual >log &&\n+\tsed -e \"s/ [0-9][0-9]* [-+][0-9][0-9][0-9][0-9]$//\" log >actual &&\n+\ttest_cmp expect actual\n+'\n+\n test_done\n-- \n2.37.0.3.g2093cce7fe.dirty\n\n"},{"id":"458196","messageId":"ad7fff11-5ab2-d314-5e12-bdf61b854aa6@gmail.com","threadId":"58088","inReplyTo":"20220630142444.651948-3-siddharthasthana31@gmail.com","subject":"Re: [PATCH 2/3] ident: rename commit_rewrite_person() to rewrite_ident_line()","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2022-06-30T15:33:30Z","receivedAt":"2022-06-30T15:34:05Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"Hi Siddharth\n\nWelcome to the list!\n\nOn 30/06/2022 15:24, Siddharth Asthana wrote:\n> We will be using commit_rewrite_person() in git-cat-file to rewrite\n> ident line in commit/tag object buffers.\n> \n> Following are the reason for renaming commit_rewrite_person():\n> - the function can be used not only on a commit buffer, but also on a\n>    tag object buffer, so having \"commit\" in its name is misleading.\n> - the function works on the ident line in the commit/tag object buffers,\n>    just like \"split_ident_line()\". Since these functions are related they\n>    should have similar terms for uniformity.\n\nI'm afraid I'm not sure about this change as the interface for \nsplit_ident_line() and commit_rewrite_person() are not uniform. \nsplit_ident_line() takes a pointer to the beginning of the name in an \nident line and a length. commit_rewrite_person() takes the whole commit \nbuffer and searches for the ident line based on the argument \"what\". I \nagree that having commit in the name of the function is confusing when \nit can be used for a tag, but having line in the name when it takes a \nwhole buffer is also confusing. Maybe buffer_rewrite_person() or \nsomething like that would be clearer?\n\nBest Wishes\n\nPhillip\n\n\n> Signed-off-by: Siddharth Asthana <siddharthasthana31@gmail.com>\n> Mentored-by: Christian Couder <christian.couder@gmail.com>\n> Mentored-by: John Cai <johncai86@gmail.com>\n> ---\n>   cache.h    | 2 +-\n>   ident.c    | 2 +-\n>   revision.c | 4 ++--\n>   3 files changed, 4 insertions(+), 4 deletions(-)\n> \n> diff --git a/cache.h b/cache.h\n> index 442bfe5f6a..c8a98d8a80 100644\n> --- a/cache.h\n> +++ b/cache.h\n> @@ -1694,7 +1694,7 @@ int split_ident_line(struct ident_split *, const char *, int);\n>    * name and email using mailmap mechanism. Signals a success with\n>    * 1 and failure with a 0.\n>    */\n> -int commit_rewrite_person(struct strbuf *buf, const char *what, struct string_list *mailmap);\n> +int rewrite_ident_line(struct strbuf *buf, const char *what, struct string_list *mailmap);\n>   \n>   /*\n>    * Compare split idents for equality or strict ordering. Note that we\n> diff --git a/ident.c b/ident.c\n> index 8c890bd474..d15f579fd5 100644\n> --- a/ident.c\n> +++ b/ident.c\n> @@ -347,7 +347,7 @@ int split_ident_line(struct ident_split *split, const char *line, int len)\n>   \treturn 0;\n>   }\n>   \n> -int commit_rewrite_person(struct strbuf *buf, const char *what, struct string_list *mailmap)\n> +int rewrite_ident_line(struct strbuf *buf, const char *what, struct string_list *mailmap)\n>   {\n>   \tchar *person, *endp;\n>   \tsize_t len, namelen, maillen;\n> diff --git a/revision.c b/revision.c\n> index da49e73cd6..0c8243a8e0 100644\n> --- a/revision.c\n> +++ b/revision.c\n> @@ -3790,8 +3790,8 @@ static int commit_match(struct commit *commit, struct rev_info *opt)\n>   \t\tif (!buf.len)\n>   \t\t\tstrbuf_addstr(&buf, message);\n>   \n> -\t\tcommit_rewrite_person(&buf, \"\\nauthor \", opt->mailmap);\n> -\t\tcommit_rewrite_person(&buf, \"\\ncommitter \", opt->mailmap);\n> +\t\trewrite_ident_line(&buf, \"\\nauthor \", opt->mailmap);\n> +\t\trewrite_ident_line(&buf, \"\\ncommitter \", opt->mailmap);\n>   \t}\n>   \n>   \t/* Append \"fake\" message parts as needed */\n"},{"id":"458198","messageId":"61074b4c-c48f-da89-5d03-b280b9c4fedf@gmail.com","threadId":"58088","inReplyTo":"20220630142444.651948-4-siddharthasthana31@gmail.com","subject":"Re: [PATCH 3/3] cat-file: add mailmap support","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2022-06-30T15:50:29Z","receivedAt":"2022-06-30T15:50:35Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"Hi Siddharth\n\nOn 30/06/2022 15:24, Siddharth Asthana wrote:\n> git cat-file is not a plumbing command anymore, especially as it gained\n> more and more high level features like its `--batch-command` mode. \n\ncat-file is definitely a plumbing command as it is intended to be used \nby scripts. It has a number of features that are used by porcelain \ncommands but that does not make cat-file itself porcelain.\n\n> So\n> tools do use it to get commit and tag contents that are then displayed\n> to users. This content which has author, committer or tagger\n> information, could benefit from passing through the mailmap mechanism,\n> before being sent or displayed.\n> \n> This patch adds --[no-]use-mailmap command line option to the git\n> cat-file command. It also adds --[no-]mailmap option as an alias to\n> --[no-]use-mailmap.\n\nI don't think we need an alias for this option, it'll just end up \nconfusing people.\n\n> At this time, this patch only adds a command line\n> option, but perhaps a `cat-file.mailmap` config option could be added as\n> well in the same way as for `git log`.\n\nAs cat-file is a plumbing command that is used by scripts we should not \nadd a config option for this as it would potentially break those scripts.\n\nI like the idea of adding mailmap support to cat-file and I think this \npatch is definitely going in the right direction.\n\n> +char *replace_idents_using_mailmap(char *object_buf, size_t *size)\n> +{\n> +\tstruct strbuf sb = STRBUF_INIT;\n> +\tstrbuf_attach(&sb, object_buf, *size, *size + 1);\n\nI'm worried by this as I don't think we really own the buffer returned \nby read_object_file(). git maintains a cache of objects it has loaded \nand if this strbuf grows when the author is rewritten then the pointer \nstored in the cache will become invalid. If you look at the code in \nrevision.c you'll see that commit_rewrite_person() is called on a copy \nof the original object.\n\n> +\trewrite_ident_line(&sb, \"\\nauthor \", &mailmap);\n> +\trewrite_ident_line(&sb, \"\\ncommitter \", &mailmap);\n> +\trewrite_ident_line(&sb, \"\\ntagger \", &mailmap);\n> +\t*size = sb.len;\n> +\treturn strbuf_detach(&sb, NULL);\n> +}\n> [...]\n> +test_expect_success '--no-use-mailmap disables mailmap in cat-file' '\n> +\ttest_when_finished \"rm .mailmap\" &&\n> +\tcat >.mailmap <<-EOF &&\n> +\tA U Thor <author@example.com> Orig <orig@example.com>\n> +\tEOF\n> +\tcat >expect <<-EOF &&\n> +\tauthor Orig <orig@example.com>\n> +\tEOF\n> +\tgit cat-file --no-use-mailmap commit HEAD >log &&\n> +\tgrep author log >actual &&\n> +\tsed -e \"/^author/q\" actual >log &&\n\nThis line does not have any effect on the contents of log\n\n> +\tsed -e \"s/ [0-9][0-9]* [-+][0-9][0-9][0-9][0-9]$//\" log >actual &&\n\nI think you can simplify this series of commands to do\n\tgit cat-file ... >log\n\tsed -n \"/^author /s/\\([^>]*>\\).*/\\1/p\" log >actual\n\nBest Wishes\n\nPhillip\n"},{"id":"458200","messageId":"Yr3Iii8rRfnXzoUI@danh.dev","threadId":"58088","inReplyTo":"20220630142444.651948-2-siddharthasthana31@gmail.com","subject":"Re: [PATCH 1/3] ident: move commit_rewrite_person() to ident.c","fromName":"Đoàn Trần Công Danh","fromEmail":"congdanhqx@gmail.com","sentAt":"2022-06-30T16:00:10Z","receivedAt":"2022-06-30T16:00:19Z","isPatch":true,"sender":{"key":"congdanhqx@gmail.com","avatar":"https://avatars.githubusercontent.com/u/42673067?v=4"},"body":"On 2022-06-30 19:54:42+0530, Siddharth Asthana <siddharthasthana31@gmail.com> wrote:\n> commit_rewrite_person() is a static function defined in revision.c.\n> As the name suggests, this function can be used to replace author's,\n> committer's or tagger's name in the commit/tag object buffer.\n> \n> This patch moves this function from revision.c to ident.c which contains\n> many other functions related to identification like split_ident_line. By\n> moving this function to ident.c, we intend to use it in git-cat-file to\n> replace committer's, author's and tagger's names and emails with their\n> canonical name and email using the mailmap mechanism. The function\n> is moved as is for now to make it clear that there are no other changes,\n> but will be renamed in a following commit.\n> \n> Signed-off-by: Siddharth Asthana <siddharthasthana31@gmail.com>\n> Mentored-by: Christian Couder <christian.couder@gmail.com>\n> Mentored-by: John Cai <johncai86@gmail.com>\n> ---\n>  cache.h    |  8 ++++++++\n>  ident.c    | 45 +++++++++++++++++++++++++++++++++++++++++++++\n>  revision.c | 45 ---------------------------------------------\n>  3 files changed, 53 insertions(+), 45 deletions(-)\n> \n> diff --git a/cache.h b/cache.h\n> index ac5ab4ef9d..442bfe5f6a 100644\n> --- a/cache.h\n> +++ b/cache.h\n> @@ -1688,6 +1688,14 @@ struct ident_split {\n>   */\n>  int split_ident_line(struct ident_split *, const char *, int);\n>  \n> +/*\n> + * Given a commit or tag object buffer, replaces the person's\n> + * (author/committer/tagger) name and email with their canonical\n> + * name and email using mailmap mechanism. Signals a success with\n> + * 1 and failure with a 0.\n\nI'm not sure if this is important or not.\nHowever, in this project, a function which does something usually\nreturn 0 on success and a negative integer on failure.\n\nHowever, the old code is there, so ...\n\n> + */\n> +int commit_rewrite_person(struct strbuf *buf, const char *what, struct string_list *mailmap);\n> +\n>  /*\n>   * Compare split idents for equality or strict ordering. Note that we\n>   * compare only the ident part of the line, ignoring any timestamp.\n> diff --git a/ident.c b/ident.c\n> index 89ca5b4700..8c890bd474 100644\n> --- a/ident.c\n> +++ b/ident.c\n> @@ -8,6 +8,7 @@\n>  #include \"cache.h\"\n>  #include \"config.h\"\n>  #include \"date.h\"\n> +#include \"mailmap.h\"\n>  \n>  static struct strbuf git_default_name = STRBUF_INIT;\n>  static struct strbuf git_default_email = STRBUF_INIT;\n> @@ -346,6 +347,50 @@ int split_ident_line(struct ident_split *split, const char *line, int len)\n>  \treturn 0;\n>  }\n>  \n> +int commit_rewrite_person(struct strbuf *buf, const char *what, struct string_list *mailmap)\n> +{\n> +\tchar *person, *endp;\n> +\tsize_t len, namelen, maillen;\n> +\tconst char *name;\n> +\tconst char *mail;\n> +\tstruct ident_split ident;\n> +\n> +\tperson = strstr(buf->buf, what);\n> +\tif (!person)\n> +\t\treturn 0;\n> +\n> +\tperson += strlen(what);\n> +\tendp = strchr(person, '\\n');\n> +\tif (!endp)\n> +\t\treturn 0;\n> +\n> +\tlen = endp - person;\n> +\n> +\tif (split_ident_line(&ident, person, len))\n> +\t\treturn 0;\n> +\n> +\tmail = ident.mail_begin;\n> +\tmaillen = ident.mail_end - ident.mail_begin;\n> +\tname = ident.name_begin;\n> +\tnamelen = ident.name_end - ident.name_begin;\n> +\n> +\tif (map_user(mailmap, &mail, &maillen, &name, &namelen)) {\n> +\t\tstruct strbuf namemail = STRBUF_INIT;\n> +\n> +\t\tstrbuf_addf(&namemail, \"%.*s <%.*s>\",\n> +\t\t\t    (int)namelen, name, (int)maillen, mail);\n> +\n> +\t\tstrbuf_splice(buf, ident.name_begin - buf->buf,\n> +\t\t\t      ident.mail_end - ident.name_begin + 1,\n> +\t\t\t      namemail.buf, namemail.len);\n> +\n> +\t\tstrbuf_release(&namemail);\n> +\n> +\t\treturn 1;\n> +\t}\n> +\n> +\treturn 0;\n> +}\n>  \n>  static void ident_env_hint(enum want_ident whose_ident)\n>  {\n> diff --git a/revision.c b/revision.c\n> index 211352795c..da49e73cd6 100644\n> --- a/revision.c\n> +++ b/revision.c\n> @@ -3755,51 +3755,6 @@ int rewrite_parents(struct rev_info *revs, struct commit *commit,\n>  \treturn 0;\n>  }\n>  \n> -static int commit_rewrite_person(struct strbuf *buf, const char *what, struct string_list *mailmap)\n> -{\n> -\tchar *person, *endp;\n> -\tsize_t len, namelen, maillen;\n> -\tconst char *name;\n> -\tconst char *mail;\n> -\tstruct ident_split ident;\n> -\n> -\tperson = strstr(buf->buf, what);\n> -\tif (!person)\n> -\t\treturn 0;\n> -\n> -\tperson += strlen(what);\n> -\tendp = strchr(person, '\\n');\n> -\tif (!endp)\n> -\t\treturn 0;\n> -\n> -\tlen = endp - person;\n> -\n> -\tif (split_ident_line(&ident, person, len))\n> -\t\treturn 0;\n> -\n> -\tmail = ident.mail_begin;\n> -\tmaillen = ident.mail_end - ident.mail_begin;\n> -\tname = ident.name_begin;\n> -\tnamelen = ident.name_end - ident.name_begin;\n> -\n> -\tif (map_user(mailmap, &mail, &maillen, &name, &namelen)) {\n> -\t\tstruct strbuf namemail = STRBUF_INIT;\n> -\n> -\t\tstrbuf_addf(&namemail, \"%.*s <%.*s>\",\n> -\t\t\t    (int)namelen, name, (int)maillen, mail);\n> -\n> -\t\tstrbuf_splice(buf, ident.name_begin - buf->buf,\n> -\t\t\t      ident.mail_end - ident.name_begin + 1,\n> -\t\t\t      namemail.buf, namemail.len);\n> -\n> -\t\tstrbuf_release(&namemail);\n> -\n> -\t\treturn 1;\n> -\t}\n> -\n> -\treturn 0;\n> -}\n> -\n>  static int commit_match(struct commit *commit, struct rev_info *opt)\n>  {\n>  \tint retval;\n> -- \n> 2.37.0.3.g2093cce7fe.dirty\n> \n\n-- \nDanh\n"},{"id":"458202","messageId":"9b33bbc3-1781-6655-d6ef-f0793bdd0951@gmail.com","threadId":"58088","inReplyTo":"61074b4c-c48f-da89-5d03-b280b9c4fedf@gmail.com","subject":"Re: [PATCH 3/3] cat-file: add mailmap support","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2022-06-30T16:36:34Z","receivedAt":"2022-06-30T16:36:41Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"On 30/06/2022 16:50, Phillip Wood wrote:\n>> +char *replace_idents_using_mailmap(char *object_buf, size_t *size)\n>> +{\n>> +    struct strbuf sb = STRBUF_INIT;\n>> +    strbuf_attach(&sb, object_buf, *size, *size + 1);\n> \n> I'm worried by this as I don't think we really own the buffer returned \n> by read_object_file(). git maintains a cache of objects it has loaded \n> and if this strbuf grows when the author is rewritten then the pointer \n> stored in the cache will become invalid. If you look at the code in \n> revision.c you'll see that commit_rewrite_person() is called on a copy \n> of the original object.\n\nSorry ignore that, looking through the code again we do own object_buf \nso this is fine.\n\nSorry for the confusion\n\nPhillip\n\n>> +    rewrite_ident_line(&sb, \"\\nauthor \", &mailmap);\n>> +    rewrite_ident_line(&sb, \"\\ncommitter \", &mailmap);\n>> +    rewrite_ident_line(&sb, \"\\ntagger \", &mailmap);\n>> +    *size = sb.len;\n>> +    return strbuf_detach(&sb, NULL);\n>> +}\n>> [...]\n>> +test_expect_success '--no-use-mailmap disables mailmap in cat-file' '\n>> +    test_when_finished \"rm .mailmap\" &&\n>> +    cat >.mailmap <<-EOF &&\n>> +    A U Thor <author@example.com> Orig <orig@example.com>\n>> +    EOF\n>> +    cat >expect <<-EOF &&\n>> +    author Orig <orig@example.com>\n>> +    EOF\n>> +    git cat-file --no-use-mailmap commit HEAD >log &&\n>> +    grep author log >actual &&\n>> +    sed -e \"/^author/q\" actual >log &&\n> \n> This line does not have any effect on the contents of log\n> \n>> +    sed -e \"s/ [0-9][0-9]* [-+][0-9][0-9][0-9][0-9]$//\" log >actual &&\n> \n> I think you can simplify this series of commands to do\n>      git cat-file ... >log\n>      sed -n \"/^author /s/\\([^>]*>\\).*/\\1/p\" log >actual\n> \n> Best Wishes\n> \n> Phillip\n"},{"id":"458206","messageId":"CAP8UFD0AjU3_6URpVYafYTxYSTPeX2zw-PLwL1b5rTiQY5EvUw@mail.gmail.com","threadId":"58088","inReplyTo":"ad7fff11-5ab2-d314-5e12-bdf61b854aa6@gmail.com","subject":"Re: [PATCH 2/3] ident: rename commit_rewrite_person() to rewrite_ident_line()","fromName":"Christian Couder","fromEmail":"christian.couder@gmail.com","sentAt":"2022-06-30T16:55:53Z","receivedAt":"2022-06-30T16:56:07Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"Hi Phillip,\n\nOn Thu, Jun 30, 2022 at 5:33 PM Phillip Wood <phillip.wood123@gmail.com> wrote:\n\n> On 30/06/2022 15:24, Siddharth Asthana wrote:\n> > We will be using commit_rewrite_person() in git-cat-file to rewrite\n> > ident line in commit/tag object buffers.\n\ns/line/lines/\n\n> > Following are the reason for renaming commit_rewrite_person():\n> > - the function can be used not only on a commit buffer, but also on a\n> >    tag object buffer, so having \"commit\" in its name is misleading.\n> > - the function works on the ident line in the commit/tag object buffers,\n> >    just like \"split_ident_line()\". Since these functions are related they\n> >    should have similar terms for uniformity.\n>\n> I'm afraid I'm not sure about this change as the interface for\n> split_ident_line() and commit_rewrite_person() are not uniform.\n> split_ident_line() takes a pointer to the beginning of the name in an\n> ident line and a length. commit_rewrite_person() takes the whole commit\n> buffer and searches for the ident line based on the argument \"what\". I\n> agree that having commit in the name of the function is confusing when\n> it can be used for a tag, but having line in the name when it takes a\n> whole buffer is also confusing.\n\nIt takes a whole buffer but it rewrites only ident lines, so maybe\n\"rewrite_ident_lines()\" (so with \"lines\" instead of \"line\").\n\n> Maybe buffer_rewrite_person() or\n> something like that would be clearer?\n\nI don't think \"person\" is better than \"ident\" for this, and I think\nit's better to use the same name for it in split_ident_line() and the\nfunction we are renaming.\n\nIt's true that we are not rewriting the date, so maybe\n\"rewrite_person_in_ident_lines()\".\n\nThanks,\nChristian.\n"},{"id":"458208","messageId":"CAP8UFD2tYzoKSr7HnQ+LbCE+YWoNqo3qPQrbr7ZWAMnDt+ajCg@mail.gmail.com","threadId":"58088","inReplyTo":"61074b4c-c48f-da89-5d03-b280b9c4fedf@gmail.com","subject":"Re: [PATCH 3/3] cat-file: add mailmap support","fromName":"Christian Couder","fromEmail":"christian.couder@gmail.com","sentAt":"2022-06-30T17:07:00Z","receivedAt":"2022-06-30T17:07:15Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"Hi Phillip,\n\nOn Thu, Jun 30, 2022 at 5:50 PM Phillip Wood <phillip.wood123@gmail.com> wrote:\n> On 30/06/2022 15:24, Siddharth Asthana wrote:\n> > git cat-file is not a plumbing command anymore, especially as it gained\n> > more and more high level features like its `--batch-command` mode.\n>\n> cat-file is definitely a plumbing command as it is intended to be used\n> by scripts. It has a number of features that are used by porcelain\n> commands but that does not make cat-file itself porcelain.\n\nOk, so maybe:\n\n\"Even if git cat-file is a plumbing command, it has gained more and\nmore high level features like its `--batch-command` mode.\"\n\n> > So\n> > tools do use it to get commit and tag contents that are then displayed\n> > to users. This content which has author, committer or tagger\n> > information, could benefit from passing through the mailmap mechanism,\n> > before being sent or displayed.\n> >\n> > This patch adds --[no-]use-mailmap command line option to the git\n> > cat-file command. It also adds --[no-]mailmap option as an alias to\n> > --[no-]use-mailmap.\n>\n> I don't think we need an alias for this option, it'll just end up\n> confusing people.\n\nI am not sure if people would be more confused by the alias or by the\nfact that the \"--[no-]mailmap\" alias works for `git log` but not `git\ncat-file`.\n\n> > At this time, this patch only adds a command line\n> > option, but perhaps a `cat-file.mailmap` config option could be added as\n> > well in the same way as for `git log`.\n>\n> As cat-file is a plumbing command that is used by scripts we should not\n> add a config option for this as it would potentially break those scripts.\n\nYeah, we could either remove this small paragraph or add the\nexplanation you give.\n\n> I like the idea of adding mailmap support to cat-file and I think this\n> patch is definitely going in the right direction.\n\nThanks!\n\n> > +test_expect_success '--no-use-mailmap disables mailmap in cat-file' '\n> > +     test_when_finished \"rm .mailmap\" &&\n> > +     cat >.mailmap <<-EOF &&\n> > +     A U Thor <author@example.com> Orig <orig@example.com>\n> > +     EOF\n> > +     cat >expect <<-EOF &&\n> > +     author Orig <orig@example.com>\n> > +     EOF\n> > +     git cat-file --no-use-mailmap commit HEAD >log &&\n> > +     grep author log >actual &&\n> > +     sed -e \"/^author/q\" actual >log &&\n>\n> This line does not have any effect on the contents of log\n>\n> > +     sed -e \"s/ [0-9][0-9]* [-+][0-9][0-9][0-9][0-9]$//\" log >actual &&\n>\n> I think you can simplify this series of commands to do\n>         git cat-file ... >log\n>         sed -n \"/^author /s/\\([^>]*>\\).*/\\1/p\" log >actual\n\nThanks for the suggestion!\n"},{"id":"458253","messageId":"xmqqpmipdf48.fsf@gitster.g","threadId":"58088","inReplyTo":"20220630142444.651948-1-siddharthasthana31@gmail.com","subject":"Re: [PATCH 0/3] Add support for mailmap in cat-file","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-06-30T21:18:47Z","receivedAt":"2022-06-30T21:18:54Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Siddharth Asthana <siddharthasthana31@gmail.com> writes:\n\n> So, this patch series adds mailmap support to the git cat-file command.\n> It does that by adding --[no-]use-mailmap command line option to the\n> git cat-file command. It also adds --[no-]mailmap option as an alias to\n> --[no-]use-mailmap.\n\nSo does this kick in only with \"git cat-file commit <object>\" and\nnever with \"git cat-file $type\" for non-commit object types?  For a\npayload like CREDITS file, people may want the blob contents\nfiltered by applying the mailmap, so limiting it to only commits may\nor may not be the best idea.\n\nHow does/should this interact with \"git cat-file -p\"?\n\nDoes it also work with the batch mode?\n\nFor a single-request-single-answer invocation like \"git cat-file\ncommit <object>\", I think a \"--[no-]use-mailmap\" option is OK, but\nfor something like the batch mode, we may want a way to obtain both\nthe original and mapped name(s).  E.g. with this option in effect,\nin addition to the \"author\" and \"committer\" headers of the commit,\nthe output may get a \"mailmap-author\" and \"mailmap-committer\" fake\nheaders that show the mapped idents.\n\nSoliciting too many questions mean the cover letter is doing a good\njob to pique interest from readers, and is not doing a good job to\nexplain adequately what it really does ;-)\n\nLet's read on.\n"},{"id":"458273","messageId":"xmqqletddegb.fsf@gitster.g","threadId":"58088","inReplyTo":"CAP8UFD2tYzoKSr7HnQ+LbCE+YWoNqo3qPQrbr7ZWAMnDt+ajCg@mail.gmail.com","subject":"Re: [PATCH 3/3] cat-file: add mailmap support","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-06-30T21:33:08Z","receivedAt":"2022-06-30T21:33: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> \"Even if git cat-file is a plumbing command, it has gained more and\n> more high level features like its `--batch-command` mode.\"\n\nWhat batch-command and batch do does not sound like \"high level\" at\nall.  It is just \"instead of invoking separate process to ask about\neach individual object, a single process answers the same low level\nrequests\".\n\nIndependent of what this \"The output from 'cat-file commit' is\ntweaked\" feature, I wonder if we want a command that can be used as\na filter.  Just like \"git name-rev --stdin\" reads a stream of text,\nfinds commit-looking references in it, and annotates them, the\ncommand (e.g. \"git mailmap\") would find ident-looking strings and\nreplaces with the mapped results, or something.\n\n>> > At this time, this patch only adds a command line\n>> > option, but perhaps a `cat-file.mailmap` config option could be added as\n>> > well in the same way as for `git log`.\n>>\n>> As cat-file is a plumbing command that is used by scripts we should not\n>> add a config option for this as it would potentially break those scripts.\n\nAbsolutely.\n"},{"id":"458291","messageId":"xmqqo7y9buu9.fsf@gitster.g","threadId":"58088","inReplyTo":"20220630142444.651948-2-siddharthasthana31@gmail.com","subject":"Re: [PATCH 1/3] ident: move commit_rewrite_person() to ident.c","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-06-30T23:22:06Z","receivedAt":"2022-06-30T23:22:17Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Siddharth Asthana <siddharthasthana31@gmail.com> writes:\n\n> +/*\n> + * Given a commit or tag object buffer, replaces the person's\n\nI do not think you should refer to \"or tag\" at this point.  It is\nnot designed to be used by anything other than a commit, and nobody\npasses a tag in the original code, or even after this patch is\napplied.\n\n> + * (author/committer/tagger) name and email with their canonical\n> + * name and email using mailmap mechanism. Signals a success with\n\n\"using\" -> \"using the\"\n\n> + * 1 and failure with a 0.\n\nI do not think 0 signals a failure.  If it makes changes, then the\nfunction returns a non-zero value.  0 only indicates \"we made no\nmodification to the buffer\".\n\n> +int commit_rewrite_person(struct strbuf *buf, const char *what, struct string_list *mailmap)\n> +{\n> +\tchar *person, *endp;\n> +\tsize_t len, namelen, maillen;\n> +\tconst char *name;\n> +\tconst char *mail;\n> +\tstruct ident_split ident;\n> +\n> +\tperson = strstr(buf->buf, what);\n> +\tif (!person)\n> +\t\treturn 0;\n\nI do not think it is a good idea to expose this as a public function\nas is, especially given that what you have to pass in \"what\" is a\nbit awkward.  The function is designed to find and replace an ident\nstring in the header part, and the way it avoids a random occurence\nof author Siddharth Asthana <si...@gmail.com> in the text, not\nnececessarily in the header, is by insisting \"author\" to appear at\nthe beginning of line by passing \"\\nauthor \" as \"what\".\n\nAlso as you can see, the implementation does not make *any* effort\nto limit itself to the commit/tag header by locating the blank line\nthat appears after the header part and stopping the search there.\nThat may not be *your* bug, but should be fixed before exposing it\nas a public function and inflicting its bug to more callers.\n\nAlso the interface forces the caller to make multiple calls if it\nwants to rewrite idents on multiple headers.  It shouldn't be the\ncase.\n\nTo support the existing caller better, it should be updated to\n\n * take one or more header names (like \"author\", \"committer\"), make\n   a single pass in the input buffer to locate these headers and\n   replace idents on them;\n\n * stop at the end of header, ensuring that nothing in the body of\n   the commit object is modified.\n\nAlternatively, it may not be a bad idea to simplify the interface so\nthat _all_ headers are subject to be rewritten, without any need to\nthe \"what\" parameter.  If you want to go that route, then you would\nprobably have a loop over buf->buf that iterates one line at a time,\nstopping at the first empty line that denotes the end of header. For\neach line, you'd skip to the first SP that is past the header name,\nsee if split_ident_line() thinks the line it got indeed has an\nident, and use map_user() to the ident if it found.  Do that for\neach line and you are done when you reached the end of the header.\n\nOnce we fix the external interface like so while being a static\nfunction inside revision.c and update its two callers (which will\nbecome just a single caller), we can move and expose it as a public\nfunction.\n\nThanks.\n"},{"id":"458292","messageId":"xmqqa69tbue8.fsf@gitster.g","threadId":"58088","inReplyTo":"20220630142444.651948-3-siddharthasthana31@gmail.com","subject":"Re: [PATCH 2/3] ident: rename commit_rewrite_person() to rewrite_ident_line()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-06-30T23:31:43Z","receivedAt":"2022-06-30T23:31:54Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Siddharth Asthana <siddharthasthana31@gmail.com> writes:\n\n> We will be using commit_rewrite_person() in git-cat-file to rewrite\n> ident line in commit/tag object buffers.\n>\n> Following are the reason for renaming commit_rewrite_person():\n> - the function can be used not only on a commit buffer, but also on a\n>   tag object buffer, so having \"commit\" in its name is misleading.\n> - the function works on the ident line in the commit/tag object buffers,\n>   just like \"split_ident_line()\". Since these functions are related they\n>   should have similar terms for uniformity.\n\n\"ident\" is good (so is \"person\" in the original).\n\n\"rewrite\" is not quite good, as you do not convey what kind of\nrewrite you are doing (it is not likely that you are upcasing their\nnames, but from \"rewrite\" you cannot tell that is the case).  We\nshould have \"mailmap\" somewhere in its name.\n\n\"line\" is not good at all.  This function receives an entire buffer,\nnot just a single line that was located by the caller and rewrites\nthat line.  \"buffer\" might be an improvement over \"line\", but as I\nalluded to in my review on [1/3], I think this function should limit\nitself only to the header part of the commit/tag buffer, so \"header\"\nwould be the word you want in its name.\n\nOnce we say \"mailmap\", there is not much point in saying ident or\nperson (as \"mailmap\" is only about the ident/person).  So\n\n  int apply_mailmap_to_header(struct strbuf *, struct string_list *mailmap)\n\nor something?\n\n> Signed-off-by: Siddharth Asthana <siddharthasthana31@gmail.com>\n> Mentored-by: Christian Couder <christian.couder@gmail.com>\n> Mentored-by: John Cai <johncai86@gmail.com>\n\nI think these are the other way around.  With help from two people,\nyou wrote the patch and the final step before sending it out to the\nlist is your sign-off.  Chronologically, in the above, your sign-off\nshould come at the end.\n"},{"id":"458295","messageId":"220701.86sfnlbu0j.gmgdl@evledraar.gmail.com","threadId":"58088","inReplyTo":"20220630142444.651948-4-siddharthasthana31@gmail.com","subject":"Re: [PATCH 3/3] cat-file: add mailmap support","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-06-30T23:36:40Z","receivedAt":"2022-06-30T23:40:05Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Thu, Jun 30 2022, Siddharth Asthana wrote:\n\n> git cat-file is not a plumbing command anymore, especially as it gained\n> more and more high level features like its `--batch-command` mode. So\n> tools do use it to get commit and tag contents that are then displayed\n> to users. This content which has author, committer or tagger\n> information, could benefit from passing through the mailmap mechanism,\n> before being sent or displayed.\n>\n> This patch adds --[no-]use-mailmap command line option to the git\n> cat-file command. It also adds --[no-]mailmap option as an alias to\n> --[no-]use-mailmap.\n\nI think I know the answer, but I think it would be helpful to discuss\nthe underlying motivations too. I.e. an obvious alternative is \"why not\njust get this information out of git show/log then?\".\n\nThe \"I think I know the answer\" being that I suspect this is to cater to\ngitaly having persistent \"cat-file\" processes around, whereas for \"git\nlog\" it would entail spinning up a new process per-request.\n\nBut maybe I'm missing something :)\n\nSo not as a blocker for this change, which I think can be made small\nenough to be justified in cat-file, but just for context: If \"git log\"\nhad a similar --batch mode, would there be a need for this change, or is\nthis just adding a common case to \"cat-file\" to \"tide us over\" (as it\nwere) while that sort of thing doesn't exist yet (and maybe never will\n:()?\n\n"},{"id":"458296","messageId":"xmqq4k01btxl.fsf@gitster.g","threadId":"58088","inReplyTo":"20220630142444.651948-4-siddharthasthana31@gmail.com","subject":"Re: [PATCH 3/3] cat-file: add mailmap support","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-06-30T23:41:42Z","receivedAt":"2022-06-30T23:41:52Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Siddharth Asthana <siddharthasthana31@gmail.com> writes:\n\n> +char *replace_idents_using_mailmap(char *object_buf, size_t *size)\n> +{\n> +\tstruct strbuf sb = STRBUF_INIT;\n> +\tstrbuf_attach(&sb, object_buf, *size, *size + 1);\n> +\trewrite_ident_line(&sb, \"\\nauthor \", &mailmap);\n> +\trewrite_ident_line(&sb, \"\\ncommitter \", &mailmap);\n> +\trewrite_ident_line(&sb, \"\\ntagger \", &mailmap);\n\nThis shows why you want to fix the existing function first before\ninflicting its poorly designed API to more callers.  There is no\nsensible reason that you have to make three calls to the helper\nfunction.\n"},{"id":"458311","messageId":"xmqqr135aeu8.fsf@gitster.g","threadId":"58088","inReplyTo":"220701.86sfnlbu0j.gmgdl@evledraar.gmail.com","subject":"Re: [PATCH 3/3] cat-file: add mailmap support","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-06-30T23:53:03Z","receivedAt":"2022-06-30T23:53:44Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:\n\n> So not as a blocker for this change, which I think can be made small\n> enough to be justified in cat-file, but just for context: If \"git log\"\n> had a similar --batch mode,\n\nPerhaps \"xargs git show\" is what you want? ;-)\n"},{"id":"458558","messageId":"CAP8UFD13MfoMqWSfZfucfdbQL5ypbcYNuHfm1QS8uhmQYq4_VA@mail.gmail.com","threadId":"58088","inReplyTo":"220701.86sfnlbu0j.gmgdl@evledraar.gmail.com","subject":"Re: [PATCH 3/3] cat-file: add mailmap support","fromName":"Christian Couder","fromEmail":"christian.couder@gmail.com","sentAt":"2022-07-07T09:02:21Z","receivedAt":"2022-07-07T09:02:37Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"On Fri, Jul 1, 2022 at 1:39 AM Ævar Arnfjörð Bjarmason <avarab@gmail.com> wrote:\n> On Thu, Jun 30 2022, Siddharth Asthana wrote:\n>\n> > git cat-file is not a plumbing command anymore, especially as it gained\n> > more and more high level features like its `--batch-command` mode. So\n> > tools do use it to get commit and tag contents that are then displayed\n> > to users. This content which has author, committer or tagger\n> > information, could benefit from passing through the mailmap mechanism,\n> > before being sent or displayed.\n> >\n> > This patch adds --[no-]use-mailmap command line option to the git\n> > cat-file command. It also adds --[no-]mailmap option as an alias to\n> > --[no-]use-mailmap.\n>\n> I think I know the answer, but I think it would be helpful to discuss\n> the underlying motivations too. I.e. an obvious alternative is \"why not\n> just get this information out of git show/log then?\".\n>\n> The \"I think I know the answer\" being that I suspect this is to cater to\n> gitaly having persistent \"cat-file\" processes around, whereas for \"git\n> log\" it would entail spinning up a new process per-request.\n>\n> But maybe I'm missing something :)\n\nNo, you are not missing anything :)\n\n> So not as a blocker for this change, which I think can be made small\n> enough to be justified in cat-file, but just for context: If \"git log\"\n> had a similar --batch mode, would there be a need for this change,\n\nOne nice thing with `git cat-file` is that it works for any kind of\ngit object. But yeah we could perhaps use `git show` if it had a\n--batch mode, or a mix of `git cat-file` for blobs and trees, and `git\nlog --batch` for commits and tag objects.\n\n> or is\n> this just adding a common case to \"cat-file\" to \"tide us over\" (as it\n> were) while that sort of thing doesn't exist yet (and maybe never will\n> :()?\n\nBy the way there have been 2 GSoC contributors working on adding\nref-filter formating support to `git cat-file` and that hasn't\nsucceeded yet, mostly for performance reasons. So another way would be\nto wait until ref-filter formats support everything that pretty\nformats support, which Jaydeep is currently working on, including %aN\n(author name respecting .mailmap) and %aE (author email respecting\n.mailmap), and then wait until `git cat-file`'s --batch formats\nsupport ref-filter formats.\n\nBut yeah, we hope the change can be made small enough to be justified\nin cat-file.\n"},{"id":"458559","messageId":"CAP8UFD3ohjS0p02SKwqKWBK1=sVuC9+iDT4at2R9ktCUXme9rA@mail.gmail.com","threadId":"58088","inReplyTo":"xmqqletddegb.fsf@gitster.g","subject":"Re: [PATCH 3/3] cat-file: add mailmap support","fromName":"Christian Couder","fromEmail":"christian.couder@gmail.com","sentAt":"2022-07-07T09:15:30Z","receivedAt":"2022-07-07T09:15:48Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"On Thu, Jun 30, 2022 at 11:33 PM Junio C Hamano <gitster@pobox.com> wrote:\n\n> Independent of what this \"The output from 'cat-file commit' is\n> tweaked\" feature, I wonder if we want a command that can be used as\n> a filter.  Just like \"git name-rev --stdin\" reads a stream of text,\n> finds commit-looking references in it, and annotates them, the\n> command (e.g. \"git mailmap\") would find ident-looking strings and\n> replaces with the mapped results, or something.\n\nYeah, that might be useful. Especially one issue is that trailers like\n\"Reviewed-by: ...\", \"Helped-by: ...\" are interesting for statistics\nand replacing their content with mapped results could help improve the\nstats.\n\nRelated to this, I wonder if `git interpret-trailers` should have a\nsimple way to map trailer content.\n"},{"id":"458569","messageId":"20220707161554.6900-1-siddharthasthana31@gmail.com","threadId":"58088","inReplyTo":"20220630142444.651948-1-siddharthasthana31@gmail.com","subject":"[PATCH v2 0/4] Add support for mailmap in cat-file","fromName":"Siddharth Asthana","fromEmail":"siddharthasthana31@gmail.com","sentAt":"2022-07-07T16:15:50Z","receivedAt":"2022-07-07T16:16:45Z","isPatch":true,"sender":{"key":"siddharthasthana31@gmail.com","avatar":"https://avatars.githubusercontent.com/u/53316982?v=4"},"body":"Thanks a lot for the review and suggestions Phillip, Danh, Ævar and Junio.\nReally grateful for that :)\n\n= Description\n\nThis patch series adds mailmap support to the git-cat-file command. It\nadds the mailmap support only for the commit and tag objects by\nreplacing the idents for \"author\", \"committer\" and \"tagger\" headers. The\nmailmap only takes effect when --[no-]-use-mailmap or --[no-]-mailmap\noption is passed to the git cat-file command. The changes will work with\nthe batch mode as well.\n\nSo, if one wants to enable mailmap they can use either of the following\ncommands:\n$ git cat-file --use-mailmap -p <object>\n$ git cat-file --use-mailmap <type> <object>\n\nTo use it in the batch mode, one can use the following command:\n$ git cat-file --use-mailmap --batch\n\n= Patch Organization\n\n- The first patch improves the commit_rewrite_person() by restricting it \n  to traverse only through the header part of the commit object buffer.\n  It also adds an argument called headers which the callers can pass. \n  The function will replace idents only on these  passed headers. \n  Thus, the caller won't have to make repeated calls to the function.\n- The second patch moves commit_rewrite_person() to ident.c to expose it\n  as a public function so that it can be used to replace idents in the\n  headers of desired objects.\n- The third patch renames commit_rewrite_person() to a name which\n  describes its functionality clearly. It is renamed to\n  apply_mailmap_to_header().\n- The last patch adds mailmap support to the git cat-file command. It\n  adds the required documentation and tests as well.\n\nChanges in v2:\n- The commit_rewrite_person() has been improved by restricting it to\n  traverse only the header part of the object buffers.\n- The callers of commit_rewrite_person() now don't require to call it\n  multiple times for different headers. They can pass an array of\n  headers and commit_rewrite_person() replaces idents only on those\n  headers.\n- commit_rewrite_person() has been renamed to a suitable name which\n  expresses its functionality clearly.\n- More tests have been added to test the --[no-]-use-mailmap option for\n  the tag objects.\n- Redundant operations from the tests have been removed.\n\nSiddharth Asthana (4):\n  revision: improve commit_rewrite_person()\n  ident: move commit_rewrite_person() to ident.c\n  ident: rename commit_rewrite_person() to apply_mailmap_to_header()\n  cat-file: add mailmap support\n\n Documentation/git-cat-file.txt |  6 +++\n builtin/cat-file.c             | 31 ++++++++++++++-\n cache.h                        |  6 +++\n ident.c                        | 69 ++++++++++++++++++++++++++++++++++\n revision.c                     | 49 +-----------------------\n t/t4203-mailmap.sh             | 54 ++++++++++++++++++++++++++\n 6 files changed, 167 insertions(+), 48 deletions(-)\n\nRange-diff against v1:\n-:  ---------- > 1:  64e1f750e1 revision: improve commit_rewrite_person()\n1:  8749b6024f ! 2:  b18ced0ece ident: move commit_rewrite_person() to ident.c\n    @@ Metadata\n      ## Commit message ##\n         ident: move commit_rewrite_person() to ident.c\n     \n    -    commit_rewrite_person() is a static function defined in revision.c.\n    -    As the name suggests, this function can be used to replace author's,\n    -    committer's or tagger's name in the commit/tag object buffer.\n    +    commit_rewrite_person() and rewrite_ident_line() are static functions\n    +    defined in revision.c.\n     \n    -    This patch moves this function from revision.c to ident.c which contains\n    -    many other functions related to identification like split_ident_line. By\n    -    moving this function to ident.c, we intend to use it in git-cat-file to\n    -    replace committer's, author's and tagger's names and emails with their\n    -    canonical name and email using the mailmap mechanism. The function\n    -    is moved as is for now to make it clear that there are no other changes,\n    -    but will be renamed in a following commit.\n    +    Their usages are as follows:\n    +    - commit_rewrite_person() takes a commit buffer and replaces the author\n    +      and committer idents with their canonical versions using the mailmap\n    +      mechanism\n    +    - rewrite_ident_line() takes author/committer header lines from the\n    +      commit buffer and replaces the idents with their canonical versions\n    +      using the mailmap mechanism.\n     \n    +    This patch moves commit_rewrite_person() and rewrite_ident_line() to\n    +    ident.c which contains many other functions related to idents like\n    +    split_ident_line(). By moving commit_rewrite_person() to ident.c, we\n    +    also intend to use it in git-cat-file to replace committer and author\n    +    idents from the headers to their canonical versions using the mailmap\n    +    mechanism. The function is moved as is for now to make it clear that\n    +    there are no other changes, but it will be renamed in a following\n    +    commit.\n    +\n    +    Mentored-by: Christian Couder <christian.couder@gmail.com>\n    +    Mentored-by: John Cai <johncai86@gmail.com>\n         Signed-off-by: Siddharth Asthana <siddharthasthana31@gmail.com>\n     \n      ## cache.h ##\n    @@ cache.h: struct ident_split {\n      int split_ident_line(struct ident_split *, const char *, int);\n      \n     +/*\n    -+ * Given a commit or tag object buffer, replaces the person's\n    -+ * (author/committer/tagger) name and email with their canonical\n    -+ * name and email using mailmap mechanism. Signals a success with\n    -+ * 1 and failure with a 0.\n    ++ * Given a commit object buffer and the commit headers, replaces the idents\n    ++ * in the headers with their canonical versions using the mailmap mechanism.\n     + */\n    -+int commit_rewrite_person(struct strbuf *buf, const char *what, struct string_list *mailmap);\n    ++void commit_rewrite_person(struct strbuf *buf, const char **commit_headers, struct string_list *mailmap);\n     +\n      /*\n       * Compare split idents for equality or strict ordering. Note that we\n    @@ ident.c: int split_ident_line(struct ident_split *split, const char *line, int l\n      \treturn 0;\n      }\n      \n    -+int commit_rewrite_person(struct strbuf *buf, const char *what, struct string_list *mailmap)\n    ++/*\n    ++ * Returns the difference between the new and old length of the ident line.\n    ++ */\n    ++static ssize_t rewrite_ident_line(const char* person, struct strbuf *buf, struct string_list *mailmap)\n     +{\n    -+\tchar *person, *endp;\n    ++\tchar *endp;\n     +\tsize_t len, namelen, maillen;\n     +\tconst char *name;\n     +\tconst char *mail;\n     +\tstruct ident_split ident;\n     +\n    -+\tperson = strstr(buf->buf, what);\n    -+\tif (!person)\n    -+\t\treturn 0;\n    -+\n    -+\tperson += strlen(what);\n     +\tendp = strchr(person, '\\n');\n     +\tif (!endp)\n     +\t\treturn 0;\n    @@ ident.c: int split_ident_line(struct ident_split *split, const char *line, int l\n     +\n     +\tif (map_user(mailmap, &mail, &maillen, &name, &namelen)) {\n     +\t\tstruct strbuf namemail = STRBUF_INIT;\n    ++\t\tsize_t newlen;\n     +\n     +\t\tstrbuf_addf(&namemail, \"%.*s <%.*s>\",\n     +\t\t\t    (int)namelen, name, (int)maillen, mail);\n    @@ ident.c: int split_ident_line(struct ident_split *split, const char *line, int l\n     +\t\t\t      ident.mail_end - ident.name_begin + 1,\n     +\t\t\t      namemail.buf, namemail.len);\n     +\n    ++\t\tnewlen = namemail.len;\n    ++\n     +\t\tstrbuf_release(&namemail);\n     +\n    -+\t\treturn 1;\n    ++\t\treturn newlen - (ident.mail_end - ident.name_begin + 1);\n     +\t}\n     +\n     +\treturn 0;\n    ++}\n    ++\n    ++void commit_rewrite_person(struct strbuf *buf, const char **headers, struct string_list *mailmap)\n    ++{\n    ++\tsize_t buf_offset = 0;\n    ++\n    ++\tif (!mailmap)\n    ++\t\treturn;\n    ++\n    ++\tfor (;;) {\n    ++\t\tconst char *person, *line = buf->buf + buf_offset;\n    ++\t\tint i, linelen = strchrnul(line, '\\n') - line + 1;\n    ++\n    ++\t\tif (!linelen || linelen == 1)\n    ++\t\t\t/* End of header */\n    ++\t\t\treturn;\n    ++\n    ++\t\tbuf_offset += linelen;\n    ++\n    ++\t\tfor (i = 0; headers[i]; i++)\n    ++\t\t\tif (skip_prefix(line, headers[i], &person))\n    ++\t\t\t\tbuf_offset += rewrite_ident_line(person, buf, mailmap);\n    ++\t}\n     +}\n      \n      static void ident_env_hint(enum want_ident whose_ident)\n    @@ revision.c: int rewrite_parents(struct rev_info *revs, struct commit *commit,\n      \treturn 0;\n      }\n      \n    --static int commit_rewrite_person(struct strbuf *buf, const char *what, struct string_list *mailmap)\n    +-/*\n    +- * Returns the difference between the new and old length of the ident line.\n    +- */\n    +-static ssize_t rewrite_ident_line(const char* person, struct strbuf *buf, struct string_list *mailmap)\n     -{\n    --\tchar *person, *endp;\n    +-\tchar *endp;\n     -\tsize_t len, namelen, maillen;\n     -\tconst char *name;\n     -\tconst char *mail;\n     -\tstruct ident_split ident;\n     -\n    --\tperson = strstr(buf->buf, what);\n    --\tif (!person)\n    --\t\treturn 0;\n    --\n    --\tperson += strlen(what);\n     -\tendp = strchr(person, '\\n');\n     -\tif (!endp)\n     -\t\treturn 0;\n    @@ revision.c: int rewrite_parents(struct rev_info *revs, struct commit *commit,\n     -\n     -\tif (map_user(mailmap, &mail, &maillen, &name, &namelen)) {\n     -\t\tstruct strbuf namemail = STRBUF_INIT;\n    +-\t\tsize_t newlen;\n     -\n     -\t\tstrbuf_addf(&namemail, \"%.*s <%.*s>\",\n     -\t\t\t    (int)namelen, name, (int)maillen, mail);\n    @@ revision.c: int rewrite_parents(struct rev_info *revs, struct commit *commit,\n     -\t\t\t      ident.mail_end - ident.name_begin + 1,\n     -\t\t\t      namemail.buf, namemail.len);\n     -\n    +-\t\tnewlen = namemail.len;\n    +-\n     -\t\tstrbuf_release(&namemail);\n     -\n    --\t\treturn 1;\n    +-\t\treturn newlen - (ident.mail_end - ident.name_begin + 1);\n     -\t}\n     -\n     -\treturn 0;\n     -}\n    +-\n    +-static void commit_rewrite_person(struct strbuf *buf, const char **headers, struct string_list *mailmap)\n    +-{\n    +-\tsize_t buf_offset = 0;\n    +-\n    +-\tif (!mailmap)\n    +-\t\treturn;\n    +-\n    +-\tfor (;;) {\n    +-\t\tconst char *person, *line = buf->buf + buf_offset;\n    +-\t\tint i, linelen = strchrnul(line, '\\n') - line + 1;\n    +-\n    +-\t\tif (!linelen || linelen == 1)\n    +-\t\t\t/* End of header */\n    +-\t\t\treturn;\n    +-\n    +-\t\tbuf_offset += linelen;\n    +-\n    +-\t\tfor (i = 0; headers[i]; i++)\n    +-\t\t\tif (skip_prefix(line, headers[i], &person))\n    +-\t\t\t\tbuf_offset += rewrite_ident_line(person, buf, mailmap);\n    +-\t}\n    +-}\n     -\n      static int commit_match(struct commit *commit, struct rev_info *opt)\n      {\n2:  aff60f541b < -:  ---------- ident: rename commit_rewrite_person() to rewrite_ident_line()\n-:  ---------- > 3:  2494ce1ed2 ident: rename commit_rewrite_person() to apply_mailmap_to_header()\n3:  2a697167db ! 4:  94838a2566 cat-file: add mailmap support\n    @@ Metadata\n      ## Commit message ##\n         cat-file: add mailmap support\n     \n    -    git cat-file is not a plumbing command anymore, especially as it gained\n    -    more and more high level features like its `--batch-command` mode. So\n    -    tools do use it to get commit and tag contents that are then displayed\n    -    to users. This content which has author, committer or tagger\n    -    information, could benefit from passing through the mailmap mechanism,\n    -    before being sent or displayed.\n    +    git-cat-file is used by tools like GitLab to get commit tag contents\n    +    that are then displayed to users. This content which has author,\n    +    committer or tagger information, could benefit from passing through the\n    +    mailmap mechanism before being sent or displayed.\n     \n         This patch adds --[no-]use-mailmap command line option to the git\n         cat-file command. It also adds --[no-]mailmap option as an alias to\n         --[no-]use-mailmap.\n     \n    -    At this time, this patch only adds a command line\n    -    option, but perhaps a `cat-file.mailmap` config option could be added as\n    -    well in the same way as for `git log`.\n    -\n    +    Mentored-by: Christian Couder <christian.couder@gmail.com>\n    +    Mentored-by: John Cai <johncai86@gmail.com>\n    +    Helped-by: Phillip Wood <phillip.wood@dunelm.org.uk>\n         Signed-off-by: Siddharth Asthana <siddharthasthana31@gmail.com>\n     \n      ## Documentation/git-cat-file.txt ##\n    @@ Documentation/git-cat-file.txt: OPTIONS\n      \n     +--[no-]mailmap::\n     +--[no-]use-mailmap::\n    -+\tUse mailmap file to map author, committer and tagger names\n    -+\tand email addresses to canonical real names and email addresses.\n    -+\tSee linkgit:git-shortlog[1].\n    ++       Use mailmap file to map author, committer and tagger names\n    ++       and email addresses to canonical real names and email addresses.\n    ++       See linkgit:git-shortlog[1].\n     +\n      --textconv::\n      \tShow the content as transformed by a textconv filter. In this case,\n    @@ builtin/cat-file.c: struct batch_options {\n     +{\n     +\tstruct strbuf sb = STRBUF_INIT;\n     +\tstrbuf_attach(&sb, object_buf, *size, *size + 1);\n    -+\trewrite_ident_line(&sb, \"\\nauthor \", &mailmap);\n    -+\trewrite_ident_line(&sb, \"\\ncommitter \", &mailmap);\n    -+\trewrite_ident_line(&sb, \"\\ntagger \", &mailmap);\n    ++\tconst char *headers[] = { \"author \", \"committer \", \"tagger \", NULL };\n    ++\tapply_mailmap_to_header(&sb, headers, &mailmap);\n     +\t*size = sb.len;\n     +\treturn strbuf_detach(&sb, NULL);\n     +}\n    @@ t/t4203-mailmap.sh: test_expect_success SYMLINKS 'symlinks not respected in-tree\n     +\tauthor Orig <orig@example.com>\n     +\tEOF\n     +\tgit cat-file --no-use-mailmap commit HEAD >log &&\n    -+\tgrep author log >actual &&\n    -+\tsed -e \"/^author/q\" actual >log &&\n    -+\tsed -e \"s/ [0-9][0-9]* [-+][0-9][0-9][0-9][0-9]$//\" log >actual &&\n    ++\tsed -n \"/^author /s/\\([^>]*>\\).*/\\1/p\" log >actual &&\n     +\ttest_cmp expect actual\n     +'\n     +\n    @@ t/t4203-mailmap.sh: test_expect_success SYMLINKS 'symlinks not respected in-tree\n     +\tauthor A U Thor <author@example.com>\n     +\tEOF\n     +\tgit cat-file --use-mailmap commit HEAD >log &&\n    -+\tgrep author log >actual &&\n    -+\tsed -e \"/^author/q\" actual >log &&\n    -+\tsed -e \"s/ [0-9][0-9]* [-+][0-9][0-9][0-9][0-9]$//\" log >actual &&\n    ++\tsed -n \"/^author /s/\\([^>]*>\\).*/\\1/p\" log >actual &&\n    ++\ttest_cmp expect actual\n    ++'\n    ++\n    ++test_expect_success '--no-mailmap disables mailmap in cat-file for annotated tag objects' '\n    ++\ttest_when_finished \"rm .mailmap\" &&\n    ++\tcat >.mailmap <<-EOF &&\n    ++\tOrig <orig@example.com> C O Mitter <committer@example.com>\n    ++\tEOF\n    ++\tcat >expect <<-EOF &&\n    ++\ttagger C O Mitter <committer@example.com>\n    ++\tEOF\n    ++\tgit tag -a -m \"annotated tag\" v1 &&\n    ++\tgit cat-file --no-mailmap -p v1 >log &&\n    ++\tsed -n \"/^tagger /s/\\([^>]*>\\).*/\\1/p\" log >actual &&\n    ++\ttest_cmp expect actual\n    ++'\n    ++\n    ++test_expect_success '--mailmap enables mailmap in cat-file for annotated tag objects' '\n    ++\ttest_when_finished \"rm .mailmap\" &&\n    ++\tcat >.mailmap <<-EOF &&\n    ++\tOrig <orig@example.com> C O Mitter <committer@example.com>\n    ++\tEOF\n    ++\tcat >expect <<-EOF &&\n    ++\ttagger Orig <orig@example.com>\n    ++\tEOF\n    ++\tgit tag -a -m \"annotated tag\" v2 &&\n    ++\tgit cat-file --mailmap -p v2 >log &&\n    ++\tsed -n \"/^tagger /s/\\([^>]*>\\).*/\\1/p\" log >actual &&\n     +\ttest_cmp expect actual\n     +'\n     +\n-- \n2.37.0.6.ga6a61a26c1.dirty\n\n"},{"id":"458570","messageId":"20220707161554.6900-2-siddharthasthana31@gmail.com","threadId":"58088","inReplyTo":"20220707161554.6900-1-siddharthasthana31@gmail.com","subject":"[PATCH v2 1/4] revision: improve commit_rewrite_person()","fromName":"Siddharth Asthana","fromEmail":"siddharthasthana31@gmail.com","sentAt":"2022-07-07T16:15:51Z","receivedAt":"2022-07-07T16:16:52Z","isPatch":true,"sender":{"key":"siddharthasthana31@gmail.com","avatar":"https://avatars.githubusercontent.com/u/53316982?v=4"},"body":"The function, commit_rewrite_person(), is designed to find and replace\nan ident string in the header part, and the way it avoids a random\noccuranace of \"author A U Thor <author@example.com\" in the text is by\ninsisting \"author\" to appear at the beginning of line by passing\n\"\\nauthor \" as \"what\".\n\nThe implementation also doesn't make any effort to limit itself to the\ncommit header by locating the blank line that appears after the header\npart and stopping the search there. Also, the interface forces the\ncaller to make multiple calls if it wants to rewrite idents on multiple\nheaders. It shouldn't be the case.\n\nTo support the existing caller better, update commit_rewrite_person()\nto:\n- Make a single pass in the input buffer to locate headers named\n  \"author\" and \"committer\" and replace idents on them.\n- Stop at the end of the header, ensuring that nothing in the body of\n  the commit object is modified.\n\nThe return type of the function commit_rewrite_person() has also been\nchanged from int to void. This has been done because the caller of the\nfunction doesn't do anything with the return value of the function.\n\nBy simplyfying the interface of the commit_rewrite_person(), we also\nintend to expose it as a public function. We will also be renaming the\nfunction in a future commit to a different name which clearly tells that\nthe function replaces idents in the header of the commit buffer.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: John Cai <johncai86@gmail.com>\nSigned-off-by: Siddharth Asthana <siddharthasthana31@gmail.com>\n---\n revision.c | 44 ++++++++++++++++++++++++++++++++++----------\n 1 file changed, 34 insertions(+), 10 deletions(-)\n\ndiff --git a/revision.c b/revision.c\nindex 211352795c..83e68c1f97 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -3755,19 +3755,17 @@ int rewrite_parents(struct rev_info *revs, struct commit *commit,\n \treturn 0;\n }\n \n-static int commit_rewrite_person(struct strbuf *buf, const char *what, struct string_list *mailmap)\n+/*\n+ * Returns the difference between the new and old length of the ident line.\n+ */\n+static ssize_t rewrite_ident_line(const char* person, struct strbuf *buf, struct string_list *mailmap)\n {\n-\tchar *person, *endp;\n+\tchar *endp;\n \tsize_t len, namelen, maillen;\n \tconst char *name;\n \tconst char *mail;\n \tstruct ident_split ident;\n \n-\tperson = strstr(buf->buf, what);\n-\tif (!person)\n-\t\treturn 0;\n-\n-\tperson += strlen(what);\n \tendp = strchr(person, '\\n');\n \tif (!endp)\n \t\treturn 0;\n@@ -3784,6 +3782,7 @@ static int commit_rewrite_person(struct strbuf *buf, const char *what, struct st\n \n \tif (map_user(mailmap, &mail, &maillen, &name, &namelen)) {\n \t\tstruct strbuf namemail = STRBUF_INIT;\n+\t\tsize_t newlen;\n \n \t\tstrbuf_addf(&namemail, \"%.*s <%.*s>\",\n \t\t\t    (int)namelen, name, (int)maillen, mail);\n@@ -3792,14 +3791,39 @@ static int commit_rewrite_person(struct strbuf *buf, const char *what, struct st\n \t\t\t      ident.mail_end - ident.name_begin + 1,\n \t\t\t      namemail.buf, namemail.len);\n \n+\t\tnewlen = namemail.len;\n+\n \t\tstrbuf_release(&namemail);\n \n-\t\treturn 1;\n+\t\treturn newlen - (ident.mail_end - ident.name_begin + 1);\n \t}\n \n \treturn 0;\n }\n \n+static void commit_rewrite_person(struct strbuf *buf, const char **headers, struct string_list *mailmap)\n+{\n+\tsize_t buf_offset = 0;\n+\n+\tif (!mailmap)\n+\t\treturn;\n+\n+\tfor (;;) {\n+\t\tconst char *person, *line = buf->buf + buf_offset;\n+\t\tint i, linelen = strchrnul(line, '\\n') - line + 1;\n+\n+\t\tif (!linelen || linelen == 1)\n+\t\t\t/* End of header */\n+\t\t\treturn;\n+\n+\t\tbuf_offset += linelen;\n+\n+\t\tfor (i = 0; headers[i]; i++)\n+\t\t\tif (skip_prefix(line, headers[i], &person))\n+\t\t\t\tbuf_offset += rewrite_ident_line(person, buf, mailmap);\n+\t}\n+}\n+\n static int commit_match(struct commit *commit, struct rev_info *opt)\n {\n \tint retval;\n@@ -3835,8 +3859,8 @@ static int commit_match(struct commit *commit, struct rev_info *opt)\n \t\tif (!buf.len)\n \t\t\tstrbuf_addstr(&buf, message);\n \n-\t\tcommit_rewrite_person(&buf, \"\\nauthor \", opt->mailmap);\n-\t\tcommit_rewrite_person(&buf, \"\\ncommitter \", opt->mailmap);\n+\t\tconst char *commit_headers[] = { \"author \", \"committer \", NULL };\n+\t\tcommit_rewrite_person(&buf, commit_headers, opt->mailmap);\n \t}\n \n \t/* Append \"fake\" message parts as needed */\n-- \n2.37.0.6.ga6a61a26c1.dirty\n\n"},{"id":"458571","messageId":"20220707161554.6900-3-siddharthasthana31@gmail.com","threadId":"58088","inReplyTo":"20220707161554.6900-1-siddharthasthana31@gmail.com","subject":"[PATCH v2 2/4] ident: move commit_rewrite_person() to ident.c","fromName":"Siddharth Asthana","fromEmail":"siddharthasthana31@gmail.com","sentAt":"2022-07-07T16:15:52Z","receivedAt":"2022-07-07T16:16:58Z","isPatch":true,"sender":{"key":"siddharthasthana31@gmail.com","avatar":"https://avatars.githubusercontent.com/u/53316982?v=4"},"body":"commit_rewrite_person() and rewrite_ident_line() are static functions\ndefined in revision.c.\n\nTheir usages are as follows:\n- commit_rewrite_person() takes a commit buffer and replaces the author\n  and committer idents with their canonical versions using the mailmap\n  mechanism\n- rewrite_ident_line() takes author/committer header lines from the\n  commit buffer and replaces the idents with their canonical versions\n  using the mailmap mechanism.\n\nThis patch moves commit_rewrite_person() and rewrite_ident_line() to\nident.c which contains many other functions related to idents like\nsplit_ident_line(). By moving commit_rewrite_person() to ident.c, we\nalso intend to use it in git-cat-file to replace committer and author\nidents from the headers to their canonical versions using the mailmap\nmechanism. The function is moved as is for now to make it clear that\nthere are no other changes, but it will be renamed in a following\ncommit.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: John Cai <johncai86@gmail.com>\nSigned-off-by: Siddharth Asthana <siddharthasthana31@gmail.com>\n---\n cache.h    |  6 +++++\n ident.c    | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++++++\n revision.c | 69 ------------------------------------------------------\n 3 files changed, 75 insertions(+), 69 deletions(-)\n\ndiff --git a/cache.h b/cache.h\nindex ac5ab4ef9d..c9dbe1c29a 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -1688,6 +1688,12 @@ struct ident_split {\n  */\n int split_ident_line(struct ident_split *, const char *, int);\n \n+/*\n+ * Given a commit object buffer and the commit headers, replaces the idents\n+ * in the headers with their canonical versions using the mailmap mechanism.\n+ */\n+void commit_rewrite_person(struct strbuf *buf, const char **commit_headers, struct string_list *mailmap);\n+\n /*\n  * Compare split idents for equality or strict ordering. Note that we\n  * compare only the ident part of the line, ignoring any timestamp.\ndiff --git a/ident.c b/ident.c\nindex 89ca5b4700..26cc60b2e1 100644\n--- a/ident.c\n+++ b/ident.c\n@@ -8,6 +8,7 @@\n #include \"cache.h\"\n #include \"config.h\"\n #include \"date.h\"\n+#include \"mailmap.h\"\n \n static struct strbuf git_default_name = STRBUF_INIT;\n static struct strbuf git_default_email = STRBUF_INIT;\n@@ -346,6 +347,74 @@ int split_ident_line(struct ident_split *split, const char *line, int len)\n \treturn 0;\n }\n \n+/*\n+ * Returns the difference between the new and old length of the ident line.\n+ */\n+static ssize_t rewrite_ident_line(const char* person, struct strbuf *buf, struct string_list *mailmap)\n+{\n+\tchar *endp;\n+\tsize_t len, namelen, maillen;\n+\tconst char *name;\n+\tconst char *mail;\n+\tstruct ident_split ident;\n+\n+\tendp = strchr(person, '\\n');\n+\tif (!endp)\n+\t\treturn 0;\n+\n+\tlen = endp - person;\n+\n+\tif (split_ident_line(&ident, person, len))\n+\t\treturn 0;\n+\n+\tmail = ident.mail_begin;\n+\tmaillen = ident.mail_end - ident.mail_begin;\n+\tname = ident.name_begin;\n+\tnamelen = ident.name_end - ident.name_begin;\n+\n+\tif (map_user(mailmap, &mail, &maillen, &name, &namelen)) {\n+\t\tstruct strbuf namemail = STRBUF_INIT;\n+\t\tsize_t newlen;\n+\n+\t\tstrbuf_addf(&namemail, \"%.*s <%.*s>\",\n+\t\t\t    (int)namelen, name, (int)maillen, mail);\n+\n+\t\tstrbuf_splice(buf, ident.name_begin - buf->buf,\n+\t\t\t      ident.mail_end - ident.name_begin + 1,\n+\t\t\t      namemail.buf, namemail.len);\n+\n+\t\tnewlen = namemail.len;\n+\n+\t\tstrbuf_release(&namemail);\n+\n+\t\treturn newlen - (ident.mail_end - ident.name_begin + 1);\n+\t}\n+\n+\treturn 0;\n+}\n+\n+void commit_rewrite_person(struct strbuf *buf, const char **headers, struct string_list *mailmap)\n+{\n+\tsize_t buf_offset = 0;\n+\n+\tif (!mailmap)\n+\t\treturn;\n+\n+\tfor (;;) {\n+\t\tconst char *person, *line = buf->buf + buf_offset;\n+\t\tint i, linelen = strchrnul(line, '\\n') - line + 1;\n+\n+\t\tif (!linelen || linelen == 1)\n+\t\t\t/* End of header */\n+\t\t\treturn;\n+\n+\t\tbuf_offset += linelen;\n+\n+\t\tfor (i = 0; headers[i]; i++)\n+\t\t\tif (skip_prefix(line, headers[i], &person))\n+\t\t\t\tbuf_offset += rewrite_ident_line(person, buf, mailmap);\n+\t}\n+}\n \n static void ident_env_hint(enum want_ident whose_ident)\n {\ndiff --git a/revision.c b/revision.c\nindex 83e68c1f97..49d15e74ff 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -3755,75 +3755,6 @@ int rewrite_parents(struct rev_info *revs, struct commit *commit,\n \treturn 0;\n }\n \n-/*\n- * Returns the difference between the new and old length of the ident line.\n- */\n-static ssize_t rewrite_ident_line(const char* person, struct strbuf *buf, struct string_list *mailmap)\n-{\n-\tchar *endp;\n-\tsize_t len, namelen, maillen;\n-\tconst char *name;\n-\tconst char *mail;\n-\tstruct ident_split ident;\n-\n-\tendp = strchr(person, '\\n');\n-\tif (!endp)\n-\t\treturn 0;\n-\n-\tlen = endp - person;\n-\n-\tif (split_ident_line(&ident, person, len))\n-\t\treturn 0;\n-\n-\tmail = ident.mail_begin;\n-\tmaillen = ident.mail_end - ident.mail_begin;\n-\tname = ident.name_begin;\n-\tnamelen = ident.name_end - ident.name_begin;\n-\n-\tif (map_user(mailmap, &mail, &maillen, &name, &namelen)) {\n-\t\tstruct strbuf namemail = STRBUF_INIT;\n-\t\tsize_t newlen;\n-\n-\t\tstrbuf_addf(&namemail, \"%.*s <%.*s>\",\n-\t\t\t    (int)namelen, name, (int)maillen, mail);\n-\n-\t\tstrbuf_splice(buf, ident.name_begin - buf->buf,\n-\t\t\t      ident.mail_end - ident.name_begin + 1,\n-\t\t\t      namemail.buf, namemail.len);\n-\n-\t\tnewlen = namemail.len;\n-\n-\t\tstrbuf_release(&namemail);\n-\n-\t\treturn newlen - (ident.mail_end - ident.name_begin + 1);\n-\t}\n-\n-\treturn 0;\n-}\n-\n-static void commit_rewrite_person(struct strbuf *buf, const char **headers, struct string_list *mailmap)\n-{\n-\tsize_t buf_offset = 0;\n-\n-\tif (!mailmap)\n-\t\treturn;\n-\n-\tfor (;;) {\n-\t\tconst char *person, *line = buf->buf + buf_offset;\n-\t\tint i, linelen = strchrnul(line, '\\n') - line + 1;\n-\n-\t\tif (!linelen || linelen == 1)\n-\t\t\t/* End of header */\n-\t\t\treturn;\n-\n-\t\tbuf_offset += linelen;\n-\n-\t\tfor (i = 0; headers[i]; i++)\n-\t\t\tif (skip_prefix(line, headers[i], &person))\n-\t\t\t\tbuf_offset += rewrite_ident_line(person, buf, mailmap);\n-\t}\n-}\n-\n static int commit_match(struct commit *commit, struct rev_info *opt)\n {\n \tint retval;\n-- \n2.37.0.6.ga6a61a26c1.dirty\n\n"},{"id":"458572","messageId":"20220707161554.6900-4-siddharthasthana31@gmail.com","threadId":"58088","inReplyTo":"20220707161554.6900-1-siddharthasthana31@gmail.com","subject":"[PATCH v2 3/4] ident: rename commit_rewrite_person() to apply_mailmap_to_header()","fromName":"Siddharth Asthana","fromEmail":"siddharthasthana31@gmail.com","sentAt":"2022-07-07T16:15:53Z","receivedAt":"2022-07-07T16:17:05Z","isPatch":true,"sender":{"key":"siddharthasthana31@gmail.com","avatar":"https://avatars.githubusercontent.com/u/53316982?v=4"},"body":"commit_rewrite_person() takes a commit buffer and replaces the idents\nin the header with their canonical versions using the mailmap mechanism.\nThe name \"commit_rewrite_person()\" is misleading as it doesn't convey\nwhat kind of rewrite are we going to do to the buffer. It also doesn't\nclearly mention that the function will limit itself to the header part\nof the buffer. The new name, \"apply_mailmap_to_header()\", expresses the\nfunctionality of the function pretty clearly.\n\nWe intend to use apply_mailmap_to_header() in git-cat-file to replace\nidents in the headers of commit and tag object buffers. So, we will be\nextending this function to take tag objects buffer as well and replace\nidents on the tagger header using the mailmap mechanism.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: John Cai <johncai86@gmail.com>\nSigned-off-by: Siddharth Asthana <siddharthasthana31@gmail.com>\n---\n cache.h    | 6 +++---\n ident.c    | 2 +-\n revision.c | 2 +-\n 3 files changed, 5 insertions(+), 5 deletions(-)\n\ndiff --git a/cache.h b/cache.h\nindex c9dbe1c29a..9edb7fefd3 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -1689,10 +1689,10 @@ struct ident_split {\n int split_ident_line(struct ident_split *, const char *, int);\n \n /*\n- * Given a commit object buffer and the commit headers, replaces the idents\n- * in the headers with their canonical versions using the mailmap mechanism.\n+ * Given a commit or tag object buffer and the commit or tag headers, replaces\n+ * the idents in the headers with their canonical versions using the mailmap mechanism.\n  */\n-void commit_rewrite_person(struct strbuf *buf, const char **commit_headers, struct string_list *mailmap);\n+void apply_mailmap_to_header(struct strbuf *buf, const char **headers, struct string_list *mailmap);\n \n /*\n  * Compare split idents for equality or strict ordering. Note that we\ndiff --git a/ident.c b/ident.c\nindex 26cc60b2e1..8503098f29 100644\n--- a/ident.c\n+++ b/ident.c\n@@ -393,7 +393,7 @@ static ssize_t rewrite_ident_line(const char* person, struct strbuf *buf, struct\n \treturn 0;\n }\n \n-void commit_rewrite_person(struct strbuf *buf, const char **headers, struct string_list *mailmap)\n+void apply_mailmap_to_header(struct strbuf *buf, const char **headers, struct string_list *mailmap)\n {\n \tsize_t buf_offset = 0;\n \ndiff --git a/revision.c b/revision.c\nindex 49d15e74ff..b561d6b5b5 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -3791,7 +3791,7 @@ static int commit_match(struct commit *commit, struct rev_info *opt)\n \t\t\tstrbuf_addstr(&buf, message);\n \n \t\tconst char *commit_headers[] = { \"author \", \"committer \", NULL };\n-\t\tcommit_rewrite_person(&buf, commit_headers, opt->mailmap);\n+\t\tapply_mailmap_to_header(&buf, commit_headers, opt->mailmap);\n \t}\n \n \t/* Append \"fake\" message parts as needed */\n-- \n2.37.0.6.ga6a61a26c1.dirty\n\n"},{"id":"458573","messageId":"20220707161554.6900-5-siddharthasthana31@gmail.com","threadId":"58088","inReplyTo":"20220707161554.6900-1-siddharthasthana31@gmail.com","subject":"[PATCH v2 4/4] cat-file: add mailmap support","fromName":"Siddharth Asthana","fromEmail":"siddharthasthana31@gmail.com","sentAt":"2022-07-07T16:15:54Z","receivedAt":"2022-07-07T16:17:10Z","isPatch":true,"sender":{"key":"siddharthasthana31@gmail.com","avatar":"https://avatars.githubusercontent.com/u/53316982?v=4"},"body":"git-cat-file is used by tools like GitLab to get commit tag contents\nthat are then displayed to users. This content which has author,\ncommitter or tagger information, could benefit from passing through the\nmailmap mechanism before being sent or displayed.\n\nThis patch adds --[no-]use-mailmap command line option to the git\ncat-file command. It also adds --[no-]mailmap option as an alias to\n--[no-]use-mailmap.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: John Cai <johncai86@gmail.com>\nHelped-by: Phillip Wood <phillip.wood@dunelm.org.uk>\nSigned-off-by: Siddharth Asthana <siddharthasthana31@gmail.com>\n---\n Documentation/git-cat-file.txt |  6 ++++\n builtin/cat-file.c             | 31 ++++++++++++++++++-\n t/t4203-mailmap.sh             | 54 ++++++++++++++++++++++++++++++++++\n 3 files changed, 90 insertions(+), 1 deletion(-)\n\ndiff --git a/Documentation/git-cat-file.txt b/Documentation/git-cat-file.txt\nindex 24a811f0ef..1880e9bba1 100644\n--- a/Documentation/git-cat-file.txt\n+++ b/Documentation/git-cat-file.txt\n@@ -63,6 +63,12 @@ OPTIONS\n \tor to ask for a \"blob\" with `<object>` being a tag object that\n \tpoints at it.\n \n+--[no-]mailmap::\n+--[no-]use-mailmap::\n+       Use mailmap file to map author, committer and tagger names\n+       and email addresses to canonical real names and email addresses.\n+       See linkgit:git-shortlog[1].\n+\n --textconv::\n \tShow the content as transformed by a textconv filter. In this case,\n \t`<object>` has to be of the form `<tree-ish>:<path>`, or `:<path>` in\ndiff --git a/builtin/cat-file.c b/builtin/cat-file.c\nindex 50cf38999d..6dc750a367 100644\n--- a/builtin/cat-file.c\n+++ b/builtin/cat-file.c\n@@ -16,6 +16,7 @@\n #include \"packfile.h\"\n #include \"object-store.h\"\n #include \"promisor-remote.h\"\n+#include \"mailmap.h\"\n \n enum batch_mode {\n \tBATCH_MODE_CONTENTS,\n@@ -36,6 +37,19 @@ struct batch_options {\n \n static const char *force_path;\n \n+static struct string_list mailmap = STRING_LIST_INIT_NODUP;\n+static int use_mailmap;\n+\n+char *replace_idents_using_mailmap(char *object_buf, size_t *size)\n+{\n+\tstruct strbuf sb = STRBUF_INIT;\n+\tstrbuf_attach(&sb, object_buf, *size, *size + 1);\n+\tconst char *headers[] = { \"author \", \"committer \", \"tagger \", NULL };\n+\tapply_mailmap_to_header(&sb, headers, &mailmap);\n+\t*size = sb.len;\n+\treturn strbuf_detach(&sb, NULL);\n+}\n+\n static int filter_object(const char *path, unsigned mode,\n \t\t\t const struct object_id *oid,\n \t\t\t char **buf, unsigned long *size)\n@@ -152,6 +166,9 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,\n \t\tif (!buf)\n \t\t\tdie(\"Cannot read object %s\", obj_name);\n \n+\t\tif (use_mailmap)\n+\t\t\tbuf = replace_idents_using_mailmap(buf, &size);\n+\n \t\t/* otherwise just spit out the data */\n \t\tbreak;\n \n@@ -183,6 +200,9 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,\n \t\t}\n \t\tbuf = read_object_with_reference(the_repository, &oid,\n \t\t\t\t\t\t exp_type_id, &size, NULL);\n+\n+\t\tif (use_mailmap)\n+\t\t\tbuf = replace_idents_using_mailmap(buf, &size);\n \t\tbreak;\n \t}\n \tdefault:\n@@ -348,11 +368,15 @@ static void print_object_or_die(struct batch_options *opt, struct expand_data *d\n \t\tvoid *contents;\n \n \t\tcontents = read_object_file(oid, &type, &size);\n+\n+\t\tif (use_mailmap)\n+\t\t\tcontents = replace_idents_using_mailmap(contents, &size);\n+\n \t\tif (!contents)\n \t\t\tdie(\"object %s disappeared\", oid_to_hex(oid));\n \t\tif (type != data->type)\n \t\t\tdie(\"object %s changed type!?\", oid_to_hex(oid));\n-\t\tif (data->info.sizep && size != data->size)\n+\t\tif (data->info.sizep && size != data->size && !use_mailmap)\n \t\t\tdie(\"object %s changed size!?\", oid_to_hex(oid));\n \n \t\tbatch_write(opt, contents, size);\n@@ -843,6 +867,8 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix)\n \t\tOPT_CMDMODE('s', NULL, &opt, N_(\"show object size\"), 's'),\n \t\tOPT_BOOL(0, \"allow-unknown-type\", &unknown_type,\n \t\t\t  N_(\"allow -s and -t to work with broken/corrupt objects\")),\n+\t\tOPT_BOOL(0, \"use-mailmap\", &use_mailmap, N_(\"use mail map file\")),\n+\t\tOPT_ALIAS(0, \"mailmap\", \"use-mailmap\"),\n \t\t/* Batch mode */\n \t\tOPT_GROUP(N_(\"Batch objects requested on stdin (or --batch-all-objects)\")),\n \t\tOPT_CALLBACK_F(0, \"batch\", &batch, N_(\"format\"),\n@@ -885,6 +911,9 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix)\n \topt_cw = (opt == 'c' || opt == 'w');\n \topt_epts = (opt == 'e' || opt == 'p' || opt == 't' || opt == 's');\n \n+\tif (use_mailmap)\n+\t\tread_mailmap(&mailmap);\n+\n \t/* --batch-all-objects? */\n \tif (opt == 'b')\n \t\tbatch.all_objects = 1;\ndiff --git a/t/t4203-mailmap.sh b/t/t4203-mailmap.sh\nindex 0b2d21ec55..c60a90615c 100755\n--- a/t/t4203-mailmap.sh\n+++ b/t/t4203-mailmap.sh\n@@ -963,4 +963,58 @@ test_expect_success SYMLINKS 'symlinks not respected in-tree' '\n \ttest_cmp expect actual\n '\n \n+test_expect_success '--no-use-mailmap disables mailmap in cat-file' '\n+\ttest_when_finished \"rm .mailmap\" &&\n+\tcat >.mailmap <<-EOF &&\n+\tA U Thor <author@example.com> Orig <orig@example.com>\n+\tEOF\n+\tcat >expect <<-EOF &&\n+\tauthor Orig <orig@example.com>\n+\tEOF\n+\tgit cat-file --no-use-mailmap commit HEAD >log &&\n+\tsed -n \"/^author /s/\\([^>]*>\\).*/\\1/p\" log >actual &&\n+\ttest_cmp expect actual\n+'\n+\n+test_expect_success '--use-mailmap enables mailmap in cat-file' '\n+\ttest_when_finished \"rm .mailmap\" &&\n+\tcat >.mailmap <<-EOF &&\n+\tA U Thor <author@example.com> Orig <orig@example.com>\n+\tEOF\n+\tcat >expect <<-EOF &&\n+\tauthor A U Thor <author@example.com>\n+\tEOF\n+\tgit cat-file --use-mailmap commit HEAD >log &&\n+\tsed -n \"/^author /s/\\([^>]*>\\).*/\\1/p\" log >actual &&\n+\ttest_cmp expect actual\n+'\n+\n+test_expect_success '--no-mailmap disables mailmap in cat-file for annotated tag objects' '\n+\ttest_when_finished \"rm .mailmap\" &&\n+\tcat >.mailmap <<-EOF &&\n+\tOrig <orig@example.com> C O Mitter <committer@example.com>\n+\tEOF\n+\tcat >expect <<-EOF &&\n+\ttagger C O Mitter <committer@example.com>\n+\tEOF\n+\tgit tag -a -m \"annotated tag\" v1 &&\n+\tgit cat-file --no-mailmap -p v1 >log &&\n+\tsed -n \"/^tagger /s/\\([^>]*>\\).*/\\1/p\" log >actual &&\n+\ttest_cmp expect actual\n+'\n+\n+test_expect_success '--mailmap enables mailmap in cat-file for annotated tag objects' '\n+\ttest_when_finished \"rm .mailmap\" &&\n+\tcat >.mailmap <<-EOF &&\n+\tOrig <orig@example.com> C O Mitter <committer@example.com>\n+\tEOF\n+\tcat >expect <<-EOF &&\n+\ttagger Orig <orig@example.com>\n+\tEOF\n+\tgit tag -a -m \"annotated tag\" v2 &&\n+\tgit cat-file --mailmap -p v2 >log &&\n+\tsed -n \"/^tagger /s/\\([^>]*>\\).*/\\1/p\" log >actual &&\n+\ttest_cmp expect actual\n+'\n+\n test_done\n-- \n2.37.0.6.ga6a61a26c1.dirty\n\n"},{"id":"458604","messageId":"xmqq4jzszj2x.fsf@gitster.g","threadId":"58088","inReplyTo":"20220707161554.6900-2-siddharthasthana31@gmail.com","subject":"Re: [PATCH v2 1/4] revision: improve commit_rewrite_person()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-07-07T21:52:38Z","receivedAt":"2022-07-07T21:52:48Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Siddharth Asthana <siddharthasthana31@gmail.com> writes:\n\n> @@ -3835,8 +3859,8 @@ static int commit_match(struct commit *commit, struct rev_info *opt)\n>  \t\tif (!buf.len)\n>  \t\t\tstrbuf_addstr(&buf, message);\n>  \n> -\t\tcommit_rewrite_person(&buf, \"\\nauthor \", opt->mailmap);\n> -\t\tcommit_rewrite_person(&buf, \"\\ncommitter \", opt->mailmap);\n> +\t\tconst char *commit_headers[] = { \"author \", \"committer \", NULL };\n\nThis is decl-after-statement our codebase avoids.\n\n> +\t\tcommit_rewrite_person(&buf, commit_headers, opt->mailmap);\n>  \t}\n>  \n>  \t/* Append \"fake\" message parts as needed */\n"},{"id":"458605","messageId":"xmqqwncoy4de.fsf@gitster.g","threadId":"58088","inReplyTo":"20220707161554.6900-5-siddharthasthana31@gmail.com","subject":"Re: [PATCH v2 4/4] cat-file: add mailmap support","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-07-07T21:55:41Z","receivedAt":"2022-07-07T21:55:54Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Siddharth Asthana <siddharthasthana31@gmail.com> writes:\n\n> +char *replace_idents_using_mailmap(char *object_buf, size_t *size)\n\nDoes this function need to be extern?  If nobody other than callers\nin cat-file would call it, perhaps it should be file-scope static.\n\n> +{\n> +\tstruct strbuf sb = STRBUF_INIT;\n> +\tstrbuf_attach(&sb, object_buf, *size, *size + 1);\n> +\tconst char *headers[] = { \"author \", \"committer \", \"tagger \", NULL };\n\nThis is decl-after-statement.\n\n> +\tapply_mailmap_to_header(&sb, headers, &mailmap);\n> +\t*size = sb.len;\n> +\treturn strbuf_detach(&sb, NULL);\n> +}\n\n"},{"id":"458606","messageId":"xmqqsfncy3w1.fsf@gitster.g","threadId":"58088","inReplyTo":"20220707161554.6900-1-siddharthasthana31@gmail.com","subject":"Re: [PATCH v2 0/4] Add support for mailmap in cat-file","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-07-07T22:06:06Z","receivedAt":"2022-07-07T22:06:15Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Siddharth Asthana <siddharthasthana31@gmail.com> writes:\n\n> Changes in v2:\n> - The commit_rewrite_person() has been improved by restricting it to\n>   traverse only the header part of the object buffers.\n> - The callers of commit_rewrite_person() now don't require to call it\n>   multiple times for different headers. They can pass an array of\n>   headers and commit_rewrite_person() replaces idents only on those\n>   headers.\n> - commit_rewrite_person() has been renamed to a suitable name which\n>   expresses its functionality clearly.\n> - More tests have been added to test the --[no-]-use-mailmap option for\n>   the tag objects.\n> - Redundant operations from the tests have been removed.\n\nI agree with the general direction and the implementation strategy.\nI've noticed a few decl-after-statement and also at least one public\nhelper function that does not need to be public.  Are you building\nwith \"make DEVELOPER=YesPlease\"?  It enables -pedantic and -Werror,\n-Wdeclaration-after-statement, among other options (see the\nconfig.mak.dev file for the complete list) to help you catch these\nlocally before sendign your patches to the list.\n\nThanks.\n"},{"id":"458607","messageId":"xmqqmtdky1gq.fsf@gitster.g","threadId":"58088","inReplyTo":"xmqqsfncy3w1.fsf@gitster.g","subject":"Re: [PATCH v2 0/4] Add support for mailmap in cat-file","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-07-07T22:58:29Z","receivedAt":"2022-07-07T22:58:37Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> Siddharth Asthana <siddharthasthana31@gmail.com> writes:\n>\n>> Changes in v2:\n>> - The commit_rewrite_person() has been improved by restricting it to\n>>   traverse only the header part of the object buffers.\n>> - The callers of commit_rewrite_person() now don't require to call it\n>>   multiple times for different headers. They can pass an array of\n>>   headers and commit_rewrite_person() replaces idents only on those\n>>   headers.\n>> - commit_rewrite_person() has been renamed to a suitable name which\n>>   expresses its functionality clearly.\n>> - More tests have been added to test the --[no-]-use-mailmap option for\n>>   the tag objects.\n>> - Redundant operations from the tests have been removed.\n>\n> I agree with the general direction and the implementation strategy.\n> I've noticed a few decl-after-statement and also at least one public\n> helper function that does not need to be public.  Are you building\n> with \"make DEVELOPER=YesPlease\"?  It enables -pedantic and -Werror,\n> -Wdeclaration-after-statement, among other options (see the\n> config.mak.dev file for the complete list) to help you catch these\n> locally before sendign your patches to the list.\n\nHere is what I prepared on top of your series to make them compile\nwhile queuing them on a topic branch.\n\n builtin/cat-file.c | 7 +++++--\n revision.c         | 4 ++--\n 2 files changed, 7 insertions(+), 4 deletions(-)\n\ndiff --git a/builtin/cat-file.c b/builtin/cat-file.c\nindex 6dc750a367..4ca024a018 100644\n--- a/builtin/cat-file.c\n+++ b/builtin/cat-file.c\n@@ -40,11 +40,14 @@ static const char *force_path;\n static struct string_list mailmap = STRING_LIST_INIT_NODUP;\n static int use_mailmap;\n \n-char *replace_idents_using_mailmap(char *object_buf, size_t *size)\n+static char *replace_idents_using_mailmap(char *, size_t *);\n+\n+static char *replace_idents_using_mailmap(char *object_buf, size_t *size)\n {\n \tstruct strbuf sb = STRBUF_INIT;\n-\tstrbuf_attach(&sb, object_buf, *size, *size + 1);\n \tconst char *headers[] = { \"author \", \"committer \", \"tagger \", NULL };\n+\n+\tstrbuf_attach(&sb, object_buf, *size, *size + 1);\n \tapply_mailmap_to_header(&sb, headers, &mailmap);\n \t*size = sb.len;\n \treturn strbuf_detach(&sb, NULL);\ndiff --git a/revision.c b/revision.c\nindex b561d6b5b5..767c6225df 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -3787,10 +3787,10 @@ static int commit_match(struct commit *commit, struct rev_info *opt)\n \t\tstrbuf_addstr(&buf, message);\n \n \tif (opt->grep_filter.header_list && opt->mailmap) {\n+\t\tconst char *commit_headers[] = { \"author \", \"committer \", NULL };\n+\n \t\tif (!buf.len)\n \t\t\tstrbuf_addstr(&buf, message);\n-\n-\t\tconst char *commit_headers[] = { \"author \", \"committer \", NULL };\n \t\tapply_mailmap_to_header(&buf, commit_headers, opt->mailmap);\n \t}\n \n-- \n2.37.0-211-gafcdf5f063\n\n"},{"id":"458631","messageId":"p3n4547s-6134-n4p9-97n5-so696qssr5n2@tzk.qr","threadId":"58088","inReplyTo":"20220707161554.6900-5-siddharthasthana31@gmail.com","subject":"Re: [PATCH v2 4/4] cat-file: add mailmap support","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2022-07-08T11:53:55Z","receivedAt":"2022-07-08T11:54:05Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Siddarth,\n\nOn Thu, 7 Jul 2022, Siddharth Asthana wrote:\n\n> diff --git a/builtin/cat-file.c b/builtin/cat-file.c\n> index 50cf38999d..6dc750a367 100644\n> --- a/builtin/cat-file.c\n> +++ b/builtin/cat-file.c\n> @@ -36,6 +37,19 @@ struct batch_options {\n>\n>  static const char *force_path;\n>\n> +static struct string_list mailmap = STRING_LIST_INIT_NODUP;\n> +static int use_mailmap;\n> +\n> +char *replace_idents_using_mailmap(char *object_buf, size_t *size)\n\nHere, we declare the `size` parameter as a pointer to a `size_t`.\n\n> +{\n> +\tstruct strbuf sb = STRBUF_INIT;\n> +\tstrbuf_attach(&sb, object_buf, *size, *size + 1);\n> +\tconst char *headers[] = { \"author \", \"committer \", \"tagger \", NULL };\n> +\tapply_mailmap_to_header(&sb, headers, &mailmap);\n> +\t*size = sb.len;\n> +\treturn strbuf_detach(&sb, NULL);\n> +}\n> +\n>  static int filter_object(const char *path, unsigned mode,\n>  \t\t\t const struct object_id *oid,\n>  \t\t\t char **buf, unsigned long *size)\n> @@ -152,6 +166,9 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,\n>  \t\tif (!buf)\n>  \t\t\tdie(\"Cannot read object %s\", obj_name);\n>\n> +\t\tif (use_mailmap)\n> +\t\t\tbuf = replace_idents_using_mailmap(buf, &size);\n\nBut here, we are once more bitten by Git's usage of last century's data\ntypes: the `size` variable is of type `unsigned long`.\n\nNow, you are probably developing this patch on 64-bit Linux or macOS,\nwhere it just so happens that `size_t` is idempotent to `unsigned long`.\n\nBut that is not the case on 32-bit Linux nor on Windows, and therefore the\nbuild fails with this patch. I need this to get the build to pass:\n\n-- snipsnap --\nFrom 237c783705b30ed4bcce81aeb860dc7e152fc8bf Mon Sep 17 00:00:00 2001\nFrom: Johannes Schindelin <johannes.schindelin@gmx.de>\nDate: Fri, 8 Jul 2022 13:47:52 +0200\nSubject: [PATCH] fixup??? cat-file: add mailmap support\n\nThis is needed whenever `unsigned long` is different from `size_t`, e.g.\non 32-bit Linux and on Windows.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/cat-file.c | 27 +++++++++++++++++++++------\n 1 file changed, 21 insertions(+), 6 deletions(-)\n\ndiff --git a/builtin/cat-file.c b/builtin/cat-file.c\nindex ac852087a74..baa6aca53ce 100644\n--- a/builtin/cat-file.c\n+++ b/builtin/cat-file.c\n@@ -185,8 +185,13 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,\n \t\tif (!buf)\n \t\t\tdie(\"Cannot read object %s\", obj_name);\n\n-\t\tif (use_mailmap)\n-\t\t\tbuf = replace_idents_using_mailmap(buf, &size);\n+\t\tif (use_mailmap) {\n+\t\t\tsize_t s;\n+\n+\t\t\tbuf = replace_idents_using_mailmap(buf, &s);\n+\n+\t\t\tsize = cast_size_t_to_ulong(s);\n+\t\t}\n\n \t\t/* otherwise just spit out the data */\n \t\tbreak;\n@@ -222,8 +227,13 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,\n \t\tbuf = read_object_with_reference(the_repository, &oid,\n \t\t\t\t\t\t exp_type_id, &size, NULL);\n\n-\t\tif (use_mailmap)\n-\t\t\tbuf = replace_idents_using_mailmap(buf, &size);\n+\t\tif (use_mailmap) {\n+\t\t\tsize_t s;\n+\n+\t\t\tbuf = replace_idents_using_mailmap(buf, &s);\n+\n+\t\t\tsize = cast_size_t_to_ulong(s);\n+\t\t}\n \t\tbreak;\n \t}\n \tdefault:\n@@ -392,8 +402,13 @@ static void print_object_or_die(struct batch_options *opt, struct expand_data *d\n\n \t\tcontents = read_object_file(oid, &type, &size);\n\n-\t\tif (use_mailmap)\n-\t\t\tcontents = replace_idents_using_mailmap(contents, &size);\n+\t\tif (use_mailmap) {\n+\t\t\tsize_t s;\n+\n+\t\t\tcontents = replace_idents_using_mailmap(contents, &s);\n+\n+\t\t\tsize = cast_size_t_to_ulong(s);\n+\t\t}\n\n \t\tif (!contents)\n \t\t\tdie(\"object %s disappeared\", oid_to_hex(oid));\n--\n2.37.0.windows.1\n\n"},{"id":"458640","messageId":"YshESKSHfpcQf/dI@danh.dev","threadId":"58088","inReplyTo":"20220707161554.6900-2-siddharthasthana31@gmail.com","subject":"Re: [PATCH v2 1/4] revision: improve commit_rewrite_person()","fromName":"Đoàn Trần Công Danh","fromEmail":"congdanhqx@gmail.com","sentAt":"2022-07-08T14:50:48Z","receivedAt":"2022-07-08T14:50:55Z","isPatch":true,"sender":{"key":"congdanhqx@gmail.com","avatar":"https://avatars.githubusercontent.com/u/42673067?v=4"},"body":"On 2022-07-07 21:45:51+0530, Siddharth Asthana <siddharthasthana31@gmail.com> wrote:\n> The function, commit_rewrite_person(), is designed to find and replace\n> an ident string in the header part, and the way it avoids a random\n> occuranace of \"author A U Thor <author@example.com\" in the text is by\n\ns/occuranace/occurrence/\n\n> insisting \"author\" to appear at the beginning of line by passing\n> \"\\nauthor \" as \"what\".\n> \n> The implementation also doesn't make any effort to limit itself to the\n> commit header by locating the blank line that appears after the header\n> part and stopping the search there. Also, the interface forces the\n> caller to make multiple calls if it wants to rewrite idents on multiple\n> headers. It shouldn't be the case.\n> \n> To support the existing caller better, update commit_rewrite_person()\n> to:\n> - Make a single pass in the input buffer to locate headers named\n>   \"author\" and \"committer\" and replace idents on them.\n> - Stop at the end of the header, ensuring that nothing in the body of\n>   the commit object is modified.\n> \n> The return type of the function commit_rewrite_person() has also been\n> changed from int to void. This has been done because the caller of the\n> function doesn't do anything with the return value of the function.\n> \n> By simplyfying the interface of the commit_rewrite_person(), we also\n\ns/simplyfying/simplifying/\n\n> intend to expose it as a public function. We will also be renaming the\n> function in a future commit to a different name which clearly tells that\n> the function replaces idents in the header of the commit buffer.\n> \n> Mentored-by: Christian Couder <christian.couder@gmail.com>\n> Mentored-by: John Cai <johncai86@gmail.com>\n> Signed-off-by: Siddharth Asthana <siddharthasthana31@gmail.com>\n> ---\n>  revision.c | 44 ++++++++++++++++++++++++++++++++++----------\n>  1 file changed, 34 insertions(+), 10 deletions(-)\n> \n> diff --git a/revision.c b/revision.c\n> index 211352795c..83e68c1f97 100644\n> --- a/revision.c\n> +++ b/revision.c\n> @@ -3755,19 +3755,17 @@ int rewrite_parents(struct rev_info *revs, struct commit *commit,\n>  \treturn 0;\n>  }\n>  \n> -static int commit_rewrite_person(struct strbuf *buf, const char *what, struct string_list *mailmap)\n> +/*\n> + * Returns the difference between the new and old length of the ident line.\n> + */\n> +static ssize_t rewrite_ident_line(const char* person, struct strbuf *buf, struct string_list *mailmap)\n>  {\n> -\tchar *person, *endp;\n> +\tchar *endp;\n>  \tsize_t len, namelen, maillen;\n>  \tconst char *name;\n>  \tconst char *mail;\n>  \tstruct ident_split ident;\n>  \n> -\tperson = strstr(buf->buf, what);\n> -\tif (!person)\n> -\t\treturn 0;\n> -\n> -\tperson += strlen(what);\n>  \tendp = strchr(person, '\\n');\n>  \tif (!endp)\n>  \t\treturn 0;\n> @@ -3784,6 +3782,7 @@ static int commit_rewrite_person(struct strbuf *buf, const char *what, struct st\n>  \n>  \tif (map_user(mailmap, &mail, &maillen, &name, &namelen)) {\n>  \t\tstruct strbuf namemail = STRBUF_INIT;\n> +\t\tsize_t newlen;\n>  \n>  \t\tstrbuf_addf(&namemail, \"%.*s <%.*s>\",\n>  \t\t\t    (int)namelen, name, (int)maillen, mail);\n> @@ -3792,14 +3791,39 @@ static int commit_rewrite_person(struct strbuf *buf, const char *what, struct st\n>  \t\t\t      ident.mail_end - ident.name_begin + 1,\n>  \t\t\t      namemail.buf, namemail.len);\n>  \n> +\t\tnewlen = namemail.len;\n> +\n>  \t\tstrbuf_release(&namemail);\n>  \n> -\t\treturn 1;\n> +\t\treturn newlen - (ident.mail_end - ident.name_begin + 1);\n>  \t}\n>  \n>  \treturn 0;\n>  }\n>  \n> +static void commit_rewrite_person(struct strbuf *buf, const char **headers, struct string_list *mailmap)\n> +{\n> +\tsize_t buf_offset = 0;\n> +\n> +\tif (!mailmap)\n> +\t\treturn;\n> +\n> +\tfor (;;) {\n> +\t\tconst char *person, *line = buf->buf + buf_offset;\n> +\t\tint i, linelen = strchrnul(line, '\\n') - line + 1;\n\nWould you mind to change those lines to avoid mixed of declaration and\nexpression. Also, I think i and linelen should be ssize_t instead.\nSomething like:\n\n\t\tconst char *person, *line;\n\t\tssize_t i, linelen;\n\n\t\tline = buf->buf + buf_offset;\n\t\tlinelen = strchrnul(line, '\\n') - line + 1;\n\n> +\n> +\t\tif (!linelen || linelen == 1)\n> +\t\t\t/* End of header */\n> +\t\t\treturn;\n\nAnd I think linelen will never be 0 or negative,\neven if linelen could be 0, I think we want \"linelen != 0\"\nfor integer comparision.\n\n> +\n> +\t\tbuf_offset += linelen;\n> +\n> +\t\tfor (i = 0; headers[i]; i++)\n> +\t\t\tif (skip_prefix(line, headers[i], &person))\n> +\t\t\t\tbuf_offset += rewrite_ident_line(person, buf, mailmap);\n> +\t}\n> +}\n> +\n>  static int commit_match(struct commit *commit, struct rev_info *opt)\n>  {\n>  \tint retval;\n> @@ -3835,8 +3859,8 @@ static int commit_match(struct commit *commit, struct rev_info *opt)\n>  \t\tif (!buf.len)\n>  \t\t\tstrbuf_addstr(&buf, message);\n>  \n> -\t\tcommit_rewrite_person(&buf, \"\\nauthor \", opt->mailmap);\n> -\t\tcommit_rewrite_person(&buf, \"\\ncommitter \", opt->mailmap);\n> +\t\tconst char *commit_headers[] = { \"author \", \"committer \", NULL };\n> +\t\tcommit_rewrite_person(&buf, commit_headers, opt->mailmap);\n>  \t}\n>  \n>  \t/* Append \"fake\" message parts as needed */\n> -- \n> 2.37.0.6.ga6a61a26c1.dirty\n> \n\n-- \nDanh\n"},{"id":"458675","messageId":"YsjTif0TjYBzBXfh@danh.dev","threadId":"58088","inReplyTo":"CAP8UFD116xMnp27pxW8WNDf6PRJxnnwWtcy2TNHU_KyV2ZVA1g@mail.gmail.com","subject":"Re: [PATCH v2 1/4] revision: improve commit_rewrite_person()","fromName":"Đoàn Trần Công Danh","fromEmail":"congdanhqx@gmail.com","sentAt":"2022-07-09T01:02:01Z","receivedAt":"2022-07-09T01:02:07Z","isPatch":true,"sender":{"key":"congdanhqx@gmail.com","avatar":"https://avatars.githubusercontent.com/u/42673067?v=4"},"body":"Add list back to cc\n\nOn 2022-07-08 23:23:07+0200, Christian Couder <christian.couder@gmail.com> wrote:\n> On Fri, Jul 8, 2022 at 4:50 PM Đoàn Trần Công Danh <congdanhqx@gmail.com> wrote:\n> >\n> > On 2022-07-07 21:45:51+0530, Siddharth Asthana <siddharthasthana31@gmail.com> wrote:\n>\n> > > By simplyfying the interface of the commit_rewrite_person(), we also\n> >\n> > s/simplyfying/simplifying/\n>\n> Thanks for noticing the typos!\n>\n> > > +static void commit_rewrite_person(struct strbuf *buf, const char **headers, struct string_list *mailmap)\n> > > +{\n> > > +     size_t buf_offset = 0;\n> > > +\n> > > +     if (!mailmap)\n> > > +             return;\n> > > +\n> > > +     for (;;) {\n> > > +             const char *person, *line = buf->buf + buf_offset;\n> > > +             int i, linelen = strchrnul(line, '\\n') - line + 1;\n> >\n> > Would you mind to change those lines to avoid mixed of declaration and\n> > expression.\n>\n> I am not sure we have some clear guidelines on this.\n\nYes, we don't have a clear guidelines on this, but this would sure\nmatches into mixed declaration and expression. And some variables are\ninitialized and some aren't in the same line. I was confused in my\nfirst glance.\n\n>\n> > Also, I think i and linelen should be ssize_t instead.\n>\n> Could you explain why?\n>\n> I think 'i' is changed only in:\n>\n> for (i = 0; headers[i]; i++)\n>\n> and therefore cannot be négative.\n>\n> While linelen is set only in:\n>\n> linelen = strchrnul(line, '\\n') - line + 1;\n>\n> and therefore cannot be négative either.\n\n\nYes, both of them can't be negative. As I explained in the part you\nremoved.  However, I choose ssize_t in my reply because it's\na ptrdiff_t.\n\nSo, size_t is an obviously a better choice.\nEither size_t and ssize_t could be used in this case, but not int.\n\n\n>>> +\n>>> +             if (!linelen || linelen == 1)\n>>> +                     /* End of header */\n>>> +                     return;\n>>\n>>And I think linelen will never be 0 or negative,\n>>even if linelen could be 0, I think we want \"linelen != 0\"\n>>for integer comparision.\n\n\n-- \nDanh\n"},{"id":"458678","messageId":"CAP8UFD0p+Ty1Fx-vBoX6N0Ahg+Z_JCYe_Jypk7Mag=yY2yzbqg@mail.gmail.com","threadId":"58088","inReplyTo":"YsjTif0TjYBzBXfh@danh.dev","subject":"Re: [PATCH v2 1/4] revision: improve commit_rewrite_person()","fromName":"Christian Couder","fromEmail":"christian.couder@gmail.com","sentAt":"2022-07-09T05:04:03Z","receivedAt":"2022-07-09T05:04:19Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"On Sat, Jul 9, 2022 at 3:02 AM Đoàn Trần Công Danh <congdanhqx@gmail.com> wrote:\n>\n> Add list back to cc\n\nSorry for not keeping the list in Cc by mistake.\n\n> On 2022-07-08 23:23:07+0200, Christian Couder <christian.couder@gmail.com> wrote:\n> > On Fri, Jul 8, 2022 at 4:50 PM Đoàn Trần Công Danh <congdanhqx@gmail.com> wrote:\n> > >\n> > > On 2022-07-07 21:45:51+0530, Siddharth Asthana <siddharthasthana31@gmail.com> wrote:\n> >\n> > > > By simplyfying the interface of the commit_rewrite_person(), we also\n> > >\n> > > s/simplyfying/simplifying/\n> >\n> > Thanks for noticing the typos!\n> >\n> > > > +static void commit_rewrite_person(struct strbuf *buf, const char **headers, struct string_list *mailmap)\n> > > > +{\n> > > > +     size_t buf_offset = 0;\n> > > > +\n> > > > +     if (!mailmap)\n> > > > +             return;\n> > > > +\n> > > > +     for (;;) {\n> > > > +             const char *person, *line = buf->buf + buf_offset;\n> > > > +             int i, linelen = strchrnul(line, '\\n') - line + 1;\n> > >\n> > > Would you mind to change those lines to avoid mixed of declaration and\n> > > expression.\n> >\n> > I am not sure we have some clear guidelines on this.\n>\n> Yes, we don't have a clear guidelines on this, but this would sure\n> matches into mixed declaration and expression. And some variables are\n> initialized and some aren't in the same line. I was confused in my\n> first glance.\n\nYeah, it might be clearer to avoid having some variables both declared\nand initialized while others are only declared on the same line.\n\n> > > Also, I think i and linelen should be ssize_t instead.\n> >\n> > Could you explain why?\n> >\n> > I think 'i' is changed only in:\n> >\n> > for (i = 0; headers[i]; i++)\n> >\n> > and therefore cannot be négative.\n> >\n> > While linelen is set only in:\n> >\n> > linelen = strchrnul(line, '\\n') - line + 1;\n> >\n> > and therefore cannot be négative either.\n>\n> Yes, both of them can't be negative. As I explained in the part you\n> removed.  However, I choose ssize_t in my reply because it's\n> a ptrdiff_t.\n>\n> So, size_t is an obviously a better choice.\n> Either size_t and ssize_t could be used in this case, but not int.\n\nI am Ok with size_t. Thanks for the explanations!\n\n> >>> +\n> >>> +             if (!linelen || linelen == 1)\n> >>> +                     /* End of header */\n> >>> +                     return;\n> >>\n> >>And I think linelen will never be 0 or negative,\n> >>even if linelen could be 0, I think we want \"linelen != 0\"\n> >>for integer comparision.\n\nmaybe `if (linelen <=1)` is just a simpler check.\n"},{"id":"458683","messageId":"20220709154149.165524-1-siddharthasthana31@gmail.com","threadId":"58088","inReplyTo":"20220707161554.6900-1-siddharthasthana31@gmail.com","subject":"[PATCH v3 0/4] Add support for mailmap in cat-file","fromName":"Siddharth Asthana","fromEmail":"siddharthasthana31@gmail.com","sentAt":"2022-07-09T15:41:45Z","receivedAt":"2022-07-09T15:42:15Z","isPatch":true,"sender":{"key":"siddharthasthana31@gmail.com","avatar":"https://avatars.githubusercontent.com/u/53316982?v=4"},"body":"Thanks a lot for the review and suggestions Junio, Danh and Johannes.\nReally grateful for that :)\n\n= Description\n\nThis patch series adds mailmap support to the git-cat-file command. It\nadds the mailmap support only for the commit and tag objects by\nreplacing the idents for \"author\", \"committer\" and \"tagger\" headers. The\nmailmap only takes effect when --[no-]-use-mailmap or --[no-]-mailmap\noption is passed to the git cat-file command. The changes will work with\nthe batch mode as well.\n\nSo, if one wants to enable mailmap they can use either of the following\ncommands:\n$ git cat-file --use-mailmap -p <object>\n$ git cat-file --use-mailmap <type> <object>\n\nTo use it in the batch mode, one can use the following command:\n$ git cat-file --use-mailmap --batch\n\n= Patch Organization\n\n- The first patch improves the commit_rewrite_person() by restricting it \n  to traverse only through the header part of the commit object buffer.\n  It also adds an argument called headers which the callers can pass. \n  The function will replace idents only on these  passed headers. \n  Thus, the caller won't have to make repeated calls to the function.\n- The second patch moves commit_rewrite_person() to ident.c to expose it\n  as a public function so that it can be used to replace idents in the\n  headers of desired objects.\n- The third patch renames commit_rewrite_person() to a name which\n  describes its functionality clearly. It is renamed to\n  apply_mailmap_to_header().\n- The last patch adds mailmap support to the git cat-file command. It\n  adds the required documentation and tests as well.\n\nChanges in v3:\n- The decl-after-statement warnings have been fixed in all the patches.\n- In commit_rewrite_person(), the data type of linelen and i variables\n  have been changed from int to size_t.\n- The return type of replace_idents_using_mailmap() function, size_t,\n  has been explicitly typecasted to unsigned long using the\n  cast_size_t_to_ulong() helper method.\n\nSiddharth Asthana (4):\n  revision: improve commit_rewrite_person()\n  ident: move commit_rewrite_person() to ident.c\n  ident: rename commit_rewrite_person() to apply_mailmap_to_header()\n  cat-file: add mailmap support\n\n Documentation/git-cat-file.txt |  6 +++\n builtin/cat-file.c             | 43 +++++++++++++++++++-\n cache.h                        |  6 +++\n ident.c                        | 72 ++++++++++++++++++++++++++++++++++\n revision.c                     | 50 ++---------------------\n t/t4203-mailmap.sh             | 54 +++++++++++++++++++++++++\n 6 files changed, 183 insertions(+), 48 deletions(-)\n\nRange-diff against v2:\n1:  64e1f750e1 ! 1:  9e95326c58 revision: improve commit_rewrite_person()\n    @@ Commit message\n     \n         The function, commit_rewrite_person(), is designed to find and replace\n         an ident string in the header part, and the way it avoids a random\n    -    occuranace of \"author A U Thor <author@example.com\" in the text is by\n    +    occurrence of \"author A U Thor <author@example.com\" in the text is by\n         insisting \"author\" to appear at the beginning of line by passing\n         \"\\nauthor \" as \"what\".\n     \n    @@ Commit message\n         changed from int to void. This has been done because the caller of the\n         function doesn't do anything with the return value of the function.\n     \n    -    By simplyfying the interface of the commit_rewrite_person(), we also\n    +    By simplifying the interface of the commit_rewrite_person(), we also\n         intend to expose it as a public function. We will also be renaming the\n         function in a future commit to a different name which clearly tells that\n         the function replaces idents in the header of the commit buffer.\n     \n         Mentored-by: Christian Couder <christian.couder@gmail.com>\n         Mentored-by: John Cai <johncai86@gmail.com>\n    +    Helped-by: Đoàn Trần Công Danh <congdanhqx@gmail.com>\n         Signed-off-by: Siddharth Asthana <siddharthasthana31@gmail.com>\n     \n      ## revision.c ##\n    @@ revision.c: static int commit_rewrite_person(struct strbuf *buf, const char *wha\n     +\t\treturn;\n     +\n     +\tfor (;;) {\n    -+\t\tconst char *person, *line = buf->buf + buf_offset;\n    -+\t\tint i, linelen = strchrnul(line, '\\n') - line + 1;\n    ++\t\tconst char *person, *line;\n    ++\t\tsize_t i, linelen;\n     +\n    -+\t\tif (!linelen || linelen == 1)\n    ++\t\tline = buf->buf + buf_offset;\n    ++\t\tlinelen = strchrnul(line, '\\n') - line + 1;\n    ++\n    ++\t\tif (linelen <= 1)\n     +\t\t\t/* End of header */\n     +\t\t\treturn;\n     +\n    @@ revision.c: static int commit_rewrite_person(struct strbuf *buf, const char *wha\n      {\n      \tint retval;\n     @@ revision.c: static int commit_match(struct commit *commit, struct rev_info *opt)\n    + \t\tstrbuf_addstr(&buf, message);\n    + \n    + \tif (opt->grep_filter.header_list && opt->mailmap) {\n    ++\t\tconst char *commit_headers[] = { \"author \", \"committer \", NULL };\n    ++\n      \t\tif (!buf.len)\n      \t\t\tstrbuf_addstr(&buf, message);\n      \n     -\t\tcommit_rewrite_person(&buf, \"\\nauthor \", opt->mailmap);\n     -\t\tcommit_rewrite_person(&buf, \"\\ncommitter \", opt->mailmap);\n    -+\t\tconst char *commit_headers[] = { \"author \", \"committer \", NULL };\n     +\t\tcommit_rewrite_person(&buf, commit_headers, opt->mailmap);\n      \t}\n      \n2:  b18ced0ece ! 2:  d9395cb8b2 ident: move commit_rewrite_person() to ident.c\n    @@ ident.c: int split_ident_line(struct ident_split *split, const char *line, int l\n     +\t\treturn;\n     +\n     +\tfor (;;) {\n    -+\t\tconst char *person, *line = buf->buf + buf_offset;\n    -+\t\tint i, linelen = strchrnul(line, '\\n') - line + 1;\n    ++\t\tconst char *person, *line;\n    ++\t\tsize_t i, linelen;\n     +\n    -+\t\tif (!linelen || linelen == 1)\n    ++\t\tline = buf->buf + buf_offset;\n    ++\t\tlinelen = strchrnul(line, '\\n') - line + 1;\n    ++\n    ++\t\tif (linelen <= 1)\n     +\t\t\t/* End of header */\n     +\t\t\treturn;\n     +\n    @@ revision.c: int rewrite_parents(struct rev_info *revs, struct commit *commit,\n     -\t\treturn;\n     -\n     -\tfor (;;) {\n    --\t\tconst char *person, *line = buf->buf + buf_offset;\n    --\t\tint i, linelen = strchrnul(line, '\\n') - line + 1;\n    +-\t\tconst char *person, *line;\n    +-\t\tsize_t i, linelen;\n    +-\n    +-\t\tline = buf->buf + buf_offset;\n    +-\t\tlinelen = strchrnul(line, '\\n') - line + 1;\n     -\n    --\t\tif (!linelen || linelen == 1)\n    +-\t\tif (linelen <= 1)\n     -\t\t\t/* End of header */\n     -\t\t\treturn;\n     -\n3:  2494ce1ed2 ! 3:  355bbda25e ident: rename commit_rewrite_person() to apply_mailmap_to_header()\n    @@ ident.c: static ssize_t rewrite_ident_line(const char* person, struct strbuf *bu\n     \n      ## revision.c ##\n     @@ revision.c: static int commit_match(struct commit *commit, struct rev_info *opt)\n    + \t\tif (!buf.len)\n      \t\t\tstrbuf_addstr(&buf, message);\n      \n    - \t\tconst char *commit_headers[] = { \"author \", \"committer \", NULL };\n     -\t\tcommit_rewrite_person(&buf, commit_headers, opt->mailmap);\n     +\t\tapply_mailmap_to_header(&buf, commit_headers, opt->mailmap);\n      \t}\n4:  94838a2566 ! 4:  69b7ad898b cat-file: add mailmap support\n    @@ Commit message\n         Mentored-by: Christian Couder <christian.couder@gmail.com>\n         Mentored-by: John Cai <johncai86@gmail.com>\n         Helped-by: Phillip Wood <phillip.wood@dunelm.org.uk>\n    +    Helped-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>\n         Signed-off-by: Siddharth Asthana <siddharthasthana31@gmail.com>\n     \n      ## Documentation/git-cat-file.txt ##\n    @@ builtin/cat-file.c: struct batch_options {\n     +static struct string_list mailmap = STRING_LIST_INIT_NODUP;\n     +static int use_mailmap;\n     +\n    -+char *replace_idents_using_mailmap(char *object_buf, size_t *size)\n    ++static char *replace_idents_using_mailmap(char *, size_t *);\n    ++\n    ++static char *replace_idents_using_mailmap(char *object_buf, size_t *size)\n     +{\n     +\tstruct strbuf sb = STRBUF_INIT;\n    -+\tstrbuf_attach(&sb, object_buf, *size, *size + 1);\n     +\tconst char *headers[] = { \"author \", \"committer \", \"tagger \", NULL };\n    ++\n    ++\tstrbuf_attach(&sb, object_buf, *size, *size + 1);\n     +\tapply_mailmap_to_header(&sb, headers, &mailmap);\n     +\t*size = sb.len;\n     +\treturn strbuf_detach(&sb, NULL);\n    @@ builtin/cat-file.c: static int cat_one_file(int opt, const char *exp_type, const\n      \t\tif (!buf)\n      \t\t\tdie(\"Cannot read object %s\", obj_name);\n      \n    -+\t\tif (use_mailmap)\n    -+\t\t\tbuf = replace_idents_using_mailmap(buf, &size);\n    ++\t\tif (use_mailmap) {\n    ++\t\t\tsize_t s = size;\n    ++\t\t\tbuf = replace_idents_using_mailmap(buf, &s);\n    ++\t\t\tsize = cast_size_t_to_ulong(s);\n    ++\t\t}\n     +\n      \t\t/* otherwise just spit out the data */\n      \t\tbreak;\n    @@ builtin/cat-file.c: static int cat_one_file(int opt, const char *exp_type, const\n      \t\tbuf = read_object_with_reference(the_repository, &oid,\n      \t\t\t\t\t\t exp_type_id, &size, NULL);\n     +\n    -+\t\tif (use_mailmap)\n    -+\t\t\tbuf = replace_idents_using_mailmap(buf, &size);\n    ++\t\tif (use_mailmap) {\n    ++\t\t\tsize_t s = size;\n    ++\t\t\tbuf = replace_idents_using_mailmap(buf, &s);\n    ++\t\t\tsize = cast_size_t_to_ulong(s);\n    ++\t\t}\n      \t\tbreak;\n      \t}\n      \tdefault:\n    @@ builtin/cat-file.c: static void print_object_or_die(struct batch_options *opt, s\n      \n      \t\tcontents = read_object_file(oid, &type, &size);\n     +\n    -+\t\tif (use_mailmap)\n    -+\t\t\tcontents = replace_idents_using_mailmap(contents, &size);\n    ++\t\tif (use_mailmap) {\n    ++\t\t\tsize_t s = size;\n    ++\t\t\tcontents = replace_idents_using_mailmap(contents, &s);\n    ++\t\t\tsize = cast_size_t_to_ulong(s);\n    ++\t\t}\n     +\n      \t\tif (!contents)\n      \t\t\tdie(\"object %s disappeared\", oid_to_hex(oid));\n-- \n2.37.0.6.g69b7ad898b\n\n"},{"id":"458684","messageId":"20220709154149.165524-2-siddharthasthana31@gmail.com","threadId":"58088","inReplyTo":"20220709154149.165524-1-siddharthasthana31@gmail.com","subject":"[PATCH v3 1/4] revision: improve commit_rewrite_person()","fromName":"Siddharth Asthana","fromEmail":"siddharthasthana31@gmail.com","sentAt":"2022-07-09T15:41:46Z","receivedAt":"2022-07-09T15:42:32Z","isPatch":true,"sender":{"key":"siddharthasthana31@gmail.com","avatar":"https://avatars.githubusercontent.com/u/53316982?v=4"},"body":"The function, commit_rewrite_person(), is designed to find and replace\nan ident string in the header part, and the way it avoids a random\noccurrence of \"author A U Thor <author@example.com\" in the text is by\ninsisting \"author\" to appear at the beginning of line by passing\n\"\\nauthor \" as \"what\".\n\nThe implementation also doesn't make any effort to limit itself to the\ncommit header by locating the blank line that appears after the header\npart and stopping the search there. Also, the interface forces the\ncaller to make multiple calls if it wants to rewrite idents on multiple\nheaders. It shouldn't be the case.\n\nTo support the existing caller better, update commit_rewrite_person()\nto:\n- Make a single pass in the input buffer to locate headers named\n  \"author\" and \"committer\" and replace idents on them.\n- Stop at the end of the header, ensuring that nothing in the body of\n  the commit object is modified.\n\nThe return type of the function commit_rewrite_person() has also been\nchanged from int to void. This has been done because the caller of the\nfunction doesn't do anything with the return value of the function.\n\nBy simplifying the interface of the commit_rewrite_person(), we also\nintend to expose it as a public function. We will also be renaming the\nfunction in a future commit to a different name which clearly tells that\nthe function replaces idents in the header of the commit buffer.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: John Cai <johncai86@gmail.com>\nHelped-by: Đoàn Trần Công Danh <congdanhqx@gmail.com>\nSigned-off-by: Siddharth Asthana <siddharthasthana31@gmail.com>\n---\n revision.c | 48 ++++++++++++++++++++++++++++++++++++++----------\n 1 file changed, 38 insertions(+), 10 deletions(-)\n\ndiff --git a/revision.c b/revision.c\nindex 211352795c..1939c56c67 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -3755,19 +3755,17 @@ int rewrite_parents(struct rev_info *revs, struct commit *commit,\n \treturn 0;\n }\n \n-static int commit_rewrite_person(struct strbuf *buf, const char *what, struct string_list *mailmap)\n+/*\n+ * Returns the difference between the new and old length of the ident line.\n+ */\n+static ssize_t rewrite_ident_line(const char* person, struct strbuf *buf, struct string_list *mailmap)\n {\n-\tchar *person, *endp;\n+\tchar *endp;\n \tsize_t len, namelen, maillen;\n \tconst char *name;\n \tconst char *mail;\n \tstruct ident_split ident;\n \n-\tperson = strstr(buf->buf, what);\n-\tif (!person)\n-\t\treturn 0;\n-\n-\tperson += strlen(what);\n \tendp = strchr(person, '\\n');\n \tif (!endp)\n \t\treturn 0;\n@@ -3784,6 +3782,7 @@ static int commit_rewrite_person(struct strbuf *buf, const char *what, struct st\n \n \tif (map_user(mailmap, &mail, &maillen, &name, &namelen)) {\n \t\tstruct strbuf namemail = STRBUF_INIT;\n+\t\tsize_t newlen;\n \n \t\tstrbuf_addf(&namemail, \"%.*s <%.*s>\",\n \t\t\t    (int)namelen, name, (int)maillen, mail);\n@@ -3792,14 +3791,42 @@ static int commit_rewrite_person(struct strbuf *buf, const char *what, struct st\n \t\t\t      ident.mail_end - ident.name_begin + 1,\n \t\t\t      namemail.buf, namemail.len);\n \n+\t\tnewlen = namemail.len;\n+\n \t\tstrbuf_release(&namemail);\n \n-\t\treturn 1;\n+\t\treturn newlen - (ident.mail_end - ident.name_begin + 1);\n \t}\n \n \treturn 0;\n }\n \n+static void commit_rewrite_person(struct strbuf *buf, const char **headers, struct string_list *mailmap)\n+{\n+\tsize_t buf_offset = 0;\n+\n+\tif (!mailmap)\n+\t\treturn;\n+\n+\tfor (;;) {\n+\t\tconst char *person, *line;\n+\t\tsize_t i, linelen;\n+\n+\t\tline = buf->buf + buf_offset;\n+\t\tlinelen = strchrnul(line, '\\n') - line + 1;\n+\n+\t\tif (linelen <= 1)\n+\t\t\t/* End of header */\n+\t\t\treturn;\n+\n+\t\tbuf_offset += linelen;\n+\n+\t\tfor (i = 0; headers[i]; i++)\n+\t\t\tif (skip_prefix(line, headers[i], &person))\n+\t\t\t\tbuf_offset += rewrite_ident_line(person, buf, mailmap);\n+\t}\n+}\n+\n static int commit_match(struct commit *commit, struct rev_info *opt)\n {\n \tint retval;\n@@ -3832,11 +3859,12 @@ static int commit_match(struct commit *commit, struct rev_info *opt)\n \t\tstrbuf_addstr(&buf, message);\n \n \tif (opt->grep_filter.header_list && opt->mailmap) {\n+\t\tconst char *commit_headers[] = { \"author \", \"committer \", NULL };\n+\n \t\tif (!buf.len)\n \t\t\tstrbuf_addstr(&buf, message);\n \n-\t\tcommit_rewrite_person(&buf, \"\\nauthor \", opt->mailmap);\n-\t\tcommit_rewrite_person(&buf, \"\\ncommitter \", opt->mailmap);\n+\t\tcommit_rewrite_person(&buf, commit_headers, opt->mailmap);\n \t}\n \n \t/* Append \"fake\" message parts as needed */\n-- \n2.37.0.6.g69b7ad898b\n\n"},{"id":"458685","messageId":"20220709154149.165524-3-siddharthasthana31@gmail.com","threadId":"58088","inReplyTo":"20220709154149.165524-1-siddharthasthana31@gmail.com","subject":"[PATCH v3 2/4] ident: move commit_rewrite_person() to ident.c","fromName":"Siddharth Asthana","fromEmail":"siddharthasthana31@gmail.com","sentAt":"2022-07-09T15:41:47Z","receivedAt":"2022-07-09T15:42:37Z","isPatch":true,"sender":{"key":"siddharthasthana31@gmail.com","avatar":"https://avatars.githubusercontent.com/u/53316982?v=4"},"body":"commit_rewrite_person() and rewrite_ident_line() are static functions\ndefined in revision.c.\n\nTheir usages are as follows:\n- commit_rewrite_person() takes a commit buffer and replaces the author\n  and committer idents with their canonical versions using the mailmap\n  mechanism\n- rewrite_ident_line() takes author/committer header lines from the\n  commit buffer and replaces the idents with their canonical versions\n  using the mailmap mechanism.\n\nThis patch moves commit_rewrite_person() and rewrite_ident_line() to\nident.c which contains many other functions related to idents like\nsplit_ident_line(). By moving commit_rewrite_person() to ident.c, we\nalso intend to use it in git-cat-file to replace committer and author\nidents from the headers to their canonical versions using the mailmap\nmechanism. The function is moved as is for now to make it clear that\nthere are no other changes, but it will be renamed in a following\ncommit.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: John Cai <johncai86@gmail.com>\nSigned-off-by: Siddharth Asthana <siddharthasthana31@gmail.com>\n---\n cache.h    |  6 +++++\n ident.c    | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++++++\n revision.c | 72 ------------------------------------------------------\n 3 files changed, 78 insertions(+), 72 deletions(-)\n\ndiff --git a/cache.h b/cache.h\nindex ac5ab4ef9d..c9dbe1c29a 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -1688,6 +1688,12 @@ struct ident_split {\n  */\n int split_ident_line(struct ident_split *, const char *, int);\n \n+/*\n+ * Given a commit object buffer and the commit headers, replaces the idents\n+ * in the headers with their canonical versions using the mailmap mechanism.\n+ */\n+void commit_rewrite_person(struct strbuf *buf, const char **commit_headers, struct string_list *mailmap);\n+\n /*\n  * Compare split idents for equality or strict ordering. Note that we\n  * compare only the ident part of the line, ignoring any timestamp.\ndiff --git a/ident.c b/ident.c\nindex 89ca5b4700..9f4f6e9071 100644\n--- a/ident.c\n+++ b/ident.c\n@@ -8,6 +8,7 @@\n #include \"cache.h\"\n #include \"config.h\"\n #include \"date.h\"\n+#include \"mailmap.h\"\n \n static struct strbuf git_default_name = STRBUF_INIT;\n static struct strbuf git_default_email = STRBUF_INIT;\n@@ -346,6 +347,77 @@ int split_ident_line(struct ident_split *split, const char *line, int len)\n \treturn 0;\n }\n \n+/*\n+ * Returns the difference between the new and old length of the ident line.\n+ */\n+static ssize_t rewrite_ident_line(const char* person, struct strbuf *buf, struct string_list *mailmap)\n+{\n+\tchar *endp;\n+\tsize_t len, namelen, maillen;\n+\tconst char *name;\n+\tconst char *mail;\n+\tstruct ident_split ident;\n+\n+\tendp = strchr(person, '\\n');\n+\tif (!endp)\n+\t\treturn 0;\n+\n+\tlen = endp - person;\n+\n+\tif (split_ident_line(&ident, person, len))\n+\t\treturn 0;\n+\n+\tmail = ident.mail_begin;\n+\tmaillen = ident.mail_end - ident.mail_begin;\n+\tname = ident.name_begin;\n+\tnamelen = ident.name_end - ident.name_begin;\n+\n+\tif (map_user(mailmap, &mail, &maillen, &name, &namelen)) {\n+\t\tstruct strbuf namemail = STRBUF_INIT;\n+\t\tsize_t newlen;\n+\n+\t\tstrbuf_addf(&namemail, \"%.*s <%.*s>\",\n+\t\t\t    (int)namelen, name, (int)maillen, mail);\n+\n+\t\tstrbuf_splice(buf, ident.name_begin - buf->buf,\n+\t\t\t      ident.mail_end - ident.name_begin + 1,\n+\t\t\t      namemail.buf, namemail.len);\n+\n+\t\tnewlen = namemail.len;\n+\n+\t\tstrbuf_release(&namemail);\n+\n+\t\treturn newlen - (ident.mail_end - ident.name_begin + 1);\n+\t}\n+\n+\treturn 0;\n+}\n+\n+void commit_rewrite_person(struct strbuf *buf, const char **headers, struct string_list *mailmap)\n+{\n+\tsize_t buf_offset = 0;\n+\n+\tif (!mailmap)\n+\t\treturn;\n+\n+\tfor (;;) {\n+\t\tconst char *person, *line;\n+\t\tsize_t i, linelen;\n+\n+\t\tline = buf->buf + buf_offset;\n+\t\tlinelen = strchrnul(line, '\\n') - line + 1;\n+\n+\t\tif (linelen <= 1)\n+\t\t\t/* End of header */\n+\t\t\treturn;\n+\n+\t\tbuf_offset += linelen;\n+\n+\t\tfor (i = 0; headers[i]; i++)\n+\t\t\tif (skip_prefix(line, headers[i], &person))\n+\t\t\t\tbuf_offset += rewrite_ident_line(person, buf, mailmap);\n+\t}\n+}\n \n static void ident_env_hint(enum want_ident whose_ident)\n {\ndiff --git a/revision.c b/revision.c\nindex 1939c56c67..14dca903b6 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -3755,78 +3755,6 @@ int rewrite_parents(struct rev_info *revs, struct commit *commit,\n \treturn 0;\n }\n \n-/*\n- * Returns the difference between the new and old length of the ident line.\n- */\n-static ssize_t rewrite_ident_line(const char* person, struct strbuf *buf, struct string_list *mailmap)\n-{\n-\tchar *endp;\n-\tsize_t len, namelen, maillen;\n-\tconst char *name;\n-\tconst char *mail;\n-\tstruct ident_split ident;\n-\n-\tendp = strchr(person, '\\n');\n-\tif (!endp)\n-\t\treturn 0;\n-\n-\tlen = endp - person;\n-\n-\tif (split_ident_line(&ident, person, len))\n-\t\treturn 0;\n-\n-\tmail = ident.mail_begin;\n-\tmaillen = ident.mail_end - ident.mail_begin;\n-\tname = ident.name_begin;\n-\tnamelen = ident.name_end - ident.name_begin;\n-\n-\tif (map_user(mailmap, &mail, &maillen, &name, &namelen)) {\n-\t\tstruct strbuf namemail = STRBUF_INIT;\n-\t\tsize_t newlen;\n-\n-\t\tstrbuf_addf(&namemail, \"%.*s <%.*s>\",\n-\t\t\t    (int)namelen, name, (int)maillen, mail);\n-\n-\t\tstrbuf_splice(buf, ident.name_begin - buf->buf,\n-\t\t\t      ident.mail_end - ident.name_begin + 1,\n-\t\t\t      namemail.buf, namemail.len);\n-\n-\t\tnewlen = namemail.len;\n-\n-\t\tstrbuf_release(&namemail);\n-\n-\t\treturn newlen - (ident.mail_end - ident.name_begin + 1);\n-\t}\n-\n-\treturn 0;\n-}\n-\n-static void commit_rewrite_person(struct strbuf *buf, const char **headers, struct string_list *mailmap)\n-{\n-\tsize_t buf_offset = 0;\n-\n-\tif (!mailmap)\n-\t\treturn;\n-\n-\tfor (;;) {\n-\t\tconst char *person, *line;\n-\t\tsize_t i, linelen;\n-\n-\t\tline = buf->buf + buf_offset;\n-\t\tlinelen = strchrnul(line, '\\n') - line + 1;\n-\n-\t\tif (linelen <= 1)\n-\t\t\t/* End of header */\n-\t\t\treturn;\n-\n-\t\tbuf_offset += linelen;\n-\n-\t\tfor (i = 0; headers[i]; i++)\n-\t\t\tif (skip_prefix(line, headers[i], &person))\n-\t\t\t\tbuf_offset += rewrite_ident_line(person, buf, mailmap);\n-\t}\n-}\n-\n static int commit_match(struct commit *commit, struct rev_info *opt)\n {\n \tint retval;\n-- \n2.37.0.6.g69b7ad898b\n\n"},{"id":"458686","messageId":"20220709154149.165524-4-siddharthasthana31@gmail.com","threadId":"58088","inReplyTo":"20220709154149.165524-1-siddharthasthana31@gmail.com","subject":"[PATCH v3 3/4] ident: rename commit_rewrite_person() to apply_mailmap_to_header()","fromName":"Siddharth Asthana","fromEmail":"siddharthasthana31@gmail.com","sentAt":"2022-07-09T15:41:48Z","receivedAt":"2022-07-09T15:42:45Z","isPatch":true,"sender":{"key":"siddharthasthana31@gmail.com","avatar":"https://avatars.githubusercontent.com/u/53316982?v=4"},"body":"commit_rewrite_person() takes a commit buffer and replaces the idents\nin the header with their canonical versions using the mailmap mechanism.\nThe name \"commit_rewrite_person()\" is misleading as it doesn't convey\nwhat kind of rewrite are we going to do to the buffer. It also doesn't\nclearly mention that the function will limit itself to the header part\nof the buffer. The new name, \"apply_mailmap_to_header()\", expresses the\nfunctionality of the function pretty clearly.\n\nWe intend to use apply_mailmap_to_header() in git-cat-file to replace\nidents in the headers of commit and tag object buffers. So, we will be\nextending this function to take tag objects buffer as well and replace\nidents on the tagger header using the mailmap mechanism.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: John Cai <johncai86@gmail.com>\nSigned-off-by: Siddharth Asthana <siddharthasthana31@gmail.com>\n---\n cache.h    | 6 +++---\n ident.c    | 2 +-\n revision.c | 2 +-\n 3 files changed, 5 insertions(+), 5 deletions(-)\n\ndiff --git a/cache.h b/cache.h\nindex c9dbe1c29a..9edb7fefd3 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -1689,10 +1689,10 @@ struct ident_split {\n int split_ident_line(struct ident_split *, const char *, int);\n \n /*\n- * Given a commit object buffer and the commit headers, replaces the idents\n- * in the headers with their canonical versions using the mailmap mechanism.\n+ * Given a commit or tag object buffer and the commit or tag headers, replaces\n+ * the idents in the headers with their canonical versions using the mailmap mechanism.\n  */\n-void commit_rewrite_person(struct strbuf *buf, const char **commit_headers, struct string_list *mailmap);\n+void apply_mailmap_to_header(struct strbuf *buf, const char **headers, struct string_list *mailmap);\n \n /*\n  * Compare split idents for equality or strict ordering. Note that we\ndiff --git a/ident.c b/ident.c\nindex 9f4f6e9071..5f17bd607d 100644\n--- a/ident.c\n+++ b/ident.c\n@@ -393,7 +393,7 @@ static ssize_t rewrite_ident_line(const char* person, struct strbuf *buf, struct\n \treturn 0;\n }\n \n-void commit_rewrite_person(struct strbuf *buf, const char **headers, struct string_list *mailmap)\n+void apply_mailmap_to_header(struct strbuf *buf, const char **headers, struct string_list *mailmap)\n {\n \tsize_t buf_offset = 0;\n \ndiff --git a/revision.c b/revision.c\nindex 14dca903b6..6ad3665204 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -3792,7 +3792,7 @@ static int commit_match(struct commit *commit, struct rev_info *opt)\n \t\tif (!buf.len)\n \t\t\tstrbuf_addstr(&buf, message);\n \n-\t\tcommit_rewrite_person(&buf, commit_headers, opt->mailmap);\n+\t\tapply_mailmap_to_header(&buf, commit_headers, opt->mailmap);\n \t}\n \n \t/* Append \"fake\" message parts as needed */\n-- \n2.37.0.6.g69b7ad898b\n\n"},{"id":"458687","messageId":"20220709154149.165524-5-siddharthasthana31@gmail.com","threadId":"58088","inReplyTo":"20220709154149.165524-1-siddharthasthana31@gmail.com","subject":"[PATCH v3 4/4] cat-file: add mailmap support","fromName":"Siddharth Asthana","fromEmail":"siddharthasthana31@gmail.com","sentAt":"2022-07-09T15:41:49Z","receivedAt":"2022-07-09T15:42:57Z","isPatch":true,"sender":{"key":"siddharthasthana31@gmail.com","avatar":"https://avatars.githubusercontent.com/u/53316982?v=4"},"body":"git-cat-file is used by tools like GitLab to get commit tag contents\nthat are then displayed to users. This content which has author,\ncommitter or tagger information, could benefit from passing through the\nmailmap mechanism before being sent or displayed.\n\nThis patch adds --[no-]use-mailmap command line option to the git\ncat-file command. It also adds --[no-]mailmap option as an alias to\n--[no-]use-mailmap.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: John Cai <johncai86@gmail.com>\nHelped-by: Phillip Wood <phillip.wood@dunelm.org.uk>\nHelped-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>\nSigned-off-by: Siddharth Asthana <siddharthasthana31@gmail.com>\n---\n Documentation/git-cat-file.txt |  6 ++++\n builtin/cat-file.c             | 43 ++++++++++++++++++++++++++-\n t/t4203-mailmap.sh             | 54 ++++++++++++++++++++++++++++++++++\n 3 files changed, 102 insertions(+), 1 deletion(-)\n\ndiff --git a/Documentation/git-cat-file.txt b/Documentation/git-cat-file.txt\nindex 24a811f0ef..1880e9bba1 100644\n--- a/Documentation/git-cat-file.txt\n+++ b/Documentation/git-cat-file.txt\n@@ -63,6 +63,12 @@ OPTIONS\n \tor to ask for a \"blob\" with `<object>` being a tag object that\n \tpoints at it.\n \n+--[no-]mailmap::\n+--[no-]use-mailmap::\n+       Use mailmap file to map author, committer and tagger names\n+       and email addresses to canonical real names and email addresses.\n+       See linkgit:git-shortlog[1].\n+\n --textconv::\n \tShow the content as transformed by a textconv filter. In this case,\n \t`<object>` has to be of the form `<tree-ish>:<path>`, or `:<path>` in\ndiff --git a/builtin/cat-file.c b/builtin/cat-file.c\nindex 50cf38999d..4b68216b51 100644\n--- a/builtin/cat-file.c\n+++ b/builtin/cat-file.c\n@@ -16,6 +16,7 @@\n #include \"packfile.h\"\n #include \"object-store.h\"\n #include \"promisor-remote.h\"\n+#include \"mailmap.h\"\n \n enum batch_mode {\n \tBATCH_MODE_CONTENTS,\n@@ -36,6 +37,22 @@ struct batch_options {\n \n static const char *force_path;\n \n+static struct string_list mailmap = STRING_LIST_INIT_NODUP;\n+static int use_mailmap;\n+\n+static char *replace_idents_using_mailmap(char *, size_t *);\n+\n+static char *replace_idents_using_mailmap(char *object_buf, size_t *size)\n+{\n+\tstruct strbuf sb = STRBUF_INIT;\n+\tconst char *headers[] = { \"author \", \"committer \", \"tagger \", NULL };\n+\n+\tstrbuf_attach(&sb, object_buf, *size, *size + 1);\n+\tapply_mailmap_to_header(&sb, headers, &mailmap);\n+\t*size = sb.len;\n+\treturn strbuf_detach(&sb, NULL);\n+}\n+\n static int filter_object(const char *path, unsigned mode,\n \t\t\t const struct object_id *oid,\n \t\t\t char **buf, unsigned long *size)\n@@ -152,6 +169,12 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,\n \t\tif (!buf)\n \t\t\tdie(\"Cannot read object %s\", obj_name);\n \n+\t\tif (use_mailmap) {\n+\t\t\tsize_t s = size;\n+\t\t\tbuf = replace_idents_using_mailmap(buf, &s);\n+\t\t\tsize = cast_size_t_to_ulong(s);\n+\t\t}\n+\n \t\t/* otherwise just spit out the data */\n \t\tbreak;\n \n@@ -183,6 +206,12 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,\n \t\t}\n \t\tbuf = read_object_with_reference(the_repository, &oid,\n \t\t\t\t\t\t exp_type_id, &size, NULL);\n+\n+\t\tif (use_mailmap) {\n+\t\t\tsize_t s = size;\n+\t\t\tbuf = replace_idents_using_mailmap(buf, &s);\n+\t\t\tsize = cast_size_t_to_ulong(s);\n+\t\t}\n \t\tbreak;\n \t}\n \tdefault:\n@@ -348,11 +377,18 @@ static void print_object_or_die(struct batch_options *opt, struct expand_data *d\n \t\tvoid *contents;\n \n \t\tcontents = read_object_file(oid, &type, &size);\n+\n+\t\tif (use_mailmap) {\n+\t\t\tsize_t s = size;\n+\t\t\tcontents = replace_idents_using_mailmap(contents, &s);\n+\t\t\tsize = cast_size_t_to_ulong(s);\n+\t\t}\n+\n \t\tif (!contents)\n \t\t\tdie(\"object %s disappeared\", oid_to_hex(oid));\n \t\tif (type != data->type)\n \t\t\tdie(\"object %s changed type!?\", oid_to_hex(oid));\n-\t\tif (data->info.sizep && size != data->size)\n+\t\tif (data->info.sizep && size != data->size && !use_mailmap)\n \t\t\tdie(\"object %s changed size!?\", oid_to_hex(oid));\n \n \t\tbatch_write(opt, contents, size);\n@@ -843,6 +879,8 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix)\n \t\tOPT_CMDMODE('s', NULL, &opt, N_(\"show object size\"), 's'),\n \t\tOPT_BOOL(0, \"allow-unknown-type\", &unknown_type,\n \t\t\t  N_(\"allow -s and -t to work with broken/corrupt objects\")),\n+\t\tOPT_BOOL(0, \"use-mailmap\", &use_mailmap, N_(\"use mail map file\")),\n+\t\tOPT_ALIAS(0, \"mailmap\", \"use-mailmap\"),\n \t\t/* Batch mode */\n \t\tOPT_GROUP(N_(\"Batch objects requested on stdin (or --batch-all-objects)\")),\n \t\tOPT_CALLBACK_F(0, \"batch\", &batch, N_(\"format\"),\n@@ -885,6 +923,9 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix)\n \topt_cw = (opt == 'c' || opt == 'w');\n \topt_epts = (opt == 'e' || opt == 'p' || opt == 't' || opt == 's');\n \n+\tif (use_mailmap)\n+\t\tread_mailmap(&mailmap);\n+\n \t/* --batch-all-objects? */\n \tif (opt == 'b')\n \t\tbatch.all_objects = 1;\ndiff --git a/t/t4203-mailmap.sh b/t/t4203-mailmap.sh\nindex 0b2d21ec55..c60a90615c 100755\n--- a/t/t4203-mailmap.sh\n+++ b/t/t4203-mailmap.sh\n@@ -963,4 +963,58 @@ test_expect_success SYMLINKS 'symlinks not respected in-tree' '\n \ttest_cmp expect actual\n '\n \n+test_expect_success '--no-use-mailmap disables mailmap in cat-file' '\n+\ttest_when_finished \"rm .mailmap\" &&\n+\tcat >.mailmap <<-EOF &&\n+\tA U Thor <author@example.com> Orig <orig@example.com>\n+\tEOF\n+\tcat >expect <<-EOF &&\n+\tauthor Orig <orig@example.com>\n+\tEOF\n+\tgit cat-file --no-use-mailmap commit HEAD >log &&\n+\tsed -n \"/^author /s/\\([^>]*>\\).*/\\1/p\" log >actual &&\n+\ttest_cmp expect actual\n+'\n+\n+test_expect_success '--use-mailmap enables mailmap in cat-file' '\n+\ttest_when_finished \"rm .mailmap\" &&\n+\tcat >.mailmap <<-EOF &&\n+\tA U Thor <author@example.com> Orig <orig@example.com>\n+\tEOF\n+\tcat >expect <<-EOF &&\n+\tauthor A U Thor <author@example.com>\n+\tEOF\n+\tgit cat-file --use-mailmap commit HEAD >log &&\n+\tsed -n \"/^author /s/\\([^>]*>\\).*/\\1/p\" log >actual &&\n+\ttest_cmp expect actual\n+'\n+\n+test_expect_success '--no-mailmap disables mailmap in cat-file for annotated tag objects' '\n+\ttest_when_finished \"rm .mailmap\" &&\n+\tcat >.mailmap <<-EOF &&\n+\tOrig <orig@example.com> C O Mitter <committer@example.com>\n+\tEOF\n+\tcat >expect <<-EOF &&\n+\ttagger C O Mitter <committer@example.com>\n+\tEOF\n+\tgit tag -a -m \"annotated tag\" v1 &&\n+\tgit cat-file --no-mailmap -p v1 >log &&\n+\tsed -n \"/^tagger /s/\\([^>]*>\\).*/\\1/p\" log >actual &&\n+\ttest_cmp expect actual\n+'\n+\n+test_expect_success '--mailmap enables mailmap in cat-file for annotated tag objects' '\n+\ttest_when_finished \"rm .mailmap\" &&\n+\tcat >.mailmap <<-EOF &&\n+\tOrig <orig@example.com> C O Mitter <committer@example.com>\n+\tEOF\n+\tcat >expect <<-EOF &&\n+\ttagger Orig <orig@example.com>\n+\tEOF\n+\tgit tag -a -m \"annotated tag\" v2 &&\n+\tgit cat-file --mailmap -p v2 >log &&\n+\tsed -n \"/^tagger /s/\\([^>]*>\\).*/\\1/p\" log >actual &&\n+\ttest_cmp expect actual\n+'\n+\n test_done\n-- \n2.37.0.6.g69b7ad898b\n\n"},{"id":"458699","messageId":"xmqqv8s5sf8x.fsf@gitster.g","threadId":"58088","inReplyTo":"20220709154149.165524-1-siddharthasthana31@gmail.com","subject":"Re: [PATCH v3 0/4] Add support for mailmap in cat-file","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-07-10T05:34:06Z","receivedAt":"2022-07-10T05:34:17Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Siddharth Asthana <siddharthasthana31@gmail.com> writes:\n\n> = Patch Organization\n>\n> - The first patch improves the commit_rewrite_person() by restricting it \n>   to traverse only through the header part of the commit object buffer.\n>   It also adds an argument called headers which the callers can pass. \n>   The function will replace idents only on these  passed headers. \n>   Thus, the caller won't have to make repeated calls to the function.\n> - The second patch moves commit_rewrite_person() to ident.c to expose it\n>   as a public function so that it can be used to replace idents in the\n>   headers of desired objects.\n> - The third patch renames commit_rewrite_person() to a name which\n>   describes its functionality clearly. It is renamed to\n>   apply_mailmap_to_header().\n> - The last patch adds mailmap support to the git cat-file command. It\n>   adds the required documentation and tests as well.\n>\n> Changes in v3:\n> - The decl-after-statement warnings have been fixed in all the patches.\n> - In commit_rewrite_person(), the data type of linelen and i variables\n>   have been changed from int to size_t.\n> - The return type of replace_idents_using_mailmap() function, size_t,\n>   has been explicitly typecasted to unsigned long using the\n>   cast_size_t_to_ulong() helper method.\n\nhttps://github.com/git/git/actions/runs/2642867380 seems to tell us\nthat tests added by this series are broken on Windows.  I am not\nsure what exactly in this series depends on being LF-only system,\nbut the symptom makes me suspect that is the cause of the problem.\n\n"},{"id":"458870","messageId":"50s3714q-8p5n-2379-65r4-17304426rp93@tzk.qr","threadId":"58088","inReplyTo":"xmqqv8s5sf8x.fsf@gitster.g","subject":"Re: [PATCH v3 0/4] Add support for mailmap in cat-file","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2022-07-12T12:34:38Z","receivedAt":"2022-07-12T12:34:59Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio & Siddarth,\n\nOn Sat, 9 Jul 2022, Junio C Hamano wrote:\n\n> Siddharth Asthana <siddharthasthana31@gmail.com> writes:\n>\n> > = Patch Organization\n> >\n> > - The first patch improves the commit_rewrite_person() by restricting it\n> >   to traverse only through the header part of the commit object buffer.\n> >   It also adds an argument called headers which the callers can pass.\n> >   The function will replace idents only on these  passed headers.\n> >   Thus, the caller won't have to make repeated calls to the function.\n> > - The second patch moves commit_rewrite_person() to ident.c to expose it\n> >   as a public function so that it can be used to replace idents in the\n> >   headers of desired objects.\n> > - The third patch renames commit_rewrite_person() to a name which\n> >   describes its functionality clearly. It is renamed to\n> >   apply_mailmap_to_header().\n> > - The last patch adds mailmap support to the git cat-file command. It\n> >   adds the required documentation and tests as well.\n> >\n> > Changes in v3:\n> > - The decl-after-statement warnings have been fixed in all the patches.\n> > - In commit_rewrite_person(), the data type of linelen and i variables\n> >   have been changed from int to size_t.\n> > - The return type of replace_idents_using_mailmap() function, size_t,\n> >   has been explicitly typecasted to unsigned long using the\n> >   cast_size_t_to_ulong() helper method.\n>\n> https://github.com/git/git/actions/runs/2642867380 seems to tell us\n> that tests added by this series are broken on Windows.  I am not\n> sure what exactly in this series depends on being LF-only system,\n> but the symptom makes me suspect that is the cause of the problem.\n\nIt has nothing to do with LF-only, but everything to do with symlinks (I\nsuspected that when I saw the skipped test cases at\nhttps://github.com/git/git/runs/7292710632?check_suite_focus=true#step:5:195,\nand could validate that suspicion via disabling the test cases by\ninverting the prereq: this caused the very same symptoms even in a Linux\nsetup):\n\n-- snipsnap --\nFrom 5bc6d52c95401f60e67312823ed406bd5a3c1026 Mon Sep 17 00:00:00 2001\nFrom: Johannes Schindelin <johannes.schindelin@gmx.de>\nDate: Tue, 12 Jul 2022 14:28:05 +0200\nSubject: [PATCH] fixup??? cat-file: add mailmap support\n\nThis patch introduced new test cases that rely on the side effects of\nthe earlier test case `set up symlink tests`. However, that test case is\nguarded behind the `SYMLINKS` prereq, therefore it is not run e.g. on\nWindows.\n\nLet's fix that by removing the prereq from the `set up` test case, and\nadjusting its title to reflect its broadened responsibility.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n t/t4203-mailmap.sh | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/t/t4203-mailmap.sh b/t/t4203-mailmap.sh\nindex c60a90615cc..94afd4717a2 100755\n--- a/t/t4203-mailmap.sh\n+++ b/t/t4203-mailmap.sh\n@@ -932,7 +932,7 @@ test_expect_success 'find top-level mailmap from subdir' '\n \ttest_cmp expect actual\n '\n\n-test_expect_success SYMLINKS 'set up symlink tests' '\n+test_expect_success 'set up symlink/--use-mailmap tests' '\n \tgit commit --allow-empty -m foo --author=\"Orig <orig@example.com>\" &&\n \techo \"New <new@example.com> <orig@example.com>\" >map &&\n \trm -f .mailmap\n--\n2.37.0.rc2.windows.1.7.g45a475aeb84\n\n"},{"id":"458888","messageId":"xmqqwnciifgv.fsf@gitster.g","threadId":"58088","inReplyTo":"50s3714q-8p5n-2379-65r4-17304426rp93@tzk.qr","subject":"Re: [PATCH v3 0/4] Add support for mailmap in cat-file","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-07-12T14:16:16Z","receivedAt":"2022-07-12T14:16:40Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n> This patch introduced new test cases that rely on the side effects of\n> the earlier test case `set up symlink tests`. However, that test case is\n> guarded behind the `SYMLINKS` prereq, therefore it is not run e.g. on\n> Windows.\n\nAh, that explains why it only fails there.\n\n> Let's fix that by removing the prereq from the `set up` test case, and\n> adjusting its title to reflect its broadened responsibility.\n>\n> -test_expect_success SYMLINKS 'set up symlink tests' '\n> +test_expect_success 'set up symlink/--use-mailmap tests' '\n>  \tgit commit --allow-empty -m foo --author=\"Orig <orig@example.com>\" &&\n>  \techo \"New <new@example.com> <orig@example.com>\" >map &&\n>  \trm -f .mailmap\n\nOK, this sets up\n\n * one commit that can be used in a test, authored by \"Orig\" person;\n * the \"map\" file that maps the \"Orig\" person; and\n * ensures .mailmap is not there.\n\nwith the intention to make a symbolic link that points at the \"map\"\nto use as the mailmap file in later tests.  This step does not require\nsymbolic links at all, but because the point of this set-up is to serve\nthe later tests, all requiring symbolic link support, it was OK to have\nthe prerequisite.\n\nThe cat-file tests does not have to use the \"map\" file to do its\nthing at all.  In fact, these tests prepare their own .mailmap file\ninside them.  But because it chose to run in the history prepared by\nprevious tests, it broke, because without SYMLINKS, the sought-for\ncommit does not get created.\n\nMakes sense.  I would have retitled it to s/set up/prepare for/ but\nthat is minor.\n\nThanks.  Siddharth, please squash the fix in when rerolling.\n\n"},{"id":"458896","messageId":"3167df9e-574c-cc00-1e00-43e81b049b6f@gmail.com","threadId":"58088","inReplyTo":"xmqqwnciifgv.fsf@gitster.g","subject":"Re: [PATCH v3 0/4] Add support for mailmap in cat-file","fromName":"Siddharth Asthana","fromEmail":"siddharthasthana31@gmail.com","sentAt":"2022-07-12T16:01:49Z","receivedAt":"2022-07-12T16:02:07Z","isPatch":true,"sender":{"key":"siddharthasthana31@gmail.com","avatar":"https://avatars.githubusercontent.com/u/53316982?v=4"},"body":"\n\nOn 12/07/22 19:46, Junio C Hamano wrote:\n> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n> \n>> This patch introduced new test cases that rely on the side effects of\n>> the earlier test case `set up symlink tests`. However, that test case is\n>> guarded behind the `SYMLINKS` prereq, therefore it is not run e.g. on\n>> Windows.\n> \n> Ah, that explains why it only fails there.\n> \n>> Let's fix that by removing the prereq from the `set up` test case, and\n>> adjusting its title to reflect its broadened responsibility.\n>>\n>> -test_expect_success SYMLINKS 'set up symlink tests' '\n>> +test_expect_success 'set up symlink/--use-mailmap tests' '\n>>   \tgit commit --allow-empty -m foo --author=\"Orig <orig@example.com>\" &&\n>>   \techo \"New <new@example.com> <orig@example.com>\" >map &&\n>>   \trm -f .mailmap\n> \n> OK, this sets up\n> \n>   * one commit that can be used in a test, authored by \"Orig\" person;\n>   * the \"map\" file that maps the \"Orig\" person; and\n>   * ensures .mailmap is not there.\n> \n> with the intention to make a symbolic link that points at the \"map\"\n> to use as the mailmap file in later tests.  This step does not require\n> symbolic links at all, but because the point of this set-up is to serve\n> the later tests, all requiring symbolic link support, it was OK to have\n> the prerequisite.\n> \n> The cat-file tests does not have to use the \"map\" file to do its\n> thing at all.  In fact, these tests prepare their own .mailmap file\n> inside them.  But because it chose to run in the history prepared by\n> previous tests, it broke, because without SYMLINKS, the sought-for\n> commit does not get created.\n> \n> Makes sense.  I would have retitled it to s/set up/prepare for/ but\n> that is minor.\n> \n> Thanks.  Siddharth, please squash the fix in when rerolling.\n> \nThanks a ton Johannes and Junio for helping me fix the test :D\nWill squash the fix in v4!\n"},{"id":"458897","messageId":"xmqqy1wygvse.fsf@gitster.g","threadId":"58088","inReplyTo":"xmqqwnciifgv.fsf@gitster.g","subject":"Re: [PATCH v3 0/4] Add support for mailmap in cat-file","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-07-12T16:06:41Z","receivedAt":"2022-07-12T16:07:09Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> The cat-file tests does not have to use the \"map\" file to do its\n> thing at all.  In fact, these tests prepare their own .mailmap file\n> inside them.  But because it chose to run in the history prepared by\n> previous tests, it broke, because without SYMLINKS, the sought-for\n> commit does not get created.\n\nSo, an alternative solution is to keep the existing tests on\nsymlinks totally unrelated to these new tests.  These cat-file tests\ncan prepare the commit to munge at the beginning of the sequence,\nand then do its thing.  This way, a platform without symlink support\ndoes not have to create the \"map\" file that nobody uses, something\nlike the attached.\n\nI do not have strong preference either way, though.\n\n t/t4203-mailmap.sh | 5 +++++\n 1 file changed, 5 insertions(+)\n\ndiff --git c/t/t4203-mailmap.sh w/t/t4203-mailmap.sh\nindex c60a90615c..cd1cab3e54 100755\n--- c/t/t4203-mailmap.sh\n+++ w/t/t4203-mailmap.sh\n@@ -963,6 +963,11 @@ test_expect_success SYMLINKS 'symlinks not respected in-tree' '\n \ttest_cmp expect actual\n '\n \n+test_expect_success 'prepare for cat-file --mailmap' '\n+\trm -f .mailmap &&\n+\tgit commit --allow-empty -m foo --author=\"Orig <orig@example.com>\"\n+'\n+\n test_expect_success '--no-use-mailmap disables mailmap in cat-file' '\n \ttest_when_finished \"rm .mailmap\" &&\n \tcat >.mailmap <<-EOF &&\n"},{"id":"458898","messageId":"20220712160634.213956-1-siddharthasthana31@gmail.com","threadId":"58088","inReplyTo":"20220709154149.165524-1-siddharthasthana31@gmail.com","subject":"[PATCH v4 0/4] Add support for mailmap in cat-file","fromName":"Siddharth Asthana","fromEmail":"siddharthasthana31@gmail.com","sentAt":"2022-07-12T16:06:30Z","receivedAt":"2022-07-12T16:07:12Z","isPatch":true,"sender":{"key":"siddharthasthana31@gmail.com","avatar":"https://avatars.githubusercontent.com/u/53316982?v=4"},"body":"Thanks a lot for helping me fix the broken test Johannes and Junio! :D\n\n= Description\n\nThis patch series adds mailmap support to the git-cat-file command. It\nadds the mailmap support only for the commit and tag objects by\nreplacing the idents for \"author\", \"committer\" and \"tagger\" headers. The\nmailmap only takes effect when --[no-]-use-mailmap or --[no-]-mailmap\noption is passed to the git cat-file command. The changes will work with\nthe batch mode as well.\n\nSo, if one wants to enable mailmap they can use either of the following\ncommands:\n$ git cat-file --use-mailmap -p <object>\n$ git cat-file --use-mailmap <type> <object>\n\nTo use it in the batch mode, one can use the following command:\n$ git cat-file --use-mailmap --batch\n\n= Patch Organization\n\n- The first patch improves the commit_rewrite_person() by restricting it \n  to traverse only through the header part of the commit object buffer.\n  It also adds an argument called headers which the callers can pass. \n  The function will replace idents only on these  passed headers. \n  Thus, the caller won't have to make repeated calls to the function.\n- The second patch moves commit_rewrite_person() to ident.c to expose it\n  as a public function so that it can be used to replace idents in the\n  headers of desired objects.\n- The third patch renames commit_rewrite_person() to a name which\n  describes its functionality clearly. It is renamed to\n  apply_mailmap_to_header().\n- The last patch adds mailmap support to the git cat-file command. It\n  adds the required documentation and tests as well.\n\nChanges in v4:\n- This patch series introduces new test cases for testing the mailmap\n  mechanism in git-cat-file command. These tests rely on the side\n  effects of the earlier test case `set up symlink tests`. However, that\n  test case is guarded behind the `SYMLINKS` prereq, therefore it is not\n  run e.g. on Windows. This caused the --use-mailmap tests to fail on \n  Windows. So, that has been fixed by removing the prereq from `set up`\n  test case.\n- The `set up symlink tests` has also been renamed to `prepare for\n  symlink/--use-mailmap tests` to reflect its broadened responsibility.\n\nSiddharth Asthana (4):\n  revision: improve commit_rewrite_person()\n  ident: move commit_rewrite_person() to ident.c\n  ident: rename commit_rewrite_person() to apply_mailmap_to_header()\n  cat-file: add mailmap support\n\n Documentation/git-cat-file.txt |  6 +++\n builtin/cat-file.c             | 43 +++++++++++++++++++-\n cache.h                        |  6 +++\n ident.c                        | 72 ++++++++++++++++++++++++++++++++++\n revision.c                     | 50 ++---------------------\n t/t4203-mailmap.sh             | 56 +++++++++++++++++++++++++-\n 6 files changed, 184 insertions(+), 49 deletions(-)\n\nRange-diff against v3:\n1:  9e95326c58 = 1:  9e95326c58 revision: improve commit_rewrite_person()\n2:  d9395cb8b2 = 2:  d9395cb8b2 ident: move commit_rewrite_person() to ident.c\n3:  355bbda25e = 3:  355bbda25e ident: rename commit_rewrite_person() to apply_mailmap_to_header()\n4:  69b7ad898b ! 4:  ac532965b4 cat-file: add mailmap support\n    @@ Commit message\n         cat-file command. It also adds --[no-]mailmap option as an alias to\n         --[no-]use-mailmap.\n     \n    +    This patch also introduces new test cases to test the mailmap mechanism in\n    +    git cat-file command.\n    +\n    +    The tests added in this patch series rely on the side effects of the earlier\n    +    test case `set up symlink tests`. However, that test case is guarded behind the\n    +    `SYMLINKS` prereq, therefore it is not run e.g. on Windows which can cause the\n    +    added tests to fail on Windows. So, fix that by removing the prereq from the\n    +    `set up` test case, and adjusting its title to reflect its broadened responsibility.\n    +\n         Mentored-by: Christian Couder <christian.couder@gmail.com>\n         Mentored-by: John Cai <johncai86@gmail.com>\n         Helped-by: Phillip Wood <phillip.wood@dunelm.org.uk>\n    @@ builtin/cat-file.c: int cmd_cat_file(int argc, const char **argv, const char *pr\n      \t\tbatch.all_objects = 1;\n     \n      ## t/t4203-mailmap.sh ##\n    +@@ t/t4203-mailmap.sh: test_expect_success 'find top-level mailmap from subdir' '\n    + \ttest_cmp expect actual\n    + '\n    + \n    +-test_expect_success SYMLINKS 'set up symlink tests' '\n    ++test_expect_success 'prepare for symlink/--use-mailmap tests' '\n    + \tgit commit --allow-empty -m foo --author=\"Orig <orig@example.com>\" &&\n    + \techo \"New <new@example.com> <orig@example.com>\" >map &&\n    + \trm -f .mailmap\n     @@ t/t4203-mailmap.sh: test_expect_success SYMLINKS 'symlinks not respected in-tree' '\n      \ttest_cmp expect actual\n      '\n-- \n2.37.0.6.g69b7ad898b\n\n"},{"id":"458899","messageId":"20220712160634.213956-2-siddharthasthana31@gmail.com","threadId":"58088","inReplyTo":"20220712160634.213956-1-siddharthasthana31@gmail.com","subject":"[PATCH v4 1/4] revision: improve commit_rewrite_person()","fromName":"Siddharth Asthana","fromEmail":"siddharthasthana31@gmail.com","sentAt":"2022-07-12T16:06:31Z","receivedAt":"2022-07-12T16:07:16Z","isPatch":true,"sender":{"key":"siddharthasthana31@gmail.com","avatar":"https://avatars.githubusercontent.com/u/53316982?v=4"},"body":"The function, commit_rewrite_person(), is designed to find and replace\nan ident string in the header part, and the way it avoids a random\noccurrence of \"author A U Thor <author@example.com\" in the text is by\ninsisting \"author\" to appear at the beginning of line by passing\n\"\\nauthor \" as \"what\".\n\nThe implementation also doesn't make any effort to limit itself to the\ncommit header by locating the blank line that appears after the header\npart and stopping the search there. Also, the interface forces the\ncaller to make multiple calls if it wants to rewrite idents on multiple\nheaders. It shouldn't be the case.\n\nTo support the existing caller better, update commit_rewrite_person()\nto:\n- Make a single pass in the input buffer to locate headers named\n  \"author\" and \"committer\" and replace idents on them.\n- Stop at the end of the header, ensuring that nothing in the body of\n  the commit object is modified.\n\nThe return type of the function commit_rewrite_person() has also been\nchanged from int to void. This has been done because the caller of the\nfunction doesn't do anything with the return value of the function.\n\nBy simplifying the interface of the commit_rewrite_person(), we also\nintend to expose it as a public function. We will also be renaming the\nfunction in a future commit to a different name which clearly tells that\nthe function replaces idents in the header of the commit buffer.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: John Cai <johncai86@gmail.com>\nHelped-by: Đoàn Trần Công Danh <congdanhqx@gmail.com>\nSigned-off-by: Siddharth Asthana <siddharthasthana31@gmail.com>\n---\n revision.c | 48 ++++++++++++++++++++++++++++++++++++++----------\n 1 file changed, 38 insertions(+), 10 deletions(-)\n\ndiff --git a/revision.c b/revision.c\nindex 211352795c..1939c56c67 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -3755,19 +3755,17 @@ int rewrite_parents(struct rev_info *revs, struct commit *commit,\n \treturn 0;\n }\n \n-static int commit_rewrite_person(struct strbuf *buf, const char *what, struct string_list *mailmap)\n+/*\n+ * Returns the difference between the new and old length of the ident line.\n+ */\n+static ssize_t rewrite_ident_line(const char* person, struct strbuf *buf, struct string_list *mailmap)\n {\n-\tchar *person, *endp;\n+\tchar *endp;\n \tsize_t len, namelen, maillen;\n \tconst char *name;\n \tconst char *mail;\n \tstruct ident_split ident;\n \n-\tperson = strstr(buf->buf, what);\n-\tif (!person)\n-\t\treturn 0;\n-\n-\tperson += strlen(what);\n \tendp = strchr(person, '\\n');\n \tif (!endp)\n \t\treturn 0;\n@@ -3784,6 +3782,7 @@ static int commit_rewrite_person(struct strbuf *buf, const char *what, struct st\n \n \tif (map_user(mailmap, &mail, &maillen, &name, &namelen)) {\n \t\tstruct strbuf namemail = STRBUF_INIT;\n+\t\tsize_t newlen;\n \n \t\tstrbuf_addf(&namemail, \"%.*s <%.*s>\",\n \t\t\t    (int)namelen, name, (int)maillen, mail);\n@@ -3792,14 +3791,42 @@ static int commit_rewrite_person(struct strbuf *buf, const char *what, struct st\n \t\t\t      ident.mail_end - ident.name_begin + 1,\n \t\t\t      namemail.buf, namemail.len);\n \n+\t\tnewlen = namemail.len;\n+\n \t\tstrbuf_release(&namemail);\n \n-\t\treturn 1;\n+\t\treturn newlen - (ident.mail_end - ident.name_begin + 1);\n \t}\n \n \treturn 0;\n }\n \n+static void commit_rewrite_person(struct strbuf *buf, const char **headers, struct string_list *mailmap)\n+{\n+\tsize_t buf_offset = 0;\n+\n+\tif (!mailmap)\n+\t\treturn;\n+\n+\tfor (;;) {\n+\t\tconst char *person, *line;\n+\t\tsize_t i, linelen;\n+\n+\t\tline = buf->buf + buf_offset;\n+\t\tlinelen = strchrnul(line, '\\n') - line + 1;\n+\n+\t\tif (linelen <= 1)\n+\t\t\t/* End of header */\n+\t\t\treturn;\n+\n+\t\tbuf_offset += linelen;\n+\n+\t\tfor (i = 0; headers[i]; i++)\n+\t\t\tif (skip_prefix(line, headers[i], &person))\n+\t\t\t\tbuf_offset += rewrite_ident_line(person, buf, mailmap);\n+\t}\n+}\n+\n static int commit_match(struct commit *commit, struct rev_info *opt)\n {\n \tint retval;\n@@ -3832,11 +3859,12 @@ static int commit_match(struct commit *commit, struct rev_info *opt)\n \t\tstrbuf_addstr(&buf, message);\n \n \tif (opt->grep_filter.header_list && opt->mailmap) {\n+\t\tconst char *commit_headers[] = { \"author \", \"committer \", NULL };\n+\n \t\tif (!buf.len)\n \t\t\tstrbuf_addstr(&buf, message);\n \n-\t\tcommit_rewrite_person(&buf, \"\\nauthor \", opt->mailmap);\n-\t\tcommit_rewrite_person(&buf, \"\\ncommitter \", opt->mailmap);\n+\t\tcommit_rewrite_person(&buf, commit_headers, opt->mailmap);\n \t}\n \n \t/* Append \"fake\" message parts as needed */\n-- \n2.37.0.6.g69b7ad898b\n\n"},{"id":"458900","messageId":"20220712160634.213956-3-siddharthasthana31@gmail.com","threadId":"58088","inReplyTo":"20220712160634.213956-1-siddharthasthana31@gmail.com","subject":"[PATCH v4 2/4] ident: move commit_rewrite_person() to ident.c","fromName":"Siddharth Asthana","fromEmail":"siddharthasthana31@gmail.com","sentAt":"2022-07-12T16:06:32Z","receivedAt":"2022-07-12T16:07:24Z","isPatch":true,"sender":{"key":"siddharthasthana31@gmail.com","avatar":"https://avatars.githubusercontent.com/u/53316982?v=4"},"body":"commit_rewrite_person() and rewrite_ident_line() are static functions\ndefined in revision.c.\n\nTheir usages are as follows:\n- commit_rewrite_person() takes a commit buffer and replaces the author\n  and committer idents with their canonical versions using the mailmap\n  mechanism\n- rewrite_ident_line() takes author/committer header lines from the\n  commit buffer and replaces the idents with their canonical versions\n  using the mailmap mechanism.\n\nThis patch moves commit_rewrite_person() and rewrite_ident_line() to\nident.c which contains many other functions related to idents like\nsplit_ident_line(). By moving commit_rewrite_person() to ident.c, we\nalso intend to use it in git-cat-file to replace committer and author\nidents from the headers to their canonical versions using the mailmap\nmechanism. The function is moved as is for now to make it clear that\nthere are no other changes, but it will be renamed in a following\ncommit.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: John Cai <johncai86@gmail.com>\nSigned-off-by: Siddharth Asthana <siddharthasthana31@gmail.com>\n---\n cache.h    |  6 +++++\n ident.c    | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++++++\n revision.c | 72 ------------------------------------------------------\n 3 files changed, 78 insertions(+), 72 deletions(-)\n\ndiff --git a/cache.h b/cache.h\nindex ac5ab4ef9d..c9dbe1c29a 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -1688,6 +1688,12 @@ struct ident_split {\n  */\n int split_ident_line(struct ident_split *, const char *, int);\n \n+/*\n+ * Given a commit object buffer and the commit headers, replaces the idents\n+ * in the headers with their canonical versions using the mailmap mechanism.\n+ */\n+void commit_rewrite_person(struct strbuf *buf, const char **commit_headers, struct string_list *mailmap);\n+\n /*\n  * Compare split idents for equality or strict ordering. Note that we\n  * compare only the ident part of the line, ignoring any timestamp.\ndiff --git a/ident.c b/ident.c\nindex 89ca5b4700..9f4f6e9071 100644\n--- a/ident.c\n+++ b/ident.c\n@@ -8,6 +8,7 @@\n #include \"cache.h\"\n #include \"config.h\"\n #include \"date.h\"\n+#include \"mailmap.h\"\n \n static struct strbuf git_default_name = STRBUF_INIT;\n static struct strbuf git_default_email = STRBUF_INIT;\n@@ -346,6 +347,77 @@ int split_ident_line(struct ident_split *split, const char *line, int len)\n \treturn 0;\n }\n \n+/*\n+ * Returns the difference between the new and old length of the ident line.\n+ */\n+static ssize_t rewrite_ident_line(const char* person, struct strbuf *buf, struct string_list *mailmap)\n+{\n+\tchar *endp;\n+\tsize_t len, namelen, maillen;\n+\tconst char *name;\n+\tconst char *mail;\n+\tstruct ident_split ident;\n+\n+\tendp = strchr(person, '\\n');\n+\tif (!endp)\n+\t\treturn 0;\n+\n+\tlen = endp - person;\n+\n+\tif (split_ident_line(&ident, person, len))\n+\t\treturn 0;\n+\n+\tmail = ident.mail_begin;\n+\tmaillen = ident.mail_end - ident.mail_begin;\n+\tname = ident.name_begin;\n+\tnamelen = ident.name_end - ident.name_begin;\n+\n+\tif (map_user(mailmap, &mail, &maillen, &name, &namelen)) {\n+\t\tstruct strbuf namemail = STRBUF_INIT;\n+\t\tsize_t newlen;\n+\n+\t\tstrbuf_addf(&namemail, \"%.*s <%.*s>\",\n+\t\t\t    (int)namelen, name, (int)maillen, mail);\n+\n+\t\tstrbuf_splice(buf, ident.name_begin - buf->buf,\n+\t\t\t      ident.mail_end - ident.name_begin + 1,\n+\t\t\t      namemail.buf, namemail.len);\n+\n+\t\tnewlen = namemail.len;\n+\n+\t\tstrbuf_release(&namemail);\n+\n+\t\treturn newlen - (ident.mail_end - ident.name_begin + 1);\n+\t}\n+\n+\treturn 0;\n+}\n+\n+void commit_rewrite_person(struct strbuf *buf, const char **headers, struct string_list *mailmap)\n+{\n+\tsize_t buf_offset = 0;\n+\n+\tif (!mailmap)\n+\t\treturn;\n+\n+\tfor (;;) {\n+\t\tconst char *person, *line;\n+\t\tsize_t i, linelen;\n+\n+\t\tline = buf->buf + buf_offset;\n+\t\tlinelen = strchrnul(line, '\\n') - line + 1;\n+\n+\t\tif (linelen <= 1)\n+\t\t\t/* End of header */\n+\t\t\treturn;\n+\n+\t\tbuf_offset += linelen;\n+\n+\t\tfor (i = 0; headers[i]; i++)\n+\t\t\tif (skip_prefix(line, headers[i], &person))\n+\t\t\t\tbuf_offset += rewrite_ident_line(person, buf, mailmap);\n+\t}\n+}\n \n static void ident_env_hint(enum want_ident whose_ident)\n {\ndiff --git a/revision.c b/revision.c\nindex 1939c56c67..14dca903b6 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -3755,78 +3755,6 @@ int rewrite_parents(struct rev_info *revs, struct commit *commit,\n \treturn 0;\n }\n \n-/*\n- * Returns the difference between the new and old length of the ident line.\n- */\n-static ssize_t rewrite_ident_line(const char* person, struct strbuf *buf, struct string_list *mailmap)\n-{\n-\tchar *endp;\n-\tsize_t len, namelen, maillen;\n-\tconst char *name;\n-\tconst char *mail;\n-\tstruct ident_split ident;\n-\n-\tendp = strchr(person, '\\n');\n-\tif (!endp)\n-\t\treturn 0;\n-\n-\tlen = endp - person;\n-\n-\tif (split_ident_line(&ident, person, len))\n-\t\treturn 0;\n-\n-\tmail = ident.mail_begin;\n-\tmaillen = ident.mail_end - ident.mail_begin;\n-\tname = ident.name_begin;\n-\tnamelen = ident.name_end - ident.name_begin;\n-\n-\tif (map_user(mailmap, &mail, &maillen, &name, &namelen)) {\n-\t\tstruct strbuf namemail = STRBUF_INIT;\n-\t\tsize_t newlen;\n-\n-\t\tstrbuf_addf(&namemail, \"%.*s <%.*s>\",\n-\t\t\t    (int)namelen, name, (int)maillen, mail);\n-\n-\t\tstrbuf_splice(buf, ident.name_begin - buf->buf,\n-\t\t\t      ident.mail_end - ident.name_begin + 1,\n-\t\t\t      namemail.buf, namemail.len);\n-\n-\t\tnewlen = namemail.len;\n-\n-\t\tstrbuf_release(&namemail);\n-\n-\t\treturn newlen - (ident.mail_end - ident.name_begin + 1);\n-\t}\n-\n-\treturn 0;\n-}\n-\n-static void commit_rewrite_person(struct strbuf *buf, const char **headers, struct string_list *mailmap)\n-{\n-\tsize_t buf_offset = 0;\n-\n-\tif (!mailmap)\n-\t\treturn;\n-\n-\tfor (;;) {\n-\t\tconst char *person, *line;\n-\t\tsize_t i, linelen;\n-\n-\t\tline = buf->buf + buf_offset;\n-\t\tlinelen = strchrnul(line, '\\n') - line + 1;\n-\n-\t\tif (linelen <= 1)\n-\t\t\t/* End of header */\n-\t\t\treturn;\n-\n-\t\tbuf_offset += linelen;\n-\n-\t\tfor (i = 0; headers[i]; i++)\n-\t\t\tif (skip_prefix(line, headers[i], &person))\n-\t\t\t\tbuf_offset += rewrite_ident_line(person, buf, mailmap);\n-\t}\n-}\n-\n static int commit_match(struct commit *commit, struct rev_info *opt)\n {\n \tint retval;\n-- \n2.37.0.6.g69b7ad898b\n\n"},{"id":"458901","messageId":"20220712160634.213956-4-siddharthasthana31@gmail.com","threadId":"58088","inReplyTo":"20220712160634.213956-1-siddharthasthana31@gmail.com","subject":"[PATCH v4 3/4] ident: rename commit_rewrite_person() to apply_mailmap_to_header()","fromName":"Siddharth Asthana","fromEmail":"siddharthasthana31@gmail.com","sentAt":"2022-07-12T16:06:33Z","receivedAt":"2022-07-12T16:07:27Z","isPatch":true,"sender":{"key":"siddharthasthana31@gmail.com","avatar":"https://avatars.githubusercontent.com/u/53316982?v=4"},"body":"commit_rewrite_person() takes a commit buffer and replaces the idents\nin the header with their canonical versions using the mailmap mechanism.\nThe name \"commit_rewrite_person()\" is misleading as it doesn't convey\nwhat kind of rewrite are we going to do to the buffer. It also doesn't\nclearly mention that the function will limit itself to the header part\nof the buffer. The new name, \"apply_mailmap_to_header()\", expresses the\nfunctionality of the function pretty clearly.\n\nWe intend to use apply_mailmap_to_header() in git-cat-file to replace\nidents in the headers of commit and tag object buffers. So, we will be\nextending this function to take tag objects buffer as well and replace\nidents on the tagger header using the mailmap mechanism.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: John Cai <johncai86@gmail.com>\nSigned-off-by: Siddharth Asthana <siddharthasthana31@gmail.com>\n---\n cache.h    | 6 +++---\n ident.c    | 2 +-\n revision.c | 2 +-\n 3 files changed, 5 insertions(+), 5 deletions(-)\n\ndiff --git a/cache.h b/cache.h\nindex c9dbe1c29a..9edb7fefd3 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -1689,10 +1689,10 @@ struct ident_split {\n int split_ident_line(struct ident_split *, const char *, int);\n \n /*\n- * Given a commit object buffer and the commit headers, replaces the idents\n- * in the headers with their canonical versions using the mailmap mechanism.\n+ * Given a commit or tag object buffer and the commit or tag headers, replaces\n+ * the idents in the headers with their canonical versions using the mailmap mechanism.\n  */\n-void commit_rewrite_person(struct strbuf *buf, const char **commit_headers, struct string_list *mailmap);\n+void apply_mailmap_to_header(struct strbuf *buf, const char **headers, struct string_list *mailmap);\n \n /*\n  * Compare split idents for equality or strict ordering. Note that we\ndiff --git a/ident.c b/ident.c\nindex 9f4f6e9071..5f17bd607d 100644\n--- a/ident.c\n+++ b/ident.c\n@@ -393,7 +393,7 @@ static ssize_t rewrite_ident_line(const char* person, struct strbuf *buf, struct\n \treturn 0;\n }\n \n-void commit_rewrite_person(struct strbuf *buf, const char **headers, struct string_list *mailmap)\n+void apply_mailmap_to_header(struct strbuf *buf, const char **headers, struct string_list *mailmap)\n {\n \tsize_t buf_offset = 0;\n \ndiff --git a/revision.c b/revision.c\nindex 14dca903b6..6ad3665204 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -3792,7 +3792,7 @@ static int commit_match(struct commit *commit, struct rev_info *opt)\n \t\tif (!buf.len)\n \t\t\tstrbuf_addstr(&buf, message);\n \n-\t\tcommit_rewrite_person(&buf, commit_headers, opt->mailmap);\n+\t\tapply_mailmap_to_header(&buf, commit_headers, opt->mailmap);\n \t}\n \n \t/* Append \"fake\" message parts as needed */\n-- \n2.37.0.6.g69b7ad898b\n\n"},{"id":"458902","messageId":"20220712160634.213956-5-siddharthasthana31@gmail.com","threadId":"58088","inReplyTo":"20220712160634.213956-1-siddharthasthana31@gmail.com","subject":"[PATCH v4 4/4] cat-file: add mailmap support","fromName":"Siddharth Asthana","fromEmail":"siddharthasthana31@gmail.com","sentAt":"2022-07-12T16:06:34Z","receivedAt":"2022-07-12T16:07:33Z","isPatch":true,"sender":{"key":"siddharthasthana31@gmail.com","avatar":"https://avatars.githubusercontent.com/u/53316982?v=4"},"body":"git-cat-file is used by tools like GitLab to get commit tag contents\nthat are then displayed to users. This content which has author,\ncommitter or tagger information, could benefit from passing through the\nmailmap mechanism before being sent or displayed.\n\nThis patch adds --[no-]use-mailmap command line option to the git\ncat-file command. It also adds --[no-]mailmap option as an alias to\n--[no-]use-mailmap.\n\nThis patch also introduces new test cases to test the mailmap mechanism in\ngit cat-file command.\n\nThe tests added in this patch series rely on the side effects of the earlier\ntest case `set up symlink tests`. However, that test case is guarded behind the\n`SYMLINKS` prereq, therefore it is not run e.g. on Windows which can cause the\nadded tests to fail on Windows. So, fix that by removing the prereq from the\n`set up` test case, and adjusting its title to reflect its broadened responsibility.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: John Cai <johncai86@gmail.com>\nHelped-by: Phillip Wood <phillip.wood@dunelm.org.uk>\nHelped-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>\nSigned-off-by: Siddharth Asthana <siddharthasthana31@gmail.com>\n---\n Documentation/git-cat-file.txt |  6 ++++\n builtin/cat-file.c             | 43 +++++++++++++++++++++++++-\n t/t4203-mailmap.sh             | 56 +++++++++++++++++++++++++++++++++-\n 3 files changed, 103 insertions(+), 2 deletions(-)\n\ndiff --git a/Documentation/git-cat-file.txt b/Documentation/git-cat-file.txt\nindex 24a811f0ef..1880e9bba1 100644\n--- a/Documentation/git-cat-file.txt\n+++ b/Documentation/git-cat-file.txt\n@@ -63,6 +63,12 @@ OPTIONS\n \tor to ask for a \"blob\" with `<object>` being a tag object that\n \tpoints at it.\n \n+--[no-]mailmap::\n+--[no-]use-mailmap::\n+       Use mailmap file to map author, committer and tagger names\n+       and email addresses to canonical real names and email addresses.\n+       See linkgit:git-shortlog[1].\n+\n --textconv::\n \tShow the content as transformed by a textconv filter. In this case,\n \t`<object>` has to be of the form `<tree-ish>:<path>`, or `:<path>` in\ndiff --git a/builtin/cat-file.c b/builtin/cat-file.c\nindex 50cf38999d..4b68216b51 100644\n--- a/builtin/cat-file.c\n+++ b/builtin/cat-file.c\n@@ -16,6 +16,7 @@\n #include \"packfile.h\"\n #include \"object-store.h\"\n #include \"promisor-remote.h\"\n+#include \"mailmap.h\"\n \n enum batch_mode {\n \tBATCH_MODE_CONTENTS,\n@@ -36,6 +37,22 @@ struct batch_options {\n \n static const char *force_path;\n \n+static struct string_list mailmap = STRING_LIST_INIT_NODUP;\n+static int use_mailmap;\n+\n+static char *replace_idents_using_mailmap(char *, size_t *);\n+\n+static char *replace_idents_using_mailmap(char *object_buf, size_t *size)\n+{\n+\tstruct strbuf sb = STRBUF_INIT;\n+\tconst char *headers[] = { \"author \", \"committer \", \"tagger \", NULL };\n+\n+\tstrbuf_attach(&sb, object_buf, *size, *size + 1);\n+\tapply_mailmap_to_header(&sb, headers, &mailmap);\n+\t*size = sb.len;\n+\treturn strbuf_detach(&sb, NULL);\n+}\n+\n static int filter_object(const char *path, unsigned mode,\n \t\t\t const struct object_id *oid,\n \t\t\t char **buf, unsigned long *size)\n@@ -152,6 +169,12 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,\n \t\tif (!buf)\n \t\t\tdie(\"Cannot read object %s\", obj_name);\n \n+\t\tif (use_mailmap) {\n+\t\t\tsize_t s = size;\n+\t\t\tbuf = replace_idents_using_mailmap(buf, &s);\n+\t\t\tsize = cast_size_t_to_ulong(s);\n+\t\t}\n+\n \t\t/* otherwise just spit out the data */\n \t\tbreak;\n \n@@ -183,6 +206,12 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,\n \t\t}\n \t\tbuf = read_object_with_reference(the_repository, &oid,\n \t\t\t\t\t\t exp_type_id, &size, NULL);\n+\n+\t\tif (use_mailmap) {\n+\t\t\tsize_t s = size;\n+\t\t\tbuf = replace_idents_using_mailmap(buf, &s);\n+\t\t\tsize = cast_size_t_to_ulong(s);\n+\t\t}\n \t\tbreak;\n \t}\n \tdefault:\n@@ -348,11 +377,18 @@ static void print_object_or_die(struct batch_options *opt, struct expand_data *d\n \t\tvoid *contents;\n \n \t\tcontents = read_object_file(oid, &type, &size);\n+\n+\t\tif (use_mailmap) {\n+\t\t\tsize_t s = size;\n+\t\t\tcontents = replace_idents_using_mailmap(contents, &s);\n+\t\t\tsize = cast_size_t_to_ulong(s);\n+\t\t}\n+\n \t\tif (!contents)\n \t\t\tdie(\"object %s disappeared\", oid_to_hex(oid));\n \t\tif (type != data->type)\n \t\t\tdie(\"object %s changed type!?\", oid_to_hex(oid));\n-\t\tif (data->info.sizep && size != data->size)\n+\t\tif (data->info.sizep && size != data->size && !use_mailmap)\n \t\t\tdie(\"object %s changed size!?\", oid_to_hex(oid));\n \n \t\tbatch_write(opt, contents, size);\n@@ -843,6 +879,8 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix)\n \t\tOPT_CMDMODE('s', NULL, &opt, N_(\"show object size\"), 's'),\n \t\tOPT_BOOL(0, \"allow-unknown-type\", &unknown_type,\n \t\t\t  N_(\"allow -s and -t to work with broken/corrupt objects\")),\n+\t\tOPT_BOOL(0, \"use-mailmap\", &use_mailmap, N_(\"use mail map file\")),\n+\t\tOPT_ALIAS(0, \"mailmap\", \"use-mailmap\"),\n \t\t/* Batch mode */\n \t\tOPT_GROUP(N_(\"Batch objects requested on stdin (or --batch-all-objects)\")),\n \t\tOPT_CALLBACK_F(0, \"batch\", &batch, N_(\"format\"),\n@@ -885,6 +923,9 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix)\n \topt_cw = (opt == 'c' || opt == 'w');\n \topt_epts = (opt == 'e' || opt == 'p' || opt == 't' || opt == 's');\n \n+\tif (use_mailmap)\n+\t\tread_mailmap(&mailmap);\n+\n \t/* --batch-all-objects? */\n \tif (opt == 'b')\n \t\tbatch.all_objects = 1;\ndiff --git a/t/t4203-mailmap.sh b/t/t4203-mailmap.sh\nindex 0b2d21ec55..dba0a8ac56 100755\n--- a/t/t4203-mailmap.sh\n+++ b/t/t4203-mailmap.sh\n@@ -932,7 +932,7 @@ test_expect_success 'find top-level mailmap from subdir' '\n \ttest_cmp expect actual\n '\n \n-test_expect_success SYMLINKS 'set up symlink tests' '\n+test_expect_success 'prepare for symlink/--use-mailmap tests' '\n \tgit commit --allow-empty -m foo --author=\"Orig <orig@example.com>\" &&\n \techo \"New <new@example.com> <orig@example.com>\" >map &&\n \trm -f .mailmap\n@@ -963,4 +963,58 @@ test_expect_success SYMLINKS 'symlinks not respected in-tree' '\n \ttest_cmp expect actual\n '\n \n+test_expect_success '--no-use-mailmap disables mailmap in cat-file' '\n+\ttest_when_finished \"rm .mailmap\" &&\n+\tcat >.mailmap <<-EOF &&\n+\tA U Thor <author@example.com> Orig <orig@example.com>\n+\tEOF\n+\tcat >expect <<-EOF &&\n+\tauthor Orig <orig@example.com>\n+\tEOF\n+\tgit cat-file --no-use-mailmap commit HEAD >log &&\n+\tsed -n \"/^author /s/\\([^>]*>\\).*/\\1/p\" log >actual &&\n+\ttest_cmp expect actual\n+'\n+\n+test_expect_success '--use-mailmap enables mailmap in cat-file' '\n+\ttest_when_finished \"rm .mailmap\" &&\n+\tcat >.mailmap <<-EOF &&\n+\tA U Thor <author@example.com> Orig <orig@example.com>\n+\tEOF\n+\tcat >expect <<-EOF &&\n+\tauthor A U Thor <author@example.com>\n+\tEOF\n+\tgit cat-file --use-mailmap commit HEAD >log &&\n+\tsed -n \"/^author /s/\\([^>]*>\\).*/\\1/p\" log >actual &&\n+\ttest_cmp expect actual\n+'\n+\n+test_expect_success '--no-mailmap disables mailmap in cat-file for annotated tag objects' '\n+\ttest_when_finished \"rm .mailmap\" &&\n+\tcat >.mailmap <<-EOF &&\n+\tOrig <orig@example.com> C O Mitter <committer@example.com>\n+\tEOF\n+\tcat >expect <<-EOF &&\n+\ttagger C O Mitter <committer@example.com>\n+\tEOF\n+\tgit tag -a -m \"annotated tag\" v1 &&\n+\tgit cat-file --no-mailmap -p v1 >log &&\n+\tsed -n \"/^tagger /s/\\([^>]*>\\).*/\\1/p\" log >actual &&\n+\ttest_cmp expect actual\n+'\n+\n+test_expect_success '--mailmap enables mailmap in cat-file for annotated tag objects' '\n+\ttest_when_finished \"rm .mailmap\" &&\n+\tcat >.mailmap <<-EOF &&\n+\tOrig <orig@example.com> C O Mitter <committer@example.com>\n+\tEOF\n+\tcat >expect <<-EOF &&\n+\ttagger Orig <orig@example.com>\n+\tEOF\n+\tgit tag -a -m \"annotated tag\" v2 &&\n+\tgit cat-file --mailmap -p v2 >log &&\n+\tsed -n \"/^tagger /s/\\([^>]*>\\).*/\\1/p\" log >actual &&\n+\ttest_cmp expect actual\n+'\n+\n test_done\n-- \n2.37.0.6.g69b7ad898b\n\n"},{"id":"458903","messageId":"98nq3r16-0p93-21p5-0pn6-r36841320903@tzk.qr","threadId":"58088","inReplyTo":"20220709154149.165524-2-siddharthasthana31@gmail.com","subject":"Re: [PATCH v3 1/4] revision: improve commit_rewrite_person()","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2022-07-12T16:29:32Z","receivedAt":"2022-07-12T16:29:51Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Siddarth,\n\nOn Sat, 9 Jul 2022, Siddharth Asthana wrote:\n\n> diff --git a/revision.c b/revision.c\n> index 211352795c..1939c56c67 100644\n> --- a/revision.c\n> +++ b/revision.c\n> @@ -3792,14 +3791,42 @@ static int commit_rewrite_person(struct strbuf *buf, const char *what, struct st\n>  \t\t\t      ident.mail_end - ident.name_begin + 1,\n>  \t\t\t      namemail.buf, namemail.len);\n>\n> +\t\tnewlen = namemail.len;\n> +\n>  \t\tstrbuf_release(&namemail);\n>\n> -\t\treturn 1;\n> +\t\treturn newlen - (ident.mail_end - ident.name_begin + 1);\n>  \t}\n>\n>  \treturn 0;\n>  }\n>\n> +static void commit_rewrite_person(struct strbuf *buf, const char **headers, struct string_list *mailmap)\n> +{\n> +\tsize_t buf_offset = 0;\n> +\n> +\tif (!mailmap)\n> +\t\treturn;\n> +\n> +\tfor (;;) {\n> +\t\tconst char *person, *line;\n> +\t\tsize_t i, linelen;\n> +\n> +\t\tline = buf->buf + buf_offset;\n> +\t\tlinelen = strchrnul(line, '\\n') - line + 1;\n> +\n> +\t\tif (linelen <= 1)\n> +\t\t\t/* End of header */\n> +\t\t\treturn;\n\nThis conditional would probably read much better if it was moved up a few\nlines and rewritten like this:\n\n\tif (!*line || *line == '\\n')\n\t\treturn; /* End of headers */\n\nor even turning the `for (;;)` into\n\n\twhile (buf->buf[buf_offset] && buf->buf[buf_offset] != '\\n')\n\n> +\n> +\t\tbuf_offset += linelen;\n\nI would prefer to avoid having `linelen` altogether, and instead move the\n`buf_offset` assignment _after_ the loop that handles the current header\nline (and _not_ modify `buf_offset` inside):\n\n\tbuf_offset = strchrnul(buf->buf + buf_offset, '\\n');\n\tif (buf->buf[buf_offset] == '\\n')\n\t\tbuf_offset++;\n\n> +\n> +\t\tfor (i = 0; headers[i]; i++)\n> +\t\t\tif (skip_prefix(line, headers[i], &person))\n> +\t\t\t\tbuf_offset += rewrite_ident_line(person, buf, mailmap);\n\nAt this point, we have handled the header and should _not_ continue the\n(inner) `for` loop. This is important because `line` is potentially\ninvalidated by that `rewrite_ident_line()` call. See below for a patch\n(which is on top of `shears/seen`, but you get the idea.\n\nThis issue could also be avoided by consistently using `buf->buf +\nbuf_offset` instead of `line`.\n\n> +\t}\n> +}\n> +\n>  static int commit_match(struct commit *commit, struct rev_info *opt)\n>  {\n>  \tint retval;\n\n-- snipsnap --\nFrom 61dd169def195eee9827a9a670f8dab606279cea Mon Sep 17 00:00:00 2001\nFrom: Johannes Schindelin <johannes.schindelin@gmx.de>\nDate: Tue, 12 Jul 2022 15:10:35 +0200\nSubject: [PATCH] fixup??? revision: improve commit_rewrite_person()\n\nWhen the `linux-musl` job failed in t4203.44 with a segmentation fault,\nI became suspicious. From\nhttps://github.com/git-for-windows/git/runs/7301741954?check_suite_focus=true#step:5:1775:\n\n  + test_config mailmap.file complex.map\n  + config_dir=\n  + test mailmap.file '=' -C\n  + test_when_finished 'test_unconfig  '\"'\"'mailmap.file'\"'\"\n  + test 0 '=' 0\n  + test_cleanup='{ test_unconfig  '\"'\"'mailmap.file'\"'\"'\n  \t\t} && (exit \"$eval_ret\"); eval_ret=$?; :'\n  + git config mailmap.file complex.map\n  + git log --use-mailmap --author '<cto@coompany.xx>'\n  Segmentation fault (core dumped)\n  error: last command exited with $?=139\n\nI suspected a memory corruption, and my go-to tool to investigate those\nis `valgrind`, so I ran `t4203-*.sh -ivx --valgrind-only=44`. It\nreported the following:\n\n-- snip --\n[...]\nexpecting success of 4203.44 'Only grep replaced author with --use-mailmap':\n\ttest_config mailmap.file complex.map &&\n\tgit log --use-mailmap --author \"<cto@coompany.xx>\" >actual &&\n\ttest_must_be_empty actual\n\n+ test_config mailmap.file complex.map\n+ config_dir=\n+ test mailmap.file = -C\n+ test_when_finished test_unconfig  'mailmap.file'\n+ test 0 = 0\n+ test_cleanup={ test_unconfig  'mailmap.file'\n\t\t} && (exit \"$eval_ret\"); eval_ret=$?; :\n+ git config mailmap.file complex.map\n+ git log --use-mailmap --author <cto@coompany.xx>\n==14374== Invalid read of size 1\n==14374==    at 0x2EE384: skip_prefix (git-compat-util.h:676)\n==14374==    by 0x2EF31D: apply_mailmap_to_header (ident.c:417)\n==14374==    by 0x3BB045: commit_match (revision.c:3831)\n==14374==    by 0x3BB389: get_commit_action (revision.c:3917)\n==14374==    by 0x3BB934: simplify_commit (revision.c:4005)\n==14374==    by 0x3BBCAD: get_revision_1 (revision.c:4083)\n==14374==    by 0x3BBEF0: get_revision_internal (revision.c:4184)\n==14374==    by 0x3BC192: get_revision (revision.c:4262)\n==14374==    by 0x1A0B05: cmd_log_walk_no_free (log.c:454)\n==14374==    by 0x1A0BCD: cmd_log_walk (log.c:496)\n==14374==    by 0x1A1E90: cmd_log (log.c:818)\n==14374==    by 0x129A04: run_builtin (git.c:466)\n==14374==  Address 0x4b76f4e is 94 bytes inside a block of size 210 free'd\n==14374==    at 0x483DFAF: realloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)\n==14374==    by 0x42F908: xrealloc (wrapper.c:136)\n==14374==    by 0x3E6742: strbuf_grow (strbuf.c:99)\n==14374==    by 0x3E6F1F: strbuf_splice (strbuf.c:242)\n==14374==    by 0x2EF220: rewrite_ident_line (ident.c:382)\n==14374==    by 0x2EF338: apply_mailmap_to_header (ident.c:418)\n==14374==    by 0x3BB045: commit_match (revision.c:3831)\n==14374==    by 0x3BB389: get_commit_action (revision.c:3917)\n==14374==    by 0x3BB934: simplify_commit (revision.c:4005)\n==14374==    by 0x3BBCAD: get_revision_1 (revision.c:4083)\n==14374==    by 0x3BBEF0: get_revision_internal (revision.c:4184)\n==14374==    by 0x3BC192: get_revision (revision.c:4262)\n==14374==  Block was alloc'd at\n==14374==    at 0x483B723: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)\n==14374==    by 0x483E017: realloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)\n==14374==    by 0x42F908: xrealloc (wrapper.c:136)\n==14374==    by 0x3E6742: strbuf_grow (strbuf.c:99)\n==14374==    by 0x3E733D: strbuf_add (strbuf.c:298)\n==14374==    by 0x3AF420: strbuf_addstr (strbuf.h:305)\n==14374==    by 0x3BB027: commit_match (revision.c:3829)\n==14374==    by 0x3BB389: get_commit_action (revision.c:3917)\n==14374==    by 0x3BB934: simplify_commit (revision.c:4005)\n==14374==    by 0x3BBCAD: get_revision_1 (revision.c:4083)\n==14374==    by 0x3BBEF0: get_revision_internal (revision.c:4184)\n==14374==    by 0x3BC192: get_revision (revision.c:4262)\n==14374==\n{\n   <insert_a_suppression_name_here>\n   Memcheck:Addr1\n   fun:skip_prefix\n   fun:apply_mailmap_to_header\n   fun:commit_match\n   fun:get_commit_action\n   fun:simplify_commit\n   fun:get_revision_1\n   fun:get_revision_internal\n   fun:get_revision\n   fun:cmd_log_walk_no_free\n   fun:cmd_log_walk\n   fun:cmd_log\n   fun:run_builtin\n}\nerror: last command exited with $?=126\nnot ok 44 - Only grep replaced author with --use-mailmap\n1..44\n-- snap --\n\nAnd indeed, we see that the `rewrite_ident_line()` function grows the\nstrbuf, which can (and does, in this instance) move the buffer to a new\naddress, which invalidates the `line` pointer, which still points at the\nold address.\n\nIt might actually make sense to rewrite the entire part of the original\npatch where it looks for the end of the header line, so that it avoids\nworking on pointers altogether, and uses offsets instead.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n ident.c | 4 +++-\n 1 file changed, 3 insertions(+), 1 deletion(-)\n\ndiff --git a/ident.c b/ident.c\nindex 5f17bd607dd..fbcf7250aab 100644\n--- a/ident.c\n+++ b/ident.c\n@@ -414,8 +414,10 @@ void apply_mailmap_to_header(struct strbuf *buf, const char **headers, struct st\n \t\tbuf_offset += linelen;\n\n \t\tfor (i = 0; headers[i]; i++)\n-\t\t\tif (skip_prefix(line, headers[i], &person))\n+\t\t\tif (skip_prefix(line, headers[i], &person)) {\n \t\t\t\tbuf_offset += rewrite_ident_line(person, buf, mailmap);\n+\t\t\t\tbreak;\n+\t\t\t}\n \t}\n }\n\n--\n2.37.0.rc2.windows.1.7.g45a475aeb84\n\n"},{"id":"458931","messageId":"220713.86mtdd4xdd.gmgdl@evledraar.gmail.com","threadId":"58088","inReplyTo":"20220712160634.213956-2-siddharthasthana31@gmail.com","subject":"Re: [PATCH v4 1/4] revision: improve commit_rewrite_person()","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-07-13T01:25:24Z","receivedAt":"2022-07-13T01:25:42Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Tue, Jul 12 2022, Siddharth Asthana wrote:\n\n> -static int commit_rewrite_person(struct strbuf *buf, const char *what, struct string_list *mailmap)\n> +/*\n> + * Returns the difference between the new and old length of the ident line.\n> + */\n> +static ssize_t rewrite_ident_line(const char* person, struct strbuf *buf, struct string_list *mailmap)\n\nAll tests pass with this as size_t, instead of size_t. Let's use that\nhere instead?\n"},{"id":"458933","messageId":"220713.86ilo14wqq.gmgdl@evledraar.gmail.com","threadId":"58088","inReplyTo":"20220712160634.213956-4-siddharthasthana31@gmail.com","subject":"Re: [PATCH v4 3/4] ident: rename commit_rewrite_person() to apply_mailmap_to_header()","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-07-13T01:25:40Z","receivedAt":"2022-07-13T01:39:34Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Tue, Jul 12 2022, Siddharth Asthana wrote:\n\n> commit_rewrite_person() takes a commit buffer and replaces the idents\n> in the header with their canonical versions using the mailmap mechanism.\n> The name \"commit_rewrite_person()\" is misleading as it doesn't convey\n> what kind of rewrite are we going to do to the buffer. It also doesn't\n> clearly mention that the function will limit itself to the header part\n> of the buffer. The new name, \"apply_mailmap_to_header()\", expresses the\n> functionality of the function pretty clearly.\n>\n> We intend to use apply_mailmap_to_header() in git-cat-file to replace\n> idents in the headers of commit and tag object buffers. So, we will be\n> extending this function to take tag objects buffer as well and replace\n> idents on the tagger header using the mailmap mechanism.\n>\n> Mentored-by: Christian Couder <christian.couder@gmail.com>\n> Mentored-by: John Cai <johncai86@gmail.com>\n> Signed-off-by: Siddharth Asthana <siddharthasthana31@gmail.com>\n> ---\n>  cache.h    | 6 +++---\n>  ident.c    | 2 +-\n>  revision.c | 2 +-\n>  3 files changed, 5 insertions(+), 5 deletions(-)\n>\n> diff --git a/cache.h b/cache.h\n> index c9dbe1c29a..9edb7fefd3 100644\n> --- a/cache.h\n> +++ b/cache.h\n> @@ -1689,10 +1689,10 @@ struct ident_split {\n>  int split_ident_line(struct ident_split *, const char *, int);\n>  \n>  /*\n> - * Given a commit object buffer and the commit headers, replaces the idents\n> - * in the headers with their canonical versions using the mailmap mechanism.\n> + * Given a commit or tag object buffer and the commit or tag headers, replaces\n> + * the idents in the headers with their canonical versions using the mailmap mechanism.\n>   */\n> -void commit_rewrite_person(struct strbuf *buf, const char **commit_headers, struct string_list *mailmap);\n> +void apply_mailmap_to_header(struct strbuf *buf, const char **headers, struct string_list *mailmap);\n>  \n>  /*\n>   * Compare split idents for equality or strict ordering. Note that we\n> diff --git a/ident.c b/ident.c\n> index 9f4f6e9071..5f17bd607d 100644\n> --- a/ident.c\n> +++ b/ident.c\n> @@ -393,7 +393,7 @@ static ssize_t rewrite_ident_line(const char* person, struct strbuf *buf, struct\n>  \treturn 0;\n>  }\n>  \n> -void commit_rewrite_person(struct strbuf *buf, const char **headers, struct string_list *mailmap)\n> +void apply_mailmap_to_header(struct strbuf *buf, const char **headers, struct string_list *mailmap)\n>  {\n>  \tsize_t buf_offset = 0;\n>  \n> diff --git a/revision.c b/revision.c\n> index 14dca903b6..6ad3665204 100644\n> --- a/revision.c\n> +++ b/revision.c\n> @@ -3792,7 +3792,7 @@ static int commit_match(struct commit *commit, struct rev_info *opt)\n>  \t\tif (!buf.len)\n>  \t\t\tstrbuf_addstr(&buf, message);\n>  \n> -\t\tcommit_rewrite_person(&buf, commit_headers, opt->mailmap);\n> +\t\tapply_mailmap_to_header(&buf, commit_headers, opt->mailmap);\n>  \t}\n>  \n>  \t/* Append \"fake\" message parts as needed */\n\nI can live with this so far, but I really think this is cementing the\nwrong approach into place here.\n\nWe only use commit_match() to feed a commit to grep.c, which if you look\nat the \"header_field\" struct there we take this pre-formatted output and\nparse this out *again*, i.e. find \"author\", \"reflog\", \"committer\" etc.,\nand eventually point the regex engine at that buffer.\n\nSo we really don't need to get a strbuf here, and munge the whole thing\nin place to feed it to grep.c, instead we can:\n\n 1. Not munge it at all, pass it as-is\n 2. Pass the mailmap along to grep.c itself\n 3. It's already parsing out the headers, so at some point it will have\n    \"author foo <bar>\\n\"\n 4. In that code, we can just consult the mailmap, and then map the \"foo\n   <bar>\" bart to \"Baz <bar>\" or whatever\n 5. Thean search that string.\n\nSo no need for any in-place rewriting, or no?\n\nEven with this approach this seems a bit odd, e.g. isn't your\ncommit_rewrite_person() largely a re-invention of find_commit_header()\nin commit.c, can't we use that function there?\n\nThe replace_idents_using_mailmap() in 4/4 seems like it could be\nimproved in a similar way.\n\nI.e. can't we just loop over the the object, then as we find \"author\"\nconsult the mailmap, and potentially emit a replacement, otherwise the\nexisting content as-is up until the next \\n etc.\n\nWe should be able to \"stream\" all of this, instead of in-place modifying\na potentially large commit buffer, which involves memmove() etc.\n"},{"id":"458951","messageId":"CAP8UFD363FPO=eOnzb_8T54eVn2c8SGAvV+27rB=gwzs6o-cNA@mail.gmail.com","threadId":"58088","inReplyTo":"220713.86mtdd4xdd.gmgdl@evledraar.gmail.com","subject":"Re: [PATCH v4 1/4] revision: improve commit_rewrite_person()","fromName":"Christian Couder","fromEmail":"christian.couder@gmail.com","sentAt":"2022-07-13T12:18:14Z","receivedAt":"2022-07-13T12:18:29Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"On Wed, Jul 13, 2022 at 3:25 AM Ævar Arnfjörð Bjarmason\n<avarab@gmail.com> wrote:\n>\n>\n> On Tue, Jul 12 2022, Siddharth Asthana wrote:\n>\n> > -static int commit_rewrite_person(struct strbuf *buf, const char *what, struct string_list *mailmap)\n> > +/*\n> > + * Returns the difference between the new and old length of the ident line.\n> > + */\n> > +static ssize_t rewrite_ident_line(const char* person, struct strbuf *buf, struct string_list *mailmap)\n>\n> All tests pass with this as size_t, instead of size_t. Let's use that\n> here instead?\n\nDo you mean you would like to use size_t instead of ssize_t for the\ntype of the value returned by the function?\n\nI think it can return a negative value if the new length of the ident\nline is shorter than the old one though.\n"},{"id":"458980","messageId":"CAP8UFD0zAk0dEhTibh24tPuRusSrPaYGWVFdBD3B1XmUG7dk_w@mail.gmail.com","threadId":"58088","inReplyTo":"220713.86ilo14wqq.gmgdl@evledraar.gmail.com","subject":"Re: [PATCH v4 3/4] ident: rename commit_rewrite_person() to apply_mailmap_to_header()","fromName":"Christian Couder","fromEmail":"christian.couder@gmail.com","sentAt":"2022-07-13T13:29:28Z","receivedAt":"2022-07-13T13:29:48Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"On Wed, Jul 13, 2022 at 3:39 AM Ævar Arnfjörð Bjarmason\n<avarab@gmail.com> wrote:\n> On Tue, Jul 12 2022, Siddharth Asthana wrote:\n\n> > diff --git a/revision.c b/revision.c> > index 14dca903b6..6ad3665204 100644\n> > --- a/revision.c\n> > +++ b/revision.c\n> > @@ -3792,7 +3792,7 @@ static int commit_match(struct commit *commit, struct rev_info *opt)\n> >               if (!buf.len)\n> >                       strbuf_addstr(&buf, message);\n> >\n> > -             commit_rewrite_person(&buf, commit_headers, opt->mailmap);\n> > +             apply_mailmap_to_header(&buf, commit_headers, opt->mailmap);\n> >       }\n> >\n> >       /* Append \"fake\" message parts as needed */\n>\n> I can live with this so far, but I really think this is cementing the\n> wrong approach into place here.\n>\n> We only use commit_match() to feed a commit to grep.c, which if you look\n> at the \"header_field\" struct there we take this pre-formatted output and\n> parse this out *again*, i.e. find \"author\", \"reflog\", \"committer\" etc.,\n> and eventually point the regex engine at that buffer.\n>\n> So we really don't need to get a strbuf here, and munge the whole thing\n> in place to feed it to grep.c, instead we can:\n>\n>  1. Not munge it at all, pass it as-is\n>  2. Pass the mailmap along to grep.c itself\n>  3. It's already parsing out the headers, so at some point it will have\n>     \"author foo <bar>\\n\"\n>  4. In that code, we can just consult the mailmap, and then map the \"foo\n>    <bar>\" bart to \"Baz <bar>\" or whatever\n>  5. Thean search that string.\n>\n> So no need for any in-place rewriting, or no?\n\nThis patch series is about improving `git cat-file` and it seems to be\nfar fetched to ask it to rewrite how grep handles mailmap first.\n\n> Even with this approach this seems a bit odd, e.g. isn't your\n> commit_rewrite_person() largely a re-invention of find_commit_header()\n> in commit.c, can't we use that function there?\n\nfind_commit_header() seems to be searching for only one header, while\nwe want to search for more than one. Also we want only one pass to be\nmade over the object buffer. So I think we cannot really reuse\nfind_commit_header().\n\n> The replace_idents_using_mailmap() in 4/4 seems like it could be\n> improved in a similar way.\n>\n> I.e. can't we just loop over the the object, then as we find \"author\"\n> consult the mailmap, and potentially emit a replacement, otherwise the\n> existing content as-is up until the next \\n etc.\n\nThat's what we do except that we replace the existing ident instead of\nemitting a replacement.\n\n> We should be able to \"stream\" all of this, instead of in-place modifying\n> a potentially large commit buffer, which involves memmove() etc.\n\nI am not sure if streaming is really much better, especially if there\nare a small number of commit or tag objects where an ident must be\nreplaced.\n"},{"id":"459083","messageId":"xmqq8rov4dc5.fsf@gitster.g","threadId":"58088","inReplyTo":"20220712160634.213956-2-siddharthasthana31@gmail.com","subject":"Re: [PATCH v4 1/4] revision: improve commit_rewrite_person()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-07-14T21:02:50Z","receivedAt":"2022-07-14T21:02:56Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Siddharth Asthana <siddharthasthana31@gmail.com> writes:\n\n> +/*\n> + * Returns the difference between the new and old length of the ident line.\n> + */\n> +static ssize_t rewrite_ident_line(const char* person, struct strbuf *buf, struct string_list *mailmap)\n\n\"const char *person\".  Asterisk sticks to the variable, not to the\ntype.\n\nWrap such an overly long line.\n\n> +static void commit_rewrite_person(struct strbuf *buf, const char **headers, struct string_list *mailmap)\n\nLikewise.\n\nThe second parameter should be called \"header\", not \"headers\",\nbecause the way this array is used is primarily to access its\nindividual members, i.e. header[i] and it is more grammatical\nto say that header[0] is the zero-th header, not headers[0].\n\n> +{\n> +\tsize_t buf_offset = 0;\n> +\n> +\tif (!mailmap)\n> +\t\treturn;\n> +\n> +\tfor (;;) {\n> +\t\tconst char *person, *line;\n> +\t\tsize_t i, linelen;\n> +\n> +\t\tline = buf->buf + buf_offset;\n\nbuf_offset is initialized to 0.  The idea is to keep track of the\nposition of the current line in buf->buf as the byte offset from the\nbeginning.  This makes it safe to let rewrite_ident_line()\nreallocate buf->buf in the loop.  So \"line\" points at the beginning\nof the current line.\n\n> +\t\tlinelen = strchrnul(line, '\\n') - line + 1;\n\nThis \"linelen\" counts the LF (or NUL) termination.  Hence ...\n\n> +\t\tif (linelen <= 1)\n> +\t\t\t/* End of header */\n> +\t\t\treturn;\n\n... linelen==0 means we are at an empty line.\n\n> +\t\tbuf_offset += linelen;\n\nAnd by adding linelen to buf_offset, we prepare buf_offset to point\nat the beginning of the next line.\n\nBUT.\n\nWhat happens when the buffer has only headers, no body, without an\nempty line after the header?  buf_offset will be pointing at the\nbyte past the final NUL at the end of the buffer.  The next round of\nthe loop will point line at an invalid piece of memory.\n\nI _think_ that the current generation of high-level tools like \"git\ncommit\" and \"git tag\" may leave an blank line at the end even when\nthey are told to create a message with no body, but this code should\nnot depend on that.  An object with no body and without a blank line\nafter the header is a valid object (cf. fsck.c::verify_headers()).\n\n> +\t\tfor (i = 0; headers[i]; i++)\n> +\t\t\tif (skip_prefix(line, headers[i], &person))\n> +\t\t\t\tbuf_offset += rewrite_ident_line(person, buf, mailmap);\n> +\t}\n\nAs the commit_headers[] array the caller gives us does not have\nduplicates, as soon as we find a match, we should break out of the\nloop, i.e.\n\n\t\tfor (i = 0; header[i]; i++) {\n\t\t\tif (skip_prefix(line, header[i], &person))\n\t\t\t\tbuf_offset += rewrite_ident_line(person, buf, maimap);\n\t\t\tbreak;\n\t\t}\n\n> +}\n> +\n>  static int commit_match(struct commit *commit, struct rev_info *opt)\n>  {\n>  \tint retval;\n> @@ -3832,11 +3859,12 @@ static int commit_match(struct commit *commit, struct rev_info *opt)\n>  \t\tstrbuf_addstr(&buf, message);\n>  \n>  \tif (opt->grep_filter.header_list && opt->mailmap) {\n> +\t\tconst char *commit_headers[] = { \"author \", \"committer \", NULL };\n\nIt is OK to call the array \"commit_headers\", because the way we use\nthe identifier is only to refer to the collection of headers as a\nwhole.\n\n>  \t\tif (!buf.len)\n>  \t\t\tstrbuf_addstr(&buf, message);\n>  \n> -\t\tcommit_rewrite_person(&buf, \"\\nauthor \", opt->mailmap);\n> -\t\tcommit_rewrite_person(&buf, \"\\ncommitter \", opt->mailmap);\n> +\t\tcommit_rewrite_person(&buf, commit_headers, opt->mailmap);\n>  \t}\n>  \n>  \t/* Append \"fake\" message parts as needed */\n\nThanks.\n"},{"id":"459183","messageId":"20220716074055.1786231-1-siddharthasthana31@gmail.com","threadId":"58088","inReplyTo":"20220712160634.213956-1-siddharthasthana31@gmail.com","subject":"[PATCH v5 0/4] Add support for mailmap in cat-file","fromName":"Siddharth Asthana","fromEmail":"siddharthasthana31@gmail.com","sentAt":"2022-07-16T07:40:51Z","receivedAt":"2022-07-16T07:41:13Z","isPatch":true,"sender":{"key":"siddharthasthana31@gmail.com","avatar":"https://avatars.githubusercontent.com/u/53316982?v=4"},"body":"Thanks a lot Johannes and Junio for helping me identify and fix the memory\ncorruption in commit_rewrite_person()!  :)\n\n= Description\n\nThis patch series adds mailmap support to the git-cat-file command. It\nadds the mailmap support only for the commit and tag objects by\nreplacing the idents for \"author\", \"committer\" and \"tagger\" headers. The\nmailmap only takes effect when --[no-]-use-mailmap or --[no-]-mailmap\noption is passed to the git cat-file command. The changes will work with\nthe batch mode as well.\n\nSo, if one wants to enable mailmap they can use either of the following\ncommands:\n$ git cat-file --use-mailmap -p <object>\n$ git cat-file --use-mailmap <type> <object>\n\nTo use it in the batch mode, one can use the following command:\n$ git cat-file --use-mailmap --batch\n\n= Patch Organization\n\n- The first patch improves the commit_rewrite_person() by restricting it \n  to traverse only through the header part of the commit object buffer.\n  It also adds an argument called headers which the callers can pass. \n  The function will replace idents only on these  passed headers. \n  Thus, the caller won't have to make repeated calls to the function.\n- The second patch moves commit_rewrite_person() to ident.c to expose it\n  as a public function so that it can be used to replace idents in the\n  headers of desired objects.\n- The third patch renames commit_rewrite_person() to a name which\n  describes its functionality clearly. It is renamed to\n  apply_mailmap_to_header().\n- The last patch adds mailmap support to the git cat-file command. It\n  adds the required documentation and tests as well.\n\nChanges in v5:\n- In commit_rewrite_person(), we make calls to rewrite_ident_line(),\n  where the strbuf can grow. This moves the buffer to a new address,\n  which invalidates the `line` pointer, which still points at the same\n  address . This issue has been fixed by breaking out of the inner for\n  loop as soon as there we find a match for any commit headers that we\n  are passing to the function.\n- The commit_rewrite_person() no longer has a `linelen` variable and\n  instead we now rely on `buf_offset` for navigating through the buffer.\n- Some overly long lines have been wrapped.\n\nSiddharth Asthana (4):\n  revision: improve commit_rewrite_person()\n  ident: move commit_rewrite_person() to ident.c\n  ident: rename commit_rewrite_person() to apply_mailmap_to_header()\n  cat-file: add mailmap support\n\n Documentation/git-cat-file.txt |  6 +++\n builtin/cat-file.c             | 43 ++++++++++++++++++-\n cache.h                        |  6 +++\n ident.c                        | 75 ++++++++++++++++++++++++++++++++++\n revision.c                     | 50 ++---------------------\n t/t4203-mailmap.sh             | 59 ++++++++++++++++++++++++++\n 6 files changed, 191 insertions(+), 48 deletions(-)\n\nRange-diff against v4:\n1:  9e95326c58 ! 1:  8c29ad9351 revision: improve commit_rewrite_person()\n    @@ Commit message\n         Mentored-by: Christian Couder <christian.couder@gmail.com>\n         Mentored-by: John Cai <johncai86@gmail.com>\n         Helped-by: Đoàn Trần Công Danh <congdanhqx@gmail.com>\n    +    Helped-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>\n         Signed-off-by: Siddharth Asthana <siddharthasthana31@gmail.com>\n     \n      ## revision.c ##\n    @@ revision.c: int rewrite_parents(struct rev_info *revs, struct commit *commit,\n     +/*\n     + * Returns the difference between the new and old length of the ident line.\n     + */\n    -+static ssize_t rewrite_ident_line(const char* person, struct strbuf *buf, struct string_list *mailmap)\n    ++static ssize_t rewrite_ident_line(const char *person, struct strbuf *buf,\n    ++\t\t\t\t\t\t\t\t  struct string_list *mailmap)\n      {\n     -\tchar *person, *endp;\n     +\tchar *endp;\n    @@ revision.c: static int commit_rewrite_person(struct strbuf *buf, const char *wha\n      \treturn 0;\n      }\n      \n    -+static void commit_rewrite_person(struct strbuf *buf, const char **headers, struct string_list *mailmap)\n    ++static void commit_rewrite_person(struct strbuf *buf, const char **header,\n    ++\t\t\t\t\t\t\t\t  struct string_list *mailmap)\n     +{\n     +\tsize_t buf_offset = 0;\n     +\n    @@ revision.c: static int commit_rewrite_person(struct strbuf *buf, const char *wha\n     +\n     +\tfor (;;) {\n     +\t\tconst char *person, *line;\n    -+\t\tsize_t i, linelen;\n    ++\t\tsize_t i;\n     +\n     +\t\tline = buf->buf + buf_offset;\n    -+\t\tlinelen = strchrnul(line, '\\n') - line + 1;\n    ++\t\tif (!*line || *line == '\\n')\n    ++\t\t\treturn; /* End of header */\n     +\n    -+\t\tif (linelen <= 1)\n    -+\t\t\t/* End of header */\n    -+\t\t\treturn;\n    ++\t\tfor (i = 0; header[i]; i++)\n    ++\t\t\tif (skip_prefix(line, header[i], &person)) {\n    ++\t\t\t\trewrite_ident_line(person, buf, mailmap);\n    ++\t\t\t\tbreak;\n    ++\t\t\t}\n     +\n    -+\t\tbuf_offset += linelen;\n    -+\n    -+\t\tfor (i = 0; headers[i]; i++)\n    -+\t\t\tif (skip_prefix(line, headers[i], &person))\n    -+\t\t\t\tbuf_offset += rewrite_ident_line(person, buf, mailmap);\n    ++\t\tbuf_offset = strchrnul(buf->buf + buf_offset, '\\n') - buf->buf;\n    ++\t\tif (buf->buf[buf_offset] == '\\n')\n    ++\t\t\t++buf_offset;\n     +\t}\n     +}\n     +\n2:  d9395cb8b2 ! 2:  ccb7f72fcb ident: move commit_rewrite_person() to ident.c\n    @@ cache.h: struct ident_split {\n     + * Given a commit object buffer and the commit headers, replaces the idents\n     + * in the headers with their canonical versions using the mailmap mechanism.\n     + */\n    -+void commit_rewrite_person(struct strbuf *buf, const char **commit_headers, struct string_list *mailmap);\n    ++void commit_rewrite_person(struct strbuf *, const char **, struct string_list *);\n     +\n      /*\n       * Compare split idents for equality or strict ordering. Note that we\n    @@ ident.c: int split_ident_line(struct ident_split *split, const char *line, int l\n     +/*\n     + * Returns the difference between the new and old length of the ident line.\n     + */\n    -+static ssize_t rewrite_ident_line(const char* person, struct strbuf *buf, struct string_list *mailmap)\n    ++static ssize_t rewrite_ident_line(const char *person, struct strbuf *buf,\n    ++\t\t\t\t\t\t\t\t  struct string_list *mailmap)\n     +{\n     +\tchar *endp;\n     +\tsize_t len, namelen, maillen;\n    @@ ident.c: int split_ident_line(struct ident_split *split, const char *line, int l\n     +\treturn 0;\n     +}\n     +\n    -+void commit_rewrite_person(struct strbuf *buf, const char **headers, struct string_list *mailmap)\n    ++void commit_rewrite_person(struct strbuf *buf, const char **header,\n    ++\t\t\t\t\t\t   struct string_list *mailmap)\n     +{\n     +\tsize_t buf_offset = 0;\n     +\n    @@ ident.c: int split_ident_line(struct ident_split *split, const char *line, int l\n     +\n     +\tfor (;;) {\n     +\t\tconst char *person, *line;\n    -+\t\tsize_t i, linelen;\n    ++\t\tsize_t i;\n     +\n     +\t\tline = buf->buf + buf_offset;\n    -+\t\tlinelen = strchrnul(line, '\\n') - line + 1;\n    -+\n    -+\t\tif (linelen <= 1)\n    -+\t\t\t/* End of header */\n    -+\t\t\treturn;\n    -+\n    -+\t\tbuf_offset += linelen;\n    -+\n    -+\t\tfor (i = 0; headers[i]; i++)\n    -+\t\t\tif (skip_prefix(line, headers[i], &person))\n    -+\t\t\t\tbuf_offset += rewrite_ident_line(person, buf, mailmap);\n    ++\t\tif (!*line || *line == '\\n')\n    ++\t\t\treturn; /* End of header */\n    ++\n    ++\t\tfor (i = 0; header[i]; i++)\n    ++\t\t\tif (skip_prefix(line, header[i], &person)) {\n    ++\t\t\t\trewrite_ident_line(person, buf, mailmap);\n    ++\t\t\t\tbreak;\n    ++\t\t\t}\n    ++\n    ++\t\tbuf_offset = strchrnul(buf->buf + buf_offset, '\\n') - buf->buf;\n    ++\t\tif (buf->buf[buf_offset] == '\\n')\n    ++\t\t\t++buf_offset;\n     +\t}\n     +}\n      \n    @@ revision.c: int rewrite_parents(struct rev_info *revs, struct commit *commit,\n     -/*\n     - * Returns the difference between the new and old length of the ident line.\n     - */\n    --static ssize_t rewrite_ident_line(const char* person, struct strbuf *buf, struct string_list *mailmap)\n    +-static ssize_t rewrite_ident_line(const char *person, struct strbuf *buf,\n    +-\t\t\t\t\t\t\t\t  struct string_list *mailmap)\n     -{\n     -\tchar *endp;\n     -\tsize_t len, namelen, maillen;\n    @@ revision.c: int rewrite_parents(struct rev_info *revs, struct commit *commit,\n     -\treturn 0;\n     -}\n     -\n    --static void commit_rewrite_person(struct strbuf *buf, const char **headers, struct string_list *mailmap)\n    +-static void commit_rewrite_person(struct strbuf *buf, const char **header,\n    +-\t\t\t\t\t\t\t\t  struct string_list *mailmap)\n     -{\n     -\tsize_t buf_offset = 0;\n     -\n    @@ revision.c: int rewrite_parents(struct rev_info *revs, struct commit *commit,\n     -\n     -\tfor (;;) {\n     -\t\tconst char *person, *line;\n    --\t\tsize_t i, linelen;\n    +-\t\tsize_t i;\n     -\n     -\t\tline = buf->buf + buf_offset;\n    --\t\tlinelen = strchrnul(line, '\\n') - line + 1;\n    --\n    --\t\tif (linelen <= 1)\n    --\t\t\t/* End of header */\n    --\t\t\treturn;\n    --\n    --\t\tbuf_offset += linelen;\n    --\n    --\t\tfor (i = 0; headers[i]; i++)\n    --\t\t\tif (skip_prefix(line, headers[i], &person))\n    --\t\t\t\tbuf_offset += rewrite_ident_line(person, buf, mailmap);\n    +-\t\tif (!*line || *line == '\\n')\n    +-\t\t\treturn; /* End of header */\n    +-\n    +-\t\tfor (i = 0; header[i]; i++)\n    +-\t\t\tif (skip_prefix(line, header[i], &person)) {\n    +-\t\t\t\trewrite_ident_line(person, buf, mailmap);\n    +-\t\t\t\tbreak;\n    +-\t\t\t}\n    +-\n    +-\t\tbuf_offset = strchrnul(buf->buf + buf_offset, '\\n') - buf->buf;\n    +-\t\tif (buf->buf[buf_offset] == '\\n')\n    +-\t\t\t++buf_offset;\n     -\t}\n     -}\n     -\n3:  355bbda25e ! 3:  38c18fd10d ident: rename commit_rewrite_person() to apply_mailmap_to_header()\n    @@ cache.h: struct ident_split {\n     + * Given a commit or tag object buffer and the commit or tag headers, replaces\n     + * the idents in the headers with their canonical versions using the mailmap mechanism.\n       */\n    --void commit_rewrite_person(struct strbuf *buf, const char **commit_headers, struct string_list *mailmap);\n    -+void apply_mailmap_to_header(struct strbuf *buf, const char **headers, struct string_list *mailmap);\n    +-void commit_rewrite_person(struct strbuf *, const char **, struct string_list *);\n    ++void apply_mailmap_to_header(struct strbuf *, const char **, struct string_list *);\n      \n      /*\n       * Compare split idents for equality or strict ordering. Note that we\n     \n      ## ident.c ##\n    -@@ ident.c: static ssize_t rewrite_ident_line(const char* person, struct strbuf *buf, struct\n    +@@ ident.c: static ssize_t rewrite_ident_line(const char *person, struct strbuf *buf,\n      \treturn 0;\n      }\n      \n    --void commit_rewrite_person(struct strbuf *buf, const char **headers, struct string_list *mailmap)\n    -+void apply_mailmap_to_header(struct strbuf *buf, const char **headers, struct string_list *mailmap)\n    +-void commit_rewrite_person(struct strbuf *buf, const char **header,\n    +-\t\t\t\t\t\t   struct string_list *mailmap)\n    ++void apply_mailmap_to_header(struct strbuf *buf, const char **header,\n    ++\t\t\t\t\t\t\t struct string_list *mailmap)\n      {\n      \tsize_t buf_offset = 0;\n      \n4:  ac532965b4 ! 4:  0a459d4c53 cat-file: add mailmap support\n    @@ Commit message\n         This patch also introduces new test cases to test the mailmap mechanism in\n         git cat-file command.\n     \n    -    The tests added in this patch series rely on the side effects of the earlier\n    -    test case `set up symlink tests`. However, that test case is guarded behind the\n    -    `SYMLINKS` prereq, therefore it is not run e.g. on Windows which can cause the\n    -    added tests to fail on Windows. So, fix that by removing the prereq from the\n    -    `set up` test case, and adjusting its title to reflect its broadened responsibility.\n    -\n         Mentored-by: Christian Couder <christian.couder@gmail.com>\n         Mentored-by: John Cai <johncai86@gmail.com>\n         Helped-by: Phillip Wood <phillip.wood@dunelm.org.uk>\n    @@ builtin/cat-file.c: int cmd_cat_file(int argc, const char **argv, const char *pr\n      \t\tbatch.all_objects = 1;\n     \n      ## t/t4203-mailmap.sh ##\n    -@@ t/t4203-mailmap.sh: test_expect_success 'find top-level mailmap from subdir' '\n    - \ttest_cmp expect actual\n    - '\n    - \n    --test_expect_success SYMLINKS 'set up symlink tests' '\n    -+test_expect_success 'prepare for symlink/--use-mailmap tests' '\n    - \tgit commit --allow-empty -m foo --author=\"Orig <orig@example.com>\" &&\n    - \techo \"New <new@example.com> <orig@example.com>\" >map &&\n    - \trm -f .mailmap\n     @@ t/t4203-mailmap.sh: test_expect_success SYMLINKS 'symlinks not respected in-tree' '\n      \ttest_cmp expect actual\n      '\n      \n    ++test_expect_success 'prepare for cat-file --mailmap' '\n    ++\trm -f .mailmap &&\n    ++\tgit commit --allow-empty -m foo --author=\"Orig <orig@example.com>\"\n    ++'\n    ++\n     +test_expect_success '--no-use-mailmap disables mailmap in cat-file' '\n     +\ttest_when_finished \"rm .mailmap\" &&\n     +\tcat >.mailmap <<-EOF &&\n-- \n2.37.1.120.g001f220fb8\n\n"},{"id":"459184","messageId":"20220716074055.1786231-2-siddharthasthana31@gmail.com","threadId":"58088","inReplyTo":"20220716074055.1786231-1-siddharthasthana31@gmail.com","subject":"[PATCH v5 1/4] revision: improve commit_rewrite_person()","fromName":"Siddharth Asthana","fromEmail":"siddharthasthana31@gmail.com","sentAt":"2022-07-16T07:40:52Z","receivedAt":"2022-07-16T07:41:19Z","isPatch":true,"sender":{"key":"siddharthasthana31@gmail.com","avatar":"https://avatars.githubusercontent.com/u/53316982?v=4"},"body":"The function, commit_rewrite_person(), is designed to find and replace\nan ident string in the header part, and the way it avoids a random\noccurrence of \"author A U Thor <author@example.com\" in the text is by\ninsisting \"author\" to appear at the beginning of line by passing\n\"\\nauthor \" as \"what\".\n\nThe implementation also doesn't make any effort to limit itself to the\ncommit header by locating the blank line that appears after the header\npart and stopping the search there. Also, the interface forces the\ncaller to make multiple calls if it wants to rewrite idents on multiple\nheaders. It shouldn't be the case.\n\nTo support the existing caller better, update commit_rewrite_person()\nto:\n- Make a single pass in the input buffer to locate headers named\n  \"author\" and \"committer\" and replace idents on them.\n- Stop at the end of the header, ensuring that nothing in the body of\n  the commit object is modified.\n\nThe return type of the function commit_rewrite_person() has also been\nchanged from int to void. This has been done because the caller of the\nfunction doesn't do anything with the return value of the function.\n\nBy simplifying the interface of the commit_rewrite_person(), we also\nintend to expose it as a public function. We will also be renaming the\nfunction in a future commit to a different name which clearly tells that\nthe function replaces idents in the header of the commit buffer.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: John Cai <johncai86@gmail.com>\nHelped-by: Đoàn Trần Công Danh <congdanhqx@gmail.com>\nHelped-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>\nSigned-off-by: Siddharth Asthana <siddharthasthana31@gmail.com>\n---\n revision.c | 51 +++++++++++++++++++++++++++++++++++++++++----------\n 1 file changed, 41 insertions(+), 10 deletions(-)\n\ndiff --git a/revision.c b/revision.c\nindex 211352795c..9909da928e 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -3755,19 +3755,18 @@ int rewrite_parents(struct rev_info *revs, struct commit *commit,\n \treturn 0;\n }\n \n-static int commit_rewrite_person(struct strbuf *buf, const char *what, struct string_list *mailmap)\n+/*\n+ * Returns the difference between the new and old length of the ident line.\n+ */\n+static ssize_t rewrite_ident_line(const char *person, struct strbuf *buf,\n+\t\t\t\t\t\t\t\t  struct string_list *mailmap)\n {\n-\tchar *person, *endp;\n+\tchar *endp;\n \tsize_t len, namelen, maillen;\n \tconst char *name;\n \tconst char *mail;\n \tstruct ident_split ident;\n \n-\tperson = strstr(buf->buf, what);\n-\tif (!person)\n-\t\treturn 0;\n-\n-\tperson += strlen(what);\n \tendp = strchr(person, '\\n');\n \tif (!endp)\n \t\treturn 0;\n@@ -3784,6 +3783,7 @@ static int commit_rewrite_person(struct strbuf *buf, const char *what, struct st\n \n \tif (map_user(mailmap, &mail, &maillen, &name, &namelen)) {\n \t\tstruct strbuf namemail = STRBUF_INIT;\n+\t\tsize_t newlen;\n \n \t\tstrbuf_addf(&namemail, \"%.*s <%.*s>\",\n \t\t\t    (int)namelen, name, (int)maillen, mail);\n@@ -3792,14 +3792,44 @@ static int commit_rewrite_person(struct strbuf *buf, const char *what, struct st\n \t\t\t      ident.mail_end - ident.name_begin + 1,\n \t\t\t      namemail.buf, namemail.len);\n \n+\t\tnewlen = namemail.len;\n+\n \t\tstrbuf_release(&namemail);\n \n-\t\treturn 1;\n+\t\treturn newlen - (ident.mail_end - ident.name_begin + 1);\n \t}\n \n \treturn 0;\n }\n \n+static void commit_rewrite_person(struct strbuf *buf, const char **header,\n+\t\t\t\t\t\t\t\t  struct string_list *mailmap)\n+{\n+\tsize_t buf_offset = 0;\n+\n+\tif (!mailmap)\n+\t\treturn;\n+\n+\tfor (;;) {\n+\t\tconst char *person, *line;\n+\t\tsize_t i;\n+\n+\t\tline = buf->buf + buf_offset;\n+\t\tif (!*line || *line == '\\n')\n+\t\t\treturn; /* End of header */\n+\n+\t\tfor (i = 0; header[i]; i++)\n+\t\t\tif (skip_prefix(line, header[i], &person)) {\n+\t\t\t\trewrite_ident_line(person, buf, mailmap);\n+\t\t\t\tbreak;\n+\t\t\t}\n+\n+\t\tbuf_offset = strchrnul(buf->buf + buf_offset, '\\n') - buf->buf;\n+\t\tif (buf->buf[buf_offset] == '\\n')\n+\t\t\t++buf_offset;\n+\t}\n+}\n+\n static int commit_match(struct commit *commit, struct rev_info *opt)\n {\n \tint retval;\n@@ -3832,11 +3862,12 @@ static int commit_match(struct commit *commit, struct rev_info *opt)\n \t\tstrbuf_addstr(&buf, message);\n \n \tif (opt->grep_filter.header_list && opt->mailmap) {\n+\t\tconst char *commit_headers[] = { \"author \", \"committer \", NULL };\n+\n \t\tif (!buf.len)\n \t\t\tstrbuf_addstr(&buf, message);\n \n-\t\tcommit_rewrite_person(&buf, \"\\nauthor \", opt->mailmap);\n-\t\tcommit_rewrite_person(&buf, \"\\ncommitter \", opt->mailmap);\n+\t\tcommit_rewrite_person(&buf, commit_headers, opt->mailmap);\n \t}\n \n \t/* Append \"fake\" message parts as needed */\n-- \n2.37.1.120.g001f220fb8\n\n"},{"id":"459185","messageId":"20220716074055.1786231-3-siddharthasthana31@gmail.com","threadId":"58088","inReplyTo":"20220716074055.1786231-1-siddharthasthana31@gmail.com","subject":"[PATCH v5 2/4] ident: move commit_rewrite_person() to ident.c","fromName":"Siddharth Asthana","fromEmail":"siddharthasthana31@gmail.com","sentAt":"2022-07-16T07:40:53Z","receivedAt":"2022-07-16T07:41:27Z","isPatch":true,"sender":{"key":"siddharthasthana31@gmail.com","avatar":"https://avatars.githubusercontent.com/u/53316982?v=4"},"body":"commit_rewrite_person() and rewrite_ident_line() are static functions\ndefined in revision.c.\n\nTheir usages are as follows:\n- commit_rewrite_person() takes a commit buffer and replaces the author\n  and committer idents with their canonical versions using the mailmap\n  mechanism\n- rewrite_ident_line() takes author/committer header lines from the\n  commit buffer and replaces the idents with their canonical versions\n  using the mailmap mechanism.\n\nThis patch moves commit_rewrite_person() and rewrite_ident_line() to\nident.c which contains many other functions related to idents like\nsplit_ident_line(). By moving commit_rewrite_person() to ident.c, we\nalso intend to use it in git-cat-file to replace committer and author\nidents from the headers to their canonical versions using the mailmap\nmechanism. The function is moved as is for now to make it clear that\nthere are no other changes, but it will be renamed in a following\ncommit.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: John Cai <johncai86@gmail.com>\nSigned-off-by: Siddharth Asthana <siddharthasthana31@gmail.com>\n---\n cache.h    |  6 +++++\n ident.c    | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++++++\n revision.c | 75 ------------------------------------------------------\n 3 files changed, 81 insertions(+), 75 deletions(-)\n\ndiff --git a/cache.h b/cache.h\nindex ac5ab4ef9d..16a08aada2 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -1688,6 +1688,12 @@ struct ident_split {\n  */\n int split_ident_line(struct ident_split *, const char *, int);\n \n+/*\n+ * Given a commit object buffer and the commit headers, replaces the idents\n+ * in the headers with their canonical versions using the mailmap mechanism.\n+ */\n+void commit_rewrite_person(struct strbuf *, const char **, struct string_list *);\n+\n /*\n  * Compare split idents for equality or strict ordering. Note that we\n  * compare only the ident part of the line, ignoring any timestamp.\ndiff --git a/ident.c b/ident.c\nindex 89ca5b4700..83007e3e5d 100644\n--- a/ident.c\n+++ b/ident.c\n@@ -8,6 +8,7 @@\n #include \"cache.h\"\n #include \"config.h\"\n #include \"date.h\"\n+#include \"mailmap.h\"\n \n static struct strbuf git_default_name = STRBUF_INIT;\n static struct strbuf git_default_email = STRBUF_INIT;\n@@ -346,6 +347,80 @@ int split_ident_line(struct ident_split *split, const char *line, int len)\n \treturn 0;\n }\n \n+/*\n+ * Returns the difference between the new and old length of the ident line.\n+ */\n+static ssize_t rewrite_ident_line(const char *person, struct strbuf *buf,\n+\t\t\t\t\t\t\t\t  struct string_list *mailmap)\n+{\n+\tchar *endp;\n+\tsize_t len, namelen, maillen;\n+\tconst char *name;\n+\tconst char *mail;\n+\tstruct ident_split ident;\n+\n+\tendp = strchr(person, '\\n');\n+\tif (!endp)\n+\t\treturn 0;\n+\n+\tlen = endp - person;\n+\n+\tif (split_ident_line(&ident, person, len))\n+\t\treturn 0;\n+\n+\tmail = ident.mail_begin;\n+\tmaillen = ident.mail_end - ident.mail_begin;\n+\tname = ident.name_begin;\n+\tnamelen = ident.name_end - ident.name_begin;\n+\n+\tif (map_user(mailmap, &mail, &maillen, &name, &namelen)) {\n+\t\tstruct strbuf namemail = STRBUF_INIT;\n+\t\tsize_t newlen;\n+\n+\t\tstrbuf_addf(&namemail, \"%.*s <%.*s>\",\n+\t\t\t    (int)namelen, name, (int)maillen, mail);\n+\n+\t\tstrbuf_splice(buf, ident.name_begin - buf->buf,\n+\t\t\t      ident.mail_end - ident.name_begin + 1,\n+\t\t\t      namemail.buf, namemail.len);\n+\n+\t\tnewlen = namemail.len;\n+\n+\t\tstrbuf_release(&namemail);\n+\n+\t\treturn newlen - (ident.mail_end - ident.name_begin + 1);\n+\t}\n+\n+\treturn 0;\n+}\n+\n+void commit_rewrite_person(struct strbuf *buf, const char **header,\n+\t\t\t\t\t\t   struct string_list *mailmap)\n+{\n+\tsize_t buf_offset = 0;\n+\n+\tif (!mailmap)\n+\t\treturn;\n+\n+\tfor (;;) {\n+\t\tconst char *person, *line;\n+\t\tsize_t i;\n+\n+\t\tline = buf->buf + buf_offset;\n+\t\tif (!*line || *line == '\\n')\n+\t\t\treturn; /* End of header */\n+\n+\t\tfor (i = 0; header[i]; i++)\n+\t\t\tif (skip_prefix(line, header[i], &person)) {\n+\t\t\t\trewrite_ident_line(person, buf, mailmap);\n+\t\t\t\tbreak;\n+\t\t\t}\n+\n+\t\tbuf_offset = strchrnul(buf->buf + buf_offset, '\\n') - buf->buf;\n+\t\tif (buf->buf[buf_offset] == '\\n')\n+\t\t\t++buf_offset;\n+\t}\n+}\n \n static void ident_env_hint(enum want_ident whose_ident)\n {\ndiff --git a/revision.c b/revision.c\nindex 9909da928e..14dca903b6 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -3755,81 +3755,6 @@ int rewrite_parents(struct rev_info *revs, struct commit *commit,\n \treturn 0;\n }\n \n-/*\n- * Returns the difference between the new and old length of the ident line.\n- */\n-static ssize_t rewrite_ident_line(const char *person, struct strbuf *buf,\n-\t\t\t\t\t\t\t\t  struct string_list *mailmap)\n-{\n-\tchar *endp;\n-\tsize_t len, namelen, maillen;\n-\tconst char *name;\n-\tconst char *mail;\n-\tstruct ident_split ident;\n-\n-\tendp = strchr(person, '\\n');\n-\tif (!endp)\n-\t\treturn 0;\n-\n-\tlen = endp - person;\n-\n-\tif (split_ident_line(&ident, person, len))\n-\t\treturn 0;\n-\n-\tmail = ident.mail_begin;\n-\tmaillen = ident.mail_end - ident.mail_begin;\n-\tname = ident.name_begin;\n-\tnamelen = ident.name_end - ident.name_begin;\n-\n-\tif (map_user(mailmap, &mail, &maillen, &name, &namelen)) {\n-\t\tstruct strbuf namemail = STRBUF_INIT;\n-\t\tsize_t newlen;\n-\n-\t\tstrbuf_addf(&namemail, \"%.*s <%.*s>\",\n-\t\t\t    (int)namelen, name, (int)maillen, mail);\n-\n-\t\tstrbuf_splice(buf, ident.name_begin - buf->buf,\n-\t\t\t      ident.mail_end - ident.name_begin + 1,\n-\t\t\t      namemail.buf, namemail.len);\n-\n-\t\tnewlen = namemail.len;\n-\n-\t\tstrbuf_release(&namemail);\n-\n-\t\treturn newlen - (ident.mail_end - ident.name_begin + 1);\n-\t}\n-\n-\treturn 0;\n-}\n-\n-static void commit_rewrite_person(struct strbuf *buf, const char **header,\n-\t\t\t\t\t\t\t\t  struct string_list *mailmap)\n-{\n-\tsize_t buf_offset = 0;\n-\n-\tif (!mailmap)\n-\t\treturn;\n-\n-\tfor (;;) {\n-\t\tconst char *person, *line;\n-\t\tsize_t i;\n-\n-\t\tline = buf->buf + buf_offset;\n-\t\tif (!*line || *line == '\\n')\n-\t\t\treturn; /* End of header */\n-\n-\t\tfor (i = 0; header[i]; i++)\n-\t\t\tif (skip_prefix(line, header[i], &person)) {\n-\t\t\t\trewrite_ident_line(person, buf, mailmap);\n-\t\t\t\tbreak;\n-\t\t\t}\n-\n-\t\tbuf_offset = strchrnul(buf->buf + buf_offset, '\\n') - buf->buf;\n-\t\tif (buf->buf[buf_offset] == '\\n')\n-\t\t\t++buf_offset;\n-\t}\n-}\n-\n static int commit_match(struct commit *commit, struct rev_info *opt)\n {\n \tint retval;\n-- \n2.37.1.120.g001f220fb8\n\n"},{"id":"459186","messageId":"20220716074055.1786231-4-siddharthasthana31@gmail.com","threadId":"58088","inReplyTo":"20220716074055.1786231-1-siddharthasthana31@gmail.com","subject":"[PATCH v5 3/4] ident: rename commit_rewrite_person() to apply_mailmap_to_header()","fromName":"Siddharth Asthana","fromEmail":"siddharthasthana31@gmail.com","sentAt":"2022-07-16T07:40:54Z","receivedAt":"2022-07-16T07:41:33Z","isPatch":true,"sender":{"key":"siddharthasthana31@gmail.com","avatar":"https://avatars.githubusercontent.com/u/53316982?v=4"},"body":"commit_rewrite_person() takes a commit buffer and replaces the idents\nin the header with their canonical versions using the mailmap mechanism.\nThe name \"commit_rewrite_person()\" is misleading as it doesn't convey\nwhat kind of rewrite are we going to do to the buffer. It also doesn't\nclearly mention that the function will limit itself to the header part\nof the buffer. The new name, \"apply_mailmap_to_header()\", expresses the\nfunctionality of the function pretty clearly.\n\nWe intend to use apply_mailmap_to_header() in git-cat-file to replace\nidents in the headers of commit and tag object buffers. So, we will be\nextending this function to take tag objects buffer as well and replace\nidents on the tagger header using the mailmap mechanism.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: John Cai <johncai86@gmail.com>\nSigned-off-by: Siddharth Asthana <siddharthasthana31@gmail.com>\n---\n cache.h    | 6 +++---\n ident.c    | 4 ++--\n revision.c | 2 +-\n 3 files changed, 6 insertions(+), 6 deletions(-)\n\ndiff --git a/cache.h b/cache.h\nindex 16a08aada2..4aa1bd079d 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -1689,10 +1689,10 @@ struct ident_split {\n int split_ident_line(struct ident_split *, const char *, int);\n \n /*\n- * Given a commit object buffer and the commit headers, replaces the idents\n- * in the headers with their canonical versions using the mailmap mechanism.\n+ * Given a commit or tag object buffer and the commit or tag headers, replaces\n+ * the idents in the headers with their canonical versions using the mailmap mechanism.\n  */\n-void commit_rewrite_person(struct strbuf *, const char **, struct string_list *);\n+void apply_mailmap_to_header(struct strbuf *, const char **, struct string_list *);\n \n /*\n  * Compare split idents for equality or strict ordering. Note that we\ndiff --git a/ident.c b/ident.c\nindex 83007e3e5d..c0f56bc752 100644\n--- a/ident.c\n+++ b/ident.c\n@@ -394,8 +394,8 @@ static ssize_t rewrite_ident_line(const char *person, struct strbuf *buf,\n \treturn 0;\n }\n \n-void commit_rewrite_person(struct strbuf *buf, const char **header,\n-\t\t\t\t\t\t   struct string_list *mailmap)\n+void apply_mailmap_to_header(struct strbuf *buf, const char **header,\n+\t\t\t\t\t\t\t struct string_list *mailmap)\n {\n \tsize_t buf_offset = 0;\n \ndiff --git a/revision.c b/revision.c\nindex 14dca903b6..6ad3665204 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -3792,7 +3792,7 @@ static int commit_match(struct commit *commit, struct rev_info *opt)\n \t\tif (!buf.len)\n \t\t\tstrbuf_addstr(&buf, message);\n \n-\t\tcommit_rewrite_person(&buf, commit_headers, opt->mailmap);\n+\t\tapply_mailmap_to_header(&buf, commit_headers, opt->mailmap);\n \t}\n \n \t/* Append \"fake\" message parts as needed */\n-- \n2.37.1.120.g001f220fb8\n\n"},{"id":"459187","messageId":"20220716074055.1786231-5-siddharthasthana31@gmail.com","threadId":"58088","inReplyTo":"20220716074055.1786231-1-siddharthasthana31@gmail.com","subject":"[PATCH v5 4/4] cat-file: add mailmap support","fromName":"Siddharth Asthana","fromEmail":"siddharthasthana31@gmail.com","sentAt":"2022-07-16T07:40:55Z","receivedAt":"2022-07-16T07:41:38Z","isPatch":true,"sender":{"key":"siddharthasthana31@gmail.com","avatar":"https://avatars.githubusercontent.com/u/53316982?v=4"},"body":"git-cat-file is used by tools like GitLab to get commit tag contents\nthat are then displayed to users. This content which has author,\ncommitter or tagger information, could benefit from passing through the\nmailmap mechanism before being sent or displayed.\n\nThis patch adds --[no-]use-mailmap command line option to the git\ncat-file command. It also adds --[no-]mailmap option as an alias to\n--[no-]use-mailmap.\n\nThis patch also introduces new test cases to test the mailmap mechanism in\ngit cat-file command.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: John Cai <johncai86@gmail.com>\nHelped-by: Phillip Wood <phillip.wood@dunelm.org.uk>\nHelped-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>\nSigned-off-by: Siddharth Asthana <siddharthasthana31@gmail.com>\n---\n Documentation/git-cat-file.txt |  6 ++++\n builtin/cat-file.c             | 43 ++++++++++++++++++++++++-\n t/t4203-mailmap.sh             | 59 ++++++++++++++++++++++++++++++++++\n 3 files changed, 107 insertions(+), 1 deletion(-)\n\ndiff --git a/Documentation/git-cat-file.txt b/Documentation/git-cat-file.txt\nindex 24a811f0ef..1880e9bba1 100644\n--- a/Documentation/git-cat-file.txt\n+++ b/Documentation/git-cat-file.txt\n@@ -63,6 +63,12 @@ OPTIONS\n \tor to ask for a \"blob\" with `<object>` being a tag object that\n \tpoints at it.\n \n+--[no-]mailmap::\n+--[no-]use-mailmap::\n+       Use mailmap file to map author, committer and tagger names\n+       and email addresses to canonical real names and email addresses.\n+       See linkgit:git-shortlog[1].\n+\n --textconv::\n \tShow the content as transformed by a textconv filter. In this case,\n \t`<object>` has to be of the form `<tree-ish>:<path>`, or `:<path>` in\ndiff --git a/builtin/cat-file.c b/builtin/cat-file.c\nindex 50cf38999d..4b68216b51 100644\n--- a/builtin/cat-file.c\n+++ b/builtin/cat-file.c\n@@ -16,6 +16,7 @@\n #include \"packfile.h\"\n #include \"object-store.h\"\n #include \"promisor-remote.h\"\n+#include \"mailmap.h\"\n \n enum batch_mode {\n \tBATCH_MODE_CONTENTS,\n@@ -36,6 +37,22 @@ struct batch_options {\n \n static const char *force_path;\n \n+static struct string_list mailmap = STRING_LIST_INIT_NODUP;\n+static int use_mailmap;\n+\n+static char *replace_idents_using_mailmap(char *, size_t *);\n+\n+static char *replace_idents_using_mailmap(char *object_buf, size_t *size)\n+{\n+\tstruct strbuf sb = STRBUF_INIT;\n+\tconst char *headers[] = { \"author \", \"committer \", \"tagger \", NULL };\n+\n+\tstrbuf_attach(&sb, object_buf, *size, *size + 1);\n+\tapply_mailmap_to_header(&sb, headers, &mailmap);\n+\t*size = sb.len;\n+\treturn strbuf_detach(&sb, NULL);\n+}\n+\n static int filter_object(const char *path, unsigned mode,\n \t\t\t const struct object_id *oid,\n \t\t\t char **buf, unsigned long *size)\n@@ -152,6 +169,12 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,\n \t\tif (!buf)\n \t\t\tdie(\"Cannot read object %s\", obj_name);\n \n+\t\tif (use_mailmap) {\n+\t\t\tsize_t s = size;\n+\t\t\tbuf = replace_idents_using_mailmap(buf, &s);\n+\t\t\tsize = cast_size_t_to_ulong(s);\n+\t\t}\n+\n \t\t/* otherwise just spit out the data */\n \t\tbreak;\n \n@@ -183,6 +206,12 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,\n \t\t}\n \t\tbuf = read_object_with_reference(the_repository, &oid,\n \t\t\t\t\t\t exp_type_id, &size, NULL);\n+\n+\t\tif (use_mailmap) {\n+\t\t\tsize_t s = size;\n+\t\t\tbuf = replace_idents_using_mailmap(buf, &s);\n+\t\t\tsize = cast_size_t_to_ulong(s);\n+\t\t}\n \t\tbreak;\n \t}\n \tdefault:\n@@ -348,11 +377,18 @@ static void print_object_or_die(struct batch_options *opt, struct expand_data *d\n \t\tvoid *contents;\n \n \t\tcontents = read_object_file(oid, &type, &size);\n+\n+\t\tif (use_mailmap) {\n+\t\t\tsize_t s = size;\n+\t\t\tcontents = replace_idents_using_mailmap(contents, &s);\n+\t\t\tsize = cast_size_t_to_ulong(s);\n+\t\t}\n+\n \t\tif (!contents)\n \t\t\tdie(\"object %s disappeared\", oid_to_hex(oid));\n \t\tif (type != data->type)\n \t\t\tdie(\"object %s changed type!?\", oid_to_hex(oid));\n-\t\tif (data->info.sizep && size != data->size)\n+\t\tif (data->info.sizep && size != data->size && !use_mailmap)\n \t\t\tdie(\"object %s changed size!?\", oid_to_hex(oid));\n \n \t\tbatch_write(opt, contents, size);\n@@ -843,6 +879,8 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix)\n \t\tOPT_CMDMODE('s', NULL, &opt, N_(\"show object size\"), 's'),\n \t\tOPT_BOOL(0, \"allow-unknown-type\", &unknown_type,\n \t\t\t  N_(\"allow -s and -t to work with broken/corrupt objects\")),\n+\t\tOPT_BOOL(0, \"use-mailmap\", &use_mailmap, N_(\"use mail map file\")),\n+\t\tOPT_ALIAS(0, \"mailmap\", \"use-mailmap\"),\n \t\t/* Batch mode */\n \t\tOPT_GROUP(N_(\"Batch objects requested on stdin (or --batch-all-objects)\")),\n \t\tOPT_CALLBACK_F(0, \"batch\", &batch, N_(\"format\"),\n@@ -885,6 +923,9 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix)\n \topt_cw = (opt == 'c' || opt == 'w');\n \topt_epts = (opt == 'e' || opt == 'p' || opt == 't' || opt == 's');\n \n+\tif (use_mailmap)\n+\t\tread_mailmap(&mailmap);\n+\n \t/* --batch-all-objects? */\n \tif (opt == 'b')\n \t\tbatch.all_objects = 1;\ndiff --git a/t/t4203-mailmap.sh b/t/t4203-mailmap.sh\nindex 0b2d21ec55..cd1cab3e54 100755\n--- a/t/t4203-mailmap.sh\n+++ b/t/t4203-mailmap.sh\n@@ -963,4 +963,63 @@ test_expect_success SYMLINKS 'symlinks not respected in-tree' '\n \ttest_cmp expect actual\n '\n \n+test_expect_success 'prepare for cat-file --mailmap' '\n+\trm -f .mailmap &&\n+\tgit commit --allow-empty -m foo --author=\"Orig <orig@example.com>\"\n+'\n+\n+test_expect_success '--no-use-mailmap disables mailmap in cat-file' '\n+\ttest_when_finished \"rm .mailmap\" &&\n+\tcat >.mailmap <<-EOF &&\n+\tA U Thor <author@example.com> Orig <orig@example.com>\n+\tEOF\n+\tcat >expect <<-EOF &&\n+\tauthor Orig <orig@example.com>\n+\tEOF\n+\tgit cat-file --no-use-mailmap commit HEAD >log &&\n+\tsed -n \"/^author /s/\\([^>]*>\\).*/\\1/p\" log >actual &&\n+\ttest_cmp expect actual\n+'\n+\n+test_expect_success '--use-mailmap enables mailmap in cat-file' '\n+\ttest_when_finished \"rm .mailmap\" &&\n+\tcat >.mailmap <<-EOF &&\n+\tA U Thor <author@example.com> Orig <orig@example.com>\n+\tEOF\n+\tcat >expect <<-EOF &&\n+\tauthor A U Thor <author@example.com>\n+\tEOF\n+\tgit cat-file --use-mailmap commit HEAD >log &&\n+\tsed -n \"/^author /s/\\([^>]*>\\).*/\\1/p\" log >actual &&\n+\ttest_cmp expect actual\n+'\n+\n+test_expect_success '--no-mailmap disables mailmap in cat-file for annotated tag objects' '\n+\ttest_when_finished \"rm .mailmap\" &&\n+\tcat >.mailmap <<-EOF &&\n+\tOrig <orig@example.com> C O Mitter <committer@example.com>\n+\tEOF\n+\tcat >expect <<-EOF &&\n+\ttagger C O Mitter <committer@example.com>\n+\tEOF\n+\tgit tag -a -m \"annotated tag\" v1 &&\n+\tgit cat-file --no-mailmap -p v1 >log &&\n+\tsed -n \"/^tagger /s/\\([^>]*>\\).*/\\1/p\" log >actual &&\n+\ttest_cmp expect actual\n+'\n+\n+test_expect_success '--mailmap enables mailmap in cat-file for annotated tag objects' '\n+\ttest_when_finished \"rm .mailmap\" &&\n+\tcat >.mailmap <<-EOF &&\n+\tOrig <orig@example.com> C O Mitter <committer@example.com>\n+\tEOF\n+\tcat >expect <<-EOF &&\n+\ttagger Orig <orig@example.com>\n+\tEOF\n+\tgit tag -a -m \"annotated tag\" v2 &&\n+\tgit cat-file --mailmap -p v2 >log &&\n+\tsed -n \"/^tagger /s/\\([^>]*>\\).*/\\1/p\" log >actual &&\n+\ttest_cmp expect actual\n+'\n+\n test_done\n-- \n2.37.1.120.g001f220fb8\n\n"},{"id":"459234","messageId":"xmqqo7xnv17x.fsf@gitster.g","threadId":"58088","inReplyTo":"20220716074055.1786231-2-siddharthasthana31@gmail.com","subject":"Re: [PATCH v5 1/4] revision: improve commit_rewrite_person()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-07-17T22:11:30Z","receivedAt":"2022-07-17T22:11:37Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Siddharth Asthana <siddharthasthana31@gmail.com> writes:\n\n> +/*\n> + * Returns the difference between the new and old length of the ident line.\n> + */\n> +static ssize_t rewrite_ident_line(const char *person, struct strbuf *buf,\n> +\t\t\t\t\t\t\t\t  struct string_list *mailmap)\n\nLine-folding is a good idea, but why do we use such a deep\nindentation?  In this project, tab-width is 8.\n\n> +static void commit_rewrite_person(struct strbuf *buf, const char **header,\n> +\t\t\t\t\t\t\t\t  struct string_list *mailmap)\n\nLikewise.\n\n> +{\n> +\tsize_t buf_offset = 0;\n> +\n> +\tif (!mailmap)\n> +\t\treturn;\n> +\n> +\tfor (;;) {\n> +\t\tconst char *person, *line;\n> +\t\tsize_t i;\n> +\n> +\t\tline = buf->buf + buf_offset;\n> +\t\tif (!*line || *line == '\\n')\n> +\t\t\treturn; /* End of header */\n> +\n> +\t\tfor (i = 0; header[i]; i++)\n> +\t\t\tif (skip_prefix(line, header[i], &person)) {\n> +\t\t\t\trewrite_ident_line(person, buf, mailmap);\n\nIf the return value of rewrite_ident_line() is never used, perhaps\nstop computing the return value in that function and make it return\n\"void\".  I personally thought it was clever to return \"how much does\nthe ident part grew/shrunk?\" from the helper and use it to adjust,\nbut I do not mind to scrap the clever-ness if some folks may find it\nharder to understand.\n\n> +\t\t\t\tbreak;\n> +\t\t\t}\n> +\n> +\t\tbuf_offset = strchrnul(buf->buf + buf_offset, '\\n') - buf->buf;\n\nAnd this is a \"easier-to-understand but need to scan the buffer once\nagain, only to figure out what we ought to already know\" version.\n\n> +\t\tif (buf->buf[buf_offset] == '\\n')\n> +\t\t\t++buf_offset;\n\nPrefer post-increment when there is no reason to favor pre-increment\nover post-increment, i.e. write this as \"buf_offset++\".\n\n> +\t}\n> +}\n> +\n>  static int commit_match(struct commit *commit, struct rev_info *opt)\n>  {\n>  \tint retval;\n> @@ -3832,11 +3862,12 @@ static int commit_match(struct commit *commit, struct rev_info *opt)\n>  \t\tstrbuf_addstr(&buf, message);\n>  \n>  \tif (opt->grep_filter.header_list && opt->mailmap) {\n> +\t\tconst char *commit_headers[] = { \"author \", \"committer \", NULL };\n> +\n>  \t\tif (!buf.len)\n>  \t\t\tstrbuf_addstr(&buf, message);\n>  \n> -\t\tcommit_rewrite_person(&buf, \"\\nauthor \", opt->mailmap);\n> -\t\tcommit_rewrite_person(&buf, \"\\ncommitter \", opt->mailmap);\n> +\t\tcommit_rewrite_person(&buf, commit_headers, opt->mailmap);\n>  \t}\n>  \n>  \t/* Append \"fake\" message parts as needed */\n"},{"id":"459319","messageId":"20220718195102.66321-1-siddharthasthana31@gmail.com","threadId":"58088","inReplyTo":"20220716074055.1786231-1-siddharthasthana31@gmail.com","subject":"[PATCH v6 0/4] Add support for mailmap in cat-file","fromName":"Siddharth Asthana","fromEmail":"siddharthasthana31@gmail.com","sentAt":"2022-07-18T19:50:58Z","receivedAt":"2022-07-18T19:51:18Z","isPatch":true,"sender":{"key":"siddharthasthana31@gmail.com","avatar":"https://avatars.githubusercontent.com/u/53316982?v=4"},"body":"Thanks a lot Junio for your suggestion :) I have made the suggested\nchanges.\n\n= Description\n\nThis patch series adds mailmap support to the git-cat-file command. It\nadds the mailmap support only for the commit and tag objects by\nreplacing the idents for \"author\", \"committer\" and \"tagger\" headers. The\nmailmap only takes effect when --[no-]-use-mailmap or --[no-]-mailmap\noption is passed to the git cat-file command. The changes will work with\nthe batch mode as well.\n\nSo, if one wants to enable mailmap they can use either of the following\ncommands:\n$ git cat-file --use-mailmap -p <object>\n$ git cat-file --use-mailmap <type> <object>\n\nTo use it in the batch mode, one can use the following command:\n$ git cat-file --use-mailmap --batch\n\n= Patch Organization\n\n- The first patch improves the commit_rewrite_person() by restricting it \n  to traverse only through the header part of the commit object buffer.\n  It also adds an argument called headers which the callers can pass. \n  The function will replace idents only on these  passed headers. \n  Thus, the caller won't have to make repeated calls to the function.\n- The second patch moves commit_rewrite_person() to ident.c to expose it\n  as a public function so that it can be used to replace idents in the\n  headers of desired objects.\n- The third patch renames commit_rewrite_person() to a name which\n  describes its functionality clearly. It is renamed to\n  apply_mailmap_to_header().\n- The last patch adds mailmap support to the git cat-file command. It\n  adds the required documentation and tests as well.\n\nChanges in v6:\n- The function rewrite_ident_line() returns the difference between the\n  new and the old length of the ident line. We were not using this\n  information and instead parsing the buffer again to look for the line\n  ending. This patch set starts using that information to update the\n  buf_offset value in commit_rewrite_person().\n- This patch set also tweaks the commit_rewrite_person() so that it is\n  easier to understand and avoids unnecessary parsing of the buffer\n  wherever possible.\n\nSiddharth Asthana (4):\n  revision: improve commit_rewrite_person()\n  ident: move commit_rewrite_person() to ident.c\n  ident: rename commit_rewrite_person() to apply_mailmap_to_header()\n  cat-file: add mailmap support\n\n Documentation/git-cat-file.txt |  6 +++\n builtin/cat-file.c             | 43 +++++++++++++++++++-\n cache.h                        |  6 +++\n ident.c                        | 74 ++++++++++++++++++++++++++++++++++\n revision.c                     | 50 ++---------------------\n t/t4203-mailmap.sh             | 59 +++++++++++++++++++++++++++\n 6 files changed, 190 insertions(+), 48 deletions(-)\n\nRange-diff against v5:\n1:  8c29ad9351 ! 1:  7c086e4c8a revision: improve commit_rewrite_person()\n    @@ revision.c: int rewrite_parents(struct rev_info *revs, struct commit *commit,\n     +/*\n     + * Returns the difference between the new and old length of the ident line.\n     + */\n    -+static ssize_t rewrite_ident_line(const char *person, struct strbuf *buf,\n    -+\t\t\t\t\t\t\t\t  struct string_list *mailmap)\n    ++static ssize_t rewrite_ident_line(const char *person, size_t len,\n    ++\t\t\t\t   struct strbuf *buf,\n    ++\t\t\t\t   struct string_list *mailmap)\n      {\n     -\tchar *person, *endp;\n    -+\tchar *endp;\n    - \tsize_t len, namelen, maillen;\n    +-\tsize_t len, namelen, maillen;\n    ++\tsize_t namelen, maillen;\n      \tconst char *name;\n      \tconst char *mail;\n      \tstruct ident_split ident;\n    @@ revision.c: int rewrite_parents(struct rev_info *revs, struct commit *commit,\n     -\t\treturn 0;\n     -\n     -\tperson += strlen(what);\n    - \tendp = strchr(person, '\\n');\n    - \tif (!endp)\n    +-\tendp = strchr(person, '\\n');\n    +-\tif (!endp)\n    +-\t\treturn 0;\n    +-\n    +-\tlen = endp - person;\n    +-\n    + \tif (split_ident_line(&ident, person, len))\n      \t\treturn 0;\n    + \n     @@ revision.c: static int commit_rewrite_person(struct strbuf *buf, const char *what, struct st\n      \n      \tif (map_user(mailmap, &mail, &maillen, &name, &namelen)) {\n    @@ revision.c: static int commit_rewrite_person(struct strbuf *buf, const char *wha\n      \t\tstrbuf_addf(&namemail, \"%.*s <%.*s>\",\n      \t\t\t    (int)namelen, name, (int)maillen, mail);\n     @@ revision.c: static int commit_rewrite_person(struct strbuf *buf, const char *what, struct st\n    + \t\tstrbuf_splice(buf, ident.name_begin - buf->buf,\n      \t\t\t      ident.mail_end - ident.name_begin + 1,\n      \t\t\t      namemail.buf, namemail.len);\n    - \n     +\t\tnewlen = namemail.len;\n    -+\n    + \n      \t\tstrbuf_release(&namemail);\n      \n     -\t\treturn 1;\n    -+\t\treturn newlen - (ident.mail_end - ident.name_begin + 1);\n    ++\t\treturn newlen - (ident.mail_end - ident.name_begin);\n      \t}\n      \n      \treturn 0;\n      }\n      \n     +static void commit_rewrite_person(struct strbuf *buf, const char **header,\n    -+\t\t\t\t\t\t\t\t  struct string_list *mailmap)\n    ++\t\t\t\t   struct string_list *mailmap)\n     +{\n     +\tsize_t buf_offset = 0;\n     +\n    @@ revision.c: static int commit_rewrite_person(struct strbuf *buf, const char *wha\n     +\tfor (;;) {\n     +\t\tconst char *person, *line;\n     +\t\tsize_t i;\n    ++\t\tint found_header = 0;\n     +\n     +\t\tline = buf->buf + buf_offset;\n     +\t\tif (!*line || *line == '\\n')\n    -+\t\t\treturn; /* End of header */\n    ++\t\t\treturn; /* End of headers */\n     +\n     +\t\tfor (i = 0; header[i]; i++)\n     +\t\t\tif (skip_prefix(line, header[i], &person)) {\n    -+\t\t\t\trewrite_ident_line(person, buf, mailmap);\n    ++\t\t\t\tconst char *endp = strchrnul(person, '\\n');\n    ++\t\t\t\tfound_header = 1;\n    ++\t\t\t\tbuf_offset += endp - line;\n    ++\t\t\t\tbuf_offset += rewrite_ident_line(person, endp - person, buf, mailmap);\n     +\t\t\t\tbreak;\n     +\t\t\t}\n     +\n    -+\t\tbuf_offset = strchrnul(buf->buf + buf_offset, '\\n') - buf->buf;\n    -+\t\tif (buf->buf[buf_offset] == '\\n')\n    -+\t\t\t++buf_offset;\n    ++\t\tif (!found_header) {\n    ++\t\t\tbuf_offset = strchrnul(line, '\\n') - buf->buf;\n    ++\t\t\tif (buf->buf[buf_offset] == '\\n')\n    ++\t\t\t\tbuf_offset++;\n    ++\t\t}\n     +\t}\n     +}\n     +\n2:  ccb7f72fcb ! 2:  2f8fba7f57 ident: move commit_rewrite_person() to ident.c\n    @@ ident.c: int split_ident_line(struct ident_split *split, const char *line, int l\n     +/*\n     + * Returns the difference between the new and old length of the ident line.\n     + */\n    -+static ssize_t rewrite_ident_line(const char *person, struct strbuf *buf,\n    -+\t\t\t\t\t\t\t\t  struct string_list *mailmap)\n    ++static ssize_t rewrite_ident_line(const char *person, size_t len,\n    ++\t\t\t\t   struct strbuf *buf,\n    ++\t\t\t\t   struct string_list *mailmap)\n     +{\n    -+\tchar *endp;\n    -+\tsize_t len, namelen, maillen;\n    ++\tsize_t namelen, maillen;\n     +\tconst char *name;\n     +\tconst char *mail;\n     +\tstruct ident_split ident;\n     +\n    -+\tendp = strchr(person, '\\n');\n    -+\tif (!endp)\n    -+\t\treturn 0;\n    -+\n    -+\tlen = endp - person;\n    -+\n     +\tif (split_ident_line(&ident, person, len))\n     +\t\treturn 0;\n     +\n    @@ ident.c: int split_ident_line(struct ident_split *split, const char *line, int l\n     +\t\tstrbuf_splice(buf, ident.name_begin - buf->buf,\n     +\t\t\t      ident.mail_end - ident.name_begin + 1,\n     +\t\t\t      namemail.buf, namemail.len);\n    -+\n     +\t\tnewlen = namemail.len;\n     +\n     +\t\tstrbuf_release(&namemail);\n     +\n    -+\t\treturn newlen - (ident.mail_end - ident.name_begin + 1);\n    ++\t\treturn newlen - (ident.mail_end - ident.name_begin);\n     +\t}\n     +\n     +\treturn 0;\n     +}\n     +\n     +void commit_rewrite_person(struct strbuf *buf, const char **header,\n    -+\t\t\t\t\t\t   struct string_list *mailmap)\n    ++\t\t\t    struct string_list *mailmap)\n     +{\n     +\tsize_t buf_offset = 0;\n     +\n    @@ ident.c: int split_ident_line(struct ident_split *split, const char *line, int l\n     +\tfor (;;) {\n     +\t\tconst char *person, *line;\n     +\t\tsize_t i;\n    ++\t\tint found_header = 0;\n     +\n     +\t\tline = buf->buf + buf_offset;\n     +\t\tif (!*line || *line == '\\n')\n    -+\t\t\treturn; /* End of header */\n    ++\t\t\treturn; /* End of headers */\n     +\n     +\t\tfor (i = 0; header[i]; i++)\n     +\t\t\tif (skip_prefix(line, header[i], &person)) {\n    -+\t\t\t\trewrite_ident_line(person, buf, mailmap);\n    ++\t\t\t\tconst char *endp = strchrnul(person, '\\n');\n    ++\t\t\t\tfound_header = 1;\n    ++\t\t\t\tbuf_offset += endp - line;\n    ++\t\t\t\tbuf_offset += rewrite_ident_line(person, endp - person, buf, mailmap);\n     +\t\t\t\tbreak;\n     +\t\t\t}\n     +\n    -+\t\tbuf_offset = strchrnul(buf->buf + buf_offset, '\\n') - buf->buf;\n    -+\t\tif (buf->buf[buf_offset] == '\\n')\n    -+\t\t\t++buf_offset;\n    ++\t\tif (!found_header) {\n    ++\t\t\tbuf_offset = strchrnul(line, '\\n') - buf->buf;\n    ++\t\t\tif (buf->buf[buf_offset] == '\\n')\n    ++\t\t\t\tbuf_offset++;\n    ++\t\t}\n     +\t}\n     +}\n      \n    @@ revision.c: int rewrite_parents(struct rev_info *revs, struct commit *commit,\n     -/*\n     - * Returns the difference between the new and old length of the ident line.\n     - */\n    --static ssize_t rewrite_ident_line(const char *person, struct strbuf *buf,\n    --\t\t\t\t\t\t\t\t  struct string_list *mailmap)\n    +-static ssize_t rewrite_ident_line(const char *person, size_t len,\n    +-\t\t\t\t   struct strbuf *buf,\n    +-\t\t\t\t   struct string_list *mailmap)\n     -{\n    --\tchar *endp;\n    --\tsize_t len, namelen, maillen;\n    +-\tsize_t namelen, maillen;\n     -\tconst char *name;\n     -\tconst char *mail;\n     -\tstruct ident_split ident;\n     -\n    --\tendp = strchr(person, '\\n');\n    --\tif (!endp)\n    --\t\treturn 0;\n    --\n    --\tlen = endp - person;\n    --\n     -\tif (split_ident_line(&ident, person, len))\n     -\t\treturn 0;\n     -\n    @@ revision.c: int rewrite_parents(struct rev_info *revs, struct commit *commit,\n     -\t\tstrbuf_splice(buf, ident.name_begin - buf->buf,\n     -\t\t\t      ident.mail_end - ident.name_begin + 1,\n     -\t\t\t      namemail.buf, namemail.len);\n    --\n     -\t\tnewlen = namemail.len;\n     -\n     -\t\tstrbuf_release(&namemail);\n     -\n    --\t\treturn newlen - (ident.mail_end - ident.name_begin + 1);\n    +-\t\treturn newlen - (ident.mail_end - ident.name_begin);\n     -\t}\n     -\n     -\treturn 0;\n     -}\n     -\n     -static void commit_rewrite_person(struct strbuf *buf, const char **header,\n    --\t\t\t\t\t\t\t\t  struct string_list *mailmap)\n    +-\t\t\t\t   struct string_list *mailmap)\n     -{\n     -\tsize_t buf_offset = 0;\n     -\n    @@ revision.c: int rewrite_parents(struct rev_info *revs, struct commit *commit,\n     -\tfor (;;) {\n     -\t\tconst char *person, *line;\n     -\t\tsize_t i;\n    +-\t\tint found_header = 0;\n     -\n     -\t\tline = buf->buf + buf_offset;\n     -\t\tif (!*line || *line == '\\n')\n    --\t\t\treturn; /* End of header */\n    +-\t\t\treturn; /* End of headers */\n     -\n     -\t\tfor (i = 0; header[i]; i++)\n     -\t\t\tif (skip_prefix(line, header[i], &person)) {\n    --\t\t\t\trewrite_ident_line(person, buf, mailmap);\n    +-\t\t\t\tconst char *endp = strchrnul(person, '\\n');\n    +-\t\t\t\tfound_header = 1;\n    +-\t\t\t\tbuf_offset += endp - line;\n    +-\t\t\t\tbuf_offset += rewrite_ident_line(person, endp - person, buf, mailmap);\n     -\t\t\t\tbreak;\n     -\t\t\t}\n     -\n    --\t\tbuf_offset = strchrnul(buf->buf + buf_offset, '\\n') - buf->buf;\n    --\t\tif (buf->buf[buf_offset] == '\\n')\n    --\t\t\t++buf_offset;\n    +-\t\tif (!found_header) {\n    +-\t\t\tbuf_offset = strchrnul(line, '\\n') - buf->buf;\n    +-\t\t\tif (buf->buf[buf_offset] == '\\n')\n    +-\t\t\t\tbuf_offset++;\n    +-\t\t}\n     -\t}\n     -}\n     -\n3:  38c18fd10d ! 3:  b4f2477b14 ident: rename commit_rewrite_person() to apply_mailmap_to_header()\n    @@ cache.h: struct ident_split {\n       * Compare split idents for equality or strict ordering. Note that we\n     \n      ## ident.c ##\n    -@@ ident.c: static ssize_t rewrite_ident_line(const char *person, struct strbuf *buf,\n    +@@ ident.c: static ssize_t rewrite_ident_line(const char *person, size_t len,\n      \treturn 0;\n      }\n      \n     -void commit_rewrite_person(struct strbuf *buf, const char **header,\n    --\t\t\t\t\t\t   struct string_list *mailmap)\n    +-\t\t\t    struct string_list *mailmap)\n     +void apply_mailmap_to_header(struct strbuf *buf, const char **header,\n    -+\t\t\t\t\t\t\t struct string_list *mailmap)\n    ++\t\t\t       struct string_list *mailmap)\n      {\n      \tsize_t buf_offset = 0;\n      \n4:  0a459d4c53 = 4:  63d6f8c201 cat-file: add mailmap support\n-- \n2.37.1.120.g63d6f8c201\n\n"},{"id":"459320","messageId":"20220718195102.66321-2-siddharthasthana31@gmail.com","threadId":"58088","inReplyTo":"20220718195102.66321-1-siddharthasthana31@gmail.com","subject":"[PATCH v6 1/4] revision: improve commit_rewrite_person()","fromName":"Siddharth Asthana","fromEmail":"siddharthasthana31@gmail.com","sentAt":"2022-07-18T19:50:59Z","receivedAt":"2022-07-18T19:51:23Z","isPatch":true,"sender":{"key":"siddharthasthana31@gmail.com","avatar":"https://avatars.githubusercontent.com/u/53316982?v=4"},"body":"The function, commit_rewrite_person(), is designed to find and replace\nan ident string in the header part, and the way it avoids a random\noccurrence of \"author A U Thor <author@example.com\" in the text is by\ninsisting \"author\" to appear at the beginning of line by passing\n\"\\nauthor \" as \"what\".\n\nThe implementation also doesn't make any effort to limit itself to the\ncommit header by locating the blank line that appears after the header\npart and stopping the search there. Also, the interface forces the\ncaller to make multiple calls if it wants to rewrite idents on multiple\nheaders. It shouldn't be the case.\n\nTo support the existing caller better, update commit_rewrite_person()\nto:\n- Make a single pass in the input buffer to locate headers named\n  \"author\" and \"committer\" and replace idents on them.\n- Stop at the end of the header, ensuring that nothing in the body of\n  the commit object is modified.\n\nThe return type of the function commit_rewrite_person() has also been\nchanged from int to void. This has been done because the caller of the\nfunction doesn't do anything with the return value of the function.\n\nBy simplifying the interface of the commit_rewrite_person(), we also\nintend to expose it as a public function. We will also be renaming the\nfunction in a future commit to a different name which clearly tells that\nthe function replaces idents in the header of the commit buffer.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: John Cai <johncai86@gmail.com>\nHelped-by: Đoàn Trần Công Danh <congdanhqx@gmail.com>\nHelped-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>\nSigned-off-by: Siddharth Asthana <siddharthasthana31@gmail.com>\n---\n revision.c | 64 +++++++++++++++++++++++++++++++++++++++---------------\n 1 file changed, 47 insertions(+), 17 deletions(-)\n\ndiff --git a/revision.c b/revision.c\nindex 211352795c..3418a1b7f1 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -3755,25 +3755,18 @@ int rewrite_parents(struct rev_info *revs, struct commit *commit,\n \treturn 0;\n }\n \n-static int commit_rewrite_person(struct strbuf *buf, const char *what, struct string_list *mailmap)\n+/*\n+ * Returns the difference between the new and old length of the ident line.\n+ */\n+static ssize_t rewrite_ident_line(const char *person, size_t len,\n+\t\t\t\t   struct strbuf *buf,\n+\t\t\t\t   struct string_list *mailmap)\n {\n-\tchar *person, *endp;\n-\tsize_t len, namelen, maillen;\n+\tsize_t namelen, maillen;\n \tconst char *name;\n \tconst char *mail;\n \tstruct ident_split ident;\n \n-\tperson = strstr(buf->buf, what);\n-\tif (!person)\n-\t\treturn 0;\n-\n-\tperson += strlen(what);\n-\tendp = strchr(person, '\\n');\n-\tif (!endp)\n-\t\treturn 0;\n-\n-\tlen = endp - person;\n-\n \tif (split_ident_line(&ident, person, len))\n \t\treturn 0;\n \n@@ -3784,6 +3777,7 @@ static int commit_rewrite_person(struct strbuf *buf, const char *what, struct st\n \n \tif (map_user(mailmap, &mail, &maillen, &name, &namelen)) {\n \t\tstruct strbuf namemail = STRBUF_INIT;\n+\t\tsize_t newlen;\n \n \t\tstrbuf_addf(&namemail, \"%.*s <%.*s>\",\n \t\t\t    (int)namelen, name, (int)maillen, mail);\n@@ -3791,15 +3785,50 @@ static int commit_rewrite_person(struct strbuf *buf, const char *what, struct st\n \t\tstrbuf_splice(buf, ident.name_begin - buf->buf,\n \t\t\t      ident.mail_end - ident.name_begin + 1,\n \t\t\t      namemail.buf, namemail.len);\n+\t\tnewlen = namemail.len;\n \n \t\tstrbuf_release(&namemail);\n \n-\t\treturn 1;\n+\t\treturn newlen - (ident.mail_end - ident.name_begin);\n \t}\n \n \treturn 0;\n }\n \n+static void commit_rewrite_person(struct strbuf *buf, const char **header,\n+\t\t\t\t   struct string_list *mailmap)\n+{\n+\tsize_t buf_offset = 0;\n+\n+\tif (!mailmap)\n+\t\treturn;\n+\n+\tfor (;;) {\n+\t\tconst char *person, *line;\n+\t\tsize_t i;\n+\t\tint found_header = 0;\n+\n+\t\tline = buf->buf + buf_offset;\n+\t\tif (!*line || *line == '\\n')\n+\t\t\treturn; /* End of headers */\n+\n+\t\tfor (i = 0; header[i]; i++)\n+\t\t\tif (skip_prefix(line, header[i], &person)) {\n+\t\t\t\tconst char *endp = strchrnul(person, '\\n');\n+\t\t\t\tfound_header = 1;\n+\t\t\t\tbuf_offset += endp - line;\n+\t\t\t\tbuf_offset += rewrite_ident_line(person, endp - person, buf, mailmap);\n+\t\t\t\tbreak;\n+\t\t\t}\n+\n+\t\tif (!found_header) {\n+\t\t\tbuf_offset = strchrnul(line, '\\n') - buf->buf;\n+\t\t\tif (buf->buf[buf_offset] == '\\n')\n+\t\t\t\tbuf_offset++;\n+\t\t}\n+\t}\n+}\n+\n static int commit_match(struct commit *commit, struct rev_info *opt)\n {\n \tint retval;\n@@ -3832,11 +3861,12 @@ static int commit_match(struct commit *commit, struct rev_info *opt)\n \t\tstrbuf_addstr(&buf, message);\n \n \tif (opt->grep_filter.header_list && opt->mailmap) {\n+\t\tconst char *commit_headers[] = { \"author \", \"committer \", NULL };\n+\n \t\tif (!buf.len)\n \t\t\tstrbuf_addstr(&buf, message);\n \n-\t\tcommit_rewrite_person(&buf, \"\\nauthor \", opt->mailmap);\n-\t\tcommit_rewrite_person(&buf, \"\\ncommitter \", opt->mailmap);\n+\t\tcommit_rewrite_person(&buf, commit_headers, opt->mailmap);\n \t}\n \n \t/* Append \"fake\" message parts as needed */\n-- \n2.37.1.120.g63d6f8c201\n\n"},{"id":"459321","messageId":"20220718195102.66321-3-siddharthasthana31@gmail.com","threadId":"58088","inReplyTo":"20220718195102.66321-1-siddharthasthana31@gmail.com","subject":"[PATCH v6 2/4] ident: move commit_rewrite_person() to ident.c","fromName":"Siddharth Asthana","fromEmail":"siddharthasthana31@gmail.com","sentAt":"2022-07-18T19:51:00Z","receivedAt":"2022-07-18T19:51:29Z","isPatch":true,"sender":{"key":"siddharthasthana31@gmail.com","avatar":"https://avatars.githubusercontent.com/u/53316982?v=4"},"body":"commit_rewrite_person() and rewrite_ident_line() are static functions\ndefined in revision.c.\n\nTheir usages are as follows:\n- commit_rewrite_person() takes a commit buffer and replaces the author\n  and committer idents with their canonical versions using the mailmap\n  mechanism\n- rewrite_ident_line() takes author/committer header lines from the\n  commit buffer and replaces the idents with their canonical versions\n  using the mailmap mechanism.\n\nThis patch moves commit_rewrite_person() and rewrite_ident_line() to\nident.c which contains many other functions related to idents like\nsplit_ident_line(). By moving commit_rewrite_person() to ident.c, we\nalso intend to use it in git-cat-file to replace committer and author\nidents from the headers to their canonical versions using the mailmap\nmechanism. The function is moved as is for now to make it clear that\nthere are no other changes, but it will be renamed in a following\ncommit.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: John Cai <johncai86@gmail.com>\nSigned-off-by: Siddharth Asthana <siddharthasthana31@gmail.com>\n---\n cache.h    |  6 +++++\n ident.c    | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++++++\n revision.c | 74 ------------------------------------------------------\n 3 files changed, 80 insertions(+), 74 deletions(-)\n\ndiff --git a/cache.h b/cache.h\nindex ac5ab4ef9d..16a08aada2 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -1688,6 +1688,12 @@ struct ident_split {\n  */\n int split_ident_line(struct ident_split *, const char *, int);\n \n+/*\n+ * Given a commit object buffer and the commit headers, replaces the idents\n+ * in the headers with their canonical versions using the mailmap mechanism.\n+ */\n+void commit_rewrite_person(struct strbuf *, const char **, struct string_list *);\n+\n /*\n  * Compare split idents for equality or strict ordering. Note that we\n  * compare only the ident part of the line, ignoring any timestamp.\ndiff --git a/ident.c b/ident.c\nindex 89ca5b4700..1eee4fd0e3 100644\n--- a/ident.c\n+++ b/ident.c\n@@ -8,6 +8,7 @@\n #include \"cache.h\"\n #include \"config.h\"\n #include \"date.h\"\n+#include \"mailmap.h\"\n \n static struct strbuf git_default_name = STRBUF_INIT;\n static struct strbuf git_default_email = STRBUF_INIT;\n@@ -346,6 +347,79 @@ int split_ident_line(struct ident_split *split, const char *line, int len)\n \treturn 0;\n }\n \n+/*\n+ * Returns the difference between the new and old length of the ident line.\n+ */\n+static ssize_t rewrite_ident_line(const char *person, size_t len,\n+\t\t\t\t   struct strbuf *buf,\n+\t\t\t\t   struct string_list *mailmap)\n+{\n+\tsize_t namelen, maillen;\n+\tconst char *name;\n+\tconst char *mail;\n+\tstruct ident_split ident;\n+\n+\tif (split_ident_line(&ident, person, len))\n+\t\treturn 0;\n+\n+\tmail = ident.mail_begin;\n+\tmaillen = ident.mail_end - ident.mail_begin;\n+\tname = ident.name_begin;\n+\tnamelen = ident.name_end - ident.name_begin;\n+\n+\tif (map_user(mailmap, &mail, &maillen, &name, &namelen)) {\n+\t\tstruct strbuf namemail = STRBUF_INIT;\n+\t\tsize_t newlen;\n+\n+\t\tstrbuf_addf(&namemail, \"%.*s <%.*s>\",\n+\t\t\t    (int)namelen, name, (int)maillen, mail);\n+\n+\t\tstrbuf_splice(buf, ident.name_begin - buf->buf,\n+\t\t\t      ident.mail_end - ident.name_begin + 1,\n+\t\t\t      namemail.buf, namemail.len);\n+\t\tnewlen = namemail.len;\n+\n+\t\tstrbuf_release(&namemail);\n+\n+\t\treturn newlen - (ident.mail_end - ident.name_begin);\n+\t}\n+\n+\treturn 0;\n+}\n+\n+void commit_rewrite_person(struct strbuf *buf, const char **header,\n+\t\t\t    struct string_list *mailmap)\n+{\n+\tsize_t buf_offset = 0;\n+\n+\tif (!mailmap)\n+\t\treturn;\n+\n+\tfor (;;) {\n+\t\tconst char *person, *line;\n+\t\tsize_t i;\n+\t\tint found_header = 0;\n+\n+\t\tline = buf->buf + buf_offset;\n+\t\tif (!*line || *line == '\\n')\n+\t\t\treturn; /* End of headers */\n+\n+\t\tfor (i = 0; header[i]; i++)\n+\t\t\tif (skip_prefix(line, header[i], &person)) {\n+\t\t\t\tconst char *endp = strchrnul(person, '\\n');\n+\t\t\t\tfound_header = 1;\n+\t\t\t\tbuf_offset += endp - line;\n+\t\t\t\tbuf_offset += rewrite_ident_line(person, endp - person, buf, mailmap);\n+\t\t\t\tbreak;\n+\t\t\t}\n+\n+\t\tif (!found_header) {\n+\t\t\tbuf_offset = strchrnul(line, '\\n') - buf->buf;\n+\t\t\tif (buf->buf[buf_offset] == '\\n')\n+\t\t\t\tbuf_offset++;\n+\t\t}\n+\t}\n+}\n \n static void ident_env_hint(enum want_ident whose_ident)\n {\ndiff --git a/revision.c b/revision.c\nindex 3418a1b7f1..14dca903b6 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -3755,80 +3755,6 @@ int rewrite_parents(struct rev_info *revs, struct commit *commit,\n \treturn 0;\n }\n \n-/*\n- * Returns the difference between the new and old length of the ident line.\n- */\n-static ssize_t rewrite_ident_line(const char *person, size_t len,\n-\t\t\t\t   struct strbuf *buf,\n-\t\t\t\t   struct string_list *mailmap)\n-{\n-\tsize_t namelen, maillen;\n-\tconst char *name;\n-\tconst char *mail;\n-\tstruct ident_split ident;\n-\n-\tif (split_ident_line(&ident, person, len))\n-\t\treturn 0;\n-\n-\tmail = ident.mail_begin;\n-\tmaillen = ident.mail_end - ident.mail_begin;\n-\tname = ident.name_begin;\n-\tnamelen = ident.name_end - ident.name_begin;\n-\n-\tif (map_user(mailmap, &mail, &maillen, &name, &namelen)) {\n-\t\tstruct strbuf namemail = STRBUF_INIT;\n-\t\tsize_t newlen;\n-\n-\t\tstrbuf_addf(&namemail, \"%.*s <%.*s>\",\n-\t\t\t    (int)namelen, name, (int)maillen, mail);\n-\n-\t\tstrbuf_splice(buf, ident.name_begin - buf->buf,\n-\t\t\t      ident.mail_end - ident.name_begin + 1,\n-\t\t\t      namemail.buf, namemail.len);\n-\t\tnewlen = namemail.len;\n-\n-\t\tstrbuf_release(&namemail);\n-\n-\t\treturn newlen - (ident.mail_end - ident.name_begin);\n-\t}\n-\n-\treturn 0;\n-}\n-\n-static void commit_rewrite_person(struct strbuf *buf, const char **header,\n-\t\t\t\t   struct string_list *mailmap)\n-{\n-\tsize_t buf_offset = 0;\n-\n-\tif (!mailmap)\n-\t\treturn;\n-\n-\tfor (;;) {\n-\t\tconst char *person, *line;\n-\t\tsize_t i;\n-\t\tint found_header = 0;\n-\n-\t\tline = buf->buf + buf_offset;\n-\t\tif (!*line || *line == '\\n')\n-\t\t\treturn; /* End of headers */\n-\n-\t\tfor (i = 0; header[i]; i++)\n-\t\t\tif (skip_prefix(line, header[i], &person)) {\n-\t\t\t\tconst char *endp = strchrnul(person, '\\n');\n-\t\t\t\tfound_header = 1;\n-\t\t\t\tbuf_offset += endp - line;\n-\t\t\t\tbuf_offset += rewrite_ident_line(person, endp - person, buf, mailmap);\n-\t\t\t\tbreak;\n-\t\t\t}\n-\n-\t\tif (!found_header) {\n-\t\t\tbuf_offset = strchrnul(line, '\\n') - buf->buf;\n-\t\t\tif (buf->buf[buf_offset] == '\\n')\n-\t\t\t\tbuf_offset++;\n-\t\t}\n-\t}\n-}\n-\n static int commit_match(struct commit *commit, struct rev_info *opt)\n {\n \tint retval;\n-- \n2.37.1.120.g63d6f8c201\n\n"},{"id":"459322","messageId":"20220718195102.66321-4-siddharthasthana31@gmail.com","threadId":"58088","inReplyTo":"20220718195102.66321-1-siddharthasthana31@gmail.com","subject":"[PATCH v6 3/4] ident: rename commit_rewrite_person() to apply_mailmap_to_header()","fromName":"Siddharth Asthana","fromEmail":"siddharthasthana31@gmail.com","sentAt":"2022-07-18T19:51:01Z","receivedAt":"2022-07-18T19:51:46Z","isPatch":true,"sender":{"key":"siddharthasthana31@gmail.com","avatar":"https://avatars.githubusercontent.com/u/53316982?v=4"},"body":"commit_rewrite_person() takes a commit buffer and replaces the idents\nin the header with their canonical versions using the mailmap mechanism.\nThe name \"commit_rewrite_person()\" is misleading as it doesn't convey\nwhat kind of rewrite are we going to do to the buffer. It also doesn't\nclearly mention that the function will limit itself to the header part\nof the buffer. The new name, \"apply_mailmap_to_header()\", expresses the\nfunctionality of the function pretty clearly.\n\nWe intend to use apply_mailmap_to_header() in git-cat-file to replace\nidents in the headers of commit and tag object buffers. So, we will be\nextending this function to take tag objects buffer as well and replace\nidents on the tagger header using the mailmap mechanism.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: John Cai <johncai86@gmail.com>\nSigned-off-by: Siddharth Asthana <siddharthasthana31@gmail.com>\n---\n cache.h    | 6 +++---\n ident.c    | 4 ++--\n revision.c | 2 +-\n 3 files changed, 6 insertions(+), 6 deletions(-)\n\ndiff --git a/cache.h b/cache.h\nindex 16a08aada2..4aa1bd079d 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -1689,10 +1689,10 @@ struct ident_split {\n int split_ident_line(struct ident_split *, const char *, int);\n \n /*\n- * Given a commit object buffer and the commit headers, replaces the idents\n- * in the headers with their canonical versions using the mailmap mechanism.\n+ * Given a commit or tag object buffer and the commit or tag headers, replaces\n+ * the idents in the headers with their canonical versions using the mailmap mechanism.\n  */\n-void commit_rewrite_person(struct strbuf *, const char **, struct string_list *);\n+void apply_mailmap_to_header(struct strbuf *, const char **, struct string_list *);\n \n /*\n  * Compare split idents for equality or strict ordering. Note that we\ndiff --git a/ident.c b/ident.c\nindex 1eee4fd0e3..7f66beda42 100644\n--- a/ident.c\n+++ b/ident.c\n@@ -387,8 +387,8 @@ static ssize_t rewrite_ident_line(const char *person, size_t len,\n \treturn 0;\n }\n \n-void commit_rewrite_person(struct strbuf *buf, const char **header,\n-\t\t\t    struct string_list *mailmap)\n+void apply_mailmap_to_header(struct strbuf *buf, const char **header,\n+\t\t\t       struct string_list *mailmap)\n {\n \tsize_t buf_offset = 0;\n \ndiff --git a/revision.c b/revision.c\nindex 14dca903b6..6ad3665204 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -3792,7 +3792,7 @@ static int commit_match(struct commit *commit, struct rev_info *opt)\n \t\tif (!buf.len)\n \t\t\tstrbuf_addstr(&buf, message);\n \n-\t\tcommit_rewrite_person(&buf, commit_headers, opt->mailmap);\n+\t\tapply_mailmap_to_header(&buf, commit_headers, opt->mailmap);\n \t}\n \n \t/* Append \"fake\" message parts as needed */\n-- \n2.37.1.120.g63d6f8c201\n\n"},{"id":"459323","messageId":"20220718195102.66321-5-siddharthasthana31@gmail.com","threadId":"58088","inReplyTo":"20220718195102.66321-1-siddharthasthana31@gmail.com","subject":"[PATCH v6 4/4] cat-file: add mailmap support","fromName":"Siddharth Asthana","fromEmail":"siddharthasthana31@gmail.com","sentAt":"2022-07-18T19:51:02Z","receivedAt":"2022-07-18T19:51:48Z","isPatch":true,"sender":{"key":"siddharthasthana31@gmail.com","avatar":"https://avatars.githubusercontent.com/u/53316982?v=4"},"body":"git-cat-file is used by tools like GitLab to get commit tag contents\nthat are then displayed to users. This content which has author,\ncommitter or tagger information, could benefit from passing through the\nmailmap mechanism before being sent or displayed.\n\nThis patch adds --[no-]use-mailmap command line option to the git\ncat-file command. It also adds --[no-]mailmap option as an alias to\n--[no-]use-mailmap.\n\nThis patch also introduces new test cases to test the mailmap mechanism in\ngit cat-file command.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: John Cai <johncai86@gmail.com>\nHelped-by: Phillip Wood <phillip.wood@dunelm.org.uk>\nHelped-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>\nSigned-off-by: Siddharth Asthana <siddharthasthana31@gmail.com>\n---\n Documentation/git-cat-file.txt |  6 ++++\n builtin/cat-file.c             | 43 ++++++++++++++++++++++++-\n t/t4203-mailmap.sh             | 59 ++++++++++++++++++++++++++++++++++\n 3 files changed, 107 insertions(+), 1 deletion(-)\n\ndiff --git a/Documentation/git-cat-file.txt b/Documentation/git-cat-file.txt\nindex 24a811f0ef..1880e9bba1 100644\n--- a/Documentation/git-cat-file.txt\n+++ b/Documentation/git-cat-file.txt\n@@ -63,6 +63,12 @@ OPTIONS\n \tor to ask for a \"blob\" with `<object>` being a tag object that\n \tpoints at it.\n \n+--[no-]mailmap::\n+--[no-]use-mailmap::\n+       Use mailmap file to map author, committer and tagger names\n+       and email addresses to canonical real names and email addresses.\n+       See linkgit:git-shortlog[1].\n+\n --textconv::\n \tShow the content as transformed by a textconv filter. In this case,\n \t`<object>` has to be of the form `<tree-ish>:<path>`, or `:<path>` in\ndiff --git a/builtin/cat-file.c b/builtin/cat-file.c\nindex 50cf38999d..4b68216b51 100644\n--- a/builtin/cat-file.c\n+++ b/builtin/cat-file.c\n@@ -16,6 +16,7 @@\n #include \"packfile.h\"\n #include \"object-store.h\"\n #include \"promisor-remote.h\"\n+#include \"mailmap.h\"\n \n enum batch_mode {\n \tBATCH_MODE_CONTENTS,\n@@ -36,6 +37,22 @@ struct batch_options {\n \n static const char *force_path;\n \n+static struct string_list mailmap = STRING_LIST_INIT_NODUP;\n+static int use_mailmap;\n+\n+static char *replace_idents_using_mailmap(char *, size_t *);\n+\n+static char *replace_idents_using_mailmap(char *object_buf, size_t *size)\n+{\n+\tstruct strbuf sb = STRBUF_INIT;\n+\tconst char *headers[] = { \"author \", \"committer \", \"tagger \", NULL };\n+\n+\tstrbuf_attach(&sb, object_buf, *size, *size + 1);\n+\tapply_mailmap_to_header(&sb, headers, &mailmap);\n+\t*size = sb.len;\n+\treturn strbuf_detach(&sb, NULL);\n+}\n+\n static int filter_object(const char *path, unsigned mode,\n \t\t\t const struct object_id *oid,\n \t\t\t char **buf, unsigned long *size)\n@@ -152,6 +169,12 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,\n \t\tif (!buf)\n \t\t\tdie(\"Cannot read object %s\", obj_name);\n \n+\t\tif (use_mailmap) {\n+\t\t\tsize_t s = size;\n+\t\t\tbuf = replace_idents_using_mailmap(buf, &s);\n+\t\t\tsize = cast_size_t_to_ulong(s);\n+\t\t}\n+\n \t\t/* otherwise just spit out the data */\n \t\tbreak;\n \n@@ -183,6 +206,12 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,\n \t\t}\n \t\tbuf = read_object_with_reference(the_repository, &oid,\n \t\t\t\t\t\t exp_type_id, &size, NULL);\n+\n+\t\tif (use_mailmap) {\n+\t\t\tsize_t s = size;\n+\t\t\tbuf = replace_idents_using_mailmap(buf, &s);\n+\t\t\tsize = cast_size_t_to_ulong(s);\n+\t\t}\n \t\tbreak;\n \t}\n \tdefault:\n@@ -348,11 +377,18 @@ static void print_object_or_die(struct batch_options *opt, struct expand_data *d\n \t\tvoid *contents;\n \n \t\tcontents = read_object_file(oid, &type, &size);\n+\n+\t\tif (use_mailmap) {\n+\t\t\tsize_t s = size;\n+\t\t\tcontents = replace_idents_using_mailmap(contents, &s);\n+\t\t\tsize = cast_size_t_to_ulong(s);\n+\t\t}\n+\n \t\tif (!contents)\n \t\t\tdie(\"object %s disappeared\", oid_to_hex(oid));\n \t\tif (type != data->type)\n \t\t\tdie(\"object %s changed type!?\", oid_to_hex(oid));\n-\t\tif (data->info.sizep && size != data->size)\n+\t\tif (data->info.sizep && size != data->size && !use_mailmap)\n \t\t\tdie(\"object %s changed size!?\", oid_to_hex(oid));\n \n \t\tbatch_write(opt, contents, size);\n@@ -843,6 +879,8 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix)\n \t\tOPT_CMDMODE('s', NULL, &opt, N_(\"show object size\"), 's'),\n \t\tOPT_BOOL(0, \"allow-unknown-type\", &unknown_type,\n \t\t\t  N_(\"allow -s and -t to work with broken/corrupt objects\")),\n+\t\tOPT_BOOL(0, \"use-mailmap\", &use_mailmap, N_(\"use mail map file\")),\n+\t\tOPT_ALIAS(0, \"mailmap\", \"use-mailmap\"),\n \t\t/* Batch mode */\n \t\tOPT_GROUP(N_(\"Batch objects requested on stdin (or --batch-all-objects)\")),\n \t\tOPT_CALLBACK_F(0, \"batch\", &batch, N_(\"format\"),\n@@ -885,6 +923,9 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix)\n \topt_cw = (opt == 'c' || opt == 'w');\n \topt_epts = (opt == 'e' || opt == 'p' || opt == 't' || opt == 's');\n \n+\tif (use_mailmap)\n+\t\tread_mailmap(&mailmap);\n+\n \t/* --batch-all-objects? */\n \tif (opt == 'b')\n \t\tbatch.all_objects = 1;\ndiff --git a/t/t4203-mailmap.sh b/t/t4203-mailmap.sh\nindex 0b2d21ec55..cd1cab3e54 100755\n--- a/t/t4203-mailmap.sh\n+++ b/t/t4203-mailmap.sh\n@@ -963,4 +963,63 @@ test_expect_success SYMLINKS 'symlinks not respected in-tree' '\n \ttest_cmp expect actual\n '\n \n+test_expect_success 'prepare for cat-file --mailmap' '\n+\trm -f .mailmap &&\n+\tgit commit --allow-empty -m foo --author=\"Orig <orig@example.com>\"\n+'\n+\n+test_expect_success '--no-use-mailmap disables mailmap in cat-file' '\n+\ttest_when_finished \"rm .mailmap\" &&\n+\tcat >.mailmap <<-EOF &&\n+\tA U Thor <author@example.com> Orig <orig@example.com>\n+\tEOF\n+\tcat >expect <<-EOF &&\n+\tauthor Orig <orig@example.com>\n+\tEOF\n+\tgit cat-file --no-use-mailmap commit HEAD >log &&\n+\tsed -n \"/^author /s/\\([^>]*>\\).*/\\1/p\" log >actual &&\n+\ttest_cmp expect actual\n+'\n+\n+test_expect_success '--use-mailmap enables mailmap in cat-file' '\n+\ttest_when_finished \"rm .mailmap\" &&\n+\tcat >.mailmap <<-EOF &&\n+\tA U Thor <author@example.com> Orig <orig@example.com>\n+\tEOF\n+\tcat >expect <<-EOF &&\n+\tauthor A U Thor <author@example.com>\n+\tEOF\n+\tgit cat-file --use-mailmap commit HEAD >log &&\n+\tsed -n \"/^author /s/\\([^>]*>\\).*/\\1/p\" log >actual &&\n+\ttest_cmp expect actual\n+'\n+\n+test_expect_success '--no-mailmap disables mailmap in cat-file for annotated tag objects' '\n+\ttest_when_finished \"rm .mailmap\" &&\n+\tcat >.mailmap <<-EOF &&\n+\tOrig <orig@example.com> C O Mitter <committer@example.com>\n+\tEOF\n+\tcat >expect <<-EOF &&\n+\ttagger C O Mitter <committer@example.com>\n+\tEOF\n+\tgit tag -a -m \"annotated tag\" v1 &&\n+\tgit cat-file --no-mailmap -p v1 >log &&\n+\tsed -n \"/^tagger /s/\\([^>]*>\\).*/\\1/p\" log >actual &&\n+\ttest_cmp expect actual\n+'\n+\n+test_expect_success '--mailmap enables mailmap in cat-file for annotated tag objects' '\n+\ttest_when_finished \"rm .mailmap\" &&\n+\tcat >.mailmap <<-EOF &&\n+\tOrig <orig@example.com> C O Mitter <committer@example.com>\n+\tEOF\n+\tcat >expect <<-EOF &&\n+\ttagger Orig <orig@example.com>\n+\tEOF\n+\tgit tag -a -m \"annotated tag\" v2 &&\n+\tgit cat-file --mailmap -p v2 >log &&\n+\tsed -n \"/^tagger /s/\\([^>]*>\\).*/\\1/p\" log >actual &&\n+\ttest_cmp expect actual\n+'\n+\n test_done\n-- \n2.37.1.120.g63d6f8c201\n\n"},{"id":"459904","messageId":"xmqqpmht3tq1.fsf@gitster.g","threadId":"58088","inReplyTo":"20220718195102.66321-1-siddharthasthana31@gmail.com","subject":"Re: [PATCH v6 0/4] Add support for mailmap in cat-file","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-07-25T18:58:14Z","receivedAt":"2022-07-25T18:58:21Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Siddharth Asthana <siddharthasthana31@gmail.com> writes:\n\n> Changes in v6:\n> - The function rewrite_ident_line() returns the difference between the\n>   new and the old length of the ident line. We were not using this\n>   information and instead parsing the buffer again to look for the line\n>   ending. This patch set starts using that information to update the\n>   buf_offset value in commit_rewrite_person().\n> - This patch set also tweaks the commit_rewrite_person() so that it is\n>   easier to understand and avoids unnecessary parsing of the buffer\n>   wherever possible.\n>\n> Siddharth Asthana (4):\n>   revision: improve commit_rewrite_person()\n>   ident: move commit_rewrite_person() to ident.c\n>   ident: rename commit_rewrite_person() to apply_mailmap_to_header()\n>   cat-file: add mailmap support\n>\n>  Documentation/git-cat-file.txt |  6 +++\n>  builtin/cat-file.c             | 43 +++++++++++++++++++-\n>  cache.h                        |  6 +++\n>  ident.c                        | 74 ++++++++++++++++++++++++++++++++++\n>  revision.c                     | 50 ++---------------------\n>  t/t4203-mailmap.sh             | 59 +++++++++++++++++++++++++++\n>  6 files changed, 190 insertions(+), 48 deletions(-)\n\nI haven't seen any comments or objections to this round.  Are people\nhappy about it going forward?  I am planning to merge it to 'next'\nand down to 'master' soonish.\n\nThanks.\n"},{"id":"460141","messageId":"CAP8UFD0U8hQ+gyN1=7M4oYEhX6=z_1LS4JaLjqdPG52BELRqtg@mail.gmail.com","threadId":"58088","inReplyTo":"xmqqpmht3tq1.fsf@gitster.g","subject":"Re: [PATCH v6 0/4] Add support for mailmap in cat-file","fromName":"Christian Couder","fromEmail":"christian.couder@gmail.com","sentAt":"2022-07-28T19:07:28Z","receivedAt":"2022-07-28T19:07:43Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"On Mon, Jul 25, 2022 at 8:58 PM Junio C Hamano <gitster@pobox.com> wrote:\n> Siddharth Asthana <siddharthasthana31@gmail.com> writes:\n>\n> > Changes in v6:\n> > - The function rewrite_ident_line() returns the difference between the\n> >   new and the old length of the ident line. We were not using this\n> >   information and instead parsing the buffer again to look for the line\n> >   ending. This patch set starts using that information to update the\n> >   buf_offset value in commit_rewrite_person().\n> > - This patch set also tweaks the commit_rewrite_person() so that it is\n> >   easier to understand and avoids unnecessary parsing of the buffer\n> >   wherever possible.\n> >\n> > Siddharth Asthana (4):\n> >   revision: improve commit_rewrite_person()\n> >   ident: move commit_rewrite_person() to ident.c\n> >   ident: rename commit_rewrite_person() to apply_mailmap_to_header()\n> >   cat-file: add mailmap support\n> >\n> >  Documentation/git-cat-file.txt |  6 +++\n> >  builtin/cat-file.c             | 43 +++++++++++++++++++-\n> >  cache.h                        |  6 +++\n> >  ident.c                        | 74 ++++++++++++++++++++++++++++++++++\n> >  revision.c                     | 50 ++---------------------\n> >  t/t4203-mailmap.sh             | 59 +++++++++++++++++++++++++++\n> >  6 files changed, 190 insertions(+), 48 deletions(-)\n>\n> I haven't seen any comments or objections to this round.  Are people\n> happy about it going forward?  I am planning to merge it to 'next'\n> and down to 'master' soonish.\n\nI am biased, but I am happy with the current state of this patch\nseries. During the last versions of this patch series there were only\ncomments related to the first patch in the series (revision: improve\ncommit_rewrite_person()). It seems to me that they were all properly\ntaken into account, and that the code in that patch is now correct and\nrelatively simple to understand.\n\nThanks,\nChristian.\n"},{"id":"460143","messageId":"xmqqh731av9f.fsf@gitster.g","threadId":"58088","inReplyTo":"CAP8UFD0U8hQ+gyN1=7M4oYEhX6=z_1LS4JaLjqdPG52BELRqtg@mail.gmail.com","subject":"Re: [PATCH v6 0/4] Add support for mailmap in cat-file","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-07-28T19:32:12Z","receivedAt":"2022-07-28T19:32:20Z","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> On Mon, Jul 25, 2022 at 8:58 PM Junio C Hamano <gitster@pobox.com> wrote:\n>> Siddharth Asthana <siddharthasthana31@gmail.com> writes:\n>>\n>> > Changes in v6:\n>> > - The function rewrite_ident_line() returns the difference between the\n>> >   new and the old length of the ident line. We were not using this\n>> >   information and instead parsing the buffer again to look for the line\n>> >   ending. This patch set starts using that information to update the\n>> >   buf_offset value in commit_rewrite_person().\n>> > - This patch set also tweaks the commit_rewrite_person() so that it is\n>> >   easier to understand and avoids unnecessary parsing of the buffer\n>> >   wherever possible.\n>> >\n>> > Siddharth Asthana (4):\n>> >   revision: improve commit_rewrite_person()\n>> >   ident: move commit_rewrite_person() to ident.c\n>> >   ident: rename commit_rewrite_person() to apply_mailmap_to_header()\n>> >   cat-file: add mailmap support\n>> >\n>> >  Documentation/git-cat-file.txt |  6 +++\n>> >  builtin/cat-file.c             | 43 +++++++++++++++++++-\n>> >  cache.h                        |  6 +++\n>> >  ident.c                        | 74 ++++++++++++++++++++++++++++++++++\n>> >  revision.c                     | 50 ++---------------------\n>> >  t/t4203-mailmap.sh             | 59 +++++++++++++++++++++++++++\n>> >  6 files changed, 190 insertions(+), 48 deletions(-)\n>>\n>> I haven't seen any comments or objections to this round.  Are people\n>> happy about it going forward?  I am planning to merge it to 'next'\n>> and down to 'master' soonish.\n>\n> I am biased, but I am happy with the current state of this patch\n> series. During the last versions of this patch series there were only\n> comments related to the first patch in the series (revision: improve\n> commit_rewrite_person()). It seems to me that they were all properly\n> taken into account, and that the code in that patch is now correct and\n> relatively simple to understand.\n\nThanks, let's move it forward.\n"},{"id":"460301","messageId":"1396d611-970f-d11a-ac35-3bf7d03469d8@gmail.com","threadId":"58088","inReplyTo":"xmqqh731av9f.fsf@gitster.g","subject":"Re: [PATCH v6 0/4] Add support for mailmap in cat-file","fromName":"Siddharth Asthana","fromEmail":"siddharthasthana31@gmail.com","sentAt":"2022-07-30T07:50:49Z","receivedAt":"2022-07-30T07:52:22Z","isPatch":true,"sender":{"key":"siddharthasthana31@gmail.com","avatar":"https://avatars.githubusercontent.com/u/53316982?v=4"},"body":"\n\nOn 29/07/22 01:02, Junio C Hamano wrote:\n> Christian Couder <christian.couder@gmail.com> writes:\n> \n>> On Mon, Jul 25, 2022 at 8:58 PM Junio C Hamano <gitster@pobox.com> wrote:\n>>> Siddharth Asthana <siddharthasthana31@gmail.com> writes:\n>>>\n>>>> Changes in v6:\n>>>> - The function rewrite_ident_line() returns the difference between the\n>>>>    new and the old length of the ident line. We were not using this\n>>>>    information and instead parsing the buffer again to look for the line\n>>>>    ending. This patch set starts using that information to update the\n>>>>    buf_offset value in commit_rewrite_person().\n>>>> - This patch set also tweaks the commit_rewrite_person() so that it is\n>>>>    easier to understand and avoids unnecessary parsing of the buffer\n>>>>    wherever possible.\n>>>>\n>>>> Siddharth Asthana (4):\n>>>>    revision: improve commit_rewrite_person()\n>>>>    ident: move commit_rewrite_person() to ident.c\n>>>>    ident: rename commit_rewrite_person() to apply_mailmap_to_header()\n>>>>    cat-file: add mailmap support\n>>>>\n>>>>   Documentation/git-cat-file.txt |  6 +++\n>>>>   builtin/cat-file.c             | 43 +++++++++++++++++++-\n>>>>   cache.h                        |  6 +++\n>>>>   ident.c                        | 74 ++++++++++++++++++++++++++++++++++\n>>>>   revision.c                     | 50 ++---------------------\n>>>>   t/t4203-mailmap.sh             | 59 +++++++++++++++++++++++++++\n>>>>   6 files changed, 190 insertions(+), 48 deletions(-)\n>>>\n>>> I haven't seen any comments or objections to this round.  Are people\n>>> happy about it going forward?  I am planning to merge it to 'next'\n>>> and down to 'master' soonish.\n>>\n>> I am biased, but I am happy with the current state of this patch\n>> series. During the last versions of this patch series there were only\n>> comments related to the first patch in the series (revision: improve\n>> commit_rewrite_person()). It seems to me that they were all properly\n>> taken into account, and that the code in that patch is now correct and\n>> relatively simple to understand.\n> \n> Thanks, let's move it forward.\nThanks a lot Junio, Phillip, Đoàn, Ævar, Johannes, Christian and John \nfor helping me with the reviews and making this patch better. Thanks a \nlot for accepting it :)\n"}]}