使用git远程修剪原点,我可以删除不在远程上的本地分支。

但是我还想删除从这些远程分支创建的本地分支(检查它们是否未合并会很好)。

我该怎么做呢?


不知道如何一次性完成,但是git git branch -d <branchname>只会在完全合并的情况下删除本地分支。注意小写的d。

git branch -D <branchname>(注意大写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帮助获取提供的信息中,有这样一个小项目:

 -p, --prune
        After fetching, remove any remote-tracking branches which no longer exist on the remote.

也许,git fetch -p是你要找的?

编辑:好吧,对于那些3年后还在争论这个答案的人,这里有一些关于我为什么给出这个答案的更多信息……

首先,OP说他们想“删除那些从远程分支创建的本地分支(这些分支不在远程上了)”。这在git中并不是完全可能的。举个例子。

假设我在中央服务器上有一个回购,它有两个分支,称为a和B。如果我将该回购克隆到我的本地系统,我的克隆将有本地引用(还不是实际的分支)称为origin/ a和origin/B。现在假设我做了以下事情:

git checkout -b A origin/A
git checkout -b Z origin/B
git checkout -b C <some hash>

这里的相关事实是,出于某种原因,我选择在我的本地回购上创建一个分支,该分支的名称与其起源不同,并且我还有一个本地分支,它(还)不存在于起源回购上。

Now let's say I remove both the A and B branches on the remote repo and update my local repo (git fetch of some form), which causes my local refs origin/A and origin/B to disappear. Now, my local repo has three branches still, A, Z, and C. None of these have a corresponding branch on the remote repo. Two of them were "created from ... remote branches", but even if I know that there used to be a branch called B on the origin, I have no way to know that Z was created from B, because it was renamed in the process, probably for a good reason. So, really, without some external process recording branch origin metadata, or a human who knows the history, it is impossible to tell which of the three branches, if any, the OP is targeting for removal. Without some external information that git does not automatically maintain for you, git fetch -p is about as close as you can get, and any automatic method for literally attempting what the OP asked runs the risk of either deleting too many branches, or missing some that the OP would otherwise want deleted.

还有其他的场景,比如,如果我在origin/A之外创建三个独立的分支,以测试三种不同的方法,然后origin/A消失了。现在我有三个分支,它们显然不能全部匹配名称,但它们是从origin/A创建的,因此OPs问题的字面解释需要删除所有三个分支。然而,如果你能找到一种可靠的方法来匹配它们,这可能并不理想……


修剪完成后,你可以使用git branch -r获取远程分支的列表。带有远程跟踪分支的分支列表可以使用git branch -vv检索。因此,使用这两个列表,您可以找到不在远程列表中的远程跟踪分支。

这一行应该做的把戏(需要bash或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的分支),然后获得输出的第一列,这将是分支名称。最后将所有分支名称传递给delete branch命令。

由于它使用的是-d选项,所以在运行此命令时,它不会删除尚未合并到您所在分支中的分支。


我很确定git remote prune origin是你想要的。

你可以运行它作为git远程剪枝起源-演练,看看它会做什么不做任何改变。


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}'

b.移除分支:

comm -23 <( git branch | grep -v "/" | grep -v "*" | sort ) <( git br -r | awk -F '/' '{print $2}' | sort ) | xargs git branch -D

删除所有没有更新到master的分支

git co master && git branch | sed s/\*/\ / | xargs git branch -d 2> /dev/null

使用GUI?手动操作,但快捷方便。

$ git gui

选择“分支->删除”。您可以使用ctrl-click(窗口)选择多个分支并删除它们。


这将删除已修剪远程跟踪分支的本地分支。(确保你在主分支上!)

git checkout master
git branch -vv | grep ': gone]' | awk '{print $1}' | xargs git branch -d

细节:

Git branch -vv对于远程已修剪的本地分支显示“gone”。 Mybranch abc1234 [origin/ Mybranch: gone]提交注释 -d将检查它是否已合并(-d将删除它) 错误:分支“mybranch”没有完全合并。


更短更安全的一行代码:

git branch -d $(git branch --merged | cut -c 3- | grep -v master)

在运行分支之前,请确保签出到尚未合并的分支。因为您不能删除当前签入的分支。


基于以上的答案,我想出了这个简单的解决方案:

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

它将列出远程跟踪分支从remote中删除的本地分支

$ git remote prune origin --dry-run

如果你想从未被跟踪的本地去引用这些本地分支

$ git remote prune origin

我已经把公认的答案变成了一个健壮的脚本。您可以在我的git-extensions存储库中找到它。

$ git-rprune --help
Remove old local branches that do not exist in REMOTE any more.
With --test, only print which local branches would be deleted.
Note: To do this automatically on each fetch / pull:
    git config --global fetch.prune true
Usage: git-rprune REMOTE [-t|--test|-f|--force] [-?|-h|--help]

使用@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就可以清理合并后不再需要的本地和远程分支。


以下是@wisbucky对Windows用户的回答:

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”。


尝试在git bash中,获取并修剪对已删除分支的引用,然后修剪跟踪已删除分支的本地分支:

git fetch -p && git branch -d `git branch -vv | grep ': gone]' | awk '{print $1}' | xargs`

记住先签出一个不会被删除的分支,这样就不会阻止该分支的删除。


可以配置Git在获取时自动删除对已删除的远程分支的引用:

git config --global fetch.prune true

当调用git fetch或git pull之后,对已删除的远程分支的引用将自动删除。


如果使用Windows和Powershell,您可以使用以下命令删除已合并到当前签出的分支中的所有本地分支:

git branch --merged | ? {$_[0] -ne '*'} | % {$_.trim()} | % {git branch -d $_}

解释

列出当前分支和已合并到其中的分支 过滤掉当前分支 清除git输出中每个剩余分支名称的前导或尾随空格 删除合并的本地分支

值得先运行git分支——自行合并,以确保它只会删除你希望它删除的东西。

(从http://railsware.com/blog/2014/08/11/git-housekeeping-tutorial-clean-up-outdated-branches-in-local-and-remote-repositories/移植/自动化。)


有一个整洁的npm包可以为你做这件事(它应该可以跨平台工作)。

使用npm Install -g git-removed-branches安装它

然后git remove -branches会显示所有过时的本地分支,然后git remove -branches -prune会删除它们。

更多信息请点击这里。


I wanted something that would purge all local branches that were tracking a remote branch, on origin, where the remote branch has been deleted (gone). I did not want to delete local branches that were never set up to track a remote branch (i.e.: my local dev branches). Also, I wanted a simple one-liner that just uses git, or other simple CLI tools, rather than writing custom scripts. I ended up using a bit of grep and awk to make this simple command, then added it as an alias in my ~/.gitconfig.

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

这是一个git配置-全局…命令可以方便地将其添加为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'

注意:对git分支使用-D标志可能非常危险。所以,在上面的config命令中,我使用-d选项来git分支而不是-d;我在实际配置中使用-D。我使用-D是因为我不想听到Git抱怨未合并的分支,我只是想让它们消失。您可能也需要这个功能。如果是这样,只需在配置命令的末尾使用-D而不是-D。


Windows的解决方案

适用于Microsoft Windows Powershell:

Git结帐大师;Git远程更新源——prune;git branch -vv | Select-String -Pattern ": gone]" | % {$_.toString(). trim()。Split(" ")[0]} | % {git branch -d $_}

解释

Git签出主切换到主分支

Git远程更新来源——修剪远程分支

Git分支-vv获取所有分支的详细输出(Git引用)

Select-String -Pattern ": gone]"只获取已从远程删除的记录。

% {$_.toString()。Split(" ")[0]}获取分支名称

% {git branch -d $_}删除分支


您可以使用该命令:

git branch --merged master | grep -v "\* master" | xargs -n 1 git branch -d

Git清洁:删除已经合并的分支,包括分解命令


git分支的Powershell版本——merged master | grep -v '^[*]*master$' | xargs git branch -d

git分支——合并主| % {if ($ _ -notmatch \ *。*主){git分支- d " $(美元_.Trim())”}}

当您在主分支上时,这将删除已合并到主分支中的任何本地分支。

Git检查主切换。


基于上面的答案,我使用了更短的一行:

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

似乎没有一个安全的一行代码,有太多的边缘情况(比如分支的名称中有“master”,等等)。最安全的是以下步骤:

Git分支-vv | grep 'gone]' > stale_branches.txt 查看文件并删除想要保留的分支(例如主分支!);您不需要编辑任何一行的内容 Awk '{print $1}' stale_branches.txt | xargs git branch -d


我到达这个页面,寻求“如何删除不再有上游分支的本地签出分支”的答案。

我也不关心本地分支是否已经被合并,因为管道到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 remote prune origin

删除已合并的本地分支。

$git branch -D $(git branch --merged)

正如@tzacks所说…有一个NPM包非常方便。只做:

npx git-removed-branches --prune

(我本想评论一下,但名声不够好)


Powershell:

git branch -D (git branch --merged |% { $_.trim() } )

以下是我的解决方案:

git fetch -p
git branch -vv | grep ": gone" | awk '{print $1}' | xargs git branch -d

-p用于删除远程上不再存在的任何远程跟踪引用。因此,第一步将删除对远程分支的引用。 -vv用于显示每个head的sha1和commit主题行,以及与上游分支的关系(如果有的话)。第二步将获取所有本地分支,grep命令将过滤掉已删除的分支。


这适用于我使用git 2.21.0 -它删除本地跟踪分支,这些分支合并到HEAD中,我之前在push上—set-upstream(我使用push.default=upstream,因为它最适合多个远程),并且上游分支已经被fetch—prune(或隐式地如果fetch。修剪=true在git配置):

git branch -vv --merged | grep ': gone]' | awk '{print $1}' | xargs git branch -d

-merged和-d的使用使得这是一个非常“安全”的删除。更激进的版本可以放弃-merged并使用-D


当遥控器本身不再存在时,我没有发现这里的答案有用。 我一直看到不存在的遥控器分支,但没有找到一个git命令来删除它们。

对我来说,解决方案是转到.git\refs\remotes目录,直接删除不再相关的文件。文件结构很容易理解。它与git branch -r的结构相同。


检查目标

$(git分支| grep -Eiv“master|develop|branchYouWantToLive”);执行echo $target;完成

使用for &子命令运行

$(git分支| grep -Eiv“master|develop|branchYouWantToLive”);做git分支-D $target;完成

你可以扩展其他关于分支的东西。


除了Schleis的答案(它工作得很完美),它还可以集成到Visual Studio中,所以在VS中打开git repo时修剪本地分支非常简单。

您可以使用外部工具功能调用sh.exe (git bash)与特定的目录和命令。它位于工具>外部工具菜单选项中(在VS 2022 17.1.0中)。我使用的参数如下:

命令:{Path-To-Git-Installation-Location} \ bin \ sh.exe

参数:——cd=$(SolutionDir) -c "git fetch -p;Git branch -r | awk '{print $1}' | egrep -v -f /dev/ fg /0 <(Git branch -vv | grep origin) | awk '{print $1}' | xargs Git branch -d"

初始目录:$(SolutionDir)

Git修剪本地分支的截图

值得注意的是,只有当你在VS中打开的解决方案在git repo目录中时,这才会起作用。

最后提醒-这可以通过Visual Studio的按键绑定用户界面在设置>通用>键盘和搜索工具进行按键绑定。ExternalCommand[n],其中n是外部命令表中的位置,您有这个外部工具的位置(它们可以在工具>外部工具对话框中重新排序)。请看下面的截图。

键盘绑定外部工具命令


这个命令和下面的脚本可以在Linux和Windows中使用Git Bash (MinGW)。

最好使用git的内部命令,这样注释或名称就不会意外地匹配并删除您不想删除的分支。git for-each-ref的格式选项可以使用许多内部“原子”来输出所需的信息。这样,我们就不必依赖管道连接到awk或grep来检查输出中的正则表达式,因为它可能包含不必要的信息。

下面的命令只使用git for-each-ref的内部低级命令来列出孤立的本地分支。一旦你有了这些,你可以管道到git分支-D。此外,别忘了先修剪和获取远程引用,否则它将找不到任何匹配:

git fetch -p
git for-each-ref --format '%(if:equals=[gone])%(upstream:track)%(then)%(refname:short)%(end)' 'refs/heads/**' | xargs -r git branch -D

以下是分类:

Git fetch -p -删除已删除的引用,并从远程获取新的引用

Git for-each-ref——format -列出使用特定输出格式的所有引用。

%(if: = =[gone])%(upstream:track) -仅在上游跟踪分支“[gone]”时输出。

%(then)%(refname:short)%(end) -输出分支名称(当跟踪消失时)。

Refs /heads/** -限制头部引用(为了提高效率)。

| xargs -r git分支- d管道输出作为参数删除。-r表示忽略空白输入。


就其本身而言,这个解很长,很难输入,也很难记住。幸运的是,向git添加自定义命令很容易。下面的脚本使用了上面的相同命令,但是它允许用户使用——dry-run选项查看将选择哪些分支。

我将我的文件命名为git-prune-local,并将其放在包含在PATH中的文件夹中。它还需要执行权限(chmod 755 git-prune-local)。

Git自动查找可执行文件,如Git -[command]。这样,你只需要输入git prune-local来删除正确的分支。

git-prune-local

#!/bin/sh

if [ $# -gt 1 ] || ([ ! -z $1 ] && [ $1 != "--dry-run" ])
then
    echo "Usage: git prune-local [--dry-run]"
    exit
fi

git fetch -p --quiet
branchesToDelete=$(git for-each-ref --format '%(if:equals=[gone])%(upstream:track)%(then)%(refname:short)%(end)' 'refs/heads/**')

while read -r branch
do
    if [ ! -z $branch ]
    then
        if [ ! -z $1 ]
        then
            echo $branch
        else
            git branch -D $branch
        fi
    fi
done <<< "$branchesToDelete"

虽然迟到了,但是你可以使用——no-contains选项来避免在使用branch -merged时删除你的主分支

git branch --no-contains master --merged master | xargs git branch -d

你可以通过一些简单的操作来做到这一点:

输出你所有的分支到一个临时文件:

git branch > branches.tmp

打开文件并删除分支以排除它们从本地删除(分支如develop/master/main/…) 通过cat命令将分支名称传递给xargs并删除分支:

cat branches.tmp | xargs git branch -D

在OS X上,支持cut -w

git branch -d $(git branch -vv | grep ': gone]' | cut -w -f 2 )

解释

删除以下分支

git branch -d ...

显示移除的分支

$ git branch -vv | grep ': gone]'
  chore/TECH-456   a4bdac8ac8 [origin/TECH-456: gone] chore: syntax error
  feature/TECH-678 0342f8e277 [origin/feature/TECH-678: gone] Added IsGross in new Income Details

保留分支名称

$ git branch -vv | grep ': gone]' | cut -w -f 2
chore/TECH-456
feature/TECH-678