👀 Watch Rust 🦀 live coding videos on our YouTube Channel.

Introduction #

There are few things that generate as much fear and anxiety in developers as git merge conflicts. git is very popular and very powerful, and it is a low level command line tool. And it is not very user friendly. It is meant to be orchestrate-able and automated using scripts and CI/CD tools, and build systems; it is extremely flexible. It is not meant to be used in an interactive manner w/ a human user at the keyboard.

This just creates an opportunity for others to come along and craft user experiences on top of git that are more use case driven. And these UXes can come in the form or GUIs, TUIs, or even conversational interfaces.

But that’s not the focus of this article which is all about the CLI experience of inducing and resolving merge conflicts. So let’s get started.

👀 Watch Rust 🦀 live coding videos on our YouTube Channel.



📦 Install our useful Rust command line apps using cargo install r3bl-cmdr (they are from the r3bl-open-core project):
  • 🐱giti: run interactive git commands with confidence in your terminal
  • 🦜edi: edit Markdown with style in your terminal

giti in action

edi in action

Setting the stage for a merge conflict #

Let’s create a local repo from scratch and set things up so that we can predictably generate a merge conflict. Here’s what we will do at a high level:

  1. Create a local repo.
  2. Create a main branch.
  3. Create a file in the main branch and add some content to it.
  4. Create a feature branch based on the main branch.
  5. Modify the file in the feature branch.
  6. Modify the same file in the main branch with a change that is going to conflict w/ a change in feature branch.
  7. Merge the feature branch into the main branch.

Here’s a script to get you started:

#!/usr/bin/env bash

# Create a local repo.
export TMP_REPO_DIR="~/Downloads/tmp/git-merge-conflict-demo"
if [ -d $TMP_REPO_DIR ]; then
  echo "Folder exists, recreating $TMP_REPO_DIR"
  rm -rf $TMP_REPO_DIR
  mkdir -p $TMP_REPO_DIR
else
  echo "Folder does not exist, creating $TMP_REPO_DIR"
  mkdir -p $TMP_REPO_DIR
fi
cd $TMP_REPO_DIR
git init
git checkout -b main

# Create a file in the main branch and add some content to it.
# This is the "OG change".
echo -e "This is a new feature.\n## 3. Example 3" > file.txt
git add file.txt
git commit -m "Add myexample3"

# Create a develop branch based on the main branch.
git checkout -b develop main

# Person A comes along and changes this line w/ a plus in the develop branch.
echo -e "This is a new feature.\n## 3. Example 3+" > file.txt
git add file.txt
git commit -m "Fix typo w/ plus in develop branch"

# Person B comes along and change this line w/ a minus in the main branch.
# This is going to conflict with the change in the develop branch.
git checkout main
echo -e "This is a new feature.\n## 3. Example 3-" > file.txt
git add file.txt
git commit -m "Fix typo w/ minus in main branch"

# Merge (using rebase, so no extra commit) the develop branch into the main branch.
git rebase develop

This results in a merge conflict. And when you run git diff it looks like this:

diff --cc file.txt
index 89da142,ef43c8f..0000000
--- a/file.txt
+++ b/file.txt
@@@ -1,2 -1,2 +1,8 @@@
  This is a new feature.
++<<<<<<< HEAD
 +## 3. Example 3+
++||||||| parent of 7c0f0e4 (Fix typo w/ - in main branch)
++## 3. Example 3
++=======
+ ## 3. Example 3-
++>>>>>>> 7c0f0e4 (Fix typo w/ - in main branch)

Let’s use some pictures to understand the story of how we got here. And how to resolve this.

Picture 1: How we got here #

Picture 2: The conflict when develop is applied to main #

Picture 3: How to understand the diff #

Picture 4: How to resolve the conflict #

Next steps #

📦 Install our useful Rust command line apps using cargo install r3bl-cmdr (they are from the r3bl-open-core project):
  • 🐱giti: run interactive git commands with confidence in your terminal
  • 🦜edi: edit Markdown with style in your terminal

giti in action

edi in action

Related Posts