git fetch –pruneで解決!branch -rに残る削除済みリモートブランチの原因と直し方

2013年11月19日


チームで開発していて、誰かがリモートブランチを削除したのに、自分のローカルでは git branch -r を実行すると削除されたはずのブランチがまだ表示されている――そんな経験はないだろうか。

このページでは、削除済みリモートブランチがローカルに残り続ける仕組みの解説から、git fetch --prune を使った最も手軽な解決策、各ホスティングサービス(GitHub・GitLab・Bitbucket)での確認方法、再発防止の設定まで、一通りの対処法をまとめている。

git branch -rに削除済みリモートブランチが残っている様子


この記事で解決できること

  • git branch -r に削除済みのリモートブランチが表示され続ける原因が分かる
  • git fetch --prunegit remote prune origin の使い分けが分かる
  • ✅ 自動 prune を有効化してこの問題を恒久的に防ぐ設定が分かる
  • ✅ GitHub・GitLab・Bitbucket それぞれでリモートブランチの状態を確認する方法が分かる

動作確認環境: Linux / macOS / Windows(Git for Windows)/ Git 2.39 以上


問題の再現と確認

チームで開発中、同僚が feature/awesome-feature というブランチを GitHub 上で削除した。しかし自分のローカルで確認すると次のように残ったままになっている。

$ git branch -r
  origin/HEAD -> origin/main
  origin/main
  origin/develop
  origin/feature/awesome-feature   ← 削除済みのはずなのに残っている

ここで削除しようと push を試みると次のエラーが出る。

$ git push origin :feature/awesome-feature
error: unable to delete 'feature/awesome-feature': remote ref does not exist
error: failed to push some refs to 'git@github.com:yourorg/yourrepo.git'

リモート上にはもう存在しないので当然のエラーだが、なぜローカルには残り続けるのかが分からず困る人が多い。

git branch -r コマンドをターミナルで実行した出力(削除済みブランチが残っている例)


原因:リモートトラッキングブランチとは何か

Git の「リモートトラッキングブランチ」の仕組み

git branch -r で表示されるのはリモートトラッキングブランチと呼ばれるもので、.git/refs/remotes/ 以下にローカルキャッシュとして保存されている。

.git/
└── refs/
    └── remotes/
        └── origin/
            ├── main
            ├── develop
            └── feature/awesome-feature  ← ローカルに残ったキャッシュ

このキャッシュは git fetch を実行したときにリモートの最新状態と同期されるが、デフォルトでは「リモートで削除されたブランチを消す」動作は行われない。新しいブランチの追加や既存ブランチの更新は反映されるが、削除は反映されないのがデフォルトの挙動だ。

操作 デフォルトの git fetch で反映されるか
リモートに新しいブランチが追加された ✅ 反映される
リモートのブランチが更新(push)された ✅ 反映される
リモートのブランチが削除された ❌ 反映されない(デフォルト)

これが「削除済みブランチがローカルに残り続ける」根本原因だ。


解決策1:git fetch --prune(最も手軽)

概要

--prune オプションを付けて fetch することで、リモートに存在しなくなったトラッキングブランチをローカルから削除できる。

# リモートの最新情報を取得しつつ、削除済みブランチのキャッシュを削除
$ git fetch --prune

# または短縮形
$ git fetch -p

実行例

$ git fetch --prune
From github.com:yourorg/yourrepo
 - [deleted]         (none)     -> origin/feature/awesome-feature

[deleted] と表示され、削除済みブランチのトラッキング情報がローカルから除去される。

確認してみると:

$ git branch -r
  origin/HEAD -> origin/main
  origin/main
  origin/develop
# feature/awesome-feature が消えた

注意: git fetch --prune はリモートトラッキングブランチ(origin/xxx)を消すだけで、ローカルブランチ(git branch で表示される方)は消えない。ローカルブランチが残っている場合は別途 git branch -d ブランチ名 で削除する。

git fetch --prune 実行後にブランチが削除される様子(ターミナル出力)


解決策2:git remote prune origin

fetch は行わず、トラッキングブランチのクリーンアップだけ行いたい場合は git remote prune を使う。

# リモートの状態を確認しながらローカルの古いトラッキングブランチを削除
$ git remote prune origin

–dry-run で事前確認する

実際に削除する前に「何が消えるか」を確認できる。

$ git remote prune --dry-run origin
Pruning origin
URL: git@github.com:yourorg/yourrepo.git
 * [would prune] origin/feature/awesome-feature

[would prune] と表示されたブランチが実際に削除される対象となる。問題なければ --dry-run なしで実行する。

git fetch --prune との使い分け

コマンド fetch も行う ユースケース
git fetch --prune ✅ 行う リモート最新化と同時にクリーンアップしたいとき(推奨)
git remote prune origin ❌ 行わない fetch はせずクリーンアップだけしたいとき

通常は git fetch --prune の方が一度でリモートの最新状態を反映できるため推奨。


解決策3:自動 prune を有効化して恒久的に防ぐ

毎回 --prune を付けるのを忘れそうな場合は、Git の設定で自動的に prune するよう設定できる。

グローバル設定(全リポジトリに適用)

$ git config --global fetch.prune true

設定後は、通常の git fetch を実行するだけで自動的に削除済みブランチがクリーンアップされるようになる。

リポジトリごとの設定

グローバルではなく特定のリポジトリのみに適用する場合:

# プロジェクトルートで実行
$ git config fetch.prune true

設定は .git/config に書き込まれる。

[remote "origin"]
    url = git@github.com:yourorg/yourrepo.git
    fetch = +refs/heads/*:refs/remotes/origin/*
    prune = true   ← これが追加される

チーム開発では全員がこの設定を入れると、「なんかブランチが増えてきた」問題が起きにくくなる。


GitHub・GitLab・Bitbucket での確認方法

GitHub でリモートブランチを確認する

GitHub のリポジトリページ → 「Branches」タブで現在存在するブランチの一覧が確認できる。

# GitHub API でリモートブランチ一覧を取得する場合
$ curl -s \
  -H "Authorization: token YOUR_GITHUB_TOKEN" \
  "https://api.github.com/repos/yourorg/yourrepo/branches" \
  | jq '.[].name'

Pull Request をマージした後に「Delete branch」ボタンを押してもらう運用にすることで、未 prune のブランチが増えにくくなる。

GitLab でリモートブランチを確認する

# GitLab API でリモートブランチ一覧を取得
$ curl -s \
  --header "PRIVATE-TOKEN: YOUR_GITLAB_TOKEN" \
  "https://gitlab.com/api/v4/projects/YOUR_PROJECT_ID/repository/branches" \
  | jq '.[].name'

GitLab では「マージリクエストのマージ時にブランチを削除」を設定できるため、活用することを推奨する。

Bitbucket でリモートブランチを確認する

# Bitbucket API でリモートブランチ一覧を取得
$ curl -s \
  -u "YOUR_USERNAME:YOUR_APP_PASSWORD" \
  "https://api.bitbucket.org/2.0/repositories/yourworkspace/yourrepo/refs/branches" \
  | jq '.values[].name'

よくある関連エラーと対処法

ローカルブランチが残っている場合

git fetch --prune でリモートトラッキングブランチは消えるが、ローカルブランチは残ったままになる。これを一括削除するには以下の方法がある。

# リモートに存在しない(トラッキング先が消えた)ローカルブランチを確認
$ git branch -vv | grep ': gone]'
  feature/awesome-feature abc1234 [origin/feature/awesome-feature: gone] Some commit message

# 該当ブランチを削除
$ git branch -d feature/awesome-feature

# マージ済みでない場合は強制削除
$ git branch -D feature/awesome-feature

一括で削除したい場合は以下のワンライナーが使える。

# 注意: 削除前に必ず git branch -vv | grep ': gone]' で確認すること
$ git fetch --prune && git branch -vv | grep ': gone]' | awk '{print $1}' | xargs git branch -d

注意: xargs git branch -d はマージ済みブランチのみ削除する(未マージブランチはエラーになる)。強制削除は -D に変更するが、作業中のコミットが失われる可能性があるため注意。

git fetch 自体がエラーになる場合

$ git fetch --prune
fatal: 'origin' does not appear to be a git repository
fatal: Could not read from remote repository.

この場合はリモートの設定が壊れているか、SSH キーの問題が考えられる。

# リモートURLを確認
$ git remote -v

# SSH接続を確認(GitHub の場合)
$ ssh -T git@github.com

まとめ

git branch -r に削除済みリモートブランチが残り続ける問題について解説した。

  • 主な原因: git fetch はデフォルトでリモートの削除をローカルに反映しない
  • 最短の解決策: git fetch --prune(または git fetch -p)を実行する
  • 再発防止策: git config --global fetch.prune true を設定し、全 fetch で自動 prune を有効化する

削除済みのリモートトラッキングブランチはただのキャッシュなので、消しても問題ない。git remote prune --dry-run origin で事前確認してから実行すれば安心だ。

チームの全員が fetch.prune true を設定しておくと、積み重なって何十本もブランチが残るような状況を防げる。


関連記事

git,開発

Posted by GENDOSU