如果我可以使用 URL 而不是名称会更好,但据我所知,git 只能在调用 git remote update 后描述遥控器。
没错,虽然有点不准确。这里“幕后”发生的事情是,一旦你完成了git fetch—git remote update,只需将git fetch 或多或少运行到各种遥控器,你可以从git fetch 本身执行此操作,所以使用任何命令你更喜欢,他们在这里基本上做同样的事情——你的 Git 现在在你的存储库中拥有他们的 Git 拥有的每一个提交; 您的Git 已更新您的远程跟踪分支名称,例如origin/master 和bean/master 以及您拥有的任何其他遥控器。
因此,既然您拥有他们所拥有的以及更多(如果还有更多的话),您现在可以确定您拥有的任何给定分支名称是否指向:
- 与某个远程跟踪分支名称相同的提交;
-
较早在同一提交链上提交;
-
稍后在同一提交链上提交;或
- 一个完全不相关的提交。
(最后一种情况不太可能,但为了完整起见,应该提及。)
提交链:提交图
这些提交链是由提交图或 DAG 形成的:
A <-B <-C <-- master
代表一个非常简单的存储库,只有三个提交。我们说 name master“指向”提交 C,因为 master 包含大而丑陋的哈希 ID,它是提交 C 的“真实名称”。同时commit C包含commit B的hash ID,所以C指向B;同样,B 指向A。 B 是 C 的父级,A 是 B 的父级。
由于A 是第一次提交,它没有父提交ID;所以它没有。这使它成为 root 提交,并且它没有指向任何地方,这意味着 git log 可以停止打印内容。我们或git log 将从名称master 开始并查看提交C,然后按照C 的箭头返回B 并查看B。然后它会沿着向后的箭头到A并查看A,现在它已经没有东西可以跟随了。
当您 git fetch 一个新的提交 D 以 C 作为其父级时,我们会得到稍微复杂的图片:
A--B--C <-- master
\
D <-- bean/master
从这张图中很容易看出bean/master 是master 的“提前一次提交”。但是在内部,所有的Git箭头都是向后工作的,所以实际上Git必须从bean/master开始并工作back,当它找到提交C即master时,我们就知道了master 落后于 bean/master。
作为AnimiVulpis answered(已投票),您可以使用--count 让git rev-list 为您计数 次提交。通常它只列出提交哈希。就像git log:它从您告诉它开始的提交开始,并沿着内部“箭头”从一个提交向后退到另一个。如果你给它一个 stopping 点,它会在它到达作为停止点的提交时停止,或者——这部分有点棘手——可从停止点到达 .
让我们画一张稍微复杂一点的图,你在master 上做了一个新的提交——我们称之为E——并从bean 中引入D 来生成bean/master 点给它:
E <-- master
/
A--B--C
\
D <-- bean/master
现在master 是bean/master 之前的一个提交,bean/master 是master 之前的一个提交,同时。这是因为如果我们从master 开始并向后工作,我们会发现一个从bean/master 开始并向后工作无法达到的提交。如果我们反过来开始,情况也是如此。
因此,我们需要 两个 git rev-list 命令。我们将使用master ^bean/master aka bean/master..master 运行一个:从master 开始,在达到提交C 时停止,因为它可以从bean/master 访问。这将在master 上提交E,然后停止。另一个,我们将使用bean/master ^master aka master..bean/master:以bean/master 开始,并在达到提交C 时停止,因为它可以从master 访问。
这个可达性 概念是使 Git 工作的关键图论位之一。可视化它的一个好方法是想象为每个提交临时着色,就像使用荧光笔一样:我们将一些提交着色为红色作为“停止”,将其他提交着色为绿色作为“开始”,如果我们同时这样做,红色往往会覆盖绿色颜色“同时”。 X ^Y 表示法使用从X 开始的绿色和从Y 开始的红色。 Y..X 符号只是同一事物的简写。
对称差异使这更容易
事实证明,Git 有一个特殊的符号,X...Y(三个点而不是两个),表示 对称差异:如果从 只有一个 的起点,但如果从两者都可以到达,则为红色。在此图中,bean/master...master 将选择提交 E——可从 master 访问,但不是 bean/master——和提交 D,但会拒绝提交 C 和更早的时间。 p>
这在这里似乎并不那么有用,直到您发现git rev-list 也有一个--left-right 选项。当将此选项与对称差异三点语法一起使用时,Git 会注意到哪些提交来自“左名称”(bean/master),哪些提交来自“右名称”(master)。通常,当git rev-list 吐出提交哈希ID 时,它使用< 和> 来标记这些。但是如果你添加--count,Git 只会像往常一样计算它们,然后打印 两个 数字:
git rev-list --count bean/master...master
左边的数字是从bean/master 到达但不能从master 到达的提交数,右边的数字是从master 到达但不能从bean/master 到达的提交数。
而且——啊哈!——这些正是git status 为“后面”和“前面”打印的计数。 (如果您愿意,可以交换名称以按其他顺序获取它们。)
警告:不相关的分支
如果您使用不相关的存储库或git checkout --orphan,您可以创建一个包含不相交子图的存储库:
A--B--C <-- master
D--E <-- unrelated/master
在这种情况下,对称差异表示法将列出或计算两个分支上的所有提交,因为它所做的只是列出或计算可从任一名称访问但不能从两个名称访问的提交。由于父链永远不会聚集在一起,因此 no 可以从两者中访问。
如果你真的需要,你可以检测到这种情况——当它发生时,两个名称之间没有合并基础——但通常一开始就不应该发生。请注意,具有多个根并不能保证,因为我们可以故意合并不相关的历史:
A--B
\
E--F <-- branch
/
C--D
我们甚至可以在合并后有一个分叉:
A--B G <-- br1
\ /
E--F
/ \
C--D H--I <-- br2
但是这些分支确实有一个合并基础提交(它是提交F,从图中很明显)。