When a Clean Merge is Wrong

Git conflicts tell us when changes don’t go together. While working with other developers, or even when working more than one branch by yourself, changes to the same code can happen. Trying to merge them together will stop Git in its tracks.

Conflicting changes are marked in their files with clear indicators to show what changes Git couldn’t figure out how to merge on its own. Current changes are shown on the top and the changes to merge in are shown below.

Changes in a Git merge.

When the merge does not have any conflicts, everything is fine and you can move on with your day.

...Right?

This was just an example, but here’s another set of changes from two branches I made recently. In one branch I was sorting a sequence of templates:

A code block sorting a sequence of templates.

In another branch I was adding an “Introduction” page at the beginning of the same list of templates:

A code block showing the addition of an introduction page to a list of templates.

Both of these branches were merged to the mainline branch. I expected them to have caused a conflict, but they didn’t. Git decided it could figure out the order in which I wanted these two lines added to the same place.

A code block showing the effect of the combined merge.

It might be clear from this GitHub diff what’s wrong with the way Git merged the two changes together. First, I’m inserting that new page to the beginning of the list. But second, I’m sorting that same list so the new page is no longer at the beginning.

The bug, caused by a merge that looked clean, had to be fixed in yet a third pull request (PR). That’s something I want to avoid in the future and, thankfully, that’s actually pretty easy with some forethought.

The simplest protection? GitHub’s Protected Branches feature. I can turn this on in the Settings section of the repository, in the Branches section.

Menu item for navigating to GitHub's Protected Branches feature.

I want to protect the develop or master branches. I also want to control all the PRs that merge into it. First, add the branch to be protected.

Selecting a branch in Protected Branches.

Next, enable three settings:

  • Protect this branch, enabling branch protection
  • Require status checks, enabling conditions that have to be met before a PR can be merged
  • Request branches to be up to date, making one of those conditions be that all the PR have the latest changes from the upstream branch merged into it, first, before it can be merged and closed.

Setting up branch protection.

This will stop anyone from merging a branch in the future when it hasn’t been updated so that you can get a chance to see the results of the merge before you actually push it upstream.

There are more options you can enable that can give you even stronger safety nets. GitHub can run the test suite automatically using a continuous integration (CI) service like TravisCI or CircleCI. GitHub does their best to make the process painless to set up. CI integration will run the whole test suite when someone creates a PR, when it gets updated, and when branches are merged, GitHub won’t let you merge a PR if the CI hasn’t given it the green light. This may slow down workflows, but it is worth it to know the right things are being merged safely and can save you time in the long run.

Of course, it won’t do everything. Once a branch is updated with the latest from a master or develop branch, a safety checklist should be followed:

  • Have an extensive test suite and be sure that any new changes or additions to a branch are covered by new or adjusted tests.
  • If behavior is added or changed, update tests accordingly to ensure changes are verified when updates, merges, and future changes could break them.
  • Check the project after merging, even with a quick smoke test. Don’t assume changes that looked fine on a branch won’t break merged. Look again.

Developers rely on a lot of tooling. Sometimes tooling fails and some of those times more tooling is actually a good solution (like GitHub helping protect us from common Git mistakes), but don’t forget the human solution of simply being more vigilant.

One last note: Protected branches can be great for small teams, where the team is likely to only have a handful of PRs open at any one time. For a larger team, it may become burdensome that every PR needs both updated and CI run again if the number of PR open (and thus affected by every merge) is much larger. In this case, teams may need to find ways to coordinate better or other tooling options that could work better in those situations.

Read more posts by Calvin on the Caktus blog.

Download Shipping Faster: Django Team Improvements
blog comments powered by Disqus
Times
Check

Success!

Times

You're already subscribed

Times