删除本地分支的 Git 命令:删除已删除上游分支的本地分支?

6

有很多类似的问题(例如这个这个),但被接受的答案似乎不能回答我的确切问题。

Branch1未合并到master。机器A和机器B都指向同一个远程。Branch1存在于该远程。

在机器A上,我本地删除了Branch1并将其推送到远程,以便从Machine A和远程中删除Branch1和remotes/origin/Branch1。

在机器B上,我运行以下操作:

  • git checkout Branch1,然后
  • git checkout Branch2,然后
  • git fetch --prune

git fetch --prune会从我的本地仓库中删除remotes/origin/Branch1。如果我通过运行git checkout Branch1返回Branch1,则会收到以下错误消息:

Switched to branch 'Branch1'
Your branch is based on 'origin/Branch1', but the upstream is gone.
(use "git branch --unset-upstream" to fixup)

是否有一个git命令可以删除具有已删除上游的本地分支?


2
我不相信有这样的功能,你需要手动修剪它们。 - Whymarrh
4个回答

6
没有内置的方法来做到这一点,但是使用以下代码是可能的:
git fetch -p && \
git for-each-ref --format '%(refname:short) %(upstream:track)' | \
  awk '$2 == "[gone]" {print $1}' | \
  xargs -r git branch -D

这个命令由几个部分组成:
1. `git fetch -p`:确保远程分支是最新的。 2. `git for-each-ref --format '%(refname:short) %(upstream:track)'`:以我们选择的格式返回git分支,其中包括本地分支名称和上游分支(对于远程已删除的分支,上游分支将显示为"[gone]")。 - `awk '$2 == "[gone]" {print $1}'`:过滤掉上游状态为"[gone]"的分支,并返回本地分支名称。 - `xargs -r git branch -D`:删除本地分支。
你甚至可以通过运行以下命令将上述命令添加为git别名:
git config --global alias.gone "! git fetch -p && git for-each-ref --format '%(refname:short) %(upstream:track)' | awk '\$2 == \"[gone]\" {print \$1}' | xargs -r git branch -D"

一旦这个命令执行完毕,你就可以使用git gone来删除本地分支,这些分支对应的远程分支已经被删除。
你可以在这篇博客文章中阅读完整的解释。

1
有点愚蠢的问题,但为什么在 ' 中的 " 要用反斜杠转义?它们不需要在它们所在的字符串中使用,而且(至少我使用的)awk 不喜欢它们。 - anon
这不是一个愚蠢的问题,因为我曾经遇到同样的问题。事实证明,在git别名命令中需要使用反斜杠,但是在终端手动运行命令时会导致命令无法执行。我已经更新了答案以反映这一点。 - imolit

2

Whymarrh的评论是正确的:没有内置命令可以做到这一点。

而且有很好的理由没有这样的内置命令。虽然上游远程跟踪分支已经被修剪,但并不意味着你一定要放弃自己的工作。以您的示例为例,在执行git fetch --prune 删除 origin/Branch1 之前,可能提交图像看起来像这样:

...--o--o--o     <-- origin/Branch1
            \
             o   <-- Branch1

假设你在Branch1上提交了一个好的提交并准备将其git push,但上周被打断了。现在origin/Branch1已经消失了,也许你想把那个好的提交复制到其他地方。但是现在origin/Branch1已经不存在了,没有理由保留图表中的弯曲部分,Git只能看到这样的内容:

...--o--o--o--o   <-- Branch1

它知道你的Branch1已经配置了上游,但是它不知道当它存在时该配置的上游指向哪个提交。

尽管如此,如果你很确定要删除这些分支,你可以通过一个简短的脚本来实现:

#! /bin/sh
#
# rm-if-gone: remove branches that have a configured upstream
# where the configured upstream no longer exists.  Run with
# -f to make it work, otherwise it just prints what it would
# remove.
force=false
case "$1" in
-f) force=true;;
esac

for branch in $(git for-each-ref --format='%(refname:short)' refs/heads); do
    # find configured upstream, if any
    remote=$(git config --get branch.$branch.remote) || continue
    # if tracking local branch, skip
    if [ "$remote" = . ]; then continue; fi
    # if the upstream commit resolves, skip
    ucommit=$(git rev-parse "${branch}@{u}" 2>/dev/null) && continue
    # upstream is invalid - remove local branch, or print removal
    $force && git branch -D $branch || echo "git branch -D $branch"
done

(以上代码未经测试;并且由于您无法删除当前分支,因此需要确保您在不打算删除的分支上。)


-1
这个命令对我很有帮助,可以删除上游已经删除的 'foo' 分支。
git branch -d foo

你必须在本地主分支上,否则会收到以下错误:error: Cannot delete branch 'foo' checked out at...

-2

git remote prune origin --dry-run

移除 --dry-run 以执行修剪。来自文档

删除 name 下的所有过时的远程跟踪分支。这些过时的分支已经从由 name 引用的远程仓库中删除,但仍然在“remotes/name”中本地可用。


1
分支'remotes/origin/Branch1'已经被git fetch --prune删除了。你建议的命令根本没有做任何事情,本地分支'Branch1'仍然在分支列表中。 - dumbledad

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接