我git remote prune origin
可以删除不再位于远程的本地分支。
但我也想删除从这些远程分支创建的本地分支(检查它们是否未合并会很好)。
我怎样才能做到这一点?
修剪后,您可以使用git branch -r
. 可以使用 检索具有远程跟踪分支的分支列表git branch -vv
。因此,使用这两个列表,您可以找到不在远程列表中的远程跟踪分支。
这条线应该可以解决问题(需要bash
or zsh
,不适用于标准 Bourne shell):
git fetch -p ; git branch -r | awk '{print $1}' | egrep -v -f /dev/fd/0 <(git branch -vv | grep origin) | awk '{print $1}' | xargs git branch -d
此字符串获取远程分支列表并通过egrep
标准输入将其传递给。并过滤具有远程跟踪分支的分支(使用git branch -vv
并过滤具有远程跟踪分支的分支origin
),然后获取该输出的第一列,该列将是分支名称。最后将所有分支名称传递给删除分支命令。
由于它正在使用该-d
选项,因此在运行此命令时,它不会删除尚未合并到您所在分支的分支。
如果要删除所有已经合并到master的本地分支,可以使用如下命令:
git branch --merged master | grep -v '^[ *]*master$' | xargs git branch -d
如果您用main
作主分支,则应相应地修改命令:
git branch --merged main | grep -v '^[ *]*main$' | xargs git branch -d
更多信息。
在 提供的信息中git help fetch
,有一个小项目:
-p, --prune
After fetching, remove any remote-tracking branches which no longer exist on the remote.
所以,也许,git fetch -p
是你在找什么?
编辑:好的,对于那些在事实发生 3 年后仍在争论这个答案的人,这里有更多关于我为什么提出这个答案的信息......
首先,OP 说他们想“删除那些从那些远程分支创建的本地分支[不再在远程]”。这在git
. 这是一个例子。
假设我在中央服务器上有一个 repo,它有两个分支,称为A
和B
。如果我将该 repo 克隆到我的本地系统,我的克隆将有本地引用(还不是实际的分支)称为origin/A
and origin/B
。现在假设我执行以下操作:
git checkout -b A origin/A
git checkout -b Z origin/B
git checkout -b C <some hash>
这里的相关事实是,我出于某种原因选择在我的本地存储库上创建一个名称与其来源不同的分支,并且我还有一个本地分支(尚不存在于原始存储库中)。
现在假设我删除了远程仓库上的A
和B
分支并更新了我的本地仓库(git fetch
某种形式),这会导致我的本地 refsorigin/A
消失origin/B
。现在,我的本地仓库仍然有三个分支,A
,Z
和C
. 这些都没有远程仓库上的相应分支。其中两个是“从......远程分支创建的”,但即使我知道曾经有一个分支调用B
原点,我也无法知道它Z
是从B
,因为它在这个过程中被重命名,可能是有充分理由的。所以,真的,如果没有一些外部进程记录分支起源元数据,或者没有一个知道历史的人,就不可能分辨出三个分支中的哪一个,如果有的话,OP 的目标是删除。如果没有一些git
不会自动为您维护的外部信息,那么您git fetch -p
将尽可能接近,并且任何用于逐字尝试 OP 要求的自动方法都有删除太多分支或丢失 OP 否则会丢失的风险想删除。
还有其他场景,例如,如果我创建三个独立的分支origin/A
来测试对某事物的三种不同方法,然后origin/A
就离开了。现在我有三个分支,显然不能全部匹配名称,但它们是从创建的origin/A
,因此对 OPs 问题的字面解释需要删除所有三个。但是,这可能是不可取的,如果您甚至可以找到一种可靠的方法来匹配它们......
这将删除已修剪远程跟踪分支的本地分支。(确保你在master
分支上!)
git checkout master
git branch -vv | grep ': gone]' | awk '{print $1}' | xargs git branch -d
细节:
git branch -vv
远程已被修剪的本地分支显示“已消失”。
mybranch abc1234 [origin/mybranch: gone] commit comments
-d
将检查它是否已被合并(-D
无论如何都会删除它)
error: The branch 'mybranch' is not fully merged.
对于 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().Split(" ")[0]}
获取分支名称
% {git branch -d $_}
删除分支
可以将 Git 配置为在获取时自动删除对已删除远程分支的引用:
git config --global fetch.prune true
调用时git fetch
或git pull
之后,对已删除远程分支的引用会自动删除。
正如@tzacks 所指出的......有一个 npm 包可以方便地解决这个问题。做就是了:
npx git-removed-branches --prune
(我会评论但没有足够的声誉)
它将列出从远程删除其远程跟踪分支的本地分支
$ git remote prune origin --dry-run
如果您想从本地取消引用这些未跟踪的本地分支
$ git remote prune origin
更短、更安全的单线:
git branch -d $(git branch --merged | cut -c 3- | grep -v master)
在运行它之前,一定要检查到尚未合并的分支。因为您无法删除当前签入的分支。
如果使用 Windows 和 Powershell,您可以使用以下命令删除所有已合并到当前签出分支的本地分支:
git branch --merged | ? {$_[0] -ne '*'} | % {$_.trim()} | % {git branch -d $_}
解释
git
每个剩余分支名称的输出中的任何前导或尾随空格值得git branch --merged
首先单独运行,以确保它只会删除您期望的内容。
我想要一些可以清除所有跟踪远程分支的本地分支的东西,on origin
,远程分支已被删除(gone
)。我不想删除从未设置为跟踪远程分支的本地分支(即:我的本地开发分支)。另外,我想要一个简单的单行代码,只使用git
. 或其他简单的 CLI 工具,而不是编写自定义脚本。我最终使用了一点grep
andawk
来制作这个简单的命令,然后将它作为别名添加到我的~/.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'
注意:使用-D
标志git branch
可能非常危险。因此,在上面的配置命令中,我使用-d
选项 togit branch
而不是-D
; 我-D
在我的实际配置中使用。我使用-D
是因为我不想听到 Git 抱怨未合并的分支,我只想让它们消失。您可能也需要此功能。如果是这样,只需在该配置命令的末尾使用-D
而不是。-d
这是我的解决方案:
git fetch -p
git branch -vv | grep ": gone" | awk '{print $1}' | xargs git branch -d
-p是删除远程不再存在的任何远程跟踪引用。所以第一步将删除对远程分支的引用。
-vv用于显示每个头的 sha1 和提交主题行,以及与上游分支的关系(如果有)。第二步将获取所有本地分支,grep 命令将过滤掉已删除的分支。
似乎没有一个安全的单线,太多的边缘情况(比如一个分支有“master”作为它的名字的一部分,等等)。最安全的是这些步骤:
git branch -vv | grep 'gone]' > stale_branches.txt
awk '{print $1}' stale_branches.txt | xargs git branch -d
要删除远程分支:
$git remote prune origin
要删除已合并的本地分支:
$git branch -D $(git branch --merged)
在Powershell中:
git branch -D (git branch --merged |% { $_.trim() } )
根据上面的答案,我正在使用这个较短的一个班轮:
git remote prune origin | awk 'BEGIN{FS="origin/"};/pruned/{print $2}' | xargs -r git branch -d
此外,如果您已经修剪并有本地悬垂的分支,那么这将清理它们:
git branch -vv | awk '/^ .*gone/{print $1}' | xargs -r git branch -d
不确定如何一次完成所有操作,但git branch -d <branchname>
只有在完全合并后,git才会删除本地分支。注意小写d。
git branch -D <branchname>
(注意大写 D)将删除本地分支,无论其合并状态如何。
Schleis 的变体对我不起作用(Ubuntu 12.04),所以让我提出我的(清晰而闪亮的 :) 变体:
变体 1(我更喜欢这个选项):
git for-each-ref --format='%(refname:short) %(upstream)' refs/heads/ | awk '$2 !~/^refs\/remotes/' | xargs git branch -D
变体 2:
一种。试运行:
comm -23 <( git branch | grep -v "/" | grep -v "*" | sort ) <( git br -r | awk -F '/' '{print $2}' | sort ) | awk '{print "git branch -D " $1}'
湾。删除分支:
comm -23 <( git branch | grep -v "/" | grep -v "*" | sort ) <( git br -r | awk -F '/' '{print $2}' | sort ) | xargs git branch -D
你可以使用这个命令:
git branch --merged master | grep -v "\* master" | xargs -n 1 git branch -d
Git Clean:删除已经合并的分支,包括命令分解
根据上面的答案,我提出了这一行解决方案:
git remote prune origin; git branch -r | awk '{print $1}' | egrep -v -f /dev/fd/0 <(git branch -vv | grep origin) | awk '{print $1}' | xargs git branch -d
使用@wisbucky 答案的变体,我将以下内容作为别名添加到我的~/.gitconfig
文件中:
pruneitgood = "!f() { \
git remote prune origin; \
git branch -vv | perl -nae 'system(qw(git branch -d), $F[0]) if $F[3] eq q{gone]}'; \
}; f"
有了这个,一个简单的git pruneitgood
将清理合并后不再需要的本地和远程分支。
以下是对 Windows 用户的@wisbucky 答案的改编:
for /f "tokens=1" %i in ('git branch -vv ^| findstr ": gone]"') DO git branch %i -d
我使用 posh-git,不幸的是 PS 不喜欢裸for
,所以我创建了一个简单的 'ol 命令脚本,名为 PruneOrphanBranches.cmd:
@ECHO OFF
for /f "tokens=1" %%i in ('git branch -vv ^| findstr ": gone]"') DO CALL :ProcessBranch %%i %1
GOTO :EOF
:ProcessBranch
IF /I "%2%"=="-d" (
git branch %1 %2
) ELSE (
CALL :OutputMessage %1
)
GOTO :EOF
:OutputMessage
ECHO Will delete branch [%1]
GOTO :EOF
:EOF
不带参数调用它以查看列表,然后使用“-d”调用它以执行实际删除或“-D”用于未完全合并但无论如何要删除的任何分支。
Powershell 版本git branch --merged master | grep -v '^[ *]*master$' | xargs git branch -d
git branch --merged master | %{ if($_ -notmatch '\*.*master'){ git branch -d "$($_.Trim())" }}
当您在 master 分支上时,这将删除任何已合并到 master 中的本地分支。
git checkout master
换成。
这适用于我使用 git 2.21.0 - 它删除本地跟踪分支,这些分支合并到HEAD
我之前--set-upstream
推送的位置(我使用push.default=upstream
它是因为它最适用于多个遥控器),并且上游分支已被删除fetch --prune
(或隐式 iffetch.prune=true
在 git 配置中):
git branch -vv --merged | grep ': gone]' | awk '{print $1}' | xargs git branch -d
使用--merged
并-d
使其成为非常“安全”的删除。更激进的版本可能会放弃--merged
并使用-D
在 git bash 中尝试此操作,以获取和修剪对已删除分支的引用,然后修剪跟踪已删除分支的本地分支:
git fetch -p && git branch -d `git branch -vv | grep ': gone]' | awk '{print $1}' | xargs`
记得先签出一个不会被删除的分支,这样就不会阻止删除分支。
检查目标
for target in $(git branch | grep -Eiv "master|develop|branchYouWantToLive"); do echo $target; done
使用 for & 子命令运行
for target in $(git branch | grep -Eiv "master|develop|branchYouWantToLive"); do git branch -D $target; done
你可以扩展其他关于分支的工作。
我已经把接受的答案变成了一个健壮的脚本。您可以在我的 git-extensions 存储库中找到它。
$ git-prune --help
Remove old local branches that do not exist in <remote> any more.
With --test, only print which local branches would be deleted.
Usage: git-prune [-t|--test|-f|--force] <remote>
我到达此页面寻求“如何删除不再具有上游分支的本地签出分支”的答案
我也不关心本地分支是否已被合并,因为管道进入git branch -d
只会发出警告而不是删除未合并的本地分支。
git branch -a | grep origin | tr -s ' ' | cut -d '/' -f3 | egrep -v -f /dev/fd/0 <(git branch -a | grep -v origin) | grep branch_prefix_that_I_care_about | xargs git branch -d
# translation
# git branch -a | grep origin | tr -s ' ' | cut -d '/' -f3
## this finds all remote branch names minus the "remote/origin/" part
#
# <(git branch -a | grep -v origin)
## this finds all local branch names and redirects it into the previous command
#
# egrep -v -f /dev/fd/0 STUFF
## this is doing some weird magic that I'm grokking as "take the set difference from whatever was piped in"
#
#
# overall translation: (STUFF TO CONSIDER) | egrep magic <(STUFF TO REMOVE FROM CONSIDERATION) | do cool things with resulting stuff
当遥控器本身不再存在时,我在这里找不到有用的答案。我一直看到不再存在的遥控器分支,但没有找到删除它们的 git 命令。
我的解决方案是转到.git\refs\remotes
目录并直接删除不再相关的文件。文件结构非常容易理解。它与您看到的结构相同git branch -r
。
删除任何与 master 不是最新的分支
git co master && git branch | sed s/\*/\ / | xargs git branch -d 2> /dev/null
我很确定这git remote prune origin
就是你想要的。
你可以运行它git remote prune origin --dry-run
来看看它会做什么而不做任何改变。
使用图形用户界面?手动程序,但快速简便。
$ git gui
选择“分支 -> 删除”。您可以使用 ctrl-click (windows) 选择多个分支并删除所有分支。