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
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.)