GitLab Merge Blocked: Source Branch Behind Target

GitLab Merge Blocked: Source Branch Behind Target

· 6 min read
gitlab-for-your-team

You merged a feature to develop, tested it, created an MR from develop to main, and got this:

The merge is blocked The source branch is 2 commits behind the target branch.

If this keeps happening, you’re missing one critical step.

The Problem

Typical scenario:

  1. Developer: Pull latest develop, branch off, build feature, push, open MR to develop
  2. Admin: Approve, merge to develop. Staging looks good.
  3. Create MR from develop to main: Blocked.
The merge is blocked
The source branch is 2 commits behind the target branch.
1 commit and 1 merge commit will be added to main (squashes 34 commits).
Source branch will not be deleted.

Why?

The Root Cause

The Missing Step

After merging developmain, you’re NOT merging main back into develop.

This is the #1 mistake that causes “source behind target” errors.

Merging develop into main creates a merge commit on main. That commit only exists on main. Now main has history that develop doesn’t.

Diagram

After the merge, main has a merge commit that develop lacks. Next time you try develop to main, Git sees develop is “behind” because it’s missing that commit.

The Fix: Sync Back After Every Merge to Main

After every merge from develop to main, sync main back:

# Step 1: Switch to develop
git checkout develop

# Step 2: Get the latest from remote
git fetch origin

# Step 3: Merge main into develop
git merge origin/main

# Step 4: Push the synced develop
git push origin develop
💡 Why This Works

By merging main back into develop, you’re bringing that merge commit into develop. Now both branches have the same history, and future merges won’t be blocked.

What Happens When You Run git merge

git merge origin/main may open an editor (Nano or Vim) for the merge commit message:

Merge remote-tracking branch 'origin/main' into develop

# Please enter a commit message to explain why this merge is necessary,
# especially if it merges an updated upstream into a topic branch.
#
# Lines starting with '#' will be ignored, and an empty message aborts
# the commit.

If you see Nano (the default editor):

  1. Merge message is at the top
  2. Ctrl + O to save
  3. Enter to confirm
  4. Ctrl + X to exit

If you see Vim:

  1. Esc to enter normal mode
  2. :wq then Enter

To skip the editor entirely:

git merge origin/main --no-edit

The Golden Rule

Rule: Always Sync Back

After every merge to main, immediately sync main back to develop:

Make this a habit. Better yet, automate it.

git checkout develop
git fetch origin
git merge origin/main --no-edit
git push origin develop

Automating the Sync-Back

GitLab CI/CD Pipeline

Add this to .gitlab-ci.yml to auto-sync after merges to main:

sync-develop:
  stage: post-deploy
  rules:
    - if: $CI_COMMIT_BRANCH == "main" && $CI_PIPELINE_SOURCE == "push"
  script:
    - git checkout develop
    - git pull origin develop
    - git merge origin/main --no-edit
    - git push origin develop
  tags:
    - docker

Complete Workflow Example

Full flow from feature to production, including sync-back:

# 1. Developer creates feature
git checkout develop
git pull origin develop
git checkout -b feature/awesome-feature

# Work on feature...
git add .
git commit -m "feat: add awesome feature"
git push origin feature/awesome-feature

# 2. Create MR: feature → develop (in GitLab UI)
# Get it reviewed and merged

# 3. After feature merged to develop, create MR: develop → main
git checkout develop
git pull origin develop

# Before creating MR, ensure develop is synced with main
git merge origin/main --no-edit
git push origin develop

# Now create MR in GitLab: develop → main

# 4. After MR merged to main, SYNC BACK!
git checkout develop
git fetch origin
git merge origin/main --no-edit
git push origin develop

Why GitLab Blocks the Merge

GitLab’s merge checks prevent merging when the source is behind the target. This is a safety feature:

  • Prevents overwriting commits on main
  • Ensures you’ve tested against the latest production code
  • Forces conflict resolution before merging

Found in Settings, Merge Requests, Merge checks:

  • Pipelines must succeed: CI must pass
  • All discussions must be resolved: All comments addressed
  • Source branch must be up to date: Blocks if behind target
Don't Disable the Check

While you can disable the “Source branch must be up to date” check, this is NOT recommended. Instead, fix the root cause by syncing your branches properly.

Prevention is Better Than Cure

1. Establish the Sync-Back Rule

Team policy: Every merge to main must be followed by syncing main back to develop.

2. Use Protected Branches

Configure in GitLab:

  • main: Fully protected, requires approval
  • develop: Protected, allows merges from main

Quick Reference

When you see “source branch is X commits behind target”:

# Sync the source branch with target
git checkout develop          # or your source branch
git fetch origin
git merge origin/main         # or your target branch
git push origin develop

After every merge to main:

git checkout develop
git merge origin/main --no-edit
git push origin develop

If you’re in Nano editor:

  1. Ctrl + OEnterCtrl + X

If you’re in Vim editor:

  1. Esc:wqEnter

Summary

“Source branch behind target” happens because main isn’t synced back to develop after merges. Fix:

  1. After every merge to main:

    git checkout develop
    git merge origin/main
    git push origin develop
  2. Make it a team habit or automate it in CI/CD

  3. Never disable the merge check — fix the root cause