当我手动检查本地Git存储库是否需要来自远程服务器的更新时,我将运行git remote show upstream
并解释其输出。但是现在我试图在我添加Git支持的Python应用程序中这样做。
实际上,我试图确定远程服务器上的给定分支是否与给定的本地分支不同,如果是,则关系如何(快速转发,前进,后退,分流)。
我知道如何通过比较git rev-list master..upstream/master
和?git rev-list upstream/master..master
的结果来做到这一点。但这只有在从远程服务器获取后才能工作。
有没有办法在不先获取的情况下完成这样的比较?
一个用途是更新应用程序本身,为此我认为首先获取它是可以接受的。但我也想通过所有注册的遥控器及其分支机构告诉用户他可以在哪里获得更多东西。我认为首先获取所有遥控器是不可接受的,因为用户可能不会需要大部分遥控器。
我认为ls-remote
是我正在寻找的命令,但我不知道如何实现我的需求。我可以比较git ls-remote --heads upstream
和git rev-parse HEAD^
的结果,以确定是否存在差异,但我不知道如何继续。
我是否必须使用git ls-remote upstream
来获取完整的提交列表并手动将其与本地提交列表进行比较?实际上我希望找到一个与git rev-list
同等的东西,它也适用于远程存储库
也许有人知道git remote show upstream
如何进行比较?
编辑:@torek:非常感谢您的详细解答。消化需要一些时间,但我会在一天中更富有成效的时间通过它,承诺;-)
也许有必要澄清预期用途的背景。也许有些事情比你怀疑的要简单(因为我没有像通用的Git GUI客户端那样做)。
我们有一个在Github上托管的现有Python应用程序。只有主开发人员具有对存储库的推送访问权限,并且他只公开他的master
分支。
有些用户使用可下载的软件包和从Git存储库运行应用程序的用户(这对于Python作为解释语言特别有用)。
我目前正在实现的第一件事是从应用程序内部通过Git更新自身的界面。 (好吧,这并不是真正具有开创性的,因为任何人都可以进入命令行并发出git pull origin master
或他命名为遥控器的任何东西。但我说这是第一个(学习)步骤以获得更多提供Git工作流程的高级工具,用于处理应用程序的文档/项目
为此,始终fetch
可以,因为有人点击了"检查更新"按钮应该接受一个提取。它也非常清楚一切是如何运作的,我通过查看他们的网址来确定遥控器的名称,以便知道哪一个(如果有多个)点在"官方"库中。
但也有用户(像我一样)同时也是贡献者。他们通常分叉存储库,因此至少有两个遥控器,主要的回购和他们的个人分叉。有时他们也注册了其他人。叉子在合并成主人之前检查他们的贡献。当我接近拉取请求时,我有时也会四处寻找我的新材料,以便提供预拉请求反馈。
我现在想要实现的目标基本上是所有遥控器上所有分支的列表,其中包含哪些信息包含新材料以及它们与upstream/master
的关联方式。例如。告诉它从master 17提交后面提交并包含12个未包含在上游repo中的提交
我的理由是,完全(并定期)获取所有远程分支并不是一个好的行为。我认为用户应该只获取他实际想要检查的分支。
但从第一次阅读你的答案后,很可能我最终会在后台获取所有内容,然后解释本地和本地遥控器之间的比较'分支。
答案 0 :(得分:6)
故障:
实际上我希望找到一个与git rev-list等效的东西,它也适用于远程存储库。
没有。这在下面很重要,如果我们想要看到我们没有多少提交一些遥控器。
实际上,我试图确定远程服务器上的给定分支是否与给定的本地分支不同,如果确实如此,则关系如何(快速转发,前进,后退,分流)。 ...有没有办法在没有先获取的情况下完成这样的比较?
嗯,主要是不,虽然这部分取决于你想要在这里的字面意义,以及你需要多少精确的结果。另外,请记住,当您从远程连接断开连接后,从其获得更新后,其他人可能会连接到同一个远程并更改所有内容。您还编写了 遥控器,好像只有一个;可能有多个遥控器。
使用git fetch
建立与远程(s)的连接并查询它们(主要是分支头和标签,还有git备注之类的东西),然后根据需要/需要带来任何新东西。< / p>
使用git ls-remote
建立与远程的连接并查询它们(然后停在那里)。
因此,如果遥控器很难到达&#34; (例如,建立连接需要一两秒钟,或者需要输入类似ssh密码或短语的内容)但是更新很小和/或很快(一旦建立连接,传输速度很快)它就更经济了fetch
,因为以后建立第二个连接很痛苦。如果它很容易到达&#34;但是更新可能很大和/或很慢,使用ls-remote
可能会更好。但无论哪种方式,您都可以建立与遥控器的连接,您可能认为该遥控器相当于&#34;等等。做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
是一个猜测,你通常应该忽略它。它是通过将HEAD
的SHA-1与所有{的SHA-1匹配来计算的。 {1}}。如果只有一个匹配,则只保证是正确的。如果有两个或更多匹配,则可能意外正确,但git需要更改协议才能使其正常工作。)
网址分别来自refs/heads/*
和git config --get remote.origin.url
(默认推送网址,如果没有设置,则与提取网址相同)。
现在让我们看一下git config --get remote.origin.pushurl
的原因。这是因为这两个配置项:
master merges with remote master
(在后一种情况下,有一些非常古怪,可能是历史意外。如果你看过documentation for git merge,你会看到:
在 命名分支的
$ git config --get branch.master.remote origin $ git config --get branch.master.merge refs/heads/master
的值 在branch.<current branch>.merge
命名的遥控器上 咨询,然后通过branch.<current branch>.remote
映射到 他们相应的远程跟踪分支,以及这些分支的提示 追踪分支合并。
&#34;理智&#34;配置 - 请参阅下面的remote.<remote>.fetch
注释 - 这意味着上面的git fetch
实际上意味着refs/heads/master
。)
此特定案例中的refs/remotes/origin/master
,因为我在此回购邮件中设置了master pushes to master
,使其在存在git config push.default matching
之前就像git一样行事。如果你有一个较新版本的git和/或没有设置push.default
,或者设置不同,它可能会推动其他东西。现在可能的值为push.default
,nothing
,current
,upstream
和simple
;请参阅git-config documentation。
现在,至于为什么这次推送是快进的:从matching
输出,我们看到遥控器ls-remote
(即我们的refs/heads/master
会push-to)指的是master
。正如你已经知道的那样(但也许没有意识到),我们可以看到他们不具备的东西:
120a630b0b71193a33cd033ae9ddcee1db3df07e
我们有四项承诺,他们没有。而且,因为我在开始所有这些之前运行$ git rev-list 120a630b0b71193a33cd033ae9ddcee1db3df07e..master
eed7b697cab0cbd5babf382f720668e12a86cf2a
224384fed46e1949c88eb514fa67743be66a4c5a
ddc0aab680bab0bd6a7dde4a6ef8cb58ba0368e6
ade842c8562cdccd1e98f7ffd5149a12ddc9226c
并且有一个合理的配置,我们可以看到他们拥有的我们没有:
git fetch
这没什么。还有一点我们需要知道 - 实际上,我们应该从这开始 - 即:&#34; $ git rev-list master..120a630b0b71193a33cd033ae9ddcee1db3df07e
实际上是我们120a630...
的祖先(master
),或者如果没有,那与我们ade842c...
之间是否有一些共同的祖先?&#34;我将使用一个缩写的SHA-1和名称master
,其长度为:
master
- 这是&#34;快速前进&#34;:我们领先4并落后于0.(事实上,作为一个祖先意味着我们立刻意味着我们不会落后:它&#39; ; s是最简单的测试,如果只有$ if git merge-base --is-ancestor 120a630 master; then echo OK; fi
OK
的输出,则可以执行。)
如果ls-remote
不是120a630
的祖先,那将意味着两件事之一。也许我们的master
与他们的master
完全无关,而我们并未#34;提前&#34;或&#34;背后&#34;总之,我们在一组完全不同的火车轨道上。或者 - 可能更有可能 - 他们只是领先于我们(我们可以快进),或者我们有一些共同的祖先,使用这样的提交图片段:
master
(其中 D--E--F
/
A--B--C
\
G--H
是共同的祖先,他们在C
,我们在F
,我们可以改变或合并。
要找到答案,我们需要从他们的H
开始并向后工作,然后从我们的master
开始并向后工作,看看这些是否在某些时候相遇。我们可以使用master
找到重点,但这意味着我们不仅需要提交git merge-base
提交ID master
,还需要中间ID(F
和D
)导致这一点。这再次意味着我们需要E
!
如果您运行git fetch
,它不仅会发现他们的git fetch
位于refs/heads/master
,还会带来任何所需的提交(可能没有,可能很多),当然会为您提供他们的ID,以便120a630b0b71193a33cd033ae9ddcee1db3df07e
他们。
使用git rev-list
还会更新我们的 git引用以设置git fetch
。但那仅仅是因为:
refs/remotes/origin/master
此配置项表示在$ git config --get remote.origin.fetch
+refs/heads/*:refs/remotes/origin/*
获取引用列表(相同的fetch
打印)后,它应该采用任何匹配ls-remote
,将名称更改为{{1然后把它们塞进本地仓库。
可以更改此设置,以便refs/heads/*
不更新refs/remotes/origin/<match>
。如果有人这样做,git fetch
将没有用处。 (而且我不确定我们是否也会提交origin/master
,git rev-list origin/master..master
和D
!我从未使用疯狂的抓取配置运行。 )
总结一下,你需要弄明白:
E
)对应于那些遥控器(用于拉动和/或推动)F
,refs/heads/*
,matching
- if-name-same),可能是不同的名称(current
),或者&#34;从未&#34; (simple
,upstream
- if-name-different)nothing
中的参考号(基于simple
行)这一切都非常混乱,因为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
。)