git merge
コマンドの概要
複数のブランチに分岐して管理されたコミットを統合して1つのブランチにするコマンド。
コミットは親子関係で把握されており、共通のご先祖さまにさかのぼってそこからの変更が統合される。
mainブランチでEをコミットしてgit switch -c topicとし、topicブランチではAからCのコミット、mainブランチではF、Gのコミットをした場合、以下のようになる。
git merge topicとするとmainブランチが指し示すコミットHは、コミットAからFまでの内容を含んだものとなり、topicブランチはCを指したまま。
git mergeしてもtopicブランチは削除されない。マージによりtopicブランチがもう不要となったら、git branch -d topicでブランチを削除する。[topic]が削除されるだけで、コミットA,B,Cが削除されるわけではない。コンフリクト
各ブランチで同じ箇所を変更してしまった場合、Gitがどちらを採用すべきか判断できず、マージがストップしてしまうので、手動で解決する。
コンフリクトするはずじゃなかった、というときはgit merge --abortでマージを中止し、各ブランチを見直してみる。
コマンドで
- コンフリクトでマージがストップ
git statusでコンフリクトしているファイルを確認git diffgit diff --oursgit diff --theirsgit diff --baseでコンフリクトしている差分を確認。git checkout --oursgit checkout --theirsでどちらかの変更を適用するか、ファイルを直接編集して解決する
マージツールで
git diffしながらエディタをさわるのも面倒なので、git mergetoolでマージツールを利用して解決する。
- コンフリクトでマージがストップ
$ git mergetool
vim diff を使用する場合、
という画面構成。ウインドウ間の移動は ctrl+w hjkl
MERGEDを直接編集してコンフリクトを解決し、:xaで保存、全ウインドウを終了。
- vim の
:wqと:x
どちらも保存して終了だが、:wqはかならず保存して終了するが、:xは変更があった場合だけ保存して終了する。(:ZZは:xと同じ)
ファストフォワード
マージしたいブランチが現在のブランチより先に進んでおり、現在のブランチがコミットしていないとき、git mergeをすると、そのままHEADがマージしたいブランチが指しているコミットに移動する。
コミットE でgit branch -c topicとし、mainではコミットなし、topicでA、B、C のコミットをしたとき
git merge topicとするとgit merge --no-ff topicとし、ファストフォワードさせずにマージコミットを作ることもできる。
git pull時にはファストフォワードしたいので(ファストフォワードしないとgit pullのたびにマージコミットができてしまう)、その設定もあわせて。1// ファストフォワードせずにマージコミットを作る、ただし git pull のときはつくらない
2$ git config --global merge.ff false
3$ git config --global pull.ff only
ブランチをまとめてひとつのコミットにする
ファストフォワードができる状況で、マージしたいブランチのコミットをまとめてひとつのコミットにすることもできる。
コミットE でgit branch -c topicとし、mainではコミットなし、topicでA、B、C のコミットをしたとき
git merge --squash topicとするとコミットA、B、Cにおける変更がインデックスにステージされる。そのままgit commitすると1$ git merge --squash topic
2$ git commit -m"merge branch topic"