◀ 24.

Git rebaseの使い方|対象範囲・競合解決・pushの判断

▶

Git rebaseは選択したcommitを別の基点へ再適用する操作です。対象範囲と共有済み履歴を確認し、競合時のcontinue・skip・abortを区別します。

Git rebaseは選択したcommitを別の基点へ再適用する操作です。対象範囲と共有済み履歴を確認し、競合時のcontinue・skip・abortを区別します。

この記事の要点
  • git rebase main は現在のブランチのコミットを 手元mainの指すcommitを基点に再適用する。リモートmainの取得は別操作
  • mergeはfast-forwardならmerge commitを作らない。rebaseの形や対象はオプション・履歴にも依存する
  • git rebase -i HEAD~3 でインタラクティブ。pick / squash / fixup / reword / edit / drop でコミット編集
  • コンフリクト発生時: 解決 → git add → git rebase --continue、やめるなら --abort、現在のpatchを適用しないのが --skip。解決を省く操作ではない
  • rebase後も通常pushできる場合がある。公開済み履歴の書換え・forceは無断で行わない

rebase とは

Git の rebase(リベース)は、ブランチのコミットを別の基点(base)に付け替える操作です。日本語では「土台を置き換える」のニュアンス。

この例を読む前に:単純な未共有の直線履歴の模式図です。再作成されるならAも含めIDが変わります。全てのrebaseが全履歴を直線化するわけではなく、通常のrebaseではmerge commitの扱いや同等patchの除外等に注意します。

[before]
        A---B---C    feature
       /
   D---E---F---G     main

git rebase main をすると…

[after]
                A'---B'---C'    feature(B', C' は新しいコミット)
               /
   D---E---F---G                main

feature のコミット A, B, C を main の先端 G の上に積み直す。
歴史が直線になる。

merge との違い

項目mergerebase
履歴の形分岐を統合。fast-forwardではmerge commitなし通常は選択commitを再適用。--rebase-merges等は別の形
コミット SHAそのまま保持再作成したcommitのIDは変わる。no-opや既適用patchの除外等もある
push 方法普通の git push送り先履歴との関係で判断。未共有commitの積み直しなら通常pushできる場合がある
共有ブランチ共有方針・保護に従う公開済み履歴の書換えは他者へ影響。合意/退避/移行なしに行わない
履歴の見やすさ分岐が分かる線形で読みやすい
コンフリクト解決1回のmerge操作でも複数ファイルの解決や検証が必要コミット単位で複数回の可能性

基本: 他ブランチの上に積み直す

この例を読む前に:各段落は別の選択肢です。rebaseは現在branch、mainは手元のrefです。origin/mainもfetch設定と取得時点を確認します。global pull.rebaseは他repoにも影響するため練習として変更しません。

# feature ブランチで作業中、main が進んだので追従したい
git checkout feature
git fetch origin
git rebase origin/main

# ローカル main が最新なら
git rebase main

# pull の代わりに rebase で取り込み
git pull --rebase origin main

# git config で常時 rebase 動作にする
git config --global pull.rebase true

インタラクティブ rebaseの対象範囲

git rebase -i は、直近のコミットを編集・並べ替え・統合できる強力な機能です。Pull Request 前に履歴を綺麗にするのに使います:

この例を読む前に:HEAD~3はその祖先が存在する場合だけです。指定基点自体は通常の編集対象から除外され、mainより後が全て「自分のcommit」とは限りません。root/mergeを含む履歴は別の指定と確認が必要です。

# 直近 3 コミットをインタラクティブに編集
git rebase -i HEAD~3

# 特定コミット以降を編集
git rebase -i abc1234

# main 以降の自分のコミット全部を編集
git rebase -i main

エディタが開き、対象コミット一覧が表示されます:

この例を読む前に:次の旧todoは説明図で、そのまま保存する完成形ではありません。e4f5g6h/i7j8k9lは16進OIDとして不正です。実際にGitが生成した一覧の実在IDを使い、resetの省略名はt、rewordはrです。execはshell命令を実行するので、他人のtodoや未知の命令を取り込みません。

pick a1b2c3d Add login form
pick e4f5g6h Fix typo in login form
pick i7j8k9l Add password validation

# Rebase 7d8e9f0..i7j8k9l onto 7d8e9f0
# Commands:
# p, pick   = use commit
# r, reword = use commit, but edit the commit message
# e, edit   = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
# f, fixup  = like squash, but discard this commit's message
# x, exec   = run command (the rest of the line) using shell
# d, drop   = remove commit
# b, break  = stop here
# l, label  = label current HEAD with a name
# r, reset  = reset HEAD to a label

squash / fixup でコミットを統合

この例を読む前に:旧例の前半/後半はfixupとsquashの代替案です。不正な例示IDや矢印付きの説明をtodoへコピーしません。統合先となる先行commitが必要で、fixupは通常そのcommitメッセージを捨て、squashは統合メッセージを編集します。元のtreeの意味が保たれたか検証します。

# typo fix を前のコミットに統合したい
pick a1b2c3d Add login form
fixup e4f5g6h Fix typo in login form         ← f に変更(メッセージは捨てる)
pick i7j8k9l Add password validation

# 保存して終了 → 自動で統合される
# 履歴は 2 コミットに

# squash の場合はメッセージ編集画面が出る
pick a1b2c3d Add login form
squash e4f5g6h Fix typo in login form
pick i7j8k9l Add password validation

reword でメッセージ修正

この例を読む前に:旧例のID/矢印注記はコピーせず、Gitが生成した実際の一覧でpickをrewordへ変えます。内容が同じでもcommit IDと後続履歴が変わり得ます。

pick a1b2c3d Add login form
reword e4f5g6h fxi tyop                       ← r に変更
pick i7j8k9l Add password validation

# 保存後、e4f5g6h のコミットメッセージ編集画面が開く
# → "Fix typo" に修正して保存

drop で不要コミット削除

この例を読む前に:dropはdebug行だけでなく、そのcommitの変更全体を適用対象から外します。後続の依存関係や必要な修正を失わないか確認します。例示ID/注釈は実行用ではありません。

pick a1b2c3d Add login form
drop e4f5g6h WIP: debug print                 ← d に変更(行ごと消しても可)
pick i7j8k9l Add password validation

並べ替え

単純に行の順序を入れ替えれば、コミット順が変わります(コンフリクトの可能性あり)。

コンフリクトが発生したとき

$ git rebase main
Auto-merging src/login.php
CONFLICT (content): Merge conflict in src/login.php
error: could not apply a1b2c3d... Add login form
Resolve all conflicts manually, mark them as resolved with
"git add/rm <conflicted_files>", then run "git rebase --continue".
You can instead skip this commit: run "git rebase --skip".
To abort and get back to the state before "git rebase", run "git rebase --abort".

この例を読む前に:continue・skip・abortは代替操作です。skipは競合解決の省略ではなく現在のpatchを適用しないため、必要な変更を失い得ます。abortは進行中rebaseの中断で、終了後の取消命令ではありません。autostashの再適用や未保存作業まで無条件に復元できるとは扱いません。

# 1. コンフリクトファイルを確認
git status

# 2. ファイルを開いて <<<<<<< ======= >>>>>>> マーカーを編集
# どちらの変更を残すか決めてマーカー削除

# 3. 解決済としてマーク
git add src/login.php

# 4. rebase 継続
git rebase --continue

# 別の対処
git rebase --skip       # このコミットを諦めてスキップ
git rebase --abort      # rebase 全体をキャンセル、開始前の状態に戻す

rebase 後の push

通常pushの可否は、送り先の現在の先端から新しい先端へfast-forwardできるか等で決まります。未共有commitを積み直した場合などは通常pushできます。次は公開済みの旧先端を新履歴が含まない場合等の拒否例で、rebase後に必ず出るものではありません。

$ git push
! [rejected]        feature -> feature (non-fast-forward)
error: failed to push some refs to 'origin'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart.

この例を読む前に:この旧ブロックを一括実行しません。force-with-leaseも強制更新で、無条件に安全ではありません。期待値省略時はbackground fetch等の更新にも影響されます。通常pushの可否と公開済み履歴の合意・保護・退避を確認し、拒否をforceで機械的に回避しません。

# 強制 push(履歴を上書き)
git push --force-with-lease

# ❌ 危険な --force(他人の push を破壊する可能性)
git push --force          # 使うな

# ✅ --force-with-lease は「リモート側に予期せぬ変更がないか」確認する
git push --force-with-lease

共有ブランチでの rebase は禁止

main や develop など他人が pull している共有ブランチを rebase してはいけません。コミット SHA が書き換わると、他人のローカルとリモートが不整合になり、複雑な復旧作業が必要になります。

ブランチrebase 可否
main / master / develop❌ 禁止
共有 feature ブランチ⚠ チーム合意必須
自分専用の feature ブランチ未共有か、退避/検証と利用者・CIへの影響を確認して判断
PR 前の自分の topic ブランチPR前でも共有済みの場合がある。整理は必須ではなく運用方針で判断

rebase --onto: 任意の基点に付け替え

# feature を main から develop の上に付け替え

[before]
       A---B---C    feature
      /
  --- main ---
      \
       D---E       develop

# git rebase --onto develop main feature

[after]
                A'---B'---C'    feature
               /
  --- main ---
      \
       D---E                    develop

この例を読む前に:2つのonto例は別操作です。--ontoは新基点、次のmainやfeature~2は除外側の基点、最後は積み直すbranchです。後半はfeatureの直近2commitをmain上へ再適用してfeature自体を動かすもので、新しい別branchを作る命令ではありません。必要な古いcommitを選択から外さないか、両境界を先に確認します。

git checkout feature
git rebase --onto develop main feature
# = (main から派生した) feature を develop の上に再構築

# 「直近 2 コミットだけ別ブランチに移したい」
git rebase --onto main feature~2 feature

rebase をやり直したい

この例を読む前に:HEAD@{5}は固定の復旧地点ではなく、操作回数で変わる例示です。reset --hardは作業/indexを変更し未コミット内容等を失い得るため、このまま実行しません。reflogは期限/ローカル設定に依存し、作業ファイルのバックアップではありません。まず現在の作業と確かめたcommitを退避し、完了後の復旧は別に判断します。

# rebase 開始前に戻る(実行中の場合)
git rebase --abort

# rebase してしまった後で取り消したい
git reflog                        # 過去の HEAD 位置を確認
git reset --hard HEAD@{5}         # rebase 前の状態に戻す

FAQ

Q: いつ rebase でいつ merge?
A: 個人用という名前だけでrebaseを選ばず、共有状態・保持したい履歴とチーム方針で判断します。PRの統合方式もサービス/設定/保護条件に従います。rebase、merge、squashを一律に優劣付けしません。

Q: rebase 中に間違って git pull してしまった
A: 未解決の競合や進行中の処理によりpullが拒否される場合があります。出力とstatusを読み、勝手に二重rebaseが完了したと決めつけません。継続/中断は現在の処理に対して選び、未保存の解決作業も確認します。

Q: 大量のコンフリクトが出る
A: rerereは記録済み解決の再利用を補助しますが、適用結果の意味が正しい保証ではありません。解決内容をレビューしテストします。必要なrepoと方針を確認し、全repoへ影響するglobal設定を一律に変えません。

Q: コミットメッセージだけまとめて修正したい
A: 存在する基点を指定したinteractive rebaseのreword、直近だけならamendが候補です。メッセージだけでもcommit IDや署名・後続へ影響するため、共有状態を確認します。HEAD~5が存在するとは限りません。

関連

  • git merge — 履歴を統合する別の方法
  • git cherry-pick — 特定コミットだけ別ブランチに適用
  • git reflog — ローカル参照の移動履歴を確認。未コミット内容の完全なバックアップではない
  • git pull --rebase — pull で自動 rebase

未共有commitなら通常pushできる練習

Bash/Git 2.28以降で空フォルダから実行します。既存の2パスがあれば停止します。別ファイルへの変更を使って競合を避け、旧featureをbefore-rebaseで保持してから再適用します。練習用の空bareへ初めて送るためforceは不要です。

set -eu
for path in rebase-client rebase-remote.git; do
    if [ -e "$path" ] || [ -L "$path" ]; then printf 'Already exists: %s\n' "$path" >&2; exit 1; fi
done
git init -b main rebase-client
git -C rebase-client config user.name Training
git -C rebase-client config user.email training@example.invalid
printf 'base\n' > rebase-client/base.txt
git -C rebase-client add base.txt
git -C rebase-client commit -m Base
git -C rebase-client switch -c feature
printf 'feature\n' > rebase-client/feature.txt
git -C rebase-client add feature.txt
git -C rebase-client commit -m Feature
git -C rebase-client branch before-rebase
git -C rebase-client switch main
printf 'main\n' > rebase-client/main.txt
git -C rebase-client add main.txt
git -C rebase-client commit -m Main
git -C rebase-client switch feature
git -C rebase-client rebase main
git -C rebase-client rev-parse before-rebase feature
git init --bare -b main rebase-remote.git
git -C rebase-client remote add origin ../rebase-remote.git
git -C rebase-client push -u origin feature

旧IDと新IDは異なり、mainの祖先を含むfeatureが通常pushされます。mainと旧featureの退避refは保持されます。この練習の成功を公開済みbranchの強制更新や共有履歴移行の許可と解釈しないでください。

再適用後に内容を検証する

statusで処理終了と作業状態を確認し、積み直す前後のdiff・commit列をレビューしてテストします。必要ならrange-diffで旧/新範囲を比較しますが、それだけで動作の一致は保証されません。順番の入替えやdropでビルド依存が壊れる場合もあります。競合はマーカーの削除だけで解決と扱いません。

関連する操作はpull・rebase・push・remote設定へ。Git親ページの子ページから選択してください。

公式資料と検証範囲

2026年10月にrebaseの範囲/onto/interactive・pushとlease・resetの影響・reflogの保持を確認しました。元コードと章を保持し、近接注意で旧例の誤りを訂正しています。追加Bash例と取込み/再適用の条件をGit 2.42の隔離ローカルrepoで検査しました。実サービスの認証/保護/CI、共有履歴の移行や全Git版を検証したものではありません。

子ページ

子ページはありません

同階層のページ
  1. 用語一覧
  2. エラー一覧
  3. git本体のインストール(Linux)
  4. Linuxサーバーへのgit導入とクライアントのセットアップ
  5. リモートリポジトリをローカルリポジトリとしてクローンする方法
  6. リモートとローカルのリポジトリを同期(pull)する方法
  7. 設定の確認
  8. gitユーザー名とemailの設定
  9. リモートリポジトリの作成
  10. ローカルリポジトリの作成
  11. 新規ファイル/ディレクトリをインデックスに登録
  12. インデックスの登録状態を確認
  13. ローカルリポジトリの変更をコミット
  14. コミット履歴の確認
  15. クライアントからリモートリポジトリの接続設定、確認、削除
  16. リポジトリへのプッシュ
  17. リモートリポジトリからクライアントへのSSHクローン
  18. リモートとローカルの差分表示
  19. バージョンの確認
  20. プロキシの設定
  21. ローカルをリモートリポジトリの状態に戻す
  22. ブランチの作成, 一覧表示, 切り替え
  23. ブランチのマージと削除
  24. リベース
  25. .gitignoreの書き方
  26. .gitignoreの設定が反映されない場合
  27. 特定のファイルをgitの管理から外す方法
  28. 参照(ORIG_HEAD, HEAD, FETCH_HEAD)
  29. git rm [-r --cached] の取り消し
  30. 一部のディレクトリ/ファイルのみをリポジトリから復元する方法
  31. ローカルとリモートリポジトリの有無を同期
  32. pushの取消し方法
  33. マージツールの起動方法
  34. Gitで「MERGING」の状態

最近更新/作成されたページ