Menu Close

Resolve a Git Merge Conflict with KDiff3 Step by Step

Post edited at February 16, 2025

Introduction

I created a small PHP demo project to create and resolve a git merge conflict with the help of KDiff3. In this project I’ve created an index file that creates a house with a number of doors and windows. To get a better grasp of Git, you can read this post first. If you need to setup an access key for a remote repository like Bitbucket, additionally read all about that here.

Setup

On my PC I have a directory named test with two folders: A and B. These represent or simulate the same project that might have been on separate computers. Both A and B are a local git repository which point to the same remote repository. To be extra clear: Local Project A and B are local git repositories of the same project, which will only sync with the help of the same remote repository. A and B never communicate directly with each other.

Project A is synced to remote. Project B is cloned from the remote version.

Project changes, preparing the conflict

Files in the project

We start out with exactly the same files in project A, B and remote. To create a merge conflict, I will edit the Door.php file in local version A. Below is the original version, which is still the same at all 3 repositories.

<?php
# Original version, synced over repository A, B and remote
namespace Test;

class Door {
	
	protected $num;
	
	public function __construct($num) {
		$this->num = $num;
	}
	
	public function __toString() {
		return "Door $this->num";
	}
}

?>
PHP

In version A of the repository, I altered this file to the following:

<?php
# Edited version in repository A
namespace Test;

class Door {
	
	protected $num;
	
	public function __construct($num) {
		$this->num = $num;
	}
	
	public function __toString() {
		$str = "I am door number %d ";
		return sprintf($str, $this->num);
	}
}

?>
PHP

In version B of the repository, I altered this file to the following:

<?php
# Edited version in repository B
namespace Test;

class Door {
	
	protected $number;
	
	public function __construct($number) {
		$this->number = $number;
	}
	
	public function __toString() {
		return "Door $this->number";
	}
}

?>
PHP

The merge conflict emerged

Line 14 is edited in both A and B which will give the conflict.

Committing the changes

# project version A: www/test/A
git add .
git commit -m "Edited Door to make use of a formatted string"
git pull origin main # nothing will be pulled, as there are no changes
git push origin main 
Bash
# project version B: www/test/B
git add .
git commit -m "Edited variable name to make it more readable"
git pull origin main # here the merge conflict will occur
Bash
From https://bitbucket.org/<username>/<repos>
 * branch            main     -> FETCH_HEAD
   bd18f21..b0ca1b9  main     -> origin/main
Auto-merging Door.php
CONFLICT (content): Merge conflict in Door.php
Automatic merge failed; fix conflicts and then commit the result.

The content of Door.php of version B of the project is now altered to the following by Git:

<?php

namespace Test;

class Door {
	
	protected $number;
	
	public function __construct($number) {
		$this->num = $number;
	}
	
	public function __toString() {
<<<<<<< HEAD
		return "Door $this->number";
=======
		$str = "I am a house with %d doors and %d windows";
		return sprintf($str, count($this->doors), count($this->windows));
>>>>>>> b0ca1b9e58365a94bb64ba558ef13a275d0467e6
	}
}

?>
Bash

Interpreting KDiff3

To resolve the merge conflict, we are going to use KDiff3. You can read about setting up KDiff3 with Git here in the Chapter configurations which is a subchapter of chapter The Flow.

We are currently working in local project B.

# startup our configured merge tool, we run this from project version B
git mergetool
Bash

This will open up KDiff3 in our case.

Three of the four lines that were altered could be automatically merged, because they were on different lines altogether.

  • (A) Base (left window): Is the common ancestor, both altered versions of Door.php derive from this commit.
  • (B) Local (middle window): Is version B of Door.php. The perspective from where we ran git mergetool from the command line. In other terms, this usually is the only local repository of the project you would have.
  • (C) Remote (right window): Is version A of Door.php. This could be the work of a co-worker or friend. Don’t confuse “C”, the label of the version made by KDiff3, with “A” our version of the project. They have nothing to do with each other.

In the Window below these three, the end result of the merge conflict is displayed. The letter (A, B or C) in front of the lines tells you from which version the content is coming.

Solving the merge conflict

From the array of buttons in the lint above the three windows, we should go to the next unresolved conflict. Because there is only one conflict, this should already be selected. Otherwise, you go through each conflict one by one. Use the buttons with arrows displayed on it or click on go to current delta to select the conflict. In any case, the buttons A, B, and C should light up for selection. For each merge conflict, you can choose to keep either the version from A (left window), B (middle window) or C (right window).

With the merge conflict selected, in this example I selected to keep version C.

This is what our merged end result will look like

You can close KDiff3 after selecting C and click on save and exit when prompted. The merge is now complete.

Debugging

As you might have noticed, the variable name $num to $number was inconsistently changed. The file after the merge looks like the following:

<?php

namespace Test;

class Door {
	
	protected $number;
	
	public function __construct($number) {
		$this->number = $number;
	}
	
	public function __toString() {
		$str = "I am door number %d ";
		return sprintf($str, $this->num); // error
	}
}
PHP

We have to manually update line 15 to:

return sprintf($str, $this->number);
PHP

The only thing left is to commit the merge and push it to the remote repository. This concludes a way to resolve a Git merge conflict with the help of KDiff3.

Related Posts