How I use git

I use git pretty much every day, it's one of my most used tools in my toolchain alongside my editor and terminal. Over the years I've slowly pulled together a few aliases and settled into a sort of workflow with git that I use for most projects.

My workflow could probably best be characterised with two "goals". These aren't really something I set out to solve, but they are the things I've come to value most about my workflow.

  1. I should be able to get back to any changes I've made, sod's law says the moment I decide to abandon something I'm going to want part of it just moments later so I need to be able to get back to changes I made, even if I've thrown them away.
  2. I don't want my workflow to conflict with other project / company workflows, but I also don't want to have to have to continually switch workflows every time I context switch.

Writing code

I'm quite scrappy with my local repositories, I make lots of commits with incredibly poor commit messages and I then reformat it all at the last minute before publishing for other people to look at. As a developer, I'm the equivilent to a cook who makes a huge mess and cleans up everything at the end the process. This is quite strange as I'm the total opposite when cooking.

When starting a new block of work I'll create a branch. It doesn't matter what I'm doing, it could be a bug fix, a refactor, or a new feature, it all gets a branch. Usually the branch name is pretty long and horrible, the goal of the branch is just to contain my mess and be identifiable to me a few weeks later. These branches can stick around for anything from 10 minutes, to three months but usually no longer than that. I try to get rid of branches when I've well and truely finish with them and if a branch gets too far behind the master I often see it as a good sign that the thing I did wasn't important or wasn't successful.

I'm sure there are some smarter people out there that can write beautiful git commits while making complex changes, but I'm not one of them. When working, I'll make commits very sporadically. The moment I think I've done something I want to capture I'll make a commit. Usually this happens when I've finished a small sub-task of the work or when I'm about to change direction and refactor or scrap a portion of what I've done. In these situations I'll make a commit with one or two bits of information to help me identify it later but I know the commits likely won't be alive for more than a few days or weeks.

If I want to get of something I've just done, I won't use git reset --hard or anything similar because it means that work is totally unrecoverable. Instead I'll either git revert the commit, or if I've yet to make a commit I'll use a command I stole from Phil Haack: git wipe. This is an alias which creates a commit with a default message of "WIPE SAVEPOINT" and then resets the head to one before the new commit. With this, the changes are saved in the git reflog until git cleans it up with a garbage collection which usually isn't for a few days at the earliest.

Once I've got some code that I'm reasonably okay with and I'm ready to publish it to somewhere more public I'll start the clean up. Usually this consists of creating a new branch and I'll then start re-writing my commits in a way which makes sense and matches any project/company standards. In most situations this means making sure each commit is a single atomic[1] change and passes the full test suite. I'll then publish the changes either by generating a .patch file and emailing it, or pushing the branch to GitHub/GitLab and opening pull request.

I'll usually leave my scrappy branch around until I'm happy I won't need that foresenic level of information again, such as when it's been merged. If it's a risky change for whatever reason then I may even keep it around for a few weeks after that until the team is happy it's stable.

Reviewing code

Reviewing code is a very simple flow, no matter the medium I'll pull the code down locally. I've got a nice alias setup for this, git fetchpr {origin} {pr-id}, this only works for GitHub since that's what I tend to use most. The alias is defined in my git config as: fetchpr = "!f() { git fetch ${1} pull/${2}/head:pr-${2}; }; f". This is a pretty simple command but I struggle to remember the syntax of the branch path GitHub requires for this so now I don't have to.

If I'm working with .patch files I'll just use git apply since it's easier to remember than the GitHub approach.

I'm a big fan of "collaboration" rather than "reviews" where possible. If I want to make or try out tweaks I'll often do it myself and either merge with the tweaks or send them back to the original author to look at. I find this easier and more helpful than trying to explain my thoughts on the smaller things. I'll also be quite liberal with this if it's one of my open source projects as it helps get changes in quicker. I also find people are generally happier and more responsive if they don't have to make changes due to me being pedantic about the small things.

In a business environment I've found it's less accepted to make tweaks and merge them, people often prefer to double check the changes I've made to their work before everyone gives it the greenlight so I'll usually send them back to the original author in this case.

If the changes are more substantial then I'll do my best to write up detailed feedback referencing specific lines (GitHub and emailed patches make this really easy). Sometimes I actually get this line wrong and I'll end up making pretty large changes to a patch or pull request before I realise I'm not best suited to do the changes, but I'm getting better at seeing this line up front.

Summary

That's all there is to it really, I try to keep my approach pretty simple. It allows me to spend less of my (very limited) brain capacity on version control and focus more on the changes I'm making. It also means I don't have to totally overhaul my working patterns every time I want to contribute to a new project or move to a new job. This way I can simply work as I always have and then spend a little bit of time making it work for other people afterwards.

I guess you could say my approach to git brings it down to my own level of intelligence; simple most of the time, with a few concentrated moments of trying to look smart.


[1] - An "atomic change" means one thing and only one thing is changed. It must be meaningful, such as completing a single task, and it should make sense on it's own.