Skip to main content
· Git · 3 min read

Git Merging Strategies for GitOps-Ready Repositories

In a GitOps workflow, your git history is your audit trail. When a deployment fails, you need to trace it back through commits. When a rollback is needed, you need a clean target. The merge strategy you choose directly affects how usable that trail is.

The Three Strategies

%%{ init: { 'look': 'handDrawn' } }%%
graph TD
    A[Feature branch] -->|Merge strategy| B[Option 1: Regular merge<br/>Preserves all commits]
    A -->|Merge strategy| C[Option 2: Squash merge<br/>Single commit per feature]
    A -->|Merge strategy| D[Option 3: Rebase + merge<br/>Clean linear history]

Strategy 1: Regular Merge

git checkout main
git merge feature/add-observability

All commits from the feature branch are preserved in the merge commit. This is the most honest history — you see exactly what happened, including intermediate work-in-progress commits.

Problem: In active branches, this creates a messy commit graph. git log --graph looks like a railroad switching yard.

When to use: Small teams, experimental branches, or when you need full traceability of every change.

Strategy 2: Squash Merge

git checkout main
git merge --squash feature/add-observability
git commit -m "feat: add observability to deployment pipeline"

All feature branch commits collapse into one commit on main. Clean history, easy rollback (one commit reverts the entire feature).

Problem: You lose the granularity of the feature branch’s development history. The squash commit is a black box.

When to use: GitOps pipelines where you want one logical change = one commit = easy rollback. Most CI/CD systems map commits to deployments, so a clean commit per feature makes rollback trivial.

%%{ init: { 'look': 'handDrawn' } }%%
graph LR
    A[feature/add-logs] -->|5 commits| B[ squash merge]
    B --> C[1 commit on main]
    C --> D[CI detects commit<br/>triggers deployment]
    D --> E[Rollback = git revert<br/>1 commit undoes all 5]

Strategy 3: Interactive Rebase + Merge

git rebase -i HEAD~5  # Rewrite commits interactively
git checkout main
git merge feature/add-observability  # Fast-forward

Clean, linear history. You control exactly what each commit says before it lands on main.

Problem: Requires --force-with-lease push. If two people are working on the same branch, rebasing rewrites history and causes conflicts on the next pull.

When to use: Open-source projects, large teams with well-defined PR processes, or when your team values a clean git log above all else.

GitOps-Specific Considerations

%%{ init: { 'look': 'handDrawn' } }%%
graph LR
    A[main branch] --> B[CI detects new commit]
    B --> C[GitOps operator<br/>ArgoCD / Flux]
    C --> D[Sync to cluster]
    D --> E{Deployment succeed?}
    E -->|Yes| F[Commit tagged as deployed]
    E -->|No| G[Rollback = git revert]
    G --> H[CI detects revert<br/>syncs previous commit]

For GitOps to work cleanly:

  • Squash merges make rollback reliable — one commit = one deployment unit
  • Commit messages become the changelog — write them like release notes, not work logs
  • Atomic commits — don’t mix “fix typo” with “add feature” in the same squash commit

Which Strategy to Choose

ScenarioStrategy
Active feature branch with WIP commitsSquash merge
Small, atomic PRs that are review-readyRebase + merge
Auditing requirement — full historyRegular merge
GitOps with ArgoCD/FluxSquash merge
Monorepo with many contributorsRebase + merge

The goal isn’t purity — it’s a history you can actually use when something breaks at 2am.

The other half of that is release structure: which branches exist, and what a version number is allowed to mean. I covered that separately in GitFlow and semantic versioning.