Git-Handy

Background

A few weekends ago, my colleague and I wrote a useful git plugin for fellow developers at our company. A few developers had not previously worked with Git, and were having trouble with the workflow. One of the most common issues was starting work from the master branch.

In some environments this would not be an issue, but our company uses a branching model, which does not support pushing directly to master. For those familiar with Git, moving changes over to a new branch is relatively simple. However, for those with little to no Git experience, this can seem complex and confusing.

Solution

Our solution to the issue was to create a small Git plugin that simply stashes what you have on your current branch, fetches from the latest branch and moves your dirty files to a new branch, all through a simple command:

git handy <new branch>

This also solved the issue of pairs not fetching the latest version of code, and starting their work from an outdated branch.

Code

The code for git-handy is very simple and can be found here. There is a small install script, cleverly named install.sh. The script simply detects your OS copies it to usr/bin or usr/local/bin (where most executables are stored) and makes git-handy an executable. The script can be ran using:

sh install.sh

git-handy is now ready to use. Lets walk through the code. The script is broken down into simple, small functions. version() and usage() are very simple and do exactly what their respective names imply: return the version and usage. gitSync() has a little more going on, but is still relatively simple.

    git stash;
    DEFAULT_BRANCH=$(findDefaultBranch);
    git checkout $DEFAULT_BRANCH;
    git fetch;
    git merge;
    git checkout -b $1;
    git stash pop;

The only line really worth explaining in this function is:

git checkout -b $1

This line is simply checking out to a new branch, using $1 as the branch name. $0, $1, $2...$N is the way bash references the arguments given to the script on the command line. $0 is the script itself, so $1 simply references whatever branch name we type after git handy. For example, if we type the command git handy new_branch, then $1 is new_branch.

You’ll also notice that $DEFAULT_BRANCH calls findDefaultBranch, which is explained below.

The most challenging part of this simple plugin, was finding the latest branch and then formatting it properly to be used in other git commands(findDefaultBranch).

After a few minutes of tinkering and experimenting with esoteric shell commands we finally came up with a solution.

git for-each-ref --sort=-committerdate
--format='%(upstream:short)' | head | grep -o '\w*$'

This command simple sorts each ref based on its last commit date and formats the refs to be short (remote/branchname), which is then cut down by the head command and formatted once again by grep. We then can use it as the $DEFAULT_BRANCH throughout our script.

This solution is less than ideal, but it has worked well so far. Git-handy is still fairly new and untested which means that the above could possibly be incorrect. However, git-handy has faired well in the wild thus far.

Wrapup

Before writing the plugin, I had done very little shell scripting. There may be better ways implement git-handy, but so far it has been a tremendous help. If you see any obvious improvements or have any valuable feedback, my email can be found in the about section of this blog.