Prevent Hidden Merge Conflicts
Tags: git, productivity, github, gitlab
Published: 2024-06-28 14:09:16

## Table of Contents

- [What are Hidden Merge Conflicts?](#what-are-hidden-merge-conflicts)
  - [Example 1: Function Signature Changes](#example-1-function-signature-changes)
  - [Example 2: Database Migrations](#example-2-database-migrations)
- [How Can They Be Prevented?](#how-can-they-be-prevented)
  - [GitLab](#gitlab)
  - [GitHub](#github)

---

> This article will use the term Merge Request (MR) as it is called on GitLab, but it is equally as relevant to GitHub's Pull Request (PR)

---

## What are Hidden Merge Conflicts?

### Assumptions:

- We aim to maintain an evergreen main branch.
- We work on features, bug fixes, and improvements on branches in MRs.

Hidden merge conflicts occur when changes in one merge request (MR) indirectly impact another MR without direct file conflicts, leading to potential issues in the main branch. Let's explore two common scenarios.

### Example 1: Function Signature Changes

Assume multiple MRs are open. One MR changes a function's signature in a file not touched by another MR, but this second MR uses the altered function. When the first MR is merged, the second branch is now a commit behind. Without "Fast-forward merge" in GitLab or "Require branches to be up to date before merging" in GitHub, the CI doesn't rerun before merging. Consequently, the second MR can be merged without detecting the break (hidden merge conflict), potentially causing the main branch to fail due to the signature change.

### Example 2: Database Migrations

Consider two parallel MRs, each adding a new database migration file. For example:

- MR1: `002_add_person_table.sql`
- MR2: `002_add_company_table.sql`

If MR1 is merged first, MR2 is unaffected. However, when MR2 is merged, its migration file (`002_add_company_table.sql`) is alphabetically before MR1's (`002_add_person_table.sql`). This leads to a migration conflict due to the execution order stored in the migration table or the tool raising a conflict for duplicate `002` definitions. Thus, the main branch fails again.

---

## How Can They Be Prevented?

### GitLab:

1. Go to Repository > Settings > Merge requests:  
   <img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/50ki29e403t43f0y3vno.png" alt="GitLab Settings" title="GitLab Settings" />

2. Under "Merge methods" select "Fast-forward merge":  
   <img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/89c3u8czhg1zfj5dlsv5.png" alt="GitLab Merge Methods" title="GitLab Merge Methods" />

### GitHub:

1. Go to Repository > Settings > Branches:  
   <img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/66nh5u6rxo7jfe40v9id.png" alt="GitHub Settings" title="GitHub Settings" />

2. Add or Edit "Branch protection rules" for your main branch:  
   <img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/unl281woq2l553opwdbo.png" alt="GitHub Branch Protection Rules" title="GitHub Branch Protection Rules" />

3. In "Protect matching branches" select "Require status checks to pass before merging" and then "Require branches to be up to date before merging":  
   <img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r4ymdaxo0juwrtrfc3ed.png" alt="GitHub Require Status Checks" title="GitHub Require Status Checks" />

---

By configuring these settings, you can effectively prevent hidden merge conflicts and maintain a stable, evergreen main branch.

---

> **Limitation:**
> This does not prevent issues like changes of global CSS affecting the new component