Как мы проверяем сообщения коммита для толчка? - PullRequest
24 голосов
/ 26 марта 2010

Исходя из CVS, у нас есть политика, согласно которой сообщения о фиксации должны быть помечены номером ошибки (простой суффикс "... [9999]"). Сценарий CVS проверяет это во время коммитов и отклоняет коммит, если сообщение не соответствует.

git hook commit-msg делает это на стороне разработчика, но мы считаем полезным, чтобы автоматизированные системы проверяли и напоминали нам об этом.

Во время git push, commit-msg не запускается. Есть ли во время push еще один хук, который может проверять сообщения коммита?

Как мы проверяем сообщения коммитов во время git push?

Ответы [ 5 ]

24 голосов
/ 26 марта 2010

Использование обновления крюка

Вы знаете о крючках - пожалуйста, прочитайте документацию о них! Хук, который вы, вероятно, хотите, это обновление, которое запускается один раз для ссылки (Предварительно получаемый хук запускается один раз за весь пуш). Есть множество вопросов и ответов об этих хуках уже на 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

Конечно, это игрушечный пример; в общем случае вы должны использовать вывод журнала, содержащий полное сообщение о фиксации, разделять его на каждую фиксацию и вызывать код подтверждения для каждого отдельного сообщения о фиксации.

Зачем вам нужен крюк для обновления

Это обсуждалось / уточнялось в комментариях; вот краткое изложение.

Хук обновления запускается один раз за ссылку. Ссылка - это указатель на объект; в данном случае мы говорим о ветвях и тегах, и, как правило, просто о ветвлениях (люди не часто нажимают на теги, поскольку они обычно используются только для маркировки версий).

Теперь, если пользователь загружает обновления для двух ветвей - основной и экспериментальной:

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

Предположим, что X - это "плохой" коммит, т. Е. Тот, который не прошел бы ловушку commit-msg. Ясно, что мы не хотим принимать толчок к мастеру. Таким образом, хук обновления отвергает это. Но нет ничего плохого в коммитах на экспериментальных! Хук обновления принимает это. Следовательно, origin / master остается неизменным, но origin / экспериментальный обновляется:

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

Хук предварительного получения запускается только один раз, непосредственно перед началом обновления ссылок (до первого запуска хука обновления). Если бы вы использовали его, вам бы пришлось заставить весь толчок потерпеть неудачу, сказав, что из-за плохого сообщения о коммите на мастере вы почему-то больше не верите, что коммиты на эксперименте хороши, даже если их сообщения в порядке! 1046 *

5 голосов
/ 28 марта 2010

Вы можете сделать это с помощью следующего pre-receive hook .Как отмечалось в других ответах, это консервативный подход «все или ничего».Обратите внимание, что он защищает только главную ветвь и не накладывает никаких ограничений на сообщения о коммитах в ветвях тем.

#! /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;

Требуется, чтобы все коммиты в push-сообщении имели номер ошибки где-то в их соответствующих сообщениях коммитов, а не толькосовет.Например:

$ 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
2 голосов
/ 06 марта 2014

Это Python-версия pre-receive, которая заняла у меня некоторое время, чтобы надеяться, что она может помочь другим. Я в основном использую его с 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()
1 голос
/ 15 декабря 2015

Вы не упомянули, какой у вас баг-трекер, но если это JIRA , то дополнение с именем Commit Policy может сделать это без какого-либо программирования.

Вы можете установить условие фиксации, которое требует, чтобы сообщение фиксации совпадало с регулярным выражением. Если этого не произойдет, push-уведомление отклоняется, и разработчик должен изменить (исправить) сообщение о коммите, а затем повторно нажать.

1 голос
/ 26 марта 2010

Вам нужно сделать скрипт на предварительном получении.

В этом скрипте вы получаете старую и новую ревизию. Вы можете проверить все коммиты и вернуть false, если один из них плохой.

...