I have a server repository of branch and trunk. The branch is all team members' repositories. I'm trying to use svn hooks
only in my repo under branch, but it doesn't seem to work fine. In the following are the steps I tried to approach:
-
checked out
my_repo
from the remote server'sbranch/my_repo
-
since the local repo
my_repo
doesn't have any content, I created a new svn repo locally and copied over everything including the/hooks
folder tomy_repo
. -
I created an empty file in
my_repo
and added a line of text. Thensvn add
this file. -
modified the
my_repo/hooks/pre-commit.tmpl
file and make it always not pass with error code 1. Now it looks like:
#!/bin/sh exit 1
-
copy the
pre-commit.tmpl
to pre-commit and add execute permit of pre-commit to myself -
The server contains other people's now the server's structure is like:
- server - branch - my_repo - myfile - hooks - pre-commit - Tom's repo - other team member's repo - trunk
- in the checked out repo I committed the changes using:
svn commit -m "dumb change"
Now from here I should not be able to commit and it should give me an error with code 1 right? But I don't see it anywhere.
- Then I tried putting the hooks folder at the top level and at same level as branch and trunk. i.e. the structure looks like:
-server - branches - my_repo - myfile - Tom's repo - other team member's repo - trunk - hooks - pre-commit
But, still not working. sigh…
HOWEVER, with David's help, I figured out what to do and what was wrong:
1. To highlight: the ownership of the hooks folder should be the same as who created to repository. Thus I had to ask the owner to add the hooks files to the server. I didn't create the repository on the server, thus the files are invisible in my working directory.
2. now here's what I tried:
1) on my own Linux system, I `svnadmin create` a new repository, maybe called test_server: in that there is folders: confs, db, hooks, locks; files: format, readme.txt 2) on the same level, mkdir a new folder (called working_dir) as your local working directory and checkout from the test_server. Now the working_dir contains a folder called test_server and it's empty. You can't see any of the folders or files in step 1 3) modify the test_server's hooks file as described above. 4) try to add a file and add a new line to the file in the working_dir/test_server folder and commit. 5) now you should see commit failed with message: svn: Commit blocked by pre-commit hook(exit code 1) with no output.
Thank you so much David and anyone put comments earlier!
Best Answer
When you run a hook, the STDOUT (what normally is produced by an
echo
statement) is disabled. This means your script cannot use STDOUT to print out anything, even if it has been redirected to a file.Instead, you need to open another file descriptor instead of using
1
(STDOUT). You can use theexec
command to open another file descriptor, and then pipe that into a file:STDERR is also redirected. The output of STDERR is collected and sent back to the calling client, but only when a hook returns a non-zero exit code. This gives you a way to communicate with the client why a hook failed.
You also must be careful because the environment that the hook runs in is scrubbed. Even
$PATH
is null.These are some of the reasons why a hook script will run fine from the command line, but not when it is executed as a hook.
If you don't believe a hook is working, just set it so it exits with a non-zero exit code. If you get a message back from Subversion that the transaction failed, you know the hook script executed.
I also recommend that you use, at a minimum,
svnserve
to act as a Subversion server -- even if you're the only one using the repository. I never usefile://
even if I'm the only one using the repository. Thesvnserve
process is pretty simple to use and it's fairly lightweight.Also, never use
svn
in hook scripts. Usesvnlook
instead.Addendum
I want to be very, very clear on this. We need to agree with some definitions:
svnadmin create foo
to create afoo
directory that will act as the repository itself.svnadmin create
command. This is the SERVER SIDE of the repository. You will not see any files you've checked into Subversion here. Instead, you will see ahooks
directory and adb
directory. This is what the server uses to track its changes.svn checkout
to checkout a particular revision of your project.svn
commands likesvn ls
orsvn log
orsvn co
. This is NOT the REPOSITORY DIRECTORY but a view of the repository.Okay, now we have this settled:
Hook scripts are stored in the REPOSITORY DIRECTORY under the
hooks
directory. When you create the REPOSITORY DIRECTORY, there will already be a sub-directory calledhooks
with some templates for hook scripts. These will have a*.tmpl
suffix. To make a hook, you need to replace one of these scripts with your hook script, and remove that*.tmpl
suffix. The hook script has to have executable permission and be owned by the user that is running the Subversion SERVER process. (The user runninghttpd
or thesvnserve
command on the server).Hooks are for the entire repository. You can't tell a hook not to fire only when a particular branch is affected. However, your hook script can see where a file is located and take action based upon that. I have a pre-commit hook that does just that. It uses a control file to determine the action it needs to take based upon the location of a file. However, every time a commit happens, this hook will fire even if it doesn't have to do anything.
I hope this answers your questions.