Git stash driven development
Iāve found myself using a pattern quite often recently, which Iāve been callingĀ āgit stash driven developmentā ā that is, relying heavily on the magic of git stash as part of my development workflow.
Normally I follow what I think of as a fairly typical TDD workflow:
- Write next test, watch it fail
- Write code to make it pass
- Commit
- Refactor
- Commit
- Push
This cycleĀ can repeat very frequently ā as often as every couple of minutes. Sometimes this cycle gets slowed down when the next test to write isnāt obvious or the refactoring needs more thought. But generally this is the process I try and follow.
Quite oftenĀ having written the next test which takes me forwards on my feature I hit a problem: I canāt actually make the test pass (easily). First I need to refactor to make the problem easy. In that situation I can mark the test as ignored, commit and come back to it later. I refactor as required, commit, push; then finally unignore my test and get back to where I was before. This is a fairly neat process.
However there are a couple of times when this process doesnāt work: what if Iām part way through writing my test and I realise I canāt finish without refactoring the test infrastructure? I canāt ignore my test, it probably isnāt even compiling. I certainly donāt want to commit it in its current state. I could just bin my test and re-write it, if Iām following the 15 minute rule Iām not going to lose much work. But, with the magic of git stash, I can stash my changes and come back once Iāve refactored the test code.
The more annoying time this happensĀ is when Iām part way through a refactor step. This happens more commonly when Iām really going through a design-change ā this isnāt really refactoring as it often happens outside of the normal TDD loop. Iām trying to evolve the design to somewhere different; sometimes this is driven by tests, sometimes its a non-feature changing refactor. But often there are non-trivial changes happening across numerous source files. At this point it is very easy to get part way through a refactor and realise that something else needed to have happened first. I could bin my change, I only stand to lose 15 minutes work ā but why throw it away when I have git stash?
So I git stash my changes, go and make the change I needed to have happened first. Then, all too commonly, I get part way through thisĀ second changeĀ and realise something else needs to happen first. Well, git stash again! This stack of git stashes can get quite deep, if youāre not careful. But once Iāve bottomed the stack out, once Iāve managed to commit a refactor that frees up the step above I can git stash pop, complete the nextĀ refactor, commit, git stash pop; and so on up the stack until Iām done.
Now, arguably, Iām discovering the refactor in reverse order, but this seems to me often how I find it. I could have spent more time analysing the change in detail, of course. Spent time planning out my change on paper before embarking on it in the correct order. However, this is always time consuming and thereās still the risk that I miss something and come at a change ābackwardsā. I find that using git stash in this way lets me discover the refactor that I need to make one step at a time. Each commit is kept small, I try and stick to the 15 minute rule so that no single commit loses more than 15 minutes. Ultimately the design change is completed in a sequence of small commits, each of which builds logically on the one before. Theyāve been discovered by exploration, the commits were just discovered in reverse order.
The danger is always that I find a refactor step I canāt complete the way Iād imagined ā now I canāt unwind the stack and potentially all the previous git stashes arenāt committable. Whenever this happens I normally find going one or two levels up the stack will present a different approach, from where I can continue as before.
| Reference: | Git stash driven development from our JCG partner David Green at the Actively Lazy blog. |


