🐧 Linux 総合学習プラットフォーム
Git バージョン管理 ・ 中級〜上級

履歴を整える(amend・rebase)

コミットメッセージを直したい、枝分かれした履歴をまっすぐに整えたい。そんなときに使うのが commit --amend と rebase です。mergeとの違いである「履歴の形」、そして最も大事な鉄則——共有済みの履歴は書き換えない——まで、事故を防ぎながら履歴を整理する考え方を学びます。

コミットした直後に、メッセージの誤字に気づいたり、1行足し忘れに気づいたりすることはよくある。そのたびに新しいコミットを積むと、履歴が「修正」「また修正」「typo直し」のようなノイズだらけになってしまう。

こうした小さな直しのコミットが積み重なると、あとで履歴を読む人(未来の自分を含む)にとって、本当に意味のある変更がどこにあるのか探しにくくなる。履歴は記録であると同時に、他人に読まれるドキュメントでもある。

直前のコミットをやり直したいだけなら git commit --amend が使える。新しいコミットを作るのではなく、直前のコミットの中身やメッセージを直接書き換える操作だ。

メッセージだけ直す $ git commit --amend -m "ログイン画面のバリデーションを修正"
直し忘れたファイルを追加してから直前のコミットに含める $ git add forgotten-file.js $ git commit --amend --no-edit
💡
ポイント--no-edit は「メッセージは変えずに、内容だけ直前のコミットに追加する」ときに使うオプションだ。
🔗
たとえamend は「さっき投函した手紙を、まだポストの中にあるうちに書き直す」ようなものだ。相手(リモート)にまだ届いていない前提で使う。

🪄 rebase=枝の付け根を移す

amend が1つのコミットの直しなら、rebase は複数のコミットの並び・付け根を移す操作だ。あるブランチの変更を、別のコミットの上に「積み直す」。

たとえば main から feature ブランチを切って作業している間に、main側で新しいコミットが進んでいたとする。この状態で git rebase main を feature 側で実行すると、feature の変更が「今のmainの最新地点」の上に付け直され、履歴が一直線になる。

merge:枝分かれのまま合流分岐点が残るrebase:一直線に積み直す枝分かれなし・履歴が直線

⚖️ mergeとの違いは「履歴の形」

merge は枝分かれをそのまま残し、合流点(マージコミット)を作る。過去に「いつ・どのブランチが・どこで合流したか」がそのまま記録として残るのが特徴だ。

rebase は枝分かれを解消し、一直線の履歴に作り直す。読みやすくすっきりするが、「元々は別のブランチで作業していた」という事実そのものは履歴上から見えにくくなる。

💡
ポイントmergeは「事実をそのまま記録する」、rebaseは「記録を読みやすく整える」。どちらが正しいという話ではなく、目的に応じて使い分ける。

実際のチームでは、リリースブランチのような「絶対に事実を改変したくない」履歴はmergeで、個人の作業ブランチのように「他人にはきれいな1本の流れとして見せたい」履歴はrebaseで、と使い分けることが多い。

🚫 鉄則:共有済みの履歴は書き換えない

amend も rebase も、コミットの中身そのものを書き換える操作だ。書き換えると、そのコミットのハッシュ値(識別子)も変わってしまう。

自分のパソコンの中だけで、まだ誰にもpushしていないコミットを直す分には問題ない。だが、すでに git push してリモートに送り、他の人がそれを取り込んでいるかもしれないコミットを書き換えると、大きな混乱を招く。

🔗
たとえ共有履歴の書き換えは、みんなが読んでいる回覧板の内容を、勝手に破って書き直すようなものだ。すでにコピーを持って帰った人との間で、内容がずれてしまう。
つまずき鉄則は「pushして共有した後のコミットは、amendもrebaseもしない」。直したくなったら、新しいコミットを積んで直すのが安全な方法だ。

具体的には、他の人が同じコミットをベースに作業を始めていた場合、書き換え後にその人がpullすると「履歴が一致しません」といったエラーに直面したり、最悪の場合は自分の変更と相手の変更が二重に混ざってしまったりする。

未pushのコミット自分だけが見ているamend / rebase OK自由に書き換えてよいpush済み・共有済み他の人が取り込み済み書き換え禁止直しは新しいコミットで

⚠️ force pushの危険と --force-with-lease

書き換えたコミットをどうしてもpushし直す必要がある場合(自分専用のブランチで作業していたときなど)、通常の git push は「履歴が食い違っている」と拒否される。これを無理やり通すのが git push --force だ。

だが --force は、自分が知らない間にリモート側へ誰かが新しいコミットを積んでいた場合、それごと踏みつぶして消してしまう危険がある。

そこで使うべきなのが git push --force-with-lease だ。これは「自分が最後に見たリモートの状態から、誰も変えていない場合に限ってpushする」という安全確認付きの強制pushになる。もし他の人が何か追加していたら、pushは拒否され、上書き事故を防げる。

安全確認付きの強制push $ git push --force-with-lease origin feature/login To github.com:example/repo.git + 3a9f1c2...8b2e4f1 feature/login -> feature/login (forced update)
コツ--force が必要になる場面自体、共有ブランチでは基本的に避けるべきサインだ。どうしても使うときは --force-with-lease を既定にし、素の --force は使わない習慣にしておくと安心できる。

履歴を整えることは大事だが、それ以上に大事なのは「他の人と食い違いを生まないこと」だ。手元だけで整える分には自由に、共有した後は足し算だけで直す。この線引きを覚えておけば、rebaseもamendも安全な道具になる。

最初のうちは「rebaseは怖いから使わない」という選択も間違いではない。自分だけの練習用リポジトリで何度も試し、amendとの感覚の違い、コンフリクトが起きたときの止まり方に慣れてから、実務のブランチで使い始めるくらいで十分だ。

🧯 rebase中に迷子になったら

rebase の途中でコンフリクトが起きると、作業は一時停止し、Git は「このコミットを付け直そうとしたら競合しました、直してから続けてください」と案内してくる。

この状態で、コンフリクトしたファイルを直して git add し、git rebase --continue と打つと、次のコミットの付け直しに進む。これをコミットの数だけ繰り返す。

rebase中の1コミット分を解消して次へ進む $ git add config.js $ git rebase --continue Successfully rebased and updated refs/heads/feature.
つまずき「やっぱりやめたい」と思ったら、いつでも git rebase --abort で、rebaseを始める前の状態にまるごと戻せる。中途半端な状態で無理に進めるより、いったん中止して考え直すほうが安全な場面も多い。
コツrebaseは1コミットずつ順番に付け直していく処理だ。コンフリクトも1つずつ順番に出てくるので、焦らず「今どのコミットの処理中か」をメッセージで確認しながら進めるとよい。
rebase 停止中コンフリクト発生直してaddrebase --continue次のコミットへrebase --abort開始前の状態へ

🆚 amendとrebase -iの位置づけ

amend は直前の1つのコミットだけが対象だが、「3つ前のコミットのメッセージを直したい」「途中のコミットを2つにまとめたい」といった、直前以外のコミットに手を入れたい場合は rebase -i(--interactive、対話的rebase)という発展的な使い方もある。

つまずきrebase -i は自由度が高い分、操作を誤ると意図しない形で履歴が変わりやすい。まずは amend で直前コミットの直しに慣れ、rebase で枝の付け根を移す感覚をつかんでから、必要になったタイミングで rebase -i に触れるくらいの順番がちょうどよい。

履歴整理の道具は、使いこなせば読みやすい記録を残せる一方、使い方を誤ると混乱のもとにもなる。「今のコミットは共有済みか、まだ自分だけのものか」を毎回意識する。この一点さえ守れれば、amendもrebaseも怖がる必要はない。

この項目に出てくる用語

履歴の書き換えりれきのかきかえ
amendやrebaseのように、既存コミットの中身やハッシュ値そのものを変える操作の総称。
安全な強制pushあんぜんなきょうせいぷっしゅ
git push --force-with-lease のこと。他人の変更を踏みつぶさずに強制pushする方法。
detached HEADでたっちどへっど
ブランチではなく、特定のコミットを直接指している状態のこと。

関連コマンド

git commit --amendgit rebase

▶ 学習アプリでこの続きを学ぶ・演習する