我们如何验证推送提交消息?
来自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
                        
                        
                    