Next Level Git
It’s no secret to anyone I’ve ever worked with that I essentially run my working life with an ever-growing, ever-changing set of shell scripts.
It is, however, somewhat of a secret that all of these are hosted on GitHub.
Some of them, I use every week or so, like
up, which updates basically everything on my machine using Homebrew,
apt-get, RVM, NPM… you name it. Some, I’ve completely forgotten about, like
whitespace, which I’m pretty sure converts tabs to spaces… I don’t even remember why I wrote it. Today, though, I’d like to talk about a set of scripts I use to save time and hassle when working on a project in a team with either manual or automated code reviews.
First of all, let me describe the potential workflows.
cdto the project directory.
- Pull down the latest changes from
masteror whatever your main branch is. If you’re on a fork, pull changes from upstream and push to your personal repository.
- Check out a new branch named after your new feature/bug fix/work of art/whatever.
- Make some changes, verify they work by running your tests (you do have tests, right?) and commit them.
- Repeat step 4 until the feature is done.
- Push the branch to the repository.
- Go to GitHub/BitBucket/GitLab/whatever and open a pull request.
- Post a link to that pull request in your IRC/Slack/Jabber channel.
- Wait for someone, either a human or a computer (or maybe both), to review it.
- If everything is successful, merge the pull request.
Whew. That’s a lot of work. Note that steps 4 and 5 are the only part where you’re contributing to the project. Everything else is waste. But wait, there’s more. If it’s not successful, you need to change things and push more commits. In the mean time, something else has probably been merged and yours is no longer mergeable, so:
- Check out the master branch.
- Pull the latest changes.
- Switch back to your development branch.
- Merge the master branch in.
- Fix the conflicts.
What a waste of life.
The thing is, apart from the bits where you’re coding, it’s all repetitive, boring work. And the beautiful thing about repetitive, boring work on a computer is you can script the hell out of it.
So I did. Here’s how I roll.
j projectto jump to the project directory using autojump.
git up. This script:
- checks out the master branch if we’re not already there,
- pulls the latest changes from either the upstream fork or the master branch,
- pushes the upstream changes to my local repository if I’m working on a fork,
- and switches back to the original branch.
- Start working.
- When I realise I forgot to switch branch and I’ve committed twice already, type
git switch-to my-featureto change to a new branch, keep all my current commits and remove them from the master branch.
- When I’m done, type
git prto push the branch and open up a web page with a button to create pull request. I was tempted to automate submitting the pull request, but I find that reading the diff beforehand often helps me find any issues.
- Let Slack find the pull request and automatically post it. If I have to use something that’s not Slack again I’m definitely making Hubot do it.
And of course, when I get clobbered by someone else’s merge, I just type
git upm, which runs
git up and then merges the changes into my current branch. Then I fix the conflicts and push again. The pull request is automatically updated.
All these commands have been in my Git configuration since 2014 or so, and they’ve become more and more sophisticated and stable as time has progressed. But I don’t advise you use them. They’re set up to work just the way I want them, and you deserve something just as fitting for you. Think about the commands you find hard to type or that require multiple steps, and go from there. Start by creating simple git aliases using the command
git config --global alias.my-alias-name command. For example, this lets you type
git a to stage everything, including deleted files:
git config --global alias.a 'add --all'
You can also run scripts from aliases. I use
git p to pull down changes with the
--ff-only flag to ensure that I don’t get an unexpected merge and then update all submodules:
git config --global alias.p '! git pull --ff-only --prune && git submodule update --init --recursive'
And there are plenty more examples in my own .gitconfig.
Git is a tool I use hundreds of times a day. You might have a different one. Whatever you’re spending your time doing, if it feels like waste, script it. And tell me about it! Either in the comments below, or on Twitter.
If you enjoyed this post, you can subscribe to this blog using RSS. I personally use Feedly; you can subscribe here.
Maybe you have something to say. You can comment below, email me, or toot at me. I love feedback. I also love gigantic compliments, so please send those too.