【Git】rebase中のエラー完全復旧ガイド|7パターン診断+safety branchで二度と詰まらない

【Git】リベース途中でエラーになったときの復旧方法 Git

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.autoStashrebase.autoSquashrebase.abbreviateCommands
スポンサーリンク

【最速60秒】迷ったらこれで脱出

rebaseで止まった直後、やってはいけないこと:.git/rebase-merge.git/rebase-apply手動削除、安易なgit reset --hard、追加のcommit。これらは状況を悪化させる三大悪手です。まずgit statusで状況を確認し、正規ルートで脱出しましょう。

60秒で安全に戻る3パターン
# ■ 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つの典型パターン

パターン 典型エラー 対処
① コンフリクト発生 CONFLICT (content) 解消→add→--continue
② 未コミット変更で開始不可 Your index contains uncommitted changes stash退避 or commit
③ 前のrebaseが残存 already rebase in progress --abortで初期化
④ untrackedファイル衝突 untracked working tree files would be overwritten stash -u or 削除
⑤ interactive rebaseのtodo記述ミス unknown command --edit-todoで修正
⑥ 空コミット(fixup/squash後) The previous cherry-pick is now empty --skipまたは--continue
⑦ hook/署名/lockファイルで失敗 pre-commit error/GPG/index.lock 原因別に対応

ポイント:パターンのほとんどは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:処理済みのtodo
  • rebase-merge/stopped-sha:今止まっているコミットのSHA
  • rebase-merge/head-name:rebase前のブランチ名
  • rebase-merge/onto:rebase先のコミットSHA

パターン①:コンフリクト発生時の復旧

もっとも多いパターン。各コミットを順次適用する過程でconflictが発生します。対処手順は固定なので、一度覚えれば迷いません。

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=現在移動中のコミット側」。混乱しやすいので、意味を理解していなければ手動解消を推奨。

パターン②:未コミット変更で開始できない

uncommitted changes エラー
$ git rebase main
error: cannot rebase: You have unstaged changes.
error: Please commit or stash them.
対処:stash退避またはcommit
# 未コミット変更を退避(未追跡も含む -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でまとめる
自動stashをデフォルト化
# rebase時に自動でstash&pop
git config --global rebase.autoStash true

# これで未コミット変更があっても自動退避&復元
git rebase main

ポイント:rebase.autoStash=trueはrebaseで未コミット変更を自動退避→完了後に自動復元する便利設定。stash忘れで怒られる事故が消えます。一度設定すれば全repoに適用されます。

パターン③:前のrebaseが残ったまま

already rebase in progressエラー
$ 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ファイルが衝突

untracked would be overwritten
$ 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記述ミス

unknown commandエラー
$ 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を修正して再開
# todoを再編集
git rebase --edit-todo
# エディタが開くので誤行を修正して保存

# 続行
git rebase --continue
interactive rebase のコマンド一覧
# 有効なコマンド(省略形も可)
# 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後)で止まる

previous cherry-pick is now empty
$ 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
対処: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失敗

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で動けない

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を切るだけで、どんな失敗しても即座に元に戻せる強力なパターン。数秒の手間でいつでもやり直せる安心感が手に入ります。

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から復旧
# 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
特定ファイルだけreflogから取り戻す
# 過去の位置から特定ファイル復元
git checkout HEAD@{3} -- path/to/file
git add path/to/file
git commit -m "restore: rebase中に失ったファイルを復元"

rebaseで詰まらなくなる推奨設定

おすすめGit設定
# 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`による予約
# 修正したいコミットをマークしながら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リストも複雑になり、エラー時の対応も変わります。

–rebase-merges の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

シナリオ② やめたい、最初に戻りたい

–abort で完全撤退
git rebase --abort
git status   # rebase前に戻った

シナリオ③ 1コミット飛ばして先に進む

–skip で特定commitだけ捨てる
git rebase --skip
# 次のcommitから再開

シナリオ④ –abort失敗 → reflog復旧

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設定・依存管理)を直しましょう。

よくある質問

Q–continue/–skip/–abort どう使い分ける?
A解消して進める→continueこの1コミットだけ捨てる→skip最初に戻す→abort。迷ったらabortでやり直すのが安全。abortしても元のブランチは無傷です。
Qrebase –abort が効かない
A.gitが壊れている可能性。git reflogでrebase開始前の位置を特定、git reset --hard HEAD@{N}で強制復元、rm -rf .git/rebase-merge .git/rebase-applyで残骸を除去。
Qinteractive rebaseのtodoでコマンドを間違えた
Agit rebase --edit-todoでエディタが再度開きます。修正して保存→git rebase --continueで再開。「unknown command」エラー後も同じ対処でOK。
Q空コミットで止まった(fixup後)
Afixupやsquashで統合されて空になった場合、git rebase --skipでそのコミットを捨てるのが一般的。意図的に空を残すならgit commit --allow-empty--continue。Git 2.26+ならrebase.empty=drop設定で自動化可。
Qrebase中のours/theirsの意味は?
Arebase中は通常のmergeと逆:ours=rebase先、theirs=移動中コミット。混乱しやすいので「わからなくなったら手動解消」が安全。merge時と同じ感覚で--oursを使うと間違えます。
Qpre-commit hookで毎回止まる
Arebase特有の問題でなく、hookが失敗しているだけ。lintやテストエラーを修正してから--continue、一時回避なら--no-verify(Git 2.36+)。常態化したら根本原因を直しましょう。
Q安全にrebaseする一番のコツは?
Asafety branchを切ってから始めるgit branch backup/before-rebaseの1行で失敗してもgit reset --hard backup/before-rebaseで即復元。本記事のエイリアス化スクリプトを活用しましょう。

関連記事

まとめ

  • rebase中に止まったらまずgit status、選択肢はcontinueskipabortの3つ
  • 7パターン:conflict/未コミット/前rebase残存/untracked衝突/todo記述ミス/空コミット/hook署名lock
  • rebase.autoStash=truerebase.autoSquash=truererere.enabled=trueで事故激減
  • safety branchを切ってからrebaseが最強の安全策
  • interactive rebaseの--edit-todoで途中修正可能
  • ours/theirsの意味はrebase中は通常mergeと逆——注意
  • 最終手段:reflogreset --hardでrebase開始前に戻る
  • 共有ブランチでのrebaseは禁物、個人ブランチ限定

rebaseのトラブルは原因が7パターンに限られ、対処は--continue--skip--abortの3つから選ぶだけ。これさえ知っていれば焦らず対応できます。日常運用ではsafety branch+推奨設定で事故そのものを減らし、interactive rebaseでは--edit-todo--autosquashを使いこなすのがプロのワークフロー。rebaseが怖くなくなれば、履歴を美しく保ちながら開発を進められます。