Gitの.mailmapで作者の表記ゆれをまとめる方法

​​Git​コマンドライン

リポジトリの一番上に .mailmap というファイルを置くと、git shortlog や git log で、名前やメールアドレスの表記がばらばらな同じ人のコミットを1人分として表示できます。コミットそのものは書き換えないので、履歴を作り直す必要はありません。作者ごとのコミット数を集計するときや、リリースノートに載せる貢献者(コントリビューター)の一覧を作るときに、同じ人が何行にも分かれてしまう問題を直せます。

補足

検証環境は Ubuntu 24.04、Git 2.43.0 です。作者の名前とメールアドレスはすべて例示用の値で、作者は git commit --author で変えながらコミットしました。コマンドはリポジトリの一番上のフォルダで実行し、ページャーは使わない設定にしています。Windows・macOS での動作や、GitHub などの Web 画面の表示に .mailmap が効くかどうかは試していません。

表記ゆれのある履歴

Neko・Tama・Mike の3人が、8件のコミットを作った履歴を用意しました。どの人も、コミットによって名前やメールアドレスが違います。

console
$ git log --format="%h %ad %an <%ae> %s" --date=short
b184bc1 2026-11-08 Mike <dev@example.com> 共用の端末から当番を修正
8ef5a80 2026-11-07 Tama <dev@example.com> 共用の端末から献立を追加
c3a38bf 2026-11-06 Mike <mike@example.com> 掃除の当番を修正
c1d8582 2026-11-05 Mike <mike@example.net> 掃除の当番を追加
2f91ec6 2026-11-04 Tama <tama@example.com> 献立を修正
ae0affd 2026-11-03 Tmaa <tama@example.com> 献立を追加
d8bd1d2 2026-11-02 neko <neko@example.org> 買い物リストを追加
8ab32da 2026-11-01 Neko <neko@example.com> メモを作成

想定した表記ゆれは次の4種類です。

  • Tama が一度だけ、名前を Tmaa と打ち間違えた
  • Mike が、前のメールアドレス mike@example.net でコミットした
  • Neko が、別のメールアドレスと小文字の名前(neko <neko@example.org>)でコミットした
  • Tama と Mike が、共用の端末のメールアドレス dev@example.com でコミットした

この状態で、作者ごとの件数を数える git shortlog -sne HEAD を実行すると、3人なのに8行に分かれました。-s は件数だけを出す、-n は多い順に並べる、-e はメールアドレスも出す、という指定です。名前とメールアドレスの組が違うと、別の作者として数えられます。

console
$ git shortlog -sne HEAD
     1	Mike <dev@example.com>
     1	Mike <mike@example.com>
     1	Mike <mike@example.net>
     1	Neko <neko@example.com>
     1	Tama <dev@example.com>
     1	Tama <tama@example.com>
     1	Tmaa <tama@example.com>
     1	neko <neko@example.org>

ここから .mailmap に1行ずつ足して、まとめていきます。.mailmap の書き方は、gitmailmap のリファレンスに4つの形が載っています。

名前だけを直す

メールアドレスは合っていて、名前だけがゆれているときは、「正しい名前 <コミットに残っているメールアドレス>」の1組だけを書きます。tama@example.com のコミットは、名前がどう書かれていても Tama として表示されます。

console
$ printf "%s\n" "Tama <tama@example.com>" > .mailmap

$ git shortlog -sne HEAD
     2	Tama <tama@example.com>
     1	Mike <dev@example.com>
     1	Mike <mike@example.com>
     1	Mike <mike@example.net>
     1	Neko <neko@example.com>
     1	Tama <dev@example.com>
     1	neko <neko@example.org>

Tmaa の行が消え、Tama <tama@example.com> が2件になりました。

メールアドレスだけを直す

名前は合っていて、メールアドレスだけが古いときは、「<正しいメールアドレス> <コミットに残っているメールアドレス>」と、名前を書かずにメールアドレスを2つ並べます。

console
$ printf "%s\n" "<mike@example.com> <mike@example.net>" >> .mailmap

$ git shortlog -sne HEAD
     2	Mike <mike@example.com>
     2	Tama <tama@example.com>
     1	Mike <dev@example.com>
     1	Neko <neko@example.com>
     1	Tama <dev@example.com>
     1	neko <neko@example.org>

mike@example.net のコミットが mike@example.com に移り、Mike <mike@example.com> が2件になりました。名前の Mike はコミットに残っていたものがそのまま使われています。

名前とメールアドレスを両方直す

名前もメールアドレスも違うときは、「正しい名前 <正しいメールアドレス> <コミットに残っているメールアドレス>」と書きます。後ろに書いたメールアドレス(コミットに残っているメールアドレス)に当てはまるコミットは、名前とメールアドレスの両方が置き換わります。

console
$ printf "%s\n" "Neko <neko@example.com> <neko@example.org>" >> .mailmap

$ cat .mailmap
Tama <tama@example.com>
<mike@example.com> <mike@example.net>
Neko <neko@example.com> <neko@example.org>

$ git shortlog -sne HEAD
     2	Mike <mike@example.com>
     2	Neko <neko@example.com>
     2	Tama <tama@example.com>
     1	Mike <dev@example.com>
     1	Tama <dev@example.com>

残ったのは、共用のメールアドレス dev@example.com の2行です。

共用のメールアドレスは、名前とあわせて書く

dev@example.com は Tama と Mike の2人が使っています。ここで、ほかの行と同じように、メールアドレスだけで合わせる書き方をすると困ったことになります。

console
$ printf "%s\n" "Tama <tama@example.com> <dev@example.com>" >> .mailmap

$ git shortlog -sne HEAD
     4	Tama <tama@example.com>
     2	Mike <mike@example.com>
     2	Neko <neko@example.com>

$ git log -2 --format="%h %an <%ae> -> %aN <%aE>"
b184bc1 Mike <dev@example.com> -> Tama <tama@example.com>
8ef5a80 Tama <dev@example.com> -> Tama <tama@example.com>

Mike が作った b184bc1 まで Tama として数えられました。

注意

複数の人が使うメールアドレスを「正しい名前 <正しいメールアドレス> <コミットに残っているメールアドレス>」の形で書くと、ほかの人のコミットまでその1人にまとまります。件数は合計で合っているので、一覧だけを見ていると気づきにくい間違いです。

こういうときは、4つ目の形「正しい名前 <正しいメールアドレス> コミットに残っている名前 <コミットに残っているメールアドレス>」を使います。名前とメールアドレスの両方が合うコミットだけが置き換わります。前の1行を消してから、2人分を書き足しました。# から行の終わりまではコメントとして読み飛ばされるので、なぜこう書いたのかを残しておけます。

console
$ cat .mailmap
Tama <tama@example.com>
<mike@example.com> <mike@example.net>
Neko <neko@example.com> <neko@example.org>
# 共用の端末(dev@example.com)からのコミットは、名前で見分ける
Tama <tama@example.com> Tama <dev@example.com>
Mike <mike@example.com> Mike <dev@example.com>

$ git shortlog -sne HEAD
     3	Mike <mike@example.com>
     3	Tama <tama@example.com>
     2	Neko <neko@example.com>

8行に分かれていた一覧が、3人分の3行になりました。-e を外せば名前だけの一覧になり、-s を外せば人ごとにコミットのタイトルが並びます。

console
$ git shortlog -e HEAD
Mike <mike@example.com> (3):
      掃除の当番を追加
      掃除の当番を修正
      共用の端末から当番を修正

Neko <neko@example.com> (2):
      メモを作成
      買い物リストを追加

Tama <tama@example.com> (3):
      献立を追加
      献立を修正
      共用の端末から献立を追加

git log での見え方

git log の書式の指定(--format)では、%an と %ae がコミットに残っている作者の名前とメールアドレス、%aN と %aE が .mailmap を反映した名前とメールアドレスです。書式の一覧は、git log のリファレンスにある PRETTY FORMATS の節に載っています。両方を並べると、どのコミットがどう置き換わったかを一度に確かめられます。

console
$ git log --format="%h %ad %an <%ae> -> %aN <%aE> %s" --date=short
b184bc1 2026-11-08 Mike <dev@example.com> -> Mike <mike@example.com> 共用の端末から当番を修正
8ef5a80 2026-11-07 Tama <dev@example.com> -> Tama <tama@example.com> 共用の端末から献立を追加
c3a38bf 2026-11-06 Mike <mike@example.com> -> Mike <mike@example.com> 掃除の当番を修正
c1d8582 2026-11-05 Mike <mike@example.net> -> Mike <mike@example.com> 掃除の当番を追加
2f91ec6 2026-11-04 Tama <tama@example.com> -> Tama <tama@example.com> 献立を修正
ae0affd 2026-11-03 Tmaa <tama@example.com> -> Tama <tama@example.com> 献立を追加
d8bd1d2 2026-11-02 neko <neko@example.org> -> Neko <neko@example.com> 買い物リストを追加
8ab32da 2026-11-01 Neko <neko@example.com> -> Neko <neko@example.com> メモを作成

書式を指定しないふつうの git log では、Author: の行に .mailmap を反映した値が出ました。コミットに残っている値を見たいときは --no-mailmap を付けます。

console
$ git log -1 HEAD~6
commit d8bd1d2d13e6f9f3567d951d98965404cd92d6ee
Author: Neko <neko@example.com>
Date:   Mon Nov 2 10:00:00 2026 +0900

    買い物リストを追加

$ git log -1 --no-mailmap HEAD~6
commit d8bd1d2d13e6f9f3567d951d98965404cd92d6ee
Author: neko <neko@example.org>
Date:   Mon Nov 2 10:00:00 2026 +0900

    買い物リストを追加

検証環境では設定 log.mailmap を何も書いていません。git config のリファレンスによると、log.mailmap は何も書かなければ true で、git log と git show は --use-mailmap を付けたときと同じ動きになります。

作者で絞り込む --author も、検証環境では .mailmap を反映した名前で探しました。--author=Tama には、もともと Tmaa のコミット(ae0affd)も入り、--author=Tmaa では1件も出ません。

console
$ git log --author=Tama --format="%h %an <%ae> %s"
8ef5a80 Tama <dev@example.com> 共用の端末から献立を追加
2f91ec6 Tama <tama@example.com> 献立を修正
ae0affd Tmaa <tama@example.com> 献立を追加

$ git log --author=Tmaa --format="%h %an <%ae> %s"

$ git log --no-mailmap --author=Tmaa --format="%h %an <%ae> %s"
ae0affd Tmaa <tama@example.com> 献立を追加

--no-mailmap を付けると、コミットに残っている Tmaa で見つかりました。打ち間違えた名前のコミットを探したいときは、--no-mailmap を付けてください。

git blame -e でも、各行の作者のメールアドレスは .mailmap を反映したものになりました。neko@example.org で作った2行目は <neko@example.com> と表示されています。

console
$ git blame -e notes.txt
^8ab32da (<neko@example.com> 2026-11-01 10:00:00 +0900 1) メモを作成
d8bd1d2d (<neko@example.com> 2026-11-02 10:00:00 +0900 2) 買い物リストを追加
ae0affde (<tama@example.com> 2026-11-03 10:00:00 +0900 3) 献立を追加
2f91ec63 (<tama@example.com> 2026-11-04 10:00:00 +0900 4) 献立を修正
c1d8582c (<mike@example.com> 2026-11-05 10:00:00 +0900 5) 掃除の当番を追加
c3a38bfd (<mike@example.com> 2026-11-06 10:00:00 +0900 6) 掃除の当番を修正
8ef5a80f (<tama@example.com> 2026-11-07 10:00:00 +0900 7) 共用の端末から献立を追加
b184bc14 (<mike@example.com> 2026-11-08 10:00:00 +0900 8) 共用の端末から当番を修正

書いた .mailmap を git check-mailmap で確かめる

git check-mailmap に「名前 <メールアドレス>」または「<メールアドレス>」を渡すと、.mailmap で置き換えたあとの値を、1件につき1行で返します。git check-mailmap のリファレンスによると、当てはまる行がなければ、渡した値をそのまま返します。

console
$ git check-mailmap "neko <neko@example.org>" "NEKO <NEKO@example.org>" "<mike@example.net>" "Mike <dev@example.com>" "Hachi <dev@example.com>" "Pochi <pochi@example.com>"
Neko <neko@example.com>
Neko <neko@example.com>
<mike@example.com>
Mike <mike@example.com>
Hachi <dev@example.com>
Pochi <pochi@example.com>

名前とメールアドレスの @ より前を大文字で書いた NEKO <NEKO@example.org> も Neko <neko@example.com> になりました。gitmailmap のリファレンスにも、名前とメールアドレスは大文字と小文字を区別せずに比べると書かれています。一方、.mailmap に書いていない名前の Hachi <dev@example.com> は、共用のメールアドレスでも置き換わりませんでした。最後の Pochi <pochi@example.com> も、当てはまる行がないので、渡した値のまま返っています。名前とメールアドレスの両方で合わせた行が、ねらいどおりに働いていることが分かります。

.mailmap はコミットして共有する

ここまでの結果は、.mailmap をまだコミットしていない状態で出したものです。

console
$ git status --short
?? .mailmap

gitmailmap のリファレンスによると、Git はリポジトリの一番上にある .mailmap を読みます。作業ツリー(チェックアウトしたファイルの置き場所)にあれば効くので、コミットする前に git shortlog や git check-mailmap で結果を確かめられます。ほかの人の手元でも同じようにまとめるには、.mailmap をコミットしてプッシュします。

自分の手元だけで足したいときは mailmap.file

リポジトリにコミットしたくない対応を、自分の手元だけで足したいときは、設定 mailmap.file に別のファイルを指定します。git config のリファレンスでは、リポジトリの一番上の .mailmap を読んだあとに、mailmap.file で指定したファイルを読むと説明されています。

リポジトリの1つ上のフォルダに my-mailmap を作り、pochi@example.org を Pochi <pochi@example.com> にする行を書きました。

console
$ printf "%s\n" "Pochi <pochi@example.com> <pochi@example.org>" > ../my-mailmap

$ git check-mailmap "<pochi@example.org>"
<pochi@example.org>

$ git config mailmap.file ../my-mailmap

$ git check-mailmap "<pochi@example.org>" "neko <neko@example.org>"
Pochi <pochi@example.com>
Neko <neko@example.com>

設定する前は <pochi@example.org> のまま返ってきましたが、設定したあとは Pochi <pochi@example.com> になりました。リポジトリの .mailmap に書いた Neko の行も、あわせて効いています。

​Posted by 86