]> git.ipfire.org Git - thirdparty/git.git/commitdiff
cat-file: add mailmap support
authorSiddharth Asthana <siddharthasthana31@gmail.com>
Mon, 18 Jul 2022 19:51:02 +0000 (01:21 +0530)
committerJunio C Hamano <gitster@pobox.com>
Mon, 18 Jul 2022 19:55:53 +0000 (12:55 -0700)
git-cat-file is used by tools like GitLab to get commit tag contents
that are then displayed to users. This content which has author,
committer or tagger information, could benefit from passing through the
mailmap mechanism before being sent or displayed.

This patch adds --[no-]use-mailmap command line option to the git
cat-file command. It also adds --[no-]mailmap option as an alias to
--[no-]use-mailmap.

This patch also introduces new test cases to test the mailmap mechanism in
git cat-file command.

Mentored-by: Christian Couder <christian.couder@gmail.com>
Mentored-by: John Cai <johncai86@gmail.com>
Helped-by: Phillip Wood <phillip.wood@dunelm.org.uk>
Helped-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>
Signed-off-by: Siddharth Asthana <siddharthasthana31@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Documentation/git-cat-file.txt
builtin/cat-file.c
t/t4203-mailmap.sh

index 24a811f0ef64b0f411c23a3598e7bc73e6a2e7ee..1880e9bba1a13386a8992747b0a8bede3011f28a 100644 (file)
@@ -63,6 +63,12 @@ OPTIONS
        or to ask for a "blob" with `<object>` being a tag object that
        points at it.
 
+--[no-]mailmap::
+--[no-]use-mailmap::
+       Use mailmap file to map author, committer and tagger names
+       and email addresses to canonical real names and email addresses.
+       See linkgit:git-shortlog[1].
+
 --textconv::
        Show the content as transformed by a textconv filter. In this case,
        `<object>` has to be of the form `<tree-ish>:<path>`, or `:<path>` in
index 50cf38999d10125428e4c558383582af4f191b95..4b68216b51d4337de897925f0ab30e3520c2124b 100644 (file)
@@ -16,6 +16,7 @@
 #include "packfile.h"
 #include "object-store.h"
 #include "promisor-remote.h"
+#include "mailmap.h"
 
 enum batch_mode {
        BATCH_MODE_CONTENTS,
@@ -36,6 +37,22 @@ struct batch_options {
 
 static const char *force_path;
 
+static struct string_list mailmap = STRING_LIST_INIT_NODUP;
+static int use_mailmap;
+
+static char *replace_idents_using_mailmap(char *, size_t *);
+
+static char *replace_idents_using_mailmap(char *object_buf, size_t *size)
+{
+       struct strbuf sb = STRBUF_INIT;
+       const char *headers[] = { "author ", "committer ", "tagger ", NULL };
+
+       strbuf_attach(&sb, object_buf, *size, *size + 1);
+       apply_mailmap_to_header(&sb, headers, &mailmap);
+       *size = sb.len;
+       return strbuf_detach(&sb, NULL);
+}
+
 static int filter_object(const char *path, unsigned mode,
                         const struct object_id *oid,
                         char **buf, unsigned long *size)
@@ -152,6 +169,12 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,
                if (!buf)
                        die("Cannot read object %s", obj_name);
 
+               if (use_mailmap) {
+                       size_t s = size;
+                       buf = replace_idents_using_mailmap(buf, &s);
+                       size = cast_size_t_to_ulong(s);
+               }
+
                /* otherwise just spit out the data */
                break;
 
@@ -183,6 +206,12 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,
                }
                buf = read_object_with_reference(the_repository, &oid,
                                                 exp_type_id, &size, NULL);
+
+               if (use_mailmap) {
+                       size_t s = size;
+                       buf = replace_idents_using_mailmap(buf, &s);
+                       size = cast_size_t_to_ulong(s);
+               }
                break;
        }
        default:
@@ -348,11 +377,18 @@ static void print_object_or_die(struct batch_options *opt, struct expand_data *d
                void *contents;
 
                contents = read_object_file(oid, &type, &size);
+
+               if (use_mailmap) {
+                       size_t s = size;
+                       contents = replace_idents_using_mailmap(contents, &s);
+                       size = cast_size_t_to_ulong(s);
+               }
+
                if (!contents)
                        die("object %s disappeared", oid_to_hex(oid));
                if (type != data->type)
                        die("object %s changed type!?", oid_to_hex(oid));
-               if (data->info.sizep && size != data->size)
+               if (data->info.sizep && size != data->size && !use_mailmap)
                        die("object %s changed size!?", oid_to_hex(oid));
 
                batch_write(opt, contents, size);
@@ -843,6 +879,8 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix)
                OPT_CMDMODE('s', NULL, &opt, N_("show object size"), 's'),
                OPT_BOOL(0, "allow-unknown-type", &unknown_type,
                          N_("allow -s and -t to work with broken/corrupt objects")),
+               OPT_BOOL(0, "use-mailmap", &use_mailmap, N_("use mail map file")),
+               OPT_ALIAS(0, "mailmap", "use-mailmap"),
                /* Batch mode */
                OPT_GROUP(N_("Batch objects requested on stdin (or --batch-all-objects)")),
                OPT_CALLBACK_F(0, "batch", &batch, N_("format"),
@@ -885,6 +923,9 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix)
        opt_cw = (opt == 'c' || opt == 'w');
        opt_epts = (opt == 'e' || opt == 'p' || opt == 't' || opt == 's');
 
+       if (use_mailmap)
+               read_mailmap(&mailmap);
+
        /* --batch-all-objects? */
        if (opt == 'b')
                batch.all_objects = 1;
index 0b2d21ec5510158cc9bb5b861a94bdfc6eccea12..cd1cab3e54b9170d5751279bd68e02dbc3cbcad2 100755 (executable)
@@ -963,4 +963,63 @@ test_expect_success SYMLINKS 'symlinks not respected in-tree' '
        test_cmp expect actual
 '
 
+test_expect_success 'prepare for cat-file --mailmap' '
+       rm -f .mailmap &&
+       git commit --allow-empty -m foo --author="Orig <orig@example.com>"
+'
+
+test_expect_success '--no-use-mailmap disables mailmap in cat-file' '
+       test_when_finished "rm .mailmap" &&
+       cat >.mailmap <<-EOF &&
+       A U Thor <author@example.com> Orig <orig@example.com>
+       EOF
+       cat >expect <<-EOF &&
+       author Orig <orig@example.com>
+       EOF
+       git cat-file --no-use-mailmap commit HEAD >log &&
+       sed -n "/^author /s/\([^>]*>\).*/\1/p" log >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success '--use-mailmap enables mailmap in cat-file' '
+       test_when_finished "rm .mailmap" &&
+       cat >.mailmap <<-EOF &&
+       A U Thor <author@example.com> Orig <orig@example.com>
+       EOF
+       cat >expect <<-EOF &&
+       author A U Thor <author@example.com>
+       EOF
+       git cat-file --use-mailmap commit HEAD >log &&
+       sed -n "/^author /s/\([^>]*>\).*/\1/p" log >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success '--no-mailmap disables mailmap in cat-file for annotated tag objects' '
+       test_when_finished "rm .mailmap" &&
+       cat >.mailmap <<-EOF &&
+       Orig <orig@example.com> C O Mitter <committer@example.com>
+       EOF
+       cat >expect <<-EOF &&
+       tagger C O Mitter <committer@example.com>
+       EOF
+       git tag -a -m "annotated tag" v1 &&
+       git cat-file --no-mailmap -p v1 >log &&
+       sed -n "/^tagger /s/\([^>]*>\).*/\1/p" log >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success '--mailmap enables mailmap in cat-file for annotated tag objects' '
+       test_when_finished "rm .mailmap" &&
+       cat >.mailmap <<-EOF &&
+       Orig <orig@example.com> C O Mitter <committer@example.com>
+       EOF
+       cat >expect <<-EOF &&
+       tagger Orig <orig@example.com>
+       EOF
+       git tag -a -m "annotated tag" v2 &&
+       git cat-file --mailmap -p v2 >log &&
+       sed -n "/^tagger /s/\([^>]*>\).*/\1/p" log >actual &&
+       test_cmp expect actual
+'
+
 test_done