git rebaseの途中で止まったとき、焦って--abortを連打したり.git/rebase-merge/を削除して状況を悪化させる——これがrebaseトラブルでもっとも多い事故パターンです。
$ git rebase main Auto-merging src/app.js CONFLICT (content): Merge conflict in src/app.js error: could not apply a1b2c3d... feat: 新機能 hint: Resolve all conflicts manually, mark them as resolved with hint: "git add/rm <conflicted_files>", then run "git rebase --continue". # 他にもこんなエラー # "fatal: It seems that there is already a rebase-merge directory" # "error: cannot rebase: Your index contains uncommitted changes" # "CONFLICT (modify/delete)" # "The previous cherry-pick is now empty, possibly due to conflict resolution"
rebase中のエラーは一見複雑に見えますが、正しい3つの道(continue/skip/abort)を選べば大半は数分で解決します。焦らず「今どこで止まっているか」を診断してから動きましょう。
この記事では、rebase進行中の7パターンのエラーと復旧フロー、interactive rebase特有の罠(pick/reword/edit/squash/fixup/drop)、--rebase-merges/autosquash/signed commit/pre-commit hookでのトラブル、そしてsafety branch+reflogで絶対に失敗しないrebase運用を解説します。rebaseで二度と詰まらないための完全ガイドです。
この記事で学べること
- rebase中の60秒安全脱出フロー(迷ったら
--abort) - 7パターンの停止原因と診断の仕方
--continue/--skip/--abort/--edit-todoの使い分け- interactive rebase各コマンドのエラー対処(pick/reword/edit/squash/fixup/drop)
--rebase-merges・autosquash・signed commit特有のトラブル- pre-commit hookや空コミット(empty commit)で止まった時の対処
- safety branch+reflogで絶対にロストしないrebase運用パターン
- 推奨設定(
rebase.autoStash/rebase.autoSquash/rebase.abbreviateCommands)
- 【最速60秒】迷ったらこれで脱出
- rebaseで止まる7つの典型パターン
- STEP 0:rebaseの進行状態を正確に把握する
- パターン①:コンフリクト発生時の復旧
- パターン②:未コミット変更で開始できない
- パターン③:前のrebaseが残ったまま
- パターン④:untrackedファイルが衝突
- パターン⑤:interactive rebaseのtodo記述ミス
- パターン⑥:空コミット(fixup/squash後)で止まる
- パターン⑦:hook・署名・lockで止まる
- プロ運用:safety branchで絶対にロストしない
- rebase中のreflog救出
- rebaseで詰まらなくなる推奨設定
- –rebase-mergesの使い方と罠
- 実践シナリオ
- やってはいけない落とし穴
- よくある質問
- 関連記事
- まとめ
【最速60秒】迷ったらこれで脱出
rebaseで止まった直後、やってはいけないこと:.git/rebase-mergeや.git/rebase-applyの手動削除、安易なgit reset --hard、追加のcommit。これらは状況を悪化させる三大悪手です。まずgit statusで状況を確認し、正規ルートで脱出しましょう。
# ■ STEP 1:状況把握(20秒) git status # "You are currently rebasing branch X on Y" が出る # ■ STEP 2:選択肢は3つだけ(40秒) # A) 解消して進める git add . git rebase --continue # B) この1コミットだけ飛ばす git rebase --skip # C) 開始前に完全に戻す(安全) git rebase --abort # ■ STEP 3:--abort で戻ったらsafety branchを切る(推奨) git switch -c safety/before-rebase-$(date +%H%M) git switch - # 元ブランチに戻って再挑戦
ポイント:rebaseで困ったらまず--abortで安全地帯に戻るのが鉄則。元の状態が復元されるので、そこから戦略を立て直せます。どうしても--continueで進めたい場合も、必ずgit statusのヒントを読んでから。
rebaseで止まる7つの典型パターン
ポイント:パターンのほとんどはgit statusがヒントを出してくれます。「Currently rebasing… onto SHA」「You are currently editing a commit」等の文を読めば、自分がどのパターンにいるか+次に何をすべきかが分かります。
STEP 0:rebaseの進行状態を正確に把握する
# 基本状態 git status # .git内の進行ファイル確認 ls .git/rebase-merge 2>/dev/null && echo "interactive or merge rebase中" ls .git/rebase-apply 2>/dev/null && echo "apply rebase中" # 現在処理中のコミット cat .git/rebase-merge/stopped-sha 2>/dev/null cat .git/rebase-merge/message 2>/dev/null # 進捗(interactive rebaseの場合) cat .git/rebase-merge/done cat .git/rebase-merge/git-rebase-todo # done=処理済み、todo=残りの計画 # HEADの移動履歴(reflog) git reflog --date=iso | head -20
`.git/rebase-*`ディレクトリの中身
rebase-merge/git-rebase-todo:残りのタスクリストrebase-merge/done:処理済みのtodorebase-merge/stopped-sha:今止まっているコミットのSHArebase-merge/head-name:rebase前のブランチ名rebase-merge/onto:rebase先のコミットSHA
パターン①:コンフリクト発生時の復旧
もっとも多いパターン。各コミットを順次適用する過程でconflictが発生します。対処手順は固定なので、一度覚えれば迷いません。
# 1. 衝突しているファイルを確認 git status # both modified: src/app.js # 2. エディタで該当ファイルを開いて手動解消 # <<<<<<< HEAD # 現在の変更 # ======= # rebase先の変更 # >>>>>>> a1b2c3d... # 3. 解消したファイルをステージ git add src/app.js # 4. 続行 git rebase --continue # → エディタが開いてcommitメッセージ確認。そのまま保存してOK # または:このコミットが不要ならスキップ git rebase --skip # または:やめて最初に戻る git rebase --abort
`–ours`/`–theirs`で機械的に解消
# rebase中の ours=rebase先(新しいbase)、theirs=移動中のコミット # 通常のmergeと逆! # rebase先の内容を採用 git checkout --ours path/to/file # 移動中コミットの変更を採用 git checkout --theirs path/to/file git add path/to/file git rebase --continue
注意:rebase中の--ours/--theirsの意味は通常のmergeとは逆です。rebase中は「ours=移動先(新しいbase)」「theirs=現在移動中のコミット側」。混乱しやすいので、意味を理解していなければ手動解消を推奨。
パターン②:未コミット変更で開始できない
$ git rebase main error: cannot rebase: You have unstaged changes. error: Please commit or stash them.
# 未コミット変更を退避(未追跡も含む -u) git stash push -u -m "before rebase" # rebase実行 git rebase main # 完了後に変更を戻す git stash pop # もしくは一時コミットして後でsquashする git add . git commit -m "WIP: rebase前の退避" git rebase main # rebase中にこのcommitをsquashでまとめる
# rebase時に自動でstash&pop git config --global rebase.autoStash true # これで未コミット変更があっても自動退避&復元 git rebase main
ポイント:rebase.autoStash=trueはrebaseで未コミット変更を自動退避→完了後に自動復元する便利設定。stash忘れで怒られる事故が消えます。一度設定すれば全repoに適用されます。
パターン③:前のrebaseが残ったまま
$ git rebase main
fatal: It seems that there is already a rebase-merge directory,
and I wonder if you are in the middle of another rebase.
If that is the case, please try
git rebase (--continue | --abort | --skip)
# まずは状態確認 git status # 進められる状態なら続行 git rebase --continue # 進められないなら中止 git rebase --abort # --abortも失敗して壊れていると判断した場合の最終手段 # (非推奨:データ喪失リスクあり) rm -rf .git/rebase-merge .git/rebase-apply git reset --hard ORIG_HEAD # reflog確認してから
警告:.git/rebase-merge等の手動削除は最終手段です。進行中のrebase情報が失われると、途中までの作業内容が取り戻せなくなる可能性があります。git reflogで開始前の位置を確認してから削除→reset --hardするのが安全です。
パターン④:untrackedファイルが衝突
$ git rebase main
error: The following untracked working tree files would be overwritten by checkout:
config/local.env
Please move or remove them before you merge.
# untrackedファイルを含めてstash退避 git stash push -u -m "untracked before rebase" git rebase --continue # 中断していたrebaseなら # または git rebase main # 新規開始 git stash pop # そのファイルが不要ならバックアップしてから削除 mv config/local.env config/local.env.bak git rebase main
パターン⑤:interactive rebaseのtodo記述ミス
$ git rebase -i HEAD~5 error: unknown command: "fxp" You can fix this with 'git rebase --edit-todo' and then run 'git rebase --continue'. # タイポで "fxp" と書いてしまった → 正しくは "fixup"
# todoを再編集 git rebase --edit-todo # エディタが開くので誤行を修正して保存 # 続行 git rebase --continue
# 有効なコマンド(省略形も可) # p, pick コミットを使用 # r, reword メッセージを編集 # e, edit コミットで停止して修正 # s, squash 前のコミットに統合(メッセージ統合) # f, fixup 前のコミットに統合(メッセージ破棄) # d, drop コミットを削除 # x, exec シェルコマンド実行 # l, label ラベル付与(--rebase-merges時) # t, reset リセット(--rebase-merges時) # m, merge マージ(--rebase-merges時) # 省略形を既定化 git config --global rebase.abbreviateCommands true
パターン⑥:空コミット(fixup/squash後)で止まる
$ git rebase --continue
The previous cherry-pick is now empty, possibly due to conflict resolution.
If you wish to commit it anyway, use:
git commit --allow-empty
If you wish to skip this commit, use:
git rebase --skip
# 内容が空になったコミットを捨てる git rebase --skip # 意図的に空コミットを残したい場合 git commit --allow-empty git rebase --continue
Git 2.26+ のempty commit自動処理
Git 2.26以降では--empty=<drop|keep|ask>オプションで空コミットの扱いを指定できます。デフォルトの挙動を変えたいならgit rebase -i --empty=dropで空になったコミットを自動削除。長いinteractive rebaseで毎回skipする手間が省けます。
パターン⑦:hook・署名・lockで止まる
pre-commit hook失敗
# pre-commit hookがlint失敗で止まった場合 # 手動でlintを修正 git add . git rebase --continue # hookを一時的に無効化してrebase継続 git rebase --continue --no-verify # Git 2.36+のみ # 古いGitなら環境変数で回避 GIT_COMMITTER_NAME="X" git -c core.hooksPath=/dev/null rebase --continue
GPG署名失敗
# rebase中にGPG/SSH署名が失敗するケース # 一時的に署名を無効化 git -c commit.gpgsign=false rebase --continue # GPG agent再起動 gpgconf --kill gpg-agent gpgconf --launch gpg-agent git rebase --continue # 署名済みコミットを保つ必要がなければ恒久設定 git config commit.gpgsign false
index.lockで動けない
$ git rebase --continue fatal: Unable to create '.git/index.lock': File exists. # 他のgitプロセスが実行中でないことを確認 ps aux | grep git # 残留ロックを削除(他プロセスがいないときのみ) rm -f .git/index.lock git rebase --continue
注意:.git/index.lockの削除は他のgitプロセスが実行中でないことを確認してから行ってください。エディタのGit拡張、gitk、自動バックアップツール等が動いている場合はそれらを停止してから削除を。
プロ運用:safety branchで絶対にロストしない
rebase開始前にsafety branchを切るだけで、どんな失敗しても即座に元に戻せる強力なパターン。数秒の手間でいつでもやり直せる安心感が手に入ります。
# rebase前に退避ブランチを切る git switch -c safety/before-rebase-$(date +%Y%m%d-%H%M) HEAD # 元ブランチに戻ってrebase git switch - git rebase main # 失敗したら一発で復元 git reset --hard safety/before-rebase-20260421-1030 # うまくいったらsafety branchは削除 git branch -D safety/before-rebase-20260421-1030
# git safe-rebase コマンドを定義
git config --global alias.safe-rebase '!f() { \
local safety="safety/$(git branch --show-current)-$(date +%Y%m%d-%H%M%S)"; \
git branch "$safety" && \
echo "Safety branch created: $safety" && \
git rebase "$@"; \
}; f'
# 使い方
git safe-rebase main
ポイント:safety branchは数秒の保険です。rebaseをかけるブランチに長い作業が積まれていて「失敗したくない」場合は必須運用。失敗時もエイリアスから簡単に戻せるので、恐怖なく複雑なrebaseに挑めます。
rebase中のreflog救出
safety branchを忘れた/数日前の作業で気付いた等の場面でも、reflogからrebase開始前のHEAD位置を辿れます(約90日間保持)。
# reflogでrebase開始前を探す
git reflog --date=iso
# 出力例:
# abc1234 HEAD@{0}: rebase finished: returning to refs/heads/feature
# def5678 HEAD@{1}: rebase onto main
# ghi9012 HEAD@{2}: rebase (start): checkout main
# jkl3456 HEAD@{3}: commit: ... ← rebase開始前
# rebase開始直前のハッシュに戻す
git reset --hard jkl3456
# または
git reset --hard HEAD@{3}
# ブランチとして復元
git branch -f feature jkl3456
# 過去の位置から特定ファイル復元
git checkout HEAD@{3} -- path/to/file
git add path/to/file
git commit -m "restore: rebase中に失ったファイルを復元"
rebaseで詰まらなくなる推奨設定
# rebase時に未コミット変更を自動stash git config --global rebase.autoStash true # "fixup!" や "squash!" プレフィックスのコミットを自動整理 git config --global rebase.autoSquash true # interactive rebaseで短縮コマンド(p/r/e/s/f/d)を既定化 git config --global rebase.abbreviateCommands true # pullでrebase既定 git config --global pull.rebase true # rebase実行時に更新された追跡ブランチを教えてくれる git config --global rebase.updateRefs true # rerere(同じconflictを記憶) git config --global rerere.enabled true # Git 2.26+でempty commit自動drop git config --global rebase.empty drop
autosquashで事前に”修正予約”
# 修正したいコミットをマークしながらfixup commit作成 git commit --fixup <修正対象SHA> # → "fixup! 元commitメッセージ" というcommitが作られる # rebase時に自動統合 git rebase -i --autosquash <修正対象の親SHA> # autosquashでfixup対象に自動並び替えされる # autosquash をデフォルト化しておけば --autosquash 不要 git config --global rebase.autoSquash true git rebase -i <base>
–rebase-mergesの使い方と罠
マージコミットを保ちつつrebaseしたい場合は--rebase-mergesを使います。通常のrebaseと挙動が異なるためtodoリストも複雑になり、エラー時の対応も変わります。
git rebase --rebase-merges -i main # エディタに以下のような複雑なtodoが表示される: # # label onto # # # Branch: feature/a # reset onto # pick 1a2b3c4 feat: Aの実装 # pick 5d6e7f8 feat: Aの続き # label A # # # Branch: feature/b # reset onto # pick 9g0h1i2 feat: Bの実装 # label B # # reset onto # merge -C <元merge> A # merge feature/a into main # merge -C <元merge> B # merge feature/b into main
–rebase-mergesのエラー対応
label/reset/mergeコマンドを誤ると複雑な連鎖エラー--edit-todoで構造を確認しながら修正- 何度も失敗するなら通常のrebaseに切り替えて履歴をリニア化も検討
- 複雑なhistoryはsafety branch必須
実践シナリオ
シナリオ① rebase中conflict→解消して進める
git status # both modified: ... # エディタで解消 git add . git rebase --continue
シナリオ② やめたい、最初に戻りたい
git rebase --abort git status # rebase前に戻った
シナリオ③ 1コミット飛ばして先に進む
git rebase --skip # 次のcommitから再開
シナリオ④ –abort失敗 → reflog復旧
# abort が効かない場合
git reflog
# rebase (start) のSHAを特定
git reset --hard HEAD@{N}
rm -rf .git/rebase-merge .git/rebase-apply
やってはいけない落とし穴
`.git/rebase-merge`を真っ先に削除する
「よくわからないからリセット」とrm -rfすると、途中までの解消作業が全部失われるうえ、Gitの整合性が壊れる可能性も。必ずgit rebase --abort→失敗したらreflogで元位置確認→reset --hardの順で。
rebase中のaddを忘れて–continue
conflict解消後にgit addせず--continueすると「No changes – did you forget to use git add?」で止まります。必ずステージしてから続行を。
共有ブランチで履歴書き換え
mainや共有featureブランチをrebaseしてforce pushすると他メンバーのローカル環境を破壊します。rebaseは個人ブランチ限定、共有ブランチはmergeが鉄則。
safety branchを切らずに長大なrebase
数十commitにまたがるrebaseでは事故率が跳ね上がります。rebase前にsafety branchを切るだけで復旧コストがゼロに近づくので、習慣化しましょう。
interactive rebaseのtodoを慌てて保存
エディタで誤ったまま保存すると、複数のコミットを失う可能性があります。保存前に必ず見直し、不安なら--abortして最初からやり直すのが安全。--edit-todoで後から修正もできます。
hook無効化を常態化する
--no-verifyで毎回hookを無効化すると、lintや機密スキャンが機能しなくなります。一時回避のみにとどめ、hookが頻繁に落ちるなら根本原因(lint設定・依存管理)を直しましょう。
よくある質問
.gitが壊れている可能性。git reflogでrebase開始前の位置を特定、git reset --hard HEAD@{N}で強制復元、rm -rf .git/rebase-merge .git/rebase-applyで残骸を除去。git rebase --edit-todoでエディタが再度開きます。修正して保存→git rebase --continueで再開。「unknown command」エラー後も同じ対処でOK。git rebase --skipでそのコミットを捨てるのが一般的。意図的に空を残すならgit commit --allow-empty+--continue。Git 2.26+ならrebase.empty=drop設定で自動化可。--oursを使うと間違えます。--continue、一時回避なら--no-verify(Git 2.36+)。常態化したら根本原因を直しましょう。git branch backup/before-rebaseの1行で失敗してもgit reset --hard backup/before-rebaseで即復元。本記事のエイリアス化スクリプトを活用しましょう。関連記事
- 【Git】rebaseとmergeの違いと使い分け — 戦略選択の基礎
- 【Git】「Pulling is not possible because you have unmerged files」の解決方法 — unmergedエラーとの関係
- 【Git】コンフリクトを解消したのにpullできないときの原因と対策 — 解消後の進まない問題
- 【Git】コミット履歴が二重化する原因と修正方法 — rebase後の二重化対処
- 【Git】pull後にマージコミットが大量発生する原因と履歴整理方法 — rebaseで履歴整理
- 【Git】コミットメッセージの変更方法 — rewordの深堀り
- 【Git】pushを取り消す方法 — rebase後のforce push
- 【Git】よく使うgitコマンドまとめ — 日常コマンドの早見表
まとめ
- rebase中に止まったらまず
git status、選択肢はcontinue/skip/abortの3つ - 7パターン:conflict/未コミット/前rebase残存/untracked衝突/todo記述ミス/空コミット/hook署名lock
rebase.autoStash=true+rebase.autoSquash=true+rerere.enabled=trueで事故激減- safety branchを切ってからrebaseが最強の安全策
- interactive rebaseの
--edit-todoで途中修正可能 - ours/theirsの意味はrebase中は通常mergeと逆——注意
- 最終手段:
reflog+reset --hardでrebase開始前に戻る - 共有ブランチでのrebaseは禁物、個人ブランチ限定
rebaseのトラブルは原因が7パターンに限られ、対処は--continue/--skip/--abortの3つから選ぶだけ。これさえ知っていれば焦らず対応できます。日常運用ではsafety branch+推奨設定で事故そのものを減らし、interactive rebaseでは--edit-todoと--autosquashを使いこなすのがプロのワークフロー。rebaseが怖くなくなれば、履歴を美しく保ちながら開発を進められます。

