Git pre-push hook,枚举所有未推送的提交

时间:2014-12-20 00:27:41

标签: git githooks

我想在所有未推送的本地提交上运行预推作业。

git rev-list BRANCH --not --remotes=origin适用于所有情况,除非您推送的遥控器为空。在这种情况下,该命令将不返回任何内容。

如果远程数据库是00000 并且 git rev-list BRANCH --not --remotes=origin返回空,那么所有提交都将被枚举git rev-list BRANCH是否安全?

有没有更好的方法来获取我在所有情况下都可以使用的信息?

1 个答案:

答案 0 :(得分:5)

我并不完全清楚你打算完成什么,但是只要你运行git push

  • 你的git调用他们的git(在遥控器上)并找出它的内容;
  • 你告诉你的git - 通常是隐含的 - 它应该在你身边看到什么分支名称(和/或其他引用),以及它应该尝试推进哪些分支名称"他们的"使用" refspecs" (在它们之间带冒号的名字对)。

也就是说,您可以运行:

git push origin mybranch:master

或:

git push origin branch1:branch1 branch2:branch2 branch3:newname

甚至:

git push origin 'refs/heads/*:refs/heads/*'

您也可以运行:

git push origin refs/tags/v1.2:refs/tags/v1.2

或(与--tags)包含一对refs/tags/*,而不是refs/heads/*行。

换句话说,你可能不只是推动一个分支(你可能会推几个),或者你可能根本就没有推动一个分支,而是一个标签,或者你可能正在推动分支标记。 (就此而言,还有"注释"。注释存在于refs/notes/中,这是一个有点新的名称空间,通常不会被转移,但请注意单词"通常" 34。)

在预推钩中,您应该从标准输入读取多行。您建议在遥控器上创建,删除或更新的每个引用名称都会有一行。

在每一行上,您获得(作为documentation注释)本地引用名称, 1 本地SHA-1,远程引用名称和远程SHA- 1,全部按顺序排列。您可以通过检查两个SHA-1来判断您是否已经要求您的git创建或删除远程引用名称。其中最多的一个将是40 0 s。对于正常更新,任何一个都不会全为零。

在提供的ref-name更新中可能没有新的提交,甚至根本没有新的对象, 2 。例如,在创建指向现有提交的新标记时,没有其他任何操作:您只需要询问远程"请创建此新标记,指向现有提交1234567890123456789012345678901234567890"管他呢。但是,如果您只是删除一些提交历史记录(使用强制推送),那么这也没有新的提交:您只是要求远程"请更改branch以指向这个新ID"。

要找出要发送的新对象(如果有),您不应该查看自己的名称,因为这些可能已过期。相反,你应该做与git相同的事情:专注于SHA-1 ID。

这里 有点问题。例如,假设您要求远程设备将引用refs/heads/branch1234567...更新为9abcdef...,以便远程SHA-1为{{1并且本地SHA-1是1234567...。这可能 - 实际上,通常是 - "前进"运动:

9abcdef...

(这里的数字是实际提交对象的SHA-1 ID,你只是要求远程将其分支... <- 1234567... <- 5555555... <- 9abcdef... <-- refs/heads/branch 向前移动两次提交)。但是,遥控器可能已经提交branch5555555...,而不是9abcdef...

branch

在这种情况下,当您通过向前移动两次提交来更新他们的... <- 1234567... <-- branch \ 5555555... <- 9abcdef... <-- develop 时,这两次提交已经在存储库中已经某处了(事实上,在分支branch)。

尽管如此,这两个提交之前并没有develop,如果推送成功将会在之后(你的branch挂钩可以阻止它,但是远程也可以运行:它可以运行它自己的钩子并决定拒绝你的推动。)

要枚举这两个提交,只需将pre-push与原始SHA-1值一起使用,就像我在github上找到的sample hook一样。

如果您在询问如何避免枚举这两个提交,那么答案就是没有100%可靠的方法。在运行git rev-list之前,您可以通过运行git fetch 3 来获得相当接近。这将允许您查找远程愿意导出给您的所有引用名称,以及它们的SHA-1值。任何可通过其引用名称查找的提交对象都必须位于远程存储库中。

在这里,git push确实是 4 正确的事情:在运行git rev-list ... --not --remotes=origin获取他们的引用副本后,您可以使用原始SHA-1查找可达提交,并使用所有这些副本来排除从任何远程分支可到达的提交。这里的缺陷不仅仅是脚注四(标签)中的缺陷,而且事实是,无论你的git fetch - 然后 - fetch序列有多快,你复制的参考文献可能已经​​过时了到push运行时。你可以让这个窗口非常小,但不能(仅用git)消除它。


1 这里有一个警告,也在documentation中提到:本地SHA-1可能没有名称。很明显,当您要求远程设备删除参考时,由于您使用push请求此操作:左侧没有名称 refspec。但是,如果您按原始SHA-1或相对引用推送,则gitrevisions也是如此。一般来说,这不是什么大问题,因为本地引用名称(如果有的话)对远程没有影响:所有操作都是由于两个SHA-1和远程引用名称。

2 请记住,git push :ref-to-delete推送所有所需的对象,而不只是提交:提交指向树,所以如果有新的提交可能有一棵新树;树木指向更多的树木和斑点,因此可能会有额外的树木和斑点;并且带注释的标签是它自己的对象类型。所有这些都可以在推送过程中传输。

3 您可以使用git push获取当前的引用名称映射,但问题是如果您的本地存储库缺少相应的对象,则无法将它们链接起来使用您自己的存储库历史记录来准确找到您不具备的对象。找出它们的唯一方法是使用git ls-remote来获取这些引用指向的对象,而不仅仅是对象本身,以便构建提交图。

4 当然,这完全忽略了标签。

可以通过标签访问遥控器上的提交。但是,如果你带来他们的标签名称空间,你(和git)通常会将所有这些标签复制到你的名称空间中。这些标记未标记其来源,因此无法判断标记git fetch您的标记,还是标记,或两者都有。如果您排除可通过标记访问的提交,则可以排除过多提交。

要正确区分远程标签与您自己或任何其他遥控器的标签,您需要(重新)发明"remote tags"