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

时间:2015-07-28 02:59:40

标签: git version-control synchronization status

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

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

2 个答案:

答案 0 :(得分:10)

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

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

一次性获取所有内容的简便方法是在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同步,devmaster同步。因此,必须没有任何东西可以推送或取出(尽管你已经为了找到它而已经取出了),因此也没有任何合并或改造。

另一方面,远程RB 同步,因为badf00d指向提交... - o <-- RB/master: tip-most commit = badf00d \ o - o <-- master: tip commit = feedbee 。这是否意味着你有合并的东西,或者推动什么?也许,也许不是:这就是并发症的来源。如果需要手动合并,Git可以提供很多帮助,但是你可以找出RB是否是&#34;提前&#34通过查看提交图如何相互叠加来显示&#34;&#34;或两者之后。

如果回购L严格&#34;在&#34;之前repo RB,即你有你可以推送的东西,那么图片段必须是这样的:

git status

这里L是&#34; 2提前&#34;,在master给你的条款中,repo RB的位置。如果你推送到RB,git会将最后两次提交交给RB并告诉它请将其feedbee设置为... - o <-- master \ o - o <-- RB/master ,这样可以赶上它。

如果回购L严格&#34;落后&#34; RB,然后图片片段看起来会一样,但标签会颠倒过来:

RB/master

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

但仍有两种可能性。 L可以在之后,例如:

...

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

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

git merge-base

这是最棘手的问题,因为我在下面描述的内容会给出错误的前/后计数。 (如果某人已经离开并重写了其中一个克隆的所有历史记录,也只能使用克隆的回购。例如,使用$ ahead=$(git rev-list --count origin/master..master) $ behind=$(git rev-list --count master..origin/master) 为这种情况添加偏执检查可能是合理的。但是我和#39; ll从这里开始忽略它。)

找到前后计数

尽管如此,以下是快速查找&#34;提前&#34; &#34;背后&#34;计算您知道的两个分支(一个本地,一个远程)。我将切换到远程&#34; origin&#34;,这是(单个)克隆源的通常名称,并使用分支名称的简短形式:

master

这些使用gitrevisions range syntax来选择可从本地分支提示(由origin/master标识的提交)而不是远程分支提示(由git push标识)可到达的修订。

如果您领先但未落后,您可以放心git merge。如果您处于落后但未提前的状态,您可以安全地pull快速前进(此时此刻没有任何意义,因为您需要fetch已经完成了git fetch步骤。如果你后面的都在前面,那么两个计数都是非零的,你必须在merge或rebase之间做出决定,如果失败则该怎么做。当然,如果两个计数都为零,则两个分支提示标识相同的SHA-1,并且不需要执行任何操作。

如果您不想使用git fetch

,该怎么办?

最终您 使用git ls-remote。但是,如果您愿意,可以从$ 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列表并重新命名:

master

如果遥控器上的SHA-1与本地SHA-1不同,这些SHA-1 携带您需要的所有图形信息,但如果您关心的SHA-1匹配,然后你就可以知道没有什么东西可以拿取或推动。此外,如果它们不同,您可以查看是否有相应的SHA-1。例如,上面显示远程a17c56c056d5fea0843b429132904c429a900229指向提交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 的分支机构:

{{1}}

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

答案 1 :(得分:4)

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

请参阅“Show git ahead and behind info for all branches, including remotes

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

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