← Back to Index

Contents

Resolve git conflicts easily

Parent backlink:

Test setup

# activate diff3 conflict style
# git config --global merge.conflictstyle diff3
# since recently, the option zdiff3 also exists
# git config --global merge.conflictstyle diff3
$ rm -rf /tmp/git-conflicts-repro
$ mkdir -p /tmp/git-conflicts-repro
$ cd /tmp/git-conflicts-repro
$ git init &&
 git branch -m main &&
 echo -e "class Square : public Rectangle {\npublic:\n  //this comment is a bit outdated\n  static Rectangle* DefaultEmpty();\n};\n" >Square.h &&
 git add Square.h &&
 git commit -m "a" &&
 git branch new-branch &&
 git switch new-branch &&
 echo -e "class Square : public Rectangle {\npublic:\n  //this comment is a bit outdated\n  static const Rectangle* DefaultEmpty();\n};\n" >Square.h &&
 git add Square.h &&
 git commit -m "b" &&
 git switch main &&
 echo -e "class Square : public Rectangle {\npublic:\n  static Rectangle* DefaultEmptyObject();\n};\n" >Square.h &&
 git add Square.h &&
 git commit -m "c" &&
 git merge new-branch

Initialized empty Git repository in /Users/mtt/pers/tmp-git-conflicts-repo/.git/
[main (root-commit) 8134ad7] a
 1 file changed, 6 insertions(+)
 create mode 100644 Square.h
Switched to branch 'new-branch'
[new-branch 5e94702] b
 1 file changed, 1 insertion(+), 1 deletion(-)
Switched to branch 'main'
[main 56d83f6] c
 1 file changed, 1 insertion(+), 2 deletions(-)
Auto-merging Square.h
CONFLICT (content): Merge conflict in Square.h
Recorded preimage for 'Square.h'
Automatic merge failed; fix conflicts and then commit the result.

Anatomy of diff3 conflict style

There are three areas, from top to bottom

  1. ours: the current state of the rebase
  2. base: the code state before the commit to apply
  3. theirs: the code state after the commit to apply

which I am going to refer by numbers.

$ cat Square.h

class Square : public Rectangle {
public:
<<<<<<< HEAD
 static Rectangle* DefaultEmptyObject(); // (1)
||||||| 8134ad7
 //this comment is a bit outdated // (2)
 static Rectangle* DefaultEmpty();
=======
 //this comment is a bit outdated // (3)
 static const Rectangle* DefaultEmpty();
>>>>>>> new-branch
};

Mechanistic method to solve diff3 conflicts

1. Understand the difference between (2) and (3)

(2) is this block:

||||||| 8134ad7
  //this comment is a bit outdated
  static Rectangle* DefaultEmpty();
=======

(3) is this block:

=======
 //this comment is a bit outdated
 static const Rectangle* DefaultEmpty();
>>>>>>> new-branch

We analyse the difference (3) - (2). First, we note that //this comment ... is identical, so it should be removed from both to simplify, now get:

(2') is this block:

||||||| 8134ad7
  static Rectangle* DefaultEmpty();
=======

(3') is this block:

=======
 static const Rectangle* DefaultEmpty();
>>>>>>> new-branch

Now, semantically, the difference (3') - (2') can be described as

add const to return type Rectangle pointer

.

2. Apply that difference to (1)

(1) is this block:

<<<<<<< HEAD
  static Rectangle* DefaultEmptyObject();
||||||| 8134ad7

So we apply this operation:

add const to return type Rectangle pointer

which results in

static const Rectangle* DefaultEmpty();

since we applied all operations, we can remove the conflict markers so the final Square file looks like

$ cat Square.h

class Square : public Rectangle {
public:
 static const Rectangle* DefaultEmptyObject();
};

Remember block names

See 2025-12-31-17-29-vim-annotate-git-conflicts-markers.

Contents