Stage 3・上級編 ー Lesson 3-5
git rebase と cherry-pick で履歴を編集する
rebase で履歴を一直線にきれいに、cherry-pick で必要なコミットだけ持ってくる
💡 たとえるなら
本の章順を並べ替える(rebase)/別の本から1ページだけコピペする(cherry-pick)
ここからは Git の パワーツール。コミット履歴を後から 編集する 技術です。慣れると非常に便利ですが、「公開済みのコミットを書き換えてはいけない」 という大原則だけは絶対に守ってください。
rebase って何?
merge が「枝を合流させる」操作だったのに対し、rebase は 「枝の根元を別の場所に付け替える」 操作です。
merge が 「歴史を残す」 のに対し、rebase は 「歴史をきれいに整える」。コミット C・D は新しいコミット C’・D’ として 作り直される のがポイント。
rebase してみる
feature ブランチで作業中、main が先に進んだ場合:
意味は 「自分(feature)のコミットを main の最新の上に積み直す」。コンフリクトしたら手で解決して git rebase --continue、やめたければ git rebase --abort。
なぜ rebase を使うのか
- 履歴が一直線になって読みやすい:
git log --graphがスッキリ - 「同期だけのマージコミット」が積まれない:feature 開発中に「main の最新を取り込みたい」と
git merge mainやgit pull(マージ方式)を何度もやると、その都度Merge branch ‘main’ into featureが積まれて履歴が膨らみます。git rebase mainに置き換えれば、これが一切残らず履歴が直列のまま保てます - チームによっては「最終 merge する前に rebase してから」が作法
「feature を main に取り込む」最終マージは、merge派でも rebase派でも 1機能あたり1コミット。減るのはあくまで 開発中に何度も発生する「同期だけのマージ」 の方です。
ただし 後述の通り、共有済みのコミットには使ってはいけません。
interactive rebase:履歴を整える究極の道具
-i オプションで 対話的rebase を起動すると、各コミットを「順番入れ替え」「メッセージ修正」「複数を1つに統合(squash)」「捨てる(drop)」できます。
エディタが開いて、こんな画面が出ます:
pick を s や f に書き換えて保存すると、自動でコミットが統合されます。
よくある使い道
- 「タイポ修正」みたいな小さなコミットを直前に統合したい →
f(fixup) - コミットメッセージを後から直したい →
r(reword) - 間違って入れてしまったコミットを消したい →
d(drop)
cherry-pick:1コミットだけ持ってくる
「あのブランチのあのコミットだけ、こっちに欲しい」というとき。
そのコミットの 変更内容だけを「コピー」して、現ブランチの先頭に新しいコミットとして積みます。
cherry-pick で持ってきたコミットは、元のコミットとは別の 新しいID を持ちます。親コミットも作者日時も変わるので、ハッシュは必ず変わるからです。
なので「あれ、同じコミットIDが両方のブランチにある!」とはなりません。中身は同じでも、Gitから見ると 別のコミット です(rebase 後の C・D が C'・D' になるのと同じ理由)。
典型的な使いどころ
- バグ修正コミットを別ブランチにも適用したい:
hotfix-1.0で直したやつをmainにも cherry-pick - 試作で作ったコミットの一部だけ採用したい
大原則:公開済みのコミットを書き換えない
rebase / 履歴編集は コミットIDを書き換える 操作。一度 push したコミットを書き換えると、チームメンバーのローカルと食い違って 大事故 になります。
push 済み・チームと共有済みのコミットを書き換えたいなら、Stage 2-5 で学んだ
git revert で「打ち消しコミット」を積む。
「mainブランチを rebase した」のは禁忌。featureブランチを rebase してから merge する、はOK(自分しか触ってないので)。
merge と rebase、どっちを選ぶ?
| merge | rebase | |
|---|---|---|
| 履歴の見た目 | 枝分かれが残る | 一直線 |
| マージコミット | 作る | 作らない |
| 共有済みコミット | 安全 | NG |
| 取り込まれた経緯 | 残せる | 消える |
チームによって「merge派」「rebase派」がありますが、初心者のうちは 「自分のfeatureを最新のmainに追従させる時は rebase、main にfeatureを取り込む時は merge」 くらいの分担が安全です。
やってみよう ①:3つのコミットを rebase -i で1つに squash する
「ちまちまコミット → 最後にきれいにまとめる」という王道フローを再現します。
fixup で残るのは 最初のコミットのメッセージだけ(「草案」)。中身は3コミット分が統合され、親は同じでも tree(中身)が変わるのでハッシュは別物 になります。
7a2e9f3 → 5c6d8b2 のように ID が変わるのが、まさに「履歴を書き換えた」証拠。だから push 済みコミットには使ってはいけません。
3つの「ちまちまコミット」が 1つの整ったコミット になりました。チームに見せる前にこうして履歴を整えるのが「rebase の作法」。
やってみよう ②:別ブランチから1コミットだけ cherry-pick
ブランチ全体をマージせず、特定の1コミットだけ 持ってこれます。バグ修正をリリース版にも適用したい時の定番。
このレッスンのまとめ
git rebase で枝の根元を付け替えられるrebase -i でコミットの統合・並べ替え・修正ができるcherry-pick で1コミットだけ持ってこれる✏️ 理解度チェック
各問題、選んだ瞬間に正解と解説が表示されます。気軽に試してください。
- Q1. git rebase の主な効果は?
- Q2. 他のブランチから1コミットだけ持ってくるコマンドは?
- Q3. 公開済み(push 済み)のコミットを rebase してはいけない理由は?