Git 和权限

Git and Permissions

所以这似乎是一个常见问题,并且有很多临时解决方案,但我想了解为什么 git 通常以这种方式构建。

问题:我克隆了一个文件具有特定权限的存储库,由于权限不同,git 状态立即显示我的大量文件具有 "changed"。正如我提到的,我不是在寻找临时修复或更改我执行默认 linux 权限的方式,我想了解为什么 git 这样做以及问题是。

例如,对于我尚未提交的任何其他更改,我可以执行 git 签出以还原更改,但是当我执行此操作时,不会更改文件的权限。如果 git 实际上在跟踪我的权限并将权限更改视为对文件的更改,为什么我不能执行 git 签出以恢复到初始权限?如果 git 正在跟踪权限,除了让我能够更改我的权限并使其他克隆或分叉我的存储库的人能够创建具有相同权限的文件之外,还有什么目的?

我想我的问题归结为,如果 git 正在跟踪文件更改时的权限更改,为什么 git 不让我使用任何用于确保我的项目与其他协作者的权限是否像内容一样是最新的?为什么每次提交人设置了不同的默认文件权限时,我都需要通过临时绷带来避免我的存储库充满文件权限更改提交?如果这是一个生产项目,我们可以做些什么来使权限更改提交真正进入项目?例如,假设我们想要限制一个文件,以便只有该组可以在生产中读取它,为什么开发人员不能进行此更改和 commit/push/pull 请求,因为他们会满足项目的任何其他要求?这都是关于 linux 顺便说一句,所以我不是在讨论从不同的文件系统提交。

Git 只保留一个文件权限位。在大多数情况下,Git 仅 存储 文件——它不存储目录(或文件夹,如果您更喜欢该术语),它只是按需创建它们。虽然 Git 确实存储符号链接,但符号链接没有关联的权限 — 至少在 Git 中没有(并且通常在 OS 中也没有)。

更具体地说,当Git存储一个文件时,它用"mode"存储它。该模式恰好是 1006441007551 此模式条目进入 index——Git 用于构建 next 提交——以及你的 work-tree 中的文件,这些文件是你可以看到和工作的使用 chmod 系统调用设置为可执行或不可执行,前提是您的 OS 和文件系统实际支持 chmod 操作。

当 Git 设置这些模式位时——如果可以的话——它会根据你的 umask 设置 +x 位,如果你在Unix 或 Linux 类型系统。 umask 告诉系统要设置哪些位 not002 的 umask 意味着文件是 rwxrwxr-xrw-rw-r--,因为 002 得到 清除 007 的 umask 意味着文件是 rwxrwx---rw-rw---- 因为 007 清除: 我们拿走了读取,写入和"other" 的执行权限。 (这三个字段是 "owner"、"group" 和 "other",其中 4 = 读取,2 = 写入,1 = 执行。)

因此:index 通过存储 100755 (+x) 或 [=10 的 mode 来保存 +x 或 -x 位=] (-x)。这在所有系统上都是如此,包括 Windows。同时,工作树包含 OS 和文件系统允许的任何内容。在 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 根据需要更新存储在工作树中的 实际 模式。


1很久以前,Git 存储了更多位。结果证明这是一个错误并已更改,因此现在它只存储 644 或 755 模式。 (前面的100表示file,其余位是Linux式权限:644表示rw-r--r--755 表示 rwx-r-x-r-x。)有一些存储库具有内部 tree 对象,其中 mode 行包含 100664,所以 git fsck 秘密地允许一些额外的模式。


哪里出错了

正如我上面提到的,Git 在您 运行 git init(或 git clone,其中 运行s git init 在内部,或多或少)。也就是说,Git 正在创建一个 new 存储库。这个新的存储库需要知道:如果我在文件上设置可执行位,OS 会正确记住吗?

所以Git实际上设置或清除OS提供的文件系统中文件的可执行位。2如果设置and/or 清除 "sticks",Git 知道 OS 正确处理可执行位。

如果 OS 正确处理 +x 和 -x,Git 会将新存储库中的 core.filemode 设置为 true。如果它 没有 正确处理 +x 和 -x,Git 会将新存储库中的 core.filemode 设置为 false.

稍后,Git 将咨询 core.filemode 以了解 OS 的 chmod 是否真的在工作树。 如果将一个版本库从一个文件系统移动到另一个文件系统,记录的core.filemode可能不正确。在这种情况下,您可以手动调整core.filemode

如果某些同事或同事的文件系统不能正确处理chmod,并且该同事摆弄他或她的core.filemode 错误,该同事将创建具有错误 mode 条目的新提交。 对此您无能为力(好吧,除了教育他们):提交一旦创建,就永远无法更改。您可以删除错误的提交并放入一个好的替代品 - 伴随着随之而来的所有痛苦 - 或者只是在下一次提交中修复模式而不用担心它,但你必须让同事或合作伙伴 -工人停止这样做。

如果您有一个不会停止这样做的同事并且权限与并不真正相关,你可以故意骗自己Git。只需将 core.filemode 设置为 false,这样您自己的 OS 正确跟踪的 chmod 设置就会被忽略。这不是一个很好的解决方案,它只是一种解决方法,直到您可以教育将伪造模式位放入存储库的人。


2此文件是 Git 正在为新存储库构建的 .git/config 文件。也可以在编译时禁用该测试:也就是说,有人可以构建一个 Git 假设 chmod 工作, 并将 core.filemode 设置为 false.