Posts Tagged ‘git’

Windows/Linux両環境で動作するC言語ソースの一元管理をGitで行う

5月 2nd, 2010

gitでリポジトリからのチェックアウト時に文字コードを変換する » tune webの続きです。
【未解決】VisualStudioとgccでコンパイルできるソースのエンコーディング » tune webでも書きましたが、問題はVisualStudioはUTF-8 BOM有のみ、gccはUTF-8 BOM無しのみ扱え、両者で問題なく扱える文字コードが存在しない事でした。gitにあるsmudge/cleanを使うとチェックアウト/ステージ時に任意のフィルタを通すことができ、BOMの除去をここでやれば出来そうなのですが、文字コード変換ソフトのnkfではBOMの有り無し以外も書き変わってしまうことがあるため実用に使えなかったのがこれまででした。

git smudge/cleanはPro Git – Pro Git 7.2 Git のカスタマイズ Git の属性に詳しく解説されています。
git smudge/cleanの設定は前の日記に書きましたが、ここでも引用しておきます。

まず.gitconfigファイルに以下を追加

[filter "fixbom"]
clean = “/usr/bin/bom_util -a”
smudge = “/usr/bin/bom_util -d”

これでsmudgeでUTF-8 BOM無し、cleanでUTF-8 BOM有りになります。

これだけではダメで、フィルタ処理をかけるファイルを指定する必要が有ります。
gitの管理フォルダである.gitがあるトップディレクトリに.gitattributesファイルを以下の内容で作成し、git checkout -fします。

*.c filter=fixbom
*.h filter=fixbom

/usr/share/git-core/templates/info/attributes を作って上記内容を書いておくとclone時に.git/info以下にコピーされてgit cloneしただけで文字コード変換が動くようになります。

上記で指定している、BOMをつけ外しするプログラムは結局自作しました。単にファイル先頭のBOMを検知して追加・削除をするだけです。ハマったこととしてgit smudge/cleanのデータは標準入力から渡され、標準出力へ書いた内容で差し替えられます。外部コマンドとして起動されるのかと思っていましたが異なるようです。
BOMをつけ外しするプログラムを下に貼っておきます。(gistはこちら→gist: 386410 – GitHub)

#!/usr/bin/ruby

require "optparse"

mode = :help

opt = OptionParser.new
opt.on("-a", "Add BOM"){|v| mode = :add}
opt.on("-d", "Delete BOM"){|v| mode = :delete}
opt.parse!(ARGV)

case mode
when :add
 STDOUT.binmode
       lines = readlines
       unless lines[0] =~ /^\M-o\M-;\M-?/ then
               print "\xEF\xBB\xBF"
       end
       print lines

when :delete
 STDOUT.binmode
       lines = readlines
 lines[0].sub!(/^\xEF\xBB\xBF/, '')
 print lines

when :help
       STDERR.puts opt.help
end

VisualStudioでの開発をメインにしているので、リポジトリ内のソースをUTF-8 BOM有、改行コードをLFCRにして運用しています。
これでLinux環境での開発がひとつやりやすくなりました。

入門Git 入門git 実用Git

実用Git

3月 23rd, 2010
実用Git
実用Git
posted with amazlet at 10.03.23
Jon Loeliger
オライリージャパン
売り上げランキング: 16867
おすすめ度の平均: 3.0

3 翻訳の質が低くて残念

言いたいことは全てAmazonに投稿されている書評で言ってもらった気がします。

翻訳の質が低くて残念です。
すでにgitについてある程度の知識を持っている人でないと、そういったミスリーディングな翻訳文から真の意味をつかむのは難しいと思います。
「入門git」と「入門Git」を制覇して次のステップを目指す人が、翻訳のまずさを自力で補う覚悟のうえで買うのなら、よい本です。

駄目な本かというとそうではなくて、Gitについてこの本より詳しく記述された文章はネットでもないので貴重だと思います。個人的にもgit-svnの使い方が大変勉強になりました。そこだけで3000円ぐらい払っても惜しくないぐらいです。たまに出てくる意味が取りにくい訳がなければ星4つ、O’reilly独特の言い回しが邦訳で取り払われていれば星5つだったと思います。

Gitのオブジェクト管理についてはWEB DB Press Vol.50でも、入門Gitでも紹介されていますが、この本が一番詳しく、説明が丁寧で、わかりやすかったです。Gitをじっくり学びたい人におすすめです。使いたいだけなら入門Gitでいいでしょう。

実用Git 入門git 入門Git WEB+DB PRESS Vol.50

Subversion, Git, Redmine, Hudson – 結局こうなった

3月 21st, 2010


前に考えていた開発プロセスの変更を色々試行錯誤してみてある程度固まってきました。過去の記事は以下からどうぞ。

ネットワークが切り離された外部チームとのやりとりは結局git bundleにしました。外部チームからはパッチでもらい、レビューした後に適用する。ある程度開発が進んだらgit bundleでリポジトリをコピーして外部チームに送付。外部チームはbundleファイルをそれぞれcloneして開発を行い、適宜git fetch/git pullしながら更新に追従します。タスクの粒度が1タスク1人だったこと、外部チームで別途central repositoryを設けることによるメリットが読めなかったのでこの形を取りました。開発メンバのGitレベルが上がればまたちがった使い方があるのかもしれません。チームの大半が入門Gitを読んだ程度だとこれぐらいから始めるのが混乱が少ないようです。
「masterだけ送ればいいから % git bundle create reponame.bundle master」でOKと思ってbundleファイルを作ったところclone出来ない問題が起きて半日ほどハマることがありました。「% git bundle create reponame.bundle master HEAD」じゃないと駄目みたいです。リポジトリ全部のコピーを送るなら「% git bundle create reponame.bundle –all」でもいけます。

以前はgitリポジトリの変更をSubversionに自動で書き戻すことを考えていましたが、GitとSubversionを共存させる » tune webで書いたようにSubversionに登録されたソースが削除されてしまうことがあり、結局手動にしました。週に1回ぐらい書き戻すことを想定しています。それに合わせてRedmineやHudsonが参照するリポジトリもgitに変更しました。

Hudsonのgitプラグインでポーリングする設定をしてみたのですが、ポーリングのログを書き込むところでたまにエラーが起きて止まってしまうため、gitのフックスクリプト(post-receive)でHudsonのジョブをcurlでキックするようにしました。ジョブはWindowsとLinuxとあるのですが、Windowsが苦戦しました。まずWindowsのジョブを実行するPCにmsysGitを入れて、コマンドプロンプトからgitコマンドが叩けるようにします。次にHudsonのgitプラグインでは認証を入力することが出来ないので、gitリポジトリをhttpで読めるようWebサーバの設定を行いました。gitのhttp公開は単にリポジトリのフォルダにアクセス出来るようすれば良いだけなので簡単です。あとはhooks/post-updateに”git update-server-info”を追加すればOKです(参考:git update-server-info)。

Hudsonのgitプラグインはテスト対象をワイルドカードを含むブランチ名で指定できるので、少し時間をかければpre-test commitも出来そうです。前は良く分からないなんて書いてしまいましたが、少しgitプラグインを使ってみれば感触がつかめるのではないかと思います。近々に必要な機能ではないので、また時間がある時に試してみようと思っています。

Redmineでgitを参照するにはRedmineと同じサーバにbareリポジトリを置く必要があります。別サーバで動かしているなら中央リポジトリからRedmine用のリポジトリに自動でpushする設定をすればいいでしょう。Redmineの昔のバージョンではリポジトリビューワが遅かったらしいのですが、0.9以降で試した限りでは気になるほどではありません。Subversionの頃よりも見やすくなった気さえします。trunkとbranchを切り替えて表示するのがSubversionより楽だと思います。リポジトリビューワがあまりに見やすいのでgit-webのインストールをやめたほどです。ソースレビューにgerritを検討しましたが、LDAP認証の設定をするところでうまく動かず断念してしまいました。最もr-labs – Code Review – Redmineが最近のバージョンアップでどんどん良くなっているので不要かもしれません。Redmineがより使われるようDoxygenで自動生成している内部仕様書もRedmineのRedmine – PluginEmbedded – Redmineですぐ見れるようにしてみました。

gitのフックスクリプトはhooks/post-receiveでメールを流す設定だけ有効にしています。コミットメッセージに Issue ID を含むことを強制させる Git のフックスクリプトを書きました|SNS構築の手嶋屋を参考にhooks/updateをつくってみたのですが、gitで自動生成されるコメント(マージとか)はRedmineのコミットIDを含まないのが問題になり結局止めています。この辺はまた時間をとってフックスクリプトを見直す必要がありそうです。

時間もかなり費やしましたが、昨年までよりも開発に専念出来る体制がようやくできました。Joel先生も分散バージョン管理で間違いないって、ベイビーと言ってるほどなので分散バージョン管理に移行しましょう!

GitとSubversionを共存させる

2月 27th, 2010

git svn cloneして、ファイル編集して、git commitして、git svn dcommitでSubversionサーバに変更を反映させる。Subversionの変更を取ってくるのはgit svn rebaseだ… なんてのがWeb上で探してすぐ見つかる情報ですが、これでは複数人でgitを使う場合の運用ですぐに行き詰まってしまいます。

実用Gitの16章に定石が載っていると聞き、さっそく買って読んでみました。他の章を飛ばして16章だけ読んだせいもあるのか自分の中ではまだうまく消化出来ていません。とりあえず手順だけ書いておきます。

◯前提条件
git svnを行う窓口は1箇所にする。git svnのオプションを変えたり、とってくるリビジョンを変えただけでもコミットオブジェクトは変わってしまう。

◯前準備
git svnを使ってSubversionリポジトリのcloneを作る

% mkdir example-svn.git
% git svn clone –stdlayout –prefix=svn/ http://example.jp/svn-repos/

git bareリポジトリを作る

% mkdir example.git
% cd example.git
% git init –bare –shared=true

git svnリポジトリからmasterとSubversionのブランチをgitのセントラルリポジトリにpushする。

% cd ../example-svn.git
% git push –all ../example.git
% git push ../example.git ‘refs/remotes/svn/*:refs/heads/svn/*’

◯Subversionにマージを書き戻す

% git checkout svn/trunk
% git merge –no-ff new-feature
% git svn dcommit

何度も実用Gitの解説を読んでいるのですが、マージを書き戻すところだけどうにも謎です。多分きちんとリモート追跡を理解できてないのでしょう。この休みにまた時間をとって勉強することにします。

実際にやってみて出来ることは確認したのですが、

  1. Subversionへの書き戻しを手動でやらないといけない
  2. Subversionのログに残るメッセージがgit mergeで生成されたものになってしまい、何の変更をしたのかSubversionからはさっぱりわからない

という問題があることも分かりました。

そこで上記でいうexample-svn.gitのフックスクリプトを作成し、example-svn.gitのmasterに変更がpushされたらSubversionに書き戻す処理を自動化してみました。動く気はしているのですが、理解が足りてないせいで、思わぬ問題を引き起こすかもしれませんのでご注意ください。

#!/bin/sh

# checkout svn/trunk
git checkout svn/trunk

# Store git log before merge
log=$(git log last-merged..master --pretty=format:"%h %s" --reverse)

# merge master to svn/trunk, don't commit
git merge --no-ff --no-commit master

# commit with git log message
git commit -a -m "$log"

# push back to svn repository
git svn dcommit

# tag last merged
git tag -d last-merged
git tag last-merged master

◯2010年3月3日追記
テスト環境ではうまく行ったのですが、本番環境でgit->Subversionの自動同期をしてみたところ、ソースファイルが削除される問題が起きてしまいました。
git push, git mergeとかのどこかでうまくいってないのにsvn dcommitまで行われたのが直接の原因ですが、なぜこうなったのかログを見ても原因が分からなかったので自動同期は止めました。

◯2010年3月4日追記
よくよく考えたらsvnのゲートウェイとなるリポジトリのmasterとsvn/trunkは別個の歴史を辿るんですね。なので前にマージされてからの差分を求めるにはsvn/trunk..masterでは駄目ですね。上のスクリプトはなんとなく書き換えてみましたが、gitの理解が足りてないですね。

Subversion, Git, Redmine, Hudson – 今考えている連携2

2月 27th, 2010

Subversion, Git, Redmine, Hudson – 今考えている連携 » tune webでいただいたコメント、実際にやってみて出来なかったことを反映してアップデートしてみました。

前回からの差分がいくつかあります。

  • git svnの窓口となるリポジトリとgit開発時のcentralとなるリポジトリを分けた。
  • 内部設計書としてソースからDoxygenで生成したものを使っていたことを思い出したので追記
  • 外部との作業項目のやりとりにRedmineからチケット一覧をExcelをエクスポートして使っているのを追記
  • お互いにパッチを送り合うのをやめて、パッチをもらったらgit-bundle(1)で作成したファイルを送るようにした。これなら物理的に離れていても同じリポジトリを使って作業出来る。

gitとSubversionの橋渡しにかなり悩んだのですが、実用Gitによると、窓口を1つにして、いくらか気をつけなければならない点があるそうです。これはまた別のエントリで。

上記構成が出来そうな目処はついてきたんですが、余力があればgerritOverview — Sphinx v0.6.4 documentationTestLinkをうまく組み合わせたいですね。

◯2010年3月3日追記
離れた箇所にリポジトリをコピーするのにはgit bundleは便利だけど、差分を渡し続けるのは無理がある気がしてきた。
masterを両者で同期を取るとなると、git bundleで貰う側はローカルのmasterにpushしちゃうとbundleからpullするのが面倒になる。ローカルでmasterにコミットするなというのは結構な制限を課している気がする。branchを切って、branchを同期するようにすると、branchからcherry-pickするような運用になるのだろうか? じっくり同期を取れる気がするけど、そこまでして同期をとらなきゃいけないものでは無い気がする。

そこまでしてリポジトリの同期を取るよりも、素直にパッチを送り合う方がいい気がしてきた。リポジトリ構成さえあっていれば最初のbundle送付すらいらないかも。
前にコメントをくれたmootohさんも、よくよく読んでみると「bundleを最初に送付して、あとはパッチを”送り合ってる”」てなってるし。

何か思い違いをしているかもしれません。おかしな点に気づかれた方は遠慮なくツッコミください。

Subversion, Git, Redmine, Hudson – 今考えている連携

2月 21st, 2010


これからが本番、検索エンジンから来た方は先にSubversion, Git, Redmine, Hudson – 現状の連携 » tune webを読むことをおすすめします。上記が週末考えていた「こういう連携なら今の問題点を解消できるかな」と思えるフローです。「こうしたほうがいいよ」とかコメントありましたらお待ちしています。

1番のポイントはバージョン管理システムとしてGitを中心に据えました。社内はSubversionで統一するという規則があるので残すとして、開発チーム内ではgit svnを使ってGit化し、Subversionを直接触らないようにします。協力会社はSubversion縛りが無いのでGitで統一してもらいます。これまでは差分ファイルを送り合っていましたが、Gitを使えばパッチをうまく作り、修正単位でパッチファイルをやり取りすることが出来るでしょう。これまでは複数の修正がまとめて送られてきてましたが、パッチ単位ならレビューもやりやすく、「こうした方がいい」とか「こうして欲しい」というやりとりもやりやすくなります。

リポジトリがプロジェクト専用になるので、フックスクリプトも仕掛けやすくなります。現状は「空メッセージのコミットは禁止」程度の緩めのものですが、コミットメッセージに Issue ID を含むことを強制させる Git のフックスクリプトを書きました|SNS構築の手嶋屋を参考にすればRedmineのチケットが無いコミットは禁止できます。これで闇コミットがなくなるはず。

さらにGitを使えば「歴史を書き換えて」テストが通らないコミットをなかった事にも出来るはずです。コミット前にテストをする機能がTeamCityにはありますが、Hudsonにはありません。[#HUDSON-1682] Pre-tested commit feature – Hudson JIRAとして要望が挙げられていますが実現はまだ先になるでしょう。HudsonのGit Pluginのページにpushされた変更をテストして、成功したらmaster/stableにマージする設定手順がありましたが、リリースブランチを持ったときにも同じように出来るかは不明です。

というのをtwitterにつぶやいていたところ、@bleisさんと@masanobuimaiさんから情報をもらえました。Gitのフックスクリプトですが

  1. pre-receiveでpush前の状態をタグ付けする設定を追加
  2. post-receiveでHudsonの複数ジョブをキックして起動。
    1. テスト結果を取得して全て成功したらタグを消してgit svn dcommitを実行
    2. 1つでも失敗していたらpre-receiveでタグ付けしたバージョンに戻してpushをなかった事にする。

とすることでいけそうです。Hudsonのジョブ実行結果を知る方法は複数あると@masanobuimaiさんに教えてもらったのがPlugins – hudson – Hudson Wikiのページです。プラグイン無しでもリモートAPIを使っても出来るのかもしれません。
自前でフックスクリプトを用意する必要がありますが、出来ないことはなさそうです。
post-receiveでのテストに多少の時間がかかることを踏まえ、Redmineで参照するリポジトリはGitではなくSubversionにするのが良さそうです。

あとはRedmineのメール経由のチケット登録機能を有効にして、HudsonのナイトリーテストでこけたらカスタマイズしたメールをRedmine指定のアドレスに送ればOKですね。上の絵には「静的解析とメトリクス集計」が入ってますが、これは内製ツールです。リポジトリを集中管理してもらえるとこういうこともやってもらいやすくなりますね。

上記構成に3月中に取り組む予定です。うまく行くといいんだけど。

Subversion, Git, Redmine, Hudson – 現状の連携

2月 21st, 2010


会社の仕事を「Gitを中心に据えた開発ワークフロー」に変えたいなとこの週末ぼんやりと考えていたんですが、現状を整理して残しておくのも、あとで振り返った時も参考になるかもしれないと思って残しておきます。

開発しているものは画像処理ライブラリで、言語はC言語。プラットフォームはWindowsとLinux両方に対応していて、32bitと64bitどちらでも動くようにしたいのが前提。ほとんどのソースは共用出来るようにしています。開発者はWindowsを使ってVisualStudioで開発し、自動テストやリリース時はLinuxでMakefileを使ってビルドします。

バージョン管理は課で管理しているSubversionを使い、他のプロジェクトともリポジトリを共用しています。他に使っているツールはテスト自動化にHudsonとタスク管理と障害管理でRedmineがあります。Hudsonは2種類のテストを管理していて、コミットの度に動くビルドのテストとCUnitを使った単体テストと、毎晩複数枚の画像入力を処理するストレステストの実行を制御しています。Redmineはチケット駆動開発(TiDD)を意識し、コミットはチケットに関連付けるようにしています。あとは開発者の1人(自分です)がgit svnを使ってローカル開発をgitにしているぐらいです。

開発メンバは社内に2人、あとは社外の協力会社に手伝ってもらっています。両者の間にはネットワーク的に「超えられない壁」があり、リポジトリを参照させることができません。ということで双方でSubversionリポジトリを持ち、同期は定期的(1〜2週間おき)に差分ソースを送り合って手動で実行しています。

ここまでが現状の紹介、以下は上記フローによる問題点です。
問題1 双方でのソースの同期を取るのが大変
一週間から二週間に一度差分ファイルを送り合ってるけど、マージに時間がかかる上、複数の変更がごっちゃになっておくられてくるためレビューしたくても途中で断念してしまう。

問題2 単体テストが通らないコミットが履歴に残り消せない
ちょっとしたミスがあってビルドに失敗してもsvnの履歴が消せない。Windows上での単体テストはコミット前に確認するけどLinuxで毎回やるのが面倒になったり、32bitと64bitを全組み合わせでやるのは面倒だったりする。動くだろうと思ってコミットすると壊れていたりとか。
あとはgccでは警告をエラー扱いしているので、使われてない変数があるとかその程度のことでエラー扱いされてしまう。

問題3 闇コミット
RedmineでTiDDに近いことをしているが、闇コミットが結構ある。スタイル直しただけとか、変数名リファクタリングしたとか。複数プロジェクトでリポジトリを共用してるからチケットIDが無いコミットを弾くのが難しい

問題4 Redmine上でチケットとコミットの関連付けを直せない
テストで問題が見つかってもRedmineのチケットとコミットの関係を直すことが出来ない。間違ってるfixesが残ってしまい、何とも出来ない

問題5 HudsonでビルドにコケてもRedmineのチケットに自動登録されない
Hudsonでコミットごとの単体テストとは別にストレステストを含むナイトリーテストを設定しているが、テストに失敗した時にRedmineのチケットが自動登録されない

問題6 TortoiseSVNのパッチ機能が腐ってる
外注からパッチで差分を送ってもらうことも考えたが、TortoiseSVNの文字コード認識がおかしく、一度エディタで開いて文字コードを保存し直す必要があった。(ちなみにソースはUTF-8)

問題7 機能ブランチの管理が大変。
一度切るとなかなか戻ってこない。戻すにも準備がかなり必要になる。試しに作ったけどいらなかったブランチも扱いに困る。

問題だけ見ると「何でこんなフローにしたんだ」と自分でも思ってしまうけど、少しずつプラクティスを取り入れた結果うまく連携できてない現状になってしまった。近々Subversionのリポジトリを課管理から本部管理に移行するお仕事があるのでこれを機にこれまでの問題点を解消しようと思っています。

詳細は後半で → Subversion, Git, Redmine, Hudson – 今考えている連携 » tune web

TortoiseSVNのオーバーレイアイコンが表示されないとき

1月 10th, 2010

TortoiseSVNだけじゃなくてTortoiseCVS/TortoiseHg/TortoiseGitでも同じだと思います。オーバーレイアイコンが表示されない原因はアイコンキャッシュが壊れていたりといろいろ原因があるのですが、ついこの前気づきにくい理由で表示されないことがあったので参考までに紹介しておきます。

会社の作業環境ではTortoiseSVNとTortoiseGitをインストールしていたのですが、いつからか両方のオーバーレイが表示されなくなってしまいました。てっきり両者が競合でもしてるか、TortoiseGitが悪さでもしているのだろうと思っていたのですが、調べてみるとWindowsの仕様で表示されなくなっていました。

Windowsではオーバーレイさせるアイコンをレジストリで記憶していますが、最大で15個という制限があるそうです。それ以上もレジストリに登録できるのですが、最初に登録されたものから無効になってしまうそうです。自分の場合、あとからインストールしたOffice2010(Microsoft Ofiice Groove?)が原因だったようです。

対処法としてはレジストリをチェックして15個以上登録されてないか確認し、不要なものをアンインストールするか、レジストリの不要項目を削除すればOKです。チェックするレジストリは”HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows
\CurrentVersion\Explorer\ShellIconOverlayIdentifiers”です。

以下のブログを参考にさせていただきました。

入門Git

11月 10th, 2009

入門Git (単行本)
4798023809

少し流行からは遅れましたが、ようやく読み終わりました。既に各所で絶賛されていますが、自分もなかなかの名著だと思います。Gitの表面的な使い方だけでなく、その設計指針や、背後にある思想などGitのエッセンスを余すこと無く、”日本語で”学ぶことができるのがすばらしいと思います。

Chapter8まではWEB DB Pressの特集の焼き直しで、残りが本書で書き下ろされた内容かと思います。自分はWEB DB Pressの特集を事前に読んでいたので前半は復習がてら読めましたが、分散バージョン管理の本を初めて読む人には1度で理解するのが難しいかもしれません。でもゆっくり読めば分かるのではないかと思います、たとえ話も上手ですし。

Chapter10以降は急に趣が変わって、辞書的な内容が強い気がします。Gitを日頃から使ってないと使い方のイメージがわかず、所々引っかかってしまうのではないかと思いました。自分もその口です。Amazonの批評にある難しいという印象はこの章以降が影響しているのではないかと個人的には思っています。

自分が仕事でGitを本格的に使い始めてまだ半年も経っていませんが、最近Subversionの時代遅れ感を強く感じます。作業途中のファイルを気軽にコミットしたり、コミットの歴史を書き換えたり、機能追加のためのブランチ(本書ではトピックブランチと言ってます)を気軽に作ってマージしたり、どれもSubversionでは日常的に運用できないことばかりです。

自分がバージョン管理を使い始めたのはCVSからSubversionの変わり目、Subversionの1.0が登場する半年ぐらい前だったのですが、バージョン管理システムはこれで完成系だろうとCVSとSubversionを学んで思っていました。大間違いでした。Subversionで満足してしまっている人こそ本書を読むべきだと思います、強く強くお勧めします。Subversionはまだ主流かもしれませんが来年、再来年は分かりません。今Gitの存在を知ったときに勉強を始めるべきです。

とりあえず周りのチームに広めるところから自分は始めます。WindowsもTortoiseGitがあって、普通に使えてますよ。

gitでリポジトリからのチェックアウト時に文字コードを変換する

9月 30th, 2009

ようやく実現できたのでやり方をメモ。
設定ファイルで拡張子に基づくフィルタリングをすればOK。

ProGitの情報によるとリポジトリから取ってくるときをsmudge、リポジトリに突っ込むときをcleanと呼ぶらしい。

以下はリポジトリ内のソースファイルがUTF-8 BOM有、改行コードがLFCRの場合の設定例。文字コード変換はnkfを使っています。
WindowsのVisualStudioに合わせると上記設定が望ましいが、Linux環境でgccを使うにはBOM無しにして、改行コードをLFにする必要がある。
まず.gitconfigファイルに以下を追加する

[filter "fixencoding"]
clean = “/usr/local/bin/nkf -w8 -Lw”
smudge = “/usr/local/bin/nkf -w -Lu”

これでsmudgeでUTF-8 BOM無し/LF、cleanでUTF-8 BOM有り/LFCRとなる。

これだけではダメで、フィルタ処理をかけるファイルを指定する必要が有る。
gitの管理フォルダである.gitがあるトップディレクトリに.gitattributesファイルを以下の内容で作成し、git checkout -fする必要が有る。

*.c filter=fixencoding
*.cpp filter=fixencoding
*.cxx filter=fixencoding
*.h filter=fixencoding
*.hxx filter=fixencoding
*.txt filter=fixencoding
Makefile filter=fixencoding

/usr/share/git-core/templates/info/attributes
を作って上記内容を書いておくとclone時に.git/info以下にコピーされてgit cloneしただけで文字コード変換が動くようになる。

動かすにあたって問題となったのはgitでチェックアウトしただけで編集されたことになってしまうファイルが多々発生したことです。原因はいろいろあったのですが
リポジトリインデックス内のファイル文字コードがバラバラだった(BOM無しファイルが紛れ込んでいた とか)
ファイル内の文字に半角カナがあるとダメらしい。
ファイル内の文字に機種依存文字(実際にあったのは丸数字)があるとダメらしい。

git statusなどで編集が有ったかどうかはインデックス内の状態と比較するからcleanして元々の状態と変わってしまうと当然チェックアウトしただけで編集されたと勘違いされてしまうファイルができてしまう ということですね。
WEB DB Press Vol.50で解説されていたgitの内部データ構造を知ってようやく理解できました。

Subverisonだと文字コードをうまく変換する機構も無いのでgitをかましてやるのが便利ですね。