Gitのコンフリクト解消は、私たち初心者エンジニアにとっては恐怖イベントですよね。
コンフリクトが起きないことを願って毎回mergeまたはrebaseしていますが、やはりチームで開発している以上、コンフリクトは必ず起きます。
コンフリクトが起きた時は、current changeを維持するか、incoming changeを受け入れるか、はたまた両方を適用するかの選択が迫られますが、mergeする時とrebaseする時で、current changeとincoming changeの指すものが異なるので、まとめました。
💡この記事のポイント
「current change / incoming change」の意味は、merge と rebase で逆転する
その理由を根本から理解できるように解説します!
そもそもコンフリクトはなぜ起きる?
Gitのmergeやrebaseは、いずれも「2つのブランチの内容を統合する」作業です。
- ブランチAとブランチBが同じ行に変更を加えていた
- Git が「どっちが正しいの?選んで!」と言ってくる
これがコンフリクトです。
conflictは「衝突・対立」という意味なので、言葉の意味通りですね!
コンフリクト解消時のcurrent / incoming changeの直感的な意味
言葉を直感的に捉えれば、
- current change:今の状態(=自分が書いたコード)
- incoming change:外からやってくる変更(=取り込むコード)
merge の時はこの解釈でOKです!
ただし、rebaseではこれが逆転します。
この謎は、git mergeとgit rebaseの仕組みを理解すると分かりやすくなります。
merge と rebase の違いを一言で
| 操作 | 目的 | 何が起きる? |
|---|---|---|
| merge | 他ブランチを今の自分のブランチに追加 | current に incoming を上書き |
| rebase | 自分のブランチの土台(base)を更新 | 古い土台から新しい土台に移行し、自分の変更を再適用 |
rebaseで反転するcurrent / incoming の意味
上の表の通り、git mergeは別のブランチを自分のブランチに統合することで変更を取り込む方法。
一方で、git rebaseはブランチを切ったその基盤(base)を変えることで変更を取り込みます。
例えば、mainブランチ(状態A)からブランチを切り、作業していたとします。
次の日mainブランチに新たな変更が加えられました。(状態B)
ここでrebaseすると起こるのが以下のステップ。
①状態Aをベースにしていたので、状態Bから切った状態にベースをrebaseする
②状態Bに更新されたベースの上にこれまで自分が作業していた変更内容を乗せ直す
③最新のベース(状態B)と今乗せ直した変更箇所で異なる部分があるよどっちを維持したい?とコンフリクトが起きる
この文脈で考えると、「やってくる変更(incoming change)」はどちらを指しますか?
...お気づきの通り、私がこれまで作業していたコードがincoming changeとなります。
本質を理解するって大事
一見謎に思えたこの逆転ですが、実際に何が起きているかを理解すると、むしろ逆転する方が自然な考え方ですよね。
「自分の変更はcurrent、取り込むブランチはincoming」とだけ魔法の言葉のように覚えていると思わぬ落とし穴にハマります。
本質を理解するって大事ですね👀