Menu Close

Resolve a Git Merge Conflict with KDiff3 Step by Step

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.

The setup

Project changes, preparing the conflict

Files in the project

To create a merge conflict, I will edit the Door.php file in local version A, of which the content is as follows:

<?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

I have opened two Git bash terminals, one with project version A and one with project version B. Besides that, I have also opened to project two times in different instances of Visual Studio Code. Furthermore, I recommend using the Peacock plugin to distinguish between the different projects with the help of adjusting the color of one of the VSCode instances.

Meanwhile, as you maybe noticed in the code blocks above, line 14 is edited in both versions 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.

# 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 in the same lint should light up for selection. This means you can choose either version for the end result of the merge for each conflict at a time.

With the conflict selected, we should determine which version we want to keep. In our case, the most logical solution would be to choose for C, the change from the remote repository.

With the merge conflict selected, we click on 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