Git和权限

9
因此,这似乎是一个常见的问题,并且有很多临时解决方案,但我想了解为什么git通常是这样构建的。
问题:我克隆一个文件权限设置不同的存储库,立即git状态显示我的大量文件已经“更改”,由于权限不同。正如我所提到的,我不是在寻找临时修复或更改我默认的Linux权限方式,而是想了解为什么Git会这样做以及问题的潜在根源在哪里。
例如,对于我尚未提交的任何其他更改,我可以执行git checkout来还原更改,但是当我执行此操作时,它对文件的权限没有任何更改。如果Git实际上正在跟踪我的权限并将权限更改视为文件更改,那么为什么我不能执行git checkout以便恢复最初的权限?如果Git正在跟踪权限,除了使我能够更改我的权限并使克隆或fork我的存储库的其他人创建具有相同权限的文件外,还有什么目的?
我猜我的问题归结为:如果Git将权限更改视为文件更改进行跟踪,为什么Git不让我使用任何用于确保我的项目与其他合作者的权限一致的常规命令,就像它处理内容一样?为什么我需要通过临时修补程序避免每次提交的人具有不同的默认文件权限设置时填充我的存储库与文件权限更改提交?如果这是一个生产项目,我们该怎么办才能使权限更改提交实际进入项目?例如,假设我们想限制一个文件,以便只有组可以在生产中读取它,为什么开发人员不能进行此更改并像履行项目的任何其他要求一样提交/推送/拉取请求?顺便说一下,这都是在Linux上进行的,因此我不讨论从不同文件系统提交。

2
我认为问题不在于git。如果更改与权限有关,则问题可能出现在底层文件系统以及它的挂载方式上。当我在Windows上工作时,我遇到过这种问题,我使用git for windows检出了一个项目,然后我用cygwin中的git进入了该项目(或反之亦然)。 - eftshift0
1个回答

11

Git只为文件保留一个权限位。大部分情况下,Git仅存储文件 - 它不存储目录(或文件夹,如果您更喜欢这个术语),它只是在需要时创建它们。虽然Git存储符号链接,但符号链接没有关联的权限 - 至少在Git中没有(通常在操作系统中也没有)。

更具体地说,当Git存储文件时,它使用“模式”存储它。该模式是100644100755。此模式条目进入索引 - Git用它来构建下一个提交的东西。您的工作树中的文件(您可以看到和使用的文件)将使用chmod系统调用设置为可执行或非可执行,前提是您的操作系统和文件系统实际支持chmod操作。

GIt设置这些模式位 - 如果可以的话 - 根据您的umask设置+ x位,如果您在Unix或Linux类型系统上。umask告诉系统不要设置哪些位:umask 002表示文件为rwxrwxr-xrw-rw-r--,因为002被清除。umask 007表示文件为rwxrwx---rw-rw----,因为007被清除:我们去掉“其他”读、写和执行权限。(三个字段是“所有者”,“组”和“其他”,其中4 =读取,2 =写入,1 =执行。)

因此:索引保存+ x或-x位,通过存储mode100755(+x)或100644(-x)。这对于包括Windows在内的所有系统都成立。与此同时,工作树保存操作系统和文件系统允许的任何内容。在Windows上,通常什么也没有。

如果工作树中没有任何内容,则Git:

  • 在创建存储库时做出记录,并
  • 只保留索引中存储的模式。

如果存储在索引中的模式来自某个现有提交 - 这很常见 - 那么它可能是正确的,Git应该将其保持不变,因此它就这样做了。

新增加到索引的文件(我认为,我没有测试过也不运行Windows)会以100755模式添加,以防万一,但你可以使用git update-index --chmod=+xgit update-index --chmod=-x进行更改:+x表示100755-x表示100644。但如果工作区持有有用的模式位(例如您可以在工作区运行chmod +x somefilechmod -x somefile来更改somefile的执行权限),那么Git会在创建仓库时记录这个信息,并且现在git add将会把这个+x-x状态复制到索引中的100755100644设置中。同时,git checkout会根据需要更新存储在工作区中的实际模式。
很久以前,Git存储了更多的位。但后来发现这是一个错误,并进行了更改,现在只存储644或755模式。(开头的100表示文件,剩余的位是Linux风格的权限:644表示rw-r--r--,而755表示rwx-r-x-r-x)。虽然还有一些内部的树对象具有包含100664mode行的库,但git fsck秘密地允许一些额外的模式。
如上所述,Git在运行git init(或git clone,它在内部运行git init)时探测实际文件系统。也就是说,Git正在创建一个新的仓库。这个新的仓库需要知道:如果我设置文件的可执行位,操作系统是否会正确地记住它? 因此,Git实际上在OS提供的文件系统上设置或清除文件的可执行位。2 如果设置和/或清除“粘住了”,Git就知道操作系统可以正确地处理可执行位。
如果操作系统正确处理了+x和-x,Git将在新存储库中设置`core.filemode`为`true`。如果操作系统没有正确处理+x和-x,则Git将在新存储库中设置`core.filemode`为`false`。
之后,Git将咨询`core.filemode`以了解操作系统的`chmod`是否在工作树上实际正常工作。如果您将存储库从一个文件系统移动到另一个文件系统,则记录的`core.filemode`可能不正确。在这种情况下,您可以手动调整`core.filemode`。
如果某个同事或同僚的文件系统不能正确处理`chmod`,并且该同事不正确地调整了自己的`core.filemode`,那么该同事将创建具有错误模式条目的新提交。这是无法更改 的。您可以删除错误提交并添加一个好的替代提交(伴随着一些麻烦),也可以在下一个提交中修复模式,并不必担心它,但必须让同事或同僚停止这样做。
如果你有一个同事无法停止这样做,而且权限与你无关,你可以故意欺骗自己的Git。只需将`core.filemode`设置为`false`,以便忽略操作系统中正确跟踪的`chmod`设置。这不是一个好的解决方案,只是一个解决办法,直到您可以教育那些将虚假模式位放入存储库中的人。
此文件是Git正在为新存储库构建的`.git / config`文件。该测试也可以在编译时禁用:也就是说,某人可以构建一个Git,假设chmod不起作用,并将core.filemode设置为false。

1
非常感谢您的详细回复,这很有道理! - zachvac

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