列出并删除git分支但不需要克隆

18
for k in $(git branch -r --merged origin/master | cut -d" " -f 3); do
    echo $k
done

我有一份GIT项目列表,想要清理旧的分支,希望能够列出并删除所有合并到主分支(master)的分支。是否有一种方法可以在不克隆每个仓库到本地的情况下完成上述操作?


使用 git branch 命令查看分支,使用 git branch -d <branch_name> 命令删除分支。 - phunsukwangdu
1
我将使用 git branch -d branch_name 来删除分支。是的,我想知道是否有一种方法可以在没有本地仓库副本的情况下完成此操作。 - A.Jac
请参考此链接:https://dev59.com/h3I-5IYBdhLWcg3wI0p9,了解如何同时在本地和远程删除 Git 分支。 - phunsukwangdu
可能我没有解释清楚,但我需要的是一种列出已合并到主干的分支的方法(就像OP中的代码)而无需本地存储库的副本。 - A.Jac
2个回答

31
您需要使用 git ls-remote 命令:

NAME

git-ls-remote - List references in a remote repository

SYNOPSIS

git ls-remote [--heads] [--tags] [--refs] [--upload-pack=<exec>]
              [-q | --quiet] [--exit-code] [--get-url]
              [--symref] [<repository> [<refs>...]]

DESCRIPTION

Displays references available in a remote repository along with the associated commit IDs.

所以它的工作方式是:
% git ls-remote origin
af51dfb080728117d898e1d0a10e3fe01ed67063        HEAD
6a60cc68a2953f1a62b0dca641eb29509b5b6e8c        refs/heads/expdate-fix
af51dfb080728117d898e1d0a10e3fe01ed67063        refs/heads/master
4c42e43b4ccfd37074d115f6e9a694ddb8b70d55        refs/heads/redux
fd18a67bbc5cbf8aa6cda136afa4e5c20ed2d522        refs/heads/rest
7ad17cdf8b0dcd1a29a1795a363279fb3c76ac66        refs/tags/test.key
be0b2d6881902600fb3d6686c10d0a47f1e6751a        refs/tags/test.pub

要仅获取分支(头),您需要缩小refspec范围:

% git ls-remote origin 'refs/heads/*'
6a60cc68a2953f1a62b0dca641eb29509b5b6e8c        refs/heads/expdate-fix
af51dfb080728117d898e1d0a10e3fe01ed67063        refs/heads/master
4c42e43b4ccfd37074d115f6e9a694ddb8b70d55        refs/heads/redux
fd18a67bbc5cbf8aa6cda136afa4e5c20ed2d522        refs/heads/rest

现在您可以编写脚本来处理此输出,例如:
git ls-remote origin 'refs/heads/*' | while read sha ref; do
  # test if $sha is merged
done

要删除一个分支,你需要向它“推送空内容”,就像这样:
git push origin :refs/heads/feature-x

请注意冒号左侧的空字符串,它定义了要推送到右侧内容的内容。

因此,我们得到类似于以下内容:

#!/bin/sh
set -e -u
git ls-remote origin 'refs/heads/*' | while read sha ref; do
  # test if $sha is merged
  E=`git cat-file -t "$sha" 2>&1`
  test $? -ne 0 -a "${E#*git cat-file: *}" = "could not get object info" && continue
  git branch --merged "$sha" && printf ':%s\0' "$ref"
done | xargs -0 git push origin

请注意,我们使用printf shell内置来用ASCII NUL字符限定输出的引用名称,然后将-0传递给xargs以期望接收以NUL结尾的输入。这样我们就可以解决奇怪的ref名称(包含空格等)。
一些解释:
- 如果git cat-file -t <object_sha1_name>无法在本地存储库中找到具有指定SHA1名称的对象,则会退出非零退出代码并打印“fatal: git cat-file: could not get object info”到其stderr。 - 因此,为了测试远程ref指向的历史记录是否存在于本地存储库中,我们在它所指向的对象的SHA1名称上运行git cat-file -t,抓取该命令的组合输出,然后测试它是否以非零退出代码退出($? -ne 0),以及它的错误消息是否指示缺少对象(${VAR#PATTERN}从变量VAR的内容中删除与PATTERN匹配的前缀,并返回结果值)。 - 如果远程ref指向的历史记录不存在于本地存储库中,则根据定义不能将其合并到任何本地ref中,因此如果我们检测到这样的ref,则跳过使用git branch --merged进一步测试。

1
这正是我所需要的,我之前看过ls-remote,但不理解它。谢谢你。 - A.Jac
这里有一个大问题:除非你的代码库与远程代码库保持同步,否则 git branch --merged 命令将无法给出正确的答案。这意味着你最好先运行 git fetch 命令,然后再进行本地操作。 - torek
@torek,因此,如果git cat-file -t“$sha”出现错误(在这里,使用Git 2.11.1,它会显示“无法获取对象信息”,并以代码128退出),则表示由该$sha标识的引用未合并,因此不得从远程存储库中删除。 - kostix
我知道这是一个旧的回复,但我很困惑这实际上如何测试分支是否已合并到主分支?按照我的理解,这将检查远程分支是否存在于本地(即:比较ls-remotecat-file,以及哪些分支已经合并到远程分支名称git branch --merged)。然而,这并没有检查$sha是否已合并到master - Eric B.
@EricB.,严谨地说,在Git中你可以有浅克隆和嫁接历史,从技术上讲,可能在本地存储库中有一个分支,它在物理上不包含其完整的历史记录(没有提交对象和其他对象引用的树、blob和其他提交),但这种情况是边缘的,通常如果一个人知道这样的东西,他们应该不需要问最初的问题;因此,我做出了一个合理的假设,即感兴趣的本地存储库没有奇怪的设置 ;) - kostix
显示剩余3条评论

4

对于更多git知识的人可能可以详细解释,但今天我也遇到了相似的问题——我想删除多个仓库中的一个分支,但我不想在每个仓库中都克隆一次再删除这个分支。

事实证明,只要你在任何仓库中,git允许你删除另一个仓库中的分支。我不确定是否存在限制,例如它们必须指向同一个GitHub服务器等。

但是这对我有效:

cd to a repo dir you do not want to remove
git push git@server:path_to_repo.git :branch_you_want_to_delete

如果你仔细想一想,这实际上与以下内容相同:

git push origin :branch_you_want_delete

除非您将引用源替换为显式路径


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