如何在Git中为文件添加chmod权限?

388

我希望在git commit一个.sh文件后,当我在另一个服务器检出该文件时,它是可执行的。

有没有办法在不手动在检出文件的服务器上运行chmod u+x命令的情况下实现这一点?

4个回答

637
根据官方文档,你可以使用update-index子命令设置或删除任何被追踪文件的“可执行”标记。
要设置该标记,请使用以下命令:
git update-index --chmod=+x path/to/file

要删除它,请使用:

git update-index --chmod=-x path/to/file

底层原理

虽然看起来像是普通的 Unix 文件权限系统,但实际上不是这样的。Git 在其内部存储中为每个文件维护了一个特殊的“模式”:

  • 100644 表示普通文件
  • 100755 表示可执行文件

你可以使用 ls-file 子命令,并带上 --stage 选项来可视化它:

$ git ls-files --stage
100644 aee89ef43dc3b0ec6a7c6228f742377692b50484 0       .gitignore
100755 0ac339497485f7cc80d988561807906b2fd56172 0       my_executable_script.sh

默认情况下,当您将文件添加到存储库时,Git 将尝试遵守其文件系统属性并相应地设置正确的文件模式。您可以通过将core.fileMode选项设置为 false 来禁用此功能:

git config core.fileMode false

故障排除

如果在某个时刻Git文件模式未设置,但文件具有正确的文件系统标志,请尝试删除模式并重新设置:

git update-index --chmod=-x path/to/file
git update-index --chmod=+x path/to/file

奖金

从Git 2.9开始,您可以在一个命令中暂存文件并设置标志:

git add --chmod=+x path/to/file

当我对test.sh执行此操作以进行测试,git commit和push,并在另一个服务器中checkout时,该文件的权限如下:-rw-rw-r-- 1 user user 12 Dec 5 11:42 test.sh。 - Henley
我本地使用的是git版本1.9.5,而服务器上执行checkout操作的git版本为1.7.1。 - Henley
刚刚尝试在另一台(较旧的)安装有git 1.7.10的服务器上进行克隆,它仍然可以正常工作,该文件具有x权限。也许您在某个时候犯了一个错误,或者您在远程服务器上克隆的用户存在权限问题。 - Antwane
1
请注意,您只能更改(设置或清除)执行权限。Git 不跟踪任何其他权限(如读取或写入权限)。 - Dan Anderson
1
如果在提交命令中使用“.”(git commit -m“bla-bla” .),它将无法正常工作。 - Alexander Samoylov
显示剩余2条评论

52

安特万的回答是正确的,这应该是一条评论,但评论没有足够的空间并且不允许格式化。 :-) 我只想补充一点,在Git中,文件权限仅以644755(拼写为100644100755; 100部分表示“常规文件”)记录:

diff --git a/path b/path
new file mode 100644

前者——644——表示该文件不应该被执行,而后者表示它应该被执行。如何在您的文件系统中实际转换成文件模式有些依赖于操作系统。在类Unix系统中,这些位通过您的umask设置传递,通常为022,以从“组”和“其他”中删除写入权限,或者为002,仅从“其他”中删除写入权限。如果您特别关注隐私并希望从“组”和“其他”中移除读取、写入和执行权限,则可能还是077


1Git的极早期版本保存了组权限,因此某些存储库中有带有664模式的树条目。 现代的Git不再这样做,但由于任何对象的任何部分都永远不能更改,因此这些旧权限位仍然存在于旧树对象中。

只存储0644或0755的更改是在提交e44794706eeb57f2中进行的,该提交在Git v0.99之前,并于2005年4月16日发布。


早期版本的Git,有没有确切的受影响版本? - user5359531
2
@user5359531指的是提交e44794706eeb57f2ee38ed1604821aa38b8ad9d2之前的版本,即早于Git版本0.99。 - torek
也许尝试重新上传 Git 仓库。 - jahantaila
这是否意味着出于历史原因,磁盘上的git数据结构实际上有存储完整Unix文件模式的空间? - Johan Boulé
1
@JohanBoulé:是的,每个树条目中的“mode”部分都是八进制数字格式,没有前导零。 - torek

7

在Linux上,不要忘记

set sudo chmod +x /path/to/file

在本地进行git更新时,否则git将始终将索引返回到本地机器默认设置的644!

在Windows Powershell中,您可以使用以下命令:

icacls .\path\to\file /grant Everyone:F

在PowerShell中,您可以执行icacls .\path\to\file /grant Everyone:F - H0R5E
@H0R5E 谢谢你的建议,我会将其作为编辑提供在我的答案中。 - Kashkashio
edit suggested as requested! - H0R5E
2
注意:令人烦恼的是,Windows用户组是本地化的,因此“Everyone”可能无法使用。您可以使用icacls build.sh /grant *S-1-1-0:F代替,请参见https://learn.microsoft.com/en-us/windows/security/identity-protection/access-control/special-identities查找其他组SID。 - yyny
1
在 Mac 上,我必须先在本地文件系统上设置“chmod +x /path/to/file”,然后才能使用“git add --chmod=+x filename”将其更改为 git 索引。否则,git 索引会被重置为不可执行状态。 - Flavio Caduff
显示剩余2条评论

7

要将代码库中所有文件设置为可执行状态:

git ls-files --stage |grep 100644 | cut -f2 | xargs -d '\n' git update-index --chmod=+x

要取消所有文件的可执行标志,请执行相反操作。
git ls-files --stage | grep 100755 | cut -f2 | xargs -d '\n' git update-index --chmod=-x

如果您想将所有的.sh脚本设置为可执行文件,也许以下方法适合您:

git ls-files --stage | grep  ".sh$" | cut -f2 | xargs -d '\n' git update-index --chmod=+x

4
希望没有叫做 100644100755 的文件 ; ) - milahu

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