* [PATCH v1 1/1] cat-file: add use-mailmap/no-use-mailmap to --batch-command
@ 2026-03-28 20:36 Siddharth Asthana
2026-03-29 0:50 ` Junio C Hamano
2026-03-29 8:28 ` [PATCH v2 0/1] cat-file: add mailmap subcommand " Siddharth Asthana
0 siblings, 2 replies; 27+ messages in thread
From: Siddharth Asthana @ 2026-03-28 20:36 UTC (permalink / raw)
To: git; +Cc: karthik.188, christian.couder, ps, gitster, toon,
Siddharth Asthana
git-cat-file(1)'s --batch-command works with the --use-mailmap option,
but this option needs to be set when the process is created. This means
we cannot change this option mid-operation.
At GitLab, Gitaly caches git-cat-file processes and it would be useful
if --batch-command supported toggling mailmap dynamically with existing
processes.
Add `use-mailmap` and `no-use-mailmap` as new subcommands to
--batch-command. `use-mailmap` enables the mailmap mechanism for
subsequent `contents` and `info` commands, lazily loading the mailmap
data from disk on first invocation. `no-use-mailmap` disables it but
keeps the data in memory so re-enabling doesn't require reloading.
The subcommand names mirror the existing --use-mailmap/--no-use-mailmap
CLI options to keep the interface consistent.
Signed-off-by: Siddharth Asthana <siddharthasthana31@gmail.com>
---
CI: https://gitlab.com/gitlab-org/git/-/pipelines/2415084557
Documentation/git-cat-file.adoc | 9 +++++++
builtin/cat-file.c | 33 ++++++++++++++++++++---
t/t4203-mailmap.sh | 48 +++++++++++++++++++++++++++++++++
3 files changed, 86 insertions(+), 4 deletions(-)
diff --git a/Documentation/git-cat-file.adoc b/Documentation/git-cat-file.adoc
index c139f55a16..03aadbbe89 100644
--- a/Documentation/git-cat-file.adoc
+++ b/Documentation/git-cat-file.adoc
@@ -174,6 +174,15 @@ flush::
since the beginning or since the last flush was issued. When `--buffer`
is used, no output will come until a `flush` is issued. When `--buffer`
is not used, commands are flushed each time without issuing `flush`.
+
+use-mailmap::
+ Enable mailmap for subsequent `contents` and `info` commands. If the
+ mailmap has not been loaded yet, it is read from disk at this point.
+
+no-use-mailmap::
+ Disable mailmap for subsequent `contents` and `info` commands. The
+ mailmap data is kept in memory so that a later `use-mailmap` command
+ does not need to reload it from disk.
--
+
diff --git a/builtin/cat-file.c b/builtin/cat-file.c
index b6f12f41d6..7772d4d41b 100644
--- a/builtin/cat-file.c
+++ b/builtin/cat-file.c
@@ -54,6 +54,7 @@ static const char *force_path;
static struct string_list mailmap = STRING_LIST_INIT_NODUP;
static int use_mailmap;
+static int mailmap_loaded;
static char *replace_idents_using_mailmap(char *, size_t *);
@@ -692,6 +693,26 @@ static void parse_cmd_info(struct batch_options *opt,
batch_one_object(line, output, opt, data);
}
+static void parse_cmd_use_mailmap(struct batch_options *opt UNUSED,
+ const char *line UNUSED,
+ struct strbuf *output UNUSED,
+ struct expand_data *data UNUSED)
+{
+ if (!mailmap_loaded) {
+ read_mailmap(the_repository, &mailmap);
+ mailmap_loaded = 1;
+ }
+ use_mailmap = 1;
+}
+
+static void parse_cmd_disable_mailmap(struct batch_options *opt UNUSED,
+ const char *line UNUSED,
+ struct strbuf *output UNUSED,
+ struct expand_data *data UNUSED)
+{
+ use_mailmap = 0;
+}
+
static void dispatch_calls(struct batch_options *opt,
struct strbuf *output,
struct expand_data *data,
@@ -725,9 +746,11 @@ static const struct parse_cmd {
parse_cmd_fn_t fn;
unsigned takes_args;
} commands[] = {
- { "contents", parse_cmd_contents, 1},
- { "info", parse_cmd_info, 1},
- { "flush", NULL, 0},
+ { "contents", parse_cmd_contents, 1 },
+ { "info", parse_cmd_info, 1 },
+ { "flush", NULL, 0 },
+ { "use-mailmap", parse_cmd_use_mailmap, 0 },
+ { "no-use-mailmap", parse_cmd_disable_mailmap, 0 },
};
static void batch_objects_command(struct batch_options *opt,
@@ -1127,8 +1150,10 @@ int cmd_cat_file(int argc,
opt_cw = (opt == 'c' || opt == 'w');
opt_epts = (opt == 'e' || opt == 'p' || opt == 't' || opt == 's');
- if (use_mailmap)
+ if (use_mailmap) {
read_mailmap(the_repository, &mailmap);
+ mailmap_loaded = 1;
+ }
switch (batch.objects_filter.choice) {
case LOFC_DISABLED:
diff --git a/t/t4203-mailmap.sh b/t/t4203-mailmap.sh
index 74b7ddccb2..2ae063e5c3 100755
--- a/t/t4203-mailmap.sh
+++ b/t/t4203-mailmap.sh
@@ -1133,6 +1133,54 @@ test_expect_success 'git cat-file --batch-command returns correct size with --us
test_cmp expect actual
'
+test_expect_success 'git cat-file --batch-command use-mailmap enables mailmap mid-stream' '
+ test_when_finished "rm .mailmap" &&
+ cat >.mailmap <<-\EOF &&
+ C O Mitter <committer@example.com> Orig <orig@example.com>
+ EOF
+ commit_sha=$(git rev-parse HEAD) &&
+ git cat-file commit HEAD >commit_no_mailmap.out &&
+ git cat-file --use-mailmap commit HEAD >commit_mailmap.out &&
+ size_no_mailmap=$(wc -c <commit_no_mailmap.out) &&
+ size_mailmap=$(wc -c <commit_mailmap.out) &&
+ printf "info HEAD\nuse-mailmap\ninfo HEAD\n" | git cat-file --batch-command >actual &&
+ echo $commit_sha commit $size_no_mailmap >expect &&
+ echo $commit_sha commit $size_mailmap >>expect &&
+ test_cmp expect actual
+'
+
+test_expect_success 'git cat-file --batch-command no-use-mailmap disables mailmap mid-stream' '
+ test_when_finished "rm .mailmap" &&
+ cat >.mailmap <<-\EOF &&
+ C O Mitter <committer@example.com> Orig <orig@example.com>
+ EOF
+ commit_sha=$(git rev-parse HEAD) &&
+ git cat-file commit HEAD >commit_no_mailmap.out &&
+ git cat-file --use-mailmap commit HEAD >commit_mailmap.out &&
+ size_no_mailmap=$(wc -c <commit_no_mailmap.out) &&
+ size_mailmap=$(wc -c <commit_mailmap.out) &&
+ printf "use-mailmap\ninfo HEAD\nno-use-mailmap\ninfo HEAD\n" | git cat-file --batch-command >actual &&
+ echo $commit_sha commit $size_mailmap >expect &&
+ echo $commit_sha commit $size_no_mailmap >>expect &&
+ test_cmp expect actual
+'
+
+test_expect_success 'git cat-file --batch-command use-mailmap works in --buffer mode' '
+ test_when_finished "rm .mailmap" &&
+ cat >.mailmap <<-\EOF &&
+ C O Mitter <committer@example.com> Orig <orig@example.com>
+ EOF
+ commit_sha=$(git rev-parse HEAD) &&
+ git cat-file commit HEAD >commit_no_mailmap.out &&
+ git cat-file --use-mailmap commit HEAD >commit_mailmap.out &&
+ size_no_mailmap=$(wc -c <commit_no_mailmap.out) &&
+ size_mailmap=$(wc -c <commit_mailmap.out) &&
+ printf "use-mailmap\ninfo HEAD\nno-use-mailmap\ninfo HEAD\nflush\n" | git cat-file --batch-command --buffer >actual &&
+ echo $commit_sha commit $size_mailmap >expect &&
+ echo $commit_sha commit $size_no_mailmap >>expect &&
+ test_cmp expect actual
+'
+
test_expect_success 'git cat-file --mailmap works with different author and committer' '
test_when_finished "rm .mailmap" &&
cat >.mailmap <<-\EOF &&
--
2.51.0
^ permalink raw reply related [flat|nested] 27+ messages in thread
* Re: [PATCH v1 1/1] cat-file: add use-mailmap/no-use-mailmap to --batch-command
2026-03-28 20:36 [PATCH v1 1/1] cat-file: add use-mailmap/no-use-mailmap to --batch-command Siddharth Asthana
@ 2026-03-29 0:50 ` Junio C Hamano
2026-03-29 7:25 ` Siddharth Asthana
2026-03-29 8:28 ` [PATCH v2 0/1] cat-file: add mailmap subcommand " Siddharth Asthana
1 sibling, 1 reply; 27+ messages in thread
From: Junio C Hamano @ 2026-03-29 0:50 UTC (permalink / raw)
To: Siddharth Asthana; +Cc: git, karthik.188, christian.couder, ps, toon
Siddharth Asthana <siddharthasthana31@gmail.com> writes:
> git-cat-file(1)'s --batch-command works with the --use-mailmap option,
> but this option needs to be set when the process is created. This means
> we cannot change this option mid-operation.
>
> At GitLab, Gitaly caches git-cat-file processes and it would be useful
> if --batch-command supported toggling mailmap dynamically with existing
> processes.
>
> Add `use-mailmap` and `no-use-mailmap` as new subcommands to
> --batch-command. `use-mailmap` enables the mailmap mechanism for
> subsequent `contents` and `info` commands, lazily loading the mailmap
> data from disk on first invocation. `no-use-mailmap` disables it but
> keeps the data in memory so re-enabling doesn't require reloading.
And the cached information in process, if any, would be flushed?
Because in your design, these command words are parsed separately
from and have nothing in common with the command line options, I
wonder if it is easier to understand if you added just a single
command, "mailmap", that takes a single parameter "yes" or "no"?
Then this hunk would ...
> + { "contents", parse_cmd_contents, 1 },
> + { "info", parse_cmd_info, 1 },
> + { "flush", NULL, 0 },
> + { "use-mailmap", parse_cmd_use_mailmap, 0 },
> + { "no-use-mailmap", parse_cmd_disable_mailmap, 0 },
... need only one addition instead of two entries and you do not
have to write boilerplate-rich helper functions twice.
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH v1 1/1] cat-file: add use-mailmap/no-use-mailmap to --batch-command
2026-03-29 0:50 ` Junio C Hamano
@ 2026-03-29 7:25 ` Siddharth Asthana
2026-03-29 20:55 ` Junio C Hamano
0 siblings, 1 reply; 27+ messages in thread
From: Siddharth Asthana @ 2026-03-29 7:25 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git, karthik.188, christian.couder, ps, toon
On 29/03/26 06:20, Junio C Hamano wrote:
> Siddharth Asthana <siddharthasthana31@gmail.com> writes:
>
>> git-cat-file(1)'s --batch-command works with the --use-mailmap option,
>> but this option needs to be set when the process is created. This means
>> we cannot change this option mid-operation.
>>
>> At GitLab, Gitaly caches git-cat-file processes and it would be useful
>> if --batch-command supported toggling mailmap dynamically with existing
>> processes.
>>
>> Add `use-mailmap` and `no-use-mailmap` as new subcommands to
>> --batch-command. `use-mailmap` enables the mailmap mechanism for
>> subsequent `contents` and `info` commands, lazily loading the mailmap
>> data from disk on first invocation. `no-use-mailmap` disables it but
>> keeps the data in memory so re-enabling doesn't require reloading.
>
> And the cached information in process, if any, would be flushed?
No. The mailmap data is kept in memory. Turning it off only disables
application of mailmap; turning it back on reuses already loaded data.
>
> Because in your design, these command words are parsed separately
> from and have nothing in common with the command line options, I
> wonder if it is easier to understand if you added just a single
> command, "mailmap", that takes a single parameter "yes" or "no"?
Agreed, this is cleaner.
I will rerolled this as a single `mailmap` subcommand with `yes|no`, so
the dispatch table has one entry and the handling is in one function
I'll send v2 with this update.
Thanks,
Siddharth
> Then this hunk would ...
>
>> + { "contents", parse_cmd_contents, 1 },
>> + { "info", parse_cmd_info, 1 },
>> + { "flush", NULL, 0 },
>> + { "use-mailmap", parse_cmd_use_mailmap, 0 },
>> + { "no-use-mailmap", parse_cmd_disable_mailmap, 0 },
>
> ... need only one addition instead of two entries and you do not
> have to write boilerplate-rich helper functions twice.
^ permalink raw reply [flat|nested] 27+ messages in thread
* [PATCH v2 0/1] cat-file: add mailmap subcommand to --batch-command
2026-03-28 20:36 [PATCH v1 1/1] cat-file: add use-mailmap/no-use-mailmap to --batch-command Siddharth Asthana
2026-03-29 0:50 ` Junio C Hamano
@ 2026-03-29 8:28 ` Siddharth Asthana
2026-03-29 8:28 ` [PATCH v2 1/1] " Siddharth Asthana
2026-03-31 12:11 ` [PATCH v3 0/1] " Siddharth Asthana
1 sibling, 2 replies; 27+ messages in thread
From: Siddharth Asthana @ 2026-03-29 8:28 UTC (permalink / raw)
To: git; +Cc: karthik.188, christian.couder, ps, gitster, toon,
Siddharth Asthana
git-cat-file(1)'s --batch-command works with the --use-mailmap option,
but this option needs to be set when the process is created. This means
we cannot change this option mid-operation.
At GitLab, Gitaly caches git-cat-file processes and it would be useful
if --batch-command supported toggling mailmap dynamically with existing
processes.
This patch adds a `mailmap` subcommand to --batch-command that takes
`yes` or `no` as its argument. When enabled, mailmap data is loaded from
disk on first use and kept in memory so that toggling back on does not
require reloading.
The series is based on top of 5361983c07 (The 22nd batch, 2026-03-21).
CI: https://gitlab.com/gitlab-org/git/-/pipelines/2416081861
Changes in v2:
- Replace two separate `use-mailmap` / `no-use-mailmap` zero-argument
subcommands with a single `mailmap` subcommand that takes `yes` or
`no` as its argument. This reduces the dispatch
table to one entry and the implementation to one function.
- Link to v1: https://public-inbox.org/git/a4ec7bfa-f16b-4505-9b37-d3dd137e93cb@gmail.com/T/#m5c62fb6ad0fbcc99a706dba4c78b66359c247acd
Thanks,
Siddharth
---
Siddharth Asthana (1):
cat-file: add mailmap subcommand to --batch-command
Documentation/git-cat-file.adoc | 7 +++++
builtin/cat-file.c | 30 ++++++++++++++++++---
t/t4203-mailmap.sh | 48 +++++++++++++++++++++++++++++++++
3 files changed, 81 insertions(+), 4 deletions(-)
Range-diff versus v1:
1: 39f40e9cb7 ! 1: 936ca27419 cat-file: add use-mailmap/no-use-mailmap to --batch-command
@@ Metadata
Author: Siddharth Asthana <siddharthasthana31@gmail.com>
## Commit message ##
- cat-file: add use-mailmap/no-use-mailmap to --batch-command
+ cat-file: add mailmap subcommand to --batch-command
git-cat-file(1)'s --batch-command works with the --use-mailmap option,
but this option needs to be set when the process is created. This means
@@ Commit message
if --batch-command supported toggling mailmap dynamically with existing
processes.
- Add `use-mailmap` and `no-use-mailmap` as new subcommands to
- --batch-command. `use-mailmap` enables the mailmap mechanism for
- subsequent `contents` and `info` commands, lazily loading the mailmap
- data from disk on first invocation. `no-use-mailmap` disables it but
- keeps the data in memory so re-enabling doesn't require reloading.
-
- The subcommand names mirror the existing --use-mailmap/--no-use-mailmap
- CLI options to keep the interface consistent.
+ Add a `mailmap` subcommand to --batch-command that takes a single
+ argument: `yes` to enable mailmap and `no` to disable it. When enabled,
+ mailmap data is loaded from disk on first use and kept in memory so that
+ toggling back on does not require reloading.
+ Suggested-by: Junio C Hamano <gitster@pobox.com>
Signed-off-by: Siddharth Asthana <siddharthasthana31@gmail.com>
@@ Documentation/git-cat-file.adoc: flush::
is used, no output will come until a `flush` is issued. When `--buffer`
is not used, commands are flushed each time without issuing `flush`.
+
-+use-mailmap::
-+ Enable mailmap for subsequent `contents` and `info` commands. If the
-+ mailmap has not been loaded yet, it is read from disk at this point.
-+
-+no-use-mailmap::
-+ Disable mailmap for subsequent `contents` and `info` commands. The
-+ mailmap data is kept in memory so that a later `use-mailmap` command
-+ does not need to reload it from disk.
++mailmap <yes|no>::
++ Enable or disable mailmap for subsequent `contents` and `info`
++ commands. When `yes` is given, mailmap data is loaded from disk on
++ first use and kept in memory; passing `yes` again does not reload it.
++ When `no` is given, mailmap is disabled but the data stays in memory
++ so that a later `mailmap yes` does not need to reload it from disk.
--
@@ builtin/cat-file.c: static void parse_cmd_info(struct batch_options *opt,
batch_one_object(line, output, opt, data);
}
-+static void parse_cmd_use_mailmap(struct batch_options *opt UNUSED,
-+ const char *line UNUSED,
-+ struct strbuf *output UNUSED,
-+ struct expand_data *data UNUSED)
++static void parse_cmd_mailmap(struct batch_options *opt UNUSED,
++ const char *line,
++ struct strbuf *output UNUSED,
++ struct expand_data *data UNUSED)
+{
-+ if (!mailmap_loaded) {
-+ read_mailmap(the_repository, &mailmap);
-+ mailmap_loaded = 1;
++ if (!strcmp(line, "yes")) {
++ if (!mailmap_loaded) {
++ read_mailmap(the_repository, &mailmap);
++ mailmap_loaded = 1;
++ }
++ use_mailmap = 1;
++ } else if (!strcmp(line, "no")) {
++ use_mailmap = 0;
++ } else {
++ die(_("mailmap: unknown argument '%s', expected 'yes' or 'no'"), line);
+ }
-+ use_mailmap = 1;
-+}
-+
-+static void parse_cmd_disable_mailmap(struct batch_options *opt UNUSED,
-+ const char *line UNUSED,
-+ struct strbuf *output UNUSED,
-+ struct expand_data *data UNUSED)
-+{
-+ use_mailmap = 0;
+}
@@ builtin/cat-file.c: static const struct parse_cmd {
+ { "contents", parse_cmd_contents, 1 },
+ { "info", parse_cmd_info, 1 },
+ { "flush", NULL, 0 },
-+ { "use-mailmap", parse_cmd_use_mailmap, 0 },
-+ { "no-use-mailmap", parse_cmd_disable_mailmap, 0 },
++ { "mailmap", parse_cmd_mailmap, 1 },
};
@@ t/t4203-mailmap.sh: test_expect_success 'git cat-file --batch-command returns co
-+test_expect_success 'git cat-file --batch-command use-mailmap enables mailmap mid-stream' '
++test_expect_success 'git cat-file --batch-command mailmap yes enables mailmap mid-stream' '
+ ...
-+ printf "info HEAD\nuse-mailmap\ninfo HEAD\n" | git cat-file --batch-command >actual &&
++ printf "info HEAD\nmailmap yes\ninfo HEAD\n" | git cat-file --batch-command >actual &&
-+test_expect_success 'git cat-file --batch-command no-use-mailmap disables mailmap mid-stream' '
++test_expect_success 'git cat-file --batch-command mailmap no disables mailmap mid-stream' '
+ ...
-+ printf "use-mailmap\ninfo HEAD\nno-use-mailmap\ninfo HEAD\n" | git cat-file --batch-command >actual &&
++ printf "mailmap yes\ninfo HEAD\nmailmap no\ninfo HEAD\n" | git cat-file --batch-command >actual &&
-+test_expect_success 'git cat-file --batch-command use-mailmap works in --buffer mode' '
++test_expect_success 'git cat-file --batch-command mailmap works in --buffer mode' '
+ ...
-+ printf "use-mailmap\ninfo HEAD\nno-use-mailmap\ninfo HEAD\nflush\n" | git cat-file --batch-command --buffer >actual &&
++ printf "mailmap yes\ninfo HEAD\nmailmap no\ninfo HEAD\nflush\n" | git cat-file --batch-command --buffer >actual &&
base-commit: 5361983c075154725be47b65cca9a2421789e410
--
2.51.0
^ permalink raw reply [flat|nested] 27+ messages in thread
* [PATCH v2 1/1] cat-file: add mailmap subcommand to --batch-command
2026-03-29 8:28 ` [PATCH v2 0/1] cat-file: add mailmap subcommand " Siddharth Asthana
@ 2026-03-29 8:28 ` Siddharth Asthana
2026-03-30 2:12 ` Junio C Hamano
` (3 more replies)
2026-03-31 12:11 ` [PATCH v3 0/1] " Siddharth Asthana
1 sibling, 4 replies; 27+ messages in thread
From: Siddharth Asthana @ 2026-03-29 8:28 UTC (permalink / raw)
To: git; +Cc: karthik.188, christian.couder, ps, gitster, toon,
Siddharth Asthana
git-cat-file(1)'s --batch-command works with the --use-mailmap option,
but this option needs to be set when the process is created. This means
we cannot change this option mid-operation.
At GitLab, Gitaly caches git-cat-file processes and it would be useful
if --batch-command supported toggling mailmap dynamically with existing
processes.
Add a `mailmap` subcommand to --batch-command that takes a single
argument: `yes` to enable mailmap and `no` to disable it. When enabled,
mailmap data is loaded from disk on first use and kept in memory so that
toggling back on does not require reloading.
Suggested-by: Junio C Hamano <gitster@pobox.com>
Signed-off-by: Siddharth Asthana <siddharthasthana31@gmail.com>
---
CI: https://gitlab.com/gitlab-org/git/-/pipelines/2416081861
Documentation/git-cat-file.adoc | 7 +++++
builtin/cat-file.c | 30 ++++++++++++++++++---
t/t4203-mailmap.sh | 48 +++++++++++++++++++++++++++++++++
3 files changed, 81 insertions(+), 4 deletions(-)
diff --git a/Documentation/git-cat-file.adoc b/Documentation/git-cat-file.adoc
index c139f55a16..af32e929a8 100644
--- a/Documentation/git-cat-file.adoc
+++ b/Documentation/git-cat-file.adoc
@@ -174,6 +174,13 @@ flush::
since the beginning or since the last flush was issued. When `--buffer`
is used, no output will come until a `flush` is issued. When `--buffer`
is not used, commands are flushed each time without issuing `flush`.
+
+mailmap <yes|no>::
+ Enable or disable mailmap for subsequent `contents` and `info`
+ commands. When `yes` is given, mailmap data is loaded from disk on
+ first use and kept in memory; passing `yes` again does not reload it.
+ When `no` is given, mailmap is disabled but the data stays in memory
+ so that a later `mailmap yes` does not need to reload it from disk.
--
+
diff --git a/builtin/cat-file.c b/builtin/cat-file.c
index b6f12f41d6..a53926d2bb 100644
--- a/builtin/cat-file.c
+++ b/builtin/cat-file.c
@@ -54,6 +54,7 @@ static const char *force_path;
static struct string_list mailmap = STRING_LIST_INIT_NODUP;
static int use_mailmap;
+static int mailmap_loaded;
static char *replace_idents_using_mailmap(char *, size_t *);
@@ -692,6 +693,24 @@ static void parse_cmd_info(struct batch_options *opt,
batch_one_object(line, output, opt, data);
}
+static void parse_cmd_mailmap(struct batch_options *opt UNUSED,
+ const char *line,
+ struct strbuf *output UNUSED,
+ struct expand_data *data UNUSED)
+{
+ if (!strcmp(line, "yes")) {
+ if (!mailmap_loaded) {
+ read_mailmap(the_repository, &mailmap);
+ mailmap_loaded = 1;
+ }
+ use_mailmap = 1;
+ } else if (!strcmp(line, "no")) {
+ use_mailmap = 0;
+ } else {
+ die(_("mailmap: unknown argument '%s', expected 'yes' or 'no'"), line);
+ }
+}
+
static void dispatch_calls(struct batch_options *opt,
struct strbuf *output,
struct expand_data *data,
@@ -725,9 +744,10 @@ static const struct parse_cmd {
parse_cmd_fn_t fn;
unsigned takes_args;
} commands[] = {
- { "contents", parse_cmd_contents, 1},
- { "info", parse_cmd_info, 1},
- { "flush", NULL, 0},
+ { "contents", parse_cmd_contents, 1 },
+ { "info", parse_cmd_info, 1 },
+ { "flush", NULL, 0 },
+ { "mailmap", parse_cmd_mailmap, 1 },
};
static void batch_objects_command(struct batch_options *opt,
@@ -1127,8 +1147,10 @@ int cmd_cat_file(int argc,
opt_cw = (opt == 'c' || opt == 'w');
opt_epts = (opt == 'e' || opt == 'p' || opt == 't' || opt == 's');
- if (use_mailmap)
+ if (use_mailmap) {
read_mailmap(the_repository, &mailmap);
+ mailmap_loaded = 1;
+ }
switch (batch.objects_filter.choice) {
case LOFC_DISABLED:
diff --git a/t/t4203-mailmap.sh b/t/t4203-mailmap.sh
index 74b7ddccb2..f66637cd86 100755
--- a/t/t4203-mailmap.sh
+++ b/t/t4203-mailmap.sh
@@ -1133,6 +1133,54 @@ test_expect_success 'git cat-file --batch-command returns correct size with --us
test_cmp expect actual
'
+test_expect_success 'git cat-file --batch-command mailmap yes enables mailmap mid-stream' '
+ test_when_finished "rm .mailmap" &&
+ cat >.mailmap <<-\EOF &&
+ C O Mitter <committer@example.com> Orig <orig@example.com>
+ EOF
+ commit_sha=$(git rev-parse HEAD) &&
+ git cat-file commit HEAD >commit_no_mailmap.out &&
+ git cat-file --use-mailmap commit HEAD >commit_mailmap.out &&
+ size_no_mailmap=$(wc -c <commit_no_mailmap.out) &&
+ size_mailmap=$(wc -c <commit_mailmap.out) &&
+ printf "info HEAD\nmailmap yes\ninfo HEAD\n" | git cat-file --batch-command >actual &&
+ echo $commit_sha commit $size_no_mailmap >expect &&
+ echo $commit_sha commit $size_mailmap >>expect &&
+ test_cmp expect actual
+'
+
+test_expect_success 'git cat-file --batch-command mailmap no disables mailmap mid-stream' '
+ test_when_finished "rm .mailmap" &&
+ cat >.mailmap <<-\EOF &&
+ C O Mitter <committer@example.com> Orig <orig@example.com>
+ EOF
+ commit_sha=$(git rev-parse HEAD) &&
+ git cat-file commit HEAD >commit_no_mailmap.out &&
+ git cat-file --use-mailmap commit HEAD >commit_mailmap.out &&
+ size_no_mailmap=$(wc -c <commit_no_mailmap.out) &&
+ size_mailmap=$(wc -c <commit_mailmap.out) &&
+ printf "mailmap yes\ninfo HEAD\nmailmap no\ninfo HEAD\n" | git cat-file --batch-command >actual &&
+ echo $commit_sha commit $size_mailmap >expect &&
+ echo $commit_sha commit $size_no_mailmap >>expect &&
+ test_cmp expect actual
+'
+
+test_expect_success 'git cat-file --batch-command mailmap works in --buffer mode' '
+ test_when_finished "rm .mailmap" &&
+ cat >.mailmap <<-\EOF &&
+ C O Mitter <committer@example.com> Orig <orig@example.com>
+ EOF
+ commit_sha=$(git rev-parse HEAD) &&
+ git cat-file commit HEAD >commit_no_mailmap.out &&
+ git cat-file --use-mailmap commit HEAD >commit_mailmap.out &&
+ size_no_mailmap=$(wc -c <commit_no_mailmap.out) &&
+ size_mailmap=$(wc -c <commit_mailmap.out) &&
+ printf "mailmap yes\ninfo HEAD\nmailmap no\ninfo HEAD\nflush\n" | git cat-file --batch-command --buffer >actual &&
+ echo $commit_sha commit $size_mailmap >expect &&
+ echo $commit_sha commit $size_no_mailmap >>expect &&
+ test_cmp expect actual
+'
+
test_expect_success 'git cat-file --mailmap works with different author and committer' '
test_when_finished "rm .mailmap" &&
cat >.mailmap <<-\EOF &&
--
2.51.0
^ permalink raw reply related [flat|nested] 27+ messages in thread
* Re: [PATCH v1 1/1] cat-file: add use-mailmap/no-use-mailmap to --batch-command
2026-03-29 7:25 ` Siddharth Asthana
@ 2026-03-29 20:55 ` Junio C Hamano
0 siblings, 0 replies; 27+ messages in thread
From: Junio C Hamano @ 2026-03-29 20:55 UTC (permalink / raw)
To: Siddharth Asthana; +Cc: git, karthik.188, christian.couder, ps, toon
Siddharth Asthana <siddharthasthana31@gmail.com> writes:
>> And the cached information in process, if any, would be flushed?
>
> No. The mailmap data is kept in memory. Turning it off only disables
> application of mailmap; turning it back on reuses already loaded data.
I was asking if the rewritten commmit objects were kept around in
memory and how long; after you show an object once with mapped
author data, toggled the mailmap use, and then try to show the same
object again, you would want to avoid reusing the mapped result
again.
But it turns out that the command, with or without your patch, reads
the object data and maps the author/commit in it every time an
object is requested. In fact, in a bad case, I think it calls
replace_idents_using_mailmap() twice, once in batch_object_write()
only to grab the size of the munged object, then again in
print_object_or_die() for both contents and the size.
So there is no "tainted data retained across the mode switch"
problem.
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH v2 1/1] cat-file: add mailmap subcommand to --batch-command
2026-03-29 8:28 ` [PATCH v2 1/1] " Siddharth Asthana
@ 2026-03-30 2:12 ` Junio C Hamano
2026-03-31 1:40 ` Siddharth Asthana
2026-03-30 9:44 ` Karthik Nayak
` (2 subsequent siblings)
3 siblings, 1 reply; 27+ messages in thread
From: Junio C Hamano @ 2026-03-30 2:12 UTC (permalink / raw)
To: Siddharth Asthana; +Cc: git, karthik.188, christian.couder, ps, toon
Siddharth Asthana <siddharthasthana31@gmail.com> writes:
> git-cat-file(1)'s --batch-command works with the --use-mailmap option,
> but this option needs to be set when the process is created. This means
> we cannot change this option mid-operation.
>
> At GitLab, Gitaly caches git-cat-file processes and it would be useful
Would "keeps interacting with a single 'cat-file' process" be more
accurate than "caches"? The latter gives, at least to me,
connotations that may not be necessarily true, like (1) there is a
pool of cat-file processes waiting for Gitaly to connect and serve,
(2) a running Gitaly may decide to disconnect from cat-file from
time to time, and then reconnect to one of them when it becomes
necessary again, etc.
> if --batch-command supported toggling mailmap dynamically with existing
> processes.
>
> Add a `mailmap` subcommand to --batch-command that takes a single
> argument: `yes` to enable mailmap and `no` to disable it. When enabled,
> mailmap data is loaded from disk on first use and kept in memory so that
> toggling back on does not require reloading.
>
> Suggested-by: Junio C Hamano <gitster@pobox.com>
This is over-crediting me. The idea to unify the two commands into
one may have come from me, but that is at most helped-by but it is
perfectly fine without any credit.
> Signed-off-by: Siddharth Asthana <siddharthasthana31@gmail.com>
> ---
> diff --git a/builtin/cat-file.c b/builtin/cat-file.c
> index b6f12f41d6..a53926d2bb 100644
> --- a/builtin/cat-file.c
> +++ b/builtin/cat-file.c
> @@ -54,6 +54,7 @@ static const char *force_path;
>
> static struct string_list mailmap = STRING_LIST_INIT_NODUP;
> static int use_mailmap;
> +static int mailmap_loaded;
Not part of this topic, but in case less experienced developers who
are watching from the sidelines wonder if we want to add this
file-scope global variable, this is perfectly fine. Anything under
builtin/foo.c are meant to serve a single command "git foo" and does
not benefit from "let's sift globals into classes that belong to
different concepts in the system; most of which will be per
repository, so make them some part of the repository object"
movement as much as more library-ish parts of the system.
Until a specific command starts working on multiple repositories at
one time, that is.
> @@ -692,6 +693,24 @@ static void parse_cmd_info(struct batch_options *opt,
> batch_one_object(line, output, opt, data);
> }
>
> +static void parse_cmd_mailmap(struct batch_options *opt UNUSED,
> + const char *line,
> + struct strbuf *output UNUSED,
> + struct expand_data *data UNUSED)
> +{
> + if (!strcmp(line, "yes")) {
> + if (!mailmap_loaded) {
> + read_mailmap(the_repository, &mailmap);
> + mailmap_loaded = 1;
> + }
> + use_mailmap = 1;
> + } else if (!strcmp(line, "no")) {
> + use_mailmap = 0;
> + } else {
> + die(_("mailmap: unknown argument '%s', expected 'yes' or 'no'"), line);
> + }
> +}
OK.
> @@ -725,9 +744,10 @@ static const struct parse_cmd {
> parse_cmd_fn_t fn;
> unsigned takes_args;
> } commands[] = {
> - { "contents", parse_cmd_contents, 1},
> - { "info", parse_cmd_info, 1},
> - { "flush", NULL, 0},
> + { "contents", parse_cmd_contents, 1 },
> + { "info", parse_cmd_info, 1 },
> + { "flush", NULL, 0 },
> + { "mailmap", parse_cmd_mailmap, 1 },
> };
Mixing style fixes to existing entries in the same patch that adds a
new feature by adding a new entry to the table is annoying than
having a preliminary clean-up patch that only fixes style and then
the main patch that adds the feature.
> static void batch_objects_command(struct batch_options *opt,
> @@ -1127,8 +1147,10 @@ int cmd_cat_file(int argc,
> opt_cw = (opt == 'c' || opt == 'w');
> opt_epts = (opt == 'e' || opt == 'p' || opt == 't' || opt == 's');
>
> - if (use_mailmap)
> + if (use_mailmap) {
> read_mailmap(the_repository, &mailmap);
> + mailmap_loaded = 1;
> + }
Hmph, interesting. Two points.
* It would make it easier to follow if these two lines are made
into a small helper function to be called from here and from the
"parse_cmd_mailmap()"?
* Can we somehow make mailmap object itself slightly smarter so
that it knows if it has already been asked to read the data from
its sources? It is a pretty dumb string_list, but from a cursory
read of the code flow, it seems that mailmap.strdup_strings is
initialized to be false in builtin/cat-file.c and then one of the
first things done in mailmap.c::read_mailmap() is to flip that
bit on, so the "yes" part of the parse_cmd_mailmap() might become
if (yes)
load_mailmap();
with the helper load_mailmap() that may look like:
static void load_mailmap(void)
{
if (mailmap.strdup_strings)
return; /* we know read_mailmap() flips it on */
read_mailmap(the_repository, &mailmap);
}
The first bullet point to introduce a small common helper will
help hiding such an ugly implementation detail there.
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH v2 1/1] cat-file: add mailmap subcommand to --batch-command
2026-03-29 8:28 ` [PATCH v2 1/1] " Siddharth Asthana
2026-03-30 2:12 ` Junio C Hamano
@ 2026-03-30 9:44 ` Karthik Nayak
2026-03-31 1:42 ` Siddharth Asthana
2026-03-30 10:37 ` Patrick Steinhardt
2026-03-31 17:11 ` Jean-Noël AVILA
3 siblings, 1 reply; 27+ messages in thread
From: Karthik Nayak @ 2026-03-30 9:44 UTC (permalink / raw)
To: Siddharth Asthana, git; +Cc: christian.couder, ps, gitster, toon
[-- Attachment #1: Type: text/plain, Size: 7486 bytes --]
Siddharth Asthana <siddharthasthana31@gmail.com> writes:
> git-cat-file(1)'s --batch-command works with the --use-mailmap option,
> but this option needs to be set when the process is created. This means
> we cannot change this option mid-operation.
>
> At GitLab, Gitaly caches git-cat-file processes and it would be useful
> if --batch-command supported toggling mailmap dynamically with existing
> processes.
>
> Add a `mailmap` subcommand to --batch-command that takes a single
> argument: `yes` to enable mailmap and `no` to disable it. When enabled,
> mailmap data is loaded from disk on first use and kept in memory so that
> toggling back on does not require reloading.
>
> Suggested-by: Junio C Hamano <gitster@pobox.com>
> Signed-off-by: Siddharth Asthana <siddharthasthana31@gmail.com>
> ---
> CI: https://gitlab.com/gitlab-org/git/-/pipelines/2416081861
>
> Documentation/git-cat-file.adoc | 7 +++++
> builtin/cat-file.c | 30 ++++++++++++++++++---
> t/t4203-mailmap.sh | 48 +++++++++++++++++++++++++++++++++
> 3 files changed, 81 insertions(+), 4 deletions(-)
>
> diff --git a/Documentation/git-cat-file.adoc b/Documentation/git-cat-file.adoc
> index c139f55a16..af32e929a8 100644
> --- a/Documentation/git-cat-file.adoc
> +++ b/Documentation/git-cat-file.adoc
> @@ -174,6 +174,13 @@ flush::
> since the beginning or since the last flush was issued. When `--buffer`
> is used, no output will come until a `flush` is issued. When `--buffer`
> is not used, commands are flushed each time without issuing `flush`.
> +
> +mailmap <yes|no>::
> + Enable or disable mailmap for subsequent `contents` and `info`
> + commands. When `yes` is given, mailmap data is loaded from disk on
Are there any commands that the mailmap wouldn't apply to? Would it make
sense to simply say
Enable or disable mailmap for subsequent commands.
also we can s/is given//.
> + first use and kept in memory; passing `yes` again does not reload it.
> + When `no` is given, mailmap is disabled but the data stays in memory
> + so that a later `mailmap yes` does not need to reload it from disk.
I think the first sentense here jumps directly into the the caching
mechanism on using `yes`. It's more important for users to know what
`yes` implies. So perhaps:
When `yes` mailmap data is used and disabled on `no`. The first
`yes` caches the mailmap data until the command exits.
> --
> +
>
> diff --git a/builtin/cat-file.c b/builtin/cat-file.c
> index b6f12f41d6..a53926d2bb 100644
> --- a/builtin/cat-file.c
> +++ b/builtin/cat-file.c
> @@ -54,6 +54,7 @@ static const char *force_path;
>
> static struct string_list mailmap = STRING_LIST_INIT_NODUP;
> static int use_mailmap;
> +static int mailmap_loaded;
>
Nit: should we use a 'bool' here?
So we use a variable and not simple rely on checking `mailmap.nr`
because it is possible that we do load the mailmap but there are no
entries. I assume we could rely on `maimap.cmp` being non-NULL, but
that's getting into implementation details.
> static char *replace_idents_using_mailmap(char *, size_t *);
>
> @@ -692,6 +693,24 @@ static void parse_cmd_info(struct batch_options *opt,
> batch_one_object(line, output, opt, data);
> }
>
> +static void parse_cmd_mailmap(struct batch_options *opt UNUSED,
> + const char *line,
> + struct strbuf *output UNUSED,
> + struct expand_data *data UNUSED)
> +{
> + if (!strcmp(line, "yes")) {
> + if (!mailmap_loaded) {
> + read_mailmap(the_repository, &mailmap);
> + mailmap_loaded = 1;
> + }
> + use_mailmap = 1;
> + } else if (!strcmp(line, "no")) {
> + use_mailmap = 0;
> + } else {
> + die(_("mailmap: unknown argument '%s', expected 'yes' or 'no'"), line);
> + }
> +}
> +
> static void dispatch_calls(struct batch_options *opt,
> struct strbuf *output,
> struct expand_data *data,
> @@ -725,9 +744,10 @@ static const struct parse_cmd {
> parse_cmd_fn_t fn;
> unsigned takes_args;
> } commands[] = {
> - { "contents", parse_cmd_contents, 1},
> - { "info", parse_cmd_info, 1},
> - { "flush", NULL, 0},
> + { "contents", parse_cmd_contents, 1 },
> + { "info", parse_cmd_info, 1 },
> + { "flush", NULL, 0 },
> + { "mailmap", parse_cmd_mailmap, 1 },
> };
>
> static void batch_objects_command(struct batch_options *opt,
> @@ -1127,8 +1147,10 @@ int cmd_cat_file(int argc,
> opt_cw = (opt == 'c' || opt == 'w');
> opt_epts = (opt == 'e' || opt == 'p' || opt == 't' || opt == 's');
>
> - if (use_mailmap)
> + if (use_mailmap) {
> read_mailmap(the_repository, &mailmap);
> + mailmap_loaded = 1;
> + }
>
The rest of the code looks good.
> switch (batch.objects_filter.choice) {
> case LOFC_DISABLED:
> diff --git a/t/t4203-mailmap.sh b/t/t4203-mailmap.sh
> index 74b7ddccb2..f66637cd86 100755
> --- a/t/t4203-mailmap.sh
> +++ b/t/t4203-mailmap.sh
> @@ -1133,6 +1133,54 @@ test_expect_success 'git cat-file --batch-command returns correct size with --us
> test_cmp expect actual
> '
>
> +test_expect_success 'git cat-file --batch-command mailmap yes enables mailmap mid-stream' '
> + test_when_finished "rm .mailmap" &&
> + cat >.mailmap <<-\EOF &&
> + C O Mitter <committer@example.com> Orig <orig@example.com>
> + EOF
> + commit_sha=$(git rev-parse HEAD) &&
> + git cat-file commit HEAD >commit_no_mailmap.out &&
> + git cat-file --use-mailmap commit HEAD >commit_mailmap.out &&
> + size_no_mailmap=$(wc -c <commit_no_mailmap.out) &&
> + size_mailmap=$(wc -c <commit_mailmap.out) &&
> + printf "info HEAD\nmailmap yes\ninfo HEAD\n" | git cat-file --batch-command >actual &&
> + echo $commit_sha commit $size_no_mailmap >expect &&
> + echo $commit_sha commit $size_mailmap >>expect &&
> + test_cmp expect actual
> +'
> +
> +test_expect_success 'git cat-file --batch-command mailmap no disables mailmap mid-stream' '
> + test_when_finished "rm .mailmap" &&
> + cat >.mailmap <<-\EOF &&
> + C O Mitter <committer@example.com> Orig <orig@example.com>
> + EOF
> + commit_sha=$(git rev-parse HEAD) &&
> + git cat-file commit HEAD >commit_no_mailmap.out &&
> + git cat-file --use-mailmap commit HEAD >commit_mailmap.out &&
> + size_no_mailmap=$(wc -c <commit_no_mailmap.out) &&
> + size_mailmap=$(wc -c <commit_mailmap.out) &&
> + printf "mailmap yes\ninfo HEAD\nmailmap no\ninfo HEAD\n" | git cat-file --batch-command >actual &&
> + echo $commit_sha commit $size_mailmap >expect &&
> + echo $commit_sha commit $size_no_mailmap >>expect &&
> + test_cmp expect actual
> +'
> +
> +test_expect_success 'git cat-file --batch-command mailmap works in --buffer mode' '
> + test_when_finished "rm .mailmap" &&
> + cat >.mailmap <<-\EOF &&
> + C O Mitter <committer@example.com> Orig <orig@example.com>
> + EOF
> + commit_sha=$(git rev-parse HEAD) &&
> + git cat-file commit HEAD >commit_no_mailmap.out &&
> + git cat-file --use-mailmap commit HEAD >commit_mailmap.out &&
> + size_no_mailmap=$(wc -c <commit_no_mailmap.out) &&
> + size_mailmap=$(wc -c <commit_mailmap.out) &&
> + printf "mailmap yes\ninfo HEAD\nmailmap no\ninfo HEAD\nflush\n" | git cat-file --batch-command --buffer >actual &&
> + echo $commit_sha commit $size_mailmap >expect &&
> + echo $commit_sha commit $size_no_mailmap >>expect &&
> + test_cmp expect actual
> +'
Shouldn't we also add tests for how this interacts with '--mailmap' and
'--no-mailmap'?
> test_expect_success 'git cat-file --mailmap works with different author and committer' '
> test_when_finished "rm .mailmap" &&
> cat >.mailmap <<-\EOF &&
> --
> 2.51.0
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 690 bytes --]
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH v2 1/1] cat-file: add mailmap subcommand to --batch-command
2026-03-29 8:28 ` [PATCH v2 1/1] " Siddharth Asthana
2026-03-30 2:12 ` Junio C Hamano
2026-03-30 9:44 ` Karthik Nayak
@ 2026-03-30 10:37 ` Patrick Steinhardt
2026-03-30 14:53 ` Junio C Hamano
2026-03-31 1:43 ` Siddharth Asthana
2026-03-31 17:11 ` Jean-Noël AVILA
3 siblings, 2 replies; 27+ messages in thread
From: Patrick Steinhardt @ 2026-03-30 10:37 UTC (permalink / raw)
To: Siddharth Asthana; +Cc: git, karthik.188, christian.couder, gitster, toon
On Sun, Mar 29, 2026 at 01:58:08PM +0530, Siddharth Asthana wrote:
> diff --git a/builtin/cat-file.c b/builtin/cat-file.c
> index b6f12f41d6..a53926d2bb 100644
> --- a/builtin/cat-file.c
> +++ b/builtin/cat-file.c
> @@ -692,6 +693,24 @@ static void parse_cmd_info(struct batch_options *opt,
> batch_one_object(line, output, opt, data);
> }
>
> +static void parse_cmd_mailmap(struct batch_options *opt UNUSED,
> + const char *line,
> + struct strbuf *output UNUSED,
> + struct expand_data *data UNUSED)
> +{
> + if (!strcmp(line, "yes")) {
> + if (!mailmap_loaded) {
> + read_mailmap(the_repository, &mailmap);
> + mailmap_loaded = 1;
> + }
> + use_mailmap = 1;
> + } else if (!strcmp(line, "no")) {
> + use_mailmap = 0;
> + } else {
> + die(_("mailmap: unknown argument '%s', expected 'yes' or 'no'"), line);
> + }
> +}
Not commenting on the overall chanegchange, but I guess we should use
`git_parse_maybe_bool()` here?
Patrick
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH v2 1/1] cat-file: add mailmap subcommand to --batch-command
2026-03-30 10:37 ` Patrick Steinhardt
@ 2026-03-30 14:53 ` Junio C Hamano
2026-03-31 1:43 ` Siddharth Asthana
1 sibling, 0 replies; 27+ messages in thread
From: Junio C Hamano @ 2026-03-30 14:53 UTC (permalink / raw)
To: Patrick Steinhardt
Cc: Siddharth Asthana, git, karthik.188, christian.couder, toon
Patrick Steinhardt <ps@pks.im> writes:
> On Sun, Mar 29, 2026 at 01:58:08PM +0530, Siddharth Asthana wrote:
>> diff --git a/builtin/cat-file.c b/builtin/cat-file.c
>> index b6f12f41d6..a53926d2bb 100644
>> --- a/builtin/cat-file.c
>> +++ b/builtin/cat-file.c
>> @@ -692,6 +693,24 @@ static void parse_cmd_info(struct batch_options *opt,
>> batch_one_object(line, output, opt, data);
>> }
>>
>> +static void parse_cmd_mailmap(struct batch_options *opt UNUSED,
>> + const char *line,
>> + struct strbuf *output UNUSED,
>> + struct expand_data *data UNUSED)
>> +{
>> + if (!strcmp(line, "yes")) {
>> + if (!mailmap_loaded) {
>> + read_mailmap(the_repository, &mailmap);
>> + mailmap_loaded = 1;
>> + }
>> + use_mailmap = 1;
>> + } else if (!strcmp(line, "no")) {
>> + use_mailmap = 0;
>> + } else {
>> + die(_("mailmap: unknown argument '%s', expected 'yes' or 'no'"), line);
>> + }
>> +}
>
> Not commenting on the overall chanegchange, but I guess we should use
> `git_parse_maybe_bool()` here?
The saame thought occureed to me. Also I agree with Karthik that we
should not say "applies only to this and that commands".
Thanks, all.
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH v2 1/1] cat-file: add mailmap subcommand to --batch-command
2026-03-30 2:12 ` Junio C Hamano
@ 2026-03-31 1:40 ` Siddharth Asthana
2026-03-31 3:41 ` Junio C Hamano
0 siblings, 1 reply; 27+ messages in thread
From: Siddharth Asthana @ 2026-03-31 1:40 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git, karthik.188, christian.couder, ps, toon
On 30/03/26 07:42, Junio C Hamano wrote:
> Siddharth Asthana <siddharthasthana31@gmail.com> writes:
>
>> git-cat-file(1)'s --batch-command works with the --use-mailmap option,
>> but this option needs to be set when the process is created. This means
>> we cannot change this option mid-operation.
>>
>> At GitLab, Gitaly caches git-cat-file processes and it would be useful
>
> Would "keeps interacting with a single 'cat-file' process" be more
> accurate than "caches"? The latter gives, at least to me,
Thanks Junio
Make sense, I will update that wording in v3!
> connotations that may not be necessarily true, like (1) there is a
> pool of cat-file processes waiting for Gitaly to connect and serve,
> (2) a running Gitaly may decide to disconnect from cat-file from
> time to time, and then reconnect to one of them when it becomes
> necessary again, etc.
>
>> if --batch-command supported toggling mailmap dynamically with existing
>> processes.
>>
>> Add a `mailmap` subcommand to --batch-command that takes a single
>> argument: `yes` to enable mailmap and `no` to disable it. When enabled,
>> mailmap data is loaded from disk on first use and kept in memory so that
>> toggling back on does not require reloading.
>>
>> Suggested-by: Junio C Hamano <gitster@pobox.com>
>
> This is over-crediting me. The idea to unify the two commands into
> one may have come from me, but that is at most helped-by but it is
> perfectly fine without any credit.
Got it, thanks for pointing that out.
>
>> Signed-off-by: Siddharth Asthana <siddharthasthana31@gmail.com>
>> ---
>
>> diff --git a/builtin/cat-file.c b/builtin/cat-file.c
>> index b6f12f41d6..a53926d2bb 100644
>> --- a/builtin/cat-file.c
>> +++ b/builtin/cat-file.c
>> @@ -54,6 +54,7 @@ static const char *force_path;
>>
>> static struct string_list mailmap = STRING_LIST_INIT_NODUP;
>> static int use_mailmap;
>> +static int mailmap_loaded;
>
> Not part of this topic, but in case less experienced developers who
> are watching from the sidelines wonder if we want to add this
> file-scope global variable, this is perfectly fine. Anything under
> builtin/foo.c are meant to serve a single command "git foo" and does
> not benefit from "let's sift globals into classes that belong to
> different concepts in the system; most of which will be per
> repository, so make them some part of the repository object"
> movement as much as more library-ish parts of the system.
>
> Until a specific command starts working on multiple repositories at
> one time, that is.
>
>
>> @@ -692,6 +693,24 @@ static void parse_cmd_info(struct batch_options *opt,
>> batch_one_object(line, output, opt, data);
>> }
>>
>> +static void parse_cmd_mailmap(struct batch_options *opt UNUSED,
>> + const char *line,
>> + struct strbuf *output UNUSED,
>> + struct expand_data *data UNUSED)
>> +{
>> + if (!strcmp(line, "yes")) {
>> + if (!mailmap_loaded) {
>> + read_mailmap(the_repository, &mailmap);
>> + mailmap_loaded = 1;
>> + }
>> + use_mailmap = 1;
>> + } else if (!strcmp(line, "no")) {
>> + use_mailmap = 0;
>> + } else {
>> + die(_("mailmap: unknown argument '%s', expected 'yes' or 'no'"), line);
>> + }
>> +}
>
> OK.
>
>> @@ -725,9 +744,10 @@ static const struct parse_cmd {
>> parse_cmd_fn_t fn;
>> unsigned takes_args;
>> } commands[] = {
>> - { "contents", parse_cmd_contents, 1},
>> - { "info", parse_cmd_info, 1},
>> - { "flush", NULL, 0},
>> + { "contents", parse_cmd_contents, 1 },
>> + { "info", parse_cmd_info, 1 },
>> + { "flush", NULL, 0 },
>> + { "mailmap", parse_cmd_mailmap, 1 },
>> };
>
> Mixing style fixes to existing entries in the same patch that adds a
> new feature by adding a new entry to the table is annoying than
> having a preliminary clean-up patch that only fixes style and then
> the main patch that adds the feature.
Agreed. I will avoid mixing style-only cleanup with the feature change
in v3.
>
>> static void batch_objects_command(struct batch_options *opt,
>> @@ -1127,8 +1147,10 @@ int cmd_cat_file(int argc,
>> opt_cw = (opt == 'c' || opt == 'w');
>> opt_epts = (opt == 'e' || opt == 'p' || opt == 't' || opt == 's');
>>
>> - if (use_mailmap)
>> + if (use_mailmap) {
>> read_mailmap(the_repository, &mailmap);
>> + mailmap_loaded = 1;
>> + }
>
> Hmph, interesting. Two points.
>
> * It would make it easier to follow if these two lines are made
> into a small helper function to be called from here and from the
> "parse_cmd_mailmap()"?
>
> * Can we somehow make mailmap object itself slightly smarter so
> that it knows if it has already been asked to read the data from
> its sources? It is a pretty dumb string_list, but from a cursory
> read of the code flow, it seems that mailmap.strdup_strings is
> initialized to be false in builtin/cat-file.c and then one of the
> first things done in mailmap.c::read_mailmap() is to flip that
> bit on, so the "yes" part of the parse_cmd_mailmap() might become
>
> if (yes)
> load_mailmap();
>
> with the helper load_mailmap() that may look like:
>
> static void load_mailmap(void)
> {
> if (mailmap.strdup_strings)
> return; /* we know read_mailmap() flips it on */
> read_mailmap(the_repository, &mailmap);
> }
>
> The first bullet point to introduce a small common helper will
> help hiding such an ugly implementation detail there.
Thanks, this is helpful.
I will introduce a small helper and call it from both places so the flow
is easier to follow. I will also avoid publicating the load check in
each callsite
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH v2 1/1] cat-file: add mailmap subcommand to --batch-command
2026-03-30 9:44 ` Karthik Nayak
@ 2026-03-31 1:42 ` Siddharth Asthana
0 siblings, 0 replies; 27+ messages in thread
From: Siddharth Asthana @ 2026-03-31 1:42 UTC (permalink / raw)
To: Karthik Nayak, git; +Cc: christian.couder, ps, gitster, toon
On 30/03/26 15:14, Karthik Nayak wrote:
> Siddharth Asthana <siddharthasthana31@gmail.com> writes:
>
>> git-cat-file(1)'s --batch-command works with the --use-mailmap option,
>> but this option needs to be set when the process is created. This means
>> we cannot change this option mid-operation.
>>
>> At GitLab, Gitaly caches git-cat-file processes and it would be useful
>> if --batch-command supported toggling mailmap dynamically with existing
>> processes.
>>
>> Add a `mailmap` subcommand to --batch-command that takes a single
>> argument: `yes` to enable mailmap and `no` to disable it. When enabled,
>> mailmap data is loaded from disk on first use and kept in memory so that
>> toggling back on does not require reloading.
>>
>> Suggested-by: Junio C Hamano <gitster@pobox.com>
>> Signed-off-by: Siddharth Asthana <siddharthasthana31@gmail.com>
>> ---
>> CI: https://gitlab.com/gitlab-org/git/-/pipelines/2416081861
>>
>> Documentation/git-cat-file.adoc | 7 +++++
>> builtin/cat-file.c | 30 ++++++++++++++++++---
>> t/t4203-mailmap.sh | 48 +++++++++++++++++++++++++++++++++
>> 3 files changed, 81 insertions(+), 4 deletions(-)
>>
>> diff --git a/Documentation/git-cat-file.adoc b/Documentation/git-cat-file.adoc
>> index c139f55a16..af32e929a8 100644
>> --- a/Documentation/git-cat-file.adoc
>> +++ b/Documentation/git-cat-file.adoc
>> @@ -174,6 +174,13 @@ flush::
>> since the beginning or since the last flush was issued. When `--buffer`
>> is used, no output will come until a `flush` is issued. When `--buffer`
>> is not used, commands are flushed each time without issuing `flush`.
>> +
>> +mailmap <yes|no>::
>> + Enable or disable mailmap for subsequent `contents` and `info`
>> + commands. When `yes` is given, mailmap data is loaded from disk on
>
> Are there any commands that the mailmap wouldn't apply to? Would it make
> sense to simply say
>
> Enable or disable mailmap for subsequent commands.
Good point, agreed. I will simplify the wording in v3 and avoid listing
specific commands there.
>
> also we can s/is given//.
>
>> + first use and kept in memory; passing `yes` again does not reload it.
>> + When `no` is given, mailmap is disabled but the data stays in memory
>> + so that a later `mailmap yes` does not need to reload it from disk.
>
> I think the first sentense here jumps directly into the the caching
> mechanism on using `yes`. It's more important for users to know what
> `yes` implies. So perhaps:
>
> When `yes` mailmap data is used and disabled on `no`. The first
> `yes` caches the mailmap data until the command exits.
>
>> --
>> +
>>
>> diff --git a/builtin/cat-file.c b/builtin/cat-file.c
>> index b6f12f41d6..a53926d2bb 100644
>> --- a/builtin/cat-file.c
>> +++ b/builtin/cat-file.c
>> @@ -54,6 +54,7 @@ static const char *force_path;
>>
>> static struct string_list mailmap = STRING_LIST_INIT_NODUP;
>> static int use_mailmap;
>> +static int mailmap_loaded;
>>
>
> Nit: should we use a 'bool' here?
Yes, makes sense. I will switch that to bool in v3.
>
> So we use a variable and not simple rely on checking `mailmap.nr`
> because it is possible that we do load the mailmap but there are no
> entries. I assume we could rely on `maimap.cmp` being non-NULL, but
> that's getting into implementation details.
>
>> static char *replace_idents_using_mailmap(char *, size_t *);
>>
>> @@ -692,6 +693,24 @@ static void parse_cmd_info(struct batch_options *opt,
>> batch_one_object(line, output, opt, data);
>> }
>>
>> +static void parse_cmd_mailmap(struct batch_options *opt UNUSED,
>> + const char *line,
>> + struct strbuf *output UNUSED,
>> + struct expand_data *data UNUSED)
>> +{
>> + if (!strcmp(line, "yes")) {
>> + if (!mailmap_loaded) {
>> + read_mailmap(the_repository, &mailmap);
>> + mailmap_loaded = 1;
>> + }
>> + use_mailmap = 1;
>> + } else if (!strcmp(line, "no")) {
>> + use_mailmap = 0;
>> + } else {
>> + die(_("mailmap: unknown argument '%s', expected 'yes' or 'no'"), line);
>> + }
>> +}
>> +
>> static void dispatch_calls(struct batch_options *opt,
>> struct strbuf *output,
>> struct expand_data *data,
>> @@ -725,9 +744,10 @@ static const struct parse_cmd {
>> parse_cmd_fn_t fn;
>> unsigned takes_args;
>> } commands[] = {
>> - { "contents", parse_cmd_contents, 1},
>> - { "info", parse_cmd_info, 1},
>> - { "flush", NULL, 0},
>> + { "contents", parse_cmd_contents, 1 },
>> + { "info", parse_cmd_info, 1 },
>> + { "flush", NULL, 0 },
>> + { "mailmap", parse_cmd_mailmap, 1 },
>> };
>>
>> static void batch_objects_command(struct batch_options *opt,
>> @@ -1127,8 +1147,10 @@ int cmd_cat_file(int argc,
>> opt_cw = (opt == 'c' || opt == 'w');
>> opt_epts = (opt == 'e' || opt == 'p' || opt == 't' || opt == 's');
>>
>> - if (use_mailmap)
>> + if (use_mailmap) {
>> read_mailmap(the_repository, &mailmap);
>> + mailmap_loaded = 1;
>> + }
>>
>
> The rest of the code looks good.
>
>> switch (batch.objects_filter.choice) {
>> case LOFC_DISABLED:
>> diff --git a/t/t4203-mailmap.sh b/t/t4203-mailmap.sh
>> index 74b7ddccb2..f66637cd86 100755
>> --- a/t/t4203-mailmap.sh
>> +++ b/t/t4203-mailmap.sh
>> @@ -1133,6 +1133,54 @@ test_expect_success 'git cat-file --batch-command returns correct size with --us
>> test_cmp expect actual
>> '
>>
>> +test_expect_success 'git cat-file --batch-command mailmap yes enables mailmap mid-stream' '
>> + test_when_finished "rm .mailmap" &&
>> + cat >.mailmap <<-\EOF &&
>> + C O Mitter <committer@example.com> Orig <orig@example.com>
>> + EOF
>> + commit_sha=$(git rev-parse HEAD) &&
>> + git cat-file commit HEAD >commit_no_mailmap.out &&
>> + git cat-file --use-mailmap commit HEAD >commit_mailmap.out &&
>> + size_no_mailmap=$(wc -c <commit_no_mailmap.out) &&
>> + size_mailmap=$(wc -c <commit_mailmap.out) &&
>> + printf "info HEAD\nmailmap yes\ninfo HEAD\n" | git cat-file --batch-command >actual &&
>> + echo $commit_sha commit $size_no_mailmap >expect &&
>> + echo $commit_sha commit $size_mailmap >>expect &&
>> + test_cmp expect actual
>> +'
>> +
>> +test_expect_success 'git cat-file --batch-command mailmap no disables mailmap mid-stream' '
>> + test_when_finished "rm .mailmap" &&
>> + cat >.mailmap <<-\EOF &&
>> + C O Mitter <committer@example.com> Orig <orig@example.com>
>> + EOF
>> + commit_sha=$(git rev-parse HEAD) &&
>> + git cat-file commit HEAD >commit_no_mailmap.out &&
>> + git cat-file --use-mailmap commit HEAD >commit_mailmap.out &&
>> + size_no_mailmap=$(wc -c <commit_no_mailmap.out) &&
>> + size_mailmap=$(wc -c <commit_mailmap.out) &&
>> + printf "mailmap yes\ninfo HEAD\nmailmap no\ninfo HEAD\n" | git cat-file --batch-command >actual &&
>> + echo $commit_sha commit $size_mailmap >expect &&
>> + echo $commit_sha commit $size_no_mailmap >>expect &&
>> + test_cmp expect actual
>> +'
>> +
>> +test_expect_success 'git cat-file --batch-command mailmap works in --buffer mode' '
>> + test_when_finished "rm .mailmap" &&
>> + cat >.mailmap <<-\EOF &&
>> + C O Mitter <committer@example.com> Orig <orig@example.com>
>> + EOF
>> + commit_sha=$(git rev-parse HEAD) &&
>> + git cat-file commit HEAD >commit_no_mailmap.out &&
>> + git cat-file --use-mailmap commit HEAD >commit_mailmap.out &&
>> + size_no_mailmap=$(wc -c <commit_no_mailmap.out) &&
>> + size_mailmap=$(wc -c <commit_mailmap.out) &&
>> + printf "mailmap yes\ninfo HEAD\nmailmap no\ninfo HEAD\nflush\n" | git cat-file --batch-command --buffer >actual &&
>> + echo $commit_sha commit $size_mailmap >expect &&
>> + echo $commit_sha commit $size_no_mailmap >>expect &&
>> + test_cmp expect actual
>> +'
>
> Shouldn't we also add tests for how this interacts with '--mailmap' and
> '--no-mailmap'?
Agreed, that coverage is missing. I will add tests for startup option +
runtime toggle interaction in v3.
>
>> test_expect_success 'git cat-file --mailmap works with different author and committer' '
>> test_when_finished "rm .mailmap" &&
>> cat >.mailmap <<-\EOF &&
>> --
>> 2.51.0
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH v2 1/1] cat-file: add mailmap subcommand to --batch-command
2026-03-30 10:37 ` Patrick Steinhardt
2026-03-30 14:53 ` Junio C Hamano
@ 2026-03-31 1:43 ` Siddharth Asthana
1 sibling, 0 replies; 27+ messages in thread
From: Siddharth Asthana @ 2026-03-31 1:43 UTC (permalink / raw)
To: Patrick Steinhardt; +Cc: git, karthik.188, christian.couder, gitster, toon
On 30/03/26 16:07, Patrick Steinhardt wrote:
> On Sun, Mar 29, 2026 at 01:58:08PM +0530, Siddharth Asthana wrote:
>> diff --git a/builtin/cat-file.c b/builtin/cat-file.c
>> index b6f12f41d6..a53926d2bb 100644
>> --- a/builtin/cat-file.c
>> +++ b/builtin/cat-file.c
>> @@ -692,6 +693,24 @@ static void parse_cmd_info(struct batch_options *opt,
>> batch_one_object(line, output, opt, data);
>> }
>>
>> +static void parse_cmd_mailmap(struct batch_options *opt UNUSED,
>> + const char *line,
>> + struct strbuf *output UNUSED,
>> + struct expand_data *data UNUSED)
>> +{
>> + if (!strcmp(line, "yes")) {
>> + if (!mailmap_loaded) {
>> + read_mailmap(the_repository, &mailmap);
>> + mailmap_loaded = 1;
>> + }
>> + use_mailmap = 1;
>> + } else if (!strcmp(line, "no")) {
>> + use_mailmap = 0;
>> + } else {
>> + die(_("mailmap: unknown argument '%s', expected 'yes' or 'no'"), line);
>> + }
>> +}
>
> Not commenting on the overall chanegchange, but I guess we should use
> `git_parse_maybe_bool()` here?
Yep, agreed. I will switch to git_parse_maybe_bool() in v3.
>
> Patrick
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH v2 1/1] cat-file: add mailmap subcommand to --batch-command
2026-03-31 1:40 ` Siddharth Asthana
@ 2026-03-31 3:41 ` Junio C Hamano
0 siblings, 0 replies; 27+ messages in thread
From: Junio C Hamano @ 2026-03-31 3:41 UTC (permalink / raw)
To: Siddharth Asthana; +Cc: git, karthik.188, christian.couder, ps, toon
Siddharth Asthana <siddharthasthana31@gmail.com> writes:
>> * Can we somehow make mailmap object itself slightly smarter so
>> that it knows if it has already been asked to read the data from
>> its sources? It is a pretty dumb string_list, but from a cursory
>> read of the code flow, it seems that mailmap.strdup_strings is
>> initialized to be false in builtin/cat-file.c and then one of the
>> first things done in mailmap.c::read_mailmap() is to flip that
>> bit on, so the "yes" part of the parse_cmd_mailmap() might become
>>
>> if (yes)
>> load_mailmap();
>>
>> with the helper load_mailmap() that may look like:
This part was a bit misstated. What I meant was more like
if (!strcmp(...yes))
use_mailmap = 1;
else if (!strcmp(...no))
use_mailmap = 0;
else
die(_("misconfigured"));
if (use_mailmap)
load_mailmap();
^ permalink raw reply [flat|nested] 27+ messages in thread
* [PATCH v3 0/1] cat-file: add mailmap subcommand to --batch-command
2026-03-29 8:28 ` [PATCH v2 0/1] cat-file: add mailmap subcommand " Siddharth Asthana
2026-03-29 8:28 ` [PATCH v2 1/1] " Siddharth Asthana
@ 2026-03-31 12:11 ` Siddharth Asthana
2026-03-31 12:11 ` [PATCH v3 1/1] " Siddharth Asthana
2026-04-15 15:09 ` [PATCH v4 0/1] " Siddharth Asthana
1 sibling, 2 replies; 27+ messages in thread
From: Siddharth Asthana @ 2026-03-31 12:11 UTC (permalink / raw)
To: git; +Cc: karthik.188, christian.couder, ps, gitster, toon,
Siddharth Asthana
git-cat-file(1)'s --batch-command works with the --use-mailmap option,
but this option needs to be set when the process is created. This means
we cannot change this option mid-operation.
At GitLab, Gitaly keeps interacting with a long-lived git-cat-file
process and it would be useful if --batch-command supported toggling
mailmap dynamically on an existing process.
This patch adds a `mailmap` subcommand to --batch-command that accepts
a boolean argument and toggles mailmap dynamically for subsequent
commands.
The series is based on top of 5361983c07 (The 22nd batch, 2026-03-21).
CI: https://gitlab.com/gitlab-org/git/-/pipelines/2419600519
Changes in v3:
- Use "keeps interacting with a long-lived git-cat-file process" wording
in the commit message and cover letter.
- Drop the `Suggested-by` trailer.
- Avoid style-only churn in the `commands[]` table by keeping existing
initializer style and only adding the new command entry.
- Introduce a `load_mailmap()` helper used by both startup and
`parse_cmd_mailmap()`.
- Parse `mailmap <bool>` using `git_parse_maybe_bool()` instead of
handling only `yes`/`no`.
- Update docs to describe `mailmap <bool>` and reference Git's boolean
syntax from `git-config(1)`.
- Add tests for startup option interaction (`--mailmap`/`--no-mailmap`),
accepted boolean values (`true`/`false`), and invalid boolean input.
- Link to v2: https://public-inbox.org/git/20260329082804.53400-1-siddharthasthana31@gmail.com/
- Link to v1: https://public-inbox.org/git/a4ec7bfa-f16b-4505-9b37-d3dd137e93cb@gmail.com/T/#m5c62fb6ad0fbcc99a706dba4c78b66359c247acd
Thanks,
Siddharth
---
Siddharth Asthana (1):
cat-file: add mailmap subcommand to --batch-command
Documentation/git-cat-file.adoc | 7 +++
builtin/cat-file.c | 32 ++++++++++--
t/t4203-mailmap.sh | 105 ++++++++++++++++++++++++++++++++++++++++
3 files changed, 140 insertions(+), 4 deletions(-)
Range-diff versus v2:
1: 936ca27419 ! 1: df446d7ca3 cat-file: add mailmap subcommand to --batch-command
@@ Commit message
but this option needs to be set when the process is created. This means
we cannot change this option mid-operation.
- At GitLab, Gitaly caches git-cat-file processes and it would be useful
- if --batch-command supported toggling mailmap dynamically with existing
- processes.
+ At GitLab, Gitaly keeps interacting with a long-lived git-cat-file
+ process and it would be useful if --batch-command supported toggling
+ mailmap dynamically on an existing process.
- Add a `mailmap` subcommand to --batch-command that takes a single
- argument: `yes` to enable mailmap and `no` to disable it. When enabled,
- mailmap data is loaded from disk on first use and kept in memory so that
- toggling back on does not require reloading.
+ Add a `mailmap` subcommand to --batch-command that takes a boolean
+ argument. The command now uses `git_parse_maybe_bool()` and supports all
+ standard Git boolean values. Mailmap data is loaded lazily and kept in
+ memory, while a helper centralizes the one-time load path used both at
+ startup and from the batch-command handler.
+
+ Extend tests to cover runtime toggling, startup option interactions
+ (`--mailmap`/`--no-mailmap`), accepted boolean forms, and invalid values.
- Suggested-by: Junio C Hamano <gitster@pobox.com>
Signed-off-by: Siddharth Asthana <siddharthasthana31@gmail.com>
## Documentation/git-cat-file.adoc ##
@@ Documentation/git-cat-file.adoc: flush::
is used, no output will come until a `flush` is issued. When `--buffer`
is not used, commands are flushed each time without issuing `flush`.
+
-+mailmap <yes|no>::
-+ Enable or disable mailmap for subsequent `contents` and `info`
-+ commands. When `yes` is given, mailmap data is loaded from disk on
-+ first use and kept in memory; passing `yes` again does not reload it.
-+ When `no` is given, mailmap is disabled but the data stays in memory
-+ so that a later `mailmap yes` does not need to reload it from disk.
++mailmap <bool>::
++ Enable or disable mailmap for subsequent commands.
+++
++The `<bool>` argument accepts the same boolean values as
++linkgit:git-config[1]. When enabled, mailmap data is loaded on first
++use and kept in memory until the process exits.
--
## builtin/cat-file.c ##
+@@ builtin/cat-file.c: static int use_mailmap;
+
+static void load_mailmap(void)
+{
+ if (mailmap.strdup_strings)
+ return;
+
+ read_mailmap(the_repository, &mailmap);
+}
+
@@ builtin/cat-file.c: static void parse_cmd_info(struct batch_options *opt,
batch_one_object(line, output, opt, data);
}
@@ builtin/cat-file.c: static void parse_cmd_info(struct batch_options *opt,
+{
-+ if (!strcmp(line, "yes")) {
-+ if (!mailmap_loaded) {
-+ read_mailmap(the_repository, &mailmap);
-+ mailmap_loaded = 1;
-+ }
-+ use_mailmap = 1;
-+ } else if (!strcmp(line, "no")) {
-+ use_mailmap = 0;
-+ } else {
-+ die(_("mailmap: unknown argument '%s', expected 'yes' or 'no'"), line);
-+ }
++ int value = git_parse_maybe_bool(line);
++
++ if (value < 0)
++ die(_("mailmap: invalid boolean '%s'"), line);
++
++ if (value > 0)
++ load_mailmap();
++ use_mailmap = value;
+}
+
@@ builtin/cat-file.c: static const struct parse_cmd {
-+ { "use-mailmap", parse_cmd_use_mailmap, 0 },
-+ { "no-use-mailmap", parse_cmd_disable_mailmap, 0 },
++ { "mailmap", parse_cmd_mailmap, 1 },
+};
@@ builtin/cat-file.c: int cmd_cat_file(int argc,
if (use_mailmap)
-+ read_mailmap(the_repository, &mailmap);
++ load_mailmap();
base-commit: 5361983c075154725be47b65cca9a2421789e410
--
2.53.0
^ permalink raw reply [flat|nested] 27+ messages in thread
* [PATCH v3 1/1] cat-file: add mailmap subcommand to --batch-command
2026-03-31 12:11 ` [PATCH v3 0/1] " Siddharth Asthana
@ 2026-03-31 12:11 ` Siddharth Asthana
2026-03-31 19:21 ` Junio C Hamano
2026-04-15 15:09 ` [PATCH v4 0/1] " Siddharth Asthana
1 sibling, 1 reply; 27+ messages in thread
From: Siddharth Asthana @ 2026-03-31 12:11 UTC (permalink / raw)
To: git; +Cc: karthik.188, christian.couder, ps, gitster, toon,
Siddharth Asthana
git-cat-file(1)'s --batch-command works with the --use-mailmap option,
but this option needs to be set when the process is created. This means
we cannot change this option mid-operation.
At GitLab, Gitaly keeps interacting with a long-lived git-cat-file
process and it would be useful if --batch-command supported toggling
mailmap dynamically on an existing process.
Add a `mailmap` subcommand to --batch-command that takes a boolean
argument. The command now uses `git_parse_maybe_bool()` and supports all
standard Git boolean values. Mailmap data is loaded lazily and kept in
memory, while a helper centralizes the one-time load path used both at
startup and from the batch-command handler.
Extend tests to cover runtime toggling, startup option interactions
(`--mailmap`/`--no-mailmap`), accepted boolean forms, and invalid values.
Signed-off-by: Siddharth Asthana <siddharthasthana31@gmail.com>
---
CI: https://gitlab.com/gitlab-org/git/-/pipelines/2419600519
Documentation/git-cat-file.adoc | 7 +++
builtin/cat-file.c | 32 ++++++++--
t/t4203-mailmap.sh | 105 ++++++++++++++++++++++++++++++++
3 files changed, 140 insertions(+), 4 deletions(-)
diff --git a/Documentation/git-cat-file.adoc b/Documentation/git-cat-file.adoc
index c139f55a16..3db925e1de 100644
--- a/Documentation/git-cat-file.adoc
+++ b/Documentation/git-cat-file.adoc
@@ -174,6 +174,13 @@ flush::
since the beginning or since the last flush was issued. When `--buffer`
is used, no output will come until a `flush` is issued. When `--buffer`
is not used, commands are flushed each time without issuing `flush`.
+
+mailmap <bool>::
+ Enable or disable mailmap for subsequent commands.
++
+The `<bool>` argument accepts the same boolean values as
+linkgit:git-config[1]. When enabled, mailmap data is loaded on first
+use and kept in memory until the process exits.
--
+
diff --git a/builtin/cat-file.c b/builtin/cat-file.c
index b6f12f41d6..a3dab0b40c 100644
--- a/builtin/cat-file.c
+++ b/builtin/cat-file.c
@@ -57,6 +57,14 @@ static int use_mailmap;
static char *replace_idents_using_mailmap(char *, size_t *);
+static void load_mailmap(void)
+{
+ if (mailmap.strdup_strings)
+ return;
+
+ read_mailmap(the_repository, &mailmap);
+}
+
static char *replace_idents_using_mailmap(char *object_buf, size_t *size)
{
struct strbuf sb = STRBUF_INIT;
@@ -692,6 +700,21 @@ static void parse_cmd_info(struct batch_options *opt,
batch_one_object(line, output, opt, data);
}
+static void parse_cmd_mailmap(struct batch_options *opt UNUSED,
+ const char *line,
+ struct strbuf *output UNUSED,
+ struct expand_data *data UNUSED)
+{
+ int value = git_parse_maybe_bool(line);
+
+ if (value < 0)
+ die(_("mailmap: invalid boolean '%s'"), line);
+
+ if (value > 0)
+ load_mailmap();
+ use_mailmap = value;
+}
+
static void dispatch_calls(struct batch_options *opt,
struct strbuf *output,
struct expand_data *data,
@@ -725,9 +748,10 @@ static const struct parse_cmd {
parse_cmd_fn_t fn;
unsigned takes_args;
} commands[] = {
- { "contents", parse_cmd_contents, 1},
- { "info", parse_cmd_info, 1},
- { "flush", NULL, 0},
+ { "contents", parse_cmd_contents, 1 },
+ { "info", parse_cmd_info, 1 },
+ { "flush", NULL, 0 },
+ { "mailmap", parse_cmd_mailmap, 1 },
};
static void batch_objects_command(struct batch_options *opt,
@@ -1128,7 +1152,7 @@ int cmd_cat_file(int argc,
opt_epts = (opt == 'e' || opt == 'p' || opt == 't' || opt == 's');
if (use_mailmap)
- read_mailmap(the_repository, &mailmap);
+ load_mailmap();
switch (batch.objects_filter.choice) {
case LOFC_DISABLED:
diff --git a/t/t4203-mailmap.sh b/t/t4203-mailmap.sh
index 74b7ddccb2..249548eb9b 100755
--- a/t/t4203-mailmap.sh
+++ b/t/t4203-mailmap.sh
@@ -1133,6 +1133,111 @@ test_expect_success 'git cat-file --batch-command returns correct size with --us
test_cmp expect actual
'
+test_expect_success 'git cat-file --batch-command mailmap yes enables mailmap mid-stream' '
+ test_when_finished "rm .mailmap" &&
+ cat >.mailmap <<-\EOF &&
+ C O Mitter <committer@example.com> Orig <orig@example.com>
+ EOF
+ commit_sha=$(git rev-parse HEAD) &&
+ git cat-file commit HEAD >commit_no_mailmap.out &&
+ git cat-file --use-mailmap commit HEAD >commit_mailmap.out &&
+ size_no_mailmap=$(wc -c <commit_no_mailmap.out) &&
+ size_mailmap=$(wc -c <commit_mailmap.out) &&
+ printf "info HEAD\nmailmap yes\ninfo HEAD\n" | git cat-file --batch-command >actual &&
+ echo $commit_sha commit $size_no_mailmap >expect &&
+ echo $commit_sha commit $size_mailmap >>expect &&
+ test_cmp expect actual
+'
+
+test_expect_success 'git cat-file --batch-command mailmap no disables mailmap mid-stream' '
+ test_when_finished "rm .mailmap" &&
+ cat >.mailmap <<-\EOF &&
+ C O Mitter <committer@example.com> Orig <orig@example.com>
+ EOF
+ commit_sha=$(git rev-parse HEAD) &&
+ git cat-file commit HEAD >commit_no_mailmap.out &&
+ git cat-file --use-mailmap commit HEAD >commit_mailmap.out &&
+ size_no_mailmap=$(wc -c <commit_no_mailmap.out) &&
+ size_mailmap=$(wc -c <commit_mailmap.out) &&
+ printf "mailmap yes\ninfo HEAD\nmailmap no\ninfo HEAD\n" | git cat-file --batch-command >actual &&
+ echo $commit_sha commit $size_mailmap >expect &&
+ echo $commit_sha commit $size_no_mailmap >>expect &&
+ test_cmp expect actual
+'
+
+test_expect_success 'git cat-file --batch-command mailmap works in --buffer mode' '
+ test_when_finished "rm .mailmap" &&
+ cat >.mailmap <<-\EOF &&
+ C O Mitter <committer@example.com> Orig <orig@example.com>
+ EOF
+ commit_sha=$(git rev-parse HEAD) &&
+ git cat-file commit HEAD >commit_no_mailmap.out &&
+ git cat-file --use-mailmap commit HEAD >commit_mailmap.out &&
+ size_no_mailmap=$(wc -c <commit_no_mailmap.out) &&
+ size_mailmap=$(wc -c <commit_mailmap.out) &&
+ printf "mailmap yes\ninfo HEAD\nmailmap no\ninfo HEAD\nflush\n" | git cat-file --batch-command --buffer >actual &&
+ echo $commit_sha commit $size_mailmap >expect &&
+ echo $commit_sha commit $size_no_mailmap >>expect &&
+ test_cmp expect actual
+'
+
+test_expect_success 'git cat-file --batch-command mailmap no overrides startup --mailmap' '
+ test_when_finished "rm .mailmap" &&
+ cat >.mailmap <<-\EOF &&
+ C O Mitter <committer@example.com> Orig <orig@example.com>
+ EOF
+ commit_sha=$(git rev-parse HEAD) &&
+ git cat-file --use-mailmap commit HEAD >commit_mailmap.out &&
+ size_mailmap=$(wc -c <commit_mailmap.out) &&
+ git cat-file commit HEAD >commit_no_mailmap.out &&
+ size_no_mailmap=$(wc -c <commit_no_mailmap.out) &&
+ printf "info HEAD\nmailmap no\ninfo HEAD\n" | \
+ git cat-file --mailmap --batch-command >actual &&
+ echo $commit_sha commit $size_mailmap >expect &&
+ echo $commit_sha commit $size_no_mailmap >>expect &&
+ test_cmp expect actual
+'
+
+test_expect_success 'git cat-file --batch-command mailmap yes overrides startup --no-mailmap' '
+ test_when_finished "rm .mailmap" &&
+ cat >.mailmap <<-\EOF &&
+ C O Mitter <committer@example.com> Orig <orig@example.com>
+ EOF
+ commit_sha=$(git rev-parse HEAD) &&
+ git cat-file commit HEAD >commit_no_mailmap.out &&
+ size_no_mailmap=$(wc -c <commit_no_mailmap.out) &&
+ git cat-file --use-mailmap commit HEAD >commit_mailmap.out &&
+ size_mailmap=$(wc -c <commit_mailmap.out) &&
+ printf "info HEAD\nmailmap yes\ninfo HEAD\n" | \
+ git cat-file --no-mailmap --batch-command >actual &&
+ echo $commit_sha commit $size_no_mailmap >expect &&
+ echo $commit_sha commit $size_mailmap >>expect &&
+ test_cmp expect actual
+'
+
+test_expect_success 'git cat-file --batch-command mailmap accepts true/false' '
+ test_when_finished "rm .mailmap" &&
+ cat >.mailmap <<-\EOF &&
+ C O Mitter <committer@example.com> Orig <orig@example.com>
+ EOF
+ commit_sha=$(git rev-parse HEAD) &&
+ git cat-file commit HEAD >commit_no_mailmap.out &&
+ size_no_mailmap=$(wc -c <commit_no_mailmap.out) &&
+ git cat-file --use-mailmap commit HEAD >commit_mailmap.out &&
+ size_mailmap=$(wc -c <commit_mailmap.out) &&
+ printf "mailmap true\ninfo HEAD\nmailmap false\ninfo HEAD\n" | \
+ git cat-file --batch-command >actual &&
+ echo $commit_sha commit $size_mailmap >expect &&
+ echo $commit_sha commit $size_no_mailmap >>expect &&
+ test_cmp expect actual
+'
+
+test_expect_success 'git cat-file --batch-command mailmap rejects invalid boolean' '
+ echo "mailmap maybe" >in &&
+ test_must_fail git cat-file --batch-command <in 2>err &&
+ test_grep "mailmap: invalid boolean .*maybe" err
+'
+
test_expect_success 'git cat-file --mailmap works with different author and committer' '
test_when_finished "rm .mailmap" &&
cat >.mailmap <<-\EOF &&
--
2.53.0
^ permalink raw reply related [flat|nested] 27+ messages in thread
* Re: [PATCH v2 1/1] cat-file: add mailmap subcommand to --batch-command
2026-03-29 8:28 ` [PATCH v2 1/1] " Siddharth Asthana
` (2 preceding siblings ...)
2026-03-30 10:37 ` Patrick Steinhardt
@ 2026-03-31 17:11 ` Jean-Noël AVILA
2026-03-31 17:49 ` Junio C Hamano
3 siblings, 1 reply; 27+ messages in thread
From: Jean-Noël AVILA @ 2026-03-31 17:11 UTC (permalink / raw)
To: git, Siddharth Asthana
Cc: karthik.188, christian.couder, ps, gitster, toon,
Siddharth Asthana
On Sunday, 29 March 2026 10:28:08 CEST Siddharth Asthana wrote:
> git-cat-file(1)'s --batch-command works with the --use-mailmap option,
> but this option needs to be set when the process is created. This means
> we cannot change this option mid-operation.
>
> At GitLab, Gitaly caches git-cat-file processes and it would be useful
> if --batch-command supported toggling mailmap dynamically with existing
> processes.
>
> Add a `mailmap` subcommand to --batch-command that takes a single
> argument: `yes` to enable mailmap and `no` to disable it. When enabled,
> mailmap data is loaded from disk on first use and kept in memory so that
> toggling back on does not require reloading.
>
> Suggested-by: Junio C Hamano <gitster@pobox.com>
> Signed-off-by: Siddharth Asthana <siddharthasthana31@gmail.com>
> ---
> CI: https://gitlab.com/gitlab-org/git/-/pipelines/2416081861
>
> Documentation/git-cat-file.adoc | 7 +++++
> builtin/cat-file.c | 30 ++++++++++++++++++---
> t/t4203-mailmap.sh | 48 +++++++++++++++++++++++++++++++++
> 3 files changed, 81 insertions(+), 4 deletions(-)
>
> diff --git a/Documentation/git-cat-file.adoc b/Documentation/git-cat-
file.adoc
> index c139f55a16..af32e929a8 100644
> --- a/Documentation/git-cat-file.adoc
> +++ b/Documentation/git-cat-file.adoc
> @@ -174,6 +174,13 @@ flush::
> since the beginning or since the last flush was issued. When `--
buffer`
> is used, no output will come until a `flush` is issued. When `--
buffer`
> is not used, commands are flushed each time without issuing `flush`.
> +
> +mailmap <yes|no>::
`yes` and `no` are keywords, and you want to express an alternative, do it
like this: `mailmap (yes|no)::`.
> + Enable or disable mailmap for subsequent `contents` and `info`
> + commands. When `yes` is given, mailmap data is loaded from disk on
> + first use and kept in memory; passing `yes` again does not reload
it.
> + When `no` is given, mailmap is disabled but the data stays in memory
> + so that a later `mailmap yes` does not need to reload it from disk.
> --
> +
>
Instead of detailing the alternatives in the same chapter, you could break it
into a sub-list:
Enable or disalbe mailmap for subsequent `contents` and `info` commands.
Possible values are:
`yes`;;
mailmap data is loaded from disk on first use and kept in memory; passing
`yes` again does not reload it.
`no`;;
mailmap is disabled but the data stays in memory so that a later `mailmap yes`
does not need to reload it from disk.
Thanks
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH v2 1/1] cat-file: add mailmap subcommand to --batch-command
2026-03-31 17:11 ` Jean-Noël AVILA
@ 2026-03-31 17:49 ` Junio C Hamano
2026-04-01 10:11 ` Jean-Noël Avila
0 siblings, 1 reply; 27+ messages in thread
From: Junio C Hamano @ 2026-03-31 17:49 UTC (permalink / raw)
To: Jean-Noël AVILA
Cc: git, Siddharth Asthana, karthik.188, christian.couder, ps, toon
Jean-Noël AVILA <jn.avila@free.fr> writes:
> On Sunday, 29 March 2026 10:28:08 CEST Siddharth Asthana wrote:
>> git-cat-file(1)'s --batch-command works with the --use-mailmap option,
>> but this option needs to be set when the process is created. This means
>> we cannot change this option mid-operation.
>>
>> At GitLab, Gitaly caches git-cat-file processes and it would be useful
>> if --batch-command supported toggling mailmap dynamically with existing
>> processes.
>>
>> Add a `mailmap` subcommand to --batch-command that takes a single
>> argument: `yes` to enable mailmap and `no` to disable it. When enabled,
>> mailmap data is loaded from disk on first use and kept in memory so that
>> toggling back on does not require reloading.
>>
>> Suggested-by: Junio C Hamano <gitster@pobox.com>
>> Signed-off-by: Siddharth Asthana <siddharthasthana31@gmail.com>
>> ---
>> CI: https://gitlab.com/gitlab-org/git/-/pipelines/2416081861
>>
>> Documentation/git-cat-file.adoc | 7 +++++
>> builtin/cat-file.c | 30 ++++++++++++++++++---
>> t/t4203-mailmap.sh | 48 +++++++++++++++++++++++++++++++++
>> 3 files changed, 81 insertions(+), 4 deletions(-)
>>
>> diff --git a/Documentation/git-cat-file.adoc b/Documentation/git-cat-
> file.adoc
>> index c139f55a16..af32e929a8 100644
>> --- a/Documentation/git-cat-file.adoc
>> +++ b/Documentation/git-cat-file.adoc
>> @@ -174,6 +174,13 @@ flush::
>> since the beginning or since the last flush was issued. When `--
> buffer`
>> is used, no output will come until a `flush` is issued. When `--
> buffer`
>> is not used, commands are flushed each time without issuing `flush`.
>> +
>> +mailmap <yes|no>::
>
> `yes` and `no` are keywords, and you want to express an alternative, do it
> like this: `mailmap (yes|no)::`.
Not
`mailmap (yes|no)`::
IOW, shouldn't the closing quote come before the double-colon?
>> + Enable or disable mailmap for subsequent `contents` and `info`
>> + commands. When `yes` is given, mailmap data is loaded from disk on
>> + first use and kept in memory; passing `yes` again does not reload
> it.
>> + When `no` is given, mailmap is disabled but the data stays in memory
>> + so that a later `mailmap yes` does not need to reload it from disk.
>> --
>> +
>>
>
> Instead of detailing the alternatives in the same chapter, you could break it
> into a sub-list:
>
> Enable or disalbe mailmap for subsequent `contents` and `info` commands.
> Possible values are:
> `yes`;;
> mailmap data is loaded from disk on first use and kept in memory; passing
> `yes` again does not reload it.
> `no`;;
> mailmap is disabled but the data stays in memory so that a later `mailmap yes`
> does not need to reload it from disk.
Great.
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH v3 1/1] cat-file: add mailmap subcommand to --batch-command
2026-03-31 12:11 ` [PATCH v3 1/1] " Siddharth Asthana
@ 2026-03-31 19:21 ` Junio C Hamano
2026-04-10 18:29 ` Junio C Hamano
0 siblings, 1 reply; 27+ messages in thread
From: Junio C Hamano @ 2026-03-31 19:21 UTC (permalink / raw)
To: Siddharth Asthana; +Cc: git, karthik.188, christian.couder, ps, toon
Siddharth Asthana <siddharthasthana31@gmail.com> writes:
> git-cat-file(1)'s --batch-command works with the --use-mailmap option,
> but this option needs to be set when the process is created. This means
> we cannot change this option mid-operation.
>
> At GitLab, Gitaly keeps interacting with a long-lived git-cat-file
> process and it would be useful if --batch-command supported toggling
> mailmap dynamically on an existing process.
>
> Add a `mailmap` subcommand to --batch-command that takes a boolean
> argument. The command now uses `git_parse_maybe_bool()` and supports all
> standard Git boolean values. Mailmap data is loaded lazily and kept in
I do not think you want to say "now uses `git_parse_maybe_bool()`".
Nobody is interested in the difference relative to what you did in
the previous iteration.
... that takes a boolean argument (usual ways you can specify a
boolean value like 'yes', 'true', etc., are supported).
> +static void load_mailmap(void)
> +{
> + if (mailmap.strdup_strings)
> + return;
> +
> + read_mailmap(the_repository, &mailmap);
> +}
This, especially the early return condition, may deserve a bit of
in-code comment, as "a used string_list has the .strdup_strings bit
set" is not a generally applicable rule.
/*
* The mailmap is initialized with .strdup_strings set to 0,
* but read_mailmap() sets the bit to 1 (this is true even when
* not a single mailmap entry is read), so it can be used for
* lazy loading.
*/
or something, perhaps?
> @@ -692,6 +700,21 @@ static void parse_cmd_info(struct batch_options *opt,
> batch_one_object(line, output, opt, data);
> }
>
> +static void parse_cmd_mailmap(struct batch_options *opt UNUSED,
> + const char *line,
> + struct strbuf *output UNUSED,
> + struct expand_data *data UNUSED)
> +{
> + int value = git_parse_maybe_bool(line);
As "line" is never NULL, one standard way to spell a boolean True is
not available to the callers, namely, "mailmap<EOL>" (like how a
configuration file entry "[core] bare" means "[core] bare = true"),
but that is probably OK. "mailmap<SP><EOL>" may be interpreted as
feeding an empty string as an argument, which is "false" to the
git_parse_maybe_bool() function. That might be surprising.
Nothing actionable in the above comment (other than perhaps as a
hint for documentation update).
> + if (value < 0)
> + die(_("mailmap: invalid boolean '%s'"), line);
> +
> + if (value > 0)
> + load_mailmap();
> + use_mailmap = value;
> +}
Hmph, why not use use_mailmap from the beginning of the function
without introducing the local variable "value"? Nothing in
load_mailmap() pays attention to the current value of use_mailmap
so I do not see much point in preserving the current status until
the last minute.
Thanks.
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH v2 1/1] cat-file: add mailmap subcommand to --batch-command
2026-03-31 17:49 ` Junio C Hamano
@ 2026-04-01 10:11 ` Jean-Noël Avila
0 siblings, 0 replies; 27+ messages in thread
From: Jean-Noël Avila @ 2026-04-01 10:11 UTC (permalink / raw)
To: Junio C Hamano
Cc: git, Siddharth Asthana, karthik.188, christian.couder, ps, toon
On 3/31/26 19:49, Junio C Hamano wrote:
> Jean-Noël AVILA <jn.avila@free.fr> writes:
>
>> On Sunday, 29 March 2026 10:28:08 CEST Siddharth Asthana wrote:
>>> git-cat-file(1)'s --batch-command works with the --use-mailmap option,
>>> but this option needs to be set when the process is created. This means
>>> we cannot change this option mid-operation.
>>>
>>> At GitLab, Gitaly caches git-cat-file processes and it would be useful
>>> if --batch-command supported toggling mailmap dynamically with existing
>>> processes.
>>>
>>> Add a `mailmap` subcommand to --batch-command that takes a single
>>> argument: `yes` to enable mailmap and `no` to disable it. When enabled,
>>> mailmap data is loaded from disk on first use and kept in memory so that
>>> toggling back on does not require reloading.
>>>
>>> Suggested-by: Junio C Hamano <gitster@pobox.com>
>>> Signed-off-by: Siddharth Asthana <siddharthasthana31@gmail.com>
>>> ---
>>> CI: https://gitlab.com/gitlab-org/git/-/pipelines/2416081861
>>>
>>> Documentation/git-cat-file.adoc | 7 +++++
>>> builtin/cat-file.c | 30 ++++++++++++++++++---
>>> t/t4203-mailmap.sh | 48 +++++++++++++++++++++++++++++++++
>>> 3 files changed, 81 insertions(+), 4 deletions(-)
>>>
>>> diff --git a/Documentation/git-cat-file.adoc b/Documentation/git-cat-
>> file.adoc
>>> index c139f55a16..af32e929a8 100644
>>> --- a/Documentation/git-cat-file.adoc
>>> +++ b/Documentation/git-cat-file.adoc
>>> @@ -174,6 +174,13 @@ flush::
>>> since the beginning or since the last flush was issued. When `--
>> buffer`
>>> is used, no output will come until a `flush` is issued. When `--
>> buffer`
>>> is not used, commands are flushed each time without issuing `flush`.
>>> +
>>> +mailmap <yes|no>::
>>
>> `yes` and `no` are keywords, and you want to express an alternative, do it
>> like this: `mailmap (yes|no)::`.
>
> Not
>
> `mailmap (yes|no)`::
>
> IOW, shouldn't the closing quote come before the double-colon?
Oops, you're completely right!
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH v3 1/1] cat-file: add mailmap subcommand to --batch-command
2026-03-31 19:21 ` Junio C Hamano
@ 2026-04-10 18:29 ` Junio C Hamano
0 siblings, 0 replies; 27+ messages in thread
From: Junio C Hamano @ 2026-04-10 18:29 UTC (permalink / raw)
To: Siddharth Asthana; +Cc: git, karthik.188, christian.couder, ps, toon
Junio C Hamano <gitster@pobox.com> writes:
> Siddharth Asthana <siddharthasthana31@gmail.com> writes:
>
>> git-cat-file(1)'s --batch-command works with the --use-mailmap option,
>> but this option needs to be set when the process is created. This means
>> we cannot change this option mid-operation.
>>
>> At GitLab, Gitaly keeps interacting with a long-lived git-cat-file
>> process and it would be useful if --batch-command supported toggling
>> mailmap dynamically on an existing process.
>>
>> Add a `mailmap` subcommand to --batch-command that takes a boolean
>> argument. The command now uses `git_parse_maybe_bool()` and supports all
>> standard Git boolean values. Mailmap data is loaded lazily and kept in
>
> I do not think you want to say "now uses `git_parse_maybe_bool()`".
> Nobody is interested in the difference relative to what you did in
> the previous iteration.
>
> ... that takes a boolean argument (usual ways you can specify a
> boolean value like 'yes', 'true', etc., are supported).
>
>> +static void load_mailmap(void)
>> +{
>> + if (mailmap.strdup_strings)
>> + return;
>> +
>> + read_mailmap(the_repository, &mailmap);
>> +}
>
> This, especially the early return condition, may deserve a bit of
> in-code comment, as "a used string_list has the .strdup_strings bit
> set" is not a generally applicable rule.
>
> /*
> * The mailmap is initialized with .strdup_strings set to 0,
> * but read_mailmap() sets the bit to 1 (this is true even when
> * not a single mailmap entry is read), so it can be used for
> * lazy loading.
> */
>
> or something, perhaps?
>
>> @@ -692,6 +700,21 @@ static void parse_cmd_info(struct batch_options *opt,
>> batch_one_object(line, output, opt, data);
>> }
>>
>> +static void parse_cmd_mailmap(struct batch_options *opt UNUSED,
>> + const char *line,
>> + struct strbuf *output UNUSED,
>> + struct expand_data *data UNUSED)
>> +{
>> + int value = git_parse_maybe_bool(line);
>
> As "line" is never NULL, one standard way to spell a boolean True is
> not available to the callers, namely, "mailmap<EOL>" (like how a
> configuration file entry "[core] bare" means "[core] bare = true"),
> but that is probably OK. "mailmap<SP><EOL>" may be interpreted as
> feeding an empty string as an argument, which is "false" to the
> git_parse_maybe_bool() function. That might be surprising.
>
> Nothing actionable in the above comment (other than perhaps as a
> hint for documentation update).
>
>> + if (value < 0)
>> + die(_("mailmap: invalid boolean '%s'"), line);
>> +
>> + if (value > 0)
>> + load_mailmap();
>> + use_mailmap = value;
>> +}
>
> Hmph, why not use use_mailmap from the beginning of the function
> without introducing the local variable "value"? Nothing in
> load_mailmap() pays attention to the current value of use_mailmap
> so I do not see much point in preserving the current status until
> the last minute.
>
> Thanks.
The thread went dark since this message.
I do not want to see energy spent on a viable topic so far disappear
into a void without achieving anything. Let's push the topic over
the finish line with futher work.
Thanks.
^ permalink raw reply [flat|nested] 27+ messages in thread
* [PATCH v4 0/1] cat-file: add mailmap subcommand to --batch-command
2026-03-31 12:11 ` [PATCH v3 0/1] " Siddharth Asthana
2026-03-31 12:11 ` [PATCH v3 1/1] " Siddharth Asthana
@ 2026-04-15 15:09 ` Siddharth Asthana
2026-04-15 15:09 ` [PATCH v4 1/1] " Siddharth Asthana
2026-04-16 3:32 ` [PATCH v5 0/1] " Siddharth Asthana
1 sibling, 2 replies; 27+ messages in thread
From: Siddharth Asthana @ 2026-04-15 15:09 UTC (permalink / raw)
To: git
Cc: karthik.188, christian.couder, ps, gitster, toon, jn.avila,
Siddharth Asthana
git-cat-file(1)'s --batch-command works with the --use-mailmap option,
but this option needs to be set when the process is created. This means
we cannot change this option mid-operation.
At GitLab, Gitaly keeps interacting with a long-lived git-cat-file
process and it would be useful if --batch-command supported toggling
mailmap dynamically on an existing process.
This patch adds a `mailmap` subcommand to --batch-command that accepts
a boolean argument and toggles mailmap dynamically for subsequent
commands.
The series is based on top of 5361983c07 (The 22nd batch, 2026-03-21).
CI: https://gitlab.com/gitlab-org/git/-/pipelines/2455043368
Changes in v4:
- Reword commit message: describe boolean support without mentioning
internal function names, following Junio's suggestion.
- Add an in-code comment explaining why `mailmap.strdup_strings` can be
used as the "already loaded" check in `load_mailmap()`.
- Drop local `value` variable in `parse_cmd_mailmap()` and assign
directly to `use_mailmap`.
- Fix documentation syntax: place the closing backtick before `::`
and break the description into a `;;` sub-list for `true`/`false`
effects.
- Link to v3: https://lore.kernel.org/git/xmqqv7dyoei6.fsf@gitster.g/T/#m0a109f3eb5129e619ecec5f2d58ead0c5a49a4f3
- Link to v2: https://lore.kernel.org/git/xmqqv7dyoei6.fsf@gitster.g/T/#m445eab3b309bded92d1b130d225b882c73988ff2
- Link to v1: https://public-inbox.org/git/a4ec7bfa-f16b-4505-9b37-d3dd137e93cb@gmail.com/T/#m5c62fb6ad0fbcc99a706dba4c78b66359c247acd
Thanks,
Siddharth
---
Siddharth Asthana (1):
cat-file: add mailmap subcommand to --batch-command
Documentation/git-cat-file.adoc | 12 +++++
builtin/cat-file.c | 37 ++++++++++++--
t/t4203-mailmap.sh | 105 ++++++++++++++++++++++++++++++++++++++++
3 files changed, 150 insertions(+), 4 deletions(-)
Range-diff versus v3:
1: dbc1a003a5 ! 1: 25ebffe39e cat-file: add mailmap subcommand to --batch-command
@@ Commit message
mailmap dynamically on an existing process.
Add a `mailmap` subcommand to --batch-command that takes a boolean
- argument. The command now uses `git_parse_maybe_bool()` and supports all
- standard Git boolean values. Mailmap data is loaded lazily and kept in
- memory, while a helper centralizes the one-time load path used both at
- startup and from the batch-command handler.
+ argument (usual ways you can specify a boolean value like 'yes', 'true',
+ etc., are supported). Mailmap data is loaded lazily and kept in memory,
+ while a helper centralizes the one-time load path used both at startup
+ and from the batch-command handler.
Extend tests to cover runtime toggling, startup option interactions
(`--mailmap`/`--no-mailmap`), accepted boolean forms, and invalid values.
@@ Documentation/git-cat-file.adoc: flush::
is used, no output will come until a `flush` is issued. When `--buffer`
is not used, commands are flushed each time without issuing `flush`.
+
-+mailmap <bool>::
-+ Enable or disable mailmap for subsequent commands.
++`mailmap (<bool>)`::
++ Enable or disable mailmap for subsequent commands. The `<bool>`
++ argument accepts the same boolean values as linkgit:git-config[1].
++ Possible effects are:
++
-+The `<bool>` argument accepts the same boolean values as
-+linkgit:git-config[1]. When enabled, mailmap data is loaded on first
-+use and kept in memory until the process exits.
++`true`;;
++ Mailmap data is loaded on first use and kept in memory until the
++ process exits. Passing `true` again does not reload the data.
++`false`;;
++ Mailmap replacements are disabled for subsequent commands, but data
++ already loaded stays in memory.
--
+
@@ builtin/cat-file.c: static int use_mailmap;
static char *replace_idents_using_mailmap(char *, size_t *);
++/*
++ * The mailmap is initialized with .strdup_strings set to 0,
++ * but read_mailmap() sets the bit to 1 (this is true even when
++ * not a single mailmap entry is read), so it can be used for
++ * lazy loading.
++ */
+static void load_mailmap(void)
+{
+ if (mailmap.strdup_strings)
@@ builtin/cat-file.c: static void parse_cmd_info(struct batch_options *opt,
+ struct strbuf *output UNUSED,
+ struct expand_data *data UNUSED)
+{
-+ int value = git_parse_maybe_bool(line);
++ use_mailmap = git_parse_maybe_bool(line);
+
-+ if (value < 0)
++ if (use_mailmap < 0)
+ die(_("mailmap: invalid boolean '%s'"), line);
+
-+ if (value > 0)
++ if (use_mailmap)
+ load_mailmap();
-+ use_mailmap = value;
+}
+
static void dispatch_calls(struct batch_options *opt,
base-commit: 5361983c075154725be47b65cca9a2421789e410
--
2.53.0
^ permalink raw reply [flat|nested] 27+ messages in thread
* [PATCH v4 1/1] cat-file: add mailmap subcommand to --batch-command
2026-04-15 15:09 ` [PATCH v4 0/1] " Siddharth Asthana
@ 2026-04-15 15:09 ` Siddharth Asthana
2026-04-15 18:28 ` Junio C Hamano
2026-04-16 3:32 ` [PATCH v5 0/1] " Siddharth Asthana
1 sibling, 1 reply; 27+ messages in thread
From: Siddharth Asthana @ 2026-04-15 15:09 UTC (permalink / raw)
To: git
Cc: karthik.188, christian.couder, ps, gitster, toon, jn.avila,
Siddharth Asthana
git-cat-file(1)'s --batch-command works with the --use-mailmap option,
but this option needs to be set when the process is created. This means
we cannot change this option mid-operation.
At GitLab, Gitaly keeps interacting with a long-lived git-cat-file
process and it would be useful if --batch-command supported toggling
mailmap dynamically on an existing process.
Add a `mailmap` subcommand to --batch-command that takes a boolean
argument (usual ways you can specify a boolean value like 'yes', 'true',
etc., are supported). Mailmap data is loaded lazily and kept in memory,
while a helper centralizes the one-time load path used both at startup
and from the batch-command handler.
Extend tests to cover runtime toggling, startup option interactions
(`--mailmap`/`--no-mailmap`), accepted boolean forms, and invalid values.
Signed-off-by: Siddharth Asthana <siddharthasthana31@gmail.com>
---
CI: https://gitlab.com/gitlab-org/git/-/pipelines/2455043368
Documentation/git-cat-file.adoc | 12 ++++
builtin/cat-file.c | 37 +++++++++--
t/t4203-mailmap.sh | 105 ++++++++++++++++++++++++++++++++
3 files changed, 150 insertions(+), 4 deletions(-)
diff --git a/Documentation/git-cat-file.adoc b/Documentation/git-cat-file.adoc
index c139f55a16..0f499c9d1b 100644
--- a/Documentation/git-cat-file.adoc
+++ b/Documentation/git-cat-file.adoc
@@ -174,6 +174,18 @@ flush::
since the beginning or since the last flush was issued. When `--buffer`
is used, no output will come until a `flush` is issued. When `--buffer`
is not used, commands are flushed each time without issuing `flush`.
+
+`mailmap (<bool>)`::
+ Enable or disable mailmap for subsequent commands. The `<bool>`
+ argument accepts the same boolean values as linkgit:git-config[1].
+ Possible effects are:
++
+`true`;;
+ Mailmap data is loaded on first use and kept in memory until the
+ process exits. Passing `true` again does not reload the data.
+`false`;;
+ Mailmap replacements are disabled for subsequent commands, but data
+ already loaded stays in memory.
--
+
diff --git a/builtin/cat-file.c b/builtin/cat-file.c
index d9fbad5358..fa45f774d7 100644
--- a/builtin/cat-file.c
+++ b/builtin/cat-file.c
@@ -57,6 +57,20 @@ static int use_mailmap;
static char *replace_idents_using_mailmap(char *, size_t *);
+/*
+ * The mailmap is initialized with .strdup_strings set to 0,
+ * but read_mailmap() sets the bit to 1 (this is true even when
+ * not a single mailmap entry is read), so it can be used for
+ * lazy loading.
+ */
+static void load_mailmap(void)
+{
+ if (mailmap.strdup_strings)
+ return;
+
+ read_mailmap(the_repository, &mailmap);
+}
+
static char *replace_idents_using_mailmap(char *object_buf, size_t *size)
{
struct strbuf sb = STRBUF_INIT;
@@ -692,6 +706,20 @@ static void parse_cmd_info(struct batch_options *opt,
batch_one_object(line, output, opt, data);
}
+static void parse_cmd_mailmap(struct batch_options *opt UNUSED,
+ const char *line,
+ struct strbuf *output UNUSED,
+ struct expand_data *data UNUSED)
+{
+ use_mailmap = git_parse_maybe_bool(line);
+
+ if (use_mailmap < 0)
+ die(_("mailmap: invalid boolean '%s'"), line);
+
+ if (use_mailmap)
+ load_mailmap();
+}
+
static void dispatch_calls(struct batch_options *opt,
struct strbuf *output,
struct expand_data *data,
@@ -725,9 +753,10 @@ static const struct parse_cmd {
parse_cmd_fn_t fn;
unsigned takes_args;
} commands[] = {
- { "contents", parse_cmd_contents, 1},
- { "info", parse_cmd_info, 1},
- { "flush", NULL, 0},
+ { "contents", parse_cmd_contents, 1 },
+ { "info", parse_cmd_info, 1 },
+ { "flush", NULL, 0 },
+ { "mailmap", parse_cmd_mailmap, 1 },
};
static void batch_objects_command(struct batch_options *opt,
@@ -1131,7 +1160,7 @@ int cmd_cat_file(int argc,
opt_epts = (opt == 'e' || opt == 'p' || opt == 't' || opt == 's');
if (use_mailmap)
- read_mailmap(the_repository, &mailmap);
+ load_mailmap();
switch (batch.objects_filter.choice) {
case LOFC_DISABLED:
diff --git a/t/t4203-mailmap.sh b/t/t4203-mailmap.sh
index 74b7ddccb2..249548eb9b 100755
--- a/t/t4203-mailmap.sh
+++ b/t/t4203-mailmap.sh
@@ -1133,6 +1133,111 @@ test_expect_success 'git cat-file --batch-command returns correct size with --us
test_cmp expect actual
'
+test_expect_success 'git cat-file --batch-command mailmap yes enables mailmap mid-stream' '
+ test_when_finished "rm .mailmap" &&
+ cat >.mailmap <<-\EOF &&
+ C O Mitter <committer@example.com> Orig <orig@example.com>
+ EOF
+ commit_sha=$(git rev-parse HEAD) &&
+ git cat-file commit HEAD >commit_no_mailmap.out &&
+ git cat-file --use-mailmap commit HEAD >commit_mailmap.out &&
+ size_no_mailmap=$(wc -c <commit_no_mailmap.out) &&
+ size_mailmap=$(wc -c <commit_mailmap.out) &&
+ printf "info HEAD\nmailmap yes\ninfo HEAD\n" | git cat-file --batch-command >actual &&
+ echo $commit_sha commit $size_no_mailmap >expect &&
+ echo $commit_sha commit $size_mailmap >>expect &&
+ test_cmp expect actual
+'
+
+test_expect_success 'git cat-file --batch-command mailmap no disables mailmap mid-stream' '
+ test_when_finished "rm .mailmap" &&
+ cat >.mailmap <<-\EOF &&
+ C O Mitter <committer@example.com> Orig <orig@example.com>
+ EOF
+ commit_sha=$(git rev-parse HEAD) &&
+ git cat-file commit HEAD >commit_no_mailmap.out &&
+ git cat-file --use-mailmap commit HEAD >commit_mailmap.out &&
+ size_no_mailmap=$(wc -c <commit_no_mailmap.out) &&
+ size_mailmap=$(wc -c <commit_mailmap.out) &&
+ printf "mailmap yes\ninfo HEAD\nmailmap no\ninfo HEAD\n" | git cat-file --batch-command >actual &&
+ echo $commit_sha commit $size_mailmap >expect &&
+ echo $commit_sha commit $size_no_mailmap >>expect &&
+ test_cmp expect actual
+'
+
+test_expect_success 'git cat-file --batch-command mailmap works in --buffer mode' '
+ test_when_finished "rm .mailmap" &&
+ cat >.mailmap <<-\EOF &&
+ C O Mitter <committer@example.com> Orig <orig@example.com>
+ EOF
+ commit_sha=$(git rev-parse HEAD) &&
+ git cat-file commit HEAD >commit_no_mailmap.out &&
+ git cat-file --use-mailmap commit HEAD >commit_mailmap.out &&
+ size_no_mailmap=$(wc -c <commit_no_mailmap.out) &&
+ size_mailmap=$(wc -c <commit_mailmap.out) &&
+ printf "mailmap yes\ninfo HEAD\nmailmap no\ninfo HEAD\nflush\n" | git cat-file --batch-command --buffer >actual &&
+ echo $commit_sha commit $size_mailmap >expect &&
+ echo $commit_sha commit $size_no_mailmap >>expect &&
+ test_cmp expect actual
+'
+
+test_expect_success 'git cat-file --batch-command mailmap no overrides startup --mailmap' '
+ test_when_finished "rm .mailmap" &&
+ cat >.mailmap <<-\EOF &&
+ C O Mitter <committer@example.com> Orig <orig@example.com>
+ EOF
+ commit_sha=$(git rev-parse HEAD) &&
+ git cat-file --use-mailmap commit HEAD >commit_mailmap.out &&
+ size_mailmap=$(wc -c <commit_mailmap.out) &&
+ git cat-file commit HEAD >commit_no_mailmap.out &&
+ size_no_mailmap=$(wc -c <commit_no_mailmap.out) &&
+ printf "info HEAD\nmailmap no\ninfo HEAD\n" | \
+ git cat-file --mailmap --batch-command >actual &&
+ echo $commit_sha commit $size_mailmap >expect &&
+ echo $commit_sha commit $size_no_mailmap >>expect &&
+ test_cmp expect actual
+'
+
+test_expect_success 'git cat-file --batch-command mailmap yes overrides startup --no-mailmap' '
+ test_when_finished "rm .mailmap" &&
+ cat >.mailmap <<-\EOF &&
+ C O Mitter <committer@example.com> Orig <orig@example.com>
+ EOF
+ commit_sha=$(git rev-parse HEAD) &&
+ git cat-file commit HEAD >commit_no_mailmap.out &&
+ size_no_mailmap=$(wc -c <commit_no_mailmap.out) &&
+ git cat-file --use-mailmap commit HEAD >commit_mailmap.out &&
+ size_mailmap=$(wc -c <commit_mailmap.out) &&
+ printf "info HEAD\nmailmap yes\ninfo HEAD\n" | \
+ git cat-file --no-mailmap --batch-command >actual &&
+ echo $commit_sha commit $size_no_mailmap >expect &&
+ echo $commit_sha commit $size_mailmap >>expect &&
+ test_cmp expect actual
+'
+
+test_expect_success 'git cat-file --batch-command mailmap accepts true/false' '
+ test_when_finished "rm .mailmap" &&
+ cat >.mailmap <<-\EOF &&
+ C O Mitter <committer@example.com> Orig <orig@example.com>
+ EOF
+ commit_sha=$(git rev-parse HEAD) &&
+ git cat-file commit HEAD >commit_no_mailmap.out &&
+ size_no_mailmap=$(wc -c <commit_no_mailmap.out) &&
+ git cat-file --use-mailmap commit HEAD >commit_mailmap.out &&
+ size_mailmap=$(wc -c <commit_mailmap.out) &&
+ printf "mailmap true\ninfo HEAD\nmailmap false\ninfo HEAD\n" | \
+ git cat-file --batch-command >actual &&
+ echo $commit_sha commit $size_mailmap >expect &&
+ echo $commit_sha commit $size_no_mailmap >>expect &&
+ test_cmp expect actual
+'
+
+test_expect_success 'git cat-file --batch-command mailmap rejects invalid boolean' '
+ echo "mailmap maybe" >in &&
+ test_must_fail git cat-file --batch-command <in 2>err &&
+ test_grep "mailmap: invalid boolean .*maybe" err
+'
+
test_expect_success 'git cat-file --mailmap works with different author and committer' '
test_when_finished "rm .mailmap" &&
cat >.mailmap <<-\EOF &&
--
2.53.0
^ permalink raw reply related [flat|nested] 27+ messages in thread
* Re: [PATCH v4 1/1] cat-file: add mailmap subcommand to --batch-command
2026-04-15 15:09 ` [PATCH v4 1/1] " Siddharth Asthana
@ 2026-04-15 18:28 ` Junio C Hamano
2026-04-16 3:08 ` Siddharth Asthana
0 siblings, 1 reply; 27+ messages in thread
From: Junio C Hamano @ 2026-04-15 18:28 UTC (permalink / raw)
To: Siddharth Asthana; +Cc: git, karthik.188, christian.couder, ps, toon, jn.avila
Siddharth Asthana <siddharthasthana31@gmail.com> writes:
> diff --git a/Documentation/git-cat-file.adoc b/Documentation/git-cat-file.adoc
> index c139f55a16..0f499c9d1b 100644
> --- a/Documentation/git-cat-file.adoc
> +++ b/Documentation/git-cat-file.adoc
> @@ -174,6 +174,18 @@ flush::
> since the beginning or since the last flush was issued. When `--buffer`
> is used, no output will come until a `flush` is issued. When `--buffer`
> is not used, commands are flushed each time without issuing `flush`.
> +
> +`mailmap (<bool>)`::
> + Enable or disable mailmap for subsequent commands. The `<bool>`
> + argument accepts the same boolean values as linkgit:git-config[1].
> + Possible effects are:
> ++
> +`true`;;
> + Mailmap data is loaded on first use and kept in memory until the
> + process exits. Passing `true` again does not reload the data.
> +`false`;;
> + Mailmap replacements are disabled for subsequent commands, but data
> + already loaded stays in memory.
> --
> +
While the above may not be telling any lies, I think the focus of
the explanation is placed on a wrong thing. What primarily matters
to end-users is that toggling 'mailmap' to true makes the mailmap
applied to identities before they appear in the output and false
makes the identities output without modification. The fact that you
read the mailmap data only once and keep it around even when
toggling the feature off, just in case the feature gets turned on
again, is an implementation detail that is of much lessor interest
to end users, no?
Perhaps delete everything from "Possible effects are" and replace it
with a brief explanation, e.g.,
`mailmap (<bool>)`::
Enable or disable mailmap for subsequent commands. The `<bool>`
argument accepts the same boolean values as linkgit:git-config[1].
The mailmap data is read upon the first use and only once,
even after the `mailmap` command is given multiple times to
toggle it off and then on back again.
would be sufficient (I would omit "even after ..." part, if I were
writing it). What is more important than the optimization aspect of
this implementation detail to end users is that we do not re-read,
so if you update the file while you are running "cat-file --batch",
even giving 'mailmap off; mailmap on' would not cause it to re-read
the updated data, and "upon the first use and only once" should be
sufficient to understand that.
The implementation looks great. I do not recall how good the tests
were but this round does not change anything there since the
previous iteration.
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH v4 1/1] cat-file: add mailmap subcommand to --batch-command
2026-04-15 18:28 ` Junio C Hamano
@ 2026-04-16 3:08 ` Siddharth Asthana
0 siblings, 0 replies; 27+ messages in thread
From: Siddharth Asthana @ 2026-04-16 3:08 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git, karthik.188, christian.couder, ps, toon, jn.avila
On 15/04/26 23:58, Junio C Hamano wrote:
> Siddharth Asthana <siddharthasthana31@gmail.com> writes:
>
>> diff --git a/Documentation/git-cat-file.adoc b/Documentation/git-cat-file.adoc
>> index c139f55a16..0f499c9d1b 100644
>> --- a/Documentation/git-cat-file.adoc
>> +++ b/Documentation/git-cat-file.adoc
>> @@ -174,6 +174,18 @@ flush::
>> since the beginning or since the last flush was issued. When `--buffer`
>> is used, no output will come until a `flush` is issued. When `--buffer`
>> is not used, commands are flushed each time without issuing `flush`.
>> +
>> +`mailmap (<bool>)`::
>> + Enable or disable mailmap for subsequent commands. The `<bool>`
>> + argument accepts the same boolean values as linkgit:git-config[1].
>> + Possible effects are:
>> ++
>> +`true`;;
>> + Mailmap data is loaded on first use and kept in memory until the
>> + process exits. Passing `true` again does not reload the data.
>> +`false`;;
>> + Mailmap replacements are disabled for subsequent commands, but data
>> + already loaded stays in memory.
>> --
>> +
>
> While the above may not be telling any lies, I think the focus of
> the explanation is placed on a wrong thing. What primarily matters
> to end-users is that toggling 'mailmap' to true makes the mailmap
> applied to identities before they appear in the output and false
> makes the identities output without modification. The fact that you
Make sense, the sub-list was over-explaining implementation details that
users don't need to care about.
> read the mailmap data only once and keep it around even when
> toggling the feature off, just in case the feature gets turned on
> again, is an implementation detail that is of much lessor interest
> to end users, no?
>
> Perhaps delete everything from "Possible effects are" and replace it
> with a brief explanation, e.g.,
>
> `mailmap (<bool>)`::
> Enable or disable mailmap for subsequent commands. The `<bool>`
> argument accepts the same boolean values as linkgit:git-config[1].
> The mailmap data is read upon the first use and only once,
> even after the `mailmap` command is given multiple times to
> toggle it off and then on back again.
>
> would be sufficient (I would omit "even after ..." part, if I were
> writing it). What is more important than the optimization aspect of
Agreed, I wend with the shorter version without the "even after" part.
> this implementation detail to end users is that we do not re-read,
> so if you update the file while you are running "cat-file --batch",
> even giving 'mailmap off; mailmap on' would not cause it to re-read
> the updated data, and "upon the first use and only once" should be
> sufficient to understand that.
>
> The implementation looks great. I do not recall how good the tests
> were but this round does not change anything there since the
> previous iteration.
Thnaks! I will send v5 with just this doc change.
Siddharth
^ permalink raw reply [flat|nested] 27+ messages in thread
* [PATCH v5 0/1] cat-file: add mailmap subcommand to --batch-command
2026-04-15 15:09 ` [PATCH v4 0/1] " Siddharth Asthana
2026-04-15 15:09 ` [PATCH v4 1/1] " Siddharth Asthana
@ 2026-04-16 3:32 ` Siddharth Asthana
2026-04-16 3:32 ` [PATCH v5 1/1] " Siddharth Asthana
1 sibling, 1 reply; 27+ messages in thread
From: Siddharth Asthana @ 2026-04-16 3:32 UTC (permalink / raw)
To: git
Cc: karthik.188, christian.couder, ps, gitster, toon, jn.avila,
Siddharth Asthana
git-cat-file(1)'s --batch-command works with the --use-mailmap option,
but this option needs to be set when the process is created. This means
we cannot change this option mid-operation.
At GitLab, Gitaly keeps interacting with a long-lived git-cat-file
process and it would be useful if --batch-command supported toggling
mailmap dynamically on an existing process.
This patch adds a `mailmap` subcommand to --batch-command that accepts
a boolean argument and toggles mailmap dynamically for subsequent
commands.
The series is based on top of 5361983c07 (The 22nd batch, 2026-03-21).
CI: https://gitlab.com/gitlab-org/git/-/pipelines/2456596910
Changes in v5:
- Simplify documentation: remove the `;;` sub-list describing
`true`/`false` effects and replace with a single sentence noting
that mailmap data is read upon the first use and only once.
- Link to v4: https://lore.kernel.org/git/20260415150943.40493-1-siddharthasthana31@gmail.com/T/#m5226263dafcf5c774c080a6688e9af0f402003c0
- Link to v3: https://lore.kernel.org/git/xmqqv7dyoei6.fsf@gitster.g/T/#m0a109f3eb5129e619ecec5f2d58ead0c5a49a4f3
- Link to v2: https://lore.kernel.org/git/xmqqv7dyoei6.fsf@gitster.g/T/#m445eab3b309bded92d1b130d225b882c73988ff2
- Link to v1: https://public-inbox.org/git/a4ec7bfa-f16b-4505-9b37-d3dd137e93cb@gmail.com/T/#m5c62fb6ad0fbcc99a706dba4c78b66359c247acd
Thanks,
Siddharth
---
Siddharth Asthana (1):
cat-file: add mailmap subcommand to --batch-command
Documentation/git-cat-file.adoc | 5 ++
builtin/cat-file.c | 37 ++++++++++++--
t/t4203-mailmap.sh | 105 ++++++++++++++++++++++++++++++++++++++++
3 files changed, 143 insertions(+), 4 deletions(-)
Range-diff versus v4:
1: 25ebffe39e ! 1: b4d6f08b43 cat-file: add mailmap subcommand to --batch-command
@@ Documentation/git-cat-file.adoc: flush::
+`mailmap (<bool>)`::
+ Enable or disable mailmap for subsequent commands. The `<bool>`
+ argument accepts the same boolean values as linkgit:git-config[1].
-+ Possible effects are:
-++
-+`true`;;
-+ Mailmap data is loaded on first use and kept in memory until the
-+ process exits. Passing `true` again does not reload the data.
-+`false`;;
-+ Mailmap replacements are disabled for subsequent commands, but data
-+ already loaded stays in memory.
++ The mailmap data is read upon the first use and only once.
--
+
base-commit: 5361983c075154725be47b65cca9a2421789e410
--
2.53.0
^ permalink raw reply [flat|nested] 27+ messages in thread
* [PATCH v5 1/1] cat-file: add mailmap subcommand to --batch-command
2026-04-16 3:32 ` [PATCH v5 0/1] " Siddharth Asthana
@ 2026-04-16 3:32 ` Siddharth Asthana
0 siblings, 0 replies; 27+ messages in thread
From: Siddharth Asthana @ 2026-04-16 3:32 UTC (permalink / raw)
To: git
Cc: karthik.188, christian.couder, ps, gitster, toon, jn.avila,
Siddharth Asthana
git-cat-file(1)'s --batch-command works with the --use-mailmap option,
but this option needs to be set when the process is created. This means
we cannot change this option mid-operation.
At GitLab, Gitaly keeps interacting with a long-lived git-cat-file
process and it would be useful if --batch-command supported toggling
mailmap dynamically on an existing process.
Add a `mailmap` subcommand to --batch-command that takes a boolean
argument (usual ways you can specify a boolean value like 'yes', 'true',
etc., are supported). Mailmap data is loaded lazily and kept in memory,
while a helper centralizes the one-time load path used both at startup
and from the batch-command handler.
Extend tests to cover runtime toggling, startup option interactions
(`--mailmap`/`--no-mailmap`), accepted boolean forms, and invalid values.
Signed-off-by: Siddharth Asthana <siddharthasthana31@gmail.com>
---
CI: https://gitlab.com/gitlab-org/git/-/pipelines/2456596910
Documentation/git-cat-file.adoc | 5 ++
builtin/cat-file.c | 37 +++++++++--
t/t4203-mailmap.sh | 105 ++++++++++++++++++++++++++++++++
3 files changed, 143 insertions(+), 4 deletions(-)
diff --git a/Documentation/git-cat-file.adoc b/Documentation/git-cat-file.adoc
index c139f55a16..86b9181599 100644
--- a/Documentation/git-cat-file.adoc
+++ b/Documentation/git-cat-file.adoc
@@ -174,6 +174,11 @@ flush::
since the beginning or since the last flush was issued. When `--buffer`
is used, no output will come until a `flush` is issued. When `--buffer`
is not used, commands are flushed each time without issuing `flush`.
+
+`mailmap (<bool>)`::
+ Enable or disable mailmap for subsequent commands. The `<bool>`
+ argument accepts the same boolean values as linkgit:git-config[1].
+ The mailmap data is read upon the first use and only once.
--
+
diff --git a/builtin/cat-file.c b/builtin/cat-file.c
index d9fbad5358..fa45f774d7 100644
--- a/builtin/cat-file.c
+++ b/builtin/cat-file.c
@@ -57,6 +57,20 @@ static int use_mailmap;
static char *replace_idents_using_mailmap(char *, size_t *);
+/*
+ * The mailmap is initialized with .strdup_strings set to 0,
+ * but read_mailmap() sets the bit to 1 (this is true even when
+ * not a single mailmap entry is read), so it can be used for
+ * lazy loading.
+ */
+static void load_mailmap(void)
+{
+ if (mailmap.strdup_strings)
+ return;
+
+ read_mailmap(the_repository, &mailmap);
+}
+
static char *replace_idents_using_mailmap(char *object_buf, size_t *size)
{
struct strbuf sb = STRBUF_INIT;
@@ -692,6 +706,20 @@ static void parse_cmd_info(struct batch_options *opt,
batch_one_object(line, output, opt, data);
}
+static void parse_cmd_mailmap(struct batch_options *opt UNUSED,
+ const char *line,
+ struct strbuf *output UNUSED,
+ struct expand_data *data UNUSED)
+{
+ use_mailmap = git_parse_maybe_bool(line);
+
+ if (use_mailmap < 0)
+ die(_("mailmap: invalid boolean '%s'"), line);
+
+ if (use_mailmap)
+ load_mailmap();
+}
+
static void dispatch_calls(struct batch_options *opt,
struct strbuf *output,
struct expand_data *data,
@@ -725,9 +753,10 @@ static const struct parse_cmd {
parse_cmd_fn_t fn;
unsigned takes_args;
} commands[] = {
- { "contents", parse_cmd_contents, 1},
- { "info", parse_cmd_info, 1},
- { "flush", NULL, 0},
+ { "contents", parse_cmd_contents, 1 },
+ { "info", parse_cmd_info, 1 },
+ { "flush", NULL, 0 },
+ { "mailmap", parse_cmd_mailmap, 1 },
};
static void batch_objects_command(struct batch_options *opt,
@@ -1131,7 +1160,7 @@ int cmd_cat_file(int argc,
opt_epts = (opt == 'e' || opt == 'p' || opt == 't' || opt == 's');
if (use_mailmap)
- read_mailmap(the_repository, &mailmap);
+ load_mailmap();
switch (batch.objects_filter.choice) {
case LOFC_DISABLED:
diff --git a/t/t4203-mailmap.sh b/t/t4203-mailmap.sh
index 74b7ddccb2..249548eb9b 100755
--- a/t/t4203-mailmap.sh
+++ b/t/t4203-mailmap.sh
@@ -1133,6 +1133,111 @@ test_expect_success 'git cat-file --batch-command returns correct size with --us
test_cmp expect actual
'
+test_expect_success 'git cat-file --batch-command mailmap yes enables mailmap mid-stream' '
+ test_when_finished "rm .mailmap" &&
+ cat >.mailmap <<-\EOF &&
+ C O Mitter <committer@example.com> Orig <orig@example.com>
+ EOF
+ commit_sha=$(git rev-parse HEAD) &&
+ git cat-file commit HEAD >commit_no_mailmap.out &&
+ git cat-file --use-mailmap commit HEAD >commit_mailmap.out &&
+ size_no_mailmap=$(wc -c <commit_no_mailmap.out) &&
+ size_mailmap=$(wc -c <commit_mailmap.out) &&
+ printf "info HEAD\nmailmap yes\ninfo HEAD\n" | git cat-file --batch-command >actual &&
+ echo $commit_sha commit $size_no_mailmap >expect &&
+ echo $commit_sha commit $size_mailmap >>expect &&
+ test_cmp expect actual
+'
+
+test_expect_success 'git cat-file --batch-command mailmap no disables mailmap mid-stream' '
+ test_when_finished "rm .mailmap" &&
+ cat >.mailmap <<-\EOF &&
+ C O Mitter <committer@example.com> Orig <orig@example.com>
+ EOF
+ commit_sha=$(git rev-parse HEAD) &&
+ git cat-file commit HEAD >commit_no_mailmap.out &&
+ git cat-file --use-mailmap commit HEAD >commit_mailmap.out &&
+ size_no_mailmap=$(wc -c <commit_no_mailmap.out) &&
+ size_mailmap=$(wc -c <commit_mailmap.out) &&
+ printf "mailmap yes\ninfo HEAD\nmailmap no\ninfo HEAD\n" | git cat-file --batch-command >actual &&
+ echo $commit_sha commit $size_mailmap >expect &&
+ echo $commit_sha commit $size_no_mailmap >>expect &&
+ test_cmp expect actual
+'
+
+test_expect_success 'git cat-file --batch-command mailmap works in --buffer mode' '
+ test_when_finished "rm .mailmap" &&
+ cat >.mailmap <<-\EOF &&
+ C O Mitter <committer@example.com> Orig <orig@example.com>
+ EOF
+ commit_sha=$(git rev-parse HEAD) &&
+ git cat-file commit HEAD >commit_no_mailmap.out &&
+ git cat-file --use-mailmap commit HEAD >commit_mailmap.out &&
+ size_no_mailmap=$(wc -c <commit_no_mailmap.out) &&
+ size_mailmap=$(wc -c <commit_mailmap.out) &&
+ printf "mailmap yes\ninfo HEAD\nmailmap no\ninfo HEAD\nflush\n" | git cat-file --batch-command --buffer >actual &&
+ echo $commit_sha commit $size_mailmap >expect &&
+ echo $commit_sha commit $size_no_mailmap >>expect &&
+ test_cmp expect actual
+'
+
+test_expect_success 'git cat-file --batch-command mailmap no overrides startup --mailmap' '
+ test_when_finished "rm .mailmap" &&
+ cat >.mailmap <<-\EOF &&
+ C O Mitter <committer@example.com> Orig <orig@example.com>
+ EOF
+ commit_sha=$(git rev-parse HEAD) &&
+ git cat-file --use-mailmap commit HEAD >commit_mailmap.out &&
+ size_mailmap=$(wc -c <commit_mailmap.out) &&
+ git cat-file commit HEAD >commit_no_mailmap.out &&
+ size_no_mailmap=$(wc -c <commit_no_mailmap.out) &&
+ printf "info HEAD\nmailmap no\ninfo HEAD\n" | \
+ git cat-file --mailmap --batch-command >actual &&
+ echo $commit_sha commit $size_mailmap >expect &&
+ echo $commit_sha commit $size_no_mailmap >>expect &&
+ test_cmp expect actual
+'
+
+test_expect_success 'git cat-file --batch-command mailmap yes overrides startup --no-mailmap' '
+ test_when_finished "rm .mailmap" &&
+ cat >.mailmap <<-\EOF &&
+ C O Mitter <committer@example.com> Orig <orig@example.com>
+ EOF
+ commit_sha=$(git rev-parse HEAD) &&
+ git cat-file commit HEAD >commit_no_mailmap.out &&
+ size_no_mailmap=$(wc -c <commit_no_mailmap.out) &&
+ git cat-file --use-mailmap commit HEAD >commit_mailmap.out &&
+ size_mailmap=$(wc -c <commit_mailmap.out) &&
+ printf "info HEAD\nmailmap yes\ninfo HEAD\n" | \
+ git cat-file --no-mailmap --batch-command >actual &&
+ echo $commit_sha commit $size_no_mailmap >expect &&
+ echo $commit_sha commit $size_mailmap >>expect &&
+ test_cmp expect actual
+'
+
+test_expect_success 'git cat-file --batch-command mailmap accepts true/false' '
+ test_when_finished "rm .mailmap" &&
+ cat >.mailmap <<-\EOF &&
+ C O Mitter <committer@example.com> Orig <orig@example.com>
+ EOF
+ commit_sha=$(git rev-parse HEAD) &&
+ git cat-file commit HEAD >commit_no_mailmap.out &&
+ size_no_mailmap=$(wc -c <commit_no_mailmap.out) &&
+ git cat-file --use-mailmap commit HEAD >commit_mailmap.out &&
+ size_mailmap=$(wc -c <commit_mailmap.out) &&
+ printf "mailmap true\ninfo HEAD\nmailmap false\ninfo HEAD\n" | \
+ git cat-file --batch-command >actual &&
+ echo $commit_sha commit $size_mailmap >expect &&
+ echo $commit_sha commit $size_no_mailmap >>expect &&
+ test_cmp expect actual
+'
+
+test_expect_success 'git cat-file --batch-command mailmap rejects invalid boolean' '
+ echo "mailmap maybe" >in &&
+ test_must_fail git cat-file --batch-command <in 2>err &&
+ test_grep "mailmap: invalid boolean .*maybe" err
+'
+
test_expect_success 'git cat-file --mailmap works with different author and committer' '
test_when_finished "rm .mailmap" &&
cat >.mailmap <<-\EOF &&
--
2.53.0
^ permalink raw reply related [flat|nested] 27+ messages in thread
end of thread, other threads:[~2026-04-16 3:33 UTC | newest]
Thread overview: 27+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-03-28 20:36 [PATCH v1 1/1] cat-file: add use-mailmap/no-use-mailmap to --batch-command Siddharth Asthana
2026-03-29 0:50 ` Junio C Hamano
2026-03-29 7:25 ` Siddharth Asthana
2026-03-29 20:55 ` Junio C Hamano
2026-03-29 8:28 ` [PATCH v2 0/1] cat-file: add mailmap subcommand " Siddharth Asthana
2026-03-29 8:28 ` [PATCH v2 1/1] " Siddharth Asthana
2026-03-30 2:12 ` Junio C Hamano
2026-03-31 1:40 ` Siddharth Asthana
2026-03-31 3:41 ` Junio C Hamano
2026-03-30 9:44 ` Karthik Nayak
2026-03-31 1:42 ` Siddharth Asthana
2026-03-30 10:37 ` Patrick Steinhardt
2026-03-30 14:53 ` Junio C Hamano
2026-03-31 1:43 ` Siddharth Asthana
2026-03-31 17:11 ` Jean-Noël AVILA
2026-03-31 17:49 ` Junio C Hamano
2026-04-01 10:11 ` Jean-Noël Avila
2026-03-31 12:11 ` [PATCH v3 0/1] " Siddharth Asthana
2026-03-31 12:11 ` [PATCH v3 1/1] " Siddharth Asthana
2026-03-31 19:21 ` Junio C Hamano
2026-04-10 18:29 ` Junio C Hamano
2026-04-15 15:09 ` [PATCH v4 0/1] " Siddharth Asthana
2026-04-15 15:09 ` [PATCH v4 1/1] " Siddharth Asthana
2026-04-15 18:28 ` Junio C Hamano
2026-04-16 3:08 ` Siddharth Asthana
2026-04-16 3:32 ` [PATCH v5 0/1] " Siddharth Asthana
2026-04-16 3:32 ` [PATCH v5 1/1] " Siddharth Asthana
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox