Предотвратить публикацию git commit с другим именем автора? - PullRequest
24 голосов
/ 22 сентября 2008

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

Есть ли способ принудительно использовать набор известных авторов для коммитов? «Центральный» репозиторий будет доступен через ssh.

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

Есть ли простое решение этой проблемы в git?

Ответы [ 6 ]

10 голосов
/ 13 марта 2009

Мы используем следующее для предотвращения случайных фиксаций неизвестного автора (например, при выполнении быстрой фиксации с сервера клиента или чего-либо еще). Он должен быть помещен в .git / hooks / pre-receive и сделан исполняемым.

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import subprocess
from itertools import islice, izip
import sys

old, new, branch = sys.stdin.read().split()

authors = {
    "John Doe": "john.doe@example.com"
}

proc = subprocess.Popen(["git", "rev-list", "--pretty=format:%an%n%ae%n", "%s..%s" % (old, new)], stdout=subprocess.PIPE)
data = [line.strip() for line in proc.stdout.readlines() if line.strip()]

def print_error(commit, author, email, message):
    print "*" * 80
    print "ERROR: Unknown Author!"
    print "-" * 80
    proc = subprocess.Popen(["git", "rev-list", "--max-count=1", "--pretty=short", commit], stdout=subprocess.PIPE)
    print proc.stdout.read().strip()
    print "*" * 80
    raise SystemExit(1)

for commit, author, email in izip(islice(data, 0, None, 3), islice(data, 1, None, 3), islice(data, 2, None, 3)):
    _, commit_hash = commit.split()
    if not author in authors:
        print_error(commit_hash, author, email, "Unknown Author")
    elif authors[author] != email:
        print_error(commit_hash, author, email, "Unknown Email")
9 голосов
/ 13 марта 2009

Используйте крючок PRE-RECEIVE (подробности см. githooks (5) ). Там вы получаете старый sha и новый sha для каждого обновления. И может легко перечислить изменения и проверить, что они имеют правильного автора (git rev-list --pretty = format: "% an% ae% n" oldsha..newsha).

Вот пример сценария:

#!/bin/bash
#
# This pre-receive hooks checks that all new commit objects
# have authors and emails with matching entries in the files
# valid-emails.txt and valid-names.txt respectively.
#
# The valid-{emails,names}.txt files should contain one pattern per
# line, e.g:
#
# ^.*@0x63.nu$
# ^allowed@example.com$
#
# To just ensure names are just letters the following pattern
# could be used in valid-names.txt:
# ^[a-zA-Z ]*$
#


NOREV=0000000000000000000000000000000000000000

while read oldsha newsha refname ; do
    # deleting is always safe
    if [[ $newsha == $NOREV ]]; then
    continue
    fi

    # make log argument be "..$newsha" when creating new branch
    if [[ $oldsha == $NOREV ]]; then
    revs=$newsha
    else
    revs=$oldsha..$newsha
    fi
    echo $revs
    git log --pretty=format:"%h %ae %an%n" $revs | while read sha email name; do
    if [[ ! $sha ]]; then
        continue
    fi
        grep -q -f valid-emails.txt <<<"$email" || {
            echo "Email address '$email' in commit $sha not registred when updating $refname"
            exit 1
        }
        grep -q -f valid-names.txt <<<"$name" || {
            echo "Name '$name' in commit $sha not registred when updating $refname"
            exit 1
        }
    done
done
2 голосов
/ 22 апреля 2016

Мы используем Gitlab, поэтому для нас имеет смысл проверять авторов на наличие членов группы Gitlab.

Следующий скрипт (на основе ответа @ dsvensson), который должен быть установлен как ловушка предварительного приема, делает именно это:

from __future__ import print_function
from __future__ import unicode_literals

import sys
import os
import subprocess
import urllib2
import json
import contextlib
import codecs
from itertools import islice, izip

GITLAB_SERVER = 'https://localhost'
GITLAB_TOKEN = 'SECRET'
GITLAB_GROUP = 4
EMAIL_DOMAIN = 'example.com'

def main():
    commits = get_commits_from_push()
    authors = get_gitlab_group_members()
    for commit, author, email in commits:
        if author not in authors:
            die('Unknown author', author, commit, authors)
        if email != authors[author]:
            die('Unknown email', email, commit, authors)

def get_commits_from_push():
    old, new, branch = sys.stdin.read().split()
    rev_format = '--pretty=format:%an%n%ae'
    command = ['git', 'rev-list', rev_format, '{0}..{1}'.format(old, new)]
    # branch delete, let it through
    if new == '0000000000000000000000000000000000000000':
        sys.exit(0)
    # new branch
    if old == '0000000000000000000000000000000000000000':
        command = ['git', 'rev-list', rev_format, new, '--not', '--branches=*']
    output = subprocess.check_output(command)
    commits = [line.strip() for line in unicode(output, 'utf-8').split('\n') if line.strip()]
    return izip(islice(commits, 0, None, 3),
            islice(commits, 1, None, 3),
            islice(commits, 2, None, 3))

def get_gitlab_group_members():
    url = '{0}/api/v3/groups/{1}/members'.format(GITLAB_SERVER, GITLAB_GROUP)
    headers = {'PRIVATE-TOKEN': GITLAB_TOKEN}
    request = urllib2.Request(url, None, headers)
    with contextlib.closing(urllib2.urlopen(request)) as response:
        members = json.load(response)
    return dict((member['name'], '{}@{}'.format(member['username'], EMAIL_DOMAIN))
        for member in members)

def die(reason, invalid_value, commit, authors):
    message = []
    message.append('*' * 80)
    message.append("ERROR: {0} '{1}' in {2}"
            .format(reason, invalid_value, commit))
    message.append('-' * 80)
    message.append('Allowed authors and emails:')
    print('\n'.join(message), file=sys.stderr)
    for name, email in authors.items():
        print(u"  '{0} <{1}>'".format(name, email), file=sys.stderr)
    sys.exit(1)

def set_locale(stream):
    return codecs.getwriter('utf-8')(stream)

if __name__ == '__main__':
    # avoid Unicode errors in output
    sys.stdout = set_locale(sys.stdout)
    sys.stderr = set_locale(sys.stderr)

    # you may want to skip HTTPS certificate validation:
    #  import ssl
    #  if hasattr(ssl, '_create_unverified_context'):
    #    ssl._create_default_https_context = ssl._create_unverified_context

    main()

См. GitLab custom Git hooks docs для инструкций по установке.

Только get_gitlab_group_members() является специфичным для Gitlab, другая логика применяется к любой ловушке перед получением (включая обработку удалений и созданий ветвей).

Сценарий теперь доступен в GitHub , пожалуйста, не стесняйтесь посылать запросы на извлечение для любых ошибок / улучшений.

0 голосов
/ 23 сентября 2008

Если вы хотите управлять правами на git-репо в Интернете, я советую вам взглянуть на Gitosis , а не на создание собственной. Идентичность обеспечивается парой секретный / открытый ключ.

Читайте меня Происходя здесь тоже.

0 голосов
/ 22 сентября 2008

git изначально не был предназначен для работы как svn с большим центральным репозиторием. Возможно, вы можете отстраниться от людей по мере необходимости и отказаться от них, если у них неточно задан автор?

0 голосов
/ 22 сентября 2008

То, что вы могли бы сделать, - это создать группу различных учетных записей пользователей, поместить их всех в одну группу и предоставить этой группе доступ для записи в репозиторий. Затем вы сможете написать простой входящий хук, который проверяет, совпадает ли пользователь, выполняющий сценарий, с пользователем в наборе изменений.

Я никогда не делал этого, потому что доверяю парням, которые проверяют код в моих репозиториях, но если есть способ, это, вероятно, тот, который описан выше.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...