how to control ownership of files auto-pushed to a

2019-03-20 11:36发布

问题:

i created a bare repo @

/srv/repos/test

i set ownership to wwwrun:www with SUID+GUID bits set

chown -R wwwrun:www /srv/repos/hub
chmod ug+s          /srv/repos/hub
ls -ald /srv/repos/test
    drwsrws---+ 10 wwwrun www 4.0K Mar  7 21:28 /srv/repos/hub/

i cloned the repo to a webroot, and changed its ownership,

git clone /srv/repos/hub /srv/www/siteA
chown -R wwwrun:www      /srv/www/siteA

for convenience, I define a remote

cd /srv/www/siteA
git remote add HUB /srv/repos/hub

then create post-commit and post-update hooks to keep things in sync,

vi /srv/www/siteA/.git/hooks/post-commit
    #!/bin/sh
    git push HUB

vi /srv/repos/hub/hooks/post-update
    #!/bin/sh
    cd /srv/www/siteA || exit
    unset GIT_DIR
    git pull HUB master
    exec git-update-server-info

as my normal user, i checkout HUB

whoami
    locuse
cd ~
git clone /srv/repos/hub WORK
ls -ald WORK
    drwxr-xr-x 10 locuse users 4.0K Mar  7 21:44 WORK/

make a change, commit and push,

cd WORK
touch touch_file
ls -al touch_file
    -rw-r--r-- 1 locuse users 0 Mar  7 21:44 touch_file
git add -A
git commit -m "add test"
git push

then checking to see that the hook fired and the update was pushed to the webroot,

ls -al /srv/www/siteA/touch_file
    -rw-rw----+ 1 locuse www 0 Mar  7 21:45 /srv/www/siteA/touch_file

the file's there -- as expected.

but, it's not the user-ownership i want, namely it's user='locuse' not user='wwwrun'.

in this specific use-case, what's the right way to make sure that i, INSTEAD, would always automatically end-up with,

ls -al /srv/www/siteA/touch_file
    -rw-rw----+ 1 wwwrun www 0 Mar  7 21:45 /srv/www/siteA/touch_file

? i.e., everything always gets promoted to /srv/www/siteA only as wwwrun:www .

something in a hook, i'm guessing?

i know i could add

chown -R wwwrun:www /srv/www/siteA

to the post-commit hook, which works fine for a small tree, but bogs at each commit/update down if it's large (which it will be).

perhaps if I could efficiently chown just the current commit ... ?

回答1:

this works,

vi /srv/repos/hub/hooks/post-update
    #!/bin/sh
    cd /srv/www/siteA || exit
    unset GIT_DIR
-   git pull HUB master
+   git fetch HUB master
+   files=`git diff ..FETCH_HEAD --name-only --diff-filter=ACMRTUXB`
+   git merge FETCH_HEAD
+   for file in $files
+   do
+       sudo chown wwwrun:www $file
+   done
    exec git-update-server-info

chown execs on only the files identified as being in the commit set -- small & fast.



回答2:

I had about the same problem and after some research i found that there isn't a solution if you update the bare (HUB) repository through SSH, becouse hooks are executed by the user that connected to the HUB repo (in our case git). If you want to avoid to give chown/chmod permission to git user (security issue), the only solution is to create a cron job to keep updated the repo. I made this script (my first bash script) modifying the old one and adding also an email notification on succesfull update:

#!/bin/sh
# web repository directory
REPO_DIR="/srv/www/siteA"
# remote repository 
REMOTE_REPO="HUB"
# public branch of the remote repository (only this branch well be public accessible trough the web server)
REMOTE_REPO_BRANCH="master"
# email address where receive notification
EMAIL_TO="your@email.com"
# sender email address and name
SENDER_ADDR="sender@email.com"
SENDER_NAME="sender name"
# tmp file that contain email body
TMP_MSG_FILE="emailmessage.txt"

cd $REPO_DIR || exit
unset GIT_DIR
echo "fetching changes..."
git fetch $REMOTE_REPO $REMOTE_REPO_BRANCH
files=`git diff ..FETCH_HEAD --name-only --diff-filter=ACDMRTUXB`
if [[ -n $files ]]; then
echo "changes found for the following file:"
echo ${files[*]}
echo "merging changes"
git merge FETCH_HEAD
echo "sending email"
SUBJECT="GIT: Web Directory Updated"
TMP_MSG_FILE="emailmessage.txt"
echo "following file are been updated/created/deleted: "> $TMP_MSG_FILE
echo ${files[*]} >>$TMP_MSG_FILE
echo "Working directory:" >>$TMP_MSG_FILE
echo "$repo_dir" >>$TMP_MSG_FILE
mutt -e "unmy_hdr from; my_hdr From: $SENDER_ADDR" -e "set realname='$SENDER_NAME' " -s "$SUBJECT" $EMAIL_TO < $TMP_MSG_FILE
else
echo "no changes found"
fi