Question

Gitolite and a Web-server stored on one server. Directory /var/www/site is clone of repo "site". A Git user consist in group www-data. I have in /home/git/repositories/site.git/hooks/post-update hook:

#!/bin/sh    
unset GIT_DIR
cd /var/www/site && git pull origin master

All worked perfectly, but after "pull" all updated or new files change owner to git:git. I don't know how change owner without privileges of root user. Any suggestions?

I found good approach (post-update):

#!/bin/sh

PATH=/usr/bin:/bin:/sbin:/usr/sbin:/usr/local/bin:/usr/local/sbin:$PATH
PROJECT="projectname"
GIT_URL="http://factory.domain.ru/git"

git update-server-info

if [ ! -f $1 ]; then
    exit 0
fi

while [ -n "$1" ]
do
    REF=`echo $1 | awk --field-separator="/" '{print $2}'`
    if [ $REF = "branches" -o $REF = "heads" ]; then
        BRANCH=`echo $1 | awk --field-separator="/" '{print $3}'`

        if [ ! -d /srv/www/$PROJECT/repo/master ]; then
            mkdir -p /srv/www/$PROJECT/repo
            GIT_SSL_NO_VERIFY=true git clone $GIT_URL/$PROJECT /srv/www/$PROJECT/repo/master
        fi

        if [ ! -d /srv/www/$PROJECT/repo/$BRANCH ]; then
            GIT_SSL_NO_VERIFY=true git clone -b $BRANCH $GIT_URL/$PROJECT /srv/www/$PROJECT/repo/$BRANCH
        else
            cd /srv/www/$PROJECT/repo/$BRANCH
            GIT_SSL_NO_VERIFY=true git fetch origin
            GIT_SSL_NO_VERIFY=true git reset --hard origin/$BRANCH
            GIT_SSL_NO_VERIFY=true git clean -d -f
            GIT_SSL_NO_VERIFY=true git checkout
            GIT_SSL_NO_VERIFY=true git pull
        fi
    fi
    shift
done

And "update":

#!/bin/sh

refname="$1"
oldrev="$2"
newrev="$3"

PROJECT="projectname"

# --- Safety check
if [ -z "$GIT_DIR" ]; then
        echo "Don't run this script from the command line." >&2
        echo " (if you want, you could supply GIT_DIR then run" >&2
        echo "  $0 <ref> <oldrev> <newrev>)" >&2
        exit 1
fi

if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then
        echo "Usage: $0 <ref> <oldrev> <newrev>" >&2
        exit 1
fi

# --- Check types
# if $newrev is 0000...0000, it's a commit to delete a ref.
zero="0000000000000000000000000000000000000000"
if [ "$newrev" = "$zero" ]; then
        newrev_type=delete
else
        newrev_type=$(git cat-file -t $newrev)
fi

BRANCH=`echo $1 | awk --field-separator="/" '{print $3}'`

delete () {
    mv /srv/www/$PROJECT/repo/$BRANCH /srv/www/$PROJECT/repo/$BRANCH.removed_by_git
    rm -rf /srv/www/$PROJECT/repo/$BRANCH.removed_by_git
}

case "$refname","$newrev_type" in
        refs/heads/*,delete)
                # delete branch
                delete
                ;;
        refs/remotes/*,delete)
                # delete tracking branch
                delete
                ;;
esac

exit 0

habrahabr.ru

Was it helpful?

Solution

As @ThiefMaster said, you can't change file ownership like that, but there's a different way to work around the problem.

When you push from some development system (possibly the same system as the deployment system, possibly some other) and are using gitolite for access, you're pushing to ssh://git@server/repo (or some URL variant, but in any case, using ssh to the gitolite server machine, to log in on that server machine as user git—ours are set up to log in as gitolite but based on your question you're using user git). Except for the way the authentication works, though, from the server's point of view, "developer@dev-host pushing to me, user git" is effectively the same as "me, user git, pulling from developer@dev-host". That's why, in your post-receive hook, when you run commands like cd /var/www/site && git pull origin master, the new files are owned by user git: it's user git doing the merge into "his" local repo, and then doing the cd and git pull steps on another repo.

The reason developer@dev-host can ssh in to git@server in the first place is that server's ~git/.ssh/authorized_keys file contains the public-key for developer@dev-host (via gitolite's admin repo and the various magic it applies when you add user keys). So, suppose user git@server has his own ssh key-pair, and let's say that you want /var/www/site to be owned by user www-site. Then if user www-site has a home directory (/var/lib/www-site perhaps) and that home directory has a .ssh/authorized_keys file authorizing user git's key, then user git can ssh in as user www-site. Your post-update hook would then do something like this:

#! /bin/sh

# update running copy on real host
update_master() {
    ssh www-site@server "cd /var/www/site && git pull origin master"
}

# update test copy on test host
update_test() {
    ssh www-site@testhost "cd /var/www/site && git pull origin test"
}

for ref do
    case "$ref" in
    refs/heads/master) update_master;;
    refs/heads/test) update_test;;
    *) ;; # ignore other branches
done

(I added code to recognize two specific branches and do the updates only for those. Note: none of this is tested.)

OTHER TIPS

You can't without granting the user root access - however, you can do so via sudo so he cannot do anything but changing the owner of that folder.

After configuring sudo that way you can simply add sudo chown -R www-data:www-data /var/www/site to the hook.

# su requireduser -c 'git pull origin branch'

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top