Understanding Git Merging: A Developer’s Guide to Bringing Code Together
When working on software projects with Git, collaboration and experimentation often lead to multiple branches—each representing a new feature, bug fix, or improvement. At some point, all this separate work needs to come back together. That’s where merging comes in.
What is Merging in Git?
In simple terms, merging means combining changes from one branch into another. It's how you integrate different lines of development. Whether you've been working on a new feature or fixing a bug in a separate branch, merging helps bring that work back into the main codebase—typically the main or develop branch.
Merging is a core part of Git's workflow, especially in collaborative teams where multiple developers contribute simultaneously.
Why Use Git Merge?
- Merging is essential because it:
- Keeps development organized
- Prevents conflicts from snowballing
- Helps track the history of changes
- Enables multiple developers to work independently and still stay in sync
Once your feature or fix is complete, merging lets you consolidate your work into the main branch without losing the commit history.
Merging Branches with git merge: A Practical Example
When you're ready to bring changes from one branch into another, the go-to Git command is git merge. This is a fundamental part of version control that helps integrate completed work—like a bug fix or feature—back into the main project line.
Step-by-Step: How to Merge Branches in Git
Let’s walk through a simple, real-world example to show how merging works.
1. Switch to the Target Branch
Before merging, you need to make sure you're on the branch that should receive the changes. Most often, this is your main development branch—usually called main or master.
git checkout master
Output:
Switched to branch 'master'
Now you're on the master branch and ready to merge changes from another branch.
2. Run the Merge Command
Let’s say you've been working on a critical bug fix in a branch called emergency-fix. To bring those changes into master, you'd run:
git merge emergency-fix
Example Output:
Updating 09f4acd..dfa79db
Fast-forward
index.html | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
Fast-Forward Merge Explained
In this example, Git performed a fast-forward merge. This happens when the branch you're merging into (master) hasn't had any new commits since the emergency-fix branch was created. Git recognizes this as a linear continuation of the project history and simply "fast-forwards" the master branch pointer to the latest commit on emergency-fix.
In other words, no new merge commit is needed because the history already lines up cleanly.
Summary
- Use git checkout to switch to the target branch.
- Use git merge <branch-name> to bring in changes.
- Git will choose the best strategy—like fast-forward—based on the commit history.
This type of clean, linear merging keeps your Git history simple and easy to follow. But in more complex scenarios where branches have diverged, Git might need to create a merge commit to preserve both histories.
Non-Fast-Forward Merge (git merge --no-ff) Made Simple
By default, when Git merges two branches and no new changes have been made on the main branch, it does a fast-forward merge. This means Git just moves the pointer forward to include the new commits—no extra merge commit is created.But What If You Want a Clearer History?
Sometimes, you might want to always create a merge commit—even if a fast-forward is possible. This helps make your project history easier to understand, especially when looking back to see when and why a feature was added.To do that, use the --no-ff option:
git merge --no-ff feature-branch
Example Output:
Merge made by the 'recursive' strategy.index.html | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
This creates a merge commit, even if Git could have fast-forwarded. That way, it’s clear in your Git history that a separate branch was merged.
Why Use --no-ff?
- Keeps a record of all feature merges
- Makes the commit history easier to follow
- Useful for teams or long-term projects
Squash Merge (git merge --squash)
If you want to bring in all the changes from another branch as a single, clean commit—without keeping its individual commits—you can use:
git merge --squash branchname
This is helpful when you want to simplify your project’s history.
Example:
git merge --squash feature-branch
Git will apply the changes and stage them for commit, but it won’t create a merge commit automatically.
You’ll see a message like:
Squash commit -- not updating HEAD
Automatic merge went well; stopped before committing as requested
Then, you finish by creating your single commit:
git commit -m "Add feature from feature-branch"
Aborting a Merge (git merge --abort)
If you start a merge and run into problems—such as conflicts you’d rather not resolve—you can stop the merge and return your branch to its previous state by running:
git merge --abort
Example:
git merge --abort
This cancels the merge in progress and resets your working directory and staging area to how they were before the merge started.
What is a Merge Conflict?
A merge conflict occurs when changes from two branches affect the same part of a file, and Git can’t automatically decide which version to keep.
It’s like two people editing the same sentence differently—Git needs you to review and choose the correct version to complete the merge.
How to Resolve a Merge Conflict
When a conflict happens, Git marks the conflicting parts in your files with special markers like <<<<<<< HEAD, =======, and >>>>>>> branch-name.
To fix it:
- Open the file and review the conflicting sections.
- Edit the file to keep the changes you want and remove the conflict markers.
- Once resolved, stage the file:
git add filename
4.Then commit the changes to complete the merge:
git commit
Troubleshooting & Tips
- To cancel a merge in progress, run:
git merge --abort
- Before starting a merge, always commit or stash any uncommitted changes to avoid conflicts.
- When resolving conflicts, carefully read and remove all conflict markers (<<<<<<<, =======, >>>>>>>).
- Use git status to check which files still need to be resolved.
If you’re unsure how to fix a conflict or error, ask a teammate or search for the specific message online for guidance.
Merge Conflict Example
Let’s switch back to the hello-world-images branch from the previous chapter to continue working.
Next, add a new image file (img_hello_git.jpg) and update index.html to display it.
Example:
git checkout hello-world-images
Switched to branch 'hello-world-images'
Merge Conflict Example
Let’s switch to the hello-world-images branch to keep working:
git checkout hello-world-images
Switched to branch 'hello-world-images'
Now, add a new image file (img_hello_git.jpg) and update index.html to show it:
Example index.html:
<!DOCTYPE html>
<html>
<head>
<title>Hello World!</title>
<link rel="stylesheet" href="bluestyle.css">
</head>
<body>
<h1>Hello world!</h1>
<div><img src="img_hello_world.jpg" alt="Hello World from Space" style="width:100%;max-width:960px"></div>
<p>This is the first file in my new Git Repo.</p>
<p>A new line in our file!</p>
<div><img src="img_hello_git.jpg" alt="Hello Git" style="width:100%;max-width:640px"></div>
</body>
</html>
Now stage and commit the changes:
git add --all
git commit -m "added new image"
[hello-world-images 1f1584e] added new image
2 files changed, 1 insertion(+)
create mode 100644 img_hello_git.jpg
Merging into master
We notice that index.html has changes in both the master branch and hello-world-images.
Let’s try merging:
git checkout master
git merge hello-world-images
Git tries to merge but finds a conflict:
Auto-merging index.html
CONFLICT (content): Merge conflict in index.html
Automatic merge failed; fix conflicts and then commit the result.
Checking the conflict
Use git status to see what’s going on:
git status
Output:
On branch master
You have unmerged paths.
(fix conflicts and run "git commit")
(use "git merge --abort" to abort the merge)
Changes to be committed:
new file: img_hello_git.jpg
new file: img_hello_world.jpg
Unmerged paths:
both modified: index.html
This tells us the image files are staged, but index.html has a conflict.
Resolving the conflict
Open index.html and you’ll see something like this:
<p>This is the first file in my new Git Repo.</p>
<<<<<<< HEAD
<p>This line is here to show how merging works.</p>
=======
<p>A new line in our file!</p>
<div><img src="img_hello_git.jpg" alt="Hello Git" style="width:100%;max-width:640px"></div>
>>>>>>> hello-world-images
Choose what you want to keep and remove the conflict markers (<<<<<<<, =======, >>>>>>>).
For example, final version:
<p>This is the first file in my new Git Repo.</p>
<p>This line is here to show how merging works.</p>
<div><img src="img_hello_git.jpg" alt="Hello Git" style="width:100%;max-width:640px"></div>
Finishing the merge
Stage the resolved file:
git add index.html
Check status again:
git status
Output:
On branch master
All conflicts fixed but you are still merging.
(use "git commit" to conclude merge)
Changes to be committed:
new file: img_hello_git.jpg
new file: img_hello_world.jpg
modified: index.html
Commit to complete the merge:
git commit -m "merged with hello-world-images after fixing conflicts"
[master e0b6038] merged with hello-world-images after fixing conflicts
Finally, delete the hello-world-images branch since it’s now merged:
git branch -d hello-world-images
Deleted branch hello-world-images (was 1f1584e).