我们如何验证推送提交消息?
来自CVS,我们有一个政策,提交的消息应该用一个错误号(简单的后缀“... [9999]”)标记。 CVS脚本在提交期间检查它,如果消息不符合,则拒绝提交。
git hook commit-msg在开发者方面做到了这一点,但我们发现让自动系统检查并提醒我们这很有帮助。
在git推送期间,commit-msg不会运行。 推送期间是否有另一个钩子可以检查提交消息?
我们如何在git推送过程中验证提交消息?
使用更新挂钩
你了解钩子 - 请阅读关于它们的文档! 你可能想要的钩子是更新,每个参数运行一次。 (预接收挂钩在整个推送过程中只运行一次)SO上已经有大量的问题和答案, 取决于你想要做什么,你可能会找到有关如何编写钩子的指导,如果你需要它。
为了强调这确实是可能的,来自文档的引用:
通过确保对象名称是一个提交对象,它是由旧对象名称命名的提交对象的后代,可以使用此钩子来防止强制更新某些引用。 也就是说,强制执行“仅快进”策略。
它也可以用来记录旧的......新状态。
具体细节:
该钩子为每个要更新的引用执行一次,并且需要三个参数:
因此,例如,如果您想确保任何提交主题都不超过80个字符,一个非常基本的实现将是:
#!/bin/bash
long_subject=$(git log --pretty=%s $2..$3 | egrep -m 1 '.{81}')
if [ -n "$long_subject" ]; then
echo "error: commit subject over 80 characters:"
echo " $long_subject"
exit 1
fi
当然,这是一个玩具的例子。 在一般情况下,您可以使用包含完整提交消息的日志输出,将其分割为每次提交,并在每个单独的提交消息上调用验证码。
为什么你想要更新钩子
这已在评论中讨论/澄清; 这里是一个总结。
更新挂钩每次运行一次。 ref是一个指向对象的指针; 在这种情况下,我们谈论的是分支和标签,通常只是分支(人们不经常推送标签,因为它们通常只是用于标记版本)。
现在,如果用户将更新推送到两个分支,即master和experimental:
o - o - o (origin/master) - o - X - o - o (master)
o - o (origin/experimental) - o - o (experimental)
假设X是“不好”的提交,即那个会失败commit-msg钩子的提交。 显然,我们不想接受推动掌握。 所以,更新钩拒绝了。 但是实验中的提交没有任何问题! 更新挂钩接受那个。 因此,起源/主人保持不变,但起源/实验得到更新:
o - o - o (origin/master) - o - X - o - o (master)
o - o - o - o (origin/experimental, experimental)
预接收钩子只在开始更新引用之前运行一次(在第一次运行更新钩子之前)。 如果你使用它,你将不得不导致整个推动失败,因此说,因为主人有一个错误的提交信息,你不知何故不再相信即使他们的信息很好,实验的提交是好的!
你可以用下面的pre-receive
钩子来完成。 正如其他答案所指出的那样,这是一种保守的,全有或全无的方法。 请注意,它仅保护主分支,并且对主题分支上的提交消息没有限制。
#! /usr/bin/perl
my $errors = 0;
while (<>) {
chomp;
next unless my($old,$new) =
m[ ^ ([0-9a-f]+) s+ # old SHA-1
([0-9a-f]+) s+ # new SHA-1
refs/heads/master # ref
s* $ ]x;
chomp(my @commits = `git rev-list $old..$new`);
if ($?) {
warn "git rev-list $old..$new failedn";
++$errors, next;
}
foreach my $sha1 (@commits) {
my $msg = `git cat-file commit $sha1`;
if ($?) {
warn "git cat-file commit $sha1 failed";
++$errors, next;
}
$msg =~ s/A.+? ^$ s+//smx;
unless ($msg =~ /[d+]/) {
warn "No bug number in $sha1:nn" . $msg . "n";
++$errors, next;
}
}
}
exit $errors == 0 ? 0 : 1;
它要求推送中的所有提交在它们各自的提交消息中有一个错误编号,而不仅仅是提示。 例如:
$ git log --pretty=oneline origin/master..HEAD 354d783efd7b99ad8666db45d33e30930e4c8bb7 second [123] aeb73d00456fc73f5e33129fb0dcb16718536489 no bug number $ git push origin master Counting objects: 6, done. Delta compression using up to 2 threads. Compressing objects: 100% (4/4), done. Writing objects: 100% (5/5), 489 bytes, done. Total 5 (delta 0), reused 0 (delta 0) Unpacking objects: 100% (5/5), done. No bug number in aeb73d00456fc73f5e33129fb0dcb16718536489: no bug number To file:///tmp/bare.git ! [remote rejected] master -> master (pre-receive hook declined) error: failed to push some refs to 'file:///tmp/bare.git'
假设我们通过压缩两个提交并推动结果来解决问题:
$ git rebase -i origin/master [...] $ git log --pretty=oneline origin/master..HEAD 74980036dbac95c97f5c6bfd64a1faa4c01dd754 second [123] $ git push origin master Counting objects: 4, done. Delta compression using up to 2 threads. Compressing objects: 100% (2/2), done. Writing objects: 100% (3/3), 279 bytes, done. Total 3 (delta 0), reused 0 (delta 0) Unpacking objects: 100% (3/3), done. To file:///tmp/bare.git 8388e88..7498003 master -> master
这是一个pre-receive
的python版本,我花了一段时间才完成,希望它能帮助其他人。 我主要将它与Trac一起使用,但它可以很容易地修改用于其他目的。
我还放下了修改历史提交信息的指示,这比我想象的要复杂一些。
#!/usr/bin/env python
import subprocess
import sys
import re
def main():
input = sys.stdin.read()
oldrev, newrev, refname = input.split(" ")
separator = "----****----"
proc = subprocess.Popen(["git", "log", "--format=%H%n%ci%n%s%b%n" + separator, oldrev + ".." + newrev], stdout=subprocess.PIPE)
message = proc.stdout.read()
commit_list = message.strip().split(separator)[:-1] #discard the last line
is_valid = True
print "Parsing message:"
print message
for commit in commit_list:
line_list = commit.strip().split("n")
hash = line_list[0]
date = line_list[1]
content = " ".join(line_list[2:])
if not re.findall("refs *#[0-9]+", content): #check for keyword
is_valid = False
if not is_valid:
print "Please hook a trac ticket when commiting the source code!!!"
print "Use this command to change commit message (one commit at a time): "
print "1. run: git rebase --interactive " + oldrev + "^"
print "2. In the default editor, modify 'pick' to 'edit' in the line whose commit you want to modify"
print "3. run: git commit --amend"
print "4. modify the commit message"
print "5. run: git rebase --continue"
print "6. remember to add the ticket number next time!"
print "reference: http://stackoverflow.com/questions/1186535/how-to-modify-a-specified-commit"
sys.exit(1)
main()
链接地址: http://www.djcxy.com/p/23441.html