Nathan Kallman
Kallmanation

Kallmanation

The Git Interpolator!

The Git Interpolator!

Subscribe to my newsletter and never miss my upcoming articles

If you're anything like me, when you use command line git, you find yourself looking at something like this more than you'd care to admit:

$ gi tpull
bash: command not found: gi

D'oh!

How many times do I type git in a day? For three simple letters, you might think it would be easier to type.

You would be wrong.

You might also be thinking that this isn't really a problem; to which I say, "Wrong again". If I take 3 seconds to fix this, and make this mistake 10 times a day, Mr. Munroe tells me I can spend a whopping 12 hours fixing this and still break even!

Just give me teh codez

Okay: github/kallmanation/gi

How does it work?

1. aliases

These can be more or less depending on your specific shell, but for our purposes an alias can be thought of as just another name for a command. Just like many Williams go by Bill; when I say "Bill", everyone knows I'm actually talking about William. alias is a way the command line does the same thing; when I say "nickname" for a command, it knows I actually mean "fullname" of the command. The syntax is simple:

alias nickname=fullname

Let's set up a couple aliases for some common misspellings of git:

alias it="git"
alias gti="git"

Now if I accidentally type it or gti, my command line knows I actually meant git. Great!

But that won't solve my first example of gi tpull. For that, we'll need something a little more advanced:

2. shell functions

For now, just think of a shell function like any other command. (In reality, they are slightly more different, but we don't need to get into that today.)

Every command that a shell runs is given a list of parameters based on the space separated values typed into the command line. In most shell scripting languages, those parameters are mapped to variables: $0, $1, $2, etc. where $0 refers to the actual string used to execute the command, with the rest being other parameters. Also all the variables $1, $2, etc. are all mapped into the single variable $@. Let's do an example, at the command prompt you enter:

git commit -m 'The best commit message evar'

If git were a shell script, the parameter variables would look like this:

$0 = git
$1 = commit
$2 = -m
$3 = 'The best commit message evar'
$@ = commit -m 'The best commit message evar'

So now the wheels might be spinning. We need to take something that looks like this:

$0 = gi
$1 = tcommit
$2 = -m
$3 = 'The best commit message evar'

And turn it into the previous example.

We'll use two commands: sed and shift

sed is a stream editor, meaning you pump text into it with instructions on how to edit it and it pumps the edited text back out. We'll use echo to pump the first parameter into into sed and give sed a regular expression to edit with (don't worry, this one will be simple, I promise)

echo "$1" | sed 's/^t//'

sed takes a parameter of the form s/regular-expression-to-search-with/text-to-replace-matches-with/. Above we give it the regular expression ^t: ^ means "the beginning of the string" and t just means "t"; so effectively we've instructed sed to find a t only at the beginning of the line and replace it with nothing (aka remove it).

So what about shift? That simply moves all those indexed parameters forward one, $2 becomes $1, $3 becomes $2, etc. and $1 is just removed which gets rid of that pesky tcommit from $@ in our example.

Now to put it together, we will do things in three steps:

  1. Correct the first parameter to remove the leading t and stash the result for use later.
  2. Remove the incorrect first parameter from the list of parameters.
  3. Call git with the corrected first parameter from 1 and the remaining parameters ($@)

And don't forget our function needs to be called gi for the command line to know to call our interpolator to come save the day from typos, which looks like this:

gi() {
  first_param_without_leading_t=$(echo "$1" | sed 's/^t//')
  shift
  git "$first_param_without_leading_t" "$@"
}

And this will do it! If we accidentally type gi tcommit -m 'The best commit message evar' our function will be called and instead call git commit -m 'The best commit message evar'.

(I'll leave it to the reader to build the very similar gt for even worse typos like gt irebase -i; or you can cheat and look at the code)

And that's great! We now auto-fixup all sorts of typos! But, there's one more class of mistakes you could make. What if you put the space too late instead of too early? Like gitp ull or gitp ush? Well:

3. eval

It's easy to see how to fix the example I gave using what we now know about shell functions. Just make a gitp function:

gitp() {
  git "p$@"
}

That's even easier than all the nonsense we had to do to get gi working! But, it doesn't help at all if I type gitr ebase and what about gitc ommit? Should we just whip up 26 functions like gitp for each letter of the alphabet?

No!

We're programmers! We can program the program!

Our command line has this nice little command, eval. It takes parameters, pretends it's a command and executes it. Is it dangerous? Yes. Is it basically evil spelled differently? Yes. Should we use it? Watch me.

Let's start with a loop over the letters a to z, with that we'll eval an expression to create a function for each letter exactly like the function we wrote above: gitx() { git "x$@"; }. Throwing in the proper escaping to make sure it gets evaluated correctly:

for x in {a..z}; do
  eval "git$x() { git \"$x\$@\"; }"
end

And that's it! Three easy steps to making a neat little git interpolator.

Let me know what you think!

 
Share this
Proudly part of