I was at an Appsterdam lunch meetup today, and before the presentation I was talking with some people about source control. They worked for Atlassian, and so of course bitbucket v. github came up. (It didn’t help that I was wearing a GitHub shirt. Atlassian - I want to give you money to get a bitbucket shirt but I don’t see any for sale. Why?) Regardless of why I typically use github more, or what my usage profiles are for the two, they were interested to hear my solution to a problem I had: how to simplify working in various source control systems, particularly in both mercurial and git.
For a long time, I used mostly git and far less mercurial. I wrote a bunch
of aliases in my .zprofile that looked something like:
1 2 3 | |
For mercurial, I just entered everything normally. However, as I started to
use mercurial more, I wanted to use those aliases for both systems. I ended
up writing a bunch of shell functions to do this. They are all strict POSIX
compatible, so they work under at least zsh, ksh, and bash. I haven’t
tested any others, so your mileage may vary. The latest version of this is
available at my dotconf github repo, you
can view it here
The core of the code is the pair of functions:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | |
get_repo_type does exactly what it says it does: it outputs a number that
identifies what type of source control the repo uses. The not-a_repo
simple provides a shortcut for displaying the error message. All of the
commands use these two functions. The commands are implemented in a similar
style, so let’s take a look at the first defined function, pull:
1 2 3 4 5 6 7 8 9 10 | |
Unfortunately, shell scripting isn’t a terribly advanced programming language, so there’s a lot of redundancy in the code; in fact all of the commands use the same basic template of
1 2 3 4 5 6 7 8 | |
I thought of some other ways to do this, but they all ended up being far more complex and time-consuming than just knocking it out like this. This style is also POSIX-compatible, meaning it can be used with really any shell.
Another feature of note is that I’ve ensured to pass through the shell variable
$@, which means any arguments are passed directly to the command; this lets
you still enable the full use of the specialised commands without having to
mentally switch context between just typing the shortened command and the full
one.
So, let’s look at what commands are supported (use vcshelp to list them):
- commit
- add
- pull
- push
- checkout
- fetch
- clog
- which_dvcs
- vcdiff
For the most part, they are wrappers around the $scm version of the command, passing through any arguments as before. The last three aren’t (but do pass through any command line options as appropriate):
clogis a shortcut for ‘commit log’, and shows the $scm log. For mercurial, it will pipe it to less (by default, hg doesn’t).which_dvcsis a wrapper around get_repo_type to print the name of the SCM instead of the numeric value used in the functions.vcdiffis a version control diff; likeclog, it will pipe hg diff to less.
There are a few commands that aren’t documented in vcshelp:
* co is an alias for checkout
* st is a variant of status that shows only tracked files
I’ve found this system to work out pretty well for me, mostly because it
requires less mental power to handle the basic SCM workflow. It also satisfies
my coder’s itch to remove unnecessary code (i.e. always having to prefix git
or hg to source control commands) by making the shell “aware” of which SCM
I’m using at the time.
There is, of course the caveat that Josh Rickmar
pointed out. I’ve come to grow used to a lot of the specifics of working
with the different SCMs. Two common idioms I use a lot with this setup are
commit -a in a git repo and pull -u in a mercurial repo. If you are using
an SCM, you should definitely get to know it before using it for serious
work. Of course, you can also take my code and tweak it so that it behaves
differently. The code is yours.
Thanks go to Chris LePetit, who suggested I write the article. Samuel Goodwin and Wally Jones proofread it for me.