import DefinitionCard from "@site/src/components/DefinitionCard";

# Merge vs Rebase

_Merge joins histories. Rebase recreates commits on a different base._

## Introduction

`git merge` and `git rebase` can bring a feature branch up to date or prepare it for integration. Merge preserves the existing commits and records how two histories joined. Rebase replaces one line of commits so it begins at a different point.

The choice affects history and collaboration. It does not change whether the final files can be correct.

## Understanding the Concept

A **merge commit** has two or more parents. For a typical two-branch merge, the first parent is the previous tip of the current branch and the second parent is the tip being merged. Existing commits keep their object IDs.

A **rebase** computes patches from commits on the current branch, applies them to a new base in order, and moves the branch ref to the new commits. Their object IDs change because their parent history changes.

| | Merge | Rebase |
| --- | --- | --- |
| Existing commits | Preserved | Replayed commits are replaced |
| History | Retains branch topology | Produces a linearized branch |
| Collaboration | Safe for shared history | Requires coordination after sharing |
| Conflicts | Usually resolved in one merge result | Can recur as each commit is replayed |
| Integration record | Merge commit when not fast-forwarded | No integration commit from rebase itself |

A merge may fast-forward when the current branch is an ancestor of the branch being merged. In that case Git moves the branch ref and creates no merge commit. Use `--no-ff` when the project requires an explicit integration commit.

## Applying It in Practice

Merge `main` into a shared feature branch without rewriting its commits:

```bash
git fetch origin
git switch feature/my-work
git merge origin/main
```

Rebase a private feature branch onto current `main`:

```bash
git fetch origin
git switch feature/my-work
git rebase origin/main
```

If that branch already exists on a remote and its rewrite is agreed, update it with:

```bash
git push --force-with-lease origin feature/my-work
```

Integrate a branch with an explicit merge commit:

```bash
git switch main
git merge --no-ff feature/my-work
```

A squash merge creates one new commit containing the branch's combined file changes. It does not create a merge commit, so Git does not record the feature branch as a parent:

```bash
git switch main
git merge --squash feature/my-work
git commit -m "Add user authentication"
```

Hosting platforms also offer rebase-and-merge. That option replays pull-request commits onto the target branch and usually creates new object IDs. Check the platform's exact behavior before making policy depend on it.

## Engineering Considerations

Merge is the conservative choice for shared branches because it does not replace commits. The graph records both the development history and the integration event. First-parent logs can show the sequence of changes merged into `main` without expanding every side branch:

```bash
git log --first-parent --oneline main
```

Rebase is useful for reorganizing private work and for moving a branch onto its intended base. A linear history can be easier to scan, but it removes the original branch topology. Do not rewrite commits that colleagues have based work on unless everyone coordinates the recovery.

`git bisect` works on both linear and merged histories. Merge commits can make a regression harder to interpret when neither parent alone reproduces the merged result, while a squash can hide which internal step introduced the bug. History quality depends more on buildable, focused commits than on graph shape alone.

`git blame` also works across merges. Options such as `-M` and `-C` help detect moved or copied lines. Rebase does not automatically make blame more accurate.

## Scaling and Operations

Set one integration policy for each protected branch. Common choices are:

- merge commits for an explicit first-parent release history
- squash merges for one target-branch commit per pull request
- rebase-and-merge for preserving individual pull-request commits in a linear history

Each choice discards different information. Merge commits retain topology. Squash merges retain the final combined change but not the branch's commit boundaries. Rebase-and-merge retains boundaries but replaces commit identities.

Protect shared branches from force pushes. If feature branches are rewriteable, make that policy explicit so reviewers know whether to build dependent work on them.

Use `git range-diff` after a substantial rebase to verify that the rewritten series still represents the intended patches. Run the full test suite after conflict resolution, regardless of strategy.

## Next Steps

- [Cherry-pick vs Rebase](./cherry-pick-vs-rebase): distinguish selected patch copying from branch rewriting
- [What are Stacked PRs?](./stacked-prs): manage branches that depend on one another
- [Stacked PR Workflow](/learn/workflows/git/stacked-pr): apply rebasing to a pull-request stack
- [Parallel Development Workflow](/learn/workflows/git/parallel-development): combine integration policy with concurrent branch work
