第 43 章:Git 修订版本语法
Git 提供了多种语法来指定和操作修订版本,这在日常开发和版本管理中非常有用。以下是详细的介绍:
43.1 通过对象名称指定修订版本
你可以使用 SHA-1 对象名称(完整的 40 字节十六进制字符串或在仓库中唯一的子串)来指定修订版本(或任何对象:标签、目录内容、文件内容)。
$ git show dae86e1950b1277e545cee180551750029cfe735
$ git show dae86e19
43.2 符号引用名称:分支、标签、远程跟踪分支
你可以使用符号引用名称来指定修订版本,包括分支(例如 master、next、maint)、标签(例如 v1.0、v0.6.3-rc2)、远程跟踪分支(例如 origin、origin/master),以及特殊引用如 HEAD(当前分支)。
$ git log master # 指定分支
$ git show v1.0 # 指定标签
$ git show HEAD # 指定当前分支
$ git show origin # 指定远程 'origin' 的默认远程跟踪分支
如果符号引用名称存在歧义(例如既有分支又有标签名为 fix),需要明确指定类型:
$ git show heads/fix # 或 'refs/heads/fix',指定分支
$ git show tags/fix # 或 'refs/tags/fix',指定标签
43.3 默认修订版本:HEAD
$ git show # 等同于 'git show HEAD'
HEAD 指向工作树中基于的提交,通常是当前分支的符号名称。许多(但不是全部)接受修订参数的命令如果缺少该参数,默认为 HEAD。
43.4 Reflog 引用:<refname>@{<n>}
$ git show @{1} # 使用当前分支的 Reflog
$ git show master@{1} # 使用分支 'master' 的 Reflog
$ git show HEAD@{1} # 使用 'HEAD' Reflog
一个引用(通常是分支或 HEAD),后面跟一个 @ 后缀和用大括号括起来的序数(例如 {1}、{15}),表示该引用在本地仓库中第 n 个之前的值。你可以使用 git reflog 命令或 git log 的 --walk-reflogs / -g 选项来查看最近的 Reflog 条目。
$ git reflog
08bb350 HEAD@{0}: reset: moving to HEAD^
4ebf58d HEAD@{1}: commit: gitweb(1): Document query parameters
08bb350 HEAD@{2}: pull: Fast-forward
f34be46 HEAD@{3}: checkout: moving from af40944bda352190f05d22b7cb8fe88beb17f3a7 to master
af40944 HEAD@{4}: checkout: moving from master to v2.6.3
使用日期指定符与 Reflog 结合,可以查找在本地仓库中对给定引用所做的操作的确切时间。
$ git reflog HEAD@{now}
08bb350 HEAD@{Sat Jul 23 19:48:13 2016 +0200}: reset: moving to HEAD^
4ebf58d HEAD@{Sat Jul 23 19:39:20 2016 +0200}: commit: gitweb(1): Document query parameters
08bb350 HEAD@{Sat Jul 23 19:26:43 2016 +0200}: pull: Fast-forward
43.5 Reflog 引用:<refname>@{<date>}
$ git show master@{yesterday}
$ git show HEAD@{5 minutes ago} # 或 HEAD@{5.minutes.ago}
一个引用后面跟一个 @ 后缀和用大括号括起来的日期(例如 {yesterday}、{1 month 2 weeks 3 days 1 hour 1 second ago} 或 {1979-02-26 18:30:00}),表示该引用在指定时间点的值(或最接近的时间点)。这会查找本地引用在给定时间的状态,例如你本地 master 分支上周的内容。
43.6 跟踪/上游分支:<branchname>@{upstream}
$ git log @{upstream}.. # 当前分支本地所做的未发布更改
$ git show master@{upstream} # 显示分支 'master' 的上游
在分支名后附加的 {upstream} 后缀(简写形式 <branchname>@{u})表示该分支设置为在其之上构建的上游分支(通过 branch.<name>.remote 和 branch.<name>.merge 配置,或使用 git branch --set-upstream-to=<branch>)。如果未指定分支名,则默认为当前分支。
结合修订范围语法,可以查看你的分支相对于上游的提交情况,包括本地未合并到上游的提交(@{u}..)和上游未合并到本地分支的提交(..@{u}),或者两者都查看(@{u}...)。
$ git log --oneline @{u}..
$ git log --oneline ..@{u}
$ git log --oneline --left-right @{u}... # 与 ...@{u} 相同
43.7 提交祖先链:<rev>^、<rev>~<n> 等
$ git reset --hard HEAD^ # 丢弃最后一次提交
$ git rebase --interactive HEAD~5 # 交互式回溯最后 4 次提交
- 修订参数后缀
^表示该提交对象的第一个父提交。^<n>表示第 n 个父提交(例如<rev>^等同于<rev>^1)。 - 修订参数后缀
~<n>表示该提交对象的第 n 代祖先提交,只考虑第一个父提交。例如<rev>~3等同于<rev>^^^。作为快捷方式,<rev>~表示<rev>~1,等同于<rev>^1或<rev>^。
这种语法是可组合的。要查找这样的符号名称,可以使用 git name-rev 命令:
$ git name-rev 33db5f4d9027a10e477ccf054b2c1ab94f74c85a
33db5f4d9027a10e477ccf054b2c1ab94f74c85a tags/v0.99~940
注意,在以下示例中必须使用 --pretty=oneline 而不是 --oneline:
$ git log --pretty=oneline | git name-rev --stdin --name-only
master Sixth batch of topics for 2.10
master~1 Merge branch 'ls/p4-tmp-refs'
master~2 Merge branch 'js/am-call-theirs-theirs-in-fallback-3way'
[...]
master~14^2 sideband.c: small optimization of strbuf usage
master~16^2 connect: read $GIT_SSH_COMMAND from config file
[...]
master~22^2~1 t7810-grep.sh: fix a whitespace inconsistency
master~22^2~2 t7810-grep.sh: fix duplicated test name
43.8 解引用分支和标签:<rev>^0、<rev>^{<type>}
在某些情况下,命令的行为取决于是否给定分支名称、标签名称或任意修订版本。如果你需要后者,可以使用“解引用”语法。
-
后缀
^{}后跟对象类型名称(例如tag、commit、tree、blob),表示递归解引用<rev>,直到找到类型为<type>的对象或无法再解引用。<rev>^0是<rev>^{commit}的简写。bash $ git checkout HEAD^0 # 等同于 'git checkout --detach'(在现代 Git 中) -
后缀
^{}表示递归解引用标签,直到找到非标签对象。bash $ git show v1.0 $ git cat-file -p v1.0 $ git replace --edit v1.0与以下命令对比:
bash $ git show v1.0^{} $ git cat-file -p v1.0^{} $ git replace --edit v1.0^{}
43.9 最年轻的匹配提交:<rev>^{/<text>}、:/<text>
$ git show HEAD^{/fix nasty bug} # 从 HEAD 开始查找
$ git show ':/fix nasty bug' # 从任何分支开始查找
一个冒号 : 后跟一个斜杠 / 和文本,表示匹配指定正则表达式的提交。这会返回从任何引用可达的最年轻的匹配提交。 正则表达式可以匹配提交信息的任何部分。例如,要匹配以字符串开头的消息,可以使用 :/^foo。特殊序列 :/! 用于修饰匹配内容。例如 :/!-foo 表示负匹配,而 :/!!foo 匹配一个字面量 ! 后跟 foo。 修订参数后缀 ^ 后跟一个包含以斜杠开头的文本的大括号对,与 :/<text> 语法相同,返回从 <rev> 之前的提交中可达的最年轻的匹配提交。