Introduction to Merging
What Will We Learn?
Introduction to Merging in Git and best practices for merging. Learn Merge process and which one to choose between fast forward merge and merge commit.
What is Merging?
In Git, merging is the process of integrating changes from one branch to another. Generally you will integrate changes to your main or master branch from any feature or bugfix branch. This is the general flow not the rule.
Git uses three-way merge to combine or integrate changes. It is three-way because it involves three parties:
- Base Commit (common parent of both source and target branch)
- Commits from Source branch
- Commits from Target branch
How it works is completely different topic for later chapters.
The Merge Process
The following is the general flow of merging.
Identify Source and Target Branches
You need to know which branch to merge into which one. This is the first step. Generally you will merge into main or master branch from feature or bugfix branch.
Apply Merge Command
Switch to the target branch and apply the merge command. Git then start three-way merge process.
git switch master
git merge feature/authHandle Merge Conflicts
Git first tries to integrate changes from feature/auth branch to master branch but if encounters any merge conflict (both branch modifies same line of code) then Git will mark the conflict to that file which you need to handle in order to continue. The process is covered in the seperate chapter.
Finalize the Merge
After you resolve the merge conflicts, you can commit or continue to the ongoing merge process.
Fast-Forward Merge vs. Merge Commit
Either Git applies new merge commit depends on the anatomy of merge and changes made. While both end up with the same version of files, but the commit history looks different.
Fast-Forward Merge
When target branch (main) has no new commits since source branch (feat) was created. Git performs fast-forward merge. For example, for the commit history:
gitGraph
commit id: "A"
commit id: "B"
branch feat
checkout feat
commit id: "C"
You can see the target main branch nas no new commits after the creation of feat branch. In this case, Git can simply apply commit C after B and both main and feat can point to the same commit C. This means history remains linear and no new commit is required. Now the commit history looks like:
gitGraph
commit id: "A"
commit id: "B"
commit id: "C" type: HIGHLIGHT tag: "master, feat"
The highlighed commit C is now pointed by both master and feat branch pointer.
Merge Commit
When both source branch feat and target branch main has new commits since source branch feat was created, Git creates new Merge Commit. For example, for the following history.
gitGraph
commit id: "A"
commit id: "B"
branch feat
checkout feat
commit id: "C"
checkout main
commit id: "D"
You can see both source main branch and target feat has new commits after feat was created at base commit B. feat has committed C since then andmaster has committed D after that. In this scenario, Git can’t create linear history with fast fast-forward merge because:
Neither
Cis the parent ofD. So, Git simply can’t putCbeforeD. The following is impossible:A <- B <- C <- DNor
Dis the parent ofC. So, Git also simply can’t putDbeforeC. Again, the following is impossible:A <- B <- D <- C
Hence, Git must create a new merge commit M with both C and D as it’s parent. Since the target branch is main, it will now point to the merge commit M whereas feat still points C.
gitGraph
commit id: "A"
commit id: "B"
branch feat
checkout feat
commit id: "C" tag: "feat"
checkout main
commit id: "D"
merge feat id: "M" type: HIGHLIGHT tag: "main"
If you visualize this with git log. The syntax is:
git log --all --oneline --decorate --graphYou will see:
* M (HEAD -> main)
|\
| * C (feat)
* | D
|/
* B
* AWhich to Choose?
Use fast-forward when the branch is simple, short-lived, and you don’t need a record that it existed separately — it keeps history linear and clean.
Use a merge commit (--no-ff) when you want to preserve the context of a feature’s development and clearly mark where it was integrated into main.
Tip
In team settings, merge commits are usually preferred since they make it easy to trace and revert entire features. Fast-forward is best for quick fixes or solo work where a clean, simple log matters more than history of branching.
Best practices For Merging
- Pull the latest changes (
git pull) and run tests on the feature branch before merging. - Use
--no-ffto preserve branch history, or rebase for a clean linear history — avoid rebasing shared branches. - Write clear, descriptive merge commit messages (not just “Merge branch ‘feat’”).
- Resolve conflicts carefully and re-run tests after resolving.
- Delete the merged branch and push promptly to keep
mainup to date for others.