是否有一种简单的方法可以删除远程等效不再存在的所有跟踪分支?
例:
分支机构(本地和远程)
-
大师
-
origin / master
-
origin / bug-fix-a
-
origin / bug-fix-b
-
origin / bug-fix-c
在本地,我只有一个主分支 . 现在我需要处理bug-fix-a,所以我检查它,处理它,并将更改推送到远程 . 接下来我用bug-fix-b做同样的事情 .
分支机构(本地和远程)
-
大师
-
bug-fix-a
-
bug-fix-b
-
origin / master
-
origin / bug-fix-a
-
origin / bug-fix-b
-
origin / bug-fix-c
现在我有本地分支机构master,bug-fix-a,bug-fix-b . Master分支维护者将我的更改合并到master中并删除他已经合并的所有分支 .
那么现在的状态是:
分支机构(本地和远程)
-
大师
-
bug-fix-a
-
bug-fix-b
-
origin / master
-
origin / bug-fix-c
现在我想调用一些命令删除分支(在本例中为bug-fix-a,bug-fix-b),这些分支不再在远程存储库中表示 .
它将类似于现有命令 git remote prune origin
,但更像是 git local prune origin
.
26 回答
git remote prune origin
prunes跟踪分支机构不在遥控器上 .git branch --merged
列出已合并到当前分支的分支 .xargs git branch -d
删除标准输入上列出的分支 .小心删除
git branch --merged
列出的分支 . 该列表可能包含master
或您不想删除的其他分支 .要在删除分支之前给自己编辑列表的机会,可以在一行中执行以下操作:
git branch --merged >/tmp/merged-branches && vi /tmp/merged-branches && xargs git branch -d </tmp/merged-branches
命令之后
运行时删除远程引用
它将显示为“已离开”作为远程状态 . 例如,
所以你可以编写一个简单的脚本来删除已经远程的本地分支:
在大多数其他解决方案中,"gone"的模式匹配对我来说有点吓人 . 为了更安全,它使用
--format
标志来提取每个分支的上游跟踪状态 .我需要一个Windows友好版本,因此这将使用Powershell删除列为“已消失”的所有分支:
第一行列出了上游分支“已消失”的本地分支的名称 . 下一行删除空白行(对于未“消失”的分支输出),然后将分支名称传递给命令以删除分支 .
这些答案中的大多数实际上并未回答原始问题 . 我做了一堆挖掘,this是我找到的最干净的解决方案 . 这是一个稍微更全面的答案:
查看您的默认分支 . 通常
git checkout master
运行
git fetch -p && git branch -vv | awk '/: gone]/{print $1}' | xargs git branch -d
Explanation:
通过修剪跟踪分支然后删除显示在
git branch -vv
中的"gone"的本地分支来工作 .Notes:
如果您的语言设置为英语以外的其他语言,则需要将
gone
更改为相应的单词 . 不会触及仅限本地的分支 . 已在远程删除但未合并的分支将显示通知但不会在本地删除 . 如果要删除它们,请将-d
更改为-D
.我通常不回答已经有16个答案的问题,但所有其他答案都是错误的,正确的答案是如此简单 . 问题是,“是否有一种简单的方法可以删除远程等效不再存在的所有跟踪分支?”
如果“简单”意味着不脆弱,不危险,并且不依赖于并非所有读者都会拥有的工具,那么正确答案是:不 .
有些答案很简单,但他们没有按照要求做 . 其他人做了所要求的,但并不简单:所有人都依赖于通过文本操作命令或脚本语言解析Git输出,这些语言可能不会出现在每个系统上 . 最重要的是,大多数建议使用瓷器命令,其输出不是设计为由脚本解析(“瓷器”是指用于人工操作的命令;脚本应使用较低级别的“管道”命令) .
进一步阅读:
tracking branches and the differences between git remote prune, git prune, git fetch --prune
why you shouldn't parse git branch output in a script .
如果你想安全地做到这一点,对于问题中的用例(垃圾收集跟踪分支已经在服务器上删除但仍然作为本地分支存在)和仅使用高级Git命令,你必须
git fetch --prune
(或git fetch -p
,这是别名,或git prune remote origin
,它在没有提取的情况下执行相同的操作,并且可能不是您想要的大部分时间) .注意报告为已删除的任何远程分支 . 或者,稍后查找它们,
git branch -v
(任何孤立的跟踪分支都将标记为"[gone]") .每个孤立的跟踪分支上的
git branch -d [branch_name]
如果你想编写一个解决方案的脚本,那么
for-each-ref
就是你的起点,就像Mark Longair's answer这里和this answer to another question一样,但是我没有办法在没有编写shell脚本循环或使用xargs之类的情况下利用它 .背景说明
要了解正在发生的事情,您需要了解的是,在跟踪分支的情况下,您没有一个分支,而是三个分支 . (并且回想一下“分支”仅仅意味着指向提交的指针 . )
给定跟踪分支
feature/X
,远程存储库(服务器)将具有此分支并将其命名为feature/X
. 您的本地存储库有一个分支remotes/origin/feature/X
,这意味着"This is what the remote told me its feature/X branch was, last time we talked,",最后,本地存储库有一个分支feature/X
,它指向您的最新提交,并配置为"track"remotes/origin/feature/X
,意思是你可以拉动并推动它们保持对齐 .在某些时候,有人删除了遥控器上的
feature/X
. 从那一刻开始,你留下你的本地feature/X
(你可能不再需要了,因为功能X上的工作可能已经完成了),你的remotes/origin/feature/X
肯定是无用的,因为它的唯一目的是记住状态服务器的分支 .并且Git会让你自动清理多余的
remotes/origin/feature/X
- 这就是git fetch --prune
所做的 - 但由于某种原因,它不会让你自动删除自己的feature/X
......即使你的feature/X
仍然包含孤立的跟踪信息,所以它具有识别已完全合并的以前跟踪分支的信息 . (毕竟,它可以为您提供让您自己手动操作的信息 . )似乎解决方案在这里 - https://stackoverflow.com/a/1072178/133986
简而言之,
git remote prune
就是神奇的我在这里找到了答案:How can I delete all git branches which have been merged?
确保我们保持主人
您可以通过在第一个之后添加另一个
grep
来确保不会删除master
或任何其他分支 . 在那种情况下你会去:因此,如果我们想保留
master
,develop
和staging
,我们会去:将其设为别名
由于它有点长,您可能想要为
.zshrc
或.bashrc
添加别名 . 我叫gbpurge
(git branches purge
):然后重新加载
.bashrc
或.zshrc
:要么
删除已合并为master的所有分支,但不要尝试删除master本身:
git checkout master && git pull origin master && git fetch -p && git branch -d $(git branch --merged | grep master -v)
或添加别名:
alias gitcleanlocal="git checkout master && git pull origin master && git fetch -p && git branch -d $(git branch --merged | grep master -v)"
说明:
git checkout master
结帐主分行git pull origin master
确保本地分支已合并所有远程更改git fetch -p
删除对已删除的远程分支的引用git branch -d $(git branch master --merged | grep master -v)
删除已合并为master的所有分支,但不要尝试删除master本身这将删除未远程跟踪的所有分支 .
Windows解决方案
对于Microsoft Windows Powershell:
git checkout master; git remote update origin --prune; git branch -vv | Select-String -Pattern ": gone]" | % { $_.toString().Trim().Split(" ")[0]} | % {git branch -d $_}
解释
git checkout master
切换到主分支git remote update origin --prune
修剪远程分支git branch -vv
获取所有分支的详细输出(git reference)Select-String -Pattern ": gone]"
仅获取已从远程删除的记录 .% { $_.toString().Trim().Split(" ")[0]}
获取分支名称% {git branch -d $_}
删除分支我认为没有内置命令可以执行此操作,但执行以下操作是安全的:
当您使用
-d
时,git将拒绝删除分支,除非它完全合并到HEAD
或其上游远程跟踪分支 . 因此,您可以始终循环git for-each-ref
的输出并尝试删除每个分支 . 这种方法的问题是我怀疑你可能不希望bug-fix-d
被删除只是因为origin/bug-fix-d
包含它的历史 . 相反,您可以创建类似以下内容的脚本:警告:我没有测试过这个脚本 - 只能小心使用...
这将删除除本地主引用和当前正在使用的引用之外的所有合并本地分支:
这将删除已从“origin ", but are still locally available in " remotes / origin”引用的远程存储库中删除的所有分支 .
可能对某些简单的一行有用,可以清除除master和develop之外的所有本地分支
根据上面的信息,这对我有用:
它会删除远程
': gone] '
的所有本地分支 .还有另一个答案,从https://stackoverflow.com/a/48411554/2858703(我喜欢它,因为它似乎消除了
gone]
将在git branch
输出中匹配的任何模糊性),但添加* nix弯曲:我把这个包裹在我路径上的
git-gone
脚本中:NB - --format选项似乎相当新;我需要将git从2.10.something升级到2.16.3才能获得它 .
上面的命令可用于获取在远程中合并和删除的分支,并删除远程不再可用的本地分支
这些都不适合我 . 我想要一些东西可以清除跟踪远程分支的所有本地分支,在
origin
上,远程分支已被删除(gone
) . 我不想删除从未设置过跟踪远程分支的本地分支(即:我的本地开发分支) . 此外,我想要一个简单的单行程序,只使用git
或其他简单的CLI工具,而不是编写自定义脚本 . 我最终使用了一些grep
和awk
来制作这个简单的命令 .这最终导致了我的
~/.gitconfig
:这是一个
git config --global ...
命令,可以轻松地将其添加为git prune-branches
:注意:在config命令中,我使用
-d
选项来git branch
而不是-D
,就像我在实际配置中一样 . 我使用-D
因为我不想听到Git抱怨未合并的分支 . 您可能也想要这个功能 . 如果是这样,只需在该config命令的末尾使用-D
而不是-d
.我想出了这个bash脚本 . 它总是保留分支
develop
,qa
,master
.这对我有用:
我不确定多久,但我现在使用git-up来处理这个问题 .
我做
git up
并开始跟踪新分支并删除旧分支 .为了说清楚,它不是开箱即用的git命令 - https://github.com/aanand/git-up
顺便说一句,它还存放了肮脏的树,并且只使用
git up
进行了折扣 .希望它对某人有用
这是我用于鱼壳的解决方案 . 在
Mac OS X 10.11.5
,fish 2.3.0
和git 2.8.3
上测试过 .几点说明:
确保设置正确的
base_branch
. 在这种情况下,我使用develop
作为基本分支,但它可以是任何东西 .这部分非常重要:
grep -v "\(master\|$base_branch\|\*\)"
. 它确保您不删除主分支或基本分支 .我使用
git branch -d <branch>
作为额外的预防措施,以便不删除任何尚未与上游或当前HEAD完全合并的分支 .一种简单的测试方法是将
git branch -d $f
替换为echo "will delete $f"
.我想我还应该补充一点:使用自己的风险!
我用一个简短的方法来做这个伎俩,我建议你做同样的事情,因为它可以节省一些时间,并提供更多的可见性
只需将以下代码段添加到.bashrc(macos上的.bashprofile)即可 .
您必须编辑grep正则表达式才能满足您的需求(这里,它会阻止master,preprod和dmz的删除)
基于Git Tip: Deleting Old Local Branches,看起来类似于jason.rickman's solution我使用Bash实现了一个名为git gone的自定义命令:
git gone -pn
结合了修剪和列出"gone"分支:然后,您可以使用
git gone -d
或git gone -D
来触发触发器 .注意事项
我使用的正则表达式是
"$BRANCH/.*: gone]"
,其中$BRANCH
通常是origin
. 如果您的Git输出已本地化为法语等,这可能不起作用 .Sebastian Wiesner也将它移植到Rust用户身上 . 那个也被称为git gone .
只需再次删除项目和git clone .
这将删除本地不存在的所有远程分支(在ruby中):
解释:
我使用这种方法,所以我可以有更多的控制权 .
git branch -D $(git branch | grep -v "master" | grep -v "develop")
这将删除任何未命名的分支:
master
或develop
.