Prevent people from pushing a git commit with a different author name?
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.
#!/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")
How to prevent author of Git commit from being changed
Your Git repository is yours. You can do anything you want to it. No one else can stop you, and you cannot stop anyone else from doing anything they want to their repositories.
In short, there is nothing—literally nothing—you can to do prevent someone else from claiming to be you, or to prevent yourself from claiming to be someone else. This is the same problem a bank ATM has. In order to make sure you are you, and Fred is Fred, and so on, you must step outside the problem itself and look to authentication. If someone claims to be Fred, how do you know whether he is or is not Fred? Especially, how can you tell whether he's really Fred if you've never met him before? He might be Ravi, or Binyamin, or Jürgen!
If you and Fred have a shared secret, or some other way of deciding whether to believe him, you can use that. And that's all you can do: decide, at the time you are obtaining some set of commits from someone, whether or not you believe them when they tell you they're Fred.
Git has GPG signature verification built in, to some extent (it does not do the GPG signature stuff itself, it relies on third-party software). You can sign individual commits, or sign an annotated tag. For a bunch of good reasons, signing individual commits is usually more cost than benefit. Git commits form a Merkle Tree, so checking the signature of an annotated tag provides a reasonable level of assurance about the commits reachable from that tag. (The amount of protection, however, is not much greater than that of SHA-1.) See also GPG.
How to prevent gerrit from modifying other commits?
I implemented what I need using git pre-push hook.
Here is a content of my .git/pre-push file:
#!/bin/sh
# A hook script to verify what is about to be pushed. Called by "git
# push" after it has checked the remote status, but before anything has been
# pushed. If this script exits with a non-zero status nothing will be pushed.
#
# This hook is called with the following parameters:
#
# $1 -- Name of the remote to which the push is being done
# $2 -- URL to which the push is being done
#
# If pushing without using a named remote those arguments will be equal.
#
# Information about the commits which are being pushed is supplied as lines to
# the standard input in the form:
#
# <local ref> <local sha1> <remote ref> <remote sha1>
AUTHOR=$(git var GIT_AUTHOR_IDENT)
while read local_ref local_sha remote_ref remote_sha
do
commit_author=$(git log -1 --pretty=format:"%ae" $local_sha)
#echo $local_ref $local_sha $remote_ref $remote_sha $commit_author
found=`echo $AUTHOR | grep -c "$commit_author"`
if [ $found == 0 ]
then
echo
echo "REJECTED by local pre-push hook:"
echo "You are trying to push some other's commit: $local_sha $commit_author"
echo "Use --no-verify if you are sure this is not an error"
exit -1
fi
done
echo "Local pre-push verify passed ok"
exit 0
Stop users committing to git as wrong user
Ooops: While this is a valid technique, it assumes you have effectively full control over the server. If you're using a hosted solution all bets are off.
You can validate the author name and email in the repository's update
hook. You can get both values like this:
#!/bin/sh
set -- refname sha1_old sha1_new
author_name=$(git log --pretty=format:%an $sha1_new)
author_email=$(git log --pretty=format:%ae $sha1_new)
The trick, of course, is figuring out whether or not these are valid. Here's one trick:
You can use the command=""
option in your ssh configuration to make a wrapper around git-receive-pack
that maps ssh keys to author information. For example, something like this:
#!/bin/sh
GV_AUTHOR_NAME="$1"
GV_AUTHOR_EMAIL="$2"
export GV_AUTHOR_EMAIL GV_AUTHOR_NAME
eval exec $SSH_ORIGINAL_COMMAND
And you would use an authorized_keys
line something like this:
command="~/bin/gitvalidator 'Lars Kellogg-Stedman' 'lars@seas.harvard.edu'" ssh-rsa ...
The result of all this is that your update
script would have the environment variables GV_AUTHOR_NAME
and GV_AUTHOR_EMAIL
available, and could check these against the commit and exit with an error if they didn't match.
Stop a git commit by a specific author using pre-commit hook
Until v1.7.10.1 (released 2012-05-01), Git did not make --author
information available to Git hooks via environment variables, command-line arguments, or stdin. However, instead of requiring the use of the --author
command line, you can instruct users to set the GIT_AUTHOR_NAME
and GIT_AUTHOR_EMAIL
environment variables:
#!/bin/sh
AUTHORINFO=$(git var GIT_AUTHOR_IDENT) || exit 1
NAME=$(printf '%s\n' "${AUTHORINFO}" | sed -n 's/^\(.*\) <.*$/\1/p')
EMAIL=$(printf '%s\n' "${AUTHORINFO}" | sed -n 's/^.* <\(.*\)> .*$/\1/p')
[ "${NAME}" != root ] && [ "${EMAIL}" != "root@localhost" ] || {
cat <<EOF >&2
Please commit under your own name and email instead of "${NAME} <${EMAIL}>":
GIT_AUTHOR_NAME="Your Name" GIT_AUTHOR_EMAIL="your@email.com" git commit
EOF
exit 1
}
Like the --author
argument, these environment variables control the commit's author. Because these environment variables are in Git's environment, they're also in the environment of the pre-commit
hook. And because they're in the environment of the pre-commit
hook, they're passed to git var GIT_AUTHOR_IDENT
which uses them like git commit
does.
Unfortunately, setting these variables is much less convenient than using --author
. If you can, upgrade to v1.7.10.1 or later.
Related Topics
Distinguish .Shstrtab and .Strtab in Elf File
New Scala Worksheets Not Evaluated in Eclipse
Linux Task Schedule to Hour, Minute, Second
How to Find a List of Ip Addresses in Another File
Svn Checkout the Contents of a Folder, Not the Folder Itself
Must My Pidfile Be Located in /Var/Run
How to Recover After Deleting the Symbolic Link Libc.So.6
Linux - Understanding the Mount Namespace & Clone Clone_Newns Flag
Ssh Error When Executing a Remote Command: "Stdin: Is Not a Tty"
A Modification to %Esp Cause Sigsegv
Bash: Best Architecture for Reading from Two Input Streams
How to Connect a Shell to a Pseudo Tty
Bash Foreach Loop Works Differently When Executed from .Sh File
What Is Preemption/What Is a Preemtible Kernel? What Is It Good For
Getting Stty: Standard Input: Inappropriate Ioctl for Device When Using Scp Through an Ssh Tunnel