乱序:
实际上,我希望找到与 git rev-list 等效的方法,它也适用于远程存储库。
没有一个。这在下面很重要,如果我们想查看某个远程有多少我们没有的提交。
实际上,我正在尝试确定远程服务器上的给定分支是否与给定的本地分支不同,如果不同,关系如何(可快速转发、前进、落后、发散)。...有没有办法在不先获取的情况下完成这样的比较?
好吧,基本上没有,尽管这部分取决于你想在这里的字面意思,以及你需要的结果有多精确。另外,请记住,在您与遥控器断开连接并从中获取更新后,其他人可能会连接到同一个遥控器并更改所有内容。你也写了遥控器,好像只有一个;可能有不止一个遥控器。
Usinggit fetch
与遥控器建立连接并查询它们的参考资料(主要是分支头和标签,还有诸如 git 注释之类的东西),然后根据需要提供任何新的东西。
使用git ls-remote
与遥控器建立连接并查询它们(然后停在那里)。
因此,如果远程“难以到达”(例如,建立连接需要一两秒钟,或者需要输入 ssh 密码或短语之类的内容)但更新很小和/或很快(一旦建立连接,传输quick) 更经济fetch
,因为稍后进行第二次连接会很痛苦。如果它“易于访问”但更新可能很大和/或很慢,那么使用ls-remote
. 但无论哪种方式,您都在建立与远程的连接,您可能认为这与执行fetch
. 如果你需要列出中间提交 ID,你必须把这些提交带过来,所以你必须做一个完整的fetch
.
还有一个问题fetch
,我稍后会解决。
让我们看一下示例git ls-remote
输出,并且git remote show origin
. 我会先做一个git fetch origin
(虽然没有输出,因为它已经是最新的了):
$ git fetch origin
$ git ls-remote origin
120a630b0b71193a33cd033ae9ddcee1db3df07e HEAD
120a630b0b71193a33cd033ae9ddcee1db3df07e refs/heads/master
$ git remote show origin
* remote origin
Fetch URL: ssh://[host]//tmp/tt.git/
Push URL: ssh://[host]//tmp/tt.git/
HEAD branch: master
Local branch configured for 'git pull':
master merges with remote master
Local ref configured for 'git push':
master pushes to master (fast-forwardable)
(这里HEAD branch
显示的是一个猜测,您通常应该忽略它。它是通过将 SHA-1HEAD
与所有 SHA-1 进行匹配来计算的refs/heads/*
。只有在只有一个匹配时才能保证是正确的。如果有两个或更多匹配项,它可能会意外正确,但 git 需要更改协议以使其可靠地工作。)
URL 分别来自git config --get remote.origin.url
和git config --get remote.origin.pushurl
(默认推送 URL,如果未设置,则与获取 URL 相同)。
现在让我们看看为什么master merges with remote master
。那是因为这两个配置项:
$ git config --get branch.master.remote
origin
$ git config --get branch.master.merge
refs/heads/master
(在后一种设置中存在一些深刻的怪异,可能是历史事故。如果您阅读git merge 的文档,您会看到:
branch.<current branch>.merge
查询远程named by的name分支的值,branch.<current branch>.remote
映射remote.<remote>.fetch
到对应的remote-tracking分支,合并这些tracking分支的tips。
使用“健全”的配置——见git fetch
下面的注释——这意味着refs/heads/master
上面的真正意思refs/remotes/origin/master
。)
此外,master pushes to master
在这种特殊情况下,因为我git config push.default matching
在这个 repo 中设置,让它像 git 在有push.default
. 如果您有较新版本的 git 和/或未设置push.default
,或设置不同,它可能会推送到其他内容。现在可能的值为nothing
, current
, upstream
, simple
, 和matching
; 请参阅git-config 文档。
现在,至于为什么这个推送是快进的:从ls-remote
输出中,我们看到遥控器refs/heads/master
(即,我们master
将推送到的内容)指的是120a630b0b71193a33cd033ae9ddcee1db3df07e
. 正如您已经知道(但可能没有意识到),我们可以看到我们拥有的东西,他们没有:
$ git rev-list 120a630b0b71193a33cd033ae9ddcee1db3df07e..master
eed7b697cab0cbd5babf382f720668e12a86cf2a
224384fed46e1949c88eb514fa67743be66a4c5a
ddc0aab680bab0bd6a7dde4a6ef8cb58ba0368e6
ade842c8562cdccd1e98f7ffd5149a12ddc9226c
我们有四个他们没有的提交。而且,因为我在开始这一切之前就跑了git fetch
并且有一个理智的配置,我们可以看到他们有什么我们没有:
$ git rev-list master..120a630b0b71193a33cd033ae9ddcee1db3df07e
这没什么。我们还需要知道一点——事实上,我们应该从这个开始——即:“120a630...
实际上是我们的master
( ade842c...
) 的祖先,或者如果不是,那和我们的 之间是否有一些共同的祖先master
?” 我将在这里使用一个缩写的 SHA-1 和名称master
,作为长度:
$ if git merge-base --is-ancestor 120a630 master; then echo OK; fi
OK
——所以这是“快进的”:我们领先 4 和落后 0。(事实上,作为祖先意味着我们没有落后:这是最简单的测试,如果你只有的输出ls-remote
。)
如果120a630
不是 的祖先master
,那将意味着两件事之一。也许我们master
与他们完全无关master
,而且我们根本没有“领先”或“落后”,我们处于完全不同的火车轨道上。或者——可能更有可能——它们就在我们前面(我们可以快进),或者我们有一些共同的祖先,有一个像这样的提交图片段:
D--E--F
/
A--B--C
\
G--H
(例如,C
共同祖先在哪里,他们在哪里F
,我们在哪里H
,我们可以变基或合并)。
要找出答案,我们需要从他们开始master
并向后工作,从我们的开始master
并向后工作,看看它们是否会在某个时候相遇。我们可以使用git merge-base
will find the point ,但这意味着我们不仅需要它们的master
commit-ID F
,还需要中间的 ID(D
和E
)导致该点。这再次意味着我们需要git fetch
!
如果你运行git fetch
,它不仅会发现他们的refs/heads/master
is at 120a630b0b71193a33cd033ae9ddcee1db3df07e
,它还会带来任何需要的提交(可能没有,可能很多),这当然会为你提供他们的 ID,以便你可以使用git rev-list
它们。
Usinggit fetch
还将更新我们的git 引用到 set refs/remotes/origin/master
。但这仅仅是因为:
$ git config --get remote.origin.fetch
+refs/heads/*:refs/remotes/origin/*
此配置项表示,在fetch
获取 refs 列表(ls-remote
打印相同的)之后,它应该采用任何 match refs/heads/*
,将 name 更改为refs/remotes/origin/<match>
,并将它们填充到本地 repo 中。
可以更改它,因此git fetch
不会更新. 如果有人这样做,将没有用。(而且我不确定我们是否会得到 commits ,,或者两者之一!我从来没有使用过疯狂的 fetch 配置。)origin/master
git rev-list origin/master..master
D
E
F
总而言之,您需要弄清楚:
- 联系哪个遥控器(如果有)
- 哪些本地分支(
refs/heads/*
)对应于那些远程(用于拉和/或推)
- 他们的分公司负责人是否与我们有关(是否同名或异名)
- 推送是否会推送到相同的名称 (
matching
, current
, simple
-if-name-same)、可能不同的名称 ( upstream
) 或“从不” ( nothing
, simple
-if-name-different)
- 如果您选择不联系部分或全部遥控器,是否信任 refs
refs/remotes/
(基于行)remote.name.fetch
这一切都很混乱,因为push
和fetch
是不对称的。有可能git push blarg
会推送matching
(所以如果blarg
有一个名为 的分支glink
,我们会推送到glink
那里,即使glink
没有branch.glink.remote
设置)。还有配置变量remote.pushdefault
,等;以及更多配置(再次,请参阅 git-config 文档)。remote.name.push
fetch
(我怀疑你最好只运行git fetch
,然后可能使用git branch -vv
。)