Merge a Git feature into main safely

Validate the feature against an updated mainline, follow branch-protection rules, and handle rollback according to the actual integration method.

Best practices
Illustration of Git branches and version history

Validate the combined feature and mainline before updating a shared branch. Resolving conflicts on a feature branch gives you room to review and test, but a fast-forward is not a guarantee that the code is correct.

The commands below use main; substitute master if that is the repository's target branch.

Update and test the feature

Start with a clean working tree. Fetch current refs, then inspect the branch state:

git fetch origin
git switch main
git merge --ff-only origin/main
git switch feature-x
git merge main

This assumes local main should track origin/main; stop and inspect if it has unexpected local commits or divergence. If feature-x is shared, also inspect and integrate its upstream work according to team policy before proceeding.

Resolve any conflicts, stage the files, and finish the merge with git merge --continue. Run the project's actual tests and build against the integrated feature. For a project whose test command is npm-based, that may include npm test; use the commands required by that repository.

Integrate the reviewed result

For a workflow that permits direct local integration, recheck the remote immediately beforehand:

git fetch origin
git switch main
git merge --ff-only origin/main
git merge --ff-only feature-x
git push origin main

If main advanced beyond the tested base, the feature integration may refuse to fast-forward. Update the feature, resolve and test again instead of overriding the refusal. A push can also be rejected because the remote advanced after your fetch.

For protected branches, push the feature and open a pull request or merge request. Require review and CI against the intended integration result. A merge queue or equivalent workflow can help avoid testing against an obsolete base.

Select the history policy

git merge --no-ff feature-x records an explicit merge commit when integration is needed, even if a fast-forward is possible. git merge --squash feature-x prepares the combined changes for a separate single-parent commit; it does not commit automatically. Rebase followed by fast-forward is another option for appropriately coordinated feature history.

Use a consistent team policy that preserves the information reviewers and release tooling need. None of these flags removes the need for tests.

Roll back the actual integration

If a local unpublished integration needs to be discarded, preserve any needed work and reset to a verified pre-integration ref. origin/main is only suitable if it still points to the intended boundary; do not assume that blindly.

For a published two-parent merge, inspect the parent order and use a reviewed git revert -m 1 MERGE_COMMIT when parent one is the desired mainline. A squash commit is an ordinary commit and uses ordinary revert. A fast-forward creates no merge commit, so reverse the selected feature commits or prepare a focused corrective change instead.

See git-merge, git-push, and git-revert.

Get a tailored plan

Contact us

Join the community

Scan with WeChat
to join the community

Try Guance

Start online and pay only for what you use.

Get started

Choose a Guance plan

Code hosting