我试图执行公司政策,采取以下假设:
到目前为止,这是我想出的:
#!/usr/bin/env ruby
# Encoding: utf-8
$oldrev, $newrev, $refname = STDIN.read.split(" ")
$real_refname = `git rev-parse --abbrev-ref #{$refname} 2> /dev/null`.strip
$merge_commits = `git rev-list --merges #{$oldrev}..#{$newrev} 2> /dev/null`.strip
$parent_commit = `git rev-parse #{$newrev}\^1`
$ancestor_branch = `git show-branch | grep '*' | grep -v '#{$real_refname}' | head -n1 | sed 's/.*\[\(.*\)\].*/\1/' | sed 's/[\^~].*//'`
puts "Enforcing Policies... \n(#{$real_refname}) (#{$oldrev[0,6]}) (#{$newrev[0,6]})"
$errors = []
def check_branch_policy()
$errors.push "Branch #{$real_refname}: Only Version, Hotfix and Master branches are allowed to be pushed upstream." if !$real_refname.match(/^(version\/[1-9.]+|hotfix\/[1-9.]+|master)/)
$errors.push "Branch #{$real_refname}: Master branch accepts only non-forwarded merge commits." if $real_refname.match('master') && (!$merge_commits.match($newrev) || !$parent_commit.match($oldrev))
$errors.push "Branch #{$real_refname}: Version and Hotfix branches accept only fast-forward/rebased commits." if !$real_refname.match('master') && !$merge_commits.empty?
$errors.push "Branch #{$real_refname}: Version and Hotfix branches must diverge from Master branch directly." if !$real_refname.match('master') && !$ancestor_branch[4,6].match('master')
false
end
check_branch_policy
unless $errors.empty?
puts '[POLICY] Invalid git branch rules.'
$errors.each { |error| puts "# #{error}" }
exit 1
end
但有几个问题:
sed
和grep
似乎不能很好地使用git hooks,所以我基本上需要替换当前的$ancestor_branch
命令。还没有想出任何东西。$real_refname
无法正常工作 - 它似乎无法正确缩写。经过一点点的修补,我得到了这个:
#!/usr/bin/env ruby
# Encoding: utf-8
oldrev, newrev, refname = STDIN.read.split(" ")
short_refname = refname[11..-1]
merge_commits = `git rev-list --merges #{oldrev}..#{newrev}`.strip
unique_revs = `git rev-list --all --not $(git rev-list --all ^#{newrev})`
missed_revs = `git rev-list #{oldrev}..#{newrev}`
puts "Enforcing Policies... \n(#{short_refname}) (#{oldrev[0,6]}) (#{newrev[0,6]})"
def check_branch_policy(oldrev,newrev,short_refname,merge_commits,unique_revs,missed_revs)
errors = []
errors << "Only Version, Hotfix and Master branches are allowed to be pushed upstream." if
!short_refname[/^(version\/[1-9.]+|hotfix\/[1-9.]+|master)/]
if short_refname['master']
# Master should have only one unique commit each time - the merge commit (newrev).
errors << "Master branch accepts only non-forwarded merge commits, one at a time." if
!merge_commits[newrev] && missed_revs.count > 2
else
# If not empty, it means there's a merge commit - whereas there shouldn't be.
errors << "Version and Hotfix branches accept only fast-forward/rebased commits." if
!merge_commits.empty?
# If not equal, it means at least one commit is reachable from another ref - meaning it was diverged.
errors << "Version and Hotfix branches must diverge from Master branch directly." if
!unique_revs[missed_revs]
end
errors
end
errors = check_branch_policy(oldrev,newrev,short_refname,unique_revs,missed_revs)
unless errors.empty?
puts '[POLICY] Invalid git branch rules.'
errors.each { |error| puts "# Branch #{short_refname}: #{error}" }
exit 1
end
虽然出现了更多问题:
short_refname = refname.chomp("refs/heads/")
,但它似乎没有用。帮助update
挂钩,我该如何获取重新命名?到目前为止,网络资源并不是那么清楚...... 答案 0 :(得分:1)
让我们首先关注红宝石部分:
几乎没有理由在ruby中使用全局变量。并且在脚本中他们无论如何都处于“全局”范围内=&gt;摆脱变量名中的前面$
在此代码中:
$errors = []
def check_branch_policy()
$errors.push "Branch #{$real_refname}: Only Version, Hotfix and Master branches are allowed to be pushed upstream." if !$real_refname.match(/^(version\/[1-9.]+|hotfix\/[1-9.]+|master)/)
$errors.push "Branch #{$real_refname}: Master branch accepts only non-forwarded merge commits." if $real_refname.match('master') && (!$merge_commits.match($newrev) || !$parent_commit.match($oldrev))
$errors.push "Branch #{$real_refname}: Version and Hotfix branches accept only fast-forward/rebased commits." if !$real_refname.match('master') && !$merge_commits.empty?
$errors.push "Branch #{$real_refname}: Version and Hotfix branches must diverge from Master branch directly." if !$real_refname.match('master') && !$ancestor_branch[4,6].match('master')
false
end
check_branch_policy
编写一个方法(或函数)的风格很糟糕,该方法只适用于仅为此目的创建的全局对象。您也可以删除方法定义,因为它在此处不执行任何操作。这不是特别的“红宝石风格”的东西,但一般适用于编程。更好的解决方案是在方法内创建对象并返回它。我也不喜欢这些长期难以理解的线条。所以总的来说可能会更像这样:
def check_branch_policy
errors = []
errors << "Only Version, Hotfix and Master branches are allowed to be pushed upstream." if
!real_refname[/^(version\/[1-9.]+|hotfix\/[1-9.]+|master)/]
if real_refname['master']
errors << "Master branch accepts only non-forwarded merge commits." if
!merge_commits[newrev] || !parent_commit[oldrev]
else
errors << "Version and Hotfix branches accept only fast-forward/rebased commits." if
merge_commits.empty?
errors << "Version and Hotfix branches must diverge from Master branch directly." if
!ancestor_branch[4, 6]['master']
end
errors
end
尽管这里的消息可能不那么整齐,但我认为这是一种改进,人们可以更好地看到每种情况应该保持的条件。请注意,我使用了ruby idoms <<
而不是.push
和[]
而不是.match
。我也将Branch #{real_refname}:
前缀保留了,如果它始终相同,它在错误输出循环中也可以。
当你掌握红宝石的力量时,几乎没有理由依赖grep
和sed
。
至于git部分:
你想要做的当然是可能的,但我想有些尝试和错误是必要的。所以我不能给你一个可行的解决方案。但有些评论:
我认为在ruby中获得简短符号引用的更好方法是
`git symbolic-ref #{refname}\`[/[^\/]*$/].chomp
甚至
`git symbolic-ref --short #{refname}`
如果它比git rev-parse --abbrev-ref
更可靠,你可以试试。此外,您的变量real_refname
名称错误。 '真正的'引用名称听起来像实际上是SHA1哈希。可能short_refname
会更好。
既然你正在从stdin读取引用,我猜你使用了pre-receive
git hook?但在这种情况下,你显然是一个错误,因为可能会在一次推送中更新几个分支。您应该迭代stdin或使用update
hook
git show-branch
是一个瓷器命令,即它不应该用于编写脚本,因为输出是针对用户的。我认为Junio在他的pre-rebase.sample
中做了一些非常好的东西。也许你可以从那里得到一些想法如何使用管道命令。
我曾经在Ruby中写过简单的钩子,但多年来我学会了bash也很有能力。因此,除非您的钩子变得非常复杂,否则您可能只是从bash开始。