Git入門:バージョン管理のきほん
rebase で履歴を整える
この回でやること
自分の作業ブランチを最新の main の上に載せ直す rebase の使い方を学びます。共有済みブランチには絶対に使わない、という線引きも押さえましょう。
- 読む 約 8 分
追いつこうとするたびに、履歴が網目になる
main から feature を切って作業している間に、main にも別の人のコミットが入りました。この差を埋めるのに merge を使うと、そのたびに合流点のコミットが増えます。何度もやれば網目になります。
rebase は違う考え方をします。自分のコミットを作り直して、最新の main の後ろにつなぎ直すのです。
プレーンテキスト
rebase 前 rebase 後
A---B---C feature A'--B'--C' feature
/ /
o---o---D---E main o---o---D---E mainA' は A と同じ変更内容ですが、親が変わったので別のコミットです。ハッシュは親のコミットもまとめて計算した結果なので、載せ替えれば必ず変わります。ここが rebase の本質で、危険もここから来ます。
使いどころは、この 1 つだけに絞る
用途は「自分の作業ブランチを最新の main に追いつかせる」だけです。
ターミナル
$ git switch main
$ git pull
$ git switch feature
$ git rebase mainmain を最新にして、作業ブランチへ戻り、その上に載せ直す。履歴は一直線になり、あとで main にマージすれば fast-forward になります。コミットしていない編集があると rebase は始まりません。git status を先に確かめてください。
動くのは自分が立っているブランチだけで、main は書き換わりません。逆に main に立ったまま git rebase feature と打つと main 側が作り直されます。これは次の理由でやってはいけません。
他人が持っているかもしれない歴史は、書き換えない
rebase はコミットを作り直します。そのブランチをすでに push していて、他の人が手元に持っている場合、履歴が食い違います。
相手の手元には古い A・B・C、あなたの手元には新しい A'・B'・C' があります。相手が git pull すると Git は両方を別のコミットとして扱うので、同じ変更が二重に入るか、大量のコンフリクトが生まれます。それを誰かが強制 push で直そうとすると、相手の作業が丸ごと消えます。
| ブランチの状態 | rebase してよいか |
|---|---|
| まだ push していない自分だけのブランチ | してよい |
| push 済みだが自分しか触っていない | 状況次第。push のやり直しが要る |
main や、他の人が作業中のブランチ | 絶対にしない |
push 済みの自分のブランチを rebase すると、そのままでは push が拒否されます。このときは --force-with-lease を使います。素の --force と違い、リモートが自分の知らない状態に進んでいたら止まってくれるので、他人の作業を消す事故を防げます。
ターミナル
$ git push --force-with-lease途中で止まったら、commit ではなく --continue
rebase はコミットを 1 つずつ載せ直すので、途中で止まることがあります。マーカーの直し方は merge と同じですが、完了のコマンドが違います。
ターミナル
$ git add index.html
$ git rebase --continueコミットが 3 つあれば、最悪 3 回この解決が起きます。重いと感じたら git rebase --abort で撤退し、merge に切り替えるほうが早いこともあります。--abort で戻る先は始める前なので、作業は 1 つも失われません。
- rebase はコミットを作り直して別の土台に載せ直す操作。ハッシュは必ず変わる
- 用途は、自分の作業ブランチを最新の
mainに追いつかせることだけに絞る - 他人が持っている履歴は書き換えない。push のやり直しは
--force-with-leaseで