在 git 分支引用中,`..` 是什么意思?

38
git log origin/master
git log origin/master..

上面的代码与此有何不同?我试图理解..符号确切的作用。我以为它是一个范围符号,但在这种情况下它的作用不同。

4个回答

51
使用git log(以及所有其他采用类似参数集的Git命令),它是一个查找修订范围的规范。请记住,在Git的一般世界中,这意味着修订图的某个子图--对大多数人来说,通常只是一个修订列表的范围。(如果您没有进行太多分支操作,那么在Git中也会简化为此)。
修订规范包含一组正引用(起始点)和负引用(停止点)以及其他过滤器(限制修订次数,grep提交文本等)。Git从正引用开始,通过修订历史向后移动,并在遇到可从负引用到达的修订时停止(不一定要到达其中一个负引用本身)。
可能相当令人困惑的是,有各种演变而来的速记符号,旨在使这一切更易于使用,但同时也管理混淆 - 我必须花费相当长的时间才能弄清楚“master..maint”,“maint..master”等表示什么,以及何时使用哪个。
当您只说“origin/master”时,那意味着“origin/master”是一个正引用,没有负引用。因此,Git从origin/master开始,穿越所有可用的修订--您将获得origin/master的完整历史记录。
“origin/master..”是“origin/master..HEAD”的速记符号,看起来有点像“从origin/master到HEAD”。实际上确实如此。它可以重写为“HEAD ^ origin/master”或“HEAD --not origin/master”。在这种情况下,HEAD是正引用,“origin/master”是负引用。因此,Git从HEAD开始向后移动,直到遇到可从origin/master到达的修订。实际上,它很可能会遇到origin/master本身。请注意,所有引用都是包容性的--正引用本身会输出,而负引用则不会(除非您提供--boundary,然后它们会被标记)。这意味着如果HEAD和origin/master是相同的修订,则“origin/master..HEAD”不会输出任何内容。
因此,如果您在上游版本之上进行了几个本地提交,则会出现以下情况:
steve@monolith:~/src/git <master>$ git log --pretty=oneline --abbrev-commit --decorate -n 4
ea3107d (refs/heads/master) Add another dummy comment
869c260 Add dummy comment
6345d7a (refs/remotes/origin/master, refs/remotes/origin/HEAD) Merge branch 'maint'
be427d7 allow -t abbreviation for --track in git branch

现在,“git log origin/master..”的意思是Git将从HEAD(ea3107d)开始,这不可从origin/master到达,因此打印出来。然后它返回到HEAD的父级(869c260),这仍然不是,所以打印出来。然后下一个父级是6345d7a,它是origin/master,所以它停止。
请注意,“git log ..origin/master”的作用相反-尝试从origin/master向后移动到HEAD。在这种情况下,它不会打印任何内容。但是如果我检出“origin/maint”,它将打印未在origin/maint上的origin/master上的修订版本:因此,通常要将“A..B”视为“B中不在A中的修订版本”,并记住省略A或B表示“HEAD”。
只是为了额外的超级混淆,还有一种表示法“A...B”。因此,请记住计算点的数量!在A和B位于修订行中的情况下,实际上没有区别。但是“A...B”的含义是A或B中的修订版本不在A和B的任何合并基础中。因此,如果A和B处于分歧分支上,则显示自它们分歧以来所做的所有提交。
修订范围的“长格式”(“B--not A”)允许您指定诸如“所有本地分支上的修订版本,而不在任何远程跟踪分支上”(“--branches --not --remotes”)之类的内容。这个参数列表由许多Git命令(“git rev-list”是其中核心之一),包括gitk进行解析。因此,您可以执行“gitk --branches --not --remotes”以图形方式查看本地更改。
最后,对于超级奖励混淆,像“git diff”这样的命令接受相同类型的简写语法,但它的含义并不完全相同。 “git diff”实际上需要两个修订版本并进行比较,这与范围不同-请记住,Git中的修订范围是子图,而不仅仅是列表。“git diff A..B”等效于“git diff A B”。 “git diff A...B”的意思是“显示自A分叉以来B中的更改”。令人困惑?有点:例如,“git log A...B”和“git log B...A”表示相同的含义,但是“git diff A...B”和“git diff B...A”则不是。

2
请参阅 git-rev-list(1) 手册页,其中解释了 <rev1>..<rev2> 语法。 - Jakub Narębski
我认为我已经得出结论,即即使是 SourceSafe,也比 Git 更好。 - Neutrino

26
git log origin/master

会像这样(假命令):

git log INITIAL..origin/master

当:

git log origin/master..

是否为:

git log origin/master..HEAD

如果你只是想要一个快速的答案,那么这个回答简短而且易懂。但显然,araqnid的回答更加全面和详细! - pattivacek
我不认为araqnid的回答有什么价值。我的回答才是回答了提出的问题。 - FelipeC
你的回答确实回答了问题,所以我点了赞。我也给araqnid的回答点了赞,因为它更全面地回答了问题。我欣赏你回答的简洁明了,但另一个回答用更详细的方式解释了命令,这也很好。 - pattivacek

5

我认为它是一个范围。".. "命令将向您显示 origin/master 最后一次提交和您正在工作的分支上的最后一次提交之间的提交。

您还可以通过在“..”后面放置要比较的分支来指定要比较的分支,因此它将变成

git log origin/master..<branch_name>

你可以使用提交标识符来过滤输出,例如:
git log 663f4c..fec6b

尝试使用git help log来查看其他选项 :-)


3

我自己记住语义的办法是...

我将 'git log start..end' 理解为日期范围,其中 start 代表 更早的历史部分end 代表 更近期的历史。然而,与日期范围不同,提交范围不是线性回溯,并且与实际时间无关,而是一个集合减法,即:

(commits reachable from "end") - (commits reachable from "start")

请记住,在提交范围中被排除的起始点代表一组一个或多个提交,而不是单个提交。

实际上,它指的是在“起始”(排除)和“结束”(包含)之间创建的所有提交。


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