Joshua Jensen <jjensen@xxxxxxxxxxxxxxxxx> wrote: > I've recently asked whether there was a public script to act as an > automatic 'maintainer', something akin to Gerrit's push always > succeeding without having to pull first when using Git as a central > repository. I received a number of suggestions, and I have begun trial > implementations. > > My current line of thought has an auto-merging script that monitors the > refs/for/ namespace (similar to Gerrit) and then applies --no-ff merges > to the appropriate branch. For instance, when the user pushes to > refs/for/master, the post-receive hook creates a secondary ref called > refs/for/master-SHA1-timestamp and then deletes the refs/for/master ref: > > #!bin/sh > # post-receive hook > while read oldrev newrev ref > do > case $ref in > refs/for/*) > timestamp=`date +%s` > `git update-ref $ref-$newrev-$timestamp $newrev` > `git update-ref -d $ref` FWIW, you don't need `` around the git update-ref calls, because you aren't using the output of the command as input to another command. > If you'll pardon my lacking shell script skills (I'm open to learn!), my > primary question concerns safety. When receiving a ref via an SSH-based > server (which happens to be Gitolite, but I don't think that is relevant > here), is the post-receive hook guaranteed to be run in a lockstep > manner? No. If there are two concurrent pushes occurring, the script may execute in parallel. But you'll actually get something much worse. receive-pack will create refs/for/master for the first user... and then might be put to sleep while another user's receive-pack starts. That second user will see refs/for/master existing, and will fail their push because their concept of $newrev doesn't match what is currently at refs/for/master. Then the first user wakes up, runs your post-receive, and the ref is cleared. The better strategy would be to use an update hook that refuses to permit the creation of refs/for/master: #!/bin/sh ref=$1 old=$2 new=$3 case $ref in refs/for/*) timestamp=`date +%s` git update-ref $ref-$new-$timestamp $new echo "Created $ref-$new-$timestamp" exit 1 ;; *) exit 0 ;; esac By exit 1 here we refuse the push attempt, so receive-pack won't create refs/for/master, and another user pushing won't see that false failure. However, unlike with Gerrit, every user is now going to receive a push failure message because the hook has appeared to reject the value, even though it accepted it. > That is, if two people push to 'refs/for/master' at the same > time, is there a lock to process one user and then the other user? There is, but only for the duration of the update hook. So if you used an update hook instead, one user would succeed with the push and the other would get a lock failure, and would need to retry. > Before I go too much deeper down this path, am I way off base here? I'd have to ask why you are using gitolite and trying to abuse git-receive-pack to do something that Gerrit does out of the box... -- Shawn. -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html