Git更新文件时更改默认的umask设置

22

我在使用Git时遇到了问题。我在Google和StackOverflow上搜索解决方案,但都没有帮助。

问题是每次Git更新工作目录中的某个文件(当我切换分支或合并分支等)时,文件权限会更改,加上“可写入组”的标志。 如果文件对组可写,则我的Apache会显示“错误500”。

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

每次执行“git checkout develop”时,我需要执行“chmod g-w index.php”。我不喜欢执行两个命令(有时我会忘记执行它,导致我的网站无法工作)。

我该怎么做才能解决这个问题? 我认为这与umask有关。我尝试了一些在网上找到的技巧,但没有任何作用。

谢谢。


1
你有没有什么理由不能适当地设置你的umask(例如设置为0022或类似值)? - CB Bailey
如何做到这一点?如何设置umask?这是系统更改还是仅限于git更改?如果是系统更改,那么我无法更改此设置。 - Roman Gelembjuk
1
只需运行 umask 0022。要将其设置为交互式会话,请将此命令放入您的 .bashrc 或 shell 的等效位置。要始终设置它,请将其放在您的 .profile 中。 - CB Bailey
我不想改变任何系统设置。该网站以此用户运行。我担心这可能会影响其他方面。有没有办法只通过更改git设置来解决这个问题?我知道git中有后置更新钩子(post update hooks),但我找不到如何使用钩子来解决这个问题。 - Roman Gelembjuk
10
这不是一个 git 的问题,而是一个 umask 的问题;如果站点以这个用户身份运行,并且仅当该用户创建的文件不可被组写入时才能正常工作,那么您肯定想要将该用户的 umask 更改为 0022。(.profile用户 设置,不是系统设置。) - CB Bailey
4个回答

12

快速回答是将以下 shell 函数放在您的 ~/.profile 中。下面是解释。

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

umask是进程的一种属性。它从父进程继承,并且可以在之后从内部更改。更改umask的命令通常也被称为umask。

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

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

当Shell执行一行时,它取行上的第一个单词,并尝试找到该名称的函数。只有在没有函数时,才会尝试在PATH中定位具有该名称的命令。上面编写的函数名为git,因此任何直接调用git都会执行该函数而不是git命令。

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

然而,该函数还展示了如何绕过自身。如果您通过command git甚至是/usr/bin/git调用git,则该函数不会被调用。对于任何体面的用途,这已经足够好了。


9

允许文件作为二进制文件执行有一定的危险性。 不过我通过使用umask解决了这个问题。我的post-receive脚本如下:

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

因此,文件权限设置为664目录权限设置为775,这对我来说非常合适。

P.S. 在git用户的.profile文件中设置umask无效,我不知道为什么,请在评论中解释原因。


umask 0022 对于普通的 Web 服务器更有意义,因为只有所有者才有写权限:导致 文件权限 644 和 目录权限 755。 - Laszlo Schürg

4
我在Ubuntu 14.04(Trusty)上使用后备的Xenial版本4.x Linux内核将repo检查到通过NFS挂载的主目录时,遇到了问题。在本地目录中进行Git克隆是没有问题的。更奇怪的是:同样挂载的目录下,第二个Ubuntu 14.04服务器没有展现出同样的问题。
经过大量探索,我使用strace看到git调用open()系统调用以选项O_CREAT, O_WRONLY和O_EXCL创建每个文件,并使用权限0666,但是下一个系统调用是对该文件执行fstat(),并告诉我它的权限为0700。在我的情况下,问题仅影响repo中的某些文件。尽管'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的主机,它们没有遇到这种问题。

2
使用钩子在检出后更改文件模式,可以解决已经发生的问题。执行钩子时,在文件系统中已经存在不良文件模式。如果在检出和钩子执行之间有请求到达,服务器将响应500错误。但是您可能仍然对此解决方案感兴趣。
您需要一个在所有必要文件上运行chmod g-w的post-checkout钩子。该钩子是.git/hooks/post-checkout,应该是可执行的,并将当前HEAD作为第二个参数(shell中的$2)。钩子可能看起来像这样:
#!/bin/bash
git ls-files -z --with-tree="$2" | xargs -0 chmod g-w --

由于钩子没有获取已检出文件列表,因此这可能是最佳实现。它会改变当前HEAD下的所有文件的模式。

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