I'm working on a project that runs on Rails ~> 3.0
on the master
branch, and ~> 3.1
on another branch.
Obviously those 2 branches need different gemsets.
Do you know of a convenient way of handling the situation using RVM?
I've thought of a couple options, none of them optimal:
using
gemset
s I would have to remember to manually switchgemset
after eachgit checkout
using
bundle package
I would have to track thevendor/bundle
directorya mix of the two approaches is not even possible, since
.bundle/config
is not trackedI could write a
git
post-checkout
hook, but it sounds a bit hacky (hardcoded branch names and all that)
Is there a better开发者_如何学编程 way that I'm failing to think of?
You will no longer have to do that when you change into a project directory. RVM 1.8.1 had this reenabled by default. (I've added documentation regarding that to the site and to rvm notes)
However, since this is an in-directory rvmrc change, and the change in the .rvmrc is not picked up, you can force it by doing an 'rvm reload'. The change should be picked up, but if its not then do the reload.
Please post any issues you have after doing this to https://github.com/wayneeseguin/rvm/issues
Thank you,
Deryl R. Doucette
NOTE: After talking with Wayne, he passed on to me via IRC that he would recommend that you do something along the lines of this in your .bash_profile to aid in what you want:
git() { command git "$@" ; [[ -s .rvmrc ]] && . .rvmrc ; }
Also, so you understand, RVM does not run as a daemon in any way shape or form. So what you want RVM to do most definintely will not be added to RVM. As Wayne said, that would be a fun way to mess with someone's head though! :)
Think of it this way. While admittedly contrived, the action is still the same. What if someone changes the rvmrc under you while you're in the middle of something (another dev working on the dir and doesn't know you are), or some rogue beastie has hacked your system and changes your rvmrc on you thinking he might gain some additional privs somehow by doing so. (This could be in a group controlled project directory where he's obtained access through another user's account, figures out that you are in the same group, changes the rvmrc underneath you to a different ruby+gemset that he's managed to set up through group permissions of the RVM group in a multi-user install, and causes some arbitrary command to be executed. Imagine further, that you are in, say, the wheel group and you just finished executing some command for root and the timeout has not completed yet for authorization reduction. Since an rvmrc is really nothing more than a bash script, thats not a far stretch of the imagination. So in the end, that makes for a VERY hazardous environment, not to mention an extremely difficult situation to monitor and control.
You could create an .rvmrc file inside your project directory and add it to the git repo. For one branch, the .rvmrc file would contain a line like
rvm 1.9.3-head@rails30 --create
for the other branch it would contain
rvm 1.9.3-head@rails31 --create
That way you'd end up with two gem sets (rails30 and rails31). Also don't forget to activate automatic execution of .rvmrc files in your {home}/.rvmrc (necessary for latest version of rvm, see rvm documentation).
I ended up using the following git post-checkout
script.
In the master
branch, I was using gems installed in $GEM_HOME
. In the other branches, gems were installed locally to vendor/cache
.
#!/usr/bin/env bash
#set -x
git_rev() {
ref=$(git symbolic-ref HEAD 2>/dev/null) || return
echo ${ref#refs/heads/}
}
ref=$(git_rev)
case $ref in
master)
echo "removing .bundle/config"
mv .bundle/config .bundle/config.no
;;
*)
if [ -f .bundle/config.no ] ; then
echo "using vendor/cache"
mv .bundle/config.no .bundle/config
fi
;;
esac
To follow on morgler's answer, if you have your .rvmrc checked into your git project, you could use git completion to add the git branch name into the .rvmrc gemset name to automate the creation of a gemset for each branch, like:
PROJECT_NAME="my_app"
RUBY_VERSION="ruby-1.9.2-p290"
GEMSET_NAME="${PROJECT_NAME}"
# if you have bash completion setup the way I do, you get a gemset for each git branch
if [ -f /usr/local/etc/bash_completion.d/git-completion.bash ]; then
. /usr/local/etc/bash_completion.d/git-completion.bash;
GEMSET_NAME="${PROJECT_NAME}-$(__git_ps1 '%s')";
fi
rvm --create "${RUBY_VERSION}@${GEMSET_NAME}"
(Note: You'll probably have to modify this. It works for me in OS X, but I was already using git completion for my terminal prompt.)
Then cd into the directory and if you do rvm gemset list, you should see that a gemset was created for that git branch. The only hiccup is that after you create a new git branch, you'd need to cd out and in of the directory to get it to recognize the different gemset create in .rvmrc (even though .rvmrc is the same file, it will behave differently).
This is not a perfect solution, and everyone in the project has to be on-board with this. If you put .rvmrc in for one project, you should consider using it for all of them, otherwise just by cd'ing into a directory, the ruby version and gemset could change, and then if you go back to another project that doesn't have an .rvmrc, you might not notice it changed and have trouble.
Edit: Michal Papis mentioned that:
a possible solution for this would be to use .versions.conf introduced here: https://gist.github.com/1912050#gistcomment-86575 - it should be easy to put there a flag -> ruby-gemset-git-branch which would append branch to gemset name if different then master
Use rbenv instead of RVM. Then you'll manage your gems entirely using Bundler.
Modify your Gemfile so that one branch is for Rails 3, and the other for Rails 3.1.
Then run bundle exec rails server
when starting WEBrick and bundler will use the version of Rails that the branch you are on needs. Keeps things DRY ;)
Read my short intro to getting started with rbenv.
精彩评论