Interactive Git Checkout — Creating a simple git branch switcher in Node

Pete Cook
Pete Cook
Apr 18 · 3 min read

Tired of constantly using git checkout to switch between branches? Let’s write a simple branch switcher in Node.

Here’s one I made earlier

Previously I’ve used git branch --sort=-committerdate aliased to gbs as a reminder of the branches I’ve been working on recently. The first thing to do is use Node’s child_process to run this command for us.

const { promisify } = require('util')
const exec = promisify(require('child_process').exec)
async function run () {
const branches = await exec('git branch -v --sort=-committerdate')
}
run()

We’re using Node’s promisify utility to create a version of exec that we can use with async/await. If you are unfamiliar with async/await I encourage you to get familiar with it, because it’s awesome.

branches will be an object containing stdout and stderr strings that give us the result of running the command in a child process. stdout will be a string we can split by newlines to get our branches.

const choices = branches.stdout
.split(/\n/)
.filter(branch => branch.trim())
.map(branch => {
const pattern = /([* ]) +([^ ]+) +(.+)/
const [, flag, value, hint] = branch.match(pattern)
return { value, hint, disabled: flag === '*' }
})

Here we parse the raw output of the git branch command into an array we can pass into the prompts library later on. The filter function uses trim() to remove any empty lines. The map function uses a regular expression to parse the branch information. We disable any branches with a * flag, as this is the currently checked out branch.

Notice how we added -v to the git branch command? This gives us information about the current commit of each branch, and how far ahead it is from the remote version. We can use this information in the next step.

const prompts = require('prompts')const { branch } = await prompts({
type: 'select',
name: 'branch',
message: 'Switch branch',
choices,
hint: choices[0].hint,
warn: 'current branch',
onState ({ value }) {
this.hint = choices.find(c => c.value === value).hint
}
})

We’re using prompts to output a very simple command line select list to let users select a branch. Note the use of onState to set the hint using the extra branch information we gathered before. The result of prompts is an object of user input values according to its name. We’re using object destructuring to grab branch straight from the resulting object. The last step is to simply run git checkout using the selected branch.

await exec(`git checkout ${branch}`)

This will work, but unfortunately gives us no feedback from the git command about if the checkout was successful or not. A bit of extra work is required.

async function checkout (branch) {
const { stdout, stderr } = await exec(`git checkout ${branch}`)
process.stdout.write(stdout)
process.stderr.write(stderr)
}

Here we essentially pipe the output of git checkout through to the terminal. The command outputs useful information in both stdout and stderr, even after a successful checkout, so we use both.


I’ve put a more complete version of the script on GitHub, and published an npm module which you can use right now:

npm install --global git-checkout-interactive

Then, switching branches becomes as simple as:

gci

OneHub | Product Engineering

Creating the technology that powers the OneHub product line

Pete Cook

Written by

Pete Cook

OneHub | Product Engineering

Creating the technology that powers the OneHub product line

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade