22

我对 Git 有疑问。我在 Google 和 StackOverflow 中搜索了解决方案,但没有任何帮助。

问题是,每次 git 更新工作目录中的某个文件时(当我签出分支或合并分支等时),文件权限都会更改,从而添加“可写入组”标志。如果文件可写入分组,我的 apache 会为该文件显示“错误 500”。

示例:我有一个文件 index.php。权限是“-rwxr-xr-x”。当前(活动)分支是主分支。此文件在“开发”分支中更改。我执行“git checkout develop”并且文件 index.php 获得权限“-rwxrwxr-x”(添加了可写到组)。我的网站停止工作。由于 apache 不允许在 php 文件中使用此标志(我不知道为什么,但我无法更改它)。

每次执行“git checkout develop”时,我还需要执行“chmod gw index.php”。我不喜欢执行两个命令(有时我忘记执行这个命令并且我的网站无法正常工作)。

我能做些什么来解决这个问题?我认为这与umask有关。我做了一些我在网上找到的技巧,但没有任何效果。

谢谢。

4

4 回答 4

12

快速回答是这个 shell 函数要放在你的~/.profile. 下面是一个解释。

git(){(umask 0022; command git "$@")}

umask是进程的属性。它是从父进程继承的,以后可以从内部更改。更改 umask 的命令通常也被命名为 umask。

Git 没有用于设置其 umask 的配置选项,它在执行后不会更改其 umask。您必须从外部设置 Git 的 umask,让它从父进程(通常是 shell)继承。

嗯,你似乎不喜欢除了 git 之外的任何东西都改变了 umask 的想法。所以让我们在执行时更改它git

当 shell 执行一行时,它会获取该行的第一个单词并尝试查找该名称的函数。只有在没有时,它才会尝试在PATH. 我上面写的函数名为git,因此 now 的任何直接调用都会git执行它而不是git命令。

该函数执行一个子shell,更改它的umask 并git从子shell 内部执行命令。Git 完成工作后,子 shell 也退出,原始 shell 实例仍将具有原始 umask。

但是,该函数还显示了如何绕过自身。如果您调用gitviacommand git或 even /usr/bin/git,该函数将不会被调用。不过,对于任何体面的用途,这已经足够了。

于 2013-11-04T15:14:40.137 回答
9

允许文件作为二进制文件执行有点危险。无论如何,我用umask解决了这个问题。我的post-receive脚本看起来像:

!/bin/sh
umask 002
GIT_WORK_TREE=/var/www/site git checkout -f

因此,file permissions 设置为664directory permissions设置为775,这非常适合我。

.profilePS在用户文件中设置umaskgit没有效果,我不明白为什么,如果你知道为什么会发生这种情况,请注释掉。

于 2014-08-22T06:53:05.297 回答
4

在使用向后移植的 Xenial 版本 4.x linux 内核在 Ubuntu 14.04 (Trusty) 上通过 NFS 安装的主目录中签出 repo 时,我刚刚遇到了这个问题。将 Git 克隆到本地目录就可以了。更奇怪的是:第二台 Ubuntu 14.04 服务器在同一个挂载目录上没有出现同样的问题。

经过大量的探索后,我能够看到使用 strace git 调用 open() 系统调用来创建每个文件,其中包含选项 O_CREAT、O_WRONLY 和 O_EXCL 以及 0666 模式,但接下来的 syscal 是针对 fstat()该文件并告诉我它是模式 0700 。就我而言,该问题仅影响回购中的某些文件。尽管大多数文件的“git ls-index”显示模式为 0644,但其中一些被正确创建,而另一些则没有;尽管它总是相同的文件在克隆上有错误的权限。

我注意到两个系统之间的内核版本存在差异,然后发现了以下错误:https ://bugs.launchpad.net/ubuntu/+source/linux/+bug/1654288

将内核升级到 4.4.0-98(从 4.4.0-59)为我解决了这个问题。我检查了一些仍在使用版本 3.x Linux Kernel 的主机,这些主机没有问题。

于 2018-02-09T14:30:26.290 回答
1

结帐后使用挂钩更改文件模式可以在问题发生后解决问题。执行钩子时,文件系统中已经存在错误的文件模式。如果请求刚刚在结帐和钩子执行之间到达,服务器将响应 500 错误。但无论如何,您可能对此解决方案感兴趣。

你需要一个在所有必要文件上post-checkout运行的钩子。chmod g-w钩子是.git/hooks/post-checkout, 应该是可执行的,并获取当前HEAD作为第二个参数(shell 中的 $2)。钩子可能如下所示:

#!/bin/bash
git ls-files -z --with-tree="$2" | xargs -0 chmod g-w --

由于钩子没有得到签出的文件列表,这可能是最好的实现。它改变了当前所有文件的模式HEAD

于 2013-11-04T15:52:37.740 回答