It’s been a while since I posted something geeky, so here goes. I’ve been playing with Git, everybody’s new favorite RCS, these last couple of days. Setting up an SSH-enabled Git repository is really easy, but it kind of introduces some redundancy. Let’s try and sort it out.
If you’re using Gitosis with a single Git user, don’t bother reading this article. In my particular scenario, I have SSH login already set up using LDAP and
git-shell, and I want to make sure that the logged in user is also the author of the Git objects being pushed.
Why this requirement? Our students, who have LDAP accounts, will be allowed—nay, required—to use the Git repository for a project. They will be doing so in groups, so it is imperative that we keep a close eye on who’s been committing what. Obviously, we want Git logs to reflect that. Sure, we could use public keys, but I think a password login is easier for most guys; I can always set up GPG later if needed.
So, if you thought
git could talk to
sshd, or even forcibly copy the
$USER variable, guess again. As crab helped me understand on #git, a
git push is basically a request to copy objects to the repository, and there is no way to change the commit. It’s kind of annoying, but makes total sense.
There’s a nice alternative, however. By setting up a
pre-receive hook, we can inspect commits and refuse them if their contents aren’t to our liking. So we just create
hooks/pre-receive in the repository directory, fill it with the code below, and make it executable.
#!/bin/bash mismatch=0 while read old new ref; do author=`git show --pretty=format:%an $new | head -1` if test "$USER" != "$author"; then echo echo "ERROR: Invalid user data on object $new:" echo " Expecting \"$USER\", got \"$author\"" mismatch=1 fi done if test $mismatch -eq 1; then echo echo "Please run the following commands and try again:" echo "> git config user.name \"$USER\"" echo "> git config user.email \"<your-email>\"" echo "> git commit --amend --author=\"$USER <your-email>\"" echo fi test $mismatch -eq 0
The additional commit is necessary, since the configuration will only apply to future commits. If the user leaves it out, he’ll just get the same error. The last line makes sure the exit status of the script tells Git what to do.
Also note that, in our case,
$USER contains the student’s full name, making it an excellent value for the
user.name option. If the user’s name is stored somewhere else, you’ll need to introduce some mapping code.