Start from the same branch graph
Git merge vs rebase is a choice between two ways of doing the same job: bringing the work of one branch into another. Atlassian’s comparison says it plainly, and the difference is in how they record it.
The repository is a throwaway named orbit-api. The branch feature/search has two commits, and main moved on with one commit of its own:
git log --oneline --graph --decorate --all
* 1ca9117 (HEAD -> main) docs: list the health route
| * aa029c4 (feature/search) feat: add search filters
| * 47fee04 feat: add search endpoint
|/
* b65211d chore: init orbit-api
The two branches have diverged. I copied the folder so that each command starts from this state. Your IDs will differ.
What merge preserves and rebase rewrites
In the first copy, merge feature/search into main. A fast-forward is impossible because main has a commit that the feature branch lacks, and --ff-only confirms it:
git merge --ff-only feature/search
fatal: Not possible to fast-forward, aborting.
A plain merge creates a merge commit (I added --no-edit to accept the proposed message):
git merge --no-edit feature/search
git log --oneline --graph --decorate
* 6f9924d (HEAD -> main) Merge branch 'feature/search'
|\
| * aa029c4 (feature/search) feat: add search filters
| * 47fee04 feat: add search endpoint
* | 1ca9117 docs: list the health route
|/
* b65211d chore: init orbit-api
Nothing was rewritten: aa029c4 and 47fee04 keep their IDs, and the new commit 6f9924d has two parents. The history records that two lines of work joined.
In the second copy, rebase the feature branch onto main:
git checkout feature/search
git rebase main
git log --oneline --graph --decorate
* 4818ca2 (HEAD -> feature/search) feat: add search filters
* eac743c feat: add search endpoint
* 1ca9117 (main) docs: list the health route
* b65211d chore: init orbit-api
The history is a straight line, but the two feature commits are new: 47fee04 became eac743c and aa029c4 became 4818ca2. Git replayed them on top of main. Because main has not moved since, bringing the branch in is now a fast-forward: main just advances to 4818ca2, with no new commit.
git checkout main
git merge --ff-only feature/search
Updating 1ca9117..4818ca2
Fast-forward
…
To keep a merge commit even when a fast-forward is possible, --no-ff forces one. In a third copy, taken right after the rebase, git merge --no-edit --no-ff feature/search run from main gives this:
* 2d2cbf4 (HEAD -> main) Merge branch 'feature/search'
|\
| * 4818ca2 (feature/search) feat: add search filters
| * eac743c feat: add search endpoint
|/
* 1ca9117 docs: list the health route
* b65211d chore: init orbit-api
In all three copies, git rev-parse main^{tree} printed c13fa637a85f3cb7cf1f47de226e6808b388e8b5. The files are identical. Only the history differs.
Choose for the branch and collaborators
The rule that matters is the “golden rule of rebasing” in Atlassian’s comparison: never rebase a public branch. A rebase gives your commits new IDs, so anyone who already has the old ones ends up with a diverged copy. Pro Git advises against including commits already pushed to a central server, and the git-rebase documentation adds that rewriting a branch others built on forces them to fix their history by hand.
| Situation | Prefer | Why |
|---|---|---|
| A feature branch only you use | Rebase, then fast-forward | Linear history, no merge commit |
| A branch teammates pulled | Merge | Existing commits keep their IDs |
main or another shared branch |
Merge, never rebase | Others already depend on it |
| You want to date the integration of a feature | Merge with --no-ff |
The merge commit marks the moment |
Atlassian names the trade-off: a rebase gives a cleaner history but loses the context a merge commit provides. If your team has a convention, follow it. To tidy your own commits before either operation, use the interactive rebase.
In GitMini, you right-click a branch other than the one that is checked out:
- With
mainchecked out, Merge “feature/search” in “main” opens a Merge dialog. It offers Fast forward if possible, Always create a merge commit and Fast-forward only, which is disabled with “impossible: branches have diverged” when a fast-forward cannot happen. - With
feature/searchchecked out, Rebase feature/search on main opens a Rebase dialog that says “2 commits of “feature/search” will be replayed on “main” (1ca9117)”.
Dragging a branch onto another in the graph opens a small menu: the rebase, labeled “feature/search on main”, and Merge feature/search in main when the target is the checked-out branch.
The rebase dialog shows warnings. A commit already on a remote shows Already pushed, with “A force push (with lease) will be required and may affect your collaborators.” A range that contains merge commits shows “1 merge commit will be linearized.” Rebasing main or master requires ticking “I want to rebase the default branch “main””.
Check conflicts and the resulting history
Conflicts behave differently. In a variant where main and the feature branch both edit the same line of README.md, a merge stops once:
Auto-merging README.md
CONFLICT (content): Merge conflict in README.md
Automatic merge failed; fix conflicts and then commit the result.
A rebase of the same branch stops on the first commit that conflicts, here the first of two:
Auto-merging README.md
CONFLICT (content): Merge conflict in README.md
error: could not apply 7e264ce... docs: announce the search route
…
These outputs come from Git 2.30; Git 2.54 adds a hint: block to the --ff-only refusal and prefixes the conflict advice with hint:. A rebase replays commits one by one, so it can stop again later: when both feature commits edited that same line, it stopped a second time, on the second commit, after I resolved the first stop. In both cases, git merge --abort or git rebase --abort brings you back to the state before the command.
GitMini shows the same stop as a banner. For a merge it reads “Merge feature/search into main” with the number of files in conflict, and Finish the merge is enabled once the files are staged. For a rebase it offers Continue, Skip and Abort. The interactive rebase guide walks through this case.
Finish by reading the result. git log --oneline --graph --decorate --all shows whether you have a loop, as after the merge, or a line, as after the rebase. The graph reading guide explains how to follow it.
Sources
- Atlassian: merging vs. rebasing (French page) and English page, consulted on October 4, 2026.
- Pro Git: Rewriting History, consulted on October 4, 2026.
- Git documentation: git-merge, consulted on October 4, 2026.
- Git documentation: git-rebase, consulted on October 4, 2026.
- GitMini product README, consulted on October 4, 2026.