Merge is an operation in Git that combines changes from one branch into another, creating a merge commit. Git supports several strategies: fast-forward (linear history), three-way merge (with a merge commit) and squash merge (compressing all commits into one). According to git-scm.com, 2025, merge remains the most used code integration mechanism in team Git development.
Key Takeaways
Merge is a fundamental operation in Git that combines changes from one branch (source) into another (target). As a result of merging, the target branch receives all commits from the source branch that were not yet in it. Depending on the situation, Git can perform a merge in three different ways.
The main value of merge is preserving history: a merge commit records the fact of branch merging, preserving information about when and which branches were merged. This facilitates change auditing, regression searching, and understanding development chronology. In large projects, merge commit is the standard way of code integration.
According to GitLab Flow, merge commits are used in 73% of teams working with Git. Alternative approaches (rebase, squash) are preferred by teams focused on linear history. The choice of strategy depends on team size, release frequency and accepted project conventions.
Merge is required when a developer has finished working on a feature and wants to integrate it into develop or main. A typical scenario: a developer created a feature branch from develop, worked on it for several days, and during that time new commits from other team members appeared in develop. Before merging, the changes need to be combined — and merge is used for this.
Without merge, it is impossible to collaboratively work on a single codebase in Git. Every time two developers simultaneously make changes to one codebase, their branches diverge. Merge is the only way to bring these changes back together without data loss.
Git supports three types of merge, each designed for its own scenario. The choice of merge type affects commit history, rollback convenience, and log readability.
Fast-forward occurs when the target branch has had no new commits since the source branch was created. In this case, Git simply moves the target branch pointer forward to the last commit of the source branch. The history remains linear, without a merge commit.
# Fast-forward merge: develop hasn’t changed since feature creation
git checkout develop
git merge feature/new-login
# Result: the develop pointer moved to the end of feature
# No merge commit was created
Fast-forward is convenient for short-lived branches where a developer worked alone. But this approach has a drawback: information that the branch existed is lost — all commits look as if they were made directly to develop.
Three-way merge is performed when both branches have new commits after the point of divergence. Git creates a separate merge commit with two parents, which records the fact of branch merging. This approach is recommended for feature branches in team development.
# Forced three-way merge with --no-ff flag
git checkout develop
git merge --no-ff feature/new-login
# A merge commit was created with the default message
# You can set your own message via -m
git merge --no-ff feature/new-login -m "Merge feature/new-login into develop"
The --no-ff flag guarantees the creation of a merge commit, even if fast-forward is possible. This is a best practice for preserving branching information in a project.
Squash merge compresses all commits of the source branch into one and applies it to the target. The feature history is lost — one commit with all changes ends up in the branch. This is convenient when detailed commits in a feature branch do not add value to the overall history.
# Squash merge: all feature commits are squashed into one
git checkout develop
git merge --squash feature/experimental
git commit -m "feat: experimental login flow (squashed)"
Squash is suitable for drafts, experimental branches, and situations where it is important to maintain a clean history. The downside is that the connection to the original commits is lost, making it harder to roll back individual changes.
Ours and Theirs are two special merge strategies in Git. Ours completely ignores changes from the source branch, keeping only what is in the target. Theirs, on the contrary, accepts the source branch version in any conflict. These strategies are useful when merging large amounts of code when it is known in advance which version should prevail.
The merge mechanism in Git is based on comparing three points: the common ancestor (merge base), the state of the source branch, and the state of the target branch. Git finds the merge base — the last commit common to both branches — and calculates what changes occurred in each branch after divergence.
Git uses a three-way merge algorithm that considers not only the two compared file versions, but also their common ancestor. Thanks to this, Git can automatically resolve situations where changes in one branch do not affect modified areas of the other — even if both files were modified.
Consider a scenario: two developers are working on different files in one feature branch. The first changed LoginActivity.kt, the second changed ProfileFragment.kt. When they merge their changes, Git sees that the changes affected different files and performs the merge automatically, without human intervention.
If both developers changed LoginActivity.kt, but in different methods — Git will also handle it automatically, merging changes line by line. A conflict only occurs if both changed the same lines or if one deleted code that the other changed.
A merge conflict occurs when Git cannot automatically merge changes because both branches modified the same lines differently. In this case, Git marks the conflicting areas in files and awaits manual resolution from the developer.
Conflict areas are marked with special markers: <<<<<<< HEAD shows code from the target branch, ======= is the separator, >>>>>>> source-branch shows code from the source branch. The developer must manually choose which version to keep or combine them.
# 1. Run merge and see the conflict
git merge feature/new-login
# Output: CONFLICT (content): Merge conflict in LoginActivity.kt
# 2. View the list of files with conflicts
git status
# both modified: src/ui/login/LoginActivity.kt
# 3. Resolve the conflict: edit the file, remove markers
# 4. Add the resolved file and finish the merge
git add src/ui/login/LoginActivity.kt
git merge --continue
# or: git commit (without --continue)
There are tools for resolving conflicts: git mergetool opens a visual merger (Meld, Beyond Compare, VS Code). Many developers prefer to resolve conflicts in the IDE — IntelliJ IDEA and Android Studio provide a built-in tool with three-panel comparison that greatly simplifies this process.
Tips for resolving conflicts: always understand what each side of the conflict does, do not delete someone else’s code without understanding its logic, and if the conflict is too complex — involve the authors of both branches in a joint resolution.
The choice between Merge and Rebase is one of the most common architectural decisions in Git. Both approaches combine changes, but do it differently: merge preserves branching history, rebase rewrites history making it linear.
Many teams use a hybrid approach: rebase to bring the feature branch up to date with develop (git rebase develop), then merge with the --no-ff flag to record the merge. This gives a clean history within the feature and informative merge points at the develop level.
Frequently Asked Questions
Without --no-ff Git performs a fast-forward merge if possible — it simply moves the branch pointer. With --no-ff Git always creates a merge commit, preserving branching information. Recommended for feature branches in team development.
Use git mergetool or a built-in IDE tool. If the conflict involves dozens of files — the branches may have diverged too much. In this case, discuss the merge plan with the team, possibly splitting it into several stages.
Yes: git merge --abort cancels the merge if it has not yet completed (conflict). If the merge is already complete — use git reset --hard HEAD~1 or git revert -m 1 <merge-commit> for a safe rollback.
Recommended for teamwork. A merge commit records the merge fact, contains references to both branches, and simplifies history understanding. For personal or experimental branches, squash merge or fast-forward is acceptable.
Git cannot automatically merge binary files — it selects one version entirely. For binary files (images, .aab, .apk) it is recommended to minimize parallel changes and use Git LFS for large files.
Summary
We will develop a mobile application turnkey
IT Sectr creates iOS and Android applications for startups and businesses since 2017. We will advise you and propose the best solution.
Read also