Git Companion Scripts

まだしつこくマルチプラットフォーム開発環境における Git のエンコーディングチェック についてやってます。とはいっても、ほとんどもう Perl の話になっているのですが。

いろいろファイルが増えてきたので、新しく Github に Git Companion Scripts というリポジトリを作ってまとめました。これの使い方について書きたいと思います。

2012/05/11 更新: git check-attr による Git 属性の活用 において pre-commit-encoding スクリプトを改良しましたので、この記事の使用法を改訂しました。

概要

Git Companion Scripts は Git の標準環境で追加のソフトウェアのインストールなしに使える便利なスクリプト集です。Linux や Unix の Git だけでなく Git for Windows (msysgit) もサポートしています。

使用法

とりあえずいますぐ利用可能なスクリプトは次のふたつです。

hooks/pre-commit-encoding

このスクリプトは Git のコミット前にテキストファイルのエンコーディングと改行文字をチェックする pre-commit フックスクリプトです。Git リポジトリ中に .git/hooks/pre-commit として名前を変えて設置すればすぐに使えます。

チェックの対象となるファイルの指定は .gitattributes ファイルで encoding 属性を設定することによって行います。 encoding 属性の値として許可するエンコーディングをコンマで区切って並べてください。

属性の値を指定しない場合はデフォルトのエンコーディングを使用します。これはスクリプトへの引数またはスクリプト中の変数 $default_allowed により指定できます。

エンコーディングとしては次のような Emacs 的表記を受け付けます。

エンコーディング表記は様々なエイリアスが存在します。詳しくは Perl のドキュメント Encode::Supported を参照してください。

.gitattributes ファイルの記述例を次に示します。文法についてはマニュアル (git help attributes) を参照してください。

# *.log ファイルには ASCII エンコーディングを設定する
*.log encoding=ascii

# *.txt ファイルにはデフォルトエンコーディングを設定する
*.txt encoding

# Visual C++ が正しく受け付けるエンコーディングを設定する
[attr]msvc encoding=ascii-dos,utf-8-with-signature-dos
*.c msvc
*.h msvc
*.cpp msvc

コミットするファイルに不正なエンコーディングが含まれていると、次のように git commit が失敗します。

$ git add hoge.c
$ git commit
hoge.c: utf8-unix (ascii-dos,utf-8-with-signature-dos)
Commit aborted!  (Use "git commit --no-verify" to skip this)

一時的にエンコーディングチェックを無効にしたい場合は git commit --no-verify を使うと pre-commit スクリプトの実行をスキップできます。

utils/ipconv

このユーティリティスクリプトは -e オプションで指定したエンコーディング、またはスクリプト中の変数 $output_encoding で指定したエンコーディングに、引数で指定したファイルを上書き一括変換します。元のファイルは .orig の拡張子をつけた名前でバックアップされます。

エンコーディングの指定は pre-commit-encoding スクリプトと同様な Emacs 的表記を使います。 utf-8 のように改行コードを指定しなかった場合、改行コードはいじらず素通しします。

マルチプラットフォーム開発環境

このスクリプトが想定している、処理系が受け付けるファイルエンコーディングの違いが問題になるようなマルチプラットフォーム開発環境について説明します。

たとえば Visual C++ と GCC でコンパイルできる共通のソースファイルを書こうとするとき、日本語の文字コードとしては UTF-8 を使いたくなると思いますが、各処理系が受け付けるエンコーディングには次のような要件があります。

UTF-8 改行文字
Visual C++ BOM が必要 CRLF のみ
GCC (4.4 以降) BOM の有無は問わない LF または CRLF

たいていのプロジェクトでは一番融通のきかない Visual C++ に合わせ、リポジトリ中のソースコードのエンコーディングは UTF-8 BOM つき・改行コード CRLF (または LF で core.autocrlf の自動変換機能を使用) で統一することが多いと思います。

このようなエンコーディングの強制については Git では clean/smudge フィルタ を使って自動変換する方法などが考案されていますが、これは意図せぬ変換が起きて問題になりまくる気がしたので、 pre-commit フック pre-commit-encoding でエラーを出してプログラマ自身に正しいファイルに変換させるほうがよいと思いました。

しかしながら、そこですぐに nkf とか iconv とか set bomb とか C-x C-m C-f utf-8-with-signature-unix とかが出てくるプログラマは少ないと思うので、簡単にエンコーディングと改行文字と BOM の有無が一括変換できるスクリプト ipconv を用意することにしたのでした。

どちらのスクリプトも単一ファイルで Git が動く環境であれば動くので、ソースコードリポジトリに同梱して使ってもらえばと思います。

おわりに

当初はあまり凝る気はなかったのですが、標準的 Git 環境で動くという制約の下で Perl スクリプトの実験を繰り返すうちにだんだん面白くなってきてしまい、最終的にはテストスイートまで書いてしまいました。

テストのフレームワークには shUnit2 というものを初めて使ってみました。シェルスクリプトでファイルひとつを source するだけで使えるので大変使い勝手がよいです。

バグ報告などを歓迎します。普段 Perl を書いておらずへぼいスクリプトなので、悪い作法の指摘などをしていただけるとうれしいです。

2012/04/22 18:56:00 JST