我应该在我的Gemfile中指定确切版本吗?


76

我注意到在rubygems.org上有很多宝石建议您使用主要版本而非确切版本来指定它们。例如...

haml-rails宝石...

gem "haml-rails", "~> 0.3.4"  # "$ bundle install" will acquire the 
                              # latest version before 1.0.

但是,根据Bundler文档,在我看来,最好像这样精确地确定版本...

gem "haml-rails", "0.3.4"

因此,这里有您的haml-rails gem,其所有依赖项都不会向前漂移。如果几周后在另一台计算机上签出项目并运行,$ bundle install您将拥有与指定的所有版本完全相同的版本。

我看到过分发布会破坏东西,我认为Bundler整个想法的一部分就是“ Bundle.lock”所有宝石版本。

但是在rubygems.org上,他们经常使用“〜>”,所以也许我遗漏了一些东西?

任何澄清对我理解邦德勒和宝石管理都将非常有帮助。


我会。惊喜越少越好。只需更新一次依赖关系,而无需您有意地将它发送给兔子洞,甚至长达数小时甚至数天,就可以使您学习此课程。无法信任第三方库和开源库来严格遵循语义版本控制(甚至是我自己的库)。不值得冒险。
约书亚·品特

Answers:


59

这就是Gemfile.lock文件的目的-在存在Gemfile.lock的情况下运行bundle install,仅使用其中列出的依赖项进行安装。它不会重新解析Gemfile。要更新依赖项/更新gem版本,则必须显式地执行bundle update,这将更新Gemfile.lock文件。

如果没有Gemfile.lock,则将代码部署到生产中将是一个主要问题,因为如您所述,依赖项和gem版本可能会发生变化。

简而言之,~>如rubygems.org建议的那样,使用悲观版本约束运算符()通常应该很安全。只需在执行a之后确保重新运行测试bundle update以确保没有任何损坏。

有一个很好的文章由耶胡达·卡茨说,对Gemfile.lock的多一点信息。


1
OK,所以gem保持在Gemfile.lock中记录的既定版本。那么添加“〜>”的目的是什么?那有什么好处呢?
伊桑(Ethan)

2
@ethan RubyGems有一个文档对此进行了解释(请参阅“防止版本灾难”一节)。其要点是它仅允许版本号中的最后一个整数增加(例如,“〜> 1.0.5”允许更新至版本1.0.9999,但不允许更新至1.1.x)。该机制用于允许更新gem,但不会引入不兼容性,否则可能会破坏事情(它假定gem遵循链接概述的“合理版本控制”策略)。
安倍·沃克

3
我认为您所写内容的主旨是,应该在自己的Gemfile中保留悲观版本约束,以便可以轻松升级到与指定的主要版本和次要版本均匹配的最新版本。但是,还应使用Gemfile.lock文件并将其保存在源代码中,以便必须显式进行升级以影响将代码部署到的任何环境。
肯尼·埃维特

7

TL; DR

是的,使用悲观锁定~>)并指定语义版本以修补(Major.minor.patch)您所有宝石!

讨论区

我对这个问题缺乏明确性感到惊讶,即使是“行业专家”前几天告诉我,Gemfile.lock在那里也可以维护gem版本。错误!

您希望以Gemfile一种可以随时运行bundle update而又不会破坏所有内容的方式来组织您的工作。要达到此目的:

  1. 为所有具有悲观锁定的宝石指定补丁程序级别的版本。这样可以bundle update为您提供修复,但不能破坏更改。

  2. ref为git指定宝石

此设置的唯一弊端是,当出现甜美的次要/主要版本的宝石时,您必须手动提高版本。

警告情况

考虑一下如果不锁定宝石会发生什么。
gem "rails"的gemfile中已解锁,版本Gemfile.lock4.1.16。您正在编码,并且在某个时候执行bundle update。现在,您的Rails版本跳至5.2.0(如果提供了其他宝石不能阻止这种情况),一切都会中断。
帮自己一个忙,不要让它成为任何宝石!

一个示例Gemfile

# lock that bundler
if (version = Gem::Version.new(Bundler::VERSION)) < Gem::Version.new('1.16.3')
  abort "Bundler version >= 1.16.3 is required. You are running #{version}"
end

source "http://rubygems.org"

# specify explicit ref for git repos
gem "entity_validator",
  git: "https://github.com/plataformatec/devise",
  ref: "acc45c5a44c45b252ccba65fd169a45af73ff369" # "2018-08-02"

# consider hard-lock on gems you do not want to change one bit
gem "rails", "5.1.5"

# pessimistic lock on your common gems
gem "newrelic_rpm", "~> 4.8.0"
gem "puma", "~> 3.12.0"

group :test do
  gem "simplecov", "~> 0.16.1", require: false
end

一个让步
如果您确信测试会捕获由gem版本更改引入的错误,则可以尝试在次要版本而不是补丁中悲观地锁定gem。
这将使gem版本在指定的主要版本之内增加,但绝不会增加到下一个版本。

gem "puma", "~> 3.12"

1
悲观这个词在这里令人困惑(我理解这只是语义,但仍然如此)。如果您将其锁定到=的版本上,那是悲观的!但是〜>实际上允许您更新到最新的次要版本。
Joel_Blum

2
你写了You want to organize your Gemfile in such a manner that you can run bundle update any time without risking breaking everything。不,这不是目标。这听起来像你可能不明白之间的差别bundle updatebundle installupdate 更新Gemfile.lock和改变了你正在使用的版本。您希望能够在任何时间运行bundle install而不会冒险破坏所有内容。正因为如此,你强迫Gemfile做什么Gemfile.lock的意思做。
iconoclast

2
那些“行业专家”是正确的:实际上Gemfile.lock 确实维护了gem版本。直到(当然)你决定覆盖它bundle update(这基本上就像在说bundle overwrite_my_locked_gem_versions)。
iconoclast

@iconoclast我们不同意“ maintain”一词的含义。对我来说,这意味着与时俱进的有限变化意识,而不是完全不变。
Epigene,

1
我看到它的方式(这就是我首先写答案的原因),存在一个误解,即仅仅因为存在一个Gemfile.lock具有所有确切版本的文件,开发人员就无需在其中指定gem版本Gemfile(锁定的想法“维护”版本)。那是错误的。开发人员通过指定版本Gemfilebundle update偶尔运行来“维护”版本。
Epigene,

6

我肯定会说使用确切的版本号。您可能总是可以将其锁定在主要版本上,也可以永远不指定任何版本,这样就可以了,但是如果您确实想要这种细粒度的控制,并且在其他计算机上运行时对程序有100%的信心,使用确切的版本号。

我一直在未指定确切版本号的情况下,当我或其他人执行a时bundle install,该项目失败了,因为它转到了较新的版本。在部署到生产环境时,这尤其糟糕。

Bundler确实锁定了您的gem规范,但如果您告诉它仅使用主要版本,则它将锁定它。因此,我们知道“哦,版本锁定在> 0.1”或诸如此类,但不是“哦”该版本专门锁定在0.1.2.3“。


11
如果Gemfile.lock存在的话,那么Bundler确实知道要安装哪个特定版本(这就是为什么Gemfile.lock应该将它与一起存储在仓库中Gemfile)的原因。
mipadi 2012年

3
bundle update <gem>即使Gemfile.lock存在,执行“尽管”操作可能最终会比您想象的更多地进行更新,这可能是危险且棘手的情况。
MrDanA 2014年

1
我同意RubyGems自己在此问题上的建议:只需使用悲观约束(〜>)。这鼓励了整个社区使用语义版本控制,这是一件好事,在这与Gemfile的内置稳定性功能之间。锁定您的基础不应该被覆盖。
user456584

1
@solidcell我不认为每次更新gem时都必须输入源代码。我更喜欢使用尽可能精确的版本,但是正如所提到的,您通常可以在大多数时间使用〜>约束。但是,我以前曾给过我一个新的,错误的宝石版本。
MrDanA 2014年

1
您不需要(也不需要)在中使用确切的版本Gemfile。这是目的Gemfile.lock。如果您执行Gemfile.lock源代码管理,那么有人拉扯并执行此操作bundle install将获得与您完全相同的gem版本。设置确切的版本会Gemfile阻止您执行操作,bundle update gem_you_want_to_update而悲观的版本(~>)或根本没有版本,则可以运行bundle update gem_you_want_to_update并获取最新的(次要)版本
PhilT 2016年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.