如果您只想了解我们推荐的工作流程,而不在乎其背后的原理,请随时跳到下面的摘要。
首先,您需要在应用程序根目录下的一个名为 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 的默认源。
接下来,您声明了一些依赖项
rails
的 4.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 确保 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
可以跳过重复大量需求。
在开发应用程序一段时间后,将应用程序与Gemfile
和Gemfile.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.0
和 rack-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-cache
与 rack 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.0
与 rack-cache
不兼容,bundler 将报告您的快照依赖项(Gemfile.lock
)和更新的 Gemfile
之间的冲突。
如果您更新了 Gemfile
,并且您的系统已经拥有所有必要的依赖项,bundler 将在您启动应用程序时透明地更新 Gemfile.lock
。例如,如果您在 Gemfile
中添加了 mysql
,并且已经在您的系统中安装了它,您可以启动您的应用程序而无需运行 bundle install
,bundler 将将“最后已知良好”配置持久化到 Gemfile.lock
快照中。
这在添加或更新具有最少依赖项的 gem(数据库驱动程序、wirble
、ruby-debug
)时非常有用。如果您更新具有大量依赖项的 gem(rails
),或者许多 gem 依赖于它(rack
),它可能会失败。如果透明更新失败,您的应用程序将无法启动,bundler 将打印出一条错误消息,指示您运行 bundle install
。
有时,您可能希望更新依赖项而不修改 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 将更新 rack
到 1.5.2
,即使您没有要求 bundler 更新 rack
。如果 bundler 需要更新另一个 gem 依赖的 gem,它将在更新完成后通知您。
如果您希望将 Gemfile 中的每个 gem 更新到最新的可能版本,请运行
$ bundle update
这将从头开始解析依赖项,忽略 Gemfile.lock
。如果您这样做,请将 git reset --hard
和您的测试套件放在手边。从头开始解析所有依赖项可能会产生意想不到的结果,尤其是在您依赖的许多第三方软件包自上次完全更新以来发布了新版本的情况下。
当您首次创建 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
报告 Gemfile
和 Gemfile.lock
之间的冲突,请运行
$ bundle update sinatra
这将更新 Sinatra gem 以及它的所有依赖项。
要将 `Gemfile` 中的所有 gem 更新到最新版本,请运行
$ bundle update
将代码部署到暂存或生产服务器时,请先运行测试(或启动本地开发服务器),确保已将 `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 个包,因此这种假设在实践中并不成立。