26

gitでは、ローカルのgit設定ファイルで正しい作成者を指定するのは各ユーザーの責任です。一元化されたベアリポジトリにプッシュすると、リポジトリのコミットメッセージには、自分のリポジトリにコミットするときに使用した作成者名が含まれます。

コミットの既知の作成者のセットが使用されるように強制する方法はありますか?「中央」リポジトリには、ssh経由でアクセスできます。

一部の人が他の人によって行われたコミットをプッシュしている可能性があるという事実によって、これは複雑になっていることを私は知っています。もちろん、信頼できる人だけがリポジトリにプッシュできるようにする必要もありますが、ここでユーザーエラーを防ぐ方法があれば素晴らしいと思います。

gitでこの問題の簡単な解決策はありますか?

4

6 に答える 6

10

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
于 2009-03-13T09:43:16.677 に答える
2

私たちは Gitlab を使用しているため、Gitlab グループ メンバーに対して作成者を検証することは理にかなっています。

pre-receive フックとしてインストールする必要がある次のスクリプト (@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 カスタム Git フック ドキュメントを参照してください。

get_gitlab_group_members()Gitlab 固有のものだけで、他のロジックは pre-receive フックに適用されます (ブランチの削除と作成の処理を含む) 。

スクリプトはGitHubで利用できるようになりました。誤りや改善点については、お気軽にプル リクエストを送信してください。

于 2016-04-22T19:31:08.597 に答える
0

あなたができることは、たくさんの異なるユーザーアカウントを作成し、それらをすべて同じグループに入れ、そのグループにリポジトリへの書き込みアクセス権を与えることです。次に、スクリプトを実行するユーザーがチェンジセット内のユーザーと同じであるかどうかを確認する単純な着信フックを記述できるはずです。

私のリポジトリにコードをチェックインする人を信頼しているので、私はそれをやったことがありませんが、方法があれば、それはおそらく上で説明したものです。

于 2008-09-22T19:38:23.187 に答える
0

gitは当初、大きな中央リポジトリを持つsvnのように機能するようには設計されていませんでした。おそらく、必要に応じて人々から引っ張ることができ、著者が不正確に設定されている場合は引っ張ることを拒否できますか?

于 2008-09-22T19:39:46.520 に答える
0

インターネットに面した git リポジトリの権利を管理したい場合は、自分で作成するのではなく、Gitosisを検討することをお勧めします。ID は、秘密鍵と公開鍵のペアによって提供されます。

ここでもポン引きを読んでください。

于 2008-09-22T20:10:42.907 に答える