自从 2 年前 Sam 帮我搭建了 Ruby 环境,除了升级就再没折腾过。懒,不爱折腾,太花时间,投入产出不成正比。
但是在开发的过程中,越来越多 Rvm & Bundler 的问题摆在了我面前,每次都要请教别人,十分的影响效率。
于是花了一个上午的时间彻底把 Rvm 和 Bundler 的关系梳理了一下。
Rvm 用于管理 Ruby 的版本和该版本的 Gem。
一开始我很疑惑,为什么同一个 Gem,同一个版本号,要保存四份?
据大牛回答,有些 Gem 需要编译,所以依赖 Ruby 版本。比如在 Ruby 1.9.3 的环境下编译的 libv8 (3.11.8.17)不一定能在 Ruby 2.0.0 中使用。
所以即使相同版本号的 Gem,也要在各个 Ruby 各自编译,各自保存。
事实上 Rvm 在管理 Gem 的方式上要比图一还要复杂 一些,它的内部还有一套 Gemsets 的机制。
我把 Gemset 理解为一个环境,这个环境中罗列了 Gem 的版本号。
Gemset 大体可分为三类:
比如:ruby-1.9.3-p448@global
安装在 @global 中的 Gem 会被其他 Gemset 继承。假如我在 ruby-1.9.3-p448@global 中安装了 bundler-1.1.5,那么 ruby-1.9.3-p448@codecampo 也可以使用 bundler-1.1.5。
比如:ruby-1.9.3-p448
若不指定 Gemset,Gem 都安装在默认环境下。
自定义的 Gemset,比如
你可以创建一个 ruby-1.9.3-p448@ruby_china 的环境用来跑 Ruby China,你也可以创建 ruby-1.9.3-p448@codecampo 跑 codecampo。
很早之前我有类似的疑问:我的每个项目都使用 Bundler 生成 Gemfile、Gemfile.lock 管理版本号和依赖关系。为毛还需要 Rvm Gemset?
我们现在的确不需要!
但,爱过。
Rvm 诞生于 Bundler 之前,并通过 Gemset 这种的式来管理 Gem(作者在此处先入为主,搞错啦,建议大家看楼下 @nightire 大牛的点评)。
随后 Bundler 才兴起,大家几乎都一窝蜂似的用它管理项目中涉及 Gem 的版本号、依赖关系。从而导致了 Rvm 的 Gemset 处于十分尴尬的地位。
rvm 下貌似使用每个 gemset 版本都是独立的一套 gems,没看见有软链啊 我觉得 rvm 主要是为了解决 ruby 和 gem 版本的冲突问题(gemset) gemfile 就是为了绑定 gem 版本用的,多个项目 gem 版本有冲突的时候可以用 gemset 解决
#5 楼 @xiaoronglv gemset 还是有好处的嘛.. 可以用 rvmrc 自动切换 gemset 环境,然后直接敲命令就是使用这个 gemset 里面的版本。如果用 bundler 的话就要 bundle exec
我觉得楼主的研究有一些地方都是先入为主的下一个结论,然后去凑证据来证明自己所言非虚。
比如说:> RVM 诞生于 Bundler 之前……处于十分尴尬的地位
我就想问一句了,你这段的因果关系是怎么来的?因为自己用不好,所以就觉得 gemset 是一个很尴尬的东西?RVM 诞生于 Bundler 之前这句话就 更是可笑 有点问题了,不知道从哪里找来的证据?但如果你能在下结论之前去看一眼 Github 上的提交记录,就知道事实恰好相反。
gemset 和 bundler 根本要解决的就不是同一个问题,也不知道有什么好对比的。一个关注的是本地环境,一个关注的是项目自身的依赖,使用它们的时候思维模型根本都是不同的。
和 Bundler 打交道的时候,思维模型是:不管什么样的环境,反正对于这个项目,我要求 gems 怎样怎样/或者针对特定条件的环境(比如某种特定版本的解释器),我要求 gems 怎样怎样
和 gemset 打交道的时候,思维模型是:不管什么样的项目,只要切换到我(gemset)这里,我就可以提供 xxx 版本的 xxx gems 供你使用。你当然可以更新我(gemset)管理的 gems,但是记住:你创造我的目的就是为了给本地开发环境设定一个可控的 gems 环境。如果你不 care 这件事情,请你直接使用 global gemset,然后从此忘了我吧——懂得人自然懂。
http://sirupsen.com/get-started-right-with-rvm/
When I wrote this article, bundler wasn’t commonly found in Ruby projects as it is now.
我在这篇文章中读到这个观点,没有仔细考证,结果误人子弟啦。在 Github 上,Bundler 的项目更早一些。
貌似很多人讨厌 gemset,就转到更简单的 rbenv 了。
bundler 先出来还是 rvm 的 gemset 先出来就不太清楚了,我只知道 gemset 这东西在 rails2 时代,到处横行,一台服务器上装多几个 rails app,不用 gemset 我记得会很麻烦,会有各种冲突出现。就算用了,也会有各种麻烦的问题。 bundler 啥时候出来啥时候开始就不太清楚了,但是我只知道 rails 有了 Gemfile(Bundler) 之后,gemset 存在的意义似乎已经不大了。因为用了 bundler 之后再也没有以前那些痛苦的问题,以至于都忘记 gemset 的存在了。
这两者解决的是同一个问题吗?是的,对于我来说是的,对于你来说是不是我就不知道了,我不知道 gemset 还能解决什么问题。而且从一开始,我就觉得 gemset 这东西就是个错误的解决办法,以至于很容易一团乱麻。
#9 楼 @xiaoronglv gemset 只是一个工具,如果你觉得它讨厌那就别用好了,这和你是否要从 rvm 转移到 rbenv 完全没有关联。你知道 rbenv 也有 gemset 吗?那为什么不会因为讨厌 gemset 而从 rbenv 转向 rvm 呢?这从道理上就完全说不通不是么?
至于说有没有人用 gemset,肯定是有的,我自己就在用。不过就像我之前说的,gemset 就是一个工具而已,派的上用场你就用,派不上了或者有更好的方式取代它了,那就不用。没什么大不了的。
举个例子吧。比方说我们常有两个项目用不同版本的 rails 的,如果你不用 gemset 也行啊,每一个项目用 bundler 去约束 rails 的版本好了。但相应的,执行 CLI 命令的时候一定不要忘了加上 bundle exec
,否则就会搞错不同版本的 rails 命令;反过来,如果你用 gemset 来分开不同版本的 rails,那就不用理会 bundle exec
了。在很长一段时间里,gemset 都带给我这样的好处。另外还有一点好处,如果你的 Ruby 升级了,你可以很方便的 export/import 指定的 gemset,而不需要费时费力的重新 gem install
。
随着 Rails 的发展,现在更流行使用 binstub 了,上面提到的第一个好处倒是变得可有可无了。不过还是有很多人都用 ./bin/rails
这样的方式来执行 rails 命令,因为如果不这样做的话,命令行会使用全局的那个 rails
而不一定是你当前项目指定的版本。于是这么一来,比之 bundle exec rail
貌似也没进步到哪儿去是吗?但是,工具是需要灵活应用的,如果你配置一下环境变量 $PATH
,让 ./bin/
成为命令查找路径里最高优先级的一个,就又可以像使用 gemset 那样直接敲 rails
了。事实上,gemset 的原理也就是如此——劫持你的环境变量,把优先级指向你创建的 gemset 里的命令而已。
工具而已,没什么高低贵贱之分。
#21 楼 @comensontin 嗯,你说的是对的,这个问题的确是一个安全隐患,值得说明一下。我还好只是在本地开发用机上这么干,纯粹图省事而已。不过话说回来如果我 ls
一下就会问我要密码,那傻子也知道不对劲了,我没有一直用 root 干活的习惯。
我是用 gemset 来保证 rake 和 bundler 的版本的 有的老项目没有人修护,一些 rake 或是 bundler 的升级会造成项目的破坏 工具都是适用环境的,你在本机上会觉得那么多 gemset,占那么大空间不合算 但到了产生环境,几 G 的空间不算什么,在稳定压倒一些的前提下,老板不会让你升级老版本的环境
RVM 解释的挺好的,最后一段有点儿虎头蛇尾的感觉=,=
我一直都用 RVM 管理不同的项目环境,主要是当有太多不同版本的 Ruby 和 Gem 的时候,我觉得 RVM 的环境感觉比较纯净吧。(新人学习中.... 虽然没遇到,不同版本的同一个 GEM 没准会有冲突?)
另外,作为精华帖,标题太误导了。我还以为 Bunder 是 RVM 的前身或转世什么的。
@nightire 看帖子进来插一句嘴,你发帖的语气能不能好一些,读起来怪怪的,不能温柔善良幽默和蔼可亲一些吗?人家就是发个帖子而已,你觉得有错你指出来来行了,不能少用一些“可笑”这样的词吗?这个事有那么可笑吗?
./bin
加到 $PATH 的最前面不可取,如果我在项目里面的 bin 里面丢个木马,名字叫做 ls
,然后通过某种手段诱骗你去下载这个项目……
-- update sorry,原来 @comensontin 已经说过了
#30 楼 @dave 改过之后多说两句,也不是为了解释什么,就是跟你说一下选择那种方式说话的原因。实际上我对楼主没有任何敌意,也没有轻视的念头,但为什么我回复的语气比较“阴阳怪调”呢?那是因为我从楼主的字里行间读出了一种“潜意识”(当然是我过分敏感了吧),我觉得楼主在做他的研究的时候有种先入为主的念头,那就是“Gemset 对于 RVM 来说是一个鸡肋/败笔”,我觉得这种做学问的态度是不对的,比不做学问还可怕,因为你胡说八道大家都看得出来,一笑置之就罢;但若你长篇累牍,一般人就看不出问题所在,很容易被你误导。最近一段时间因为工作的原因遇到了一些类似的人和事情,生了很大的气,所以魔由心生,不觉得就有些代入感过强了。
当然了,我说话的态度更是不对的,如你所说:若有错误指出来便是,不应在言语上令人难堪,否则也不足以服人,更不要说服众。此后关于 ./bin
追加给 $PATH
的讨论就能侧面反映出这一点,我自己由于很小心所以没有出过什么岔子,但是其他人说的不安全之处更加值得注意,我已经改掉了自己的习惯,也很感谢大家让我涨了这个见识。由此可见学问处处皆可见,莫因先知笑后觉。再次感谢你的提醒,总的来说社区对我是相当宽容的,Ruby 并非我的最强项,但我偶然的发言却也总能得到大家的肯定和鼓励,想想我也的确应该更加柔和厚重,才是一个回报的态度,兄弟的当头棒喝真的很及时,谢在心里不多废话了。
ggg #38 楼 @xiaoronglv give me a link please. There are a lot of skitchs on the web. Sorry for the input method.