防止人们使用不同的作者姓名推送 git 提交?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/117006/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Prevent people from pushing a git commit with a different author name?
提问by Readonly
In git, it is up to each user to specify the correct author in their local git config file. When they push to a centralized bare repository, the commit messages on the repository will have the author names that they used when committing to their own repository.
在 git 中,每个用户都可以在其本地 git 配置文件中指定正确的作者。当他们推送到一个集中的裸存储库时,存储库上的提交消息将具有他们在提交到自己的存储库时使用的作者姓名。
Is there a way enforce that a set of known authors for commits are used? The "central" repository will be accessible via ssh.
有没有办法强制使用一组已知的提交作者?“中央”存储库可以通过 ssh 访问。
I know that this is complicated by the fact that some people may be pushing commits that were made by others. Of course, you should also only allow people you trust to push to your repositories, but it would be great if there was a way to prevent user error here.
我知道这很复杂,因为有些人可能正在推动其他人所做的提交。当然,您也应该只允许您信任的人推送到您的存储库,但如果有一种方法可以防止用户错误,那就太好了。
Is there a simple solution to this problem in git?
在 git 中这个问题有简单的解决方案吗?
采纳答案by dsvensson
We use the following to prevent accidental unknown-author commits (for example when doing a fast commit from a customer's server or something). It should be placed in .git/hooks/pre-receive and made executable.
我们使用以下内容来防止意外的未知作者提交(例如,当从客户的服务器或其他地方进行快速提交时)。它应该放在 .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": "[email protected]"
}
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")
回答by Anders Waldenborg
Use the PRE-RECEIVE hook (see githooks(5)for details). There you get old sha and new sha for each ref updated. And can easily list the changes and check that they have proper author (git rev-list --pretty=format:"%an %ae%n" oldsha..newsha).
使用 PRE-RECEIVE 钩子(有关详细信息,请参阅githooks(5))。在那里,您会为每个 ref 更新获得旧 sha 和新 sha。并且可以轻松列出更改并检查它们是否具有正确的作者(git rev-list --pretty=format:"%an %ae%n" oldsha..newsha)。
Here is an example script:
这是一个示例脚本:
#!/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$
# ^[email protected]$
#
# 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
回答by mrts
We use Gitlab and so it makes sense for us to validate authors against Gitlab group members.
我们使用 Gitlab,因此我们可以根据 Gitlab 组成员验证作者。
The following script (based on @dsvensson's answer) that should be installed as pre-receive hook does exactly that:
应该作为预接收钩子安装的以下脚本(基于@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()
See GitLab custom Git hooks docsfor installation instructions.
有关安装说明,请参阅GitLab 自定义 Git 挂钩文档。
Only get_gitlab_group_members()is Gitlab-specific, other logic applies to any pre-receive hook (including handling branch deletions and creations).
只有get_gitlab_group_members()Gitlab 特定,其他逻辑适用于任何预接收挂钩(包括处理分支删除和创建)。
The script is now available in GitHub, please feel free to send pull requests for any mistakes/improvements.
该脚本现已在 GitHub 中可用,请随时发送任何错误/改进的请求请求。
回答by Armin Ronacher
What you could do is create a bunch of different user accounts, put them all in the same group and give that group write access to the repository. Then you should be able to write a simple incoming hook that checks if the user that executes the script is the same as the user in the changeset.
您可以做的是创建一堆不同的用户帐户,将它们全部放在同一个组中,并授予该组对存储库的写访问权限。然后您应该能够编写一个简单的传入钩子来检查执行脚本的用户是否与变更集中的用户相同。
I've never done it because I trust the guys that check code into my repositories, but if there is a way, that's probably the one explained above.
我从来没有这样做过,因为我相信那些将代码检查到我的存储库中的人,但如果有办法,那可能就是上面解释的方法。
回答by davetron5000
git wasn't initially designed to work like svn with a big central repository. Perhaps you can pull from people as needed, and refuse to pull if they have their author set inaccurately?
git 最初并不是为了像 svn 那样使用大型中央存储库而设计的。也许您可以根据需要从人们那里拉取,如果他们的作者设置不准确,则拒绝拉取?
回答by webmat
If you want to manage rights to an internet facing git repo, I suggest you look at Gitosisrather than whipping up your own. Identity is provided by private/public key pairs.
如果您想管理面向 Internet 的 git repo 的权限,我建议您查看Gitosis而不是创建自己的。身份由私钥/公钥对提供。
Read me pimping it here, too.
也请阅读我在这里拉皮条。

