2012年9月13日木曜日

git pull 時の rebase オプションのススメ


今日は、Git で複数人作業を行う際に共有リポジトリから pull する際の rebase オプションの必要性について検討してみました。

タイトルで結果は想像つくような気がしますが、順を追ってみましょう。

  1. git pull でやってること
  2. merge と rebase
  3. git pull と git pull --rebase
  4. まとめ



  1. git pull でやってること

git pull コマンドは、fetch, merge をまとめて実行しています。
つまり、リモートブランチの最新のコミット情報をローカルトラッキングブランチへ持ってきて(fetch)、持ってきた最新のコミット情報とローカルブランチをマージ(merge)します。

参考:3.5 Git のブランチ機能 - リモートブランチ


  2. merge と rebase

ブランチを統合するには、マージの他にリベースがあります。

mergeでは、ブランチAコミット1から派生したブランチA2コミット2とブランチA3コミット3を統合した場合、統合結果のコミットオブジェクト4が統合先のブランチ上に作成されます。

これに対し、リベースでは、その名のとおり、基点を移動するかのような挙動をとります。
つまり、コミット3の基点がコミット1ではなく、コミット2とし、コミット2に対してコミット3の差分を適用します。

参考:3.6 Git のブランチ機能 - リベース


  3. git pull と git pull --rebase

共有リポジトリから資産を取得するのに通常は、git pull を利用しますが、このコマンドにはオプションとして --rebase オプションが用意されています。

rebase オプションをつけた場合は、fetch後の挙動がmergeではなく、rebaseとなります。

以下、それぞれの挙動と、それによるコミット履歴の差を確認してみました。

環境

確認用に以下のシンプルな構成で分散環境を構築します。
  • リモートリポジトリ:gitPullTest.git
  • ローカルリポジトリ(Alice):gitPullAlice
  • ローカルリポジトリ(Bob):gitPullBob
  • バージョン管理対象:gitPullTest.txt

以下の動作検証を行います。
  • リポジトリは全てローカルマシン上に作成する。
  • Alice役とBob役がそれぞれ独自の編集を行う。
  • Aliceが先にプッシュし、Bobは、git pull、git pull --rebase で変更を取り込む。
  • 例を単純にするため、masterブランチのみとする(git flowは利用しない)

準備(共有リポジトリ、Alice, Bob リポジトリ作成と内容の同期)


git pull(マージによるコミット)


git pull --rebase(リベース)


結果(コミット履歴)







コミットログ最下部は、初期登録時のコミット
下部2番目から4番目までが、git pull によるコミット履歴(3コミット)
下部5番目から6番目までが、git pull --rebase によるコミット履歴(2コミット)


  4. まとめ

このように、マージの場合、マージコミット分が履歴に残るのに対し、リベースでは(例えコンフリクトが発生したとしても)コミット履歴は直線的に保たれます。
このことから、共有リポジトリを介した頻繁に資産のやり取りが発生するような開発ではgit pull 時のrebaseオプションは以下のように使い分けるべきだと考えられます。

  • 通常の資産共有の一環としてのgit pull では、リベースを用いる。
  • 統合した事実を残しておくべき場合(リリースブランチへの機能追加など)はマージを用いる。


やはり、通常開発時はリベースを用いることのメリットのほうが多いと思います。
(資産のやり取りごとに不要なマージコミットができるのは避けたいはず)
また、マージを用いるべき箇所に関してはgit-flowなどの運用フローを採用することで意識しないようにするほうが確実です。

git-flowに関しては、以下を参考にしてください。
ゼロからわかるgit-flow

Gitに関しては、色々な運用方法があるので、他にもよいプラクティスがあれば教えてもらえればうれしいです。

ではでは。

1 件のコメント: