如何让git忽略文件的未来修订?

215

我创建了一个在git仓库中的文件的默认版本,并且希望当别人克隆这个仓库时,他们可以得到这个文件的副本。但是,我想设置git忽略后续对这个文件所做的更改,.gitignore只适用于未被跟踪的文件。

我的动机是因为这个文件包含特定于机器的信息。我想提供默认值,同时允许人们进行本地更改,这些更改不会被推回到源存储库,从而在我们拉取新更改时创建合并冲突。

通常我们很懒,经常使用git add .,所以我非常确定如果我不能告诉git忽略这个文件,对它所做的更改最终会被提交和推送。

总结一下:

  1. 我想创建一个名为default_values.txt的文件,将其添加到我的git仓库中,在克隆该仓库时包括它。
  2. git add .不应该将default_values.txt加入提交内容。
  3. 这种行为应该传递给存储库的任何克隆。

2
你可以利用 git 钩子来创建一个 pre-commit 钩子,如果修改的文件是 default_values.txt(例如),则中止提交吗? - sateesh
2
Git的纯粹主义者会说不要偷懒,正确使用暂存区,那就是它的作用。 - Xint0
1
Git 纯粹主义者会说使用 smudge/clean 脚本。这是最可维护的解决方案。 - Adam Dymitruk
1
Xint0: true. 但是您如何防止其他人意外检查? - Alan
可能是提交机器特定配置文件的重复问题。 - Senseful
有趣。第二高投票的答案有一条来自 OP 的评论,指出“他们不接受,因为你无法将行为传递给其他克隆体”,但是被接受的答案具有完全相同的命令 - 和问题。 - igorsantos07
7个回答

238

正如其他许多人提到的那样,一个好的现代解决方案是:

git update-index --skip-worktree default_values.txt

这将忽略对该文件的更改,无论是本地更改还是上游更改,直到您决定使用以下命令再次允许它们:

git update-index --no-assume-unchanged
git update-index --no-skip-worktree default_values.txt

您可以使用以下命令获取已跳过标记的文件列表:

git ls-files -v . | grep ^S

请注意,与--skip-worktree不同,--assume-unchanged状态会在拉取上游更改后丢失。


8
如果有其他人拉取代码仓库并编辑文件,那么他们的更改是否会被忽略?我希望他们需要输入"--no-skip-worktree"才能添加他们的更改。 - neaumusic
6
他们控制着对他们所做的更改的处理方式。换句话说,如果他们不希望将其更改推送出去,则必须在其存储库中为该文件设置skip-worktree。如果这是一个旨在发送给每个人并且所有后续更改都将被忽略的文件,则每个人都必须遵循相同的说明。 - moodboom
3
请注意,如果同一文件在另一个分支中被跟踪,您可能需要在切换分支之前取消文件的“--skip-worktree”状态。 - moodboom
5
嗯,它有效了……我在文件中做了一些更改后,在git status中没有显示,但当我尝试切换到不同的分支时,出现了 error: Your local changes to the following files would be overwritten by checkout: 的错误提示。即使使用了-f选项也无济于事。另外还有这个错误提示:error: Entry 'wix-stores-merchant-app/demo/credentials.js' not uptodate. Cannot merge. - ykravv
6
我将这些别名设置为 git ignoregit unignore - Michael
显示剩余5条评论

55

11
这个不起作用。虽然它让 git add . 在本地分支上忽略了该文件,但克隆的存档没有这种行为(如果你在克隆的存档中更改 default_values.txt 文件,则会使用 "git add ." 将其添加到提交中)。 - Marc
7
是的,因为你只是针对本地仓库设置了这种信息,你无法将其推送出去。 - tamasd
10
@Indradhanush - 这种解决方案不符合第3标准 -- "行为应该传递给存储库的任何克隆" -- 这就是为什么我没有接受它的原因。但这并不意味着它不是一个好答案。 - Marc
我从未注意到第三个标准,因为我没有寻找它。 :) - Indradhanush Gupta
5
对于包含私有应用程序设置的本地配置文件,您可能希望使用skip-worktree而不是assume-unchanged。更多信息请参见https://dev59.com/nWYr5IYBdhLWcg3wfaSc。 - Aaron Hoffman
在大多数情况下,我更喜欢这个答案,因为这意味着您永远不会错过上游的更改。 - DrCord

24

我通常看到的方法是创建一个不同名称的文件,例如:default_values_template.txt,并将default_values.txt放入.gitignore中。告诉人们将default_values_template.txt复制到本地工作区并根据需要进行更改。


嗯...也许我可以编写一个钩子,如果default_values不存在,自动将default_values_template复制到default_values? - Marc
2
这是我经验中最常见的解决方法。它几乎是最省力的路径,因为它“只是工作”,而且您可以轻松地让您的代码检查本地配置文件是否存在,并在不存在时提供有用的错误提示。 - Jani Hartikainen
1
@AdamDymitruk:是的,在这种情况下可以使用clean/smudge,但很明显这不是最佳选择。例如,如果人们真的想更改文件,那么这将使事情变得非常困难,因为clean/smudge会妨碍它。我实际上更喜欢这里描述的方法。 - sleske
关于“人们可能会忘记复制文件”: 通常default_values.txt将作为您使用的任何构建工具的本地生成过程的一部分。该工具甚至可以检查default_values_template.txt以进行更改并将其合并到default_values.txt中。 - sleske
1
我从git本身(特别是git钩子)中借鉴,使用“.sample”后缀。因此,在您的情况下,文件名应为“default_values.txt.sample”。 - tir38
显示剩余3条评论

6

可以看一下涂抹/清洁脚本。这样你就可以对文件进行版本控制,但是当它被检出时,你将用机器特定的数据替换文件中的通用/占位符数据来“涂抹”它。

当你提交它时,你将用通用或占位符信息替换机器特定的信息来“清洁”它。

涂抹/清洁脚本必须是确定性的,即多次应用它们,以不同的顺序将等同于仅运行序列中的最后一个。

如果你需要公开你的存储库,但内容可能包含敏感信息,也可以使用相同的方法处理密码。


清理和格式化脚本是本地的还是仓库的一部分? - Alan
是的。 :) ... 这意味着您可以通过存储库共享代码,但如果其中包含生产密码等敏感数据,则不是一个好主意。如果这不是问题,git需要您明确启用脚本。否则,人们可能会通过GitHub和其他共享存储库对其他用户进行恶意操作。 - Adam Dymitruk
我需要再多了解一些关于这个的内容。基本上,我想设置一个项目,其中有一个默认的 user.json 文件,需要用每个开发者的凭据进行覆盖,但我不希望开发人员意外地将他们的凭据提交。 - Alan
我会在谷歌上搜索干净的涂抹示例脚本,看看有什么结果。同时,加入freenode上的git irc聊天室,你会立即得到帮助。 - Adam Dymitruk

3
我已经解决了这个问题,通过定义“clean”过滤器来简单地连接索引文件中的内容。 git show :path/to/myfile 应该只打印指定文件的索引内容,所以我们可以在脚本中使用它来用索引中未修改的副本替换工作副本。
#! /bin/sh

git show :$1

将其设置为所涉及文件的“clean”过滤器(假设您将其放置在“discard_changes”中):

$ git config filter.ignore_myfile.clean "discard_changes path/to/myfile"
$ echo "path/to/myfile filter=ignore_myfile" >> .gitattributes

很遗憾,我找不到一种适用于多个文件的方法,因为在清理脚本中无法确定正在处理哪个文件。当然,你可以为每个文件添加不同的过滤规则,但这有点笨拙。


几乎可以理解。如果您已将过滤器添加到.gitattributes中的特定路径,则为什么需要在“放弃更改”命令中指定要操作的文件?为什么不会对传递的任何文件执行此命令?例如,如果在.gitattributes中,您指定*/ProjectSettings.asset作为受影响的文件,并应用了一个过滤器,则该过滤器应该能够在存储库中的任何该文件上运行!如何做到这一点? - eric frazer

1
我找到了一个适合我的团队的解决方案。我们通过符号链接共享githooks,在向git添加模板文件后,我添加了一个pre-commit hook,检查模板文件是否已被修改,如果是,我使用git reset -- templatefile.txt进行重置。如果它是唯一更改的文件,我也会中止提交。

-3
我建议您研究子模块。如果您将机器特定的文件放在子模块中,git add 命令应该会忽略它。

这是一个好主意,但我还必须将单个文件存储库放在git服务器上,这不是最理想的,只是因为我们正在使用GitHub并且有限数量的存储库。 - Marc
@Marc 看看Visual Studio Team Services,无限免费的私有项目和git存储库。看板、工作项和缺陷跟踪、将检入与工作项关联、管理sprint(如果你喜欢scrum或其他项目类型)。除此之外,它还拥有出色的构建工具,可针对多个平台进行构建,太多免费的东西可以提供了。有些人因为它是微软的而抨击它,但它绝对比github提供的工具更胜一筹,除了仓库托管之外。虽然有免费使用的限制,但我很少超过它们。 - Aran Mulholland
@Marc,我发现它非常方便的另一件事是我可以设置任意多个账户,因此如果我为一个想要拥有源代码控制权的客户编写项目,我可以创建一个账户,用它来规划、设计和执行项目,完成后我可以将账户所有权转移给客户。 - Aran Mulholland

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