Skip to main content

Lesson: Branches, Merges & Conflicts

What you'll learn

  • What a branch really is (a cheap, movable pointer — not a copy of your files).
  • How to create and switch branches with git branch and git switch.
  • How to combine work with git merge, and the difference between a fast-forward and a merge commit.
  • How a merge conflict happens, and a calm, step-by-step way to resolve one.
  • Why branching is the foundation of safe teamwork.

By the end you will be able to develop a change in isolation, merge it back, and handle conflicts without panic.

The lesson

1. What a branch is

A branch is just a lightweight, movable pointer to a commit. It is not a copy of your project. Creating a branch is instant and nearly free, which is why Git users branch constantly.

Recall from Module 4 Lesson 1 that commits form a chain, each pointing at its parent. A branch name simply points at the newest commit on a line of work, and HEAD points at the branch you are currently on:

            main
              │
  (A) ─> (B) ─> (C)   <- HEAD points here (you are on main)

When you commit, the branch pointer moves forward to the new commit automatically.

2. Why branch at all?

Branches let you work on something new without touching the known-good version. Your main branch stays stable and deployable while you experiment on a feature branch. If the experiment fails, you delete the branch and main is untouched. If it succeeds, you merge it in. On a team, everyone works on their own branch and merges when ready — that is how people avoid stepping on each other.

3. Creating and switching branches

The modern commands are git switch (change branches) and git branch (list/create/delete). Older tutorials use git checkout for both; switch is clearer and is what we use here.

git branch                 # list branches; * marks the current one
git switch -c add-logging   # create a new branch AND switch to it

-c means "create." After this, HEAD points at add-logging, which starts at the same commit main is on:

                  main
                   │
  (A) ─> (B) ─> (C)
                   │
              add-logging  <- HEAD

Now make a commit on the feature branch:

echo 'echo "logging enabled"' >> hello.sh
git add hello.sh
git commit -m "Add logging line to hello.sh"

The picture is now:

                  main
                   │
  (A) ─> (B) ─> (C) ─> (D)
                        │
                   add-logging  <- HEAD

main still points at C; only add-logging moved forward to D. Switch back any time with git switch main — your files change to match that branch.

4. Merging: bringing work together

Merging takes the commits from one branch and combines them into another. You merge into the branch you are currently on. To bring add-logging into main:

git switch main
git merge add-logging

There are two outcomes.

5. Fast-forward merge

If main has not moved since you branched (it still points at C), Git can simply slide main forward to D. No new commit is needed — this is a fast-forward:

  before:  (C:main) ─> (D:add-logging)
  after:   (C) ─> (D)   <- main and add-logging both here

The history stays perfectly linear. This is the common case for a quick solo feature.

6. Merge commit (true merge)

If main also gained commits while you worked (say someone added commit E), the two lines have diverged:

  (A) ─> (B) ─> (C) ─> (E)        <- main
                 │
                 └────> (D)        <- add-logging

Git cannot just slide the pointer. It creates a new merge commit (M) that has two parents — E and D — tying the histories together:

  (A) ─> (B) ─> (C) ─> (E) ─> (M)  <- main
                 │            │
                 └────> (D) ──┘

Git opens an editor for the merge commit message; usually you accept the default and save.

7. When a conflict happens

Most merges are automatic. A conflict occurs only when the same lines of the same file were changed differently on both branches — Git cannot know which version you want, so it asks you.

Let's create one on purpose to learn the fix. On main, edit line 2 of hello.sh to say echo "hello from main" and commit it. Then switch to a branch where line 2 says echo "hello from feature" and commit that. Now merge:

git switch main
git merge feature

Git stops and reports a conflict. git status will list hello.sh under "Unmerged paths."

8. Resolving a conflict, step by step

Open the conflicted file. Git has inserted conflict markers:

<<<<<<< HEAD
echo "hello from main"
=======
echo "hello from feature"
>>>>>>> feature
  • Between <<<<<<< HEAD and ======= is your current branch's version.
  • Between ======= and >>>>>>> feature is the incoming branch's version.

To resolve, do these in order:

  1. Edit the file so it contains exactly what you want the final result to be. Delete all three marker lines (<<<<<<<, =======, >>>>>>>) and keep/blend the correct content. For example, settle on echo "hello from the team".
  2. Stage the resolved file to tell Git you have settled it:
    git add hello.sh
    
  3. Complete the merge by committing:
    git commit          # accept the default merge message, or write your own
    

That's it — the merge commit is created and the conflict is resolved. If you ever feel lost mid-conflict, you can abort and return to the pre-merge state:

git merge --abort

9. Cleaning up

Once a feature branch is merged, delete it to keep things tidy:

git branch -d add-logging   # -d refuses if not yet merged (safe)

Conflicts feel scary the first time, but the routine is always the same: edit to the desired result, remove the markers, add, then commit. Practice it a few times and it becomes routine. In the next lesson you take all of this online, pushing branches to the lab's Gitea server and merging through pull requests.

Dig deeper

Search terms

  • git branch and switch tutorial beginner
  • git fast forward vs merge commit difference
  • how to resolve a git merge conflict step by step
  • git merge conflict markers explained
  • git merge abort undo a merge

Check yourself

  1. A branch is a pointer to what? Is it a copy of your files?
  2. What is the difference between a fast-forward merge and a merge commit, and when does each happen?
  3. Under exactly what condition does a merge produce a conflict?
  4. List the three steps to resolve a conflict once you see the markers.
  5. Which command throws away an in-progress merge and returns you to where you started?