Merge branch 'sa/cat-file-batch-mailmap-switch'

"git cat-file --batch" learns an in-line command "mailmap"
that lets the user toggle use of mailmap.

* sa/cat-file-batch-mailmap-switch:
  cat-file: add mailmap subcommand to --batch-command
main
Junio C Hamano 2026-05-31 10:00:38 +09:00
commit 33da2f4d3b
3 changed files with 143 additions and 4 deletions

View File

@ -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.
--
+


View File

@ -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:

View File

@ -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 &&