Imagine your codebase looks like this:
line 1
line 2
Your coworkers, Alice
and Bob
, each submit a pull request on their respective branch.
Alice
The PR of Alice
includes two commits:
- In the first commit, she adds her own name to the top of the file:
+ alice
line 1
line 2
- In the second commit, she copies
line 1
andline 2
above the existing code:
+ line 1
+ line 2
alice
line 1
line 2
Bob
Bob
’s PR consists of a single commit where he adds his name in between the existing code:
line 1
+ bob
line 2
Code Review
You are tasked with reviewing the PRs from Alice
and Bob
.
First you inspect the two diffs (#1 and #2) of Alice
’s commits and then merge her PR. Then, you proceed to review the diff
of Bob
’s PR.
After merging both PRs, you anticipate the code to appear as follows:
line 1
line 2
alice
line 1
bob
line 2
However, contrary to your expectations, the code looks like this:
line 1
bob
line 2
alice
line 1
line 2
What Happened?
Git uses a three-way-merge strategy (more precisely the ort
strategy), which does not consider intermediate commits. It analyzes the differences between the latest commits of the two commit histories and their common ancestor commit.
Loading graph...
So in our case, it will only compare the 2nd commit of Alice
with the one of Bob
and doesn’t take into consideration the first commit of Alice
. The information on how she arrived at a specific version of the code is lost.
Specifically, both Alice
’s 2nd commit and the common ancestor begin with:
line 1
line 2
Meanwhile, Bob
’s file starts with:
line 1
bob
line 2
Consequently, Git opts for Bob
’s section of the code. During the subsequent step, while Bob
and the common ancestor share an empty section, Alice
’s version contains:
alice
line 1
line 2
Hence, Git selects Alice
’s section in this instance. This results in the final code looking as follows:
line 1
bob
line 2
alice
line 1
line 2
How Can You Prevent This?
To avoid this issue, use GitHub’s options to always update your branch before merging:
Settings > General > Pull Requests
Settings > Branches > Protection Rules
Note While this doesn’t prevent Git from merging “incorrectly,” this method allows you to identify errors before merging into your
main
branch. Therefore, you can notice the error when inspecting the diff (Files changed) and your CI would be capable of detecting them.
References
This entire repository is based on an example presented in this talk.