Git Polishing 💎
git configuration often ends up being something we hone over the course of our development careers, slowly evolving into a perfectly tuned set of non-standard commands (this is much the same as how I feel about my Emacs and Vim configs).
As I read this tweet the other day I realized that we could all benefit from sharing our own workflows:
The ux of `git branch` is pretty rough. Gotta read SO to do simple things like prune local branches that have been merged or sort by recency— Martin Muñoz (@_mmun) April 28, 2017
I'd like to share a few of the
git commands I use every day for "getting the job done".
Before we start digging into specific tips/tricks I think it would be useful to share the general idea of creating custom
git commands. This is effectively like making shell aliases, but they work with the
To define a custom alias, you would run:
git config --global alias.co checkout
After running that command, in any
git repo you can run
git co instead of
git checkout. 🎉
I most often take advantage of custom
git aliases globally (using
git config --global or manually editing my global
~/.gitconfig file), but you can also add them to your projects own configuration (
git config without
--global or via editing
./.git/config) if they are not generally useful outside of a given project.
Quite often I want to see a listing of branches in my current repo. Many of you might be thinking:
WAT, this is trivial 😏:
You're right that is trivial, and I used this for quite a while but I slowly started to get annoyed. What I really wanted was to see a list of the branches in most recently used order (this is likely due to my forgetfulness about what I named a given branch 😜).
So for this, I use a custom command:
git config --global alias.list-branches "branch --sort=committerdate"
This one is fairly obvious (it used to be a bit harder before newer features added in Git 2.7), but its still pretty nice to have a quick auto-complete for it.
git list-branches at least 10 times a day now...
Delete Merged Branches
I think almost everyone has a variation of this (or does it manually 😫). Deleting merged branches (and pruning the remote) is a very common task (otherwise the
git list-branches alias we added above is not terribly useful).
git config --global alias.delete-merged-branches "!git branch --merged master | grep -v -e 'master' -e '\\*' | xargs -n 1 git branch -d && git remote prune origin"
😨⁉️ OK, hold on. Lets break it down a bit.
- Aliases that start with a
!are independent commands to be executed. If you look back to the
list-branchesalias, you will see that we do not have a leading
!because this command is for the
gititself (without need for
git branch --merged masteris fairly straight forward, it just lists the branches that are merged with master.
- Then we pipe that into
grep -v -e 'master' -e '\\*'which filters the list to exclude the
masterbranch and the current branch (signified by a
git branch --merged masteroutput).
- At this point we have our list of branches to delete, so we pipe that into
xargs -n 1 git branch -d. This takes each branch returned from
git branch --merged master | grep -v -e "master" -e "\\*"and invokes
git branch -d <BRANCH NAME HERE>for it.
- Now that we have cleared local branches that have been deleted, we prune our remote branches via
git remote prune origin.
git delete-merged-branches is probably one of my most used commands (right behind
git push, and
git pull). It looks complicated (and kinda is), but it's just so useful.
Checkout Pull Request
While reviewing a pull request I often want to pull it down locally and test things out. For that I use the following alias:
git config --global alias.setup-fetching-prs "!git config --add remote.origin.fetch '+refs/pull/*/head:refs/remotes/origin/pr/*' && git fetch origin"
This one isn't nearly so difficult as the last one, lets break it down:
- Github repos include the refs of all pull requests, we just need to instruct our local project to also fetch them via
git config --ad remote.origin.fetch '+refs/pull/*/head:refs/remotes/origin/pr/*'.
- Then we kick off the fetch of the remote to get the new refs.
After you run this, you can run
git checkout pr/1234 to checkout a given pull request.
There is a great alternative to this command (though it still uses the same basics) over on the Ghost Dev Blog which just runs the above for specific pull requests (and therefore avoiding fetching a remote for each PR). Both are great workflows, the "best" really just depends on how often you will need to checkout pull-requets for a given project.
These are the
git customizations I use on a regular basis. What are you using?