说明
tag(标签) 是 git 版本库的指向某个 commit 的指针。主要用于在代码版本管理时,保存一个阶段性的版本。
tag 对应某次 commit, 是一个点,是不可移动的。branch 对应一系列 commit,是很多点连成的一根线,有一个HEAD 指针,是可以依靠 HEAD 指针移动的。所以,两者的区别决定了使用方式,改动代码用 branch ,不改动只查看用 tag。
tag 和 branch 的相互配合使用,有时候起到非常方便的效果,例如:已经发布了 v1.0 v2.0 v3.0 三个版本,这个时候,我突然想不改现有代码的前提下,在 v2.0 的基础上加个新功能,作为 v4.0 发布。就可以检出 v2.0 的代码作为一个 branch ,然后作为开发分支。
每创建一个 tag 会在 .git/refs/tags 目录下生成一个同名文件,该文件保存了 tag 对应的 commit 号。
tag 分为简易版本和修饰版本两种。简易版本在打 tag 时除了 commit 号不添加任何 message,主要用于个人或临时的版本。修饰版本(打tag 时使用了 -a/-s/-u 参数)还会包含创建时间,tag 名称和 email 等信息,主要用于正式发布的版本。
常用操作集
列出标签
git tag
搜索标签
# git tag -l ["tagename"]
git tag -l "v1.*"
查看标签
# git show [tagname]
git show v1.0.0
打一个新标签
# git tag [tagname] [commit]
git tag v1.0.0
v1.0.0 表示新的标签名称,如果不加 commit,默认在最后一个 commit 的基础上添加 tag。
切换到 tag 版本
# git checkout [tagname]
git checkout v1.0.0
此时会切换到打这个标签时的代码
删除标签
# git tag -d [tagname]
git tag -d v1.0.0
远程操作
# 推送标签到远程
git push origin [tagname]
# 推送所有tag
git push [origin] --tags
# 删除远程标签
git push origin :refs/tags/tagname
git tag 命令详解
使用格式
git tag [-a | -s | -u <keyid>] [-f] [-m <msg> | -F <file>] [-e]
<tagname> [<commit> | <object>]
git tag -d <tagname>…
git tag [-n[<num>]] -l [--contains <commit>] [--no-contains <commit>]
[--points-at <object>] [--column[=<options>] | --no-column]
[--create-reflog] [--sort=<key>] [--format=<format>]
[--[no-]merged [<commit>]] [<pattern>…]
git tag -v [--format=<format>] <tagname>…
参数解释
- -a / --annotate : 创建一个未签名的、带注释的标签对象。如果没有 -m 则会弹出输入框来填写标签信息。
- -s / --sign : 使用默认电子邮件地址的密钥制作 GPG 签名标签。
- --no_sign : 强制覆盖签名的 tag.gpgSign 配置变量,即不使用签名
- -u <keyid> / --local-user=<keyid> : 使用给定的 keyid 生成签名标签
- -f / --force :如果标签名称已存在,则替换该标签。(通常情况下,标签存在时会报错)
- -m <msg> : 使用给定的 msg 作为标签信息,使用此参数时,不会再出现 nano 弹窗来输入信息
- -F <file> / --file=<file> : 从 file 文件中获取标签信息
- -e / --edit : 从带有-F 的文件和带有-m 的命令行获取的消息通常用作未修改的标记消息。然后显示编辑窗口来进行修改。
- -d / --delete : 删除标签
- -n <num> : 在使用 -l 时,显示 num 行注释。不带此参数时,默认不打印注释,带了 -n 没有 num,则显示一行注释
- -l / --list : 显示所有标签
- --contains [<commit>] : 仅列出包含指定 commit 版本的标签
- --no-contains [<commit>] : 除指定 commit 版本外,列出所有标签
- --points-at <object> :仅列出给定对象的标签
- --column[=<options>] / --no-column : 按列/不案列显示标签
- --create-reflog : 为标签创建一个 reflog。
- --sort=<key> : 根据给定的关键字(key)进行排序,此参数可以多次使用
- --format=<format> : 从显示的标记 ref 和它指向的对象中插入 %(fieldname) 的字符串。格式与 git-for-each-ref(1) 相同。未指定时,默认为 %(refname:strip=2)。
- --merged [<commit>] : 仅列出指定 commit 版本对应的标签,不带 commit 时默认为 HEAD
- --no-merged [<commit>] : 列出除指定 commit 版本之外所有的标签
- -v / --verify : 验证标签的 GPG 签名
- --cleanup=<mode> : 此选项设置如何清理标记消息。 <mode> 可以是verbatim、whitespace 和 strip 之一。strip 模式是默认的。verbatim 模式不会更改消息,whitespace 仅删除前导/尾随空格行,而剥离删除空格和注释。
- <object> : 新标签将引用的对象,通常时 commit 号,默认为 HEAD。
什么是 git 签名标签
由于 Git 是分布式版本控制系统,所有的用户终端都可以创建标签和发布版本,当我们需要验证发行版的来源时,就可以使用签名标签。只有当标签的 GPG 密钥匹配时,才能验证该标签的真实创建这。
要创建签名标签首先需要设置 GPG 签名密钥:
git config --global user.signingkey [gpg-key-id]
如果有多个账户,则需要多个签名密钥,此时需要针对每个账户设置密钥。
然后创建一个标签并对其进行签名:
git tag --sign [signed-tag-name]
如果在创建签名标签时报错,说明还没有创建密钥对。
$ git tag --sign tag_sign
error: gpg failed to sign the data
error: unable to sign the tag
此时我们就需要创建密钥对,如果不确定,可以先检查 GPG 密钥对:
$ gpg --list-keys
没有的话,可以根据以下命令生成密钥:
$ gpg --gen-key
生成时可以根据 name 或者 email 产生,这个由个人选择。生成时间会很长,请耐心等待。
接下来就是验证我们创建的标签了,如果只是在本地验证标签,很简单:
git tag --verify [signed-tag-name]
但是通常我们的版本是要发布给别人使用的,那么对方就需要使用签名者的公钥才能验证版本。多数维护者将他们的公钥放在存储库中的一个特殊对象中——一个只能从特定标签(或者当然是它自己的 SHA)访问的对象。
我们可以按以下步骤在标签中添加公共密钥:
$ gpg -a --export [gpg-key-id] | git hash-object -w --stdin
[object SHA]
$ git tag -a [object SHA] maintainer-pgp-pub
要将维护者的公钥导入密钥环,可以显示标签:
$ git show maintainer-pgp-pub | gpg --import
参考资料