【问题标题】:remove branches not on remote删除不在远程的分支
【发布时间】:2013-05-16 14:27:26
【问题描述】:
==> git branch -a
* master
  test
  remotes/origin/master
  remotes/origin/test

当有人删除remotes/origin/test时,我仍然可以在我的电脑上看到它。

我知道我可以这样做并删除test

==> git remote prune
==> git branch -d test
==> git branch -a
* master
  remotes/origin/master

但是如果我有更多的本地分支,并且它们不在远程,那么我怎样才能快速删除它们呢?

【问题讨论】:

标签: git git-branch


【解决方案1】:

这就是我删除不再相关的本地分支的方式:

git branch --merged origin/master | xargs git branch -d

您可能需要根据您的特定配置对其进行调整(例如,请参阅下面的 cmets 以排除特定分支),但管道之前的第一个命令应该为您提供已合并到您的主分支的所有本地分支的列表分支。

【讨论】:

  • 怕删除本地master,我修改为:git branch --merged origin/master | grep -v master | xargs git branch -d
  • 对上述评论的挑剔更改,但为了避免意外删除“master”以外的其他分支(即 Gitflow 中的“develop”),最好不要反转 grep 命令,而是做一些事情喜欢:git branch --merged origin/develop | grep "^\s*feature/" | xargs git branch -d
【解决方案2】:

简单的修剪不会删除本地分支。

这是实现真正删除的另一种方法。请务必先执行“git fetch -p”以获取远程仓库的最新状态。

git branch -vv | grep ': gone]'|  grep -v "\*" | awk '{ print $1; }' | xargs -r git branch -d

这将检查所有本地分支及其来源,并将删除其来源被删除的所有本地分支。

详细说明:

git branch -vv

将列出您的本地分支并显示有关远程分支的信息,如果它不再存在,则说“gone”。

grep ': gone]'

将获取匹配“gone]”短语的分支。

grep -v "\*"

将只获取不包含星号的行。这将忽略您当前所在的分支,并防止“git branch -d”以“*”结尾执行,这将导致删除所有本地分支

awk '{print $1}'

将获取输出直到第一个空格,这将导致本地分支名称。

xargs git branch -d

将使用输出(分支名称)并将其附加到“git branch -d”命令以最终删除分支。如果你还想删除没有完全合并的分支,你可以使用大写的“D”而不是“d”来强制删除。

【讨论】:

  • 在 macOS 上工作,但留下了一些没有远程源的分支。有趣..
  • @JohnnyFive 只需执行一个普通的“git branch -vv”并检查分支是否标记为“gone”。您可能需要再次执行 git fetch。
  • 获取xargs: illegal option -- r
  • @Leo 如果您在非 GNU Linux 系统上执行命令,则会出现此错误。只有基于 GNU Linux 的系统具有 -r 选项,如果输入参数(在本例中为分支名称)为空,则该选项负责跳过执行。您可以从命令中删除该选项,但可能会得到一些您可以忽略的无效参数错误。
  • 确实有这个问题,比使用 git branch -vv | grep ': 消失了]'| grep -v "*" | awk '{ 打印 $1; }' | xargs git 分支 -D
【解决方案3】:

根据git-fetch 手册页,git fetch -p 将“在获取后,删除远程不再存在的任何远程跟踪分支。”如果您有本地分支跟踪这些远程分支,您可能需要修剪那些手动的。

【讨论】:

  • 但是如何删除不在远程的本地分支? -p 只删除远程跟踪
  • 您能否可靠地区分设置为跟踪远程分支的本地分支与用于本地开发的分支?如果我的本地分支被命名为foo,它最初是为了跟踪remotes/origin/foo 而创建的,还是我为了测试一些新想法而创建的本地分支?如果您可以为每个本地分支机构可靠地回答该问题,您可以git branch -D 那些您不想要的。如果你做不到,那么尝试“自动”进行操作将具有破坏性。
  • The manual 表示--prune“删除遥控器上不再存在的任何远程跟踪引用”。因此,不跟踪远程分支的本地分支不会受到影响。
【解决方案4】:

为此,我编写了一个名为git-dangling-branches 的简单shell 脚本。如果您指定-D 选项,它将删除所有没有refs/remotes/origin/<branch_name> 的本地分支。当然,这样做时你应该小心。

#!/bin/bash -e
if [[ "$1" == '-D' ]]; then
  DELETE=1
else
  DELETE=0
fi

REMOTE_BRANCHES="`mktemp`"
LOCAL_BRANCHES="`mktemp`"
DANGLING_BRANCHES="`mktemp`"
git for-each-ref --format="%(refname)" refs/remotes/origin/ | \
  sed 's#^refs/remotes/origin/##' > "$REMOTE_BRANCHES"
git for-each-ref --format="%(refname)" refs/heads/ | \
  sed 's#^refs/heads/##' > "$LOCAL_BRANCHES"
grep -vxF -f "$REMOTE_BRANCHES" "$LOCAL_BRANCHES" | \
  sort -V > "$DANGLING_BRANCHES"
rm -f "$REMOTE_BRANCHES" "$LOCAL_BRANCHES"

if [[ $DELETE -ne 0 ]]; then
  cat "$DANGLING_BRANCHES" | while read -r B; do
    git branch -D "$B"
  done
else
  cat "$DANGLING_BRANCHES"
fi
rm -f "$DANGLING_BRANCHES"

【讨论】:

  • 这就是我想要的答案。我有兴趣清除在 github 中不存在同名的本地分支。其他答案删除了远程跟踪分支,并删除了所有合并的分支,但这不是我想要的。所以谢谢你。我在运行之前将 -D 更改为 -d,以防万一。
  • 这太棒了。我不得不更改mktemp 以接触实际的文件名,因为我的操作系统不支持mktemp,但这绝对很棒。
  • 我还添加了这个:git remote prune origin $DRY_RUN 在顶部,如果-D 未通过,则$DRY_RUN 设置为--dry-run。很好地清理我的系统。
【解决方案5】:

我最终得到了与kcm 的方法非常相似的东西。我想要一些东西来清除所有跟踪远程分支的本地分支,在origin,远程分支已被删除(gone)。我不想删除从未设置为跟踪远程分支的本地分支(即:我的本地开发分支)。我还想要一个简单的单行代码,它只使用git 或其他简单的 CLI 工具,而不是编写自定义脚本。我最终使用了一些grepawk 来制作这个简单的命令,然后将它作为别名添加到我的~/.gitconfig 中。

[alias]
  prune-branches = !git remote prune origin && git branch -vv | grep ': gone]' | awk '{print $1}' | xargs -r git branch -D

这是一个git config --global ... 命令,可以轻松地将其添加为git prune-branches

git config --global alias.prune-branches '!git remote prune origin && git branch -vv | grep '"'"': gone]'"'"' | awk '"'"'{print $1}'"'"' | xargs -r git branch -d'

注意:正如Matteo 在他之前对另一个答案的评论中指出的那样,将-D 标志用于git branch 可能非常危险。所以,在配置命令中,我使用-d 选项来git branch 而不是-D;我在实际配置中使用-D。我使用-D 是因为我不想听到 Git 抱怨未合并的分支,我只想让它们消失。您可能也需要此功能。如果是这样,只需在该配置命令的末尾使用-D 而不是-d

【讨论】:

    【解决方案6】:

    您可以通过迭代 refs 来做到这一点,我使用以下命令删除所有没有远程分支的本地分支并且它有效。 警告:此操作会强制删除未完全合并的分支,请谨慎使用。

    git branch -D `git for-each-ref --format="%(fieldName)" refs/heads/<branch-name-pattern>`
    

    %(fieldName) = refname:short)

    refs/heads/ = 如果你在分支名称中有一个共同的前缀/后缀,则可以加上后缀 例如:refs/heads/*abc*

    更多信息请参考git-for-each-ref(1) Manual Page

    【讨论】:

    • 使用您的解决方案,您还将强制删除未完全合并的分支,非常危险!
    【解决方案7】:

    快速

    git fetch -p
    git branch -v | grep "\[gone\]"
    

    然后手动检查并删除输出中的分支。


    详细

    基于此线程中的答案以及here,最简单的手动解决方案是删除遥控器上不再存在的所有远程跟踪引用

    git fetch -p
    

    然后查看已从远程跟踪中删除但仍在本地工作树中的内容

    git branch -v
    

    并手动删除输出中包含[gone] 的分支。

    为了得到一个简洁的列表运行

    git branch -v | grep "\[gone\]"
    

    【讨论】:

      【解决方案8】:

      首先,做:

      git fetch &amp;&amp; git remote prune origin

      然后:

      git branch -a | grep -v ${$(git branch -a | grep remotes | cut -d/" -f3-)/#/-e} | xargs git branch -D

      • 列出所有没有远程/源前缀的远程:git branch -a | grep remotes | cut -d'/' -f3-
      • 从 git 中删除所有列表:git branch -a | grep v ${&lt;all remotes without prefix&gt;/#/-e}
      • 从本地需求中删除-D,因为不必将所有内容都标记为已合并。例如,Github 中的 squash 和 merge 不会将它们标记为已合并。

      【讨论】:

      • 我收到了pipe braceparam cmdsubst pipe pipe dquote&gt;,但不知道它是什么意思。
      猜你喜欢
      • 2016-07-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-09-29
      • 2011-12-05
      相关资源
      最近更新 更多