Monday, June 23, 2014

Git: Keeping a clean master branch

Since moving to Git, I'm loving the power. I feel safe. Once changes are committed, no matter what I do, I won't lose anything. And within reason I can later edit history to tell the story I want it to tell.

In our team, we use the commit messages from our master branch to automatically generate release notes. To achieve this the master commit history need to stay pretty clean. Ideally one commit per feature.

We therefore have been working on feature branches and squash merging them to master once they pass code review.

We use Atlassian Stash for code reviews. When a code review is accepted it does a merge to your destination branch. Stash doesn't do a squash merge, or use our commit comment, so we can't have it automatically commit to master. If we don't accept the review though, all we can do is leaves the code review open or marks it as abandoned.

To avoid this we make a review branch from master and review the feature onto that. Stash can then merge it once the review passes... so it's happy... then the developer manually squash merges the review branch to master, so we are happy.

This was working fine, until we needed a feature to branch from another feature mid development.

The downside of squash merges, is that the master doesn't know the changes came from a branch. This means :-

  • If you branch from feature A, 
  • then feature A makes more changes to the already changed files 
  • and feature A commits to master first 
  • when you merge to master, it looks like the changes you inherited are conflicting with the committed files. 

This is a real pain.

To get around this... we have started to use a common "integration" branch. (instead of the review branches)

  • A developer branches from integration, 
  • does changes... 
  • then reviews back to integration. 
  • Once accepted and merged, the developer then squash merges integration to master, 
  • and then merges master back into integration. 

This final merge is easy as the code is the same, and tells Git that these branches align at this point. This means that later "squash merges" onto master keep working without merge conflicts. Also any branches committed to "integration" retain all history, so they merge nicely too.

This looks like this:


Happy Coding.

GitHub Projects