When building a software product on a team, to create an effective and sustainable development flow, one needs to abide by a version control branching model that is agreed upon all team members. If there is a chosen approach to branching, individual contributors on a team can contribute code without issue.
In this post, I want to focus on a specific technique within a specific branching model that I believe is quite effective at keeping each contributor productive without introducing cognitive overhead of a complex branching model.
The branching model being Trunk-Based Development and the technique that I’ll refer to is saving progress with Work-In-Progress (WIP) commits.
Trunk-Based Development model encourages merging to the ‘trunk’ (think of a tree trunk that all branches spring from) as often as possible and keeping branches short-lived: no more than a day or so if possible. We claim ‘master’ branch as the trunk.
Read more about the benefits of Trunk Based Development
To that effect, the WIP commit technique encourages small save commits that are temporary and will never make it to the trunk, i.e. ‘master’ branch. This technique helps us create checkpoints at some predetermined stopping points in your development flow. I think of cases when I have to leave for the day or go to a meeting at a not-so-clean point in my feature story.
Here’s how it goes.
Work-in-Progress (WIP) commits
I have cloned a Git repository to my machine being a new team member on any given team that is using Trunk-Based Development branching model. I’m using a fake git repository to drive out this example alongside a phantom product.
git clone https://github.com/ddubson/my-repo.git
Make sure you are on the ‘master’ branch (the trunk).
Let’s create a simulated example of some git history:
Check out a new feature branch off of local ‘master’ branch
git checkout -b display-item-details-1122337
The name format of the branch follows [short-description-of-story]-[story-id]
Now we can write some code for this feature story…
Once we have a stopping point that isn’t the end of the story, we can utilize WIP commit technique
The steps are:
- Add all changed files to Git staging
- WIP commits are temporary, we will come back and review all changes once the story is done. For now, add all the changes.
- Create a WIP commit with specific format (depicted below)
- Prefix the commit message with “WIP: "
- the commit message format should indicate what is currently being worked on in the branch or which test suites are failing
- Push to remote feature branch
git add .
git commit -m "WIP: working on rendering item SKU"
git push origin head
When we are ready to resume working on the story, we can continue contributing new code.
After some time, we might need to create more WIP commits like so:
On the left, we can see that the history of origin/master has advanced. This is to represent that other developers on the team have merged their code changes to remote master. We will reconcile these changes below.
Once we are done with the story (we know that we are done after all the test cases for the given feature pass), we can add the final WIP commit to track the final chunk of the story.
git add .
git commit -m "WIP: finished feature display items"
git push origin head
We can now create the formal feature story commit, here are the steps:
- Reset commits on the feature branch to where master branch is
- Add all new files that are untracked
- Pick through all the changes made in the story
- Create formal commit
# Story is done, and we can reset the WIP commits back to where the original branch veered off of 'master' branch
git reset master
# WIP commits have been erased locally
# Add all the new files added as part of this feature
git add -N .
# Pick through the changes of this feature
git add -p
# Create a formal feature commit
git commit -m"Add display item details feature [#1122337]"
Here’s what our git history looks like now:
Note that the git hash has changed, indicating that this is a completely different commit from any of the WIP commits.
We can now switch back to the master branch and merge the changes from the feature branch
git checkout master
git merge display-item-details-1122337
# Check git history
git log --graph --decorate --oneline
This should be a fast-forward merge so there will not be any merge conflicts.
But we do have to reconcile changes with origin/master.
Here’s how we can safely do this:
git pull origin master --rebase
Rebase flag is enabled, and so our feature commit will be placed on top of the commits that came earlier on origin/master
Rebasing concept is beyond the scope of this post, but you can find more here.
After a successful rebase, we can observe similar results as below:
Now all that’s left is to push to origin
git push origin master
That’s it.
There are many variations on how to approach reconciling a feature branch, master, and origin/master. I have depicted only one of them, but if there are others that work better for you, do not hesitate to do what is right for you or your team.
I have also specifically omitted formal commits on a feature branch that are tiny enough to merge to master without completing the entire story. This is on purpose so as to not complicate the flow in this happy path example. I encourage you to add tiny commits that further the story while chipping away at its overall complexity if possible.
Vocabulary
Branching - version control concept of duplicating source code so that modifications can be done in parallel alongside multiple branches.
Branching Model - a defined pattern of branching.
Trunk-Based Development - branching model centered around having the central trunk, i.e. ‘master’ branch as the main branch.
WIP Commit - convention for calling a temporary commit that is meant to be a temporary save point during the lifetime of a user story.
Feature Branch - convention for calling a git branch that is used specifically to work on one user feature story.