git mergeのbug?

XCodeのプロジェクトをgitで管理している際に、mergeでいろいろと問題が起きたのでメモっておく。

XCodeのプロジェクトを作ると、プロジェクトのファイル・グループ構造を管理するxxx.pbxprojというファイルがXCodeによって自動生成される。内容はjsonっぽい形式(property list)のテキストファイルだが、XCodeがプロジェクトの構成を管理するために簡易データベース的に使っているファイルなので、基本的には人間がいじっちゃいけないファイルである。

プロジェクトにファイルを追加するとpbxprojの内容が書き換わるので、gitなどでチーム開発するとどうしても頻繁に更新が入り、pbxprojがコンフリクトしてしまう。コンフリクトするたびに、本来人間が編集すべきでないpbxprojをテキストエディタで開き、<<<とか>>>でgrepして手作業で修正、とかチマチマやる必要がある。だるい。

ということで、このへんのダルさを解決するための方法が以下のページで紹介されていた。

http://robots.thoughtbot.com/post/33796217972/xcode-and-git-bridging-the-gap

.gitattributesというファイルにpbxprojはバイナリファイルであることを指定することで、テキストデータではなくバイナリファイルとしてマージさせる、というもの。こうすることでコンフリクトが発生したときにgitがupstreamのファイルを優先で自動でマージしてくれる、という話。

確かにこの方法であれば、コンフリクトせず良い感じにマージしている「ように見える」のだが、たまに構造的に誤ったマージをしてしまうことがある。しかし、git mergeコマンド自体は成功してしたことになっているの、上手く言ったように見えて実はpbxprojがぶっ壊れてる、という状態になってしまうことがある。

 

例えば、こんな感じのXCodeのpbxproj形式のファイルがmasterにあったとする

f:id:kenmaz:20130131222816p:plain

ここでfooというブランチを切って、このpbxprojを以下のように修正してコミットする。

f:id:kenmaz:20130131222823p:plain

一方で、masterブランチのほうにも以下のような修正を加えてコミットする(fooブランチと似たような場所・内容の修正)。

f:id:kenmaz:20130131222820p:plain

で、.gitattributesの設定をした上で、fooの修正をmasterにマージする。 すると以下のように意図しない、誤ったマージをしてしまう(git mergeコマンドは成功したことになっている)。

f:id:kenmaz:20130131222826p:plain

ちなみに、.gitattributeを設定しなければ、以下のようにコンフリクトが発生する。ということでテキストエディタでマージ解消するんだが、よくみるとこちらの差分もやっぱりちょっとおかしい感じになってしまっている。

f:id:kenmaz:20130131222833p:plain

 

結論

.gitattributeを設定して楽しようとするとすると思わぬマージ結果になっちゃうことがあるので、ちゃんとコミット前に目視で確認するか、そもそも.gitattribute指定しないほうがいい。

なんか他に良い解決方法があれば教えて下さい。