清理旧的远程git分支


693

我在两台不同的计算机(A和B)上工作,并将一个通用的git远程存储在dropbox目录中。

假设我有两个分支,master和devel。两者都在跟踪其远程对方的原点/原点和原点/开发。

现在,在计算机A上,我删除本地和远程上的branch devel。

git push origin :heads/devel
git branch -d devel

git branch -a在计算机A上运行,我得到以下分支列表。

  • 来源/头
  • 起源/主人

git fetch在计算机B上运行,我可以使用删除本地devel分支git branch -d devel,但不能删除远程devel分支。

git push origin :heads/devel 返回以下错误消息。

错误:无法推送到不合格的目标:heads / proxy3d
目标refspec 既不匹配远程服务器上的现有ref,也不以refs /开头,我们无法根据源ref猜测前缀。
致命:远端意外挂断

git branch -a 仍在远程分支中列出起点/终点。

如何从计算机B清理远程分支?


4
曾经尝试过的人告诉我,Dropbox文件夹中的git存储库有些脆弱(但没有其他详细信息)。
托尔比约恩Ravn的安徒生

5
@ThorbjørnRavnAndersen可能是因为您必须等待确保每次提交时都完全同步,然后才能确保可以安全地在另一台计算机上使用(甚至需要再次同步)。
2013年

Answers:


1238

首先,git branch -a在机器B上的结果是什么?

其次,您已经在上删除heads/develorigin,因此这就是为什么您无法从计算机B删除它的原因。

尝试

git branch -r -d origin/devel

要么

git remote prune origin

要么

git fetch origin --prune

并随意添加--dry-rungit语句末尾以查看运行该语句的结果,而无需实际运行它。

git remote prune和的文档git branch


50
git remote prune origin为我工作=> * [pruned] origin/my-old-branch
Hari Karam Singh

126
git remote prune origin --dry-run向您显示实际删除的内容。
Wolfram Arnold

30
git fetch origin --prune是完美的去除删除分支
塞巴斯蒂安·巴比

10
如果您有一个本地分支机构跟踪已消失的远程站点,则不会删除任何内容。对于那些人来说,git branch -vv随后git branch -D branchname修剪是最好的方法。
罗曼·斯塔科夫

7
您可以通过设置以下选项将修剪配置为在拉取/获取时自动发生:git config remote.origin.prune true
Patrick James McDougle,2015年

99

考虑运行:

git fetch --prune

定期在每个存储库中删除一直在跟踪已删除的远程分支的本地分支(远程GIT存储库中不再存在)。

这可以通过进一步简化

git config remote.origin.prune true

per-repo设置将使将来git fetch or git pull有任何可能自动修剪

要为您的用户进行设置,您还可以编辑全局.gitconfig并添加

[fetch]
    prune = true

但是,建议使用以下命令完成此操作:

git config --global fetch.prune true

或将其应用到整个系统(不仅限于用户)

git config --system fetch.prune true

14

这是可以为您做的bash脚本。它是http://snippets.freerobby.com/post/491644841/remove-merged-branches-in-git脚本的修改版本。我的修改使它能够支持不同的远程位置。

#!/bin/bash

current_branch=$(git branch --no-color 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/\1/')
if [ "$current_branch" != "master" ]; then
  echo "WARNING: You are on branch $current_branch, NOT master."
fi
echo -e "Fetching merged branches...\n"

git remote update --prune
remote_branches=$(git branch -r --merged | grep -v '/master$' | grep -v "/$current_branch$")
local_branches=$(git branch --merged | grep -v 'master$' | grep -v "$current_branch$")
if [ -z "$remote_branches" ] && [ -z "$local_branches" ]; then
  echo "No existing branches have been merged into $current_branch."
else
  echo "This will remove the following branches:"
  if [ -n "$remote_branches" ]; then
echo "$remote_branches"
  fi
  if [ -n "$local_branches" ]; then
echo "$local_branches"
  fi
  read -p "Continue? (y/n): " -n 1 choice
  echo
  if [ "$choice" == "y" ] || [ "$choice" == "Y" ]; then
    remotes=`echo "$remote_branches" | sed 's/\(.*\)\/\(.*\)/\1/g' | sort -u`
# Remove remote branches
for remote in $remotes
do
        branches=`echo "$remote_branches" | grep "$remote/" | sed 's/\(.*\)\/\(.*\)/:\2 /g' | tr -d '\n'`
        git push $remote $branches 
done

# Remove local branches
git branch -d `git branch --merged | grep -v 'master$' | grep -v "$current_branch$" | sed 's/origin\///g' | tr -d '\n'`
  else
echo "No branches removed."
  fi
fi

1
这在名为“ origin / feature / mybranch”的分支上中断了,我不确定为什么。
Stavros Korokithakis 2014年

问题出在两个sed秒内。更换sed 's/\(.*\)\/\(.*\)/\1/g'sed 's/\([^/]*\)\/\(.*\)/\1/g'
伯努瓦Latinier

14

该命令将“空运行”删除origin除(master。您可以更改它,或者在master之后添加其他分支:grep -v for-example-your-branch-here |

git branch -r --merged | 
  grep origin | 
  grep -v '>' | 
  grep -v master | 
  xargs -L1 | 
  awk '{sub(/origin\//,"");print}'| 
  xargs git push origin --delete --dry-run

如果看起来不错,请删除--dry-run。此外,您可能想先在叉子上进行测试。


真好 我使用perl而不是第一个xargs + awk进行了调整:git branch -r --merged | grep来源| grep -v'>'| grep -v大师| perl -lpe'($ junk,$ _)= split(/ \ //,$ _,2)'| | | | | xargs git push origin --delete
Andrew

6

如果git branch -r显示了许多您不感兴趣的远程跟踪分支,并且您只想从本地删除它们,请使用以下命令:

git branch -r | grep -Ev 'HEAD|master|develop'  | xargs -r git branch -rd

一个更安全的版本是仅删除合并的版本:

git branch -r --merged | grep -Ev 'HEAD|master|develop'  | xargs -r git branch -rd

这对于大型项目可能很有用,在这些项目中您不需要其他队友的功能分支,但是在初始克隆中有很多远程跟踪分支。

但是,仅此步骤是不够的,因为那些删除的远程跟踪分支将再次出现git fetch

要停止获取这些远程跟踪分支,您需要在.git / config中显式指定要获取的引用:

[remote "origin"]
  # fetch = +refs/heads/*:refs/remotes/origin/*    ### don't fetch everything
  fetch = +refs/heads/master:refs/remotes/origin/master
  fetch = +refs/heads/develop:refs/remotes/origin/develop
  fetch = +refs/heads/release/*:refs/remotes/origin/release/*

在上面的例子中,我们只取masterdevelop释放分支机构,随时适应,因为你需要。


1
谢谢,第一个命令对我有用。您还可以仅使用提取一个分支,git fetch origin branchname或创建一个别名,例如ft = "!f() { git fetch origin $(git rev-parse --abbrev-ref HEAD);}; f"仅提取当前分支(我个人的最爱)。干杯。
GiovanyMoreno

也许是旧约,但-r标志是什么意思?我看到xargs有一个-R争论,但没有发现任何有关-r。我的意思是,从理论上讲,如果我没有记错的话xargs,即使没有,-r它也应该起作用。
Aldo'xoen'Giambelluca'1

我喜欢这个答案。一些注意事项(确实说明了明显的事实)。通过删除最后一个管道和最后一个命令,可以“预览”要删除的分支| xargs git branch -d。同样,通过从中删除-r选项(--remotes),git branch -d我们仅清除本地分支(考虑到默认情况下git branch无论如何都不显示远程分支,这可能就足够了)。
Aldo'xoen'Giambelluca'1

谢谢!这正是我所需要的。其他解决方案建议将修剪后的本地分支推送到远程也将其删除,但这在远程站点已被删除或不再存在时无济于事。这种方法删除了对我不再有权访问的远程分支的本地引用。
warningbug

@aldo,关于xargs -r--no-run-if-empty这是GNU扩展的意思,这是一个很好的解释
ryenus

4

删除始终是一项艰巨的任务,并且可能很危险!因此,首先执行以下命令以查看会发生什么:

git push --all --prune --dry-run

通过像上面那样操作,git将为您提供执行以下命令时将发生的情况的列表。

然后运行以下命令从远程存储库中删除不在本地存储库中的所有分支:

git push --all --prune

10
此命令似乎很危险...它设法删除了我想要的内容(并且至少无法使用以上四个答案)。但是它也删除了其他四个开发分支。Git绝对糟透了……
jww

2
这些分支机构一定不在您的本地。但是,一切并没有丢失。Git提交,Git reflog,然后git reset --hard <校验和>。您可以使用此字面量执行任何提交(也称为保存)和其他操作。分支只是一个标签,删除标签不会删除保存...它将永远具有校验和。让我知道我是否可以帮忙
Timothy LJ Stewart

3
当然,您将要很快恢复它们,因为git的垃圾收集器最终将删除分支未引用的提交。
安德鲁

1
最好-n在此命令中添加(空运行),以便您可以预览更改,然后,如果一切正常,请在不使用的情况下再次调用它-n
mati865 '16

1
同意@GuiWeinmann-这太危险了,尤其是在没有特定标注的情况下,至少要先空运行。
Vivek M. Chawla

2

这是使用SourceTree(v2.3.1)的方法:
1.单击访存
2.检查“修剪跟踪分支...”
3.按“确定”
4.😀

在此处输入图片说明


1

我将不得不在此处添加一个答案,因为其他答案或者没有涵盖我的情况,或者是不必要的复杂。我将github与其他开发人员一起使用,我只希望将所有远程已从github PR(可能已合并并)删除的本地分支从我的机器中一次性删除。不,像git branch -r --merged事情不会覆盖那些没有本地合并的分支,或者根本没有合并(废弃)的分支,等等,因此需要一个不同的解决方案。

无论如何,第一步我是从其他答案中得到的:

git fetch --prune

枯燥的 git remote prune origin在我的情况下,似乎可以实现相同的目的,因此我选择了最短的版本以使其简单。

现在,a git branch -v应该将其删除了远程的分支标记为[gone]。因此,我要做的就是:

git branch -v|grep \\[gone\\]|awk '{print $1}'|xargs -I{} git branch -D {}

如此简单,它删除了我在上述情况下想要的所有内容。

较不常用的xargs语法是,除了Linux外,它还可以在Mac和BSD上使用。小心,此命令不是空运行,因此它将强制删除所有标记为的分支[gone]。显然,这是git,一切永远不会消失,如果您看到删除的分支(记得要保留),则可以始终取消删除它们(上面的命令将在删除时列出它们的哈希值,所以很简单)git checkout -b <branch> <hash>


0
# First use prune --dry-run to filter+delete the local branches
git remote prune origin --dry-run \
  | grep origin/ \
  | sed 's,.*origin/,,g' \
  | xargs git branch -D

# Second delete the remote refs without --dry-run
git remote prune origin

从本地引用和远程引用中修剪相同的分支(在我的示例中为origin)。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.