Git and GitHub course menu
git merge Explained: Fast-Forward and Three-Way Merges
Combine branches with git merge. Understand fast-forward and three-way merges, merge commits, --no-ff, squash merges, how to abort a merge, and cleaning up afterwards.
On this page
git merge brings the work from another branch into the current branch. So first switch to the branch that should receive the work, usually main. There are two kinds of merge.
Fast-forward merge#
Here add-cart has a new commit, and main has not moved since the branch started:
git switch -q -c add-cart
echo "Cart page" > cart.html
git add .
git commit -q -m "Add cart page"
git switch -q main
git log --oneline --graph --all* 0f0e747 Add cart page
* 4e04c7b Add home pageNothing has happened on main, so Git only needs to move the main label forward:
git merge add-cartUpdating 4e04c7b..0f0e747
Fast-forward
cart.html | 1 +
1 file changed, 1 insertion(+)
create mode 100644 cart.htmlBefore: A main
\
B add-cart
After: A <--- B main, add-cartNo new commit is created. The branch is finished, so delete it:
git branch -d add-cartDeleted branch add-cart (was 0f0e747).Three-way merge#
Now both branches have new commits. Git cannot just move a label, so it makes a merge commit with two parents.
git switch -q -c add-search
echo "Search page" > search.html
git add .
git commit -q -m "Add search page"
git switch -q main
echo "Contact page" > contact.html
git add .
git commit -q -m "Add contact page"
git log --oneline --graph --all* a294284 Add search page
| * 28d92ec Add contact page
|/
* 0f0e747 Add cart page
* 4e04c7b Add home pagegit merge --no-edit add-search
git log --oneline --graphMerge made by the 'ort' strategy.
search.html | 1 +
1 file changed, 1 insertion(+)
create mode 100644 search.html
* 56bc1a5 Merge branch 'add-search'
|\
| * a294284 Add search page
* | 28d92ec Add contact page
|/
* 0f0e747 Add cart page
* 4e04c7b Add home pageIt is called three-way because Git compares three commits: the tip of each branch and their common ancestor. Without --no-edit, Git opens your editor so you can confirm the message Merge branch 'add-search'.
Forcing a merge commit#
Some teams like every feature to show up as a merge commit, even when a fast-forward was possible:
git merge --no-ff add-cartThis keeps a visible record of where a feature began and ended.
Squash merging#
--squash takes all the changes on a branch and stages them as one change, for you to commit as a single commit:
git branch -d add-search
git switch -q -c fix-title
echo "Title 1" >> index.html
git commit -q -am "Try title"
echo "Title 2" >> index.html
git commit -q -am "Fix title again"
git switch -q main
git merge --squash fix-title
git commit -q -m "Improve page title"
git log --oneline -n 2Deleted branch add-search (was a294284).
Updating 56bc1a5..9354a08
Fast-forward
Squash commit -- not updating HEAD
index.html | 2 ++
1 file changed, 2 insertions(+)
1011687 Improve page title
56bc1a5 Merge branch 'add-search'The two messy commits became one clean commit on main. GitHub offers this as a button on pull requests. Because the branch's commits were not merged directly, git branch -d will refuse to delete it, so use -D.
Which branch receives the changes?#
Always the one you are on. To check before merging:
git branch --show-currentmainStopping a merge#
If a merge goes wrong or you change your mind while it is in progress, this returns everything to how it was before the merge began:
git merge --abortCommon mistakes#
Practice#
Practice exercise
Create a branch docs, add and commit README.md, return to main, add and commit LICENSE, and then merge docs into main. Print the graph.
Show solution
git switch -q -c docs
echo "# App" > README.md
git add . && git commit -q -m "Add README"
git switch -q main
echo "MIT" > LICENSE
git add . && git commit -q -m "Add license"
git merge -q --no-edit docs
git log --oneline --graph* 5a289e4 Merge branch 'docs'
|\
| * 217e5f2 Add README
* | 5ad2cc7 Add license
|/
* c17a865 StartKey takeaway#
Next: Resolving Merge Conflicts.
Finished this lesson?