Re: Deleting of the specified ref during the post-receive hook

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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


[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]