AR ホームベーカリー

オイラのアウトプット用ホームベーカリー!

UTF-16 ファイルを git(hub) 上で diff がみたいらしい

結論からいうと github は出来ない、 git は gitattributes を利用すれば出来る。

これを解決したい

f:id:donbulinux:20210305171930p:plain
UTF-16 なファイルの diff を github の PR や history で確認した時

「not shown じゃないんだよ!」と言われるなど。

ファイル単体で閲覧する

f:id:donbulinux:20210305171829p:plain
githubUTF-16 なファイル単体を直接閲覧した時

単体だと見える。

どうしてこうなるのか

git はバイナリファイルの比較は (おおむね) できない、いや変更されたかどうかで比較は出来てるけど、変更箇所だけの差分比較はできないのほうが正しいのか?

今回の対象はテキストファイルだし、直接見れば見えるやんけ!というお気持ちもあろうが、 UTF-16 は扱い的にはバイナリファイルなんすよ。

bttb.s1.valueserver.jp

文字コード自体のお話を短く知るにはこのあたりかなあ、と思うけど、読んでも UTF-8/16 の違いが可変長か固定長か、 ASCII 互換あるなしくらいしかサッと入ってこないと思うので、詳しく知りたければ「プログラマのための文字コード技術入門」あたりを読むと良いです。 僕は「難しいねぇ!」となり、半分くらい読んだところで挫折して10年寝かせてます。

とにかく今は UTF-8 は拡張子に関わらずテキスト扱いできる、 UTF-16 はバイナリ扱いになる、くらいの理解でいてほしいお気持ち。

どうする

脇道にそれましたが、解決する方法として git diff が行われる時に nkf による変換処理を挟む、という手段をとります。

この設定によって、 git diff を各種 git 系コマンドを実行しても元ファイルが変更されないことは確認していますが、他の環境では違うかもしれん。 変更されたらすまん。

github は無理なもんは無理。

git config で変換動作を反映する

git config で変換用の動作を反映します。 これは --local を付与しているので、実行したディレクトリ以下の git プロジェクトにしか反映されません。

ググると出てくる記事の大体は --global で反映しているので ~/.gitconfig に反映されていますが、以下だと ${実行したディレクトリ}/.git/config へ反映されます。

ちなみに git を使う環境で nkf にパスを通しとく必要があります、パッケージマネージャとかでシュッと入れましょう。

[user@localhost プロジェクトのルートディレクトリ]$ git config --local diff.to_utf8.textconv 'nkf -w'

gitattributes を作成する

git コマンドで該当するファイルを呼び出す時の動作を設定することができます (という浅い理解をしている)。

上記で宣言した diff.to_utf8.textconv を利用するにはこのようにします。

[user@localhost プロジェクトのルートディレクトリ]$ vi .gitattributes

.gitattributes

.txt text diff=to_utf8

git diff する

git diff ${差分のあるコミットID} ${対象の UTF-16 バイナリファイル} などすれば、 UTF-8 に変換されて diff が取れるようになります。

まず UTF-16 が必要な場面てあまり思いつかないので、ファイルの扱いを UTF-8 に改めるのが一番な気がしますね。

ここからはおまけです。

git がバイナリファイルを判断する基準

git がバイナリファイルか否かを判断しているのは、ファイルの先頭 8000 byte を参照して判断しているようです。

日本語だとこのあたりがわかりやすいでしょうか。

qiita.com

エンコードが UTF- なんとか、や拡張子がメディアファイルの類、というリストを持っているわけではないんですね。 たしかに未知の拡張子、たとえば .fuckinmyfirststrongtextfile などとんでもない拡張子が突然生まれたとしても、これの対応のためになんらかのリストを更新する、というのはナンセンスな気がします。 あたまいいなあ!

改行コード問題

.gitattributes では改行コードを揃えることも出来ます。 というか git 的には LF が推奨されているようなので、 diff が git 的に正常に取れる環境というのは、 LF で正規化されたバイナリでないファイル、ということかなと。

kiririmode.hatenablog.jp

参考にさせて頂いたリンク先にも基礎知識として記載されておりますが、 WindowsCR+LF のためなるべくこれを LF に寄せるようにしましょう。 それこそプロジェクトのデプロイ先含めて、全部の環境が Windows ということであれば CR+LF のほうが問題ないとは思います。

gitattributes がワイのプロジェクトには存在しないんだけど

ja.stackoverflow.com

ある程度は git 自体の標準動作が存在して、それに従い変換がされているようです。 .gitattributes はこの設定に追加 (上書き) するものなので、新規に追加したからといって宣言していないものが壊れるわけではないようですね。

最強の .gitattributes

最強とは? という感じですが、一つの参考として Googlechromium リポジトリ内の .gitattributes が参考になるでしょう。

chromium.googlesource.com

C と PythonJavaScript あたりが主に採用されている技術のようなので、内容もそれに準じているように見えます。 これを参考に利用しているプロジェクトに合わせて作ると良いのではないでしょうか。