先月はSteamBirdsをずーっとやってたなぁ。こういう司令官ごっこ的なぬるいシミュレーションは好き。
先月はSteamBirdsをずーっとやってたなぁ。こういう司令官ごっこ的なぬるいシミュレーションは好き。
なんとかまともに使えそうな設定が見つかったのでメモ。
条件:
以上を考慮すると、Meadow-git間はutf-8にするのが無難。
cp932にしていろいろ試してみたのだけれど、git logのformatで%sを使った場合にlogOutputEncodingを考慮してくれない(gitにログをcp932で出力させられない)というところでギブアップ。magit-insert-unpushed-commitsなどがこのフォーマット指定を使っている。
utf-8にすると、今度はsh経由でgitを呼び出す部分で困る。sh経由でほかのツールを呼び出すこともあるので、shのエンコーディングを一律utf-8にするわけにはいかない。仕方ないので、defadviceでごにょごにょした。
msysgitの中で無効化するファイル。Cygwinのを使うので、削除するなり移動するなり。
.bashrcの関係ありそうな部分。
export TMP=/tmp export TEMP=/tmp export LANG=ja_JP.CP932
.emacsの関係ありそうな部分。
; *環境変数の設定。これらをシステム全体の設定にするのは抵抗があるのでここで。 ; Cygwin1.7の動作とか、win-ssh-askpassの動作とかで問題になったものを列挙。 (setenv "LANG" "ja_JP.CP932") (setenv "TMP" "c:/app/cygwin/tmp") ;Meadowを使っている間はCygwinの/tmpを使う。 (setenv "TEMP" "c:/app/cygwin/tmp") ;Meadowを使っている間はCygwinの/tmpを使う。 ; *とりあえず日本語環境が前提。 (set-language-environment "Japanese") ; *magit.elはgitを直接起動することもあるし、shell-file-nameのコマンド経由で起動することもあるので注意。 (setq shell-file-name "sh") (setq shell-command-switch "-c") ; *私はMeadow-Cygwin間は基本的にcp932にしている。 ; ほとんどの自作コマンドラインツールがcp932前提だし、 ; 日本語版Windowsのデフォルトのロケールはcp932なわけだから、 ; Cygwin以外のWindows用ツールと連携させるならば普通はこの方がいい。 (modify-coding-system-alist 'process "sh" '(cp932-dos . cp932-unix)) ; *Meadowとgitとの間はutf-8にする。 ; コミットログをutf-8で記録したい。 ; i18n.commitEncodingはコミット時に変換してくれるわけではないっぽい。 ; また、magit.el内でgit log --format %sを使っている場所があるので、 ; どうしてもutf-8でやりとりせざるを得ない。 ; この設定はshell-file-name経由でgitを呼ぶ場合には適用されないので注意。 ; そちらは.gitconfigのi18n.logOutputEncodingと、sh.exeに対する ; process-coding-system-alistの設定で調整すること。 (modify-coding-system-alist 'process "git" '(utf-8-dos . utf-8-unix)) ; magitを使えるようにする。 (cond ((locate-library "magit") (require 'magit) ;; magitがshell-file-name(sh.exe)経由でgitを呼ぶとき、utf-8で入出力する。 ;; magitがshell-file-nameを使ってprocess-fileやcall-processする関数には次のものがある。 ;; - magit-shell-command-to-string ;; - magit-git-exit-code ;; - magit-run-shell ;; これらの呼び出し時、一時的にprocess-coding-system-alistを書き換える。 (defun add-sh-utf8-process-coding-system-alist () (cons (cons shell-file-name '(utf-8-dos . utf-8-unix)) process-coding-system-alist)) (defadvice magit-shell-command-to-string (around magit-shell-command-to-string-proc-coding activate) (let ((process-coding-system-alist (add-sh-utf8-process-coding-system-alist))) ad-do-it)) (defadvice magit-git-exit-code (around magit-git-exit-code-proc-coding activate) (let ((process-coding-system-alist (add-sh-utf8-process-coding-system-alist))) ad-do-it)) (defadvice magit-run-shell (around magit-run-shell-proc-coding activate) (let ((process-coding-system-alist (add-sh-utf8-process-coding-system-alist))) ad-do-it)) ))
.gitconfig
[diff] external = ~/git-diff-nkf.sh #[i18n] # logOutputEncoding = utf-8
~/git-diff-nkf.sh (異なる文字エンコーディングで書かれたファイルの差分をUTF-8に統一するために必要。echoの部分はちょっと怪しい。モード値だけが変わった場合にどうなるのかとかよくわかっていない)
#!/bin/sh # $1 = 比較しているファイルのファイル名 # $2 = 旧バージョンの内容が入ったテンポラリファイル名 # $3 = 旧バージョンの内容のオブジェクト名 # $4 = 旧バージョンのファイルのモード値 # $5 = 新バージョンの内容が入ったテンポラリファイル名 # $6 = 新バージョンの内容のオブジェクト名 # $7 = 新バージョンのファイルのモード値 echo diff --git a/$1 b/$1 if test $3 == "." then # *新しくファイルを追加するとき。 # 例: # diff --git a/.gitignore b/.gitignore # new file mode 100644 # index 0000000..b25c15b # --- /dev/null # +++ b/.gitignore echo new file mode $7 echo index 0000000..${6:0:7} diff -u -L /dev/null -L b/$1 $2 $5 | nkf --utf8 -d else # *内容が変わった場合。 # 例: # diff --git a/readme.txt b/readme.txt # index 353a8aa..401f140 100644 # --- a/readme.txt # +++ b/readme.txt echo index ${3:0:7}..${6:0:7} $7 diff -u -L a/$1 -L b/$1 $2 $5 | nkf --utf8 -d fi
2010-04-24追記:上の方法は選択範囲(日本語を含む)を部分的にstageする機能が正しく動かない場合がある。それに対処するためエンコーディング調整ラッパーを使う方法を書いた。これを使うと.gitconfigとgit-diff-nkf.shは不要。
ジュエルペットてぃんくるのOPってどこかで聞いたような曲なんだけど、何だろう。
プロジェクト内に2つのファイルがあって、一方はSJIS、もう一方はUTF-8で書かれている。両方修正してMagit上で差分を見ると、当然のように一方が文字化け。やれやれ。コミットログに関してはi18n.commitencodingだとかi18n.logoutputencodingだとか、それっぽいものが用意されているようだが(ちゃんと働くのか確認してないけど)、肝心のファイルの中身はどうすればいいのか分からなかった。
でも、diff.external(GIT_EXTERNAL_DIFF)でdiffを置き換えられると知って、nkfで変換することを思いついた。
.gitconfigに以下を追加。
[diff] external = ~/gitdiff.sh
gitdiff.shは以下のような感じ。自分はMeadowとgitの間は(今のところ)sjisにしているので–sjis。改行コードがLFになるように-d。
#!/bin/sh echo diff --git a/$1 b/$5 echo index $3 $4 diff -u -L a/$1 -L b/$5 $2 $5 | nkf --sjis -d
echoの部分はMagitが認識できるように、できるだけgit標準の出力に近づけた。magit.el内には(looking-at "^diff –git ./\(.*\) ./\(.*\)(")という記述の下に(looking-at "^diff --cc +\(.*\))")という記述もあるのだけど、こっちはどういう状況での出力なのか分からないのでスルー。
なんかもう、Subversionでいいんじゃないかという気がしてくるのだが……。
とりあえずGitの本を買ってきた。もう少し勉強しますかね。
今はほめられ不況なのでほめられインフレを恐れずにもっとほめましょう。
なんかGitを勧められたのでこの際だから試してみることにした。CVSやSubversionで十分なんだけどなぁ。ぶつぶつ……。
せっかちな人のための git 入門 - git をインストールし、共同で開発できる環境を整えるまで : 僕は発展途上技術者を読んだ。なるほど、CVSやSubversionはローカルにワーキングコピーを作るけど、Gitは作業するところは常にリポジトリで、リポジトリ同士を同期していく感じなのかな。
とりあえずやってみよう。Cygwinでgitを入れて、適当なディレクトリを作ってgit init、readme.txtを書いてgit add readme.txt。
fatal: cannot use .git/info/exclude as an exclude file
あれ、なんだこりゃ。エラーメッセージで検索してみると、どうやらテキストモードでマウントしているとダメらしい。バイナリモードでマウントすべし、と。えー、バイナリモードだとCVSがUnix改行コードで入出力してしまうんですけど……。
どうしよう、道は二つ。
CVSを使うディレクトリはテキストにして、Gitを使うディレクトリはバイナリにする、なんてのはさすがに嫌。
msysgitをインストールしてC:Program FilesGitbinへパスを通してからやり直したらちゃんとできた。Cygwinのbashからも問題なく動いているように見える。
git addしたらgit commit。名前とメールアドレスを設定した方がいいと出たので、表示されたとおりに操作したら、%HOME%/.gitconfigが作成された。よしよし。
さて、サーバーとのやりとりも試してみようか。サーバー側にもGitを入れて、git –bare initでリポジトリを作る。–bareを指定するとローカルでやったときに作られた.gitディレクトリの内容相当が生でトップのディレクトリに展開されるみたいだ。確かに作業用のファイルなんかいらないので、サーバー上ではこの方が都合がいい。
ローカルに戻って、git remote add origin ssh://~でサーバーのリポジトリを設定して、git push origin masterすると……、んん? ssh鍵のパスフレーズを聞いてきた。win-ssh-askpassが効いてない? いや、どうやらmsysgitに付属のssh.exeが使われているせいらしい。__ssh.exeのようにファイル名を変えてCygwinのssh.exeが使われるようにしたら、パスフレーズを聞かれることはなくなった。
なるほど、細かい疑問点はいろいろあるけれど、ひとまずはよしとしよう。
次はMeadow上から操作できるようにしたい。Emacsクライアントはどうすればいいのだろうか。検索で上位に出てきたMagitというのを使えばいいのかな。とりあえず入れてみよう。
M-x magit-status ……ぎゃー。
Local: master ~/work/tmp/git_lesson/ Head: 6224579 first commit Untracked files: 'c:Program' は、内部コマンドまたは外部コマンド、 操作可能なプログラムまたはバッチ ファイルとして認識されていません。 Stashes: 'c:Program' は、内部コマンドまたは外部コマンド、 操作可能なプログラムまたはバッチ ファイルとして認識されていません。 Changes: 'c:Program' は、内部コマンドまたは外部コマンド、 操作可能なプログラムまたはバッチ ファイルとして認識されていません。
すぐにmsysgitを別のパスへ入れ直した。
動くようになったけど、やっぱりpcl-cvsやpsvnなんかとはちょっと違う。セクションって何だ? diffがとりたいのだけど=を押すんじゃないのか? など。
とりあえずコミットしてみようかとcを押したらNothing stagedとかなんとか言われた。staged、unstagedって何だろう。最初stag-edかと思ったらstage-dだったようだ。誰得UNIX-Blog: ステージを理解して git をもっと便利に使うを読んだ。
すげぇ、ファイル内の選択した部分だけをステージにあげてコミットできるんだ! これならこのインタフェースも納得だわ。確かに同一ファイルに違う目的の修正を施してしまって、分離するのが面倒だからそれを一度にコミットしてしまうということはよくあったんだよね。
Magitからssh経由でpullができない。Cygwinのbashからやるとこんな感じ。
$ git pull bash.exe: warning: could not find /tmp, please create! Enter passphrase for key '/c/home/k-aki/.ssh/id_dsa': Already up-to-date.
bashが/tmpが無いなどと寝ぼけたことを言ってから、パスフレーズを求めてきている。パスフレーズを求められるとMeadow上からは入力できないのでまずい(fakecygpty.exeを使えばできるのかもしれないけど)。
いろいろ調べてみたら、どうやら環境変数TMPとTEMPが設定されていないから、このwarningが出るようだ。つい先日Cygwin1.7にしたとき.bashrcはほとんどデフォルトのままいじらなかったのだけど、中を確認したらunset TMPなどとしているではないか。Windowsのテンポラリディレクトリと混ざると良くないらしい。.bashrcのunsetの後にset TMP=/tmpとset TEMP=/tmpを追加。
これでもMagitからpullできない。プロセス一覧を見るとssh.exeが起動しっぱなしで終了しないので、やはりパスフレーズが取れないで止まっているのだろう。複数のsh.exeも一緒に起動しっぱなしになっているので、msysgitのsh.exeを使えなくしてみた。すると今度はsed.exeがエラー。msysgitのsedはcygwinのパスを理解しないのでファイルが開けないらしい。msysgitのsedも無効化してCygwinのsedを使うようにしてみる。今度はgitが「git: 'Merge branch 'master' of ssh://********* is not a git command'」などという訳のわからないエラーを。う゛ー、なんだこりゃ。
たぶんCygwinのsedを使おうとしたせいで何かテキストの切り出しに失敗したのだろう。仕方ないのでshとsedはmsysgitのものを使うことにする。
となると、やはりパスフレーズが取れなくてssh.exeが止まったままになってしまう。
Cygwinのbash上からはちゃんと何も聞かれずにgit pullできるので、何が違うのだろうと環境変数一覧を比較してみた。
あ、TMPとTEMPの値が違う。Meadow3はスタートメニューから起動しているので%USERPROFILE%Tempだし、bashの方はさっき明示したとおり/tmp(私の場合c:appcygwintmp)だ。そういえばwin-ssh-askpassは/tmpの下にファイルを作ってたっけ。
というわけで、.emacsに(setenv "TMP" "c:/app/cygwin/tmp")(setenv "TEMP" "c:/app/cygwin/tmp")を追加したら、まともにpullできるようになった。いいのかこれで。