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

时间:2014-12-18 18:44:05

标签: git

我有一个检入Git的文件。该文件需要保存API密钥,但出于安全原因,我不希望将API密钥提交给Git。我解释了如何为每个开发人员生成API密钥而不是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;
});

4 个答案:

答案 0 :(得分:7)

隐含主题行问题的答案("我可以将git检出特定文件为只读")是"不,至少不是直接",因为git每个文件只存储一个权限位:可执行或不可执行。每个文件的所有其他位设置相同。

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

任何和所有挂钩的缺点是必须为每个存储库设置它们,并且用户可以覆盖它们(服务器端挂钩除外,假设用户无法直接访问服务器)。 1 这也是一个钩子的优点,虽然对于天真的用户来说,它可能比优势更有缺点,因为git本身不会自动设置钩子。

post-checkout钩子可能是设置文件权限最明显的地方,因为git的文档包括这一点:

  

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

方便的是,只要用户实际上在git工作树中,钩子似乎总是在顶级目录中运行,无论用户在哪里。 2 所以这很简单hook足以将一个文件更改为只读:

#! /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的设置。

请注意,在工作树中,在子目录中,会使钩子失败;这就是我的意思"似乎总是在顶级目录中运行"。

答案 1 :(得分:4)

一种可能的方法是安装一些server-side hook(例如update

  1. 在推送的引用中检查所讨论的blob的哈希值是否相同,并且
  2. 拒绝任何包含引用的推送,其中有问题的blob的哈希值会发生变化。
  3. 当然,这样的服务器端钩子不会阻止贡献者创建包含不同版本文件的提交(在本地,在他们的机器上)。然而,在看到他们的一些推动被拒绝后,他们肯定会吸取教训。 :p

答案 2 :(得分:1)

如果您不希望开发人员将某些更改放入存储库,那么一个好的解决方案就是锁定存储库并改为使用像Gerrit这样的审查系统。个人变更被推入Gerrit而不得不通过同行评审。

任何添加应该是本地文件的提交,例如API密钥文件或编译目标文件,都可以被拒绝。

然后,开发人员可以修改提交,将其重写为不包含违规文件,重新提交以供审核。当它通过审查时,它被挑选到适当的目标分支。

答案 3 :(得分:1)

另一个解决方案是:

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