了解 Gemfile.lock 文件

Posted

技术标签:

【中文标题】了解 Gemfile.lock 文件【英文标题】:Understanding the Gemfile.lock file 【发布时间】:2011-11-22 23:16:20 【问题描述】:

运行bundle install 命令后,'Gemfile.lock' 在工作目录中创建。该文件中的指令是什么意思?

例如,我们以下面的文件为例:

PATH
  remote: .
  specs:
    gem_one (0.0.1)

GEM
  remote: http://example.org/
  specs:
    gem_two (0.0.2)
    gem_three (0.0.3)
      gem_four (0.0.4)

PLATFORMS
  platform

DEPENDENCIES
  gem_two
  gem_one!

'PATH'、'GEM'、'PLATFORMS' 和 'DEPENDENCIES' 描述了什么?都需要吗?

什么应该包含 'remote' 和 'specs' 子指令?

'DEPENDENCIES' 组中 gem 名称后的感叹号是什么意思?

【问题讨论】:

【参考方案1】:

似乎没有关于Gemfile.lock 格式的明确文档。可能是因为Gemfile.lock只是bundle内部使用的。

但是,由于Gemfile.lockGemfile 的快照,这意味着它的所有信息都应该来自Gemfile(或者如果Gemfile 中没有指定,则来自默认值)。

对于GEM,它列出了您在Gemfile 中直接或间接引入的所有依赖项。 remoteGEM 下的GEM 告诉从哪里获得宝石,这是由Gemfile 中的source 指定的。

如果没有从 remote 获取 gem,PATH 会告诉位置找到它。当您声明依赖项时,PATH 的信息来自 path 中的 Gemfile

PLATFORM 来自here。

对于DEPENDENCIES,它是捆绑解决的依赖关系的快照。

【讨论】:

【参考方案2】:

在过去的几个月里,我在构建一个自动依赖项更新工具1 时,一直在搞乱 Gemfiles 和 Gemfile.locks。下面的内容远非明确,但它是理解 Gemfile.lock 格式的一个很好的起点。您可能还想查看 Bundler 的 lockfile parser 的源代码。

您会在 Bundler 1.x 生成的锁定文件中找到以下标题:

GEM(可选但很常见)

这些是来自 Rubygems 服务器的依赖项。这可能是 Rubygems.org 上的主要 Rubygems 索引,也可能是自定义索引,例如 Gemfury 等提供的索引。在本节中,您将看到:

remote: 一行或多行指定 Rubygems 索引的位置 specs: 依赖项列表、版本号以及任何子依赖项的约束

GIT(可选)

这些是来自给定 git 远程的依赖项。对于每个 git 远程,您会看到其中不同的部分,并且在每个部分中您会看到:

remote: git 遥控器。例如,git@github.com:rails/rails revision: Gemfile.lock 被锁定到的提交引用 tag:(可选)Gemfile 中指定的标签 specs: 在此远程找到的 git 依赖项,及其版本号,以及对任何子依赖项的约束

路径(可选)

这些是来自 Gemfile 中提供的给定 path 的依赖项。您将看到每个路径依赖项的不同部分,并且在每个部分中您会看到:

remote: 路径。例如,plugins/vendored-dependency specs: 在此远程找到的 git 依赖项,及其版本号,以及对任何子依赖项的约束

平台

生成 Gemfile.lock 的 Ruby 平台。如果 Gemfile 中的任何依赖项指定了一个平台,那么它们只会在该平台上生成锁定文件时包含在 Gemfile.lock 中(例如,通过安装)。

依赖关系

Gemfile 中指定的依赖项列表,以及其中指定的版本约束。

使用主 Rubygems 索引以外的源指定的依赖项(例如,git 依赖项、基于路径的依赖项)具有 !,这意味着它们被“固定”到该源2 (虽然有时必须查看 Gemfile 才能确定)。

RUBY 版本(可选)

创建此 Gemfile.lock 时在 Gemfile 中指定的 Ruby 版本。如果在 .ruby_version 文件中指定了 Ruby 版本,则此部分将不存在(因为 Bundler 将认为 Gemfile / Gemfile.lock 与安装程序的 Ruby 版本无关)。

捆绑在一起(捆绑器 >= v1.10.x)

用于创建 Gemfile.lock 的 Bundler 版本。用于提醒安装者更新他们的 Bundler 版本,如果它比创建文件的版本旧。

插件源(可选且非常少见)

理论上,Gemfile 可以指定 Bundler 插件,以及 gems3,然后会在此处列出。实际上,截至 2017 年 7 月,我不知道有任何可用的插件。Bundler 的这一部分仍在积极开发中!


    https://dependabot.com https://github.com/bundler/bundler/issues/4631 http://andre.arko.net/2012/07/23/towards-a-bundler-plugin-system/

【讨论】:

似乎是最好的答案【参考方案3】:

Bundler 是一个 Gem 管理器,它通过跟踪和安装所需的确切 gem 和版本来为 Ruby 项目提供一致的环境。

Gemfile 和 Gemfile.lock 是 Bundler gem 提供的主要产品(Bundler 本身就是一个 gem)。

Gemfile 包含您的项目对 gem(s) 的依赖,您手动提及指定的版本,但这些 gem(s) 又依赖于由 bundler 自动解析的其他 gem。

Gemfile.lock 包含 Gemfile 中所有 gem 的完整快照以及相关的依赖项。

当你第一次调用bundle install 时,它会创建这个 Gemfile.lock 并在所有后续调用 bundle install 时使用这个文件,这样可以确保你安装了所有依赖项,并且会跳过依赖项安装。

与不同机器共享代码时也会发生同样的情况

您与 Gemfile 共享您的 Gemfile.lock,当您在其他机器上运行 bundle install 时,它将引用您的 Gemfile.lock 并跳过依赖项解析步骤,而是安装所有与您相同的依赖 gem在原始机器上使用,在多台机器上保持一致性

为什么我们需要在多台机器上保持一致性?

在不同的机器上运行不同的版本可能会导致损坏 代码

假设您的应用使用的是 1.5.3 版本,并且它在 14 个月前可以运行 没有任何问题,您尝试在不同的机器上安装 没有 Gemfile.lock 现在你得到版本 1.5.8。也许它坏了 使用某些 gem 的最新版本,您的应用程序将 失败。保持一致性至关重要(首选 练习)。

也可以使用更新 Gemfile.lock 中的 gem bundle update.

这是基于conservative updating的概念

【讨论】:

【参考方案4】:

“DEPENDECIES”组中 gem 名称后面的感叹号是什么意思?

当使用“https://rubygems.org”以外的源安装 gem 时,会出现感叹号。

【讨论】:

【参考方案5】:

您可以在bundler website 中找到有关它的更多信息(为方便起见,在下面添加了重点):

在开发应用程序一段时间后,将应用程序连同 Gemfile 和 Gemfile.lock 快照一起签入。现在,您的存储库记录了您上次使用的所有 gem 的确切版本,您确定该应用程序工作正常...

这很重要:Gemfile.lock 使您的应用程序成为您自己的代码和它最后一次运行的第三方代码的单一包,您可以确定一切正常。在 Gemfile 中指定您依赖的第三方代码的确切版本不会提供相同的保证,因为 gem 通常会为其依赖项声明一系列版本。

【讨论】:

这没有回答他的任何问题,他是在询问 Gemfile.lock 的格式,但这只是描述了它的作用。【参考方案6】:

关于感叹号,我刚刚发现它在通过:git 获取的宝石上,例如

gem "foo", :git => "git@github.com:company/foo.git"

【讨论】:

哇,很好地解决了这个问题,我也想知道这一点。谢谢。 通过path选项加载本地gem时也会发生这种情况。我猜这与加载未编译的 gem 有关吗? 是的,这是一个原因。但这并不是宝石标有感叹号的唯一原因。我目前看到在源块中声明的任何 gem 都标有感叹号。【参考方案7】:

在我看来,PATH 直接从您的 gemspec 中列出了第一代依赖项,而 GEM 列出了第二代依赖项(即您的依赖项所依赖的内容)和 Gemfile 中的那些。 PATH::remote 是 .,因为它依赖当前目录中的本地 gemspec 来找出 PATH::spec 中的内容,而 GEM::remote 是 rubygems.org,因为它必须去那里才能找到GEM::spec 中的内容。

在 Rails 插件中,您会看到 PATH 部分,但在 Rails 应用程序中看不到。由于该应用没有 gemspec 文件,因此不会在 PATH 中放置任何内容。

至于依赖关系,gembundler.com 声明:

Runtime dependencies in your gemspec are treated like base dependencies, 
and development dependencies are added by default to the group, :development

rails plugin new my_plugin 生成的 Gemfile 说了类似的话:

# Bundler will treat runtime dependencies like base dependencies, and
# development dependencies will be added by default to the :development group.

这意味着两者的区别

s.add_development_dependency "july" # (1)

s.add_dependency "july" # (2)

是 (1) 将仅在开发环境中的 Gemfile.lock(因此在应用程序中)中包含“july”。因此,当您运行bundle install 时,您不仅会在 PATH 下而且还会在 DEPENDENCIES 下看到“july”,而且只会在开发中看到。在生产中,它根本不存在。但是,当您使用 (2) 时,您只会在 PATH 中看到“july”,而不是在 DEPENDENCIES 中,但是当您在生产环境中 bundle install 时(即在包含您作为依赖项的其他 gem 中)时,它会显示),不仅仅是开发。

这些只是我的观察,我无法完全解释为什么会这样,但我欢迎更多的 cmets。

【讨论】:

以上是关于了解 Gemfile.lock 文件的主要内容,如果未能解决你的问题,请参考以下文章

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

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

Gemfile.lock 包含合并冲突

git 和 Gemfile.lock 的问题

Gemfile.lock 在 Rails 中使用?

变基时 Gemfile.lock 中的冲突