防止git pull时覆盖文件所有者

11

我在这里看到了一些类似的问题,但是给出的解决方案似乎都不起作用...想知道它们是否过时,或者这种情况是否有所不同...因此我想开一个新线程来讨论一下。

我遇到了一个令人沮丧的问题,在每次执行 git pull 后,它会将所有权更改为拉取者的用户。然后会显示以下错误:

Warning:file_get_contents(/var/www/html/wp-content/themes/<my-theme>/resources/views/<changed-file>):failed to open stream: Permission denied in /var/www/html/wp-includes/class-wp-theme.php on line 1207

只能通过在更改的文件上运行chown www-data 来修复。

当更多人开始在网站上工作时,或者重要文件被更改(如默认模板/header/footer..),就会成为一个问题,网站会变空白直到运行 chown 命令。


网站详细信息

Laravel,wordpress,ubuntu 18,armor hosting

Git repo 存储在自定义主题中


我尝试了一些解决方案,但是似乎没有任何一个起作用(也许是因为实施方式不正确...)

我尝试过的解决方案

1:将 filemode 设置为 false - 我在本地机器和相关服务器上将 filemode 设置为 false。我也尝试将其更改为 "fileMode"。

2:实现 post-update 钩子 - 我添加了一个 post-update 钩子来自动更新文件权限/所有权。以下是脚本(请注意,git repo 存储在自定义主题中):

#!/bin/sh

# default owner user
OWNER="www-data:www-data"

# changed file permission
PERMISSION="664"

# web repository directory
REPO_DIR="/var/www/html/wp-content/themes/quorum-theme"

# remote repository 
REMOTE_REPO="origin"

# public branch of the remote repository
REMOTE_REPO_BRANCH="master"

cd $REPO_DIR || exit
unset GIT_DIR
files="$(git diff-tree -r --name-only --no-commit-id HEAD@{1} HEAD)"
git merge FETCH_HEAD

for file in $files
do
  sudo chown $OWNER $file
  sudo chmod $PERMISSION $file
done

exec git-update-server-info

如果有其他值得尝试的内容,或者您注意到我的代码存在问题,请告知我...

祝一切顺利,

Jill


作为总结,您是否有一个存储库,在其中执行git pull时,更改文件夹/文件权限? - JRichardsz
@JRichardsz,是的,完全正确。 - Jillian Hoenig
你解决了你的问题吗? - JRichardsz
3个回答

9

你已经接近正确的解决方案了。

你需要启用以下的钩子:

  • post-merge,在成功执行 git pull 后调用
  • post-checkout,在成功执行 git checkout 后调用

如果你确定只使用 git pull,那么 post-merge 钩子就足够了。
启用两个钩子可以保证无论什么情况都会被调用,而不会增加额外的成本。

钩子的内容应该像这样:

#!/bin/sh

# default owner user
OWNER="www-data:www-data"

# web repository directory
REPO_DIR="/var/www/html/wp-content/themes/quorum-theme"

echo
echo "---"
echo "--- Resetting ownership to ${OWNER} on ${REPO_DIR}"

sudo chown -R $OWNER $REPO_DIR

echo "--- Done"
echo "---"

该脚本将重置REPO_DIR目录下的所有文件和目录的所有权为OWNER
我已经复制了您帖子中的值,最终根据您的需求进行更改。
要启用钩子,您应该:
  • 创建名为post-merge的文件,并使用上述脚本。
  • 将其移动到您存储库的.git/hook/目录中。
  • 使用chmod +x post-merge命令赋予其可执行权限。
如果您的用户不是root,请注意执行sudo git pull。目标目录中的所有文件和目录都归www-data所有,您需要以超级用户特权执行git pull命令,否则命令将失败。
请为post-checkout钩子重复执行这些步骤,该钩子需要与post-merge钩子相同。

非常感谢 - 这个答案很有效。感谢您让您的回复清晰简洁。包含post-checkout hook也是一个很好的捕捉..我没有想到,但它将在未来节省我的时间,当我最终遇到它时。 - Jillian Hoenig

3

从你提问的情况看,似乎你正在使用 git pull 进行生产部署。

git 不是一个用于部署的工具。如果你想要部署你的代码,我建议你编写一个部署脚本。

你的脚本第一个版本可以是:

# deploy.sh

# cd to the appropriate directory :
cd /var/www/mysite

# change to the correct user before pulling :
sudo -u www-data git pull

更新后的方法是停止依赖 git pull

理想情况下:你希望能够确定可部署到生产环境的代码版本,并且不依赖于“git pull 可以正常工作而不触发合并冲突”的事实。

以下是您可以遵循的通用工作流程概述 :

当您想要部署到生产环境时:

  1. produce some artifact that packs your code from an identified commit : for php code this can be a simple .tar.gz

    # set a clearly identifiable tag on target commit
    git tag v-x.y.z
    
    # create a tar.gz archive that stores the files :
    # look at 'git help archive'
    git archive -o ../myapp-x.y.z.tgz v-x.y.z
    
  2. push that artifact your production server

    scp myapp-x.y.z.tgz production-server:
    
  3. run your deployment script, without calling git anymore :

    # deploy.sh :
    #   usage :   ./deploy.sh myapp-x.y.z.tgz
    
    archive="$1"
    
    # extract the archive to a fresh folder :
    mkdir /var/www/mysite.new
    tar -C /var/www/mysite.new -xzf "$archive"
    
    chown -R www-data: /var/www/mysite.new
    
    # replace old folder with new folder :
    mv /var/www/mysite /var/www/mysite.old
    mv /var/www/mysite.new /var/www/mysite
    

在部署时,您通常需要管理一些额外的操作:

  • 在部署之前备份您的数据库
  • 处理配置参数(复制生产环境的配置文件?设置环境?...)
  • 执行迁移操作
  • 重新启动 Apache 或 Nginx 服务
  • ...

您可能需要将 deploy.sh 脚本与您的项目一起进行版本控制。


3
您的问题是“如何防止git更改所有者?”,这个答案技术上并不是您问题的直接回答。直接回答是:当git创建一些文件时,它是使用当前用户进行操作的。在拉取之前切换到预期的用户,例如sudo -u www-data git pull - LeGEC
2
我想指出,没有理由不使用git进行部署:https://security.stackexchange.com/questions/45452/is-using-git-for-deploying-a-bad-practice - online Thomas
实际上,www-data用户通常是一个非登录用户,只用于运行Web服务守护程序(如nginxphp-fpmhttpd),因此您不能使用sudo -u www-data - Willis

0

我的方法适合我。

首先,在/path/to/your_project/.git/hooks/中添加一个名为post-merge的文件。

cd /path/to/your_project/.git/hooks/
touch post-merge

然后,将其所有权更改为与<your_project>文件夹相同(这与nginxphp-fpm运行程序相同),在我的情况下,我使用www:www

sudo chown www:www post-merge

然后将其文件模式更改为775(然后可以执行)

sudo chmod 775 post-merge

然后将下面的片段放到post-merge中。要理解这个片段,请参见这里(实际上那是我)。

#!/bin/sh

# default owner user
OWNER="www:www"

# changed file permission
PERMISSION="664"

# web repository directory
REPO_DIR="/www/wwwroot/your_project/"

# remote repository
REMOTE_REPO="origin"

# public branch of the remote repository
REMOTE_REPO_BRANCH="master"

cd $REPO_DIR || exit
unset GIT_DIR
files="$(git diff-tree -r --name-only --no-commit-id HEAD@{1} HEAD)"

for file in $files
do
  sudo chown $OWNER $file
  sudo chmod $PERMISSION $file
done

exec git-update-server-info

一切都完成了,现在回到你的项目文件夹

cd /path/to/your_project/

在你的项目文件夹下运行git pull命令,记得要以root或sudo身份运行(我记得是sudo)。
sudo git pull

现在检查从远程仓库拉取的新文件,看看它的所有权是否已更改为www:www(如果一切正常,新拉取的文件的所有权应该已更改为www:www)。

这种方法比sudo chown -R www:www /www/wwwroot/your_project/好得多,因为它只更改了新文件的所有权,而不是所有文件!假设我只拉取了2个新文件,如果您更改整个文件夹的所有权,则会耗费更多时间和服务器资源(CPU使用率,内存使用率等),这是完全不必要的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接