Git Merge – Fast-Forward, 3-Way Merge, Conflicts & Best Practices

DevOps · Infrastructure as Code (IaC) · Git Series – Part 12


Merging is how Git combines work from different branches.
It is the heart of collaboration and the backbone of DevOps workflows like:

  • Pull Requests
  • Feature branches
  • Release branches
  • Hotfix workflows
  • CI/CD deployment merges

In this chapter, you’ll learn:

  • How Git Merge works internally
  • Fast-forward vs. 3-way merge
  • Handling merge conflicts
  • Viewing merge history
  • Merge strategies
  • When to choose merge vs rebase
  • DevOps merging standards & best practices

1. What Is Git Merge?

A merge takes the changes from one branch and integrates them into another branch.

Typical workflow:

feature/login  → merged →  main

Merging preserves history, which makes it a preferred choice for team collaboration.


2. Fast-Forward Merge

A fast-forward merge happens when the target branch has no new commits since the feature branch was created.

main ------>
             \
              feature ------>

Git simply moves the pointer forward.

Command:

git switch main
git merge feature/login

Advantages:

✔ Clean history
✔ No merge commit

Disadvantages:

✘ Does not record the merge event
✘ Feature branch disappears into flat history


3. 3-Way Merge (Recursive Merge)

Occurs when both branches have new commits (divergent history).

       A---B (feature/login)
      /
main-O---C---D

Git creates a merge commit that joins the histories.

Command:

git switch main
git merge feature/login

You will see:

Merge made by the 'recursive' strategy.

Advantages:

✔ Preserves exact history
✔ Shows when branches diverged and merged
✔ Good for PR-based workflows

Disadvantages:

✘ More complex graph
✘ Occasional merge conflicts


4. Merge Conflicts – Why They Happen

Conflicts occur when both branches modify the same:

  • lines in a file
  • function block
  • JSON/YAML structure
  • configuration setting

Example conflict (in file):

<<<<<<< HEAD
timeout: 30
=======
timeout: 60
>>>>>>> feature/api

5. How to Resolve Merge Conflicts

Step 1: Check conflict summary

git status

Step 2: Edit the conflicting files

Choose correct version or combine them.

Step 3: Mark conflict resolved

git add <file>

Step 4: Complete merge

git commit

Git automatically creates a merge commit.


6. Tools to Help Resolve Conflicts

VS Code merge editor:

code --wait .

VS Code shows:

  • Current changes
  • Incoming changes
  • Combined result
  • Accept incoming / current / both

Git Built-in Merge Tool

git mergetool

Supports:

  • vimdiff
  • meld
  • kdiff3
  • beyond compare

Enable default tool:

git config --global merge.tool vimdiff

7. Prevent Merge Conflicts (Best Practices)

✔ Pull latest changes before starting work

git pull origin main

✔ Keep branches small & frequent
✔ Commit often
✔ Avoid large monolithic changes
✔ Use .gitattributes to standardize line endings
✔ Use pre-commit hooks for formatting (linting, YAML formatting)


8. Merge Strategies Advanced

Git supports multiple merge strategies:

1. Recursive (default)

Used for most merges; handles simple and complex merges.

2. Ours

git merge -s ours other-branch

Keeps current branch’s content, ignores other branch’s changes.

3. Theirs

No direct command, but possible during conflict resolution.
Used for overwriting with the incoming branch.

4. Fast-forward only

git merge --ff-only feature

Fails if merge cannot fast-forward.

5. No fast-forward (force merge commit)

To preserve merge record:

git merge --no-ff feature

This generates a merge commit even when FF was possible.

Companies often enforce this for PR merges.


9. Merge vs Rebase (When to Use Which)

✔ Use merge when:

  • Working in a team
  • You want full history
  • You are merging feature → main
  • You want PR merge commits retained
  • History rewriting is unacceptable

✔ Use rebase when:

  • Working solo
  • You want clean linear history
  • You need to update your feature branch with main changes

Simple rule:

Never rebase public (shared) branches.


10. Viewing Merge History

Show merge commits only:

git log --merges

Show graph of merges:

git log --graph --oneline --all

View merge commit details:

git show <merge-hash>

11. Undoing a Merge

If merge commit was not yet pushed:

git reset --hard HEAD~1

If merge was pushed, use revert:

git revert -m 1 <merge-commit-hash>

-m 1 means keep main branch’s version as the parent.


12. Real DevOps / IaC Merge Scenarios


📌 1. A new feature is complete – merge to main

git switch main
git pull
git merge --no-ff feature/new-dashboard
git push

Why --no-ff?
Keeps audit-friendly merge records for production.


📌 2. Hotfix workflow

git switch main
git switch -c hotfix/db-timeout
# fix bug
git merge hotfix/db-timeout
git tag -a v1.0.4 -m "DB timeout hotfix"
git push --tags

📌 3. Merging IaC environment branches

For GitOps-style deployments:

main → stage → prod

Promote IaC changes:

git merge stage

This reflects state promotion in tools like ArgoCD & AAP.


📌 4. Merge automation in CI/CD

Tools like GitHub Actions / GitLab CI trigger deployments:

on:
  push:
    branches:
      - main

13. Summary Table – Merge Commands

ActionCommand
Basic mergegit merge branch
Fast-forward onlygit merge --ff-only branch
Force merge commitgit merge --no-ff branch
Abort mergegit merge --abort
View merge commitsgit log --merges
Resolve conflictsedit → git add . → git commit
Merge toolsgit mergetool
Undo merge (local)git reset --hard HEAD~1
Undo merge (public)git revert -m 1 <hash>

Even experienced developers make common merging mistakes. Here are the most frequent ones and how to avoid them:

✘ Merging into the wrong branch: Always verify which branch you’re on with ‘git status’ or ‘git branch’ before merging.

✘ Forgetting to pull before merge: Run ‘git pull origin ‘ before initiating a branch integration to avoid unnecessary conflicts.

✘ Committing merge conflict markers: Never commit files with unresolved conflict markers (<<<<<<, ======, >>>>>>). Always resolve conflicts completely.

✘ Using force push after merge: Avoid ‘git push –force’ after a merge on shared branches; use ‘git push –force-with-lease’ if absolutely necessary, preferably with team communication.

✘ Merging large feature branches without testing: Always test the merge in a development environment before merging to main.

✘ Not updating commit messages in merge commits: Keep merge commits informative with descriptive messages explaining why the branches were combined.

14. Git Merge Troubleshooting Guide

    If you encounter issues during merging, here are practical solutions:

    “Merge in progress” state: If a merge gets stuck, use ‘git merge –abort’ to cancel and start fresh, or ‘git merge –continue’ if conflicts are resolved.

    Untracked file blocks merge: If an untracked file causes merge failure, either delete it or stash changes with ‘git stash’ before retrying the merge.

    Stale branch references: Remote branch deletions can cause issues; run ‘git fetch –prune’ to clean up outdated remote references.

    Large file merge conflicts: For binary files or large files, use ‘git checkout –ours’ or ‘git checkout –theirs’ to take one version entirely, then verify the choice is intentional.

    Merge commits not showing history: Use ‘git log –graph –oneline –all’ to visualize merge commit relationships and confirm the merge structure.

    15. Frequently Asked Questions

      Q: What’s the difference between “git merge” and “git rebase”?
      A: Merge combines branches while preserving both histories; rebase replays commits linearly. Use merge for shared branches, rebase for local feature branches.

      Q: Can I undo a merge that’s already been pushed?
      A: Yes, use ‘git revert -m 1 ‘ to create a new commit that undoes the merge, preserving history for other team members.

      Q: When should I use “–no-ff” for merging?
      A: Use “–no-ff” (no fast-forward) for feature branches to main, as it creates a merge commit that documents the feature integration point.

      Q: How do I merge only specific commits from another branch?
      A: Use ‘git cherry-pick ‘ to apply individual commits from one branch to another.

      Q: What’s the best conflict resolution strategy for large teams?
      A: Communicate with team members, pull latest changes frequently, use merge tools like VS Code’s merge editor, and keep branches focused and short-lived.

      To deepen your understanding of Git merge strategies and best practices, check out these resources:Official Git Documentation – Git Merge:

      GitHub Guides on Git Merge: https://guides.github.com/introduction/git-handbook/

      Atlassian Git Tutorials: https://www.atlassian.com/git/tutorials/using-branches/merge-strategy

      Git Cherry Pick and Advanced Merging: Part of our comprehensive Git Series tutorial series

      16. What’s Next?

      You now understand:

      ✔ Fast-forward merges
      ✔ 3-way recursive merges
      ✔ Merge commit structure
      ✔ Conflict resolution
      ✔ Merge tools
      ✔ Merge strategies
      ✔ DevOps-friendly merging workflows

      Next chapter:

      ➡️ Part 13 – Git Rebase: Clean Linear History, Interactive Rebase, Squashing & Conflict Handling
      A deeper dive into rebasing, rewriting history safely, interactive rebase (pick, squash, fixup), and DevOps rebase workflows.Resources & Further ReadingCommon Git Merge Mistakes

      Leave a Reply

      Your email address will not be published. Required fields are marked *