27

CVS から来て、コミット メッセージにバグ番号 (単純な接尾辞 "... [9999]") をタグ付けする必要があるというポリシーがあります。CVS スクリプトはコミット中にこれをチェックし、メッセージが準拠していない場合はコミットを拒否します。

git フックの commit-msg は開発者側でこれを行いますが、自動化されたシステムがこれをチェックして通知してくれると便利です。

git push 中、commit-msg は実行されません。プッシュ中にコミットメッセージをチェックできる別のフックはありますか?

git push 中にコミット メッセージを確認するにはどうすればよいですか?

4

5 に答える 5

25

更新フックの使用

あなたはフックについて知っています - それらについてのドキュメントを読んでください! おそらく必要なフックは、ref ごとに 1 回実行される update です。(pre-receive フックは、プッシュ全体に対して 1 回実行されます) これらのフックに関する質問と回答は、すでに SO に山ほどあります。やりたいことに応じて、必要に応じてフックの書き方に関するガイダンスを見つけることができます。

これが実際に可能であることを強調するために、ドキュメントからの引用:

このフックを使用して、オブジェクト名が、古いオブジェクト名で指定されたコミット オブジェクトの子孫であるコミット オブジェクトであることを確認することにより、特定の参照に対する強制更新を防ぐことができます。つまり、「早送りのみ」のポリシーを適用します。

古い..新しいステータスをログに記録するためにも使用できます。

そして詳細:

フックは、更新される参照ごとに 1 回実行され、次の 3 つのパラメーターを受け取ります。

  • 更新される参照の名前、
  • ref に保存されている古いオブジェクト名、
  • およびrefに格納される新しいオブジェクト名。

したがって、たとえば、どのコミット サブジェクトも 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

もちろん、これはおもちゃの例です。一般的なケースでは、完全なコミット メッセージを含むログ出力を使用し、それをコミットごとに分割し、個々のコミット メッセージごとに検証コードを呼び出します。

更新フックが必要な理由

これはコメントで議論/明確化されています。ここに要約があります。

update フックは、ref ごとに 1 回実行されます。ref はオブジェクトへのポインターです。この場合、ブランチとタグについて話していますが、通常はブランチだけです (通常はバージョンをマークするためだけにタグをプッシュすることはあまりありません)。

ここで、ユーザーがマスターと実験的な 2 つのブランチに更新をプッシュしている場合:

o - o - o (origin/master) - o - X - o - o (master)
 \
  o - o (origin/experimental) - o - o (experimental)

X が「悪い」コミット、つまり commit-msg フックに失敗するコミットであるとします。明らかに、マスターへのプッシュを受け入れたくありません。したがって、更新フックはそれを拒否します。しかし、実験的なコミットには何も問題はありません! 更新フックはそれを受け入れます。したがって、origin/master は変更されませんが、origin/experimental は更新されます。

o - o - o (origin/master) - o - X - o - o (master)
 \
  o - o - o - o (origin/experimental, experimental)

pre-receive フックは、ref の更新を開始する直前 (初めて update フックが実行される前) に 1 回だけ実行されます。これを使用すると、プッシュ全体を失敗させる必要があり、master に不適切なコミット メッセージがあったため、experimental のコミットが正常であっても、そのメッセージが正常であるとは信じられなくなります。

于 2010-03-26T14:52:31.317 に答える
7

次の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 failed\n";
    ++$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:\n\n" . $msg . "\n";
      ++$errors, next;
    }
  }
}

exit $errors == 0 ? 0 : 1;

プッシュ内のすべてのコミットには、ヒントだけでなく、それぞれのコミット メッセージのどこかにバグ番号が含まれている必要があります。例えば:

$ git log --pretty=oneline origin/master..HEAD
354d783efd7b99ad8666db45d33e30930e4c8bb7 秒 [123]
aeb73d00456fc73f5e33129fb0dcb16718536489 バグ番号なし

$ git push オリジン マスター
オブジェクトのカウント: 6、完了。
最大 2 つのスレッドを使用したデルタ圧縮。
オブジェクトの圧縮: 100% (4/4)、完了。
オブジェクトの書き込み: 100% (5/5)、489 バイト、完了。
合計 5 (デルタ 0)、再利用 0 (デルタ 0)
オブジェクトの開梱: 100% (5/5)、完了。
aeb73d00456fc73f5e33129fb0dcb16718536489 にバグ番号はありません:

バグ番号なし

file:///tmp/bare.git へ
 ! [リモート拒否] マスター -> マスター (事前受信フックが拒否されました)
エラー: 一部の参照を「file:///tmp/bare.git」にプッシュできませんでした

2 つのコミットを一緒に押しつぶして結果をプッシュすることで問題を解決するとします。

$ git rebase -i オリジン/マスター
[...]

$ git log --pretty=oneline origin/master..HEAD
74980036dbac95c97f5c6bfd64a1faa4c01dd754 秒 [123]

$ git push オリジン マスター
オブジェクトのカウント: 4、完了。
最大 2 つのスレッドを使用したデルタ圧縮。
オブジェクトの圧縮: 100% (2/2)、完了。
オブジェクトの書き込み: 100% (3/3)、279 バイト、完了。
合計 3 (デルタ 0)、再利用 0 (デルタ 0)
オブジェクトの開梱: 100% (3/3)、完了。
file:///tmp/bare.git へ
   8388e88..7498003 マスター -> マスター
于 2010-03-27T22:32:27.320 に答える
1

あなたのバグトラッカーが何であるかについては言及していませんでしたが、それがJIRAである場合、 Commit Policyという名前のアドオンは、プログラミングなしでこれを行うことができます。

コミット メッセージが正規表現と一致することを要求するコミット条件を設定できます。そうでない場合、プッシュは拒否され、開発者はコミット メッセージを修正 (修正) してから、再度プッシュする必要があります。

于 2015-12-15T09:22:11.177 に答える
1

事前受信でスクリプトを作成する必要があります。

このスクリプトでは、古いリビジョンと新しいリビジョンを受け取ります。すべてのコミットをチェックして、これのいずれかが悪い場合は false を返すことができます。

于 2010-03-26T14:55:40.290 に答える