DEV Community

Ahmed Rakan
Ahmed Rakan

Posted on

Fear no more: merge conflicts

To over come fear with merge conflicts you have to deliberately create them " personal project " and fix them the hard way. So when it accidently happen, you are more than ready to shine.

But in order to fix merge conflicts the hard way, as there is no easy way, a sound knowledge of git branching and merging is required.

Requirements: Basic knowledge of git.

Table of content:

  • Branching.
  • Branching main operations.
  • Git Flow
  • Branch Types.
  • merging
  • types of merging
  • two-way merge
  • three-way merge
  • merge conflict
  • steps to resolve merge conflict
  • strategies to approach merge conflict with

Branching

Image description

Branching means you diverge from the main line of development and continue to do work without messing with that main line. In many VCS tools, this is a somewhat expensive process, often requiring you to create a new copy of your source code directory, which can take a long time for large projects.
One must understand the way git stores data in order to grasp branching.

Git store data as snapshots not series of changes and differences between files as most people think.

When you commit a change git stores a commit object that contains a pointer to the snapshot of the staged content.

Let us see an example:

  1. we will create plain example.text
  2. we will create a commit using the file
  3. we will use git log, git-show commands to see the blolb tree " a blob is a content of a file "
$ git add example.txtgit 
$ git commit -m " example.txt "
$ git log
commit 6d9d95c14f2d7ac6cdcbbb03c376ba431efc6ad6 (HEAD -> main)
Author: Ahmed <myemail>
Date:   Mon May 22 18:52:03 2023 +0300

     example.txt 
$ git log --pretty=format:"%h %s" --graph
* 6d9d95c  example.txt
* 40b12af  learning notes 5/9/2023
* 7d11262  ch1 done
*   fd63c0c  merge
|\
| *   efc9861  merge con
| |\
| * | 08ce855  nginx
* | | 1a88669  rabbitmq laptob
| |/
|/|
* | da88f70  nginx
|/
* 2898ec5  nginx
*   2d76698 Merge branch 'main' of https://github.com/ARAldhafeeri/learning
|\
| * f8b3bd6  cloud
* | 02d29af  learning
:
Enter fullscreen mode Exit fullscreen mode

as you can see there is a one full tree that lists content of the directory. With 6d9d95c blob representing a snapshot of the content of example.txt

lets make another change and commit the file again

$ git add example.txt   
$ git commit -m " example.txt 2"
[main b1dcd02]  example.txt 2
 1 file changed, 1 insertion(+)
$ git log --oneline --decorate --graph --all
* b1dcd02 (HEAD -> main)  example.txt 2
* 6d9d95c  example.txt
* 40b12af (origin/main)  learning notes 5/9/2023
* 7d11262  ch1 done
*   fd63c0c  merge
|\  
| *   efc9861  merge con
| |\
| * | 08ce855  nginx
* | | 1a88669  rabbitmq laptob
| |/
|/|
* | da88f70  nginx
|/
* 2898ec5  nginx
*   2d76698 Merge branch 'main' of https://github.com/ARAldhafeeri/learning
|\
| * f8b3bd6  cloud

Enter fullscreen mode Exit fullscreen mode

As you can see new blob created b1dcd02 with a snapshot of our change with ( HEAD -> main ).

The previous example shows us that a branch in git is nothing but a pointer that moves and point to a specific commit within our local branch until we push the changes. In other words, every time you make a commit the branch pointer moves forward automatically.
Image description
Image source: Git Branching - Branches in a Nutshell

Branching main operations:

Now we have better understanding on what a branch is, lets see some operations we can do with git on branches.

List branches

To list branches in git use the following command:

$ git branch
* main
Enter fullscreen mode Exit fullscreen mode

Branch deleting operations

There are two options with deleting a branch:
with -d flag: safe option if the branch has unmerged commits they will not be deleted.

with -D flag: To forcefully delete a branch.

Example -d flag, deleting meow branch with keeping unmerged commits locally

$ git branch -d meow
Enter fullscreen mode Exit fullscreen mode

Example -D, deleting a branch meow forcefully everything will be gone:

$ git branch -D meow
Enter fullscreen mode Exit fullscreen mode

rename current branch :

 $ git branch -a 
  main
* meow
$ git branch -m test
$ git branch
  main
* test
Enter fullscreen mode Exit fullscreen mode

creating new branches:

git branch test2
Enter fullscreen mode Exit fullscreen mode

Git flow

Image description
Image source:

After a good dive into git branches concept and operations. Now we are ready to move to branches type within a given version control system using git. But not before we explain git flow:

Gitflow is an alternative Git branching model that involves the use of feature branches and multiple primary branches. It was first published and made popular by Vincent Driessen at nvie. Compared to trunk-based development, Gitflow has numerous, longer-lived branches and larger commits. Under this model, developers create a feature branch and delay merging it to the main trunk branch until the feature is complete. These long-lived feature branches require more collaboration to merge and have a higher risk of deviating from the trunk branch. They can also introduce conflicting updates.

Gitflow is abstracted idea of git workflow which is simply separating and protecting the main branch from other types of branches. Which allows teams to create multiple branches and work on hotfixes, features in-parallel.

In the image above you will see there are five types of branches: master, feature, development, release , hotfix.

In the next section we will talk about each in details:

Git branch types:

The master/main branch:

When a repository is made; git automatically creates new branch.

  • Main branch must be protected from direct changes, changes must be merged via a feature branch.
  • Only tested, verified , stable code should be merged with main branch.

Feature Branch:

Where developers perform development and test, add new features.

  • Can be created for many reasons: testing, bug fixing, new software features.
  • All feature branches that a team is currently working on , may or may not be merged into a single development branch.
  • Features for a specific release are usually combined into single feature branch.

Development feature:

Where multiple feature branches are merged.

  • Instead a single development main branch, branches are split into many development branches usually linked to a specific release that a development team is pushing for.

Release branch:

A verified , test-pass development branch is merged for further verification before staging it to the production branch " master ".

  • A point at which no further commits are to be done and a specific release is ready for production.
  • After the development team checks few flags automatically or manually, the release branch is merged with main and the code is pushed to production manually or automatically.

hot fix branch:

A temporary branch for urgent fixes to the production environment.

  • Urgent fixes to unexpected bugs or errors, once the issue is resolved within the hotfix branch, the code is merged with main.

Merging

We mentioned the word merge a lot talking about branching in git, because they are closely related.

Merging is Git's way of putting a forked history back together again. The git merge command lets you take the independent lines of development created by git branch and integrate them into a single branch.

What problem merging solve ?

When multiple developers work on local repositories on a specific feature branch, they will merge the branch with a development branch after all the tasks are done.

If the developers pull the changes on a specific branch before they start making changes on a daily basis, they will avoid known problem aka merge conflict. Which we will talk about after clarifying the word merging types, operations.

Merge types :

Two-way merge

  • Where the merge involves only two snapshots. For example let say we checkout the following branches from main, assuming no further commits are made on main branch: F1 feature branch Then we checkout F2 feature branch from F1 branch When we merge F2 with main branch this is called two-ways merge. The change of having a merge conflict is low.

Three way merge

Where merge involves three snapshots. For example
let say we checkout the following branches from main, assuming no further commits are made on main branch:
F1 feature branch
Then we checkout
F2 feature branch from F1 branch
Then another developer on the team checkout
F3 feature branch and add some code to it.

Then we need first to merge F2 with F3 if no merge conflict we can merge with main.

merge conflict

A merge conflict occur when two developers push changes on the same line of a file, or when a developer delete a file, and another developer have made changes on it.

Image description

In the example above , both Jenny and John changed the factor, both pushed changes to the same branch changing the same line on the same file.

What is going to happen ? One of them will receive a merge conflict message from git.

Since the local git repository for John or Jenny is not up to date depending who pushed the changes first.

Steps to resolve merge conflicts:

Step number one is solid fundamentals in git. Git is an important skill to master as a developer. If your team is not following the standards , suggest to them, as most good teams do, and every developer wants to work with good teams.

Practical steps:
1- Communicate with your teammate about the merge conflict professionally and have pair programming session if possible to solve the merge conflict.

2- Once merge conflict on the specific file/files is resolved, add the content.

3- Perform a new commit and push it, hopefully without any merge conflicts.

How to over come fear of merge conflict ?

  • Create personal project and deliberately create merge conflicts and solve them the hard way.

merge strategies :

As explained merge happen when developers want to combine two branches. Git will try to find a base commit between the two branches. Git have many methods in which a base commit is found which are called merge strategies:

Recursive:

The recursive strategy default behavior is to pull or merge one branch into the other. Benefits of using this strategy; It detect and manage mergers

$ git merge -s recursive b1 b2
Enter fullscreen mode Exit fullscreen mode

Resolve:

  • A three way merge to resolve branches; This strategy can resolve two heads using 3-way merge algorithm. Very fast and save as it tries to detect merge differences.
$ git merge -s resolve b1 b2
Enter fullscreen mode Exit fullscreen mode

ours:

Operate on multiple branches, all changes from previous feature branch is ignored and changes from the master branch will be considered

git merge -s our b1 b2 b3 b4
Enter fullscreen mode Exit fullscreen mode

octopus

The best option to deal with a merge that involves two or more branches.

$ git merge -s octopus b1 b2 b3 bN
Enter fullscreen mode Exit fullscreen mode

sub-tree

An extension of recursive strategy, used to merge two trees that have common parent or ancestor.

For example consider the following :
main
|
/ \
K S
/\
A B

$ git merge -s subtree A B
Enter fullscreen mode Exit fullscreen mode

Since both A and B have common ancestor K branch, then subtree will handle the merge, even if there is another subtree under A or B.

Top comments (0)