Running 'git clone' in order to install the RBENV codebase from source.

In my walk-through of the RBENV codebase, we do a lot of experiments which involve modifying the code and then running it. The goal is sometimes to break the code intentionally for educational purposes, and other times just to log what's happening as it happens.

If you'd like to follow along with those, the first step is to install RBENV on your machine.

Even if you've already installed RBENV, you'll want to read this post, since there's a good chance you previously installed it using Homebrew or another package manager, and that won't work for our purposes. When installed via Homebrew, we don't have access to RBENV's git repository, and we'll need that in order to roll back to a common version.

If you'd rather not do this, you can still follow along with the RBENV code via its Github repo, or by cloning said repo to your machine. You'll still be able to perform any experiment we do in this guide which isn't RBENV-specific.

I'm writing this tutorial on a Macbook running macOS, and I'll be using macOS-specific installation instructions and commands throughout.

Ensuring you have no other version managers installed

Admittedly, the best candidates for reading this guide are people who already use RBENV as their Ruby version manager. As you'll soon see, users of other version managers (such as rvm, asdf, chruby, etc.) will face more and bigger hurdles than users of RBENV (more on why in a minute).

With that in mind, we'll need to make sure you don't have a different Ruby version manager installed, such as RVM. If you do, that will represent a blocker to your continuing this guide, since you'll have different version managers competing to manage your Ruby version. This could introduce unexpected behavior and negatively impact your usage of Ruby.

We can check for the most popular Ruby version managers by using the which command:

$ which asdf
asdf not found
$ which rvm
rvm not found
$ which chruby
chruby not found
$ 

If you see anything other than "not found" for which asdf, which rvm, and which chruby, you likely have another version manager on your machine. In that case, you'll need to make a decision about which version manager you want to use. RBENV's Github page has a guide on the pros and cons of the various version managers out there.

If you don't have other version managers on your machine, feel free to move on to the next section.

Making sure RBENV is installed correctly

Installing RBENV via brew install rbenv would be a perfectly fine option for a normal user. But it won't work for our purposes, because it would leave us without access to RBENV's .git directory, and therefore its git history. That means we couldn't roll back to the specific version of RBENV that I'll be using for this walk-through. It's important that we work off the same codebase, so let's try another technique- installing from source.

To do this, we'll follow the instructions on this version of the RBENV Readme file. First, open your terminal and check whether you already have a directory called ~/.rbenv, by running ls -la ~/.rbenv:

$ ls -la ~/.rbenv
total 80
drwxr-xr-x  18 richiethomas          staff    576 Jan  9 14:11 .
drwxr-x---+ 36 richiethomas          staff   1152 Jan 10 12:23 ..
drwxr-xr-x  13 richiethomas          staff    416 Jan  9 14:11 .git
drwxr-xr-x   3 richiethomas          staff     96 Jan  9 14:11 .github
-rw-r--r--   1 richiethomas          staff     97 Jan  9 14:10 .gitignore
-rw-r--r--   1 richiethomas          staff     35 Jan  9 14:10 .vimrc
-rw-r--r--   1 richiethomas          staff   3390 Jan  9 14:10 CODE_OF_CONDUCT.md
-rw-r--r--   1 richiethomas          staff   1058 Jan  9 14:10 LICENSE
-rw-r--r--   1 richiethomas          staff  18411 Jan  9 14:11 README.md
drwxr-xr-x   3 richiethomas          staff     96 Jan  9 14:10 bin
drwxr-xr-x   4 richiethomas          staff    128 Jan  9 14:11 completions
drwxr-xr-x  27 richiethomas          staff    864 Jan  9 14:11 libexec
drwxr-xr-x   3 richiethomas          staff     96 Dec 23 11:37 rbenv.d
drwxr-xr-x  39 richiethomas          staff   1248 Jan  9 14:35 shims
drwxr-xr-x   7 richiethomas          staff    224 Jan  9 14:11 src
drwxr-xr-x  28 richiethomas          staff    896 Jan  9 14:11 test
-rw-r--r--   1 richiethomas          staff      6 Dec 23 11:38 version
drwxr-xr-x   5 richiethomas          staff    160 Dec 23 11:38 versions
$ 

If this directory does exist, and if the command output includes a .git/ directory in it like it does above, you should be good to go.

Another possibility is that the output exists but looks like this:

$ ls -la ~/.rbenv
total 8
drwxr-xr-x   5 richiethomas  staff   160 Jan 10 12:56 .
drwxr-x---+ 37 richiethomas  staff  1184 Jan 10 12:56 ..
drwxr-xr-x  15 richiethomas  staff   480 Jan 10 12:56 shims
-rw-r--r--   1 richiethomas  staff     6 Jan 10 12:57 version
drwxr-xr-x   3 richiethomas  staff    96 Jan 10 12:48 versions
$ 

Specifically, you run the ls -la command and you don't see a .git folder included in the output.

That likely means you previously installed RBENV using a package manager like Homebrew. If this is the case, one option is to simply rename your /.rbenv directory as /.rbenv-old or something similar:

$ mv ~/.rbenv/ ~/.rbenv-old

After the old RBENV folder is renamed, we can install RBENV again via source, by following the instructions on this version of the RBENV Readme file. Run the following command:

$ git clone https://github.com/rbenv/rbenv.git ~/.rbenv
Cloning into '/Users/richiethomas/.rbenv'...
remote: Enumerating objects: 3270, done.
remote: Counting objects: 100% (420/420), done.
remote: Compressing objects: 100% (218/218), done.
remote: Total 3270 (delta 234), reused 327 (delta 188), pack-reused 2850
Receiving objects: 100% (3270/3270), 662.28 KiB | 258.00 KiB/s, done.
Resolving deltas: 100% (2024/2024), done.
$ 

Once this is done, you should have a fresh installation of RBENV inside ~/.rbenv, which includes a .git directory:

$ ls -la ~/.rbenv
total 80
drwxr-xr-x  18 richiethomas  staff    576 Jan 10 13:03 .
drwxr-x---+ 37 richiethomas  staff   1184 Jan 10 13:03 ..
drwxr-xr-x  12 richiethomas  staff    384 Jan 10 13:03 .git
-rw-r--r--   1 richiethomas  staff     47 Jan 10 13:03 .gitattributes
drwxr-xr-x   4 richiethomas  staff    128 Jan 10 13:03 .github
-rw-r--r--   1 richiethomas  staff     97 Jan 10 13:03 .gitignore
-rw-r--r--   1 richiethomas  staff     35 Jan 10 13:03 .vimrc
-rw-r--r--   1 richiethomas  staff   3390 Jan 10 13:03 CODE_OF_CONDUCT.md
-rw-r--r--   1 richiethomas  staff   1058 Jan 10 13:03 LICENSE
-rw-r--r--   1 richiethomas  staff    163 Jan 10 13:03 Makefile
-rw-r--r--   1 richiethomas  staff  12636 Jan 10 13:03 README.md
drwxr-xr-x   3 richiethomas  staff     96 Jan 10 13:03 bin
drwxr-xr-x   4 richiethomas  staff    128 Jan 10 13:03 completions
drwxr-xr-x  27 richiethomas  staff    864 Jan 10 13:03 libexec
drwxr-xr-x   3 richiethomas  staff     96 Jan 10 13:03 rbenv.d
drwxr-xr-x   3 richiethomas  staff     96 Jan 10 13:03 share
drwxr-xr-x   4 richiethomas  staff    128 Jan 10 13:03 src
drwxr-xr-x  28 richiethomas  staff    896 Jan 10 13:03 test
$ 

Ensuring your new RBENV install has your old data

Next, we'll copy your currently-installed Ruby versions, gems, etc. to this new installation, ensuring that you can continue using RBENV as you did before:

$ cp -r ~/.rbenv-old/versions \                                                                                     
> ~/.rbenv-old/version \                                                                        
> ~/.rbenv-old/shims \                                                     
> ~/.rbenv-old/rbenv.d \                                
> ~/.rbenv-old/completions \       
> ~/.rbenv
$ 

Now, the version of RBENV which you installed from source should have any and all gems, installed Ruby versions, selected Ruby version, completions, and hooks that you may have previously installed in your old RBENV version.

If you ever encounter version-related problems with Ruby or RBENV on your machine from now on, you can simply delete the version of RBENV that we just installed, and rename your ~/.rbenv-old directory back to ~/.rbenv, and you should be good-to-go.

Rolling back to the correct git commit

Next, let's navigate into this directory via cd ~/.rbenv.

We want to make sure that we're all looking at the same code, which means looking at the same git commit. So we'll create a new branch, separate from your master or main branch, and point that branch to a specific commit, i.e. the one that I used when I started writing this guide (that commit SHA is c4395e58201966d9f90c12bd6b7342e389e7a4cb).

I called my new branch impostorsguides, but you can call it whatever is easiest for you to remember:

$ git checkout -b impostorsguides
Switched to a new branch 'impostorsguides'
~/.rbenv (impostorsguides)  $ git reset --hard c4395e58201966d9f90c12bd6b7342e389e7a4cb
HEAD is now at c4395e5 Merge pull request #1418 from uraitakahito/patch-0
$ 

For future reference, the Github link to this specific version of the RBENV codebase can be found here.

Enabling RBENV's shell function

We're getting close to the end, but we still have 2 more steps in the installation instructions. Next we have to add some text to our shell's startup script. This script will create a shell function called rbenv, which (for our purposes) will do the same job as if we were running the command from a file.

The RBENV Readme file tells you how to add the text to your script. The command you'll copy/paste into your terminal depends on which shell program (bash, zsh, etc.) you're running:

2. Configure your shell to load rbenv: For bash: Ubuntu Desktop users should configure ~/.bashrc:
echo 'eval "$(~/.rbenv/bin/rbenv init - bash)"' >> ~/.bashrc
On other platforms, bash is usually configured via ~/.bash_profile:
echo 'eval "$(~/.rbenv/bin/rbenv init - bash)"' >> ~/.bash_profile
For Zsh:
echo 'eval "$(~/.rbenv/bin/rbenv init - zsh)"' >> ~/.zshrc
For Fish shell:
echo 'status --is-interactive; and ~/.rbenv/bin/rbenv init - fish | source' >> ~/.config/fish/config.fish

To find out which shell you're running, run the following command:

$ echo $SHELL

In my case, since I'm on a new Mac, my default terminal is Zsh:

$ echo $SHELL
/bin/zsh
$

Therefore, I'd paste the following into my terminal:

$ echo 'eval "$(~/.rbenv/bin/rbenv init - zsh)"' >> ~/.zshrc

This will add the text eval "$(~/.rbenv/bin/rbenv init - zsh)" into a file called ~/.zshrc, which is run every time I open a new terminal tab. If your terminal is different from mine (for example, bash), the filename will be different from ~/.zshrc (for example, ~/.bashrc), but the gist of what's happening is still the same.

Lastly, in order for these changes to take effect, I'll need to do exactly that- open a new terminal tab. When I do so, and I run which rbenv, I see the following shell command definition:

$ which rbenv
rbenv () {
  local command
  command="${1:-}" 
  if [ "$#" -gt 0 ]
  then
    shift
  fi
  case "$command" in
    (rehash | shell) eval "$(rbenv "sh-$command" "$@")" ;;
    (*) command rbenv "$command" "$@" ;;
  esac
}
$

If we see the above output, we know RBENV has been successfully installed.

Generating an RBENV shim

The last thing we should do is make sure our Ruby version and its associated gems will be managed by RBENV (not by the system). To do this, we'll attempt to install a Ruby version, followed by a Ruby gem

Run brew install ruby-build to install the rbenv install command. This is the program which enables RBENV to install new versions of Ruby.

If it was successful, you should see something like the following:
==> Downloading https://ghcr.io/v2/homebrew/core/ruby-build/manifests/20240119
  ##################################################################################################################################################### 100.0%
  ==> Fetching ruby-build
  ==> Downloading https://ghcr.io/v2/homebrew/core/ruby-build/blobs/sha256:61f4463a727fd0e6434db47da818bc3184c0788cba906e1083743329aa288641
  ##################################################################################################################################################### 100.0%
  ==> Pouring ruby-build--20240119.all.bottle.tar.gz
  🍺  /opt/homebrew/Cellar/ruby-build/20240119: 599 files, 316.5KB
  ==> Running `brew cleanup ruby-build`...
  Disable this behaviour by setting HOMEBREW_NO_INSTALL_CLEANUP.
  Hide these hints with HOMEBREW_NO_ENV_HINTS (see `man brew`).
  Removing: /Users/richiethomas/Library/Caches/Homebrew/ruby-build--20231225... (65.2KB)

When that's done, run rbenv install 3.2.2 (or some other current version of Ruby). This may take a few minutes to complete. When that's done, run rbenv version 3.2.2 (or the version # you just installed) to ensure that this version is the one you're currently using.

You should see something like the following as output:

...
==> Downloading ruby-3.2.2.tar.gz...
-> curl -q -fL -o ruby-3.2.2.tar.gz https://cache.ruby-lang.org/pub/ruby/3.1/ruby-3.2.2.tar.gz
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                  Dload  Upload   Total   Spent    Left  Speed
100 19.1M  100 19.1M    0     0  8803k      0  0:00:02  0:00:02 --:--:-- 8811k
==> Installing ruby-3.2.2...
ruby-build: using readline from homebrew
ruby-build: using libyaml from homebrew
-> ./configure "--prefix=$HOME/.rbenv/versions/3.2.2" "--with-openssl-dir=$HOME/.rbenv/versions/3.2.2/openssl" --enable-shared --with-readline-dir=/opt/homebrew/opt/readline --with-libyaml-dir=/opt/homebrew/opt/libyaml --with-ext=openssl,psych,+
-> make -j 14
-> make install
==> Installed ruby-3.2.2 to /Users/richiethomas/.rbenv/versions/3.2.2

Next, run rbenv global 3.2.2 to tell RBENV to use your newly-installed Ruby version as the default global version (instead of using the version which came pre-installed on your machine):

$ rbenv global 3.2.2
$ rbenv global
3.2.2

Next, run gem install bundler to make sure that this version of Ruby has the Bundler gem installed.

Lastly, run which bundle to make sure that the directory that appears is ~/.rbenv/shims/bundle. You should see something like:

 $ which bundle
/Users/richiethomas/.rbenv/shims/bundle
$ 

If you see this, that means the bundle command corresponds to a shim in your RBENV directory, and you are good to go!

If, instead, you see something like...

 $ which bundle
/usr/bin/bundle
$ 

...this means your Bundler gem is still controlled by your system, not by RBENV. If that's the case, verify that the ~/.rbenv/shims folder comes before /usr/bin/ in your $PATH variable:

$ echo -e ${PATH//:/\\n}
/Users/richiethomas/.rbenv/bin
/Users/richiethomas/.rbenv/shims
/usr/local/lib/ruby/gems/2.6.0/bin
/opt/homebrew/bin
/opt/homebrew/sbin
/usr/local/bin
/System/Cryptexes/App/usr/bin
/usr/bin
/bin
/usr/sbin
/sbin
...

If it doesn't, you likely need to add the following to your ~/.bashrc file (if you're using Bash as your terminal):

eval "$(~/.rbenv/bin/rbenv init - bash)"
PATH="/Users/richiethomas/.rbenv/bin:$PATH"

Or if you're using Zsh (the default shell on MacOS), you'll add the following to your ~/.zshrc file:

eval "$(~/.rbenv/bin/rbenv init - zsh)"
PATH="/Users/richiethomas/.rbenv/bin:$PATH"

Then open a new terminal tab and re-run which bundle. If you still see /usr/bin/bundle, check the file permissions of both the ~/.rbenv/shims folder and the shims within this folder, by running:

$ ls -la ~/.rbenv
total 80
drwxr-xr-x  18 root  staff    576 Jan 20 10:50 .
drwxr-x---+ 41 root  staff   1312 Jan 20 11:42 ..
...
drwxr-xr-x  39 root  staff   1248 Jan 20 11:16 shims
...
$ ls -la ~/.rbenv/shims
total 296
drwxr-xr-x  39 root  staff  1248 Jan 20 11:16 .
drwxr-xr-x  18 root  staff   576 Jan 20 10:50 ..
-rwxr-xr-x   1 root  staff   409 Jan 20 11:03 bootsnap
-rwxr-xr-x   1 root  staff   409 Jan 20 11:03 bundle
-rwxr-xr-x   1 root  staff   409 Jan 20 11:03 bundler
...

You should see your UNIX username to the left of staff, not root (as above). If you do in fact see root next to staff, then it's possible your directory and file permissions are preventing the shim from being executable. In which case, verify that you cloned the RBENV repository via the git clone command, not sudo git clone.

After running this last step, I opened a new terminal tab and re-ran which bundle, and I finally saw my expected output: /Users/richiethomas/.rbenv/shims/bundle.

Summary

Now that we've installed RBENV and are pointing to the right version, you'll be able to replicate any experiments that we run on the RBENV code itself, such as adding log statements to the code so we can see what happens during RBENV's execution.