【Git】誤ってmaster/mainを削除したときの復旧方法|90秒最速復旧&7パターン完全ガイド

【Git】誤ってmaster/mainを削除したときの復旧方法 Git

「あっ、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秒復旧フロー

削除からまだ他の操作をしていないなら、以下の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)
状況 復旧パターン 復旧難易度
ローカルだけ削除(リモート健在) ケースA:追跡ブランチから復元 ★☆☆☆☆(秒)
リモート削除(ローカル健在) ケースB:ローカルを再push ★☆☆☆☆(秒)
両方削除・削除SHAが判明 ケースC:SHAから再作成 ★★☆☆☆(分)
両方削除・reflogに履歴あり ケースD:reflog探索 ★★☆☆☆(分)
reflogにも無いがオブジェクトDB残存 ケースE:fsck+dangling ★★★☆☆(10分〜)
手元リポから完全消失 ケースF:他クローン/CIから回収 ★★★★☆(1時間〜)
全員のローカルからも消失 ケースG:ホスティングサポート ★★★★★(日単位)

ポイント:ほとんどのケース(体感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運用の場合

上記コマンドのmainmasterに置き換えれば同じ手順で復旧可能。以降のケースも同様に、ブランチ名は環境に合わせて読み替えてください。

ケース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から再作成
# 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 ...のような行に手がかりがあります。

reflogからの復元
# 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
reflogに残る時刻指定での検索
# 「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で総当たり探索します。

fsckでdangling候補を列挙
# 参照されていない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個に固めて救出できます。

他クローンからbundle救出
# 【他メンバーのマシンで】履歴を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
CIログ/デプロイログから先端SHAを特定
# GitHub Actionsの run ログ
# 通常ビルドログ先頭に "Triggered by commit &lt;SHA&gt;" が記録される

# ローカル→CI→デプロイと、その足跡を辿ってSHA特定
# 見つかったらケースC同様に再作成
git branch main <CIから拾ったSHA>

探すべき候補

  • 同僚のローカルリポジトリ(最も成功率高)
  • CIサーバーのチェックアウトディレクトリ
  • デプロイ済みのサーバー(ホスト内の.git)
  • バックアップミラー(定期バックアップ導入済みなら)
  • GitHubのforkリポジトリ(forked pull request由来のSHA)

ケースG:完全消失 → ホスティングサポートに依頼

全員のローカルから消え、CIも履歴を捨てている最悪ケースでも、ホスティングサービス側にサーバーサイドバックアップが残っている場合があります。公式サポートに事象と復旧希望を連絡しましょう。

主要ホスティングのサポート窓口

  • GitHubhttps://support.github.com/contact から復旧依頼(Enterprise Cloudは約90日のサーバーside reflog保持)
  • GitLabsupport.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/HEADgit 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」ボタン

  1. リポジトリトップ → Branchesタブ
  2. 左下の「Deleted branches」リンクを開く
  3. 削除済みブランチ一覧から対象を選びRestoreボタン
  4. GitHubサーバー側のreflog(約90日)から自動復元される
  5. 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:管理者にもルール適用(強く推奨)

定期バックアップの自動化

cronで毎日bundle
#!/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 Actionsで自動バックアップ
# .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設定(自前ホスティング)

git config でdefault branch削除を拒否
# サーバーの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をリモート削除した直後

ローカルから再push
git checkout main
git push -u origin main
# GitHub Settingsでdefault branchをmainに戻す
git remote set-head origin --auto

シナリオ③ 数日前に削除、reflog期限内

reflogから復元
git reflog --all | grep "main" | head
# 候補SHA特定
git branch main <候補SHA>
git push -u origin main

シナリオ④ 全員のローカルから消失、CIログは残存

CIログからSHAを回収
# 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/メールで必ず周知を。

よくある質問

Qローカルでgit branch -D mainしたが復旧可能?
A削除メッセージのwas <SHA>から即復旧できます。メッセージを閉じた後でもreflogから辿れる可能性が高いので、落ち着いてgit reflogを確認しましょう。
QリモートmainをGitHubで削除したPRをどう元に戻す?
AGitHub Branches → Deleted branchesからRestoreボタンで復元可能(約90日間)。またはローカルにmainが残っていればgit push -u origin mainで再公開できます。
Qreflogに載らない古い削除を復旧したい
Agit fsck --no-reflogs --lost-foundでdangling commitを列挙、日時や内容から候補を特定できます。他メンバーのクローンからgit bundle救出も有効。詳細は本記事のケースE/Fを参照。
Q全員のローカルから消えた場合の最終手段は?
Aホスティングサービスのサポートに連絡するか、バックアップ(定期git bundle等)から復旧。GitHub Supportは約90日のサーバーreflogから復元可能な場合があります。
Q復旧後に他メンバーが混乱しないためには?
A再同期コマンド(git fetch && git reset --hard origin/main)を通知し、default branch設定/branch protection/CIの動作確認を済ませてから作業再開を指示しましょう。
Qgit gc後のdangling commitは復旧不可?
Agcで削除されたオブジェクトはローカルからは消えます。他クローン/CI/バックアップに依存するケースF/Gの対応となります。gc前にbackup/before-gcブランチを切っておくのが予防。
Q誤削除を二度と起こさない最強の設定は?
AGitHub Branch Protectionで「Restrict deletions」「Disallow force pushes」「Include administrators」を有効化。加えて毎日のgit bundle自動バックアップとBackup復元テストの定期実施で、ほぼ完全に防げます。

関連記事

まとめ

  • main/master誤削除はほぼ必ず復旧可能——落ち着いて手を止めるのが第一歩
  • 削除メッセージのwas <SHA>は最優先の手がかり
  • ケースA(ローカルのみ)・B(リモートのみ)は秒速復旧
  • SHA不明ならgit refloggit 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を有効化し、定期バックアップを自動化することで二度と同じ事故を起こさない体制を整えましょう。