【发布时间】:2016-06-10 02:12:12
【问题描述】:
有没有办法编写一个 git pre-commit 钩子来停止具有相同名称的提交,唯一的区别是大写和小写。
例如
分支名称 1:firstBranch
分支名称 2:FirstBrancH
分支名称 3 : firsTbranch
但是分支名称:firstbranchname 应该是允许的。
如果在时间 T 为分支名称 firstBranch 完成提交,那么在 T+n ,使用分支名称“FirstBrancH”或任何组合提交,git pre-hook 将不允许提交。这需要是一个服务器钩子,因为客户端钩子可以很容易地被 pypassed。
所以我的想法是:
所以我得到了被提交到的分支的 $NAME,然后将它与忽略 CASE 的所有分支进行比较,并通过一条消息使其失败 如果比赛通过。
我已经在 gitlab 服务器上设置了一个 pre-receive 钩子:
#!/bin/bash
check_dup_branch=`git branch -a | sed 's; remotes/origin/;;g' | tr '[:upper:]' '[:lower:]' | uniq -d`
if [ check_dup_branch ]
then
echo "Duplicate CaseInsensitive Branch Name Detected"
exit 1
fi
exit 0
按照说明:
选择一个需要自定义 git 挂钩的项目。
在 GitLab 服务器上,导航到项目的存储库目录。对于从源代码安装,路径通常是 /home/git/repositories//.git。对于 Omnibus 安装,路径通常是 /var/opt/gitlab/git-data/repositories//.git。
在此位置创建一个名为 custom_hooks 的新目录。
在新的 custom_hooks 目录中,创建一个名称与挂钩类型匹配的文件。对于预接收挂钩,文件名应为预接收且不带扩展名。
使挂钩文件可执行并确保它归 git 所有。
编写代码以使 git 挂钩按预期运行。 Hooks 可以是任何语言。确保顶部的“shebang”正确反映语言类型。例如,如果脚本在 Ruby 中,则 shebang 可能是 #!/usr/bin/env ruby。
但它没有按预期工作。
如果我 push aaa,当 AAA 已经在 gitlab 中时,会报错:
remote: Duplicate CaseInsensitive Branch Name Detected
但当我尝试推送分支 bbb 时,它也给了我相同的“重复”消息
如果分支名称重复,我希望它不允许提交)忽略大小写)
After a bit more study on git hooks:
ref:如果您想逐个接受或拒绝分支,则需要使用更新挂钩。
当更新钩子是:
#!/usr/bin/python
import sys
print "Testing pre-receive Hook in Python"
branch = sys.argv[1]
print "Branch '%s' pushing" %(branch)
sys.exit(0)
git push origin AAA
Total 0 (delta 0), reused 0 (delta 0)
remote: Testing pre-receive Hook in Python
remote: Branch 'refs/heads/AAA' pushing
- [新分支] AAA -> AAA
现在我们必须像 grep -i , git branch -a 和做一个 uniq -d 和 aaa ,在小写所有分支之后
然后比较,如果有MATCH,调用sys.exit(1)
不允许推送
python 更新钩子:
#!/usr/bin/python
import sys
import subprocess
#print "Testing pre-receive Hook"
branch = sys.argv[1]
old_commit = sys.argv[2]
new_commit = sys.argv[3]
#print "Moving '%s' from %s to %s" % (branch, old_commit, new_commit)
#print "Branch '%s' pushing" %(branch)
#print "old_commit '%s' pushing" %(old_commit)
#print "new_commit '%s' pushing" %(new_commit)
def git(*args):
return subprocess.check_call(['git'] + list(args))
if __name__ == "__main__":
#git("status")
#git("for-each-ref" , "refs/heads/" , "--format='%(refname:short)'")
git("for-each-ref" , "--format='%(refname:short)'")
sys.exit(0)
python更新钩子的进一步增强:
#!/usr/bin/python
import sys
import subprocess
#print "Testing pre-receive Hook"
branch = sys.argv[1]
old_commit = sys.argv[2]
new_commit = sys.argv[3]
# order is important, for update hook: refname oldsha1 newsha1
print "Moving '%s' from %s to %s" % (branch, old_commit, new_commit)
print "Branch '%s' " %(branch)
print "old_commit '%s' " %(old_commit)
print "new_commit '%s' " %(new_commit)
def git(*args):
return subprocess.check_call(['git'] + list(args))
#if %(branch).lower() in []array of results from the git for-each-ref
#sys.exit(1)
def get_name(target):
p = subprocess.Popen(['git', 'for-each-ref', 'refs/heads/'], stdout=subprocess.PIPE)
for line in p.stdout:
sha1, kind, name = line.split()
if sha1 != target:
continue
return name
return None
if __name__ == "__main__":
#git("status")
#git("for-each-ref" , "refs/heads/" , "--format='%(refname:short)'")
#cmd = git("for-each-ref" , "--format='%(refname:short)'")
cmd = git("for-each-ref" , "--format='%(refname:short)'")
#print cmd
#print get_name(branch)
#print get_name(old_commit)
print get_name(new_commit)
sys.exit(0)
所以拒绝案例当然是比较当前的 %(branch) 或 % (refname:short) ,并以 IgnoreCase 方式将其与所有现有的 refnames 进行比较,如果找到( 1 或 many )然后使用消息“重复的分支名称”执行 sys.exit(1)
但目前我得到的是:
remote: Moving 'refs/heads/IIII' from 0000000000000000000000000000000000000000 to 4453eb046fe11c8628729d74c3bec1dd2018512e
remote: Branch 'refs/heads/IIII'
remote: old_commit '0000000000000000000000000000000000000000'
remote: new_commit '4453eb046fe11c8628729d74c3bec1dd2018512e'
remote: refs/heads/10B
不知何故,远程:refs/heads/10B 保持静态。所以我不确定如何转换结果:
cmd = git("for-each-ref" , "--format='%(refname:short)'")
放入列表或数组,然后在每个元素之间进行字符串比较,然后 远程:分支'refs/heads/IIII'
【问题讨论】: