如何在Git中将已提交的文件标记为只读?

26

我有一个被提交到Git的文件。这个文件需要保存API密钥,但出于安全考虑,我不想将API密钥提交到Git。相反,我在文件中写了如何为每个开发者生成API密钥的说明。

我不希望任何开发人员意外地提交他们的API密钥并覆盖基本文件。

我已经:

  • 将该文件添加到.gitignore文件中,但由于它已经提交了,所以这并没有起作用。
  • 运行了命令git update-index --assume-unchanged myFile.js
  • 将该命令添加到说明文件中,告知其他开发人员他们也应该运行此命令。

然而,我刚换到我的笔记本电脑上,忘记运行命令,并意外地将一个密钥提交到了代码库。我正在寻找一种更可靠的方法。实际上,我想提交文件的初始版本到GitHub,然后禁止修改该文件。

这可能吗?

供参考,该文件看起来像:

define(function () {
    //  The Simple API Access API key is used here.
    //  Please note that I've specifically omitted this key from GitHub for security. 
    //  Feel free to generate your own in order to use YouTube's API: https://code.google.com/apis/console/
    //  A valid key will look something like:
    //  Key for browser apps (with referers)
    //  API key: -------------------------------
    //  Referers: Any referer allowed
    //  Activated on:   Apr 6, 2014 2:46 PM
    //  Activated by:   ------------ – you
    //  NOTE: Please do not commit changes to this file once downloaded. CommandS:
    //  - Disable tracking: "git update-index --assume-unchanged src/js/background/key/youTubeAPI.js"
    //  - Enable tracking: "git update-index --no-assume-unchanged src/js/background/key/youTubeAPI.js"
    var key = 'API_KEY_MISSING';

    if (key === 'API_KEY_MISSING') {
        console.error('YouTube API key is not present.');
    }

    return key;
});

2
使用一些服务器端钩子pre-receiveupdate)检查所涉及文件的哈希值是否保持不变,并拒绝修改该文件的任何推送,这个方案怎么样? - jub0bs
1
@Jubobs 这看起来是正确的方法。你能否再次以回答的形式回复我,而不是评论,我会接受的?谢谢。(顺便说一下,这对于GitHub来说行不通,但它确实回答了我的问题。) - Sean Anderson
今天,我出于同样的原因问了同样的问题,但人们认为我很疯狂。不过看起来这是 Git 用户的需求!https://dev59.com/e2sMtIcB2Jgan1znsz-j - Scott Shipp
4个回答

13

对于隐含的主题问题(“我能让git仅将特定文件检出为只读吗?”)的答案是“不能直接实现”,因为Git每个文件仅存储一个权限位:可执行或不可执行。所有其他位对于每个文件都设置相同。

尽管如此,有一些使用钩子的技巧。正如一些评论者建议的那样,您可以在服务器端钩子中测试某些内容以防止推送。您可以使用深色和清洁过滤器。您可以有post-checkout钩子将文件设置为只读。

任何和所有钩子的缺点是它们必须针对每个存储库设置,并且用户可以覆盖它们(除非是服务器端钩子,假设用户无法直接访问服务器)。1 这也是钩子的优点,尽管对于天真的用户而言,这可能比优点更加困扰,因为Git本身不会自动设置这些钩子。

post-checkout钩子可能是设置文件权限的最明显位置,因为Git的文档包括以下内容:

此钩子可用于...设置工作目录元数据属性。

方便地,无论用户身在何处,只要用户实际上在Git工作树中,钩子似乎总是在顶层目录中运行。2 因此,这个非常简单的钩子足以将一个文件更改为只读:

#! /bin/sh
# post-checkout hook to make one file read-only
chmod -w path/to/file

(在任何具有 chmod 的系统上都可以,记得将钩子设置为可执行文件。)

用户必须将此钩子放入他/她的存储库中,在.git/hooks/post-checkout中(尽管您可以将文件本身提交到存储库中,然后要求用户通过辅助设置脚本将其复制或链接到位置)。


1因此,如果您想严格执行策略,则服务器端钩子是所需之处(这通常是正确的)。

2也就是说,以下操作可以规避该钩子:

$ pwd
/home/user/dir/example
$ ls -l .git/hooks/post-checkout
-rwxr-xr-x  1 user  group  27 Dec 18 11:10 .git/hooks/post-checkout
$ cd /tmp
$ GIT_DIR=/home/user/dir/example/.git git checkout master

在这里,当前工作目录只是/tmp,挂钩无法确定它应该是什么(你可以读取$GIT_DIR,但那不一定有用,因为工作树中的.git目录不必直接连接到第一个地方,并且这就是设置GIT_DIR的目的所在)。

请注意,在工作树中,位于子目录中并不会使挂钩失效;这就是我所说的“似乎总是在顶级目录中运行”的意思。


9

一个可能的方法是安装一些服务器端钩子(例如update),该钩子将:

  1. 检查推送的引用中,所涉及的 blob 的哈希值是否相同。
  2. 拒绝包含更改了所涉及的 blob 哈希值的引用的任何推送。

当然,这样的服务器端钩子并不能阻止贡献者在他们本地机器上创建包含不同版本文件的提交。但是,在看到几次推送被拒绝后,他们肯定会学到教训。:p


3
另一个解决方案是:
  1. 首先将文件重命名为模板,例如myFile_template.js
  2. 指示开发人员将模板复制到myFile.js并编辑详细信息
  3. myFile.js添加到.gitignore
这仍然不是非常强大的解决方案,因为开发人员仍然可以提交您试图保持隐藏的信息,但至少该文件不会出现在状态列表中。

0
如果你不希望开发人员将某些更改放入代码库中,一个好的解决方案是锁定代码库,并使用像Gerrit这样的审查系统。个别更改被推送到Gerrit中,并需要通过同行审查。
任何添加应该是本地文件的提交,例如API密钥文件或已编译的对象文件,都可以被拒绝。
然后,开发人员可以修改提交,重新编写以不包含有问题的文件,并重新提交进行审查。当它通过审查后,它将被挑选到适当的目标分支中。

我们如何锁定一个目录? - snwfdhmp
@snwfdhmp 我不知道,我们在谈论什么? - Kaz

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