繁体   English   中英

git:我如何以编程方式确定是否需要拉动或推动?

[英]git: how can I programmatically determine if I need a pull or push?

我正在编写一个程序来检查几个克隆的git存储库的状态。

如何判断我的存储库是否需要“git pull”或“git push”?

首先, pull只是fetch然后是merge (或rebase )。 这很重要,因为您首先想要的是一个相关的,更简单的问题的答案:与某些远程存储库相比,您的本地存储库有多远和/或落后? (对于TL; DR回答,请跳到下面的第一个标题部分。)

还有其他潜在的复杂情况,但这里最简单的方法是检查你的分支提示与其他一些git存储库/那些。 为了便于说明,我们给它们一些名字。 我们可以将您的存储库称为“L”(对于本地),并且假设有两个额外的存储库“RA”(远程A)和“RB”,它们在远程名称RA和RB下存储在本地存储库L中的URL。

获取所有可能需要的所有内容的简单方法是在RA和RB上运行git fetch (或git remote update )。 (我们会看到一种延迟提取的方法,虽然我不确定它是否有任何实际价值。)

给定一个典型的设置,获取两个遥控器将复制其本地分支您自己的“远程分支”。 让我们假设RA有masterdev ,RB有masterfeature ,所以在你的提取完成之后:

L$ git rev-parse --short refs/remotes/RA/master
feedbee
L$ git rev-parse --short refs/remotes/RA/dev
feedbee
L$ git rev-parse --short refs/remotes/RB/master
badf00d
L$ git rev-parse --short refs/remotes/RB/feature
c0ffee1

(这些数字是组成的但是用于说明。另外,如果你在实际代码中执行此操作,则不需要--short 。并且,您可以缩写分支名称,省略refs/remotes/ - 和在下面, refs/heads/ - 只要它们是明确的。但是,如果你是脚本,为了以防万一,使用全名可能更明智。)

现在让我们检查一下你自己当地分支机构的提示:

L$ git rev-parse --short refs/heads/master
feedbee

这意味着您的master与RA的master同步,该master与其dev人员同步。 因此,必须没有任何东西可以推送或获取(尽管你已经取出以便找到它),因此也没有任何合并或重组。

另一方面,远程RB 同步,因为它的master指向提交badf00d 这是否意味着你有合并的东西,或者推动什么? 也许,也许不是:这就是并发症的来源。如果需要手动合并,Git无法提供太多帮助,但是你可以通过查看提交方式了解RB是“先行”,“落后”还是两者兼而有之图形相互叠加。

如果repo L严格“在”repo RB之前,即你有可以推送的东西,那么图形片段必须如下所示:

... - o           <-- RB/master: tip-most commit = badf00d
        \
          o - o   <-- master: tip commit = feedbee

这里的L是“2提前”,在git status给你的术语中,repo RB的位置。 如果你推送到RB,git会将最后两次提交交给RB,并告诉它请将其master设置为feedbee ,这样可以赶上它。

如果repo L严格“落后”RB,那么图形片段将看起来相同,但标签将颠倒:

... - o           <-- master
        \
          o - o   <-- RB/master

在这种情况下,如果你进行了合并以将RB/master带入master ,那么git会看到快进并将你的master设置为badf00d 此时repo RA将落后,你可能想要推进那里。

但仍有两种可能性。 L时既超前落后,例如:

... - o - o       <-- master
        \
          o - o   <-- RB/master

这需要一个rebase或一个真正的合并,如果git不能自己组合各种变化(或者即使它可能,它可能会让它们错误),其中任何一个都需要手动手持。

最后,虽然不太可能,但两个分支提示是完全无关的(在...部分中没有共同的祖先):

... - o   <-- master

... - o   <-- RB/master

这是最难处理的,因为我在下面描述的内容给出了错误的前/后计数。 (如果某人已经离开并重写了其中一个克隆的历史记录,也只能使用克隆的回购。例如,使用git merge-base为这种情况添加偏执检查可能是合理的。但是我'我会从这里忽略它。)

发现前后数量

尽管如此,这里有一个快速的方法来找到你知道相关的两个分支(一个本地,一个远程)的“前方”和“后方”计数。 我将切换到远程“origin”,这是(单个)克隆源的通常名称,并使用分支名称的简短形式:

$ ahead=$(git rev-list --count origin/master..master)
$ behind=$(git rev-list --count master..origin/master)

这些使用gitrevisions范围语法来选择可从本地分支提示(由master标识的提交)而不是远程分支提示(由origin/master标识)可访问的修订。

如果你领先但不落后,你可以放心地git push 如果你是落后但未提前你可以安全地进行git merge以获得快进(此时没有意义,因为你已经完成了fetch步骤,所以使用pull )。 如果你俩都领先落后,这样既计数为零,则必须合并或重订,以及如果这些做不到之间做出选择。 当然,如果两个计数都为零,则两个分支提示标识相同的SHA-1,并且不需要执行任何操作。

如果你不想使用git fetch怎么办?

最终你必须使用git fetch 但是,如果您愿意,可以从git ls-remote ,它会吐出一个SHA-1列表并重新命名:

$ git ls-remote
From [url redacted]
a17c56c056d5fea0843b429132904c429a900229    HEAD
ca00f80b58d679e59fc271650f68cd25cdb72b09    refs/heads/maint
a17c56c056d5fea0843b429132904c429a900229    refs/heads/master
0029c496ce1b91f10b75ade16604b8e9f5d8d20b    refs/heads/next
fcd56459647e0c41f2ea9c5b7e2ed827f701fc95    refs/heads/pu
e8f6847178db882bd42d5572439333ca4cb3222e    refs/heads/todo
d5aef6e4d58cfe1549adef5b436f3ace984e8c86    refs/tags/gitgui-0.10.0
3d654be48f65545c4d3e35f5d3bbed5489820930    refs/tags/gitgui-0.10.0^{}
[mass snippage]

如果遥控器上的SHA-1与本地SHA-1不同,这些SHA-1 包含您需要的所有图形信息,但如果您关心的SHA-1匹配,那么您可以知道没有任何东西可以获取或推。 此外,如果它们不同,您可以查看是否有相应的SHA-1。 例如,上面显示遥控器的master指向提交a17c56c056d5fea0843b429132904c429a900229 如果我拥有它(我没有),我可以使用它作为git rev-list --count中的一个说明git rev-list --count来找出遥控器背后的距离。 因为我没有它,我几乎肯定落后了:我不知道多少,但我需要取,然后可能合并或变基(我不知道我是否也领先,直到我取)。

你怎么知道要看哪个分支?

这可能是最好的事先确定,而不是仅仅迭代所有可能的分支。 但是,如果想遍历分支,这个工具是git for-each-ref ,这需要相当多的争论。 要查找您自己的本地分支,例如:

$ git for-each-ref --format='%(refname)' refs/heads
refs/heads/master
refs/heads/precious
refs/heads/stash-exp

找到远程origin的分支:

$ git for-each-ref --format='%(refname)' refs/remotes/origin
refs/remotes/origin/maint
refs/remotes/origin/master
refs/remotes/origin/next
refs/remotes/origin/pu
refs/remotes/origin/todo

剥离足够的这些字符串并匹配分支名称很容易,以便能够比较它们。 如果要检查(并跳过)匹配的SHA-1,使用其他选项可以获得分支名称和SHA-1,这显然会为前后计数提供零。

实际上,自从Git 2.5(今天发布)以来,您可以快速查看哪个分支在前方(需要推动)或后面(需要拉动)

请参阅“ 显示所有分支的前后信息,包括遥控器

git for-each-ref --format="%(push:track)" refs/heads

这是因为<branch>@{push}是一个新的快捷方式,它专门引用用于推送的上游分支(它并不总是用于拉动的分支)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM