Merge: What is a Merge in Git?
Définition
A merge in Git is the operation that combines the changes from two branches into one. It is the mechanism by which work done on a development branch is integrated into the project's main branch.What is a Git Merge?
A merge is a fundamental Git operation that combines the history of two branches into one. When a developer has completed their work on a feature branch, the merge is the final step that integrates their changes into the main branch (often main or develop). It is the convergence point where individual work joins the common project.
Git is designed to facilitate parallel work through branches. The merge is the complementary mechanism that reconciles this parallel work. The git merge command analyzes the differences between the two branches, identifies compatible changes, and combines them automatically. When changes affect the same lines of code, a merge conflict occurs and requires human intervention.
At KERN-IT, merging is closely tied to our pull request process. Every merge into the main branch is preceded by a code review and automated test validation, ensuring that only quality code reaches the common trunk.
Why Merge Matters
The merge is the operation that gives branching its full meaning. Without it, branches would be dead ends: isolated code that would never rejoin the main project.
- Team work integration: the merge is when individual contributions come together. It is the keystone of collaboration in a Git project.
- History preservation: unlike some destructive operations, merging preserves the complete history of both branches. Every commit remains traceable.
- Feature delivery: in a Gitflow or GitHub Flow workflow, merging a feature branch into main marks the official delivery of a feature.
- Divergence resolution: when two developers have modified the same code in parallel, the merge is the reconciliation point where differences are resolved explicitly.
How It Works
Git offers two main types of merge. The fast-forward merge is the simplest case: it occurs when the target branch has not received any new commits since the source branch was created. Git simply moves the target branch pointer to the latest commit of the source branch, without creating an additional merge commit.
The three-way merge is necessary when both branches have diverged (each contains commits the other does not have). Git then identifies the common ancestor commit of both branches and creates a new merge commit that combines changes from both sides. This merge commit has two parents, creating a diamond-shaped structure in the history graph.
Conflict resolution is the most delicate aspect of merging. A conflict occurs when both branches have modified the same lines in the same file. Git marks the conflicting areas in the file with special markers (<<<<<<<, =======, >>>>>>>) and asks the developer to manually choose which version to keep or combine both.
Merge vs Rebase
Rebase is an alternative to merge that produces a linear history. Instead of creating a merge commit, git rebase replays the commits of one branch on top of another. The result is a cleaner history, but the operation rewrites commits, which can cause issues on shared branches.
The golden rule is simple: use rebase for local, unshared branches and merge for integrating branches into the common trunk. At KERN-IT, we combine both: local rebase to clean up history before creating the PR, then squash merge for the final integration.
Concrete Example
Two KERN-IT developers are working simultaneously on the same project. The first is developing a new reporting module on the branch feature/reporting, while the second is fixing bugs on fix/data-validation. The fix is merged first into main via a pull request.
When the reporting module developer creates their pull request, GitHub detects a conflict: both developers modified the same model file. The developer fetches the latest changes from main, resolves the conflict by keeping their colleague's corrections while adding their new fields, and pushes the resolution. The PR is then merged without issues.
Best Practices
- Merge main into your branches frequently: regularly pull the latest changes from the main branch to limit conflicts during the final merge.
- Resolve conflicts carefully: take the time to understand both versions of the code before resolving a conflict. A poorly resolved conflict introduces subtle, hard-to-trace bugs.
- Use squash merge for feature branches: this produces a clean history in main with one commit per feature.
- Never force a merge: if Git reports conflicts, resolve them properly rather than forcing the merge.
- Test after merging: even if CI tests pass, perform a quick manual test to verify the integration works as expected.
Conclusion
The merge is the moment of truth in the Git development workflow. It is the operation that transforms parallel work into a coherent project. Well mastered, it enables smooth collaboration and a clear project history. Poorly managed, it can introduce regressions and confusion. The key is to adopt consistent merge practices within the team and rely on automation tools to ensure quality at every integration.
Before merging a long-lived branch, merge main into your feature branch first (not the other way around). This lets you resolve conflicts in your branch, verify everything works, then create a clean PR. This avoids polluting main with hasty conflict resolutions.