【问题标题】:Get commits per branch in git "update" hook在 git "update" 钩子中获取每个分支的提交
【发布时间】:2017-08-24 00:21:23
【问题描述】:

考虑下一个创建所需 git 日志的伪代码:

git checkout master
git checkout -b 123-test-branch-1
git commit -m "#123 b1 c1"
git commit -m "#123 b1 c2"
git push
git checkout master
git checkout -b 456-test-branch-2
git commit -m "#456 b2 c1"
git commit -m "#456 b2 c2"
git push
git checkout 123-test-branch-1
git merge 456-test-branch-2
git commit -m "#123 b1 c3"
git push

在现实世界中,我在远程 git 存储库中的 update 挂钩验证分支名称和提交消息格式。分支名称和提交消息必须包含问题编号,例如123-test-branch-1#123 b1 c1 中的问题编号为123。推送分支时,挂钩从分支中提取问题编号并提交消息并进行比较。如果它们不相等,则钩子退出并出错。

当我推送只有“自己的”提交的分支时,这很好用。但是,上面的 git log 示例,推送分支 123-test-branch-1 具有来自合并分支 456-test-branch-2 的提交,因此钩子尝试仅将来自两个分支的所有提交与推送分支 123-test-branch-1 进行比较,并以错误退出,因为来自 456-test-branch-2 的提交具有问题编号456,当需要 123 时。

为了接收提交,我使用git log --pretty=%s ${oldRef}..${newRef},其中oldRefnewRef 是“更新”挂钩参数。

所以,我的问题是如何解决这个问题。以某种方式对每个分支进行分组提交,或过滤来自现在推送的分支的提交(但如果 456-test-branch-2 是本地分支并且从未推送且从未验证,则挂钩可能会跳过无效提交)或其他内容。

【问题讨论】:

  • 也许这有帮助:stackoverflow.com/a/7131735/575643
  • 我想这更有帮助:stackoverflow.com/a/2707110/575643
  • 您还应该考虑这样一种情况:用户等待并在最后执行一个git push origin 123-test-branch-1 456-test-branch-2,而不是三个单独的git push 命令。
  • @torek,在这种情况下,update 钩子将运行两次,对于每个推送的分支,对于 123-test-branch-1,git log 将与三个 git push 命令相同,对吧?如果是这样,问题是一样的:提交,从456-test-branch-2合并将被处理。
  • 正确,更新挂钩每次更新运行一次。这就是为什么我建议,至少对于合并遍历,使用--first-parent。您可能还想精确限制 可以进行合并和/或何时进行。对于一些非常花哨的东西(尽管仍有缺陷),请参阅我的示例预接收挂钩 here

标签: git hook githooks


【解决方案1】:

更新挂钩没有获得足够的信息:它无法获得传入哈希 ID 的“全局视图”。接收前或接收后挂钩确实,1,因此确实获得了足够的信息——至少对于某些目的而言。

最大的问题在于新分支的创建。例如,假设一个更新正在传递名称refs/heads/arefs/heads/b,其中两个名称都是新名称(它们的旧哈希是空哈希),并且refs/heads/a 指向提交N2refs/heads/b 指向在此图形片段中提交N3

                 N2   <-- A
                /
...--O--O--O--N1
                \
                 N3   <-- B

其中所有O 提交都是“旧的”(例如,之前可以从现有的分支或标签名称访问),而N 提交是“新的”,因为以前永远无法访问,因此被列出作者:

git rev-list refs/heads/a refs/heads/b --not \
    $(git for-each-ref --format '%(refname) |
        egrep -v '^(refs/heads/a|refs/heads/b)$')

很明显,这三个N 提交是“新的”,但是您应该将N1 分配到哪个分支?

对此没有唯一的正确答案。毕竟,提交N1 在两个分支上。

无论如何,如果您更关心合并提交,例如:

...O1--O2--N1--N2   <-- A
              /
...-O3--O4--N3    <-- B

——你可能想使用--first-parent 遍历。在这里,我们可以相信,基于这两个分支名称更新(AO2 移动到 N2BO4 移动到 N3)—N2 的第一个父级是N1(有可能,但很难,以相反的方式实现),所以跟随--first-parents 将“分配”提交N1A 而不是B。同样,如果您是从更新挂钩而不是接收前或接收后挂钩执行此操作,那可能是您能做的最好的事情,因为您没有得到 both @987654349 的信息@ B 建议更新。


1一个 post-receive 挂钩在删除所有锁后运行,因此它与可能更新引用名称的其他操作竞争。 pre-receive 钩子获取所有建议的更新,因此在引用名称更新周围有一个很大的锁定,所以从某种意义上说,在那里进行这项工作显然更安全。

缺点是 pre-receive 钩子在持有大锁的同时运行,所以它所做的任何“慢”操作都会禁止并行性。

【讨论】:

  • 你能对git reflog show --all | grep &lt;hash&gt;说些什么?此命令可以显示第一次出现提交的分支。这种方法有局限性:由于 git gc 默认情况下只有最后 90 天可用,但在大多数情况下,这是可以接受的解决方案。所以,我可以找到所有提交的分支,被钩子(updatepre-receive)拦截,并为每个分支运行验证。
  • reflog 技术有三个缺陷:(1)它只适用于 90 天或其他 reflog 到期,如您所述; (2) 仅当引用日志启用时才有效(它们是可选的); (3) 对钩子最重要的是,它只在创建分支的机器上工作,而不是接收推送的服务器(在服务器裸存储库上,reflogs 默认也被禁用) )。
  • 在远程仓库上使用git reflog 进行几次实验后,我可以声明基于 reflog 的解决方案不起作用。您能否详细解释一下,我如何使用git rev-list 的方法找到分支?我需要为所有收到的(挂钩)提交找到分支,并知道哪个提交来自哪个分支以进行正确验证。
  • 事实上你不能解决这个问题;您能做的最好的事情就是处理您认为“足够好”的特定情况。请参阅stackoverflow.com/a/3162929/1256452 了解更多信息。
  • 我们也可以缩写为:git rev-list refs/heads/a refs/heads/b --not --exclude="refs/heads/a" --exclude="refs/heads/b" --all 有人知道这是否有效吗?根据文档,它应该...
猜你喜欢
  • 2011-09-16
  • 1970-01-01
  • 2011-07-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-12-15
相关资源
最近更新 更多