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

发布于 2025-01-05 11:11:34 字数 799 浏览 4 评论 0原文

我注意到 ruby​​gems.org 上的很多 gem 建议您通过主要版本而不是确切版本来指定它们。例如...

haml-rails gem...

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”你的所有 gem 版本。

但在 ruby​​gems.org 上他们使用“~>”很多,所以也许我错过了一些东西?

任何澄清都会对我理解 Bundler 和 gem 管理非常有帮助。

I've noticed that on rubygems.org a lot of the gems suggest you specify them by major version rather than exact version. For example...

The haml-rails gem...

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

However, based on the Bundler docs it sounded to me like it would be better to nail down the exact version like this...

gem "haml-rails", "0.3.4"

So there's your haml-rails gem and all its dependencies won't drift forward. If you check out the project on a different machine a few weeks later and run $ bundle install you'll have precisely the same versions of everything you specified.

I've seen point releases break stuff, and I thought part of the whole idea of Bundler was to "Bundle.lock" all your gem versions.

But on rubygems.org they use "~>" a lot so maybe I'm missing something?

Any clarification would be very helpful to me in understanding Bundler and gem management.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

箹锭⒈辈孓 2025-01-12 11:11:34

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

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

简而言之,按照 ruby​​gems.org 的建议,使用悲观版本约束运算符 (~>) 通常应该是安全的。请务必在执行捆绑包更新后重新运行测试,以确保没有任何问题。

Yehuda Katz 有一篇好文章,其中包含有关 Gemfile.lock 的更多信息。

This is the purpose of the Gemfile.lock file - running bundle install with a Gemfile.lock present only installs using the dependencies listed in there; it doesn't re-resolve the Gemfile. To update dependencies / update gem versions, you then have to explicitly do a bundle update, which will update your Gemfile.lock file.

If there wasn't a Gemfile.lock, deploying code to production would be a major issue because, as you mention, the dependencies and gem versions could change.

In short, you should be generally safe using the pessimistic version constraint operator (~>) as rubygems.org advises. Just be sure to re-run your tests after you do a bundle update to make sure nothing breaks.

There's a nice article by Yehuda Katz that has a little more info on Gemfile.lock.

一梦浮鱼 2025-01-12 11:11:34

TL;DR

是的,使用悲观锁定 (~>)并指定要修补的语义版本Major.minor.patch< /代码>) 上你所有的宝石!

讨论

我对这个问题缺乏明确性感到惊讶,甚至“行业专家”前几天告诉我 Gemfile.lock 是为了维护 gem 版本。错误的!

您希望以这样的方式组织您的 Gemfile,以便您可以随时运行 bundle update 而不必冒破坏所有内容的风险。要实现此目的:

  1. 为所有带有悲观锁定的 gem 指定补丁级别版本。这将允许bundle update为您提供修复,但不会进行重大更改。

  2. 为 git 中的 gem 指定一个 ref

此设置的唯一缺点是,当一个新的次要/主要gem 的版本出来了,你必须手动升级版本。

警告场景

考虑一下如果您不锁定宝石会发生什么。
您的 gemfile 中有一个未锁定的 gem "rails",并且 Gemfile.lock 中的版本是 4.1.16。您正在编写代码,并在某个时候进行捆绑包更新。现在你的 Rails 版本跳转到 5.2.0 (假设其他一些 gem 不能阻止这种情况)并且一切都会崩溃。
帮自己一个忙,不要让任何宝石出现这种情况!

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"

TL;DR

Yes, use pessimistic locking (~>) and specify a semantic version down to patch (Major.minor.patch) on all your gems!

Discussion

I am surprised by the lack of clarity on this issue, even "industry experts" told me the other day that Gemfile.lock is there to maintain gem versions. Wrong!

You want to organize your Gemfile in such a manner that you can run bundle update any time without risking breaking everything. To achive this:

  1. Specify a patch-level version for all your gems with pessimistic locking. This will allow bundle update to give you fixes, but not breaking changes.

  2. Specify a ref for gems from git

The only downside to this setup is that when a sweet new minor/major version for a gem comes out, you have to bump the version up manually.

Warning scenario

Consider what happens if you do not lock your gems.
You have an unlocked gem "rails" in your gemfile and the version in Gemfile.lock is 4.1.16. You are coding along and at some point you do a bundle update. Now your Rails version jumps to 5.2.0 (provided some other gem does not prevent this) and everything breaks.
Do yourself a favor and do not allow this for any gem!

An example 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

A concession
If you are confident your tests will catch bugs introduced by gem version changes, you can try pessimistic-locking gems at minor version, not patch.
This will allow the gem version to increase within the specified major version, but never into the next one.

gem "puma", "~> 3.12"
梦冥 2025-01-12 11:11:34

我肯定会说使用确切的版本号。您可能总是可以将其锁定到一个主要版本,或者从不指定任何版本,这样就可以了,但是如果您确实想要细粒度的控制级别并且在其他机器上运行时对您的程序有 100% 的信心,使用准确的版本号。

我曾经遇到过未指定确切版本号的情况,当我或其他人进行捆绑安装时,项目会崩溃,因为它转到了较新的版本。当部署到生产环境时,这可能尤其糟糕。

Bundler确实锁定你的 gem 规范,但如果你告诉它只使用主要版本,那么它就会锁定它。所以它只知道“哦,版本被锁定在 > 0.1 ”或其他什么,但不是“哦,版本被明确锁定在 0.1.2.3”。

I would definitely say use the exact version numbers. You can probably always just lock it down to a major version, or never specify any version, and be okay, but if you really want that fine grained level of control and to have 100% confidence in your program when being run on other machines, use the exact version numbers.

I've been in situations where the exact version number wasn't specified, and when I or someone else did a bundle install, the project broke because it went to a newer version. This can be especially bad when deploying to production.

Bundler does lock in your gem specifications, but if you're telling it to just use a major release, then it locks that in. So is just knows "Oh the version is locked in at > 0.1" or whatever, but not "Oh the version is locked in specifically at 0.1.2.3".

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文