python - 相当于git remote show origin的管道(从Python使用)

标签 python git

当我手动检查本地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 upstreamgit rev-parse HEAD^的结果以确定是否存在差异,但是我不知道如何进行。
我是否必须使用git ls-remote upstream来获取完整的提交列表并将其与本地提交列表进行手动比较?实际上,我希望找到一个等效于git rev-list的东西,它也可以用于远程存储库。
也许有人知道git remote show upstream如何执行比较?



编辑:@torek:非常感谢您的详细回答。这将需要一些时间来消化,但我会在一天中更有生产力的时候进行尝试,答应;-)
可能需要对预期用法的上下文进行澄清。也许有些事情比您想像的要简单(因为我没有做通用的Git GUI客户端之类的事情)。

我们有一个现有的Python应用程序托管在Github上。仅主要开发人员具有对存储库的推送访问权限,并且他仅公开公开其master分支。

有些用户使用可下载的软件包,有些用户从Git存储库运行该应用程序(这对于使用Python作为解释语言特别有用)。

我当前要实现的第一件事是从应用程序内部通过Git更新自身的接口。 (好吧,这并不是真正意义上的突破,因为任何人都可以转到命令行并发出git pull origin master或他命名为遥控器的任何名称。但是,我正在说这是第一步,这是为更高级的工具提供Git工作流以进行工作的第一步。与应用程序的文档/项目。
为此,总是fetch是可以的,因为单击“检查更新”按钮的人应该接受提取。同样很清楚,一切工作如何,我通过查看其URL来确定远程服务器的名称,从而知道哪个(如果有多个)指向“官方”存储库。

但是也有一些用户(像我一样)同时是参与者。他们通常分叉了存储库,因此至少有两个遥控器,即主仓库和他们的个人叉子。有时,他们还注册了其他人的分叉,以便在将其合并为母版之前检查其贡献。当我接近拉取请求时,有时我还会要求周围取回我的新材料,以便提供拉前请求反馈。

我现在想要实现的基本上是列出所有遥控器上所有分支的列表,并提供其中哪些具有新内容以及可能与upstream/master的关系的信息。例如。告诉它是从主站分支出来的,后面有17个提交,其中包含上游回购协议中未包含的12个提交。
我的理由是,完全(并定期)获取所有这些远程分支不是一个好行为。我认为用户应该只获取他实际要检查的分支。

但是,从阅读您的答案开始,很可能最终我会在后台获取所有内容,然后解释本地分支与“本地远程”分支之间的比较。

最佳答案

乱序:


实际上,我希望找到一个等效于git rev-list的东西,它也可以用于远程存储库。


没有一个。在下面这很重要,如果我们想查看多少远程提交而我们没有。


实际上,我正在尝试确定远程服务器上的给定分支与给定的本地分支是否不同,以及是否存在这种关系(快速转发,向前,向后,分开)。 ...是否有一种无需先获取就可以完成这种比较的方法?


好吧,主要不是。尽管这部分取决于您希望在此处显示的字面量以及所需结果的精确程度。另外,请记住,从远程服务器断开连接后,从远程服务器获取更新后,其他人可能会连接到同一远程控制器并更改所有内容。您还编写了遥控器,就好像只有一个遥控器一样。可能有多个遥控器。

使用git fetch可以连接到遥控器,并查询有关参考的信息(主要是分支头和标签,还有git note之类的东西),然后根据需要/带来新的东西。

使用git ls-remote连接到遥控器并查询它们(然后在此处停止)。

因此,如果遥控器“很难到达”(例如,建立连接需要一到两秒钟,或者需要输入诸如ssh密码或短语之类的信息),但是更新量较小和/或较快(一旦建立连接,则进行传输)快速),仅使用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是一个猜测,您通常应该忽略它。它是通过将HEAD的SHA-1与所有refs/heads/*的SHA-1进行匹配来计算的。只有在存在完全匹配一个匹配项。如果存在两个或多个匹配项,这可能是无意间正确的,但是git需要更改协议以使其可靠运行。)

URL分别来自git config --get remote.origin.urlgit 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


(在后一种情况下,存在一些深层的怪异,可能是历史性的意外。如果阅读documentation for git merge,您将看到以下内容:



命名分支的branch.<current branch>.merge的值
branch.<current branch>.remote命名的远程
咨询,然后通过remote.<remote>.fetch将它们映射到
他们相应的远程跟踪分支,以及这些技巧
跟踪分支被合并。


使用“合理”配置(请参见下面的git fetch注释),这意味着上面的refs/heads/master的确是refs/remotes/origin/master。)

另外,在这种特殊情况下,master pushes to master是因为我在此存储库中设置了git config push.default matching,以使其像git在出现push.default之前所做的那样工作。如果您具有较新版本的git和/或未设置push.default或将其设置为其他值,则可能会推送到其他内容。现在可能的值为nothingcurrentupstreamsimplematching;参见git-config documentation

现在,关于为什么此推送是快速转发的原因:从ls-remote输出中,我们看到远程服务器的refs/heads/master(即,我们的master将推送到的内容)是指120a630b0b71193a33cd033ae9ddcee1db3df07e。如您所知(但可能没有意识到),我们可以看到他们没有的东西:

$ git rev-list 120a630b0b71193a33cd033ae9ddcee1db3df07e..master
eed7b697cab0cbd5babf382f720668e12a86cf2a
224384fed46e1949c88eb514fa67743be66a4c5a
ddc0aab680bab0bd6a7dde4a6ef8cb58ba0368e6
ade842c8562cdccd1e98f7ffd5149a12ddc9226c


我们有四个承诺,他们没有。而且,由于我在开始所有操作之前运行了git fetch并进行了合理的配置,因此我们可以看到它们没有的内容:

$ git rev-list master..120a630b0b71193a33cd033ae9ddcee1db3df07e


没什么我们还需要知道一点—实际上,我们应该从这里开始—即:“ 120a630...实际上是我们的masterade842c...)的祖先,或者如果不是,那么这两者之间是否有一些共同的祖先?还有我们的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找到要点,但这意味着我们不仅需要具有它们的master提交ID F,还需要有导致它们之间的中间ID(DE)那一点。这又意味着我们需要git fetch

如果运行git fetch,它不仅会发现其refs/heads/master位于120a630b0b71193a33cd033ae9ddcee1db3df07e,还将带出所有需要的提交(可能没有,可能很多),这当然会为您获取其ID,因此您可以< cc>他们。

使用git rev-list还将更新我们的git引用以设置git fetch。但这仅仅是因为:

$ git config --get remote.origin.fetch
+refs/heads/*:refs/remotes/origin/*


此配置项表示,在refs/remotes/origin/master获取引用列表(与fetch打印相同的引用)之后,应采用与ls-remote匹配的任何内容,将名称更改为refs/heads/*,然后将其填充到本地存储库中。

可以更改此设置,以使refs/remotes/origin/<match>不会更新git fetch。如果有人这样做,origin/master将无用。 (而且我不确定是否会得到提交git rev-list origin/master..masterDE!我从来没有运行过疯狂的获取配置。)

总结一下,您需要弄清楚:


要联系哪个遥控器(如果有)
哪些本地分支(F)对应于那些遥控器(用于拉动和/或推动)
他们的分支头是否与我们的分支头相关(无论是同名还是异名)
推送是否将推送到相同的名称(refs/heads/*matchingcurrent -if-name-same),可能不同的名称(simple)或“从不”(upstreamnothing -如果名称不同)
是否(如果您选择不联系部分或全部遥控器)是否信任simple中的引用(基于refs/remotes/行)


都很混乱,因为remote.name.fetchpush是不对称的。 fetch可能会推送git push blarg(因此,如果matching有一个名为blarg的分支,即使glink没有设置glink,我们也会在其中推送glink)。还有配置变量branch.glink.remoteremote.pushdefault等。以及remote.name.push的更多配置(同样,请参见git-config文档)。

(我怀疑您最好只运行fetch,然后再使用git fetch。)

关于python - 相当于git remote show origin的管道(从Python使用),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19312976/

相关文章:

git - .nyc_output 应该包含在 .gitignore 中吗?

git - 在窗口 git bash 中运行 shell 时找不到 sed 命令

git - 使用 Git 分离要修改的目录作为分支 elsewere

python - 如何使用 Python 子进程执行长 bash 序列

python - PIL ImageGrab 返回 24 位图像而不是 32 位

python - 无法从/dev/input/event* 获取 Wacom 事件

c++ - Python API C++ : "Static variable" for a Type Object

python - 计算字典-列出项目python

git fork repo 到同一个组织

git - 如何将以编程方式生成的文件列表传递给 `git filter-branch` ?