从远程仓库获取最新的git标签而不需要克隆

79

如何从(未签出的)远程存储库中获取最后一个标签?

在我的本地副本中,我使用describe命令。

git describe --abbrev=0 --tags

但是我无法在远程存储中使用describe

7个回答

149

TL;DR

使用git ls-remote命令可以获取远程存储库的引用列表。

要查看最新版本,请查看输出的最后一行:

git -c 'versionsort.suffix=-' ls-remote --tags --sort='v:refname' <repository>

如果要仅输出使用语义化版本的存储库中的最新标签(例如在shell脚本中),请使用:

git -c 'versionsort.suffix=-' \
    ls-remote --exit-code --refs --sort='version:refname' --tags <repository> '*.*.*' \
    | tail --lines=1 \
    | cut --delimiter='/' --fields=3
对于没有--sort标志的旧版Git(v2.18之前),或者不支持versionsort.suffix(v2.4之前)的版本,请使用以下命令:
git ls-remote --refs --tags <repository> \
    | cut --delimiter='/' --fields=3     \
    | tr '-' '~'                         \
    | sort --version-sort                \
    | tail --lines=1
sort 的旧版本不具备 --version-sort 标记,因此本问题不在讨论范围内...

详细说明

仅限标签

使用 --tags 确保列表仅包含标签引用。

这将包括已引用和取消引用的标签。这意味着某些标签将在 refname 末尾带有 ^{}。(有关详细信息,请参见 StackOverflow 上的此问题)。

对于人类来说,这并不重要,但如果不想看到这些 ^{},请添加 --refs

排序

可以使用 --sort 对引用列表进行排序。

排序选项使用 git for-each-ref 相同的排序键。由于我们没有所有本地信息,因此并非所有选项都可用(例如与日期有关的排序键)。

我们想要基于 引用名称 使用 版本排序。为此,我们使用 version:refname 键。这也可以缩写为 v:refname

这将按升序排序版本,这意味着最新版本将是 最后一个

要反转列表,请在排序键前加上 ---sort='-v:refname'

预发行版排序

此时,版本排序 将把发行候选版(例如 v2.28.0-rc2放在它们应该排在前面的稳定版本之后。

自 v2.12 以来,我们可以使用配置标记告诉 Git 对具有特定字符后缀的 refnames 进行排序,在没有该字符后缀的引用之后: git -c 'versionsort.suffix=-'

要始终像这样使用 versionsort.suffix,可以全局设置:

git config --global 'versionsort.suffix' '-'
在版本 2.4 和版本 2.12 之间,该标志被称为 versionsort.prereleaseSuffix。 在旧版 Git 中进行排序有一个技巧:连字符 - 在空格 前排序,但波浪号 ~ 在空格后排序。因此,通过将破折号 - 替换为波浪号 ~,可以按正确的顺序排序。可以使用 tr '-' '~' 进行操作。 由于我们只关心除最后一行以外的所有输出内容,因此只需显示尾部:tail --lines=1。当然,如果列表按降序检索(使用 --sort='-v:refname'),则为:head --lines=1。 ls-remote 命令的输出还会输出引用哈希。
ada126bd28d66c8c8ff5966a52d63ce2c9e4d031        refs/tags/v2.28.0-rc0

要仅显示实际的标签(即引用名称),可以截掉行的第一部分:cut --delimiter='/' --fields=3

引用过滤器

最后需要注意的是,ls-remote可以使用筛选模式来显示与筛选模式匹配的引用。例如,对于语义化版本控制,我们可以使用:'*.*.*'。不符合该模式的任何内容都将不会被显示。

如果存储库始终使用v前缀的版本标签,则可以进一步缩小范围,如此'v*.*.*'

另一个例子是仅检索特定主版本的最新标签。例如,要仅查看存储库的版本2的标签,可以使用'v2.*'

请确保在筛选器周围使用引号,否则星号*会给您带来麻烦!

找不到引用

使用筛选器时,最好使用--exit-code标志。

这是因为Git将始终退出状态码0以表示已成功与远程存储库通信。

对于人类消费者来说,这没问题,因为您会在屏幕上看到是否找到了任何引用。

但是,如果在shell脚本中使用此代码,则可能会有问题。

当在远程存储库中找不到匹配的引用时,可以告诉Git使用状态码2。这是通过使用--exit-code标志完成的。

这样脚本将知道什么时候出错!

显然,如果未使用筛选器,则使用--exit-code没有太多意义。

时间来举个例子吧!

假设我们想知道Git的最新标签是什么。

我们将执行:

git ls-remote --sort='version:refname' --tags https://github.com/git/git.git

这会返回一个长列表,其中包含所有标签的顺序,如下所示(为了保持清晰,已截断)。

    ...

4c8bcdda4d6e4757caf876ddc401b5392e874e21        refs/tags/v2.28.0
ada126bd28d66c8c8ff5966a52d63ce2c9e4d031        refs/tags/v2.28.0-rc0
bd42bbe1a46c0fe486fc33e82969275e27e4dc19        refs/tags/v2.28.0-rc0^{}
49bfe36405d1631a303992cac5cc408980a0454e        refs/tags/v2.28.0-rc1
3ddac3d691c3633cd4d9a74c07e3b2301f546f77        refs/tags/v2.28.0-rc1^{}
84a0d5cc2107b83a791aa4034cc54874e1d50668        refs/tags/v2.28.0-rc2
b066807397fd55553f4910ede74839e319b661fd        refs/tags/v2.28.0-rc2^{}
47ae905ffb98cc4d4fd90083da6bc8dab55d9ecc        refs/tags/v2.28.0^{}

这告诉我们最新的标签是v2.28.0

另一个例子是全局设置versionsort.suffix,然后只获取最后一个标签:

git config --global 'versionsort.suffix' '-'

git ls-remote --refs --sort=':refname' --tags https://github.com/git/git.git \
    | tail --lines=1 | cut --delimiter='/' --fields=3

现在,让我们看看Git是否已经有了第3版!

$ git ls-remote --exit-code --refs --tags https://github.com/git/git.git 'v3.*'
$ echo $?
2 # nope, not yet

2
如何剥离除分支名称以外的所有内容? - kilianc
3
@Potherca 我做到了!| awk -F/ '{ print $3 }' - kilianc
4
为什么所有标签名称都在末尾添加^{}后缀重复显示? - Michael Knudsen
2
@MichaelKnudsen ^{}是用于取消引用标签的语法。更多信息可以在StackOverflow的以下问题中找到:https://dev59.com/T2Up5IYBdhLWcg3wJlEH https://dev59.com/pmcs5IYBdhLWcg3wVyel - Potherca
1
在排序字段前加上“-”将会反转顺序,例如 --sort="-version:refname" - Nigel Thorne
显示剩余3条评论

35
自从版本2.18git已经有了一个内置的--sort选项,专门用于对引用名称进行排序。
因此,最新的命令将是:
git ls-remote --tags --sort="v:refname" git://github.com/git/git.git | tail -n1

为了去掉哈希和解引用标记(^{}),只需加入一些简单的 sed
git ls-remote --tags --sort="v:refname" git://github.com/git/git.git | tail -n1 | sed 's/.*\///; s/\^{}//'

根据@Frederik Nord的建议,您还可以使用--refs开关来摆脱^{},这样只留下一个sed命令(使oneliner缩短4个字符):

git ls-remote --tags --refs --sort="v:refname" git://github.com/git/git.git | tail -n1 | sed 's/.*\///'

# output: v2.18.0

对于 git 版本在 2.18 之前的用户,以下是通过 sort 进行管道输出的组合:

git ls-remote --tags git://github.com/git/git.git | sort -t '/' -k 3 -V | awk -F/ '{ print $3 }' | awk '!/\^\{\}/' | tail -n 1

使用 --refs 参数是否有助于删除一个 sed 命令,即去掉 {}? - Frederick Nord
@FrederickNord 是的,它有效,感谢您的建议。 - Ivan Bartsov

18

不幸的是,git ls-remote --tags实际上按字母顺序列出标签(至少在1.7.2.5版本中是这样)。因此,在1.7.10、1.7.11或1.7.12成为最新标签的时候,1.7.9将会是列表中的最后一个标签:

git ls-remote --tags git://github.com/git/git.git |grep "1\.7\."

[...]
bf68fe0313c833fa62755176f6e24988ef7cf80f        refs/tags/v1.7.9.6
cb2ed324fc917db0b79d7b1f3756575ffa5f70d5        refs/tags/v1.7.9.6^{}
3996bb24c84013ec9ce9fa0980ce61f9ef97be4d        refs/tags/v1.7.9.7
d0f1ea6003d97e63110fa7d50bb07f546a909b6e        refs/tags/v1.7.9.7^{}

然而,我们可以通过“sort”将这些结果导出以更接近我们寻找的结果:

git ls-remote --tags git://github.com/git/git.git |grep "1\.7\."| sort -g -k3 -t.

[...]
eab05abaeb51531e11835aaa4c26564a1babebac        refs/tags/v1.7.9-rc2
eac2d83247ea0a265d923518c26873bb12c33778        refs/tags/v1.7.9-rc0^{}
f59f511e26b4924b22c6966e79fe4f754bc81dc6        refs/tags/v1.7.9.2
0e2d57fd50f61e668be3180bc8f25991ea88aa8c        refs/tags/v1.7.10-rc1^{}
121f71f0da1bc9a4e1e96be2c3e683191a82a354        refs/tags/v1.7.10.4^{}
26e5c5d09334d157bd04f794f16f6e338d50c752        refs/tags/v1.7.10.3^{}
[...]
cffb45719f60d6fc2cc98ead6af88a895c63c9ac        refs/tags/v1.7.12.4
d8cf053dacb4f78920c112d10c7be21e4f5a5817        refs/tags/v1.7.12.2^{}
dcd07fb6262fd8bb9f531890df3986a8b719a0b5        refs/tags/v1.7.12-rc0
e15c16de396a1e1f42001b03cb885ce64eb4098e        refs/tags/v1.7.12-rc2^{}

虽然还不完全正确,但已经接近了。如果我们排除-rc和^{},并在最后的子版本号上添加一个额外的排序,那么对于大多数需求来说,可能已经足够接近了:

git ls-remote --tags git://github.com/git/git.git |grep "1\.7\."|grep -v -|grep -v {| sort -n -t. -k3 -k4

23ed9debf17263ed6bed478a4d6d86e71342c18a        refs/tags/v1.7.11.6
527b331100ddba839cc54bb31c1bcd66acc08321        refs/tags/v1.7.11.7
14d20a75e3d57a872a8c81ae90dcc4c61ddba011        refs/tags/v1.7.12
51993a414a76120fda20d56ba767fa513d9ff440        refs/tags/v1.7.12.1
04043f4d1ae42bddee67d354a2e6fd2464592a1e        refs/tags/v1.7.12.2
b38da673be332933b8f3a873ce46ffea08d2ee2c        refs/tags/v1.7.12.3
cffb45719f60d6fc2cc98ead6af88a895c63c9ac        refs/tags/v1.7.12.4

1
Windows cmd 是什么? - albanx

4

简而言之:

% git -c 'versionsort.suffix=-' ls-remote -t --exit-code --refs --sort=-v:refname \
    https://github.com/robert7/nixnote2 'v*' \
    | sed -En '1!q;s/^[[:xdigit:]]+[[:space:]]+refs\/tags\/(.+)/\1/gp'  
v2.1.0-beta4g

解释

在使用git ls-remote命令时,通过添加--refs参数可以消除其他答案中显示的{}引用:

$ git ls-remote -t --refs <URL>

这将输出以下内容:
8f235769a2853c415f811b19cd5effc47cc89433        refs/tags/continuous
24e666ed73486a2ac65f09a1479e91e6ae4a1bbe        refs/tags/continuous-develop
7c2cff2c26c1c2ad4b4023a975cd2365751ec97d        refs/tags/v2.0
35b69eed46e5b163927c78497983355ff6a5dc6b        refs/tags/v2.0-beta10

要仅获取标签名称,请执行以下操作:

sed -E 's/^[[:xdigit:]]+[[:space:]]+refs\/tags\/(.+)/\1/g':

$ git ls-remote -t --exit-code --refs https://github.com/robert7/nixnote2.git \
  | sed -E 's/^[[:xdigit:]]+[[:space:]]+refs\/tags\/(.+)/\1/g'
continuous
continuous-develop
v2.0
v2.0-beta10

您可以通过适当的 grep 和/或 head -n1(或者如果您喜欢保持 PID 数字较低,可以添加到您的 sed 命令中)来传递经过清理的列表。
建议:
  • 在命令行末尾添加一个模式进行筛选。例如,如果所有版本标签都以 v 开头,则添加 'v*'
  • 传递 --exit-code 以确保在没有匹配的引用返回时退出非 0
  • 使用 https:// 版本:它更快,如果您正在打包,则不想冒被要求提供 ssh 密钥的风险。
  • --sort=-v:refname 按版本而不是按词典顺序排序,并将最大版本放在顶部
  • 使用 git -c versionsort.suffix=- 防止 2.0-rc2.0 之后出现。

4

当最新的标签是1.4.34时,它会让我失败。相反,它将报告1.4.9。我猜9在3之后 - 它不被解释为34。 - s-m-e
@ernestopheles 您是正确的,我已经更新了答案以解决该问题。感谢您指出。 - Vbp
无法使用,因为我们更改了标记方式,这个程序不会按日期排序。 - Dimitri Kopriwa

4

这是我的一行代码 :-)

git ls-remote --tags --refs --sort="version:refname" git://github.com/git/git.git | awk -F/ 'END{print$NF}'

@tborychowski 感谢您的示例。现在它可以工作了 :) - SebMa

-1

对于 Git < 2.0,不支持使用ls-remote --sort命令:

用法:git ls-remote [--heads] [--tags] [-u | --upload-pack ] [-q|--quiet] [--exit-code] [--get-url] [ [...]]

要列出最新的标签,并包括旧版本的 Git,请使用内置的sort命令。

按版本号(反向)的第二列排序打印标签:

git ls-remote --tags $my_repo | sort -Vr -k2

...哈希 ID... refs/tags/v0.10.0-rc0
...哈希 ID... refs/tags/v0.9.0-rc0
...哈希 ID... refs/tags/v0.9.0
...哈希 ID... refs/tags/v0.8.1
...哈希 ID... refs/tags/v0.8.0-rc1

使用 grep 获取特定版本的最新标签(例如,最新的 0.8 版本):

git ls-remote --tags $my_repo | sort -Vr -k2 | grep -Po -m 1 "tags/\K.*0.8.*"

v0.8.1


这对我来说是有效的,但我尝试在Groovy中运行它时出现了错误。 - Parth Shah

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