Skip to main content

🌿 Lesson 4: Branches & Merging

Try a bold new idea for your website on a branch, where the working site can't be harmed, then merge it in when you love it. Along the way you'll cause a real merge conflict on purpose and fix it like a pro.

🎯 Learning Objectives

By the end of this lesson, you will be able to:

  • Explain what a branch is and why it makes experiments safe
  • List, create, and switch branches with git branch, git switch -c, and git switch
  • Merge a branch into main with git merge, and tell a fast-forward from a merge commit
  • Read your branch history with git log --oneline --graph --all and tidy up with git branch -d
  • Read conflict markers and resolve a merge conflict in VS Code, or back out with git merge --abort

Estimated Time: 50 minutes

Project: Build a new color scheme on a branch, merge it, then create and resolve a merge conflict on your own site

In This Lesson

🌳 Introduction: Why Branches?

Imagine you want to try a dark color scheme on your website. It might look amazing. It might look terrible. And it might take a few tries and a few commits to find out. Meanwhile, you'd like your working site to stay exactly as it is, in case you need to fix a typo on the Contact page in the middle of the experiment.

That's what a branch is for. A branch is a separate line of commits, a safe copy of your timeline where you can experiment freely. Your main timeline (the main branch you've been using all morning) doesn't change until you decide to merge the experiment in. And if the experiment flops, you simply never merge it.

%%{init: {"themeVariables": {"git0": "#3b82f6", "gitBranchLabel0": "#ffffff", "git1": "#f59e0b", "gitBranchLabel1": "#1e293b", "commitLabelFontSize": "12px"}}}%% gitGraph commit id: "Add pages" commit id: "Add styles" branch dark-theme checkout dark-theme commit id: "Try dark colors" commit id: "Tweak link color" checkout main commit id: "Fix contact typo" merge dark-theme

In the diagram, main keeps moving (a typo fix) while the dark-theme branch holds two experimental commits. When the experiment is done, it's merged back into main.

πŸ’‘ Branches Are Cheap

Creating a branch doesn't copy your files. Git just creates a small label that points to a commit. Making one takes a fraction of a second, so professionals create branches for everything: every feature, every fix, every "what if…?" You can too.

πŸ”€ Creating & Switching Branches

Before you start, make sure your work is committed: git status should say nothing to commit, working tree clean.

See your branches: git branch

git branch
* main

Just one so far. The * marks the branch you're currently on.

Create a branch and switch to it: git switch -c

Branch names should be short, lowercase, and use hyphens instead of spaces, and they should describe the experiment:

git switch -c dark-theme
Switched to a new branch 'dark-theme'

-c means create. Check again:

git branch
* dark-theme
  main

Commit on the branch

Now work exactly as you did this morning. In VS Code, change your body colors in css/style.css, save, check Live Server, then commit:

body {
    font-family: Arial, sans-serif;
    background-color: #0f172a;
    color: #e2e8f0;
}
git add css/style.css
git commit -m "Try a dark color scheme"
[dark-theme 742986d] Try a dark color scheme
 1 file changed, 2 insertions(+), 1 deletion(-)

Notice the commit output now says [dark-theme …] instead of [main …]. The commit landed on your branch.

Switch back: git switch main

git switch main
Switched to branch 'main'

Now look at Live Server. Your site is light again! Open style.css in VS Code: the dark colors are gone. They're not lost; they live on the dark-theme branch. Switch back with git switch dark-theme and they reappear. Try it a couple of times. This is the moment branches "click" for most people.

πŸ’‘ Your Branch Is Always in View

VS Code shows the current branch name at the bottom-left of the window, in the status bar. Click it to open a list of branches (and a Create new branch… option). It does the same thing as git switch.

⚠️ Commit Before You Switch

Uncommitted edits don't belong to any branch yet, so they tag along when you switch, which is confusing. If your edits would clash with the other branch, Git refuses to switch and tells you to commit your changes first. The habit that avoids all of this: commit (or discard) before you switch. Run git status first.

πŸ’‘ You'll See git checkout Online

Many tutorials and Stack Overflow answers use git checkout -b dark-theme to create a branch and git checkout main to switch. Those are the older spellings, and they still work. git switch was added to Git in 2019 because checkout does too many different jobs. In this course we use switch.

🀝 Merging a Branch Back

You love the dark theme. Time to bring it into main. Merging always works the same way: go to the branch you want to receive the changes, then merge the other branch into it.

git switch main
git merge dark-theme
Updating 9a988fb..742986d
Fast-forward
 css/style.css | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

Check Live Server: main is dark now. That's it, you merged!

⚠️ Which Direction?

The most common beginner slip is running the merge from the wrong branch. Read it as "merge dark-theme into the branch I'm on." So git switch main first, every time.

⏩ Fast-Forward vs. Merge Commit

Git merges in one of two ways, and it picks for you. You just need to recognize them.

Fast-forward: main didn't move

In the example above, nobody committed anything on main while you worked on dark-theme. So Git didn't need to combine anything. It just slid the main label forward to your branch's latest commit. That's why the output said Fast-forward. No new commit is created.

Merge commit: both branches moved

Now suppose you start an add-footer branch and commit a footer there, but before merging you switch back to main and commit a font change. Both lines have new commits, so Git has to combine them. It makes a special merge commit with two parents:

git switch main
git merge add-footer

A VS Code tab called MERGE_MSG opens with the message Merge branch 'add-footer'. That default is fine. Close the tab and Git finishes:

Merge made by the 'ort' strategy.
 index.html | 1 +
 1 file changed, 1 insertion(+)

('ort' is just the name of Git's merge engine. Older Git versions say 'recursive'. You can ignore it.)

πŸ’‘ No Editor Tab Appeared?

If Git prints unable to start editor or There was a problem with the editor instead of opening a tab (usually because the code command isn't set up; see Lesson 1), nothing is lost: Git says Not committing merge, and the merge is simply waiting for its commit. Run git commit --no-edit to finish it with the default message. Next time you can skip the editor from the start with git merge --no-edit add-footer.

Fast-forward Merge commit
When main has no new commits since the branch started Both branches have new commits
What Git does Moves the main label forward Creates a new commit that joins the two lines
Output says Fast-forward Merge made by the 'ort' strategy.
Editor opens? No Yes, for the merge message (close it to finish)

Either way, the result is the same: main now contains the branch's work.

πŸ—ΊοΈ Seeing Branches & Cleaning Up

Draw the history: git log --oneline --graph --all

Add --graph to draw the lines and --all to include every branch, not just the one you're on:

git log --oneline --graph --all
*   36ac9a0 Merge branch 'add-footer'
|\
| * 6fa0174 Add a footer to the home page
* | 1e78600 Switch body font to Georgia
|/
* 742986d Try a dark color scheme
* 9a988fb Revert "Rewrite about page intro"
...

Read it from the bottom up. Each * is a commit. Where the lines split, a branch started; where they join, it was merged. The dark-theme commit sits in a straight line, because it was a fast-forward. The footer work split off and joined back with a merge commit. (Remember: press q if the log opens in the pager.)

Delete a merged branch: git branch -d

Once a branch is merged, its commits are safely part of main, and the branch label is just clutter. Delete it:

git branch -d dark-theme
Deleted branch dark-theme (was 742986d).

The lowercase -d is the safe version: if the branch has commits that aren't merged yet, Git refuses and warns you that the branch is not fully merged. That's your safety net against deleting unfinished work. (It mentions an uppercase -D that forces the delete. Only use that for an experiment you truly want to throw away.)

πŸ’₯ Merge Conflicts

Usually Git combines branches on its own, even when both changed the same file, as long as they changed different lines. But if both branches change the same line in different ways, Git can't know which one you want. So it stops and asks you. That's a merge conflict.

🌱 Conflicts Are Normal, Not Failure

A merge conflict doesn't mean you broke anything. Nothing is lost; both versions are right there in the file. It just means Git is being careful and asking a human to make a decision. Professional developers resolve conflicts every week. That's why we're going to cause one on purpose, calmly, while you have help nearby.

Causing a conflict on purpose

Here's the recipe. Both branches will change the h1 color in css/style.css:

  1. Create a branch: git switch -c heading-color
  2. In style.css, set the h1 color to purple (#7c3aed). Save and commit: git commit -am "Make headings purple"
  3. Go back: git switch main
  4. Change the same line to green (#059669). Save and commit: git commit -am "Make headings green"
  5. Merge: git merge heading-color

This time Git stops:

Auto-merging css/style.css
CONFLICT (content): Merge conflict in css/style.css
Automatic merge failed; fix conflicts and then commit the result.

Take a breath and run git status. It tells you exactly where you are and what to do:

On branch main
You have unmerged paths.
  (fix conflicts and run "git commit")
  (use "git merge --abort" to abort the merge)

Unmerged paths:
  (use "git add <file>..." to mark resolution)
	both modified:   css/style.css

no changes added to commit (use "git add" and/or "git commit -a")

Reading the conflict markers

Open css/style.css. Git has written both versions into the file, fenced off with markers:

h1 {
<<<<<<< HEAD
    color: #059669;
=======
    color: #7c3aed;
>>>>>>> heading-color
}
  • <<<<<<< HEAD starts the version from the branch you're on (main). VS Code calls this the Current change.
  • ======= divides the two versions.
  • >>>>>>> heading-color ends the version from the branch you're merging in. VS Code calls this the Incoming change.

Your job: make the file look the way you want it to, and delete all three marker lines. You can keep one side, keep both, or write something new.

graph TD A["git merge heading-color"] --> B{"Same line changed<br/>on both branches?"} B -->|No| C["βœ… Merge finishes by itself"] B -->|Yes| D["πŸ’₯ CONFLICT<br/>markers written into the file"] D --> E["Edit the file:<br/>choose, then remove markers"] E --> F["git add css/style.css"] F --> G["git commit<br/>close the MERGE_MSG tab"] G --> H["βœ… Merge complete"] D -.->|"Want out?"| I["git merge --abort<br/>back to before the merge"] style C fill:#ecfdf5,stroke:#22c55e,stroke-width:2px,color:#1e293b style H fill:#ecfdf5,stroke:#22c55e,stroke-width:2px,color:#1e293b style D fill:#fef2f2,stroke:#ef4444,stroke-width:2px,color:#1e293b style B fill:#fef3c7,stroke:#f59e0b,stroke-width:2px,color:#1e293b style I fill:#eff6ff,stroke:#3b82f6,stroke-width:2px,color:#1e293b

🧩 Resolving a Conflict

Option 1: The inline buttons

When VS Code opens a conflicted file, it highlights the two versions in different colors and shows a row of small clickable links just above the <<<<<<< line:

Accept Current Change | Accept Incoming Change | Accept Both Changes | Compare Changes

  • Accept Current Change keeps main's green and removes the markers.
  • Accept Incoming Change keeps the branch's purple and removes the markers.
  • Accept Both Changes keeps both lines, one after the other. For two color values that isn't what you want (the second one wins in CSS), but it's perfect when both sides added something, like two new nav links.

Let's say you choose purple: click Accept Incoming Change. The file becomes:

h1 {
    color: #7c3aed;
}

You can also simply edit the text by hand: delete the lines you don't want plus the three markers. That works everywhere, in any editor.

Option 2: The merge editor

VS Code also has a three-pane merge editor. Open it with the Resolve in Merge Editor button at the bottom-right of the conflicted file (or from the file's entry under Merge Changes in the Source Control panel). The top panes show Incoming and Current side by side; the bottom pane is the Result. Tick the checkbox or Accept link on the side you want, look at the Result, then click Complete Merge. (Button labels can shift a little between VS Code versions.)

Finish the merge: git add + git commit

Save the file, check Live Server to make sure the page looks right, then tell Git the conflict is resolved by staging the file:

git add css/style.css
git status
On branch main
All conflicts fixed but you are still merging.
  (use "git commit" to conclude merge)

Changes to be committed:
	modified:   css/style.css

Now commit. Leave off -m: Git already wrote a message for you.

git commit

The MERGE_MSG tab opens with Merge branch 'heading-color'. Close the tab to finish:

[main 1088d56] Merge branch 'heading-color'

(In VS Code's Source Control panel you can instead click + on the file to stage it, then the Commit button.) Look at your graph:

*   1088d56 Merge branch 'heading-color'
|\
| * 5a219ae Make headings purple
* | bb98465 Make headings green
|/
*   36ac9a0 Merge branch 'add-footer'
...

πŸŽ‰ You just resolved a merge conflict. Delete the branch with git branch -d heading-color and you're done.

πŸšͺ The Escape Hatch: git merge --abort

Feeling lost in the middle of a conflict? Maybe you merged the wrong branch, or you'd like to ask someone first. Run:

git merge --abort

Everything goes back to exactly how it was before you typed git merge: no markers, clean git status, both branches untouched. You can try the merge again whenever you're ready.

⚠️ Don't Commit the Markers

Git doesn't check whether you actually removed the <<<<<<<, =======, and >>>>>>> lines. If you stage a file with markers still in it, they'll end up in your commit, and in your CSS, where they'll break the rule they sit in. Before git add, search the file (Ctrl+F / Cmd+F) for <<<< and check the page in the browser.

❓ Common Questions

Where did my files go when I switched branches?

Nowhere! Git swaps the files in your folder to match the branch you switch to. Everything committed on the other branch is safely stored in the .git folder. Switch back and it reappears. (This is also why you commit before switching.)

Is it main or master?

Both are just names for the default branch. Older projects and tutorials often use master; GitHub and most new projects use main, which is what you set up in Lesson 1. The commands work the same either way.

What if the branch was a bad idea?

Don't merge it. Switch to main and delete it with git branch -D <name> (uppercase, because it isn't merged). Or just leave it there; unmerged branches don't affect main at all.

Can a conflict happen in HTML files too?

Yes, in any text file, whenever two branches change the same lines. The markers and the fix are exactly the same as in CSS.

πŸ› οΈ Hands-on Exercise

πŸ‹οΈ Exercise: A New Look, Then a Conflict on Purpose

Objective: On your own my-website, merge an experiment branch, then create and resolve a real merge conflict. Start with a clean git status on main.

Part A: Experiment and merge

  1. Create and switch to a branch: git switch -c new-colors
  2. In css/style.css, give your site a new color scheme (change at least the body background and text colors). Check Live Server, then commit.
  3. Switch to main and watch the old colors come back in the browser. Switch to new-colors and back again.
  4. On main, merge the branch: git merge new-colors. Was it a fast-forward?
  5. Delete the branch with git branch -d new-colors.

Part B: Cause a conflict and fix it

  1. Create a branch: git switch -c new-heading. In index.html, change the text of your <h1>. Save and commit.
  2. git switch main. Change the same <h1> line to different text. Save and commit.
  3. Run git merge new-heading. Read the CONFLICT message, then run git status.
  4. Practice the escape hatch: run git merge --abort and confirm git status is clean. Then run git merge new-heading again.
  5. Resolve the conflict in VS Code (inline buttons, merge editor, or by hand). Make sure no markers remain and the page looks right in Live Server.
  6. git add index.html, then git commit and close the MERGE_MSG tab.
  7. Run git log --oneline --graph --all, then delete the branch with git branch -d new-heading.

Deliverable: a clean git status on main, your new colors and your chosen heading live in the browser, and a graph showing a Merge branch 'new-heading' commit where two lines join.

πŸ’‘ Hint

A conflict only happens if main gets its own commit on the same line before you merge. If git merge new-heading said Fast-forward, you forgot step 7. Check git log --oneline --graph --all to see what happened, then try again with a new branch. If the terminal seems stuck after git commit, look for the MERGE_MSG tab in VS Code and close it.

βœ… Solution
# Part A
git switch -c new-colors
# edit css/style.css in VS Code, save
git add css/style.css
git commit -m "Try a new color scheme"
git switch main
git merge new-colors          # "Fast-forward"
git branch -d new-colors

# Part B
git switch -c new-heading
# edit the h1 in index.html, save
git commit -am "Change heading to Sam's Photo Corner"
git switch main
# edit the SAME h1 line differently, save
git commit -am "Change heading to Welcome, Friends"
git merge new-heading         # CONFLICT (content): Merge conflict in index.html
git status
git merge --abort             # practice the escape hatch
git merge new-heading         # conflict again
# resolve in VS Code, remove all markers, save
git add index.html
git commit                    # close the MERGE_MSG tab
git log --oneline --graph --all
git branch -d new-heading

While conflicted, index.html looked something like this:

<body>
<<<<<<< HEAD
    <h1>Welcome, Friends</h1>
=======
    <h1>Sam's Photo Corner</h1>
>>>>>>> new-heading

After resolving, only the <h1> you chose remains, with no marker lines.

🌟 Want to Go Further?

Make a merge that isn't a fast-forward and doesn't conflict: create an about-update branch and change about.html there, then on main change contact.html. Merge, and look for Merge made by the 'ort' strategy. Then draw the result with git log --oneline --graph --all. Can you predict the shape of the graph before you run it?

🎯 Quick Quiz

Question 1: Which command creates a new branch called dark-theme and switches to it?

Question 2: You finished work on new-footer and want it in main. What do you run?

Question 3: git merge dark-theme printed Fast-forward. What does that tell you?

Question 4: In a conflicted file, what's between <<<<<<< HEAD and =======?

Question 5: You've removed the markers and the page looks right. How do you finish the merge?

πŸ““ Learning Journal

Take five minutes to add to your learning journal. Write down:

  • Key concepts you learned
  • What clicked β€” the idea or technique that made sense
  • Questions or confusion, so you know what to revisit
  • Ideas to try on your own pages
  • How you feel about your progress

✍️ This lesson's prompt: How did you feel when you first saw CONFLICT and Automatic merge failed in your terminal, and how did that feeling change once you'd resolved it? Name two experiments you'd like to try on a branch of your website (a new layout, a new page, a font change). Which part of branching or merging would you like to practice again?

Summary

πŸŽ‰ Key Takeaways

  • A branch is a separate line of commits for safe experiments; main is untouched until you merge
  • git switch -c <name> creates and switches; git switch <name> switches; git branch lists (* = current)
  • To merge: git switch main, then git merge <branch>
  • Fast-forward just moves main forward; a merge commit joins two lines that both moved
  • git log --oneline --graph --all draws your branches; git branch -d deletes a merged branch safely
  • A conflict means both branches changed the same line: pick a version, delete the markers, git add, git commit. Or back out with git merge --abort.

πŸ“š Additional Resources

πŸš€ What's Next?

So far everything lives on your own computer. In the next lesson you'll put your repository on GitHub: create an account and a repository, push your commits up, pull changes down, and clone a project. Your site's history will be backed up in the cloud and ready to share.