Skip to main content

Git 各種日常問題集合 - 遠端

Git 教學現在有獨立的網站了!請移駕 Git 零到一百

都是簡單的日常問題但是要花一點時間搜尋,所以這篇文章集中列出方便查詢。

一次清除遠端所有分支

發了一堆 PR 被合併後該如何快速清除?

git remote prune origin

一次清除所有被合併的分支

請使用此腳本而不是浪費時間在背指令、找小抄:

腳本
#!/usr/bin/env bash

# delete_merged_branch - 刪除已合併的 Git 分支
#
# Usage:
# delete-merged-branch # 只刪除本地已合併分支
# delete-merged-branch true # 刪除本地與遠端(使用 origin)
# delete-merged-branch true NAME # 刪除本地與遠端 upstream NAME

set -e

DELETE_REMOTE="${1:-false}"
REMOTE_NAME="${2:-origin}"

COLOR_YELLOW='\033[33m'
COLOR_RESET='\033[0m'

if ! git rev-parse --git-dir >/dev/null 2>&1; then
echo "Error: Not in a Git repository"
exit 1
fi

BRANCHES=$(git branch --merged | grep -v -E "^[[:space:]]*\\*|[[:space:]]*(master|main)[[:space:]]*$" | sed 's/^[[:space:]]*//')

if [ -z "$BRANCHES" ]; then
echo "No merged branches found."
exit 0
fi

echo "Found merged branches:"
echo "$BRANCHES" | while IFS= read -r branch; do
[ -n "$branch" ] && printf " ${COLOR_YELLOW}%s${COLOR_RESET}\n" "$branch"
done
echo

BRANCH_ARRAY=()
while IFS= read -r branch; do
[ -n "$branch" ] && BRANCH_ARRAY+=("$branch")
done <<<"$BRANCHES"

for branch in "${BRANCH_ARRAY[@]}"; do
if [ "$DELETE_REMOTE" = "true" ]; then
printf "Delete merged branch '${COLOR_YELLOW}%s${COLOR_RESET}' locally and from remote '${COLOR_YELLOW}%s${COLOR_RESET}'? [y/N] " "$branch" "$REMOTE_NAME"
else
printf "Delete merged branch '${COLOR_YELLOW}%s${COLOR_RESET}' locally? [y/N] " "$branch"
fi

read -r ans

case "$ans" in
[Yy] | [Yy][Ee][Ss])
# 本地分支刪除成功才會刪遠端
if git branch -d "$branch"; then
if [ "$DELETE_REMOTE" = "true" ]; then
if git push "$REMOTE_NAME" --delete "$branch" 2>/dev/null; then
printf "Deleting remote branch '${COLOR_YELLOW}%s${COLOR_RESET}' from '${COLOR_YELLOW}%s${COLOR_RESET}' successfully." "$branch" "$REMOTE_NAME"
else
printf "Fail to delete remote branch '${COLOR_YELLOW}%s${COLOR_RESET}' from '${COLOR_YELLOW}%s${COLOR_RESET}'." "$branch" "$REMOTE_NAME"
fi
fi
else
printf "Failed to delete local branch '${COLOR_YELLOW}%s${COLOR_RESET}'\n" "$branch"
fi
;;
*)
printf "Skip branch: ${COLOR_YELLOW}%s${COLOR_RESET}\n" "$branch"
;;
esac
done

printf "\nBranch cleanup completed.\n"

我的用法是儲存腳本後使用 gitconfig 把腳本加入 Git alias,例如 dm = "!delete_merged_branch"

遠端追蹤分支是什麼?和遠端分支一樣嗎?追蹤分支又是什麼?

遠端追蹤分支 (Remote-tracking Branch) 是本地儲存庫用來記錄遠端分支最新狀態的本地參考,其名稱格式為 <遠端名稱>/<分支名稱>,例如預設的 origin/main

執行 git clone 後,Git 會自動檢出 (checkout) 一個預設的本地分支,並將其設定為追蹤分支(Tracking Branch),該分支會與對應的遠端追蹤分支建立追蹤關係。例如 git clone 後預設檢出的 main 分支,會追蹤 origin/main 這個遠端追蹤分支,而 origin/main 也可稱為 main 分支的上游分支(Upstream Branch)。

所謂口語上的遠端分支就是在遠端中的本地分支,和遠端追蹤分支是不同的概念。


無法推送

有兩種可能,遠端分支設定錯誤或者遠端提交歷史比本地還要新。

比本地還新的話就使用 git pull --rebase,如果設定跑掉就用設定遠端分支,如果想要覆蓋就使用安全的強制推送


還是無法推送,重設遠端分支

請見 Git 遠端指令的 找不到遠端的處理方式 段落。


安全的強制推送

你以為我要講 force-with-lease 嗎,我要說的是更少人知道的 force-if-includes,請見使用 Force if Includes 安全的強制推送,裡面還有解釋 lease 到底在「租」什麼東西。


清除隱私資料

使用任意方式把目標提交從提交歷史中移除就可以了,不用擔心 reflog 紀錄,因為 reflog 紀錄壓根就不會被推送到遠端,如果要徹底清除本地紀錄可以使用 filter-repo,內建的 filter-branch 已經不被建議使用。

賣課網寫錯了,每個人的 reflog 紀錄都不一樣,那怎麼可能被推送?搞清楚 Git 是「分散式」的「鏡像系統」就不會說出 reflog 紀錄被推送這句話。

你可能會覺得我很嚴格,可能作者就是剛好沒想到啊,你說的沒錯,那退一步來說,要寫書教別人之前至少要測試正確性吧,看起來是沒有。


只推送部分提交

git push <遠端名稱> <指定提交>:<遠端分支名稱>

這個 10 秒能講完的事情賣課網拍了七分鐘的影片。


加速 Clone

請見我的文章使用 Git Sparse Checkout 只下載部分專案以加速 Clone 速度

其實 The Will Will Web 就寫的很詳細,我覺得雖然詳細但不夠清楚,而且指令有部分更新,所以統整後寫成文章。