「あっ、main消した」——本番mainブランチを誤って消してしまったとき、画面の前で凍りつく経験をした方も多いのではないでしょうか。しかし落ち着いてください。Gitのmaster/main削除は、ほとんどの場合90秒以内で復旧可能です。コミットオブジェクト自体は残っており、参照(ブランチ名)が外れただけだからです。
# ローカルで誤削除 $ git branch -D main Deleted branch main (was a1b2c3d). # ↑ この"was a1b2c3d"が救済の鍵 # リモートで誤削除 $ git push origin --delete main To github.com:user/repo.git - [deleted] main
この記事では、master/mainを誤削除した場合の復旧フロー7パターンを影響範囲の小さい順に解説します。削除直後で気付いた場合の90秒最速復旧から、reflog期限切れ/dangling commit探索/他クローンからbundle救出、GitHub/GitLabの管理画面復旧、災害級の全消失まで、現場で即使える具体コマンドと判断基準をまとめました。
この記事で学べること
- main/master削除の影響範囲診断(ローカル/リモート/両方)
- 90秒最速復旧フロー:削除直後ならこれで即解決
reflogからのSHA特定と再作成git fsck --lost-foundによるdangling commit救出- 他クローン・CIログ・
git bundleによる回収 - GitHub/GitLab/Bitbucket管理画面の復旧機能
- default branch切替と保護ルール再設定
- 二度と起こさないための保護設定とバックアップ戦略
- 【最速】削除直後の90秒復旧フロー
- STEP 0:影響範囲を正確に診断する
- ケースA:ローカルだけ削除してしまった(最頻出)
- ケースB:リモートのmainを削除した(ローカル健在)
- ケースC:両方消えたが削除時のSHAを覚えている
- ケースD:SHA不明 → reflogから探す
- ケースE:reflogにも無い → fsckで dangling commit 探索
- ケースF:他メンバー/CI/バックアップから救出
- ケースG:完全消失 → ホスティングサポートに依頼
- 復旧後の整合性チェック(重要)
- GitHub/GitLab/Bitbucket 管理画面での復旧
- 再発防止:二度と起こさないための保護設定
- 実践シナリオ
- やってはいけない落とし穴
- よくある質問
- 関連記事
- まとめ
【最速】削除直後の90秒復旧フロー
削除からまだ他の操作をしていないなら、以下の3パターンで即復旧できます。「作業を止めて」「これを実行」で大半は数十秒で元通りに戻ります。
# ■ ローカルだけ削除した場合 ──── # 削除メッセージに出ていたSHAから復活 git branch main <削除時のSHA> # 例: git branch main a1b2c3d git switch main # ■ リモート追跡が生きている場合 ──── git switch -c main origin/main # ■ リモートも削除した直後 ──── # ローカルが生きていれば再公開 git push -u origin main # ■ SHAを覚えていない場合 ──── git reflog | head -20 # "checkout: moving from main to ..." の行からSHAを特定 git branch main <SHA>
ポイント:削除直後の成功率はほぼ100%。「Deleted branch main (was a1b2c3d)」という出力行のSHAを拾えればgit branch main a1b2c3dで即復活します。この出力を閉じる前にメモする習慣を付けておくと、さらに速く対応できます。
注意:削除に気付いたら追加の操作をしないのが鉄則。git gcの自動実行・大量commit・checkout・reset等でオブジェクトが押し出されると救済が難しくなります。まず手を止めて、退避ブランチを切ってから復旧作業に入りましょう。
STEP 0:影響範囲を正確に診断する
復旧方法を選ぶには、どこまで消えたかを先に把握します。ローカルだけか、リモートも消したか、両方消えたか、タグやPRにも波及したか。
# 1. リモートの状況を把握 git fetch --prune --all git ls-remote --heads origin # origin/main が出れば「ローカルだけ削除」確定 # 2. ローカルの状況 git branch -a # 3. HEADの履歴(主たる救出経路) git reflog | head -30 # 4. 参照から外れたコミット(danglingの有無) git fsck --no-reflogs --lost-found | grep commit | head -10 # 5. 念のため退避ブランチを作成 git switch -c safety/backup-$(date +%Y%m%d-%H%M) HEAD 2>/dev/null || \ git checkout -b safety/backup-$(date +%Y%m%d-%H%M)
ポイント:ほとんどのケース(体感8割)はケースA〜Cで解決します。ケースD〜Eはreflogの90日期限との勝負、ケースF以降はホスティングやチームメンバーとの連携が鍵になります。
ケースA:ローカルだけ削除してしまった(最頻出)
リモートorigin/mainが残っていれば、追跡ブランチから作り直すだけで復旧完了。プロジェクトへの影響はゼロです。
# 現状確認 git fetch --prune git branch -a | grep main # remotes/origin/main ← 生きていればOK # ローカルmainをリモート追跡から再作成 git switch -c main origin/main # または git checkout -b main origin/main # 追跡設定(自動でつくが念のため) git branch --set-upstream-to=origin/main main # 確認 git branch -vv # * main abc1234 [origin/main] ... ← 完了
master運用の場合
上記コマンドのmainをmasterに置き換えれば同じ手順で復旧可能。以降のケースも同様に、ブランチ名は環境に合わせて読み替えてください。
ケースB:リモートのmainを削除した(ローカル健在)
ローカルにmainが残っていれば、git pushで再公開するだけ。ただし管理画面のdefault branch設定・branch protection rulesは削除時に解除されている可能性があるため、復旧後に再設定が必要です。
# ローカルmainの先端が正しいことを確認 git checkout main git log --oneline -5 # リモートに再push git push -u origin main # 管理画面で default branch を main に再設定 # GitHub: Settings → Branches → Default branch → 切替 # origin/HEAD も更新 git remote set-head origin --auto
注意:default branchを削除すると、GitHubでは自動的に他のブランチがdefaultに昇格する場合があります。復旧後は必ず管理画面でdefault branchがmainに戻っているか確認し、branch protection rules(force push禁止・削除禁止・PR必須等)も再有効化してください。
「remote HEAD refers to nonexistent ref」警告が出る場合はremote HEAD refers to nonexistent ref警告の対処法を参照。
ケースC:両方消えたが削除時のSHAを覚えている
削除時の出力(was a1b2c3d)、別ターミナルの履歴、PR画面、リリースタグなどからmainの先端SHAが判明すれば、そのハッシュから一発でブランチ再作成できます。
# SHAからブランチ作成 git branch main <既知SHA> # 例: git branch main a1b2c3d # checkoutと同時に作成 git switch -c main <既知SHA> # 問題なければリモートにpush git push -u origin main # SHAが短いなら git log --all --oneline で確認 git log --oneline --all | grep "a1b2c3d"
SHAの見つけ方いろいろ
- 削除時のターミナル出力に
was <SHA>と表示される - PR画面(GitHub)で「Merge pull request」コミットのSHA
- リリースタグ(
git log -1 v1.2.0) - CI/デプロイログに記録されたSHA
- issue tracker/Slackに貼られたcommit URL
ケースD:SHA不明 → reflogから探す
削除前のSHAをメモしていなくても、HEADの移動履歴を記録するreflogから辿れます。checkout: moving from main to ...のような行に手がかりがあります。
# HEADの移動履歴を一覧
git reflog
# 出力例:
# abc1234 HEAD@{3}: checkout: moving from main to feature/xxx
# def5678 HEAD@{4}: commit: mainへの最後のcommit
# ↑ このabc1234が「mainを離れる直前のHEAD」= mainの先端SHA候補
# mainブランチ固有のreflogを見る(まだ残っていれば)
git reflog show main 2>/dev/null
# or
git reflog --all | grep -i " main"
# 見つけたSHAからブランチ再作成
git branch main abc1234
git push -u origin main
# 「1時間前のmain先端」を取得
git log --oneline --all --since="1 hour ago" | head -20
# reflogを時刻付きで
git reflog --date=iso | head -30
# HEAD@{yesterday}で直接参照(前日時点)
git show "HEAD@{yesterday}" --stat
# それをブランチ化
git branch main "HEAD@{yesterday}"
注意:reflogは既定90日で自動clean upされます。数ヶ月前に削除されたブランチはreflogに載っていない可能性があります。期限前にgcが走ると、それ以前の実体も消えるので、気付いたら即座に行動を。
ケースE:reflogにも無い → fsckで dangling commit 探索
reflogから押し出された(またはgit gcの閾値に達していない)コミットは、参照されない「ぶら下がりコミット(dangling commit)」として.git/objects/に残っている可能性があります。git fsckで総当たり探索します。
# 参照されていないcommitを列挙
git fsck --no-reflogs --lost-found
# 出力例:
# dangling commit abc1234...
# dangling blob def5678...
# dangling commitを時刻降順で候補化(新しいものから確認)
for sha in $(git fsck --no-reflogs --lost-found | awk '/dangling commit/ {print $3}'); do
date=$(git show --no-patch --format="%ci" "$sha")
msg=$(git show --no-patch --format="%s" "$sha")
echo "$date $sha $msg"
done | sort -r | head -20
# 候補をひとつずつ中身確認
git show --stat <候補SHA>
git show -p <候補SHA> | head -50
# mainの先端らしきコミットが見つかったら復旧
git branch main <候補SHA>
git push -u origin main
ポイント:mainの先端コミットは通常「Merge pull request #xx」「Release v1.2.3」等のメッセージを持ちます。「親が2つ」(マージコミット)や「タグが付いている」(git tag --contains <SHA>)コミットは候補の有力株です。
ケースF:他メンバー/CI/バックアップから救出
自分のリポジトリからは完全消失しても、チームメンバーのローカル・CI環境・デプロイ用ミラーなどに同じ履歴がまだ残っている可能性が高いです。git bundle経由でファイル1個に固めて救出できます。
# 【他メンバーのマシンで】履歴を1ファイルに固める git bundle create /tmp/recovery.bundle --all # 【自分のマシンへ転送後】取り込み # 新規リポに展開する場合 git clone /tmp/recovery.bundle recovered-repo # 既存リポにfetchする場合 git fetch /tmp/recovery.bundle "refs/heads/*:refs/remotes/bundle/*" git branch main bundle/main git push -u origin main
# GitHub Actionsの run ログ # 通常ビルドログ先頭に "Triggered by commit <SHA>" が記録される # ローカル→CI→デプロイと、その足跡を辿ってSHA特定 # 見つかったらケースC同様に再作成 git branch main <CIから拾ったSHA>
探すべき候補
- 同僚のローカルリポジトリ(最も成功率高)
- CIサーバーのチェックアウトディレクトリ
- デプロイ済みのサーバー(ホスト内の.git)
- バックアップミラー(定期バックアップ導入済みなら)
- GitHubのforkリポジトリ(forked pull request由来のSHA)
ケースG:完全消失 → ホスティングサポートに依頼
全員のローカルから消え、CIも履歴を捨てている最悪ケースでも、ホスティングサービス側にサーバーサイドバックアップが残っている場合があります。公式サポートに事象と復旧希望を連絡しましょう。
主要ホスティングのサポート窓口
- GitHub:
https://support.github.com/contactから復旧依頼(Enterprise Cloudは約90日のサーバーside reflog保持) - GitLab:
support.gitlab.com(Self-managed/Dedicatedはバックアップ依頼可) - Bitbucket:Atlassian Support(プランにより保持期間異なる)
- Azure DevOps:Azure Support経由
- 自前ホスティング(Gitea/Gerrit等):サーバー管理者にバックアップ確認
警告:サポート経由の復旧は時間がかかる上、プランによっては不可能なこともあります。常日頃から定期バックアップ(git bundleなど)を自動化しておくのが、この最悪ケースを防ぐ唯一の確実な方法です。詳細は後述の「予防」章へ。
復旧後の整合性チェック(重要)
ブランチを復旧しても、周辺設定は壊れたままのことが多いです。次の項目を順に確認して再設定しましょう。
復旧後チェックリスト
- default branch:管理画面で
mainに戻す - branch protection rules:force push禁止・削除禁止・レビュー必須を再有効化
- origin/HEAD:
git remote set-head origin --auto - CI/デプロイ:mainブランチ対象の自動化が動いているか
- webhook:ブランチ名含むfilter設定を確認
- PRのbase branch:未マージPRが正しいmainを向いているか
- タグ:mainコミットを指すタグが正しいSHAか
- 他メンバー:再clone/再同期の指示をチームに周知
# チームに案内するコマンド例 git fetch --all --prune git switch main git reset --hard origin/main git remote set-head origin --auto # localブランチが壊れていれば一度削除して再作成 # git branch -D main # git switch -c main origin/main
GitHub/GitLab/Bitbucket 管理画面での復旧
GitHub:削除済みブランチの復元機能
GitHub Branches ページの「Restore」ボタン
- リポジトリトップ → Branchesタブ
- 左下の「Deleted branches」リンクを開く
- 削除済みブランチ一覧から対象を選びRestoreボタン
- GitHubサーバー側のreflog(約90日)から自動復元される
- default branchを戻す場合はSettings → Branchesで再設定
GitLab:削除タイミングに応じた復旧
GitLabの方針
- Protected Branchに設定されていれば一般ユーザーは削除不可
- Self-managed GitLabは管理者がサーバー内
git reflogから復旧可能 - SaaS GitLab.comはSupport経由でバックアップ復旧依頼
Bitbucket:ブランチ復元はプランによる
Bitbucketの確認事項
- Premium以上では監査ログから削除履歴を確認可能
- Atlassian Support経由でサーバーバックアップ依頼
- Branch permissionsで事前に削除禁止を設定推奨
再発防止:二度と起こさないための保護設定
Branch Protectionで物理的に防ぐ
- Restrict deletions:main/masterの削除を禁止
- Disallow force pushes:強制pushを禁止
- Require a pull request before merging:PRベースのマージ必須
- Require status checks to pass:CIパス必須
- Require review from Code Owners:承認必須
- Include administrators:管理者にもルール適用(強く推奨)
定期バックアップの自動化
#!/bin/bash # daily-backup.sh REPO=/path/to/repo BACKUP_DIR=/backup/git-bundles mkdir -p "$BACKUP_DIR" cd "$REPO" git fetch --all --prune git bundle create "$BACKUP_DIR/$(basename "$REPO")-$(date +%Y%m%d).bundle" --all # 30日より古いバックアップは削除 find "$BACKUP_DIR" -name "*.bundle" -mtime +30 -delete # crontabに登録(毎日3時実行) # 0 3 * * * /path/to/daily-backup.sh
# .github/workflows/backup.yml
name: Backup bundle
on:
schedule:
- cron: '0 3 * * *' # 毎日3時
workflow_dispatch:
jobs:
bundle:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- run: |
git bundle create repo.bundle --all
- uses: actions/upload-artifact@v4
with:
name: git-bundle-$(date +%Y%m%d)
path: repo.bundle
retention-days: 90
ポイント:バックアップは「取るより復旧テスト」が重要。月に1回はgit clone repo.bundle test-recoveryで復旧できるか試し、手順書をREADMEに残しておくと、いざという時に慌てずに済みます。
サーバー側のdeny設定(自前ホスティング)
# サーバーのbareリポジトリ側で設定 cd /var/git/repo.git git config receive.denyDeleteCurrent true # 削除全般を禁止 git config receive.denyDeletes true # force push禁止 git config receive.denyNonFastForwards true
実践シナリオ
シナリオ① うっかりgit branch -D main
# 削除メッセージから SHA 拾う # Deleted branch main (was a1b2c3d). git branch main a1b2c3d git switch main # 完了(30秒)
シナリオ② mainをリモート削除した直後
git checkout main git push -u origin main # GitHub Settingsでdefault branchをmainに戻す git remote set-head origin --auto
シナリオ③ 数日前に削除、reflog期限内
git reflog --all | grep "main" | head # 候補SHA特定 git branch main <候補SHA> git push -u origin main
シナリオ④ 全員のローカルから消失、CIログは残存
# GitHub Actions の workflow run ログを確認 # "Commit: abc1234..." を特定 # デプロイ先サーバーの .git 経由でbundle作成 ssh prod-server "cd /app && git bundle create - --all" > recovery.bundle git fetch recovery.bundle "refs/heads/*:refs/remotes/recovery/*" git branch main recovery/main git push -u origin main
やってはいけない落とし穴
削除に気付いて慌ててgit gcを実行
「整理すれば直るかも」とgit gcを打つと、dangling commitが削除されて復旧可能性を自ら潰します。削除に気付いたら手を止め、retryや再commitも控え、まずreflogとfsckで状況確認を。
削除メッセージを閉じてから動き出す
Deleted branch main (was abc1234)のSHAは最重要の手がかり。ターミナルを閉じる前にスクリーンショットやメモを取りましょう。tmux/screenのスクロールバッファ、scriptコマンドでの記録も有効です。
同名ブランチを新規作成してforce push
「main消えたから作り直せばいい」と、空のmainを新規作成してgit push --force origin mainすると、GitHub側のサーバーreflog以外の復旧経路が消えます。必ずreflog/他クローン/bundleで元履歴を救出してからpushを。
Branch protectionを無効のまま運用
そもそもmain削除できる状態のリポジトリは事故待ち。GitHub等のBranch protection rulesで「Restrict deletions」「Disallow force pushes」を必ず有効化し、管理者にもルールを適用(Include administrators)しておきましょう。
チームへの通知を忘れる
mainを復旧したらSHAが変わっている場合があります。他メンバーがpullすると想定外のconflictになるので、git fetch && git reset --hard origin/mainの再同期コマンドをSlack/メールで必ず周知を。
よくある質問
git branch -D mainしたが復旧可能?was <SHA>から即復旧できます。メッセージを閉じた後でもreflogから辿れる可能性が高いので、落ち着いてgit reflogを確認しましょう。git push -u origin mainで再公開できます。git fsck --no-reflogs --lost-foundでdangling commitを列挙、日時や内容から候補を特定できます。他メンバーのクローンからgit bundle救出も有効。詳細は本記事のケースE/Fを参照。git bundle等)から復旧。GitHub Supportは約90日のサーバーreflogから復元可能な場合があります。git fetch && git reset --hard origin/main)を通知し、default branch設定/branch protection/CIの動作確認を済ませてから作業再開を指示しましょう。git gc後のdangling commitは復旧不可?backup/before-gcブランチを切っておくのが予防。git bundle自動バックアップとBackup復元テストの定期実施で、ほぼ完全に防げます。関連記事
- 【Git】「remote HEAD refers to nonexistent ref」警告の対処法 — default branch消失の関連問題
- 【Git】ブランチを削除する方法 — そもそもの削除手順と注意点
- 【Git】ブランチ名を変更する方法 — master→main改名
- 【Git】新しいブランチを作成する基本的な手順 — ブランチ再作成の基礎
- 【Git】stashした内容を失ってしまったときの復元方法 — 類似のdangling救出
- 【Git】pushを取り消す方法 — 復旧後の誤pushリカバリ
- 【Git】pushしようとしたら”non-fast-forward”で拒否されたときの解決方法 — 復旧後のpush拒否対処
- 【Git】よく使うgitコマンドまとめ — 日常コマンドの早見表
まとめ
- main/master誤削除はほぼ必ず復旧可能——落ち着いて手を止めるのが第一歩
- 削除メッセージの
was <SHA>は最優先の手がかり - ケースA(ローカルのみ)・B(リモートのみ)は秒速復旧
- SHA不明なら
git reflog→git fsck --lost-foundの順で探索 - 手元消失は他メンバー/CI/
git bundleから救出 - GitHub Branches → Deleted branchesのRestoreボタンは約90日有効
- 復旧後はdefault branch/branch protection/CIを再設定
- 予防:Branch protection「Restrict deletions」+定期
git bundleバックアップ
main/master削除は見た目の深刻さほど致命的ではありません。Git内部のコミットオブジェクトは参照が外れても直ちには消えない設計のおかげで、削除直後なら90秒以内で復旧できるケースが大半です。焦らず手を止めて削除メッセージのSHAを確保し、本記事の7パターンから自分の状況に合う復旧手順を選んでください。復旧後は必ずBranch protection rulesを有効化し、定期バックアップを自動化することで二度と同じ事故を起こさない体制を整えましょう。

