Lesson 3 of 9 · about 15 minutes

Merge and clean up

Bringing a branch home, then throwing away the pointer.

You will merge a branch into main, recognise a fast-forward versus a merge commit, delete branches safely, and resolve a real merge conflict.

Two kinds of merge

A merge brings another branch's commits into the branch you are on. You always merge into HEAD, so first switch to the branch that should receive the work (usually main), then run git merge <branch>.2

Fast-forward: main hasn't moved main (before) main, add-cleaning Merge commit: both sides moved main merge commit add-plot
Top: Git slides main forward. Bottom: Git creates a new commit with two parents.

git merge --no-ff <branch> means "Create a merge commit in all cases," even when a fast-forward was possible.2 GitHub's default Merge pull request button does exactly this.5 You'll meet it in lesson 4.

Deleting a branch is deleting a pointer

Once a branch is merged, its commits live on in main. The branch is just a leftover label, so delete it with git branch -d <branch>.1 The lowercase -d is the safe version. The branch "must be fully merged," and if it isn't, Git refuses:3

$ git branch -d try-polars
error: the branch 'try-polars' is not fully merged
hint: If you are sure you want to delete it, run 'git branch -D try-polars'

Uppercase -D ("--delete --force") deletes it anyway.3 That's the right move for a failed experiment, such as an agent attempt you've decided to abandon, but it throws those commits away. Read the error before reaching for -D.

Try it: one fast-forward, one merge commit

main has two commits, and add-cleaning is one commit ahead. Watch which tasks move a pointer and which create a new commit.

Compare the two merges in the terminal output: Fast-forward versus Merge made by the 'ort' strategy. Then compare the graph. Only the second merge drew a new node with two incoming lines.

Do it: merge in penguins-lab

  1. $ git switch main
    $ git merge add-cleaning
    Updating 1d28f0e..3ef57a2
    Fast-forward
     clean.py | 5 +++++
     1 file changed, 5 insertions(+)
  2. $ git branch -d add-cleaning
    Deleted branch add-cleaning (was 3ef57a2).

Your first merge conflict

Git can't decide for you when "you changed the same part of the same file differently in the two branches."1 That's a merge conflict. It isn't an error, just a question Git needs you to answer. GitHub has the same rule: the Merge pull request button stays disabled until conflicts are resolved.4 Make one on purpose so it's familiar before an agent hands you one.

  1. $ git switch -c readme-title
    #   ...edit line 1 of README.md...
    $ git commit -am "Retitle README"
    $ git switch main
  2. $ git switch -c readme-title-2
    #   ...edit line 1 of README.md...
    $ git commit -am "Rename project in README"
    $ git switch main
  3. $ git merge readme-title
    Fast-forward
    $ git merge readme-title-2
    Auto-merging README.md
    CONFLICT (content): Merge conflict in README.md
    Automatic merge failed; fix conflicts and then commit the result.
  4. <<<<<<< HEAD
    # Palmer Penguins Analysis
    =======
    # Penguin Data Lab
    >>>>>>> readme-title-2

    Above ======= is the version from HEAD, the branch you're on. Below it is the branch you're merging in.1 Edit the block until it says what you actually want, for example # Palmer Penguins Data Lab, and delete all three marker lines.

  5. $ git add README.md
    $ git commit -m "Merge readme-title-2, combine titles"
    $ git branch -d readme-title readme-title-2
Search the file for leftover <<<<<<< before you git add. Git will happily commit marker lines, and a .py file with markers in it won't even import.

Recall the commands

You're on main. Bring in the commits from add-cleaning.

Safely delete the merged branch add-cleaning.

Throw away the unmerged experiment branch try-polars.

You're mid-conflict and want to go back to how things were before the merge.

Merge add-plot, forcing a merge commit even if a fast-forward is possible.

Check yourself

main hasn't moved since you created add-cleaning. What does git merge add-cleaning do?

No divergent work means a fast-forward. Git just moves main to the branch tip, and no new commit is made.

git branch -d add-plot fails with "not fully merged." What is Git warning you about?

add-plot has commits that aren't in your current branch. Merge first, or use -D if you really mean to throw them away.

In a conflict block, what is the text above the ======= line?

The top half is HEAD, the branch you ran git merge from. The bottom half is the branch being merged in.

Read Pro Git §3.2, "Basic Branching and Merging". It walks through a fast-forward, a merge commit, and a conflict, with diagrams (about 15 minutes). For more conflict practice, try GitHub Skills' Resolve merge conflicts course.
Ask Claude: "I have a merge conflict in clean.py. Explain each side of the conflict to me before changing anything," or "When should I use git branch -D instead of -d?" Asking Claude to explain a conflict before it resolves one is a good habit.

Want more practice before moving on? Paste the branch practice tutor prompt into Claude. It finds your level and drills merges and conflicts in a throwaway repository until you can do them without hints.

Sources

  1. Chacon & Straub, Pro Git, §3.2 Basic Branching and Merging.
  2. Git reference, git-merge (fast-forward options, --abort, conflict presentation).
  3. Git reference, git-branch (-d, -D).
  4. GitHub Docs, About merge conflicts.
  5. GitHub Docs, About pull request merges.