Better Development Environment: Git Branch in bashrc and Virtualenvwrapper
This week is UC Berkeley’s Spring Break. Obviously I’m not on vacation, because I actually need Spring Break to catch up on research due to how much time my GSI is consuming; it is taking 25-ish hours a week if I’m tracking my work hours correctly. (I’m not sure if students realize this, but teaching assistants, and probably professors, look forward to the Spring Break just as much as they do.) But I figured that since since the week would give me leeway to step off the gas pedal just a tad bit, I should use the time to tinker and improve my development environment. Broadly speaking, this means improving how I code, since my normal daily activity involves lots and lots of programming. Therefore, a proper investment in a development environment should pay for itself.
Almost two years ago, I wrote a blog post stating how I organized my GitHub
repositories. That’s technically part of my development environment, but
perhaps more important than GitHub repository organization is how I design my
.bashrc
files (or .bash_profile
if I use my Mac OS X laptop) and how I
organize my Python virtual environments. Those two are the subject of this blog
post.
After reading my fellow lab-mate Roshan Rao’s development environment on
GitHub, I realized that I was missing out on a key feature: having the git
branch explicitly listed in the command line, like this where the text
(master)
is located after the name of this repository:
danielseita@dhcp-46-186:~/DanielTakeshi.github.io (master) $ ls
Gemfile _config.yml _posts about.md css new-start-here.md
Gemfile.lock _includes _sass archive.md feed.xml subscribe.md
README.md _layouts _site assets index.html
danielseita@dhcp-46-186:~/DanielTakeshi.github.io (master) $
Having the branch listed this way is helpful because otherwise it is easy to
forget which one I’m on when coding across multiple projects and multiple
machines, and I’d rather not have to keep typing git status
to reveal the
branch name. Branches are useful for a variety of reasons. In particular, I use
them for testing new features and fixing bugs, while keeping my master branch
stable for running experiments. Though, even that’s not technically true: I’ll
often make “archived” branches solely for the purpose of reproducing
experiments. Finally, the value of branches for a project arguably increases
when there are multiple collaborators, since each can work on their own feature
and then make a pull request from their branch.
All that’s needed for the above change are a couple of lines in the .bashrc
file, which I copied from Roshan earlier. No extra “plugins” or fancy
installations are needed. Incidentally, I am putting my development
environment online, and you can see the relevant changes in .bashrc
. I
used to have a vimrc repository, but I am deprecating that in favor of
putting my vimrc details in the development environment. Note that I won’t be
discussing vimrc in this post.
There was one annoying issue after implementing the above fix. I noticed that
calling an alias which activates a virtualenv caused the git branch detail to
disappear, and additionally reverted some of the .bashrc
color changes. To be
clear on the “alias” part, as of yesterday (heh!) I organized my Python virutual
environments (“virualenvs”) by saving them all in a directory like this:
danielseita@dhcp-46-186:~ $ ls -lh seita-venvs/
drwxr-xr-x 7 danielseita staff 224B Feb 4 21:18 py2-cs182
drwxr-xr-x 7 danielseita staff 224B Mar 8 18:09 py2-cython-tests
drwxr-xr-x 8 danielseita staff 256B Mar 12 21:45 py3-hw3-cs182
drwxr-xr-x 7 danielseita staff 224B Mar 8 13:36 py3.6-mujoco
danielseita@dhcp-46-186:~ $
and then putting this in my .bashrc
file:
alias env182='source ~/seita-venvs/py2-cs182/bin/activate'
alias cython='source ~/seita-venvs/py2-cython-tests/bin/activate'
alias hw3_182='source ~/seita-venvs/py3-hw3-cs182/bin/activate'
alias mujoco='source ~/seita-venvs/py3.6-mujoco/bin/activate'
So that, for example, if I wanted to go to my environment which I use to test
Python MuJoCo bindings, I just type in mujoco
on the command line. Otherwise,
it’s really annoying to have to type in source <env_path>/bin/activate
each
time!
But of course people must have settled on a solution to avoiding that. During
the process of trying to fix the puzzling issue above of aliases “resetting”
some of my .bashrc
changes, I came across virtualenvwrapper, a package
to manage multiple virtualenvs. I’m embarrassed that I didn’t know about it
before today!
Now, instead of doing the silly thing with all the aliases, I installed
virtualenvwrapper, adjusted my ~/.bashrc
accordingly, and made a new directory
~/Envs
in my home level directory which now stores all my environents. Then, I
create virtualenvs which are automatically inserted in ~/Envs/
. For example,
the Python2 virtualenv that I use for testing CS 182 homework could be created
like this:
mkvirtualenv py2-cs182
I often put in py2
and similar stuff to prefix the virtualenv to make it easy
to remember what Python versions I’m using. Nowadays, I normally need Python3
environments, because Python2 is finally going to be deprecated as of January
1, 2020. Let’s dump Python 2, everyone!!
For Python 3 virtualenvs, the following command works for both Mac OS X and Ubuntu systems:
mkvirtualenv --python=`which python3` py3.6-mujoco
To switch my virtualenv, all I need to do is type workon <ENV>
, and this
will tab-complete as needed. And fortunately, it seems like this will preserve
the colors and git branch changes from my .bashrc
file changes.
One weakness of the virtualenvwrapper
solution is that it does require a
global pip installation for installing it in the first place, via:
pip install --user virtualenvwrapper
So that you can even start using it. I’m not sure how else to do this without
having someone install pip with sudo access. But that should be the only
requirement. The --user
option means virtualenvwrapper is only applied locally
to you, but it also means you have to change your .bashrc
to source the local
directory, not the global one. It works, but I wish there was an easy option
that didn’t require a global pip installation.
As a second aside, I also have a new .bash_aliases
file that I use for
aliases, mostly for ssh-ing into machines without having to type the full ID,
but I’ll be keeping that private for obvious reasons. Previously, I would put
them in my .bashrc
, but for organizational purposes, it now makes sense to put
them in a separate file.
Whew. I don’t know how I managed to work without these changes above. I use multiple machines for research, so I’ll be converting all of my user accounts and file organization to follow the above.
Of course, in about six more months, I will probably be wondering how I managed to work without features XYZ … there’s just so much to learn, yet time is just so limited.