bundle exec bash

The bundler README makes passing mention of bundle exec bash—when you bundle everything, you want to avoid typing bundle exec rake all the time.

Here are 3 tips to help you enjoy the experience:

Sort your .bashrc from your .profile

The first time I ran bundle exec bash, I lost the git branch from my prompt:

~/Code/captain master* bundle exec bash
bash: __git_ps1: command not found
~/Code/captain

Poring through the documentation for the bash startup files, here’s what I pieced together:

Connecting the dots, you’ll want to:

  1. Move all your aliases, functions and completions out of ~/.profile and into ~/.bashrc. (example)

  2. Source your ~/.bashrc at the bottom of your ~/.profile:

if [ -f ~/.bashrc ]; then
  source ~/.bashrc
fi

And then you should have __git_ps1 and friends again:

~/Code/captain master* bundle exec bash
~/Code/captain master*

Beware the RUBYOPT

What you can’t see in the prompt above is the next problem I ran into. I should have written something more like this:

~/Code/captain master* bundle exec bash
... THREE SECOND DELAY ...
~/Code/captain master*

Here’s what’s going on:

  1. __git_ps1 calls git 5 or 6 times.

  2. I had mixed (the non-rubygems version of) hub into git with alias git=hub.

  3. bundle exec adds -rbundler/setup to your RUBYOPT.

Boom! I was resolving the dependencies in my Gemfile 5 or 6 times just to generate a prompt!

The simple workaround is to clear RUBYOPT when calling hub:

alias git='RUBYOPT= hub'

Show the bundle in your prompt

It gets hard to remember if you’ve already run bundle exec bash, or, if you tend to cd wildly all over the place, which project you ran it in.

With this function in your ~/.bashrc:

function __bundler_ps1 {
  if [ -n "${BUNDLE_GEMFILE-}" ]; then
    project_path="${BUNDLE_GEMFILE%/Gemfile}"
    project_name="${project_path##**/}"

    if [ -n "${1-}" ]; then
      printf "$1" "${project_name}"
    else
      printf " (%s)" "${project_name}"
    fi
  fi
}

And a PS1 setting in your ~/.profile that calls it:

export PS1='\[\e[36m\]$(__bundler_ps1 "[%s] ")\[\e[0m\]\w\[\e[35m\]$(__git_ps1 " %s")\[\e[0m\] '

You’ll see the name of the active bundle in your prompt:

~/Code/captain master* bundle exec bash
[captain] ~/Code/captain master*

Conclusion

It seems like the main thing I’m learning is that it’s worth spending time tinkering with your $SHELL.

Along the way, I’ve found it immensely helpful to version my dotfiles. If you haven’t done that yet, make it your weekend project—you’ll love the freedom it gives you to experiment! I found Joe Ferris’ install.sh quite helpful as I got started.