Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

git wrapper adjustment character encoding.

branch: master

Fetching latest commit…

Cannot retrieve the latest commit at this time

readme.txt
-*-outline-*-

git用文字エンコーディング調整ラッパー
AKIYAMA Kouhei
2010-04-23

*目的

git-encwrapperは、gitコマンドをラップして入出力の文字コード(文字エンコー
ディング。以下単にエンコーディング)を統一し、文字化けを防ぎます。

具体的には次のことを行います。

- git-encwrapper diff 実行時、次のことを行います。
  1.gitを子プロセスとして起動します。
    コマンドライン引数は全てそのままgitへ引き継がれます。
  2.gitの標準出力から出る差分テキスト(パッチテキスト)をファイルヘッダー
    (「diff --git a/hoge.txt b/hoge.txt」のような行)を区切りとして区分け
    します。
  3.区分けした区間ごとに、ファイル名からファイルのエンコーディングを求めます。
    .gitattributesにencoding属性が指定されている場合は、その指定に従います。
    指定されていない場合はデフォルトのエンコーディングを使います。
  4.区間を、求めたファイルのエンコーディングから端末のエンコーディング
    へ変換します。

- git-encwrapper apply 実行時、次のことを行います。
  1.gitを子プロセスとして起動します。
    コマンドライン引数は全てそのままgitへ引き継がれます。
  2.git-encwrapperの標準入力から入る差分テキスト(パッチテキスト)を
    ファイルヘッダーを区切りとして区分けします。
  3.区分けした区間ごとに、ファイル名からファイルのエンコーディングを求めます。
    .gitattributesにencoding属性が指定されている場合は、その指定に従います。
    指定されていない場合はデフォルトのエンコーディングを使います。
  4.区間を、端末のエンコーディングから求めたファイルのエンコーディング
    へ変換し、gitへ渡します。

- git-encwrapperでdiff、apply以外を実行したときは、gitへ処理を委譲しま
  す。コマンドライン引数や標準入出力は全てそのままgitへ引き継がれます。


*背景・動機

git-encwrapperはコンソール(端末)やEmacs等からgitを呼び出したときに発生
する文字化けを回避するために作られました。

たとえば、gitで管理している二つのファイルがあるとします。一つはutf-8で
書かれており、もう一つはiso-2022-jpで書かれています。この二つのファイル
を両方修正し、git diffを実行すると、どちらかまたは両方が文字化けしてし
まいます。もし端末が認識する文字エンコーディングがutf-8の場合、
iso-2022-jpで書かれた方が文字化けすることでしょう。gitはファイルのエン
コーディングについては何も関知せず、何の変換も行わないため、結果diffの
出力は異なるエンコーディングで書かれた2つのファイルの差分が混ざったもの
になります。

このような状況は、文字エンコーディングを処理するプログラムとそのテスト
ケースを作る場合に起こりえます。たとえばメールのテキストを処理するプロ
グラムを作るとします。プログラムのソースコードはutf-8で記述したとします。
ソース内には日本語で作者名やコメントが書かれているかもしれません。一方
テスト用にiso-2022-jpで書かれているテキストを用意したとします。このよう
な状況で、もし特定の文字シーケンスを正しく処理できないミスが見つかった
らどうでしょう。テストケースとなるテキストファイルにその特定の文字シー
ケンスを書き加え(iso-2022-jpで)、テストし、ソースコード内のミスを特定し、
修正(utf-8で)するでしょう。そしてコミットする前にgit diffすると、文字化
けを起こしてうまく確認できないわけです。

また、もしエンコーディングが統一された差分(パッチ)を出力できたとしても、
その出力を流用して一部を切り出し、git applyでパッチを適用しようとすると、
元のエンコーディングと異なっているため、パッチが正しく当たらないことに
なります。この問題を避けるため、git applyの実行時にdiffとは逆の変換を行
う必要があります。私はMeadow(EmacsのWindows版亜種)上でmagit.elを使用し
ているのですが、部分的なstageをしたいとき、まさにこの変換が必要になりま
す。

gitには.gitattributesファイルのencoding属性でファイルのエンコーディング
を指定する仕組みが存在します。しかしこの属性はgit-guiやgitkといったGUI
フロントエンドが使用するだけで、gitコマンドは使用しません。

本来、gitコマンドはこのencoding属性を見て、出力のエンコーディングを調整
する機能を提供すべきです。エンコーディングの統一処理を行うかどうかに
GUIかどうかは関係なく、人間が目で見て確認する使い方をするかどうかが問題
です。gitコマンドはページャーとの連携など、人間が直接コマンドをたたく用
途を想定しているわけですから、当然encoding属性を見て適切に変換すべきで
す。

しかしそのようにはなっていなかったため、仕方ないのでこのコマンドを作りました。


*ビルド・インストール方法

C++/Cで書かれています。

確認はCygwin上でしか行っていません。

Cygwin上のgcc4でビルドしています。

boostはxpressiveを使っているので、比較的新しいものが必要です。boost.orgから最新版をダウンロードし、インクルードパスを通してください。Cygwinならば、/usr/include/boostがライブラリ展開後のboostディレクトリを指すようにシンボリックリンクを張ってください。必要なのはヘッダーファイルだけなので、ライブラリのビルドは不要です。

libiconvが必要です。Cygwinならばパッケージからインストールしてください。

make releaseでgit-encwrapper.exeができあがります。パスの通った場所へ移動してください。

*使い方

gitコマンドの代わりにgit-encwrapperコマンドを使うだけです。
ページャーなどはうまく動かないかもしれません。今のところ変換の対象は
diffの標準出力とapplyの標準入力だけです。

ファイルのエンコーディングは自動的に判別するわけではありません。
.gitattributesファイルを作って「hoge.txt encoding=utf-8」や
「*.c encoding=cp932」のように指定してください。

端末のエンコーディングやデフォルトのエンコーディングはソースコード内に
埋め込んであるので、変更したい場合はあらかじめ修正してからビルドしてく
ださい。
指定がないときのエンコーディングは
git-encwrapper.cpp の default_file_encoding のところに書いてあります。
端末のエンコーディングは
git-encwrapper.cpp の terminal_encoding のところに書いてあります。



*言い訳

pipeやfork等、UNIXっぽいプログラミングはあまりやったことがないので、変
なことをしているかもしれません。

git自体まだ触りくらいしか学んでいないので、色々誤解しているところがある
かもしれません。マージの仕方とかもまだ知らないし。

gitコマンドが標準でこのくらいのことが出来ないなんて、未だに信じられませ
ん。誰も気がつかないなんてことは無いと思うのですが。たぶん私が知らない
だけで、こんなことをしなくても良い方法があるんだと思います。知っている
人は教えてください。

gitのソースコードから属性取得部分を拝借しました。libgitディレクトリの中
です。出来るだけ余計なものが入らないように、不要な部分は#if
GIT_ENCWRAPPER_CUTOFF~#endifでカットしてあります。テキトーに処理したの
で、変な動作をしたらすみません。git_path関数を何もしない関数に置き換え
てしまっているので、カレントディレクトリがリポジトリがあるディレクトリ
じゃないとうまく動かないかもしれません。

端末のエンコーディングやファイルのデフォルトのエンコーディングはソース
コード内に埋め込んであります。すみません。変更したい場合は直接いじって
ください。

xpressiveを使って無駄にビルドしづらくしてすみません。最近集中力が無くて、
細かい文字処理を自分で書く気にどうしてもなれなくて、手元にあった
xpressiveを使ってしまいました。xpressiveはお手軽です。regexのようにライ
ブラリをビルド・リンクする必要もないし。

もともとMeadow(Emacs)上でMagitを使ってみて困ったので作りました。必要最
低限の機能しかないのはそのためです。MeadowとGitとの間はutf-8でやりとり
するようにしたので、ログの変換は不要でした。ログのエンコーディングに関
しては、git-configでi18n.logOutputEncodingがあるので、比較的融通が利き
ます。でも--pretty=format:%sでの出力が変換されないんですけど……。

「fatal: cannot handle encwrapper internally」というエラーメッセージが
出ることがありました。execvpに渡すプログラム名がgitなのにargv[0]が
git-encwrapperであることが原因だったようです。argv[0]を書き換えるように
しました。どうもexecvpで呼ぶ先がmsysgitだとこのエラーメッセージは出ず、
cygwinのgitだと出るようです。私はmsysgitを使っていたので気づきませんで
した。
Something went wrong with that request. Please try again.