All tutorials

Tutorial 3 of 8

Branches and Merging

Work on an idea without disturbing main, then bring it back with a merge and a clear message.

About 6 minutes

What you will be able to do

  1. Explain a branch as a movable label on a commit, with main as the usual default name (master in older setups).
  2. Create and switch branches with git switch -c, and know the older git checkout -b.
  3. Merge a branch and tell a fast-forward apart from a merge commit.
  4. Write a custom merge message with git merge -m, and use --no-ff when you always want a merge commit.

Title

Branches and Merging. Try ideas safely, then bring them home.

This tutorial shows how branches let you work on an idea separately and how merging brings that work back.

main, and the older name master

Your first branch is usually called main. Older setups and tutorials call it master. Same idea, different name.

New GitHub repositories use main, and plain git init may still say master on some machines unless you set init.defaultBranch or use -b main.

Analogy: a sticky note on a chain of photos

A branch is a sticky note on one photo in a chain. Take a new photo, and the note moves forward.

A branch is a lightweight label that points at a commit and moves forward whenever you commit on that branch.

The analogy, and where it breaks

Commits are photos in a chain. A branch is a sticky note stuck on one photo, and it moves to each new photo you take on that branch.

A branch is not a copy of your files; it is only a tiny pointer to one commit, which is why creating a branch is instant and cheap.

Create and switch

git switch -c creates a branch and moves you onto it. HEAD now follows the new branch.

git switch -c feature
# older command, same result: git checkout -b feature
git branch

The new branch starts at your current commit, and HEAD now follows feature instead of main.

Commit on the branch

New commits move only the branch HEAD is on. main stays where it was.

Your feature commits build a separate line of work, while main stays untouched on C3.

Meanwhile, main moves on

Back on main, someone adds a new commit. Now the two lines of work have split.

When both branches have new commits after C3, the history has diverged and a real merge is needed.

Analogy: two rivers joining

git merge joins two lines of work. The result is a merge commit with two parents.

git switch main
git merge feature

A merge commit ties the two lines together by pointing to both parents, and main moves to that new commit.

The analogy, and where it breaks

Two rivers flow separately and then join into one wider river.

Joined rivers cannot be separated again, but a merge commit keeps both histories and records exactly two parents, so you can still trace each line.

A custom merge message

Add -m to write your own merge message instead of the default "Merge branch 'feature'".

git switch main
git merge -m "Merge greeting feature into main" feature
git log --oneline --graph

The -m option sets the merge commit's message, which is easier to read later than the default text.

Fast-forward: no merge commit

If main has no new commits, Git just slides main forward. No merge commit is made, so -m has nothing to name.

When main is directly behind feature, Git fast-forwards main without creating any commit, so a message given with -m is not used.

The analogy, and where it breaks

The sticky note simply slides along the chain to the newest photo.

Sliding a note leaves no trace, and a fast-forward also leaves no record that a merge happened, which is why -m has no effect here.

Always make a merge commit with --no-ff

Want a merge commit and your message, even when a fast-forward is possible? Add --no-ff.

git merge --no-ff -m "Merge feature: add greeting" feature

With --no-ff, Git always creates a merge commit, so your -m message is saved and the branch shows clearly in history.

Tidy up the branch label

Done with a branch? git branch -d feature removes the label. The commits stay in history.

git branch -d feature

Deleting a merged branch only removes its label, because its commits are already part of main's history.

Recap

A branch is a movable label. Merge joins work. Fast-forward makes no commit. Use --no-ff -m for a named merge.

{"commits": [{"id": "C1", "parents": []}, {"id": "C2", "parents": ["C1"]}, {"id": "F1", "parents": ["C2"]}, {"id": "F2", "parents": ["F1"]}], "refs": [{"name": "main", "target": "C2", "kind": "branch"}, {"name": "feature", "target": "F2", "kind": "branch"}], "head": {"ref": "main"}}

You can now branch, merge and name your merges, and next you will learn to park unfinished work with stash.

Check yourself

0 of 5 answered

Check 1 of 5

What does git switch -c feature create?

Check 2 of 5

On main you run git merge -m "Merge feature" feature. Click where main points after the merge.

C1C2HEAD: mainF1F2feature

main points at C2. feature has F1 then F2 on top of C2. main has no other commits. HEAD is on main. A dashed circle "new merge commit?" is shown to the right.

Check 3 of 5

The merge succeeds. What is the message of the newest commit on main?

git switch main
git merge --no-ff -m "Merge login work" login

Check 4 of 5

Which statement about a merge commit is true?

Check 5 of 5

Your friend's new repo has a branch named master, and yours has main. What does this mean?

mkdir -p ~/git-practice/t03-branches && cd ~/git-practice/t03-branches
git init -b main
echo "Home" > index.txt && git add index.txt && git commit -m "Add homepage"

# 1. Fast-forward: main has no new commits
git switch -c feature
echo "Hello" > greeting.txt && git add greeting.txt && git commit -m "Add greeting"
git switch main
git merge -m "Merge feature" feature      # says Fast-forward: no merge commit
git log --oneline --graph

# 2. Real merge: both lines have new commits
git switch -c contact
echo "Call us" > contact.txt && git add contact.txt && git commit -m "Add contact page"
git switch main
echo "Home v2" > index.txt && git add index.txt && git commit -m "Update homepage"
git merge -m "Merge contact page" contact  # a merge commit with your message

# 3. Force a merge commit with --no-ff
git switch -c about
echo "About us" > about.txt && git add about.txt && git commit -m "Add about page"
git switch main
git merge --no-ff -m "Merge about page" about

git log --oneline --graph                  # press q if a pager opens
git branch -d feature contact about