The most common cause of Git merge failures is undoubtedly conflicting changes, by which I mean changes to the same region of the same file. But in my experience, the most common cause of silent Git merge failures is when two developers independently make the same change in two different places. By “silent failure”, I mean that the code is broken by these two independent attempts to implement the same feature of fix the same bug.

Most people who have worked on a team of software developers have seen failures like this, but for new developers, I wanted to generate an example of such a failure to demonstrate the problem. A version of the script I used is below. I’ve provided a very simple program, but for internal corporate education, using the company’s own code is usually best.

#!/bin/bash
set -e

function main {
  mkdir merge-demo
  cd merge-demo
  git init .

  write_demo_py 1 1 1
  git add demo.py
  git commit -m "Initial commit"
  python demo.py

  git checkout -b new-branch
  write_demo_py 1 2 1
  git add demo.py
  git commit -m "Change sum to four"
  python demo.py

  git checkout master
  write_demo_py 1 1 2
  git add demo.py
  git commit -m "Change sum to four"
  python demo.py

  git merge new-branch -m "Auto-merge"
  cat demo.py
  python demo.py
}

function write_demo_py {
  # takes three arguments:
  # the values of a, b, and c
  cat << EOF > demo.py
#!/usr/bin/env python3

a = $1
b = $2

# Comments here make these blocks appear unrelated
# to git's text-based merge, even though they
# don't make any difference to Python when it
# executes our program.

c = $3

# Here is another block of comments to break things
# up. In real code, you could imagine there being
# more code here, rather than just comments.

print(a+b+c)
EOF
}

main

This script generates the following output.

$ ./test.sh
Initialized empty Git repository in /tmp/merge-demo/.git/
[master (root-commit) cc472fe] Initial commit
 1 file changed, 17 insertions(+)
 create mode 100644 demo.py
3
Switched to a new branch 'new-branch'
[new-branch 0eb63b2] Change sum to four
 1 file changed, 1 insertion(+), 1 deletion(-)
4
Switched to branch 'master'
[master bbcbd74] Change sum to four
 1 file changed, 1 insertion(+), 1 deletion(-)
4
Auto-merging demo.py
Merge made by the 'recursive' strategy.
 demo.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
#!/usr/bin/env python3

a = 1
b = 2

# Comments here make these blocks appear unrelated
# to git's text-based merge, even though they
# don't make any difference to Python when it
# executes our program.

c = 2

# Here is another block of comments to break things
# up. In real code, you could imagine there being
# more code here, rather than just comments.

print(a+b+c)
5