HOWTO · Git

在 Git 中刪除不再位於遠端倉庫中的本地分支

本文展示了刪除不再位於遠端倉庫中的本地分支的方法

本頁內容

Git 使用 prune 一詞來表示移除過時的遠端追蹤參照。這和刪除本地分支不同。如果隊友從 origin 刪除了 feature-x,你的本地 origin/feature-x 參照仍可能保留,直到下一次執行帶有修剪功能的 fetch。你自己的本地 feature-x 分支也會保留;如果已不再需要,請另外檢查並刪除它。

清理儲存庫時,這項區別很重要:先更新遠端追蹤資訊,再檢查哪些本地分支顯示上游分支已不存在,最後只刪除你檢查過的分支。標記為 gone 的分支是值得檢查的候選項目,並不代表其中的提交可以丟棄。移除分支前,請保留或備份可能還會用到的工作。

Git prune 會移除什麼

像 origin/main 這樣的遠端追蹤分支,是 Git 在本地記錄某個遠端分支的方式。它不是遠端分支本身,也不同於 main 這類本地分支。git fetch --prune 會更新遠端追蹤參照,並移除遠端上已不存在之分支所對應的參照。它不會移除本地分支、提交,也不會刪除工作目錄中的檔案。

修剪可以減少分支清單中的過時名稱,但不會判斷本地工作是否已完成。本地分支可能包含尚未推送的提交;即使其上游分支已被刪除,這個本地分支仍可能有用。刪除前請檢查分支歷史,並與團隊協調。

更新遠端追蹤分支

先從你要更新其參照的遠端執行 fetch。請將 origin 換成你使用的遠端名稱。--prune 選項只會套用到這次 fetch 的遠端;如果希望定期自動修剪,也可以設定 fetch 的修剪選項。

執行 git fetch --prune origin 來更新該遠端。

使用 git remote -v 查看已設定的遠端。接著以 git branch -vv 檢查本地分支及其上游分支。上游分支已被移除的分支,修剪後會標記為 [gone]。如果沒有先執行最新的 fetch,這個狀態可能已過時。git remote prune origin 也可以移除 origin 的過時遠端追蹤參照;但它同樣不會刪除本地分支。

找出並刪除過時的本地分支

檢查 git branch -vv 的輸出,找出標記為 [gone] 的本地分支。視需要檢查每個候選分支的提交和工作目錄狀況。git branch --merged main 可以協助找出其變更已包含在 main 中的分支,但請使用你儲存庫適用的整合分支。上游分支已不存在和分支已合併回答的是不同問題:前者描述追蹤狀態,後者描述提交是否可從指定分支取得。

使用 git branch -d feature-x 刪除已檢查的分支。如果分支有設定上游,Git 會檢查它是否已合併到該上游;如果沒有上游,Git 會檢查它是否已合併到目前分支。這項防護有助於保護工作,但不能取代你自己的檢查。另一個指令 git branch --merged main 會明確列出已合併到 main 的分支,不受目前分支影響;請依需要換成你的整合分支。如果你已確認提交在其他地方有保留,而且確實要移除尚未合併的分支,git branch -D feature-x 會強制刪除,讓那些工作更難找回。不要只因為上游分支已不存在就使用 -D。

以下簡短範例示範如何辨識擷取的分支清單文字中的標記。它只會解析範例內容;請使用 Git 更新並檢查你的儲存庫。

執行以下範例:

本節中的程式碼以及顯示的標籤或輸出仍為英文。

branch_status = "  feature-x  abc1234 [gone] work in progress"
parts = branch_status.split()
if "[gone]" in parts:
    print(f"Review local branch: {parts[0]}")
Review local branch: feature-x

安全地自動清理

自動化可以減少重複檢查所花的時間,但指令碼應在刪除任何內容前,先清楚列出候選分支。避免以按空白字元切分文字的管線,從人類可讀格式的 git branch -vv 輸出擷取名稱:分支名稱可能包含會讓這種解析方式不可靠的字元,而刪除所有標記為 [gone] 的分支也可能丟失有用的工作。

較謹慎的流程是執行 git fetch --prune origin,使用 NUL 分隔符產生候選清單,檢查清單,並逐一確認是否刪除。提供的執行記錄只測試了儲存庫外部的防護條件,並印出下方所示訊息;沒有在儲存庫中測試候選項目選取或刪除。範例會將分支名稱和追蹤狀態讀取為以 NUL 結尾的獨立欄位,因此不會依空格或其他顯示格式切分名稱。如果沒有上游已不存在的分支,它會略過刪除;對每個候選項目則會先提示確認,並使用一般的 -d。如果 Git 拒絕刪除,錯誤訊息仍會顯示。請在你打算清理的儲存庫中執行:

本節中的程式碼以及顯示的標籤或輸出仍為英文。

if ! git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
    printf 'Run this from inside the repository to clean.\n'
    exit 0
fi

declare -a candidates=()
while IFS= read -r -d '' branch && IFS= read -r -d '' tracking; do
    branch=${branch#$'\n'}
    if [[ $tracking == *'[gone]'* ]]; then
        candidates+=("$branch")
    fi
done < <(git for-each-ref --format='%(refname:short)%00%(upstream:track)%00' refs/heads)

if ((${#candidates[@]} == 0)); then
    printf 'No local branches have a gone upstream.\n'
    exit 0
fi

for branch in "${candidates[@]}"; do
    printf 'Candidate: %q\n' "$branch"
done
for branch in "${candidates[@]}"; do
    answer=
    if [[ -r /dev/tty ]]; then
        printf 'Delete %q with git branch -d? [y/N] ' "$branch" > /dev/tty
        IFS= read -r answer < /dev/tty || answer=
    else
        printf 'No terminal available; skipping %q.\n' "$branch"
    fi
    if [[ $answer == [yY] ]]; then
        git branch -d -- "$branch"
    fi
done
Run this from inside the repository to clean.

請先閱讀候選清單,再回答任何提示。上游標記為 gone 只表示這個分支值得檢查,無法證明其中的提交可以丟棄。不要把未檢查的清單交給 git branch -D。如果你想自行選擇分支,請使用顯示的名稱,逐一以 git branch -d -- <branch> 刪除選定的分支。

如果需要定期清理,可以考慮為儲存庫或特定遠端設定 fetch.prune。這會在 fetch 時自動移除過時的遠端追蹤參照,但仍不會刪除本地分支。使用 git config --get fetch.prune 檢查設定,並在變更前選擇適合該儲存庫的設定範圍。

驗證結果並復原分支

清理後再次執行 git branch -vv。已刪除的本地分支應不再出現;其他上游已不存在的分支則會繼續列出,直到你將它們刪除。若要確認遠端追蹤參照已清理,請使用 git branch -r,並檢查過時的 origin/... 參照是否已消失。這兩項檢查顯示的內容不同:git branch -r 列出遠端追蹤參照,git branch -vv 則列出本地分支及其追蹤狀態。

如果不小心刪除了本地分支,git reflog 可能會顯示該分支頂端的提交。找出正確的提交後,可以使用 git branch feature-x <commit> 重建分支。reflog 項目可能過期,不能取代備份;請儘快復原,並在繼續前確認新分支。如果已知該提交,直接在該提交建立分支就是復原方式。