上川純
一
![]() |
2008 年 11 月、 12 月、 および 2009 年 1 月には事前課題を Git を利用して Git の生成するパッチをメールで提出してもらう という形式にしていました。 その場合には git pull するたびにコンフリクトが発生します。 その原因となる仕組みと対策方法 について説明します。
それでは、 Debian 勉強会の 2008 年 11,12 月の資料でコンフリクトが発生しやすかった理由を分析してみま しょう。
-\subsection{}
+\subsection{XXXX} + 内容 + |
同じファイルについて作業し、 しかも同じ場所にすこしづつ異なる変更を別の人が行うという仕組みになっていました。 この場 合、 二つのパッチはかならずコンフリクトし、 手動で解消する必要があります。 今回パッチが同じ場所に挿入している場合に、 順序は問わないので適当でよいのですが、 git apply にはその知識はないため、 毎回コンフリクトの解消を行い ます。
締切り直前に作業するのが習慣のため、 複数の人がある時点の同じコミットに対してパッチを作成、 それを上川がある時点で マージしました (図 1)。
毎回コンフリクトが発生するのですが、 それを上川が解消してマージとして記録されています。 そのため、 各自 が提出したバージョンとは若干違うパッチとなって alioth.debian.org にある Git ツリーにマージされてい ます。
Git はデフォルトでは master ブランチで作業します。 git pull コマンドは Alioth にあるリモートのツリーの情報を origin ブランチにとってきて、 master ブランチにマージします。 マージする内容がなければ、 Fast-forward され ます。
まず最初に各自が自分の Git ツリーの master ブランチでパッチを作成します。 そして、 git format-patch の結果をパッ チファイルとして送付します。 上川がgit am でそのパッチを適用し、 Alioth の Git ツリーに公開します。 複数人が同 時期に事前課題を提出しているため、 git am でパッチを適用した場合にそのままでは適用できない状況が おき、 「コンフリクト」 が発生します。 「コンフリクト」 が発生した場合には上川が手動でその部分を修正し ます。
各自が Alioth の Git ツリーの最新バージョンを git pull で取得してくると origin ブランチには上川の作成した変更を 伴ったパッチが入ります。 master ブランチで自分の作成したものからは若干変更が加わっています。 そのため、 内容に整合性 がとれるとはかぎらないため、 コンフリクトが発生します。 コンフリクトがおきなかったとしても履歴にマージが残り ます。
マージなどを解消するためには、 git rebase -i origin で不要なパッチを目視して消す作業をすればよいです。 そもそも git pull --rebase すると、 おそらくマージが残らないが、 コンフリクトの解消は必要になります。 これは面倒 です。
解決策としては、 各自が提出用のブランチを作成してそこで作業し、 そこで提出用のデータを作成してしまえばよいというの があります。
$ git checkout -b preworkXXXX origin $ # ... このブランチで作業 $ git format-patch ... # 提出してしまったら master ブランチにもどる $ git checkout master $ git pull # 上川の適用した版がとりこまれる # さらに新しいブランチを作成して次の月の作業を行う $ git checkout -b preworkYYYY origin |
preworkXXXX ブランチを毎回捨てる。
もう一つの選択肢としては、 format-patch ではない方法でデータの送受信を行うことがあります。 format-patch と git am の 送 受 信 の 過 程 で コ ミ ット の ハ ッシ ュが 異 な って い る こ と か ら 各 位 の コ ン フ リ ク ト が 発 生 し て い る の だ ろ う と い う こ と です。
git bundle でバイナリ形式でデータを送付することができます。 これを使うとハッシュは保存されるので上川のコンフリク トは解消されませんが、 コンフリクトを解消したログがそのまま残るので、 各位のコンフリクトは発生しないで しょう。
視点をすこし変えてリポジトリの管理者として上川の作業を見てみましょう。 git am でパッチを適用して、 マージするという 作業を行うのですが、 そのワークフローは実は面倒です。
特にメールを受けて、 git am がコンフリクトを起こす確率が高く、 複数のパッチがあるとほぼ確実にコンフリクトを解消す ることになります。
現状は複数の一時的に利用するブランチに git am で適用したものをあとでマージする、 という方法をとってい ます。
git checkout -b マージ用のブランチ A master
git am -3 パッチ git checkout -b マージ用のブランチ B master git am -3 パッチ git checkout master git merge マージ用のブランチ A マージ用のブランチ B コンフリクトの解消 git commit -a |
ただ、 10 人以上の事前課題のハンドリングには時間もかかり、 毎回したい作業ではないです。
自動でコンフリクトするかしないかについては判定できるし、 その結果がビルドするかはチェックできるのであれば、 自動処 理でコミットを管理できないか?と考えています。
最低限のチェックだけしてパッチを master ブランチに自動でとりこんでくれるような仕組み、 ないもんでしょうか ねぇ ?
第 48 回東京エリア Debian 勉強会 2009 年 1 月
____________________________________________________________________________________________