Docs header transparent bg

如果您只想了解我们推荐的工作流程,而不在乎其背后的原理,请随时跳到下面的摘要

Bundler 的目的和原理

首先,您需要在应用程序根目录下的一个名为 Gemfile 的文件中声明这些依赖项。它看起来像这样

source 'https://rubygems.org.cn'
gem 'rails', '4.1.0.rc2'
gem 'rack-cache'
gem 'nokogiri', '~> 1.6.1'

这个 Gemfile 说明了几件事。首先,它表示 Bundler 默认情况下应该在 https://rubygems.org.cn 中查找 Gemfile 中声明的 gem。如果您的某些 gem 需要从私有 gem 服务器获取,则可以覆盖这些 gem 的默认源。

接下来,您声明了一些依赖项

  • 依赖 rails4.1.0.rc2 版本
  • 依赖任何版本的 rack-cache
  • 依赖 >= 1.6.1< 1.7.0 版本的 nokogiri

声明完第一组依赖项后,您需要告诉 Bundler 去获取它们

$ bundle install    # 'bundle' is a shortcut for 'bundle install'

Bundler 将连接到 rubygems.org(以及您声明的任何其他源)并找到满足您指定要求的所有必需 gem 的列表。由于 Gemfile 中的所有 gem 都有自己的依赖项(其中一些 gem 也有自己的依赖项),因此在上面的 Gemfile 上运行 bundle install 将安装相当多的 gem。

$ bundle install
Fetching gem metadata from https://rubygems.org.cn/.........
Fetching additional metadata from https://rubygems.org.cn/..
Resolving dependencies...
Using rake 10.3.1
Using json 1.8.1
Installing minitest 5.3.3
Installing i18n 0.6.9
Installing thread_safe 0.3.3
Installing builder 3.2.2
Installing rack 1.5.2
Installing erubis 2.7.0
Installing mime-types 1.25.1
Using bundler 1.6.2
Installing polyglot 0.3.4
Installing arel 5.0.1.20140414130214
Installing hike 1.2.3
Installing mini_portile 0.5.3
Installing multi_json 1.9.3
Installing thor 0.19.1
Installing tilt 1.4.1
Installing tzinfo 1.1.0
Installing rack-test 0.6.2
Installing rack-cache 1.2
Installing treetop 1.4.15
Installing sprockets 2.12.1
Installing activesupport 4.1.0.rc2
Installing mail 2.5.4
Installing actionview 4.1.0.rc2
Installing activemodel 4.1.0.rc2
Installing actionpack 4.1.0.rc2
Installing activerecord 4.1.0.rc2
Installing actionmailer 4.1.0.rc2
Installing sprockets-rails 2.0.1
Installing railties 4.1.0.rc2
Installing rails 4.1.0.rc2
Installing nokogiri 1.6.1
Your bundle is complete!
Use `bundle show [gemname]` to see where a bundled gem is installed.

如果任何所需的 gem 已经安装,Bundler 将使用它们。在将任何所需的 gem 安装到您的系统后,Bundler 会将所有已安装 gem 及其版本的快照写入 Gemfile.lock

设置您的应用程序以使用 Bundler

Bundler 确保 Ruby 可以找到 Gemfile 中的所有 gem(以及它们的所有依赖项)。如果您的应用程序是 Rails 应用程序,您的默认应用程序已经包含调用 Bundler 所需的代码。

对于其他类型的应用程序(例如 Sinatra 应用程序),您需要在尝试加载任何 gem 之前设置 Bundler。在应用程序加载的第一个文件(对于 Sinatra,调用 require 'sinatra' 的文件)的顶部,添加以下代码

require 'bundler/setup'

这将自动发现您的Gemfile,并将Gemfile中所有 gem 提供给 Ruby(从技术角度来说,它将 gem “放在加载路径上”)。您可以将其视为为require 'rubygems'添加了一些额外的功能。

现在您的代码已可供 Ruby 使用,您可以按需加载所需的 gem。例如,您可以require 'sinatra'。如果您有很多依赖项,您可能想说“加载Gemfile中的所有 gem”。为此,请将以下代码放在require 'bundler/setup'之后。

Bundler.require(:default)

对于我们的示例 Gemfile,这行代码与以下代码完全等效:

require 'rails'
require 'rack-cache'
require 'nokogiri'

对于如此小的Gemfile,我们建议您跳过Bundler.require,并手动加载 gem。对于更大的Gemfile,使用Bundler.require可以跳过重复大量需求。

将您的代码检入版本控制

在开发应用程序一段时间后,将应用程序与GemfileGemfile.lock快照一起检入。现在,您的存储库记录了您上次确认应用程序正常工作时使用的所有 gem 的确切版本。请记住,虽然您的Gemfile只列出了三个 gem(版本严格程度不同),但考虑到您依赖的 gem 的所有隐式需求,您的应用程序依赖于数十个 gem。

这一点很重要:Gemfile.lock将您的应用程序打包成一个包含您自己的代码和上次确认一切正常时运行的第三方代码的单一包。在您的Gemfile中指定您依赖的第三方代码的确切版本并不能提供相同的保证,因为 gem 通常会为其依赖项声明一个版本范围。

下次您在同一台机器上运行bundle install时,bundler 会发现它已经拥有您需要的所有依赖项,并跳过安装过程。

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

如果您已经运行了 bundle pack,您的 bundle 所需的 gem(但不是 git gem)将被下载到 vendor/cache 中。如果所有需要的 gem 都存在于该文件夹中并已签入您的源代码控制,Bundler 可以在不连接互联网(或 RubyGems 服务器)的情况下运行。这是一个可选步骤,不建议这样做,因为这会增加您的源代码控制存储库的大小。

与其他开发者共享您的应用程序

当您的共同开发者(或您在另一台机器上)检出您的代码时,它将包含您上次开发时使用的所有第三方代码的精确版本(在 Gemfile.lock 中)。当他们运行 bundle install 时,bundler 将找到 Gemfile.lock 并跳过依赖项解析步骤。相反,它将安装您在原始机器上使用的所有相同 gem。

换句话说,您不必猜测应该安装哪些版本的依赖项。在我们一直在使用的示例中,即使 rack-cache 声明对 rack >= 0.4 的依赖,我们也确信它与 rack 1.5.2 兼容。即使 Rack 团队发布了 rack 1.5.3,bundler 也会始终安装 1.5.2,即我们知道有效的 gem 的确切版本。这减轻了应用程序开发人员的很大一部分维护负担,因为所有机器始终运行完全相同的第三方代码。

更新依赖项

当然,在某些时候,您可能希望更新应用程序依赖的特定依赖项的版本。例如,您可能希望将 rails 更新到 4.1.0 最终版。重要的是,仅仅因为您要更新一个依赖项,并不意味着您希望重新解析所有依赖项并使用所有内容的最新版本。在我们的示例中,您只有三个依赖项,但即使在这种情况下,更新所有内容也会导致复杂情况。

举个例子,rails 4.1.0.rc2 gem 依赖于 actionpack 4.1.0.rc2 gem,后者又依赖于 rack ~> 1.5.2(意味着 >= 1.5.2< 1.6.0)。rack-cache gem 依赖于 rack >= 0.4。假设 rails 4.1.0 正式版也依赖于 rack ~> 1.5.2,并且在 rails 4.1.0 发布后,Rack 团队发布了 rack 1.5.3

如果我们简单地更新所有 gem 来更新 Rails,我们将得到 rack 1.5.3,它满足 rails 4.1.0rack-cache 的要求。然而,我们并没有明确要求更新 rack-cache,它可能与 rack 1.5.3 不兼容(无论出于何种原因)。虽然从 rack 1.5.2 更新到 rack 1.5.3 可能不会造成任何问题,但类似的情况可能会发生,涉及更大的跳跃。(有关更详细的讨论,请参见下面的 [1])

为了避免这个问题,当您更新一个 gem 时,bundler 不会更新该 gem 的依赖项,除非另一个 gem 仍然依赖于它。在本例中,由于 rack-cache 仍然依赖于 rack,bundler 不会更新 rack gem。这确保了更新 rails 不会意外地破坏 rack-cache。由于 rails 4.1.0 的依赖项 actionpack 4.1.0 仍然与 rack 1.5.2 兼容,bundler 会保留它,即使 rack-cacherack 1.5.3 不兼容,它也能继续工作。

由于您最初声明了对 rails 4.1.0.rc2 的依赖,如果您想更新到 rails 4.1.0,只需将您的 Gemfile 更新为 gem 'rails', '4.1.0' 并运行

$ bundle install

如上所述,bundle install 命令始终执行保守更新,拒绝更新您在 Gemfile 中没有明确更改的 gem(或其依赖项)。这意味着,如果您没有在 Gemfile 中修改 rack-cache,bundler 将将其视为一个不可修改的单元,包括其依赖项rack)。如果 rails 4.1.0rack-cache 不兼容,bundler 将报告您的快照依赖项(Gemfile.lock)和更新的 Gemfile 之间的冲突。

如果您更新了 Gemfile,并且您的系统已经拥有所有必要的依赖项,bundler 将在您启动应用程序时透明地更新 Gemfile.lock。例如,如果您在 Gemfile 中添加了 mysql,并且已经在您的系统中安装了它,您可以启动您的应用程序而无需运行 bundle install,bundler 将将“最后已知良好”配置持久化到 Gemfile.lock 快照中。

这在添加或更新具有最少依赖项的 gem(数据库驱动程序、wirbleruby-debug)时非常有用。如果您更新具有大量依赖项的 gem(rails),或者许多 gem 依赖于它(rack),它可能会失败。如果透明更新失败,您的应用程序将无法启动,bundler 将打印出一条错误消息,指示您运行 bundle install

更新 Gemfile 中的 Gem 而不修改 Gemfile

有时,您可能希望更新依赖项而不修改 Gemfile。例如,您可能希望更新到最新版本的 rack-cache。由于您没有在 Gemfile 中声明特定版本的 rack-cache,因此您可能希望定期获取最新版本的 rack-cache。为此,您需要使用 bundle update 命令

$ bundle update rack-cache

此命令将更新 rack-cache 及其依赖项到 Gemfile 允许的最新版本(在本例中,为可用的最新版本)。它不会修改任何其他依赖项。

但是,如果需要,它会更新其他 gem 的依赖项。例如,如果最新版本的 rack-cache 指定对 rack >= 1.5.2 的依赖关系,bundler 将更新 rack1.5.2,即使您没有要求 bundler 更新 rack。如果 bundler 需要更新另一个 gem 依赖的 gem,它将在更新完成后通知您。

如果您希望将 Gemfile 中的每个 gem 更新到最新的可能版本,请运行

$ bundle update

这将从头开始解析依赖项,忽略 Gemfile.lock。如果您这样做,请将 git reset --hard 和您的测试套件放在手边。从头开始解析所有依赖项可能会产生意想不到的结果,尤其是在您依赖的许多第三方软件包自上次完全更新以来发布了新版本的情况下。

摘要

简单的 Bundler 工作流程

  • 当您首次创建 Rails 应用程序时,它已经包含一个 Gemfile。对于其他类型的应用程序(例如 Sinatra),请运行

    $ bundle init
    

    bundle init 命令会创建一个简单的 Gemfile,您可以对其进行编辑。

  • 接下来,添加您的应用程序依赖的任何 gem。如果您关心需要特定 gem 的哪个版本,请务必包含适当的版本限制

    source 'https://rubygems.org.cn'
    gem 'sinatra', '~> 1.3.6'
    gem 'rack-cache'
    gem 'rack-bug'
    
  • 如果您尚未在系统中安装 gem,请运行

    $ bundle install
    
  • 要更新 gem 的版本要求,请先修改 Gemfile

    source 'https://rubygems.org.cn'
    gem 'sinatra', '~> 1.4.5'
    gem 'rack-cache'
    gem 'rack-bug'
    

    然后运行

    $ bundle install
    
  • 如果 bundle install 报告 GemfileGemfile.lock 之间的冲突,请运行

    $ bundle update sinatra
    

    这将更新 Sinatra gem 以及它的所有依赖项。

  • 要将 `Gemfile` 中的所有 gem 更新到最新版本,请运行

    $ bundle update
    
  • 每当 `Gemfile.lock` 发生变化时,请务必将其提交到版本控制系统。它会记录所有第三方代码的精确版本,这些代码用于成功运行您的应用程序。
  • 将代码部署到暂存或生产服务器时,请先运行测试(或启动本地开发服务器),确保已将 `Gemfile.lock` 提交到版本控制系统。在远程服务器上,运行

    $ bundle install --deployment
    

注意

[1] 例如,如果 `rails 4.1.0` 依赖于 `rack 2.0`,那么该 gem 仍然可以满足 `rack-cache` 的要求,`rack-cache` 声明 `>= 0.4` 作为依赖项。当然,您可以争辩说 `rack-cache` 依赖于开放式版本是愚蠢的,但这种情况在现实中广泛存在,项目在决定依赖于哪个版本时经常会陷入两难境地。过度限制依赖项(`rack =1.5.1`)会使您的项目难以在其他兼容项目中使用。限制过少(`rack >= 1.0`)可能会导致 Rack 的新版本破坏您的代码。使用 `rack ~> 1.5.2` 等依赖项和以符合 SemVer 的方式对代码进行版本控制,在很大程度上解决了这个问题,但它假设普遍遵守。由于 RubyGems 包含超过 100,000 个包,因此这种假设在实践中并不成立。

在 GitHub 上编辑此文档,如果您发现错误或遗漏。