Could you please guide me on how svnlook
is working below. I want to include this in a hook to prevent commits in a tag under /tags
:
$SVNLOOK changed -t "$TXN" "$REPOS" | grep "^U\W.*\/tags\/" && /bin/echo "Cannot commit to tags!" 1>&2 && exit 1
A Subversion pre-commit hook will allow a commit to go through if it returns an exit code of 0
. Otherwise, the pre-commit hook will fail and the commit will not be processed.
The $SVNLOOK changed -t "$TXN" "$REPOS"
will show the changes in $REPOS
that took place in $TXN
. The shell variables must be set by you. If you look at the pre-commit
script that comes with Subversion, you'll see:
$TXN=$1
$REPO=$2
The output of the svnlook changed
command looks like this:
$ $SVNLOOK changed -t $TXN $REPOS
A trunk/vendors/deli/
A trunk/vendors/deli/chips.txt
A trunk/vendors/deli/sandwich.txt
A trunk/vendors/deli/pickle.txt
U trunk/vendors/baker/bagel.txt
_U trunk/vendors/baker/croissant.txt
UU trunk/vendors/baker/pretzel.txt
D trunk/vendors/baker/baguette.txt
The first column is whether something was Uprated, Added, or Deleted. The second column refers to attributes.
The rest is the name of the file that was acted upon. You can see that baguette.txt
was deleted, and that a property on croissant.txt
was changed, but the file itself wasn't updated.
Let's say someone tried to change a tag. The output of svnlook changed
will look like this:
$SVNLOOK changed -t $TXN $REPOS
U tags/4.2.1/vendors/baker/bagel.txt
The grep command is this:
grep "^U\W.*\/tags\/"
This is looking for a line that starts with ^U
meaning it was an update. Then, it looks for a string that begins with /tags
. Hmmm... that might be an issue. It doesn't match the output of the svnlook changed
command.
Maybe it should be:
grep -q "^U.[[\s+tags/"
This will match any string that starts with U
, possibly followed by another character, followed by whitespace, and then immediately the word tags/
.
You might want to verify that expression.
The &&
is a list operator. If the expression on the left side of &&
executes successfully (i.e. it returns a zero exit code), the statement on the right side will be executed. Otherwise, the statement on the right won't be executed.
Thus, if your grep
matches a pattern that looks like someone updated a tag, it will be true. The statement on the right side of the &&
will be executed.
Thus,
/bin/echo "Cannot commit to tags!" 1>&2
will be executed. This is sent to STDERR which will be sent to the Subversion client, but only if the exit code of the pre-commit hook is zero.
Thus the next list operator command exit 1
will execute if the /bin/echo
is successful. (It might not be, but usually will be). With that, the pre-commit hook exits with a non-zero exit code, the hook fails, and the Cannot commit to tags!
will be sent to the SVN client for the user to see.
There is absolutely no reason in the world for this statement to look like this. This is almost equivalent, and is easier to understand:
if $SVNLOOK changed -t $TXN $REPOS | grep -q "^U.[[\s+tags/"
then
/bin/echo "Cannot commit to tags!" 1>&2"
exit 1
fi
exit 0
After all, you need to put this in a shell script called pre-commit
anyway and have the shell variables $SVNLOOK
, $REPOS
, and $TXN
set anyway.
The reason this isn't quite equivalent is that this will fail the commit even if the /bin/echo
fails.
If you are looking for a pre-commit hook to control tags, you should take a look at mine. This has been tested on hundreds of site, and will give you a lot more control over your repository and does better error checking.
This hook uses a control file to control access to the repository. For example, you might want to be able to let yourself change tags if necessary.
[file You are allowed to create a new tag, but you may not make any changes to it]
file = /tags/**
access = read-only
users = @ALL
[file You are allowed to create a new tag, but you may not make any changes to it]
file = /tags/
access = add-only
users = @ALL
[file I can modify and delete tags]
file = /tags/**
access = read-write
users = jazzr
Take a look at the hook. It works with the standard Perl 5.8.8 installation and up. It requires no other modules. However, if you use LDAP or Active Directory for Subversion access control, you can install the Net::LDAP
Perl module and use LDAP or Active Directory groups in your pre-commit hook for access control.