阻止人们使用不同的作者名称推送git提交?

时间:2008-09-22 19:35:44

标签: git

在git中,由每个用户在其本地git配置文件中指定正确的作者。当他们推送到集中式裸存储库时,存储库上的提交消息将具有他们在提交到自己的存储库时使用的作者名称。

是否有办法强制使用一组已知的提交作者?可以通过ssh访问“中央”存储库。

我知道有些人可能正在推动其他人提出的承诺,这很复杂。当然,您也应该只允许您信任的人推送到您的存储库,但如果有一种方法可以防止用户出错,那就太棒了。

git中有这个问题的简单解决方案吗?

6 个答案:

答案 0 :(得分:10)

我们使用以下内容来防止意外的未知作者提交(例如,从客户的服务器或其他东西进行快速提交时)。它应该放在.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")

答案 1 :(得分:9)

使用PRE-RECEIVE钩子(详见githooks(5))。每次更新时,你会得到旧的沙子和新的沙子。并且可以轻松列出更改并检查它们是否具有合适的作者(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 :(得分:2)

我们使用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的,其他逻辑适用于任何预接收挂钩(包括处理分支删除和创建)。

脚本现在是available in GitHub,请随时发送任何错误/改进的拉请求。

答案 3 :(得分:0)

您可以做的是创建一堆不同的用户帐户,将它们全部放在同一个组中,并为该组提供对存储库的写访问权限。然后你应该能够编写一个简单的传入钩子来检查执行脚本的用户是否与变更集中的用户相同。

我从来没有这样做,因为我相信那些将代码检查到我的存储库中的人,但如果有办法,那可能是上面解释的那个。

答案 4 :(得分:0)

git最初的设计并不像svn那样具有大型中央存储库。也许你可以根据需要从人手中抽出来,如果他们的作者设置不准确,就拒绝拉?

答案 5 :(得分:0)

如果您想管理面向git repo的互联网的权利,我建议您查看Gitosis,而不是自己动手。身份由私钥/公钥对提供。

也请读我pimping it here