In Git, merging is the process of combining the work from different branches into one branch. It is one of the core features that makes Git so powerful in collaborative environments, allowing multiple developers to work on different features or bug fixes in parallel. Once their work is complete, the changes are merged back into the main branch or another branch, integrating the work done.
In this chapter, we will dive deep into merging Git branches, starting from the basics and gradually moving into advanced topics, ensuring you fully understand the concept and its nuances.
Git merge is a command that integrates changes from one branch into another. It is typically used to combine the work done on a feature branch back into the main or develop branch. Merging brings together two different lines of development, often done after a feature is completed or a bug is fixed.
Imagine two branches: main
and feature
. Over time, they diverge as different commits are added to each branch.
main: A---B---C
\
feature: D---E
When you merge feature
into main
, Git integrates the commits from feature
(D and E) into the main
branch.
There are two primary types of merge operations in Git:
This occurs when there are no new commits on the target branch (e.g., main
) since the branch you’re merging from (e.g., feature
) was created. Git simply moves the pointer forward to the latest commit on the feature branch.
$ git checkout main
$ git merge feature
In this scenario, since there were no new commits on main
after feature
branched off, Git can perform a fast-forward merge:
Before:
main: A---B---C
\
feature: D---E
After Fast-Forward:
main: A---B---C---D---E
The main
branch simply points to the latest commit on the feature
branch, and no merge commit is necessary.
A three-way merge happens when both branches have made new commits since they diverged. Git will create a special “merge commit” that has two parent commits: one from each branch.
$ git checkout main
$ git merge feature
If both main
and feature
have diverged:
Before:
main: A---B---C
\
feature: D---E
After the merge, Git will create a new merge commit, F
, that combines the changes from both branches:
After Three-Way Merge:
main: A---B---C---F
\ /
feature: D---E
The merge commit F
is created by Git to indicate that both main
and feature
have been combined.
Let’s go through the basic steps of performing a merge.
1.Start by making sure you’re on the branch you want to merge into (often main
):
$ git checkout main
2.Pull the latest changes (if collaborating with others):
$ git pull origin main
Now, to merge a feature
branch into main
:
$ git merge feature
If a fast-forward merge is possible, Git will automatically move the main
branch pointer forward. Otherwise, a three-way merge will occur, and a merge commit will be created.
After merging, you can view the commit history to see how the merge was incorporated:
$ git log --oneline --graph
This command gives you a visual representation of how the branches were merged.
Merging branches doesn’t always go smoothly. If both branches modify the same part of a file, Git will be unable to automatically merge them and will mark a conflict.
Let’s assume we have a file called greetings.txt
in both main
and feature
branches:
main
:
Hello, World!
feature
:
Hello, Git!
If you try to merge feature
into main
:
$ git merge feature
Auto-merging greetings.txt
CONFLICT (content): Merge conflict in greetings.txt
Git will mark the file with conflict markers:
<<<<<<< HEAD
Hello, World!
=======
Hello, Git!
>>>>>>> feature
To resolve the conflict, you need to manually edit the file to remove the conflict markers (<<<<<<
, =======
, >>>>>>
). Decide which version (or combination of both) you want to keep.
Hello, Git and World!
Once the conflict is resolved, stage the file and complete the merge:
$ git add greetings.txt
$ git commit
Git will automatically create a merge commit to finalize the process.
Squash merging is a way to combine all the commits from a feature branch into a single commit before merging into the target branch. This helps keep the commit history clean.
$ git checkout main
$ git merge --squash feature
$ git commit -m "Merged feature with squashed commits"
Squash merge compresses the entire branch’s history into one commit:
main: A---B---C---S
Git has several merge strategies. The default one is recursive
, which handles most cases. However, you can specify a different strategy when necessary:
ours
: Favor the current branch’s changes in case of conflicts.theirs
: Favor the incoming branch’s changes in case of conflicts.Example:
$ git merge -s ours feature
While merge conflicts are a normal part of collaboration, they can be minimized with some best practices:
Always pull changes from the main branch into your feature branch before merging:
$ git checkout feature
$ git pull origin main
This ensures your branch is up to date with the latest changes, reducing the chance of conflicts.
Make sure team members are aware of who is working on which parts of the project. Overlapping work increases the chances of conflicts.
Breaking down large changes into smaller, manageable commits helps make merging easier and more transparent.
After successfully merging, it’s a good practice to clean up unused branches. Deleting a branch does not remove the commits; they remain part of the history.
$ git branch -d feature
This deletes the feature
branch from your local repository. To delete a branch from the remote repository, use:
$ git push origin --delete feature
Merging branches is a crucial part of working with Git, especially when collaborating in teams. From simple fast-forward merges to more complex three-way merges with conflict resolution, mastering these techniques ensures smooth integration of code changes.Git provides powerful tools for resolving conflicts and keeping your project history clean and understandable. By following best practices and understanding different merge strategies, you can avoid common pitfalls and become more effective in managing your codebase. Happy coding !❤️