πΏ 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, andgit switch - Merge a branch into
mainwithgit merge, and tell a fast-forward from a merge commit - Read your branch history with
git log --oneline --graph --alland tidy up withgit 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.
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:
- Create a branch:
git switch -c heading-color - In
style.css, set theh1color to purple (#7c3aed). Save and commit:git commit -am "Make headings purple" - Go back:
git switch main - Change the same line to green (
#059669). Save and commit:git commit -am "Make headings green" - 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
}
<<<<<<< HEADstarts the version from the branch you're on (main). VS Code calls this the Current change.=======divides the two versions.>>>>>>> heading-colorends 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.
π§© 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
colorvalues 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
- Create and switch to a branch:
git switch -c new-colors - In
css/style.css, give your site a new color scheme (change at least thebodybackground and text colors). Check Live Server, then commit. - Switch to
mainand watch the old colors come back in the browser. Switch tonew-colorsand back again. - On
main, merge the branch:git merge new-colors. Was it a fast-forward? - Delete the branch with
git branch -d new-colors.
Part B: Cause a conflict and fix it
- Create a branch:
git switch -c new-heading. Inindex.html, change the text of your<h1>. Save and commit. git switch main. Change the same<h1>line to different text. Save and commit.- Run
git merge new-heading. Read theCONFLICTmessage, then rungit status. - Practice the escape hatch: run
git merge --abortand confirmgit statusis clean. Then rungit merge new-headingagain. - 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.
git add index.html, thengit commitand close theMERGE_MSGtab.- Run
git log --oneline --graph --all, then delete the branch withgit 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;
mainis untouched until you merge git switch -c <name>creates and switches;git switch <name>switches;git branchlists (*= current)- To merge:
git switch main, thengit merge <branch> - Fast-forward just moves
mainforward; a merge commit joins two lines that both moved git log --oneline --graph --alldraws your branches;git branch -ddeletes 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 withgit merge --abort.
π Additional Resources
- Pro Git β Basic Branching and Merging
- VS Code β Source Control (includes merge conflicts)
- Learn Git Branching (an interactive visual playground)
- Git Quick Reference (this site): the branching & merging commands on one page
π 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.