Merge commit, squash or rebase?
↑What does “Choose a branch to merge into XXX” mean?
Section titled “What does “Choose a branch to merge into XXX” mean?”XXX is the destination, usually your currently checked-out local branch. The branch you select is the source. If you are on feature/inventory and select main, you bring main’s changes into your feature branch. To deliver the feature into main, the destination must instead be main.
Check the destination, source, preview and selected method before confirming. A local operation changes your local repository; it does not by itself push, create a PR/MR, grant approvals or deploy anything. A later push can trigger deployment if the repository is configured that way.
In the pictured menu, Create a merge commit, Squash and merge and Rebase describe ways to combine history. Rebase dialogs vary: GitHub Desktop’s separate Rebase Current Branch action replays the current branch onto a selected base. Read the preview rather than assuming every rebase action has the same direction.
main is an example name; substitute master or your real target. See Git terminology.
Quick choice
Section titled “Quick choice”| Method | What happens | Advantages | Costs / when to avoid it |
|---|---|---|---|
| Create a merge commit | Joins both histories with a commit that has two parents | Keeps original commit IDs and an explicit integration boundary; useful for shared or long-lived branches | Extra merge commits and a busier graph; conflicts still need resolution |
| Squash and merge | Records the source’s combined changes as one new commit on the destination | One logical feature/fix is easy to scan and usually easy to revert | Individual steps and original ancestry are absent from destination history; poor for repeatedly syncing a long-lived branch |
| Rebase / rebase and merge | Replays commits onto a new base, usually with new IDs; integration can then fast-forward | A linear sequence retains separate, meaningful steps | Rewrites the replayed history; conflicts may recur per commit; needs coordination if others use those commits |
Practical starting point: use a reviewed PR/MR with squash for one feature containing noisy work-in-progress commits. Keep merge commits when shared ancestry or integration boundaries matter. Choose rebase for a deliberately organized sequence when your team accepts rewriting those commits. Repository rules take precedence over personal graph preferences.
One starting history, three outcomes
Section titled “One starting history, three outcomes”These are alternative outcomes, not three operations to run in sequence. Letters are commit IDs; D' and E' mean replacement commits.
A---B---C main (destination) \ D---E feature/inventory (source)1. Create a merge commit
Section titled “1. Create a merge commit”A---B---C---M main \ / D------E feature/inventoryBoth lines of work remain visible. M records their combined result, including any conflict resolutions. D and E keep their IDs and become ancestors of main.
Choose it when: two people share the source branch, you regularly integrate between long-lived branches, or you want to see when a feature entered the destination. It also preserves a useful series of source commits without rewriting them.
Trade-offs: frequent updates can clutter the graph. Reverting a merge requires choosing the mainline parent; it is not equivalent to reverting an ordinary single-parent commit. A merge commit is a history boundary, not proof of review.
A plain git merge may fast-forward when the destination has no separate work: only its branch pointer advances. --no-ff requests an explicit merge boundary when there are changes to integrate. An already integrated branch may still produce no new commit.
2. Squash and merge
Section titled “2. Squash and merge”A---B---C---S main \ D---E feature/inventory (original source)S is a new commit representing the integrated changes. D and E remain on the source branch but are not added as ancestors of main through S. Squashing does not erase them everywhere or delete the branch automatically.
Choose it when: one completed feature has commits such as “add UI”, “fix typo” and “address review”. Give S a message describing the finished change, why it exists and the linked PR/MR.
Trade-offs: destination history loses the individual steps, making commit-by-commit investigation less detailed. Contributor attribution needs care in the final message. Reverting S reverses the combined change, although later edits can still cause conflicts.
After integration, start new work from the updated destination. Reusing the same source for repeated squash merges can show old commits again and cause repeated conflicts because the ancestry was not joined. Avoid squashing main into a long-lived feature branch merely to bring it up to date.
3. Rebase, then integrate
Section titled “3. Rebase, then integrate”A---B---C---D'---E' mainD’ and E’ reproduce the changes on a different parent chain. For this divergent history they have new IDs; main’s existing A/B/C history stays intact. The source branch’s exact final pointer depends on whether you rebased it locally or used a hosting service’s merge action.
Choose it when: each commit is understandable and useful on its own, you want linear history, and you control the branch being rewritten. Updating your own unpublished feature branch before review is a common case.
Trade-offs: the same area may conflict while replaying several commits. Existing links, signatures and collaborators’ branches can refer to the old IDs. Ordinary rebase also does not preserve merge topology by default. It neither runs tests nor guarantees that the replayed result still behaves correctly.
Local git rebase rewrites the branch being rebased; it does not itself merge that branch back into the target. A fast-forward integration is a separate step. GitHub’s web Rebase and merge does that integration and always creates replacement commit IDs, even in cases where a local rebase could be a no-op. Never rebase shared main just to make its graph prettier.
Is a PR an alternative to these methods?
Section titled “Is a PR an alternative to these methods?”A pull request (PR) on GitHub or merge request (MR) on GitLab is the collaboration workflow around a proposed integration. You can approve a PR/MR and still select a merge commit, squash or a linear integration according to the host’s settings.
| Route | What you gain | What you must handle |
|---|---|---|
| Local branch integration | Quick offline experiments; update your own feature branch; try combined changes before requesting review | Run tests yourself; no review record or server-side merge gate is created by the local action |
| PR/MR integration | A proposed diff, discussion, review record, issue links and CI results; configured rules can enforce checks | Publish the branch, wait for required checks/review, and choose an allowed history method |
Use a PR/MR for shared integration branches when review, team coordination, an audit trail or required checks matter. Solo work can benefit too: a draft request keeps the diff, reasoning and CI results together.
Use a local merge/rebase to update your own branch, combine unpublished experiments, or inspect an integration in a temporary branch. A direct integration and push can be reasonable for a small solo repository when its policy allows it and you perform the required checks yourself. It trades away the PR/MR’s review checkpoint; it does not make merging technically safer or automatically test anything.
Branch protections may reject direct pushes, require a particular history shape or require a PR/MR. A locally successful merge does not override those rules. A PR/MR also needs actual configured checks/reviews; merely opening one does not ensure quality.
GitLab detail: merge method and squashing are separate project settings. An MR can produce a squash commit and a merge commit. GitLab’s merge commit, semi-linear and fast-forward policies do not map one-to-one to every GitHub/Desktop button. Inspect the project’s settings and resulting history.
Two different jobs people confuse
Section titled “Two different jobs people confuse”| Your goal | Destination / current branch | Source / base | Usual approach |
|---|---|---|---|
| Bring the latest main into my feature | Your feature branch | Updated main | Merge main into a shared feature branch, or rebase a private feature onto main |
| Deliver my finished feature | main or the release branch | Your feature | Open a PR/MR and choose the allowed integration method |
| Try two features together without publishing | A temporary integration branch | Each feature branch | Local merges, test, then keep or discard that temporary branch deliberately |
For a shared feature branch, merging main in avoids changing existing commit IDs. Rebasing an already published feature may require a force update of that feature branch. Coordinate first; do not force-push protected main. A lease can reject an unexpected remote tip, but it does not replace communication.
CLI equivalents in a practice repository
Section titled “CLI equivalents in a practice repository”The following Git commands work in PowerShell or Git Bash on Windows 10/11, and Bash on Linux, with Git installed. They use no shell-specific variable assignment. GUI availability differs: official GitHub Desktop supports Windows/macOS; Linux users can follow the CLI.
Use a disposable repository with an existing integration-demo destination and feature/inventory source matching the starting graph. Choose one alternative from that starting point. These snippets do not push.
git switch integration-demogit merge --no-ff feature/inventorygit switch integration-demogit merge --squash feature/inventorygit diff --cachedgit commit -m "Add inventory filtering"git switch feature/inventorygit rebase integration-demogit switch integration-demogit merge --ff-only feature/inventoryFor squash, inspect the staged diff and run the project’s checks before committing. For all methods, test the final result before sharing it. Afterward, inspect git log --graph --oneline --decorate --all and git status.
If a normal merge stops with conflicts, resolve and stage the affected files before completing it, or use git merge --abort while that merge is in progress. For rebase, resolve/stage and use git rebase --continue, or git rebase --abort. A squash merge does not set up the same merge state: do not assume merge-abort will undo its staged changes. See conflicts and recovery and inspect your state before discarding anything.
Check your understanding
Section titled “Check your understanding”You have eight “WIP/fix” commits for one bug fix. It needs review before entering main. What should you choose?
- A local merge to bypass review.
- A PR/MR, then squash if repository policy permits it.
- Rebase shared main onto the feature.
Answer: 2. The request supplies the review workflow, and squash records one finished fix. If instead those eight commits are a meaningful series that must keep its ancestry, choose a merge commit; if you need the series in linear history and rewriting is acceptable, consider rebase.
