Gemfile.lock 是不是应该包含在 .gitignore 中?

Posted

技术标签:

【中文标题】Gemfile.lock 是不是应该包含在 .gitignore 中?【英文标题】:Should Gemfile.lock be included in .gitignore?Gemfile.lock 是否应该包含在 .gitignore 中? 【发布时间】:2011-05-08 06:43:52 【问题描述】:

我对 bundler 和它生成的文件有点陌生。我有一份来自 GitHub 的 git repo 的副本,该副本由许多人贡献,所以我惊讶地发现 bundler 创建了一个在 repo 中不存在且不在 .gitignore 列表中的文件。

由于我已经分叉了它,我知道将它添加到 repo 不会破坏主 repo 的任何内容,但是如果我执行 pull request,它会导致问题吗?

Gemfile.lock 是否应该包含在存储库中?

【问题讨论】:

相关:***.com/questions/14034561/… 如果您在这里找到了自己的方式,因为您有 Linux 和 Windows 机器共享同一个存储库,请参阅 Joe Yang 的回答。在我写这篇文章的时候,它排在第三位。另见***.com/questions/14034561/… 【参考方案1】:

假设您不是在编写 ruby​​gem,Gemfile.lock 应该在您的存储库中。它用作所有所需 gem 及其依赖项的快照。这样,bundler 就不必在每次部署时重新计算所有 gem 依赖项等。

来自以下cowboycoded的评论:

如果您正在开发 gem,请不要签入您的 Gemfile.lock。如果您正在开发 Rails 应用程序,请检查您的 Gemfile.lock。

这是一个很好的 article 解释锁定文件是什么。

【讨论】:

取决于您的工作。如果您正在处理 gem,那么不要签入您的 Gemfile.lock。如果您正在开发 Rails 应用程序,请检查您的 Gemfile.lock。更多信息在这里 - yehudakatz.com/2010/12/16/… 你应该把cowboycoded所说的写在你的回答中:gems。 文章链接需要一个新的href。 这是另一个用于 Bundler 的 very helpful Best Practices guide 请不要那样做!!将您的 Gemfile.lock 保存在原处!就像说here 和here。【参考方案2】:

同意 r-dub,将其保留在源代码管理中,但对我来说,真正的好处是:

在相同环境中的协作(忽略 windows 和 linux/mac 的东西)。在 Gemfile.lock 之前,下一个安装项目的家伙可能会看到各种令人困惑的错误,责备自己,但他只是那个幸运的人获得了下一个版本的超级 gem,打破了现有的依赖关系。

更糟糕的是,这发生在服务器上,除非受到纪律处分并安装准确的版本,否则会获得未经测试的版本。 Gemfile.lock 明确说明了这一点,它会明确告诉您您的版本不同。

注意:记住将东西分组,如 :development 和 :test

【讨论】:

【参考方案3】:

真正的问题发生在您正在开发需要具有可配置数据库适配器的开源 Rails 应用程序时。我正在开发 Fat Free CRM 的 Rails 3 分支。 我的首选是 postgres,但我们希望默认数据库是 mysql2。

在这种情况下,Gemfile.lock 仍然需要使用默认的一组 gem 进行签入,但我需要忽略我在我的机器上对其所做的更改。为此,我运行:

git update-index --assume-unchanged Gemfile.lock

并反转:

git update-index --no-assume-unchanged Gemfile.lock

在您的Gemfile 中包含类似以下代码的内容也很有用。这会根据您的 database.yml 加载适当的数据库适配器 gem。

# Loads the database adapter gem based on config/database.yml (Default: mysql2)
# -----------------------------------------------------------------------------
db_gems = "mysql2"     => ["mysql2", ">= 0.2.6"],
           "postgresql" => ["pg",     ">= 0.9.0"],
           "sqlite3"    => ["sqlite3"]
adapter = if File.exists?(db_config = File.join(File.dirname(__FILE__),"config","database.yml"))
  db = YAML.load_file(db_config)
  # Fetch the first configured adapter from config/database.yml
  (db["production"] || db["development"] || db["test"])["adapter"]
else
  "mysql2"
end
gem *db_gems[adapter]
# -----------------------------------------------------------------------------

我不能说这是否是一个既定的最佳实践,但它对我很有效。

【讨论】:

非常有用的信息...不知道为什么你只有 3 分,而一个不太有用的答案有 50 多分。哦,是的,看看日期戳。 (SO 的一大失败是在提出问题后不久就回答所带来的不成比例的好处。) @iconoclast:我真的很高兴你发布了你所做的。我认为许多来到这篇文章的人,包括我自己,都被问题标题“蒙蔽”了。我现在意识到我的答案只回答了一个特定的用例,不一定是这个问题的正确答案。我会在不久的将来努力更新它。也就是说,如果我的答案不能满足他/她的需求,则 OP 不应该将我的答案标记为正确。【参考方案4】:

我和我的同事有不同的Gemfile.lock,因为我们使用不同的平台,windows和mac,而我们的服务器是linux。

我们决定删除 repo 中的 Gemfile.lock 并在 git repo 中创建 Gemfile.lock.server,就像 database.yml 一样。然后在将它部署到服务器之前,我们使用 cap deploy hook 将 Gemfile.lock.server 复制到服务器上的 Gemfile.lock

【讨论】:

我有一个在 OSX 中开发的应用程序,然后必须部署在 Windows 服务器上。用 git 跟踪 Gemfile.lock 被证明是一个坏主意,所以它确实进入了我的 .gitignore 文件。许多 gem 需要针对不同环境的不同版本。理想情况下,您应该避免陷入这种情况,但我别无选择(该死的 IT 部门!)【参考方案5】:

Bundler 文档也解决了这个问题:

原文:http://gembundler.com/v1.3/rationale.html

编辑:http://web.archive.org/web/20160309170442/http://bundler.io/v1.3/rationale.html

请参阅“将代码检查到版本控制”部分:

在开发您的应用程序一段时间后,签入 应用程序连同 Gemfile 和 Gemfile.lock 快照。现在, 您的存储库记录了所有 gem 的确切版本 你最后一次使用你确定的应用程序 工作。请记住,虽然您的 Gemfile 仅列出了三个 gem (具有不同程度的版本严格性),您的应用程序取决于 在几十颗宝石上,一旦你考虑到所有的 您所依赖的宝石的隐含要求。

这很重要:Gemfile.lock 使您的应用程序成为一个单一的 你自己的代码和它最后运行的第三方代码的包 时间你肯定知道一切正常。指定确切 您在 Gemfile 中依赖的第三方代码的版本会 不提供相同的保证,因为 gems 通常会声明一个范围 它们的依赖项的版本。

下次您在同一台机器上运行 bundle install 时,bundler 将 看到它已经拥有你需要的所有依赖项,然后跳过 安装过程。

不要签入 .bundle 目录或其中的任何文件。 这些文件特定于每台特定的机器,并用于 在 bundle install 的运行之间保留安装选项 命令。

如果你运行了 bundle pack,gems(虽然不是 git gems) 您的捆绑包所需的内容将下载到供应商/缓存中。捆绑器 可以在不连接到互联网(或 RubyGems 服务器)的情况下运行,如果 您需要的所有宝石都存在于该文件夹中并已签入 你的源代码控制。这是一个可选步骤,不推荐, 由于源代码控制存储库的大小增加。

【讨论】:

【参考方案6】:

聚会有点晚了,但答案仍然花了我时间和外国阅读来理解这个问题。所以我想总结一下我对 Gemfile.lock 的发现。

当您构建 Rails 应用程序时,您会在本地机器上使用某些版本的 gems。如果你想避免生产模式和其他分支中的错误,你必须在任何地方都使用那个 Gemfile.lock 文件,并告诉 bundler 到 bundle 以在每次更改时重建 gem。

如果您的生产机器上的Gemfile.lock 已更改并且Git 不允许您git pull,您应该写git reset --hard 以避免该文件更改并再次写git pull

【讨论】:

如果文件自动更改,例如通过构建过程,这是一个明确的标志,它不应该被添加到版本控制中。【参考方案7】:

没有 Gemfile.lock 意味着:

新贡献者无法运行测试,因为奇怪的事情失败了,所以他们不会贡献或获得失败的 PR ......糟糕的第一次体验。 如果您丢失了本地 Gemfile.lock,您将无法返回一个 x 年前的项目并修复错误,而无需更新/重写该项目

-> 始终检查 Gemfile.lock,如果您想更加彻底,请让 travis 删除它https://grosser.it/2015/08/14/check-in-your-gemfile-lock/

【讨论】:

【参考方案8】:

这里的其他答案是正确的:是的,您的 Ruby 应用程序(不是您的 Ruby gem)应该在 repo 中包含Gemfile.lock。要详细了解为什么应该这样做,请继续阅读:

我错误地认为每个环境(开发、测试、登台、产品...)都做了一个bundle install 来构建自己的 Gemfile.lock。我的假设是基于 Gemfile.lock 不包含任何分组数据的事实,例如 :test、:prod 等。这个假设是错误,我在一个痛苦的本地问题中发现。

经过仔细调查,我很困惑为什么我的 Jenkins 构建显示成功获取特定的 gem(ffaker,FWIW),但是当应用程序加载并需要 ffaker 时,它说找不到文件。什么鬼?

更多的调查和实验显示了这两个文件的作用:

首先它使用 Gemfile.lock 去获取所有的 gem,即使是那些不会在这个特定环境中使用的。 然后它使用 Gemfile 来选择在这个环境中实际使用的那些获取的 gem。

因此,即使它在第一步中基于 Gemfile.lock 获取了 gem,但它并没有包含在我的 :test 环境中,基于 Gemfile 中的组。

解决方法(在我的情况下)是将gem 'ffaker' 从 :development 组移动到主组,以便所有 env 都可以使用它。 (或者,仅将其添加到 :development、:test 中,视情况而定)

【讨论】:

【参考方案9】:

2021 年的简单答案: Gemfile.lock 也应该在 Rubygems 的版本控制中。现在接受的答案是 11 岁。

这里的一些推理(从 cmets 中挑选出来的):

@josevalimhttps://github.com/heartcombo/devise/pull/3147#issuecomment-52193788

Gemfile.lock 应该保留在存储库中,因为贡献者和开发人员应该能够分叉项目并使用可以保证工作的版本运行它。

@rafaelfranca https://github.com/rails/rails/pull/18951#issuecomment-74888396

我认为即使是插件也忽略锁定文件不是一个好主意。

这意味着“git clone;bundle;rake test”序列不能保证通过,因为您的其中一个依赖项已升级数十个并且使您的代码中断。此外,正如@chancancode 所说,它使平分变得更加困难。

Rails 在 git 中也有 Gemfile.lock:

https://github.com/rails/rails/commit/0ad6d27643057f2eccfe8351409a75a6d1bbb9d0

【讨论】:

以上是关于Gemfile.lock 是不是应该包含在 .gitignore 中?的主要内容,如果未能解决你的问题,请参考以下文章

Gemfile.lock 在 Rails 中使用?

理解 Gemfile.lock:删除 Gemfile.lock 然后再次运行 bundle install 可以吗?

变基时 Gemfile.lock 中的冲突

Ruby on Rails 中的 Gemfile 和 Gemfile.lock 有啥区别

了解 Gemfile.lock 文件

如何在协作上下文中处理捆绑器更新(Gemfile.lock)?