履歴を整える(amend・rebase)
コミットメッセージを直したい、枝分かれした履歴をまっすぐに整えたい。そんなときに使うのが commit --amend と rebase です。mergeとの違いである「履歴の形」、そして最も大事な鉄則——共有済みの履歴は書き換えない——まで、事故を防ぎながら履歴を整理する考え方を学びます。
コミットした直後に、メッセージの誤字に気づいたり、1行足し忘れに気づいたりすることはよくある。そのたびに新しいコミットを積むと、履歴が「修正」「また修正」「typo直し」のようなノイズだらけになってしまう。
こうした小さな直しのコミットが積み重なると、あとで履歴を読む人(未来の自分を含む)にとって、本当に意味のある変更がどこにあるのか探しにくくなる。履歴は記録であると同時に、他人に読まれるドキュメントでもある。
直前のコミットをやり直したいだけなら git commit --amend が使える。新しいコミットを作るのではなく、直前のコミットの中身やメッセージを直接書き換える操作だ。
🪄 rebase=枝の付け根を移す
amend が1つのコミットの直しなら、rebase は複数のコミットの並び・付け根を移す操作だ。あるブランチの変更を、別のコミットの上に「積み直す」。
たとえば main から feature ブランチを切って作業している間に、main側で新しいコミットが進んでいたとする。この状態で git rebase main を feature 側で実行すると、feature の変更が「今のmainの最新地点」の上に付け直され、履歴が一直線になる。
⚖️ mergeとの違いは「履歴の形」
merge は枝分かれをそのまま残し、合流点(マージコミット)を作る。過去に「いつ・どのブランチが・どこで合流したか」がそのまま記録として残るのが特徴だ。
rebase は枝分かれを解消し、一直線の履歴に作り直す。読みやすくすっきりするが、「元々は別のブランチで作業していた」という事実そのものは履歴上から見えにくくなる。
実際のチームでは、リリースブランチのような「絶対に事実を改変したくない」履歴はmergeで、個人の作業ブランチのように「他人にはきれいな1本の流れとして見せたい」履歴はrebaseで、と使い分けることが多い。
🚫 鉄則:共有済みの履歴は書き換えない
amend も rebase も、コミットの中身そのものを書き換える操作だ。書き換えると、そのコミットのハッシュ値(識別子)も変わってしまう。
自分のパソコンの中だけで、まだ誰にもpushしていないコミットを直す分には問題ない。だが、すでに git push してリモートに送り、他の人がそれを取り込んでいるかもしれないコミットを書き換えると、大きな混乱を招く。
具体的には、他の人が同じコミットをベースに作業を始めていた場合、書き換え後にその人がpullすると「履歴が一致しません」といったエラーに直面したり、最悪の場合は自分の変更と相手の変更が二重に混ざってしまったりする。
⚠️ force pushの危険と --force-with-lease
書き換えたコミットをどうしてもpushし直す必要がある場合(自分専用のブランチで作業していたときなど)、通常の git push は「履歴が食い違っている」と拒否される。これを無理やり通すのが git push --force だ。
だが --force は、自分が知らない間にリモート側へ誰かが新しいコミットを積んでいた場合、それごと踏みつぶして消してしまう危険がある。
そこで使うべきなのが git push --force-with-lease だ。これは「自分が最後に見たリモートの状態から、誰も変えていない場合に限ってpushする」という安全確認付きの強制pushになる。もし他の人が何か追加していたら、pushは拒否され、上書き事故を防げる。
履歴を整えることは大事だが、それ以上に大事なのは「他の人と食い違いを生まないこと」だ。手元だけで整える分には自由に、共有した後は足し算だけで直す。この線引きを覚えておけば、rebaseもamendも安全な道具になる。
最初のうちは「rebaseは怖いから使わない」という選択も間違いではない。自分だけの練習用リポジトリで何度も試し、amendとの感覚の違い、コンフリクトが起きたときの止まり方に慣れてから、実務のブランチで使い始めるくらいで十分だ。
🧯 rebase中に迷子になったら
rebase の途中でコンフリクトが起きると、作業は一時停止し、Git は「このコミットを付け直そうとしたら競合しました、直してから続けてください」と案内してくる。
この状態で、コンフリクトしたファイルを直して git add し、git rebase --continue と打つと、次のコミットの付け直しに進む。これをコミットの数だけ繰り返す。
🆚 amendとrebase -iの位置づけ
amend は直前の1つのコミットだけが対象だが、「3つ前のコミットのメッセージを直したい」「途中のコミットを2つにまとめたい」といった、直前以外のコミットに手を入れたい場合は rebase -i(--interactive、対話的rebase)という発展的な使い方もある。
履歴整理の道具は、使いこなせば読みやすい記録を残せる一方、使い方を誤ると混乱のもとにもなる。「今のコミットは共有済みか、まだ自分だけのものか」を毎回意識する。この一点さえ守れれば、amendもrebaseも怖がる必要はない。