在 git "update" 挂钩中获取每个分支的提交
Get commits per branch in git "update" hook
考虑下一个创建所需 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
。推送分支时,挂钩从分支和提交消息中提取问题编号并进行比较。如果它们不相等,钩子将错误退出。
当我推送只有 "own" 提交的分支时,这很好用。但是,上面的 git 日志示例,推送分支 123-test-branch-1
有来自合并分支 456-test-branch-2
的提交,因此 hook 尝试将来自两个分支的所有提交仅与推送分支 123-test-branch-1
进行比较并退出错误,因为来自 456-test-branch-2
的提交有问题编号 456
,而预期 123
。
为了接收提交,我使用 git log --pretty=%s ${oldRef}..${newRef}
,其中 oldRef
和 newRef
是 "update" 钩子参数。
所以,我的问题是如何解决这个问题。以某种方式对每个分支进行分组提交,或者从现在推送的分支中过滤提交(但是如果 456-test-branch-2
是本地分支并且从未推送并且从未验证过,钩子可能会跳过无效提交),或者其他东西。
更新挂钩没有获得足够的信息:它无法获得传入哈希 ID 的“全局视图”。 pre- 或 post-receive 钩子确实,1,因此确实获得了足够的信息——至少对于某些目的。
最大的问题在于新分支的创建。例如,假设更新正在传递名称 refs/heads/a
和 refs/heads/b
,其中两个名称都是新的(它们的旧哈希是空哈希),并且 refs/heads/a
指向提交 N2
和 refs/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
遍历。在这里我们可以相信,基于这两个分支名称更新(A
从 O2
移动到 N2
,B
从 O4
移动到 N3
)—N2
的第一个父级是 N1
(有可能,但很难,相反),所以跟随 --first-parent
s 将“分配”提交 N1
到 A
而不是 B
。同样,如果您是从更新挂钩而不是预接收挂钩或 post-接收挂钩执行此操作,那可能是您能做的最好的,因为您没有获得 both 的信息A
和B
建议更新
1一个 post-receive 挂钩在删除所有锁后是 运行,因此它与可能更新引用名称的其他操作竞争。预接收挂钩获取所有建议的更新,因此在引用名称更新周围有一个大锁,所以从某种意义上说,在那里做这项工作显然更安全。
缺点是预接收挂钩 运行 持有大锁,所以它做的任何“慢”事情都会禁止并行。
考虑下一个创建所需 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
。推送分支时,挂钩从分支和提交消息中提取问题编号并进行比较。如果它们不相等,钩子将错误退出。
当我推送只有 "own" 提交的分支时,这很好用。但是,上面的 git 日志示例,推送分支 123-test-branch-1
有来自合并分支 456-test-branch-2
的提交,因此 hook 尝试将来自两个分支的所有提交仅与推送分支 123-test-branch-1
进行比较并退出错误,因为来自 456-test-branch-2
的提交有问题编号 456
,而预期 123
。
为了接收提交,我使用 git log --pretty=%s ${oldRef}..${newRef}
,其中 oldRef
和 newRef
是 "update" 钩子参数。
所以,我的问题是如何解决这个问题。以某种方式对每个分支进行分组提交,或者从现在推送的分支中过滤提交(但是如果 456-test-branch-2
是本地分支并且从未推送并且从未验证过,钩子可能会跳过无效提交),或者其他东西。
更新挂钩没有获得足够的信息:它无法获得传入哈希 ID 的“全局视图”。 pre- 或 post-receive 钩子确实,1,因此确实获得了足够的信息——至少对于某些目的。
最大的问题在于新分支的创建。例如,假设更新正在传递名称 refs/heads/a
和 refs/heads/b
,其中两个名称都是新的(它们的旧哈希是空哈希),并且 refs/heads/a
指向提交 N2
和 refs/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
遍历。在这里我们可以相信,基于这两个分支名称更新(A
从 O2
移动到 N2
,B
从 O4
移动到 N3
)—N2
的第一个父级是 N1
(有可能,但很难,相反),所以跟随 --first-parent
s 将“分配”提交 N1
到 A
而不是 B
。同样,如果您是从更新挂钩而不是预接收挂钩或 post-接收挂钩执行此操作,那可能是您能做的最好的,因为您没有获得 both 的信息A
和B
建议更新
1一个 post-receive 挂钩在删除所有锁后是 运行,因此它与可能更新引用名称的其他操作竞争。预接收挂钩获取所有建议的更新,因此在引用名称更新周围有一个大锁,所以从某种意义上说,在那里做这项工作显然更安全。
缺点是预接收挂钩 运行 持有大锁,所以它做的任何“慢”事情都会禁止并行。