Programming and IT
git merge
Merging brings work from one branch into another. git merge takes the branch you name and joins its history with the current one — sometimes by just moving a pointer, sometimes by creating a separate commit, and sometimes by stopping and asking for help.
In this article
What merges into what#
A merge always goes one way: from the branch you name into the branch you are on. So first you switch to the receiving branch and only then name the source:
The source branch does not go anywhere afterwards and stays on its commit — you either delete it as finished or keep working in it. How the pointers themselves work is explained in the article on git branch.
Fast-forward versus a real merge#
If main has not received a single commit since the branch split off, Git does
not invent anything — it just moves the pointer forward:
Updating 4f1c2ab..9d31c07
Fast-forward
export.py | 28 ++++++++++++++++++++++++++++
1 file changed, 28 insertions(+)
create mode 100644 export.py
If both branches have moved on, a commit with two parents appears:
Merge made by the 'ort' strategy.
export.py | 28 ++++++++++++++++++++++++++++
1 file changed, 28 insertions(+)
ort is the name of the merge algorithm in recent versions of Git; older ones
said recursive here. It does not change what the output means.
| Option | What it changes |
|---|---|
--no-ff |
always create a merge commit, even when a fast-forward would do |
--ff-only |
the opposite: merge only by fast-forward, otherwise refuse |
--squash |
combine all the branch's commits into one set of changes, no merge commit |
--no-commit |
stop before recording, so you can inspect the result |
-m "text" |
your own message for the merge commit |
--abort |
drop an unfinished merge and put everything back |
Teams like --no-ff where it matters to see in history that a group of commits
is one task. --squash is handy when a branch has twenty tiny commits like
"typo" that the shared history does not need: afterwards the changes sit in the
index and you commit them yourself with git commit.
If you would rather replay commits than join histories, compare this with
git rebase.
A conflict: what it is and what to do#
A conflict happens when the same piece of a file was changed differently in both branches. Automation cannot guess here:
Auto-merging README.md
CONFLICT (content): Merge conflict in README.md
Automatic merge failed; fix conflicts and then commit the result.
Git does not roll back; it leaves the work halfway: what merged cleanly is already in the index, and the disputed part is marked right in the file.
<<<<<<< HEAD
Run: python app.py
=======
Run: python -m app
>>>>>>> feature/export
On top is the version from the current branch, below it the one from the branch being merged. The routine goes like this:
git status— the "Unmerged paths" section lists the disputed files.- Open each one, keep the right text and remove all three marker lines.
git add README.md— this tells Git the file is resolved.git merge --continue(orgit commit) — record the merge commit.
A useful detail: git checkout --ours README.md takes the current branch's
version in full, --theirs takes the incoming one. This saves you in conflicts
over generated files where there is nothing to mix. The full walkthrough, with
the zdiff3 style and common traps, is in
how to resolve a merge conflict.
How to undo a merge#
The merge is not finished, the file is full of conflict markers, and you want to start over:
The branch and the working directory return to the state before the command.
The merge commit is already created but not pushed:
ORIG_HEAD holds where the branch was before the merge began. --hard erases
uncommitted work, so first make sure you have nothing unsaved.
The merge is already on the server and others have seen it — you must not rewrite history, so you undo it with a new commit:
The number after -m is the parent to treat as the main line; 1 means the
branch you merged into. More on pushing and its rejections in the article on
git push.
How to look at the result#
The slanted lines on the left show where history split and where it joined
again. If the picture is not what you expected, do not worry: until the commits
are pushed, any merge can be undone without a trace, and the earlier positions of
the branch are listed in git reflog.
Step-by-step plan
- Update the receiving branchSwitch to the target branch and pull the latest commits from the server.
- See what will come ingit log --oneline main..feature — the list of the source branch's commits.
- Run the mergegit merge feature; add --no-ff or --squash if needed.
- Resolve conflictsFix the files, remove the markers, git add, git merge --continue.
- Check and tidy upRun the tests, then delete the finished branch with git branch -d.
Start learning this in your own space
The plan goes into your repository: tick off stages, keep notes — the change history shows how far you have come.
Check yourself
1.A merge stopped on a conflict. Which command puts everything back as it was before the merge?
2.What does git merge --no-ff do?
3.The conflicted file is edited and the markers are removed. What next?
Sources
-
Pro Git bookThe sections on basic merging and resolving conflictsfree
-
git merge referenceStrategies, options and behaviour on conflictfree
-
Learn Git BranchingAn interactive visual sandbox for merges and rebasesfree
Was this helpful?