清理Git中的冗余分支

4
这是情景:有人在git存储库(如果相关的话,可以在github上)中,我已经复刻了这个存储库。在我的分支中,我创建了许多带有变更的分支,这些变更已被上游拉取或者在某些情况下应用了我的分支差异而没有正确地拉取该分支。
我想找到所有已完全合并到上游主分支中的分支列表。这样我就可以安全地删除这些分支,因为“git branch”和其他工具会列出30多个分支,看起来很混乱。
我认为我已经清楚地解释了为什么这个问题与链接中的问题不同:或者在某些情况下应用了我的分支差异而没有正确地拉取该分支 例如,“git branch --merged”并不是一个完整的答案,但无论如何...

1
投票重新开放,因为检测上游仓库(多个远程)中合并的分支是一个微妙但显著不同的问题 - 盲目应用于检测已经合并的分支的建议将删除例如 origin/master 如果它未被修改。 - AD7six
2个回答

5
根据您希望进行操作的频率,您可以选择手动执行(首先解释)或使用脚本执行(之后解释)。以下假设存在一个指向您复制的仓库的"上游(upstream)"远程。例如:
$ git remote -v
origin git@github.com:you/repo.git (fetch)
origin git@github.com:you/repo.git (push)
upstream git://github.com/original/repo.git (fetch)
upstream git://github.com/original/repo.git (push)

列出所有已合并的本地分支

要获取已经与上游主分支合并过的分支列表:

$ git fetch upstream
$ git branch --merged upstream/master
my-feature
my-other-feature
master

您可以随后删除它们:
$ git branch -d my-feature
$ git branch -d my-other-feature

如果更改是手动应用的,则可能不在上游历史记录中,因此具有等效代码更改的本地分支可能不会列出。需要手动检测这种情况的分支。
删除不存在的远程分支的本地引用
如果您有本地分支代表已经被删除的远程分支(分支是为拉取请求而创建的,在合并拉取请求后,通过github的gui删除了分支),则有一个标准的git命令来清理这些分支引用:
$ git remote prune origin

删除已合并的远程分支

要获取您的 fork 中已合并的远程分支列表,类似于第一个命令,但使用 -r 开关(远程分支):

$ git branch -r --merged upstream/master
origin/my-feature
origin/my-other-feature
upstream/someone-elses-branch

要删除已合并的自己的远程分支:

$ git push origin :my-feature
$ git push --delete origin my-other-feature # equivalent, just different syntax

脚本解决方案

使用脚本解决方案时要小心,因为很容易意外删除您不想删除的分支。但是请记住,分支只是引用/名称 - 意外删除分支并不意味着内容丢失,它们可以轻松恢复(例如,只需检查git reflog)。

下面的脚本将删除以“feature”开头的本地和远程分支 - 这是确保您自己的最新主分支不会被意外删除的一种方法。

#!/bin/bash
# E.g. save as ~/bin/git-cleanup, make executable and have ~/bin in your path
# call as `git cleanup`

echo -n "Fetching latest ... "
git fetch origin
git fetch upstream
echo "done"

echo "Deleting merged local feature branches ... "
branches=`git branch --no-color --merged upstream/master`
for branch in $branches;
do
    if [[ "$branch" =~ ^feature ]]; then
        git branch -d $branch;
    fi
done
echo "done"

echo "Deleting local refs to remote branches that don't exist ... "
git remote prune origin
git remote prune upstream
echo "done"

echo "Deleting merged remote feature and hotfix branches ... "
branches=`git branch -r --no-color --merged upstream/master`
for branch in $branches;
do
    if [[ "$branch" =~ ^(origin)\/(feature.*$) ]]; then
        remote=${BASH_REMATCH[1]};
        branch=${BASH_REMATCH[2]};
        git push $remote :$branch;
    fi
done

echo "done"

echo ""
echo "all finished"

1
当删除一个分支时,如果“意外”发生了,“git reflog”确实会派上用场。比我的回答更详细;) +1 - VonC
那么你的Git工作流程肯定有些问题 =)。 - AD7six
我知道,谢谢你提供脚本。但我认为它应该可以扩展到处理错误应用的分支,可能通过比较差异来实现。 - Björn Lindqvist
顺便说一句,我认为上游根本没有做错任何事情,问题在于 Git 太蠢了,如果你不使用 git merge --no-ff,它就无法创建一个正确的合并。快进合并不会列在 git branch --merged 中。 - Björn Lindqvist
好吧,老实说我不知道为什么“合并”的分支没有正确列出。但它们就是没有。也许使用了 git merge --squash,这似乎是一种“忘记”分支已合并的情况。 - Björn Lindqvist
显示剩余3条评论

1
如果您已经将您的分支与上游仓库(您派生的那个)的最新提交进行了更新,那么您可以按照 "如何删除所有已合并的 git 分支?" 进行操作。
git branch --merged | grep -v "\*" | xargs -n 1 git branch -d 

但那只会列出已合并的分支(例如通过拉取请求),而不是cherry-picking(仅将一个分支的差异应用于另一个分支)。
对于第二类,您可能需要比较这些本地分支,看看它们是否仍然具有尚未成为主要分支一部分的差异。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接