KhueApps
Home/DevOps/Fix 'The branch is not fully merged' when deleting in Git

Fix 'The branch is not fully merged' when deleting in Git

Last updated: October 07, 2025

Overview

Git blocks git branch -d <name> if the branch’s commits are not reachable from your current branch (often main or develop). This protects unmerged work from accidental loss. You can:

  • Integrate the work (merge, rebase, or cherry-pick), then delete.
  • Decide to discard it and force-delete (-D) after a quick safety check.

This guide shows practical, DevOps-friendly steps to resolve the message safely.

Quickstart (most common fixes)

  • See what’s unmerged:
    • git branch --no-merged
    • git log --oneline --left-right --cherry-pick --graph main...feature
  • Merge the branch into your target:
    • git checkout main && git merge --no-ff feature
  • Or pick specific commits:
    • git checkout main && git cherry-pick <commit1> <commit2>
  • If discarding on purpose, make a backup tag and force-delete:
    • git tag backup/feature feature && git branch -D feature
  • Delete remote branch (if needed):
    • git push origin --delete feature && git fetch -p

Minimal working example

This demonstrates the error and three ways to fix it.

# 1) Setup demo repo
mkdir demo && cd demo
git init -b main
printf "one\n" > file.txt
git add file.txt && git commit -m "init"

# 2) Create a feature branch with unique commits
git checkout -b feature
echo "feature A" >> file.txt
git commit -am "feat: add A"
echo "feature B" >> file.txt
git commit -am "feat: add B"

# 3) Switch back and try to delete (will fail)
git checkout main
git branch -d feature
# -> The branch 'feature' is not fully merged ...

# Fix Option A: Merge the work
git merge --no-ff feature
git branch -d feature  # now succeeds

# Reset to before merge to try other options (demo only)
git reset --hard HEAD~1

# Fix Option B: Cherry-pick specific commit(s)
git log --oneline main..feature   # list unique commits
git cherry-pick <hash-of-desired-commit>
git branch -d feature

# Fix Option C: Force-delete after making a backup tag
git tag backup/feature feature
git branch -D feature

Step-by-step resolution

  1. Confirm target branch
  • Ensure you’re on the branch that should contain the work (e.g., main).
  • git rev-parse --abbrev-ref HEAD
  1. Identify unmerged work
  • List branches not fully merged into your current branch:
    • git branch --no-merged
  • Compare differences (symmetric diff):
    • git log --oneline --left-right --cherry-pick --graph main...feature
  • Show commits unique to feature:
    • git log --oneline main..feature
  • Diff actual changes:
    • git diff main...feature
  1. Decide how to handle the changes
  • Merge (keeps history): git checkout main && git merge --no-ff feature
  • Squash merge (single commit): git checkout main && git merge --squash feature && git commit
  • Rebase feature onto main, then fast-forward merge:
    • git checkout feature && git rebase main && git checkout main && git merge feature
  • Cherry-pick selected commits onto main:
    • git checkout main && git cherry-pick <commit1> [<commit2> ...]
  1. Delete the local branch
  • Safe delete (only if fully merged): git branch -d feature
  • Force delete (discarding remaining work):
    • Optional backup: git tag backup/feature feature
    • Force delete: git branch -D feature
  1. Delete the remote branch (if applicable)
  • git push origin --delete feature
  • Clean up local stale tracking refs: git fetch -p
  1. Verify cleanup
  • git branch --all --list '*feature*'

When to use each option

  • Merge or squash merge: You want to keep the branch’s work and history (or a condensed form) in the target branch.
  • Cherry-pick: Only some commits are desired.
  • Force delete: You intentionally discard remaining work (back it up first with a tag or note the commit hashes).

Common pitfalls

  • Deleting the checked-out branch: Switch away first (git checkout main).
  • Confusing local vs remote: git branch -d affects local branches only. Remote deletion uses git push origin --delete <name>.
  • Protected branches: Remotes (GitHub/GitLab) may block deletion; adjust protections or use an admin workflow.
  • Orphaned work after force-delete: Without a tag or note of commit IDs, finding the commits later is harder.
  • Assuming PR merge equals Git merge: Squash/rebase merges may create new commit IDs; confirm the target branch truly contains the changes: git log --cherry-pick --oneline main...feature.

Recovery tips (if you deleted too soon)

  • Find the last commit of the deleted branch in the reflog:
    • git reflog | grep feature (or inspect recent entries)
  • Recreate the branch from the commit:
    • git branch feature <commit>
  • If remote was deleted but others still have it, fetch from a peer or the remote’s refs if available.

DevOps considerations

  • CI/CD pipelines: Delete branches after merging to reduce clutter, but only after green pipelines and artifact publication.
  • Branch protection policies: Require reviews/status checks and allow branch deletion only after merge.
  • Automation: In cleanup scripts, check merged status first:
#!/usr/bin/env bash
set -euo pipefail
base=${1:-main}
for b in $(git for-each-ref --format='%(refname:short)' refs/heads/); do
  [[ "$b" == "$base" ]] && continue
  if git merge-base --is-ancestor "$b" "$base"; then
    git branch -d "$b"
  fi
done

Performance notes

  • Large repos: Prefer commit-range operations over full diffs when deciding merge status:
    • git merge-base --is-ancestor feature main is fast and reliable.
  • Fetch pruning: git fetch -p keeps refs lean and speeds up branch listings.
  • Commit-graph: Enable for faster history queries:
    • git config --global core.commitGraph true && git commit-graph write --reachable

FAQ

  • What does “not fully merged” mean?
    • The target branch (usually your current branch) doesn’t contain all commits from the branch you’re deleting.
  • Is -D safe?
    • It force-deletes even if unmerged. Use only after verifying diffs or tagging a backup.
  • Do I need to merge before deleting a remote branch?
    • No. Remotes typically allow deletion regardless of merge state, unless protections apply.
  • How do I check if a branch is merged into a specific target?
    • git merge-base --is-ancestor feature main (exit code 0 means merged).

Series: Git

DevOps