What "linear" means
A linear history has no merge commits - every commit has exactly one parent, and the history is a single line from the initial commit to HEAD. Bisect runs cleanly, blame is unambiguous, and git log reads top-to-bottom like a chronological narrative.
Why linear matters
Each merge commit complicates blame, bisect, and revert. With a linear history:
git bisectwalks one path, not a graph.git log --onelinetells the truth without--graph.git reverttargets a single commit cleanly.- Reviewers see one logical change per commit.
Achieving linearity locally
Always rebase your feature branch onto main before merging:
git checkout feature/login
git fetch origin
git rebase origin/main
git push --force-with-lease
Enforcing on the remote
Configure your Git host to require linear history. On GitHub: branch protection rules → "Require linear history". This rejects merge commits at push time.
Three integration strategies preserve linearity:
- Rebase and merge - replays branch commits onto main individually.
- Squash and merge - flattens the branch to a single commit on main.
- Fast-forward only - requires the branch to already be up-to-date.
Local enforcement
Configure pull to rebase by default:
git config --global pull.rebase true
git config --global pull.ff only
git config --global rebase.autoStash true
pull.ff only refuses any pull that would create a merge commit, forcing you to rebase explicitly.
The trade-off
Linearity comes at a cost: rebase rewrites SHAs. If your team relies on stable SHAs (some compliance environments do), or if you want a literal record of when branches diverged and merged, linear may not fit. Decide once, document it, and stick with it.
Squash vs rebase merge
# Squash and merge: 1 commit on main per PR
git merge --squash feature/login
git commit -m "Add OAuth login"
# Rebase and merge: every commit on main
git rebase main feature/login
git checkout main
git merge --ff-only feature/login
Squash is simpler and produces a clean main; rebase preserves atomic commit detail. Most teams pick squash for app code and rebase for libraries where commit-level detail matters.
Detecting non-linear history
git log --merges
# Any output means you have merge commits.
git log --first-parent --oneline
--first-parent traces only the trunk, useful for release notes even on non-linear histories.
Pick a merging policy, enforce it in branch protection, and your history will stay readable for years.