不要考虑“pull”,这就像试图同时摸肚子和拍头一样。虽然可以做到,但最好在掌握每个部分之后再尝试。所以,将其分解为以下几个组成部分:
1. fetch
2. merge
现在,记住,clone本质上是init + remote add + fetch + checkout,我们可以看到浅克隆实际上是浅获取。
这意味着您需要修改步骤1中的fetch,使其变得更加浅显易懂。
到目前为止,这没有什么大不了的,但现在我们来到第二步,合并。进行合并需要一定程度的深度。但是,需要多少深度?这就是我们拆分问题的原因。所需深度取决于图中的节点,而要获取节点,我们必须获取它们。暂时假设我们已经获取了足够数量的节点,无论是多少:我们现在将拥有一个类似以下的图形:
...--o--*--o--o <-- yourbranch (HEAD)
\
o--o--o <-- other
git merge other
命令中的
other
参数通常是一个远程跟踪分支名称,比如
origin/master
,用于指定你想要合并的某个提交。Git需要
你的分支末端提交(即
yourbranch
,例如
master
所指向的
o
节点)、
他们的分支末端提交以及我用
*
标记的合并基础提交。
为了让Git能够
找到并证明这是合并基础提交,Git需要
*
和每个分支末端之间的所有提交(包括
*
本身)。
那需要多少呢?这取决于实际的图形结构。我们画了一个图形,其中最上面的线代表你的分支,需要三个提交:末端、末端的前一步、末端的前两步。我们底部的线需要四个提交:末端、末端的前两步,再往前一步就到达了
*
。
因此,对于
这个图形,所需的
--depth
值为4,因为3和4中较大的是4。
那么对于
你的图形需要多少呢?这取决于你的图形!无法提前预测:在你获得足够的图形以找出是否有足够的图形之前,你没有足够的图形。一旦你
拥有了足够的图形,就可以找到合并基础提交,然后计算“最深一行”。
请注意,我们画了一个非常简单的图形,它可能更加复杂,例如:
...--o--*--o--...--o <-- yours (HEAD)
\
\ o--o--o
\ / \
o--o o--o <-- other
\ /
o-----o
要找到此图的最小深度,请从
yours
沿顶部直线回溯到
*
,并从
other
沿底部的两条线路都回溯到
*
。(显然,底部拆分的上半部分将是更长的线路,因此我们可以有点懒,只计算这些节点。)
在哪里进行这个计数
现在问题很明显:为了计算回到(包括)合并基础,我们必须找到合并基础,这意味着我们需要足够的深度才能找到合并基础。
不幸的是,我们必须在具有
所有提交的存储库中执行此操作,并且您已在您的存储库中进行了新提交,而这些提交不在其他存储库中。如果我们可以将您的提交推送到主存储库并在那里完成工作,那将很容易。
(实际上,我们不必一次获得所有计数。获取“您的计数”和“他们的计数”,并取其中较大的一个即可。细节会有点棘手;如果您想走这条路,我会让您自己解决。考虑合并基础是否包含在您迄今为止获得的子图中,或者不包含在其中;这是您必须实现的两种情况。)
因此,一个解决方案就是确实只做到这一点:将您的提交推送到已经拥有其他所有内容的存储库中。(请参见 VonC 对
为什么无法从浅克隆进行推送? 的回答以获取此操作的限制条件。)为此,您需要写入该更完整克隆的
名称,该名称保留供您执行此类操作。例如,您可以有一个保留的分支或标记名称,例如
for-blitz-count-trick
等:
git push $remote HEAD:for-blitz-count-trick
然后让Git在
$remote
上执行合并基础计算和提交计数。然后完全删除
for-blitz-count-trick
名称,以便下次需要再次执行此操作时准备好。
假设您计划运行
git merge $remote/other
,因此
$remote
上的名称为
other
,并且您已经完成了此特殊推送。现在登录到
$remote
,在那里您可以计算出正确的
--depth
。
如果您愿意超额完成,可能超过相当大的范围,命令序列:
base=$(git merge-base for-blitz-count-trick other)
git rev-list --count --ancestry-path $base^@..for-blitz-count-trick
git rev-list --count --ancestry-path $base^@..other
这应该能够完成任务。
我没有亲自测试过这个方法,但它是基于明显的图形操作而来。对于像我展示的更复杂的图形,它会计算所有分叉和合并序列上的节点数量,这就是为什么它有可能重复计数的原因。我使用$base^@
来包含提交$base
,同时排除其父提交。值得注意的是,如果没有共同的合并基础或者有多个合并基础,该方法将失败,因此最好检查是否只有一个合并基础。
我认为--ancestry-path
不能与--left-right
组合使用,但类似的命令可以:
git rev-list --count --left-right --boundary for-blitz-count-trick...other
应该也可以工作,但在某些情况下可能会过度计算边界提交的数量,因为--boundary
实现得有点粗糙。这个命令不会因多个合并基础而失败,并且可以在一个命令中获取两个计数,因此在实践中可能是一种可行的方法。
如果这是不可能的(或者只是太麻烦了)
可能的情况是您无法登录到$remote
进行此操作,或者某些策略防止在那里创建临时名称,或者两者都不能。在这种情况下,您可以简单地反复增加克隆深度,直到找到合并基础,或者完全取消浅层克隆(仅当不存在合并基础时才会发生)。
根本问题在于您需要足够的深度来计算足够的深度。一旦您拥有了这个深度,您就可以“重新浅化”到确切的数量,无论它是多少,但是没有真正必要进行这种“重新浅化”。随着存储库本身通过添加新提交而增长,所需的--depth
也往往会增长,尽管如果您的工作被反复合并(并推送),那么所需的--depth
tend to shrink。
实际上,可能只需要每次添加50个,直到有足够的深度,然后保持在该深度上,无论它是多少,直到证明它太浅为止;然后增加它。请注意,您将需要在某处自己存储此数字:请参见如何知道git的浅克隆的深度?
因此,这是一个丑陋但实用的方法:只需选择一些可行的深度,并使用它,直到它不起作用,然后增加它。永远不要运行git pull
,只需将其拆分为其组成部分的git fetch
和其他命令(通常是git merge
,但git rebase
也可以)。