Подтвердить что ты не робот

Как мы проверяем фиксацию сообщений для push?

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

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

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

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

4b9b3361

Ответ 1

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

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

Чтобы подчеркнуть, что это действительно возможно, цитата из документов:

Этот крючок можно использовать для предотвращения принудительного обновления определенных ссылок, убедившись, что имя объекта является объектом фиксации, являющимся потомком объекта фиксации, названного старым именем объекта. То есть, для обеспечения политики "ускоренной перемотки вперед".

Он также может использоваться для записи старого.. нового статуса.

И особенности:

Крюк выполняется один раз для каждого ref, который должен быть обновлен, и принимает три параметра:

  • имя обновляемого 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

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

Зачем нужен хук обновления

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

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

Теперь, если пользователь нажимает обновления на две ветки, мастер и экспериментальные:

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

Ответ 2

Вы можете сделать это со следующим 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

Ответ 3

Вам нужно сделать script для вашего предварительного получения.

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

Ответ 4

Это версия 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()

Ответ 5

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

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