本稿では、 Git でブランチをマージした際にコンフリクトした xib ファイルの衝突解決手順を解説する。
追記: Xcode 5 から導入された新しい xib フォーマットではコンフリクトが起こりにくくなっている。また、コンフリクトした場合に手作業で xib ファイルを編集することも、以前のフォーマットと比べれば容易になっている。本稿では以前のフォーマットを使っていることを前提に話を進める。
ステップ0:コンフリクトの解決をあきらめる
Xib ファイルをテキストエディタで編集してコンフリクトを解決しようなどと考えてはいけない(変更がごく小規模な場合を除く)。コンフリクトした xib ファイルは捨てて素直に作り直すのがよい。ただし、記憶を頼りに変更を再現する必要はない。 Xib ファイルの要素は コピー&ペーストできる ので、変更点の移植は比較的簡単にできる。
ステップ1:ベースにする xib ファイルをチェックアウトする
以下、 base
ブランチに other
ブランチをマージし、 Foo.xib
がコンフリクトしたと想定する:
git checkout base
git merge --no-ff other
# Foo.xib がコンフリクト
まずはどちらかのブランチから Foo.xib
をチェックアウトする。ここでチェックアウトしたファイルをベースにして他方のファイルの変更を取り込むため、共通の祖先から見て 変更量が多いほう を選ぶとよい:
git checkout base -- Foo.xib
# または
git checkout other -- Foo.xib
ステップ2:他方の xib ファイルをプロジェクトに追加する
他方のブランチから xib ファイルを Foo_.xib
に書き出す:
# ステップ1で base をベースにしたなら
git show other:Foo.xib > Foo_.xib
# other をベースにしたなら
git show base:Foo.xib > Foo_.xib
そして Foo_.xib
をプロジェクトに追加する。
ステップ3:ベースとなる xib ファイルに他方の要素を取り込む
Foo_.xib
を開き、取り込みたい Foo_.xib
の要素を選択してコピーする。 Foo.xib
を開き、コピーした要素をペーストする。
コピー&ペーストでは Identifier や Tag、 Editable といった属性もコピーされる。ただし、アウトレットと Cocoa Binding の設定は コピーされない ので、コピー後に改めて設定する。また、要素の Object ID も変化していることに注意。
要素のコピーと設定を終えたら Foo_.xib
をプロジェクトから削除する。
ステップ4(オプション): strings ファイルを編集する
ローカライズに使う strings ファイルが存在する場合、コピー後の要素に合わせて Object ID を書き換える:
/* Class = "NSButtonCell"; title = "Button"; ObjectID = "42"; */ // ←ここと
"42.title" = "ボタン"; // ←ここの ID
ステップ5(オプション): ibtool で xib をローカライズする
ibtool コマンドで差分ローカライズを実践しているなら、コンフリクトした2つの xib ファイルの 共通の祖先 を差分のベースにするとよい。
git show `git merge-base base other`:Foo.xib > Foo_common_ancestor.xib
ibtool --localize-incremental \
--previous-file Foo_common_ancestor.xib \
--incremental-file Foo_localized.xib \
--strings-file Foo.strings \
--write Foo_localized.xib \
Foo.xib
rm Foo_common_ancestor.xib
Git Tips
マージ中の2つのブランチの、元々チェックアウトされていたほうは HEAD
で参照できる。他方(git merge
の引数にしたほう)は MERGE_HEAD
になる。つまりステップ1とステップ2は次のようにも実行できる:
git checkout HEAD -- Foo.xib
git show MERGE_HEAD:Foo.xib > Foo_.xib
また、 git checkout
には --ours
と --theirs
オプションもある:
# 同じ
git checkout HEAD -- Foo.xib
git checkout --ours -- Foo.xib
# 同じ
git checkout MERGE_HEAD -- Foo.xib
git checkout --theirs -- Foo.xib