防止 git 在 git 拉取时覆盖文件所有者

Prevent git from overwriting file owner upon git pull

我在这里看到了一些类似的问题,但是 none 给出的解决方案似乎有效...想知道它们是否已经过时,或者这种情况有所不同...所以我想开一个新话题来谈谈它。

我 运行 遇到了一个令人沮丧的问题,每次我执行 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

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

当更多人开始在网站上工作时,或者当重要文件发生更改(默认 template/header/footer..)时,这将成为一个问题,并且网站变为空白,直到 chown 为 运行 .


站点详细信息

Laravel, wordpress, ubuntu 18, 装甲托管

Git repo 存储在自定义主题中


我已经尝试了一些解决方案,但 none 似乎有效,(可能是因为它们实施不正确..)

我试过的解决方案

1: 将 filemode 设置为 false - 我在我的本地计算机和相关服务器上将 filemode 本地和全局设置为 false。我也试过将大小写更改为 "fileMode"。

2: 实现 post-更新挂钩 - 我添加了一个 post 更新挂钩来自动更新文件 permissions/ownership。这是脚本(请注意 git 存储库位于自定义主题中):

#!/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

让我知道是否还有其他值得尝试的事情,或者如果您发现我的代码有问题...

祝一切顺利,

吉尔

您非常接近正确的解决方案。

您需要启用以下挂钩:

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

如果确定只使用git pullpost-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 中复制了这些值,最终将其更改为你的需要。

要启用挂钩,您应该:

  • 使用上面的脚本创建一个名为 post-merge 的文件
  • 将其移至您的存储库
  • 的目录 .git/hook/
  • 给它可执行权限 chmod +x post-merge

最后对 post-checkout 钩子重复这些步骤,它需要等于 post-merge 钩子。

如果您的用户不是 root,请注意执行 sudo git pull。目标目录中的所有文件和目录都属于www-data,您需要以超级用户权限执行git pull命令,否则命令将失败。

从你的问题来看,你似乎正在使用 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 拉取将在不触发合并冲突的情况下工作”这一事实。

这是您可以遵循的通用工作流程的概要:

何时要部署到生产环境:

  1. 生成一些工件,从已识别的提交中打包您的代码:对于 php 代码,这可以是一个简单的 .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. 将工件推送到您的生产服务器

    scp myapp-x.y.z.tgz production-server:
    
  3. 运行 您的部署脚本,不再调用 git :

    # deploy.sh :
    #   usage :   ./deploy.sh myapp-x.y.z.tgz
    
    archive=""
    
    # 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
    

您通常希望围绕部署管理的一些额外操作:

  • 部署前备份您的数据库
  • hanlde 配置参数(复制您的生产配置文件?设置环境?...)
  • 应用迁移操作
  • 重启apache或nginx
  • ...

您可能希望随项目一起对 deploy.sh 脚本进行版本控制。

我的方法适合我。

首先,将名为post-merge的文件添加到/path/to/your_project/.git/hooks/

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

然后,将其所有权更改为与 文件夹相同(这与 nginxphp-fpm 运行ner 相同),在我的例子中,我使用 www:www

sudo chown www:www post-merge

然后把它的文件模式改成775(就可以执行了)

sudo chmod 775 post-merge

然后把下面的片段放到post-merge。要了解该代码段,请参阅 here(实际上就是我)。

#!/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

一切都完成了,现在,回到your_project文件夹

cd /path/to/your_project/

运行 git pull 在 your_project 文件夹下,记住你必须 运行 作为 root 或 sudo(我记得 sudo)

sudo git pull

现在检查从远程仓库拉取的新文件,看看它的所有权是否已经更改为www:www(如果符合预期,新拉取文件的所有权应更改为www:www).

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