问题
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 myselfThe 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!
回答1:
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 the exec
command to open another file descriptor, and then pipe that into a file:
exec 4> $my_file #Opening my_file for writing
echo "This is going to $my_file" >&4
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 use file://
even if I'm the only one using the repository. The svnserve
process is pretty simple to use and it's fairly lightweight.
Also, never use svn
in hook scripts. Use svnlook
instead.
Addendum
I want to be very, very clear on this. We need to agree with some definitions:
- The SERVER is the machine which is running the Subversion repository. You used the command
svnadmin create foo
to create afoo
directory that will act as the repository itself. - The REPOSITORY DIRECTORY is the directory on the server created by the
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. - The WORKING DIRECTORY is the directory you've done a
svn checkout
to checkout a particular revision of your project. - The REPOSITORY is the VIRTUAL view of the REPOSITORY DIRECTORY you get when you use the various
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 called hooks
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 running httpd
or the svnserve
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.
回答2:
Have you tried using an output file somewhere else, like /tmp
? It sounds like you're trying to write back to your working copy directory, so maybe the hook script doesn't have access there?
Note that the hook will run as whatever user the SVN server process is running under, not the SVN client. So if you're using Apache WebDAV type access, it will be the user of Apache (I think); if using SSH access, it is the user listed in the svn+ssh://user@path
syntax;
回答3:
modified the hooks/pre-commit.tmpl file and now it looks like
The pre-commit hook needs to be named just pre-commit. The pre-commit.tmpl is just an example file and will never be run.
回答4:
After reading your question, I am feeling a bit confusing. I was here just to make sure your understanding is correct:
There is no such thing as "checked out repo" in Subversion. We have repo (normally in a remote server), and after we checked out from that repo, we have a local working copy. Hooks is something happening in the repository, not local working copy.
From your descriptions of steps, this is what I get:
checked out from a remote repository: remote server
Since the checked out working copy doesn't have any content, I created a new svn repo locally and copied over everything including the /hooks folder to my checked out working copy.
I created an empty file in the checked out working copy and added a line of text. Then svn add this file.
modified the hooks/pre-commit.tmpl file in the working copy and now it looks like: (removed)
add execute permit to all users and copy the pre-commit.tmpl to pre-commit (these are all happening in the working copy)
in the checked out working copy I committed the changes using: svn commit -m "dumb change"
If my understanding is correct, you have simply misunderstood the use of hook. Hook is something put in the repository, not working copy. Hook runs on the repository machine when you are committing (or doing other actions), not on your local machine.
回答5:
copy from the tmpl and add exec to the hooks script, just like below
cp post-commit.tmpl post-commit
chmod +x post-commit
来源:https://stackoverflow.com/questions/14966807/svn-hooks-not-working