昔こういう記事を書いて、今も commit.template
を使っていたが思わぬ罠を踏んだので共有する。
起こったこと
git のコミットメッセージにテンプレートが適応されるよう以下のように設定していたとする。
$ git config --global core.editor vim $ git config --global commit.template /path/to/emoji.md
このとき、 emoji.md の文字コードは以下のように設定しているとする。
$ file --mime /path/to/emoji.md emoji.md: text/plain; charset=utf-8
この状態だと UTF-8 以外の文字コードを扱うリポジトリを編集した際、コミットメッセージが文字化けしてしまう。
例えば編集したいファイル(hoge.txtとでもしておく)が EUC-JP で git commit -v
を実行すると以下のようになる。
これは git commit -m 'なんかメッセージ'
などでコミットするなら、あまり影響はない(本当か?)。だが、私のようにうっかり変なものをコミットしないか差分を確認してからコミットしたい人間にとっては結構致命的だ。
原因
根本原因は .git/COMMIT_EDITMSG
の文字コードが判定不能になることだ。 .git/COMMIT_EDITMSG
はコミットメッセージ編集時の一時ファイルで、 git の設定で core.editor
を設定している場合は、このファイルを開いてコミットメッセージを書こうとする。このとき、 emoji.md は UTF-8 、 hoge.txt (正確にはhoge.txtのパッチファイル)は EUC-JP で、この二つのファイルを組み合わせて .git/COMMIT_EDITMSG
を作ろうとするので、文字コードが壊れて以下のようになる。
$ file --mime .git/COMMIT_EDITMSG .git/COMMIT_EDITMSG: text/plain; charset=unknown-8bit
charset=unknown-8bit
でググると sjis だよー、とよく出てくるけど違う。 UTF-8 と EUC-JP を無理やりくっつけたファイルを vim で開いてコミットメッセージを書こうとするから本当にわけわからん文字コードになってる。 charset=unknown-8bit
が sjis なのではなくて、 file --mime
コマンドでは sjis が判定できないから sjis のファイルを開いたときも charset=unknown-8bit
になってしまう、というのが正しい。
対策
このような状況で以下のような対策を取った。
1. ~/.gitconfig
の commit.template
をコメントアウトする
文字通りコメントアウトする。各人の設定がどうかわからんが、私は以下のようにした。
#[commit] # template = /path/to/emoji.md
要するに UTF-8 と他の文字コードが混ざらないようにする。コミットテンプレートが表示されなくなるが、コミットメッセージが文字化け起こすよりは全然いい。
2. vim で文字コードを自動判定
手順1でほぼ対応は終わりなんだが、ついでにやっとくと便利。
.vimrc
に以下のような設定を追加する。
set fileencodings=utf-8,sjis,euc-jp,iso-2022-jp,latin1
latin1とかいらなそーと思ってるけど、まぁ私はいろいろ扱ってるんですよ…。
これで .git/COMMIT_EDITMSG
が文字化けすることはなくなる。
今回のでついでにやっとくと色々便利なこと
git にはページャー設定も入れられるらしく、最終的に以下のような差分を .gitconfig
に追加した。
+[pager] + log = diff-highlight | nkf -w | more -F -X + show = diff-highlight | nkf -w | more -F -X + diff = diff-highlight | nkf -w | more -F -X
また .zshrc に more
や less
コマンドの設定も追加。
+export LESS='-i -M -R' +export MORE='-i -M -R'
これで git で diff をみたり log をみたりするときに自動的に文字コード判定もしてキレイに表示されるようになった。