Project Overview
What you'll build and version:
- A simple portfolio page (
index.html) - Basic styles (
style.css) - Dark mode toggle (
app.js) — developed on a feature branch
What you'll practice:
- Initializing a Git repository
- Making meaningful, atomic commits
- Working with feature branches
- Merging and cleaning up
- Tagging a release
- Pushing to GitHub
Step 1 – Initialize the Repository
# Create the project directory
mkdir my-portfolio
cd my-portfolio
# Initialize Git
git init
# Initialized empty Git repository in /home/you/my-portfolio/.git/
# Set your identity (if not already configured globally)
git config user.name "Your Name"
git config user.email "you@example.com"
# Verify
git status
# On branch main
# No commits yet
# nothing to commit
Steps 2–3 – First Commits
Commit 1: Add index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Jane Dev – Portfolio</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<header>
<h1>Jane Dev</h1>
<p>Full Stack Developer</p>
</header>
<main>
<section id="about">
<h2>About Me</h2>
<p>I build web applications with React and Node.js.</p>
</section>
<section id="projects">
<h2>Projects</h2>
<ul>
<li>Project Alpha — Task management app</li>
<li>Project Beta — E-commerce store</li>
</ul>
</section>
</main>
<footer><p>© 2026 Jane Dev</p></footer>
<script src="app.js"></script>
</body>
</html>
git add index.html
git commit -m "feat: add portfolio index.html"
# [main (root-commit) a1b2c3d] feat: add portfolio index.html
# 1 file changed, 28 insertions(+)
Commit 2: Add CSS
:root {
--bg: #ffffff;
--text: #1a1a2e;
--accent: #6c63ff;
}
body {
font-family: system-ui, sans-serif;
background: var(--bg);
color: var(--text);
max-width: 800px;
margin: 0 auto;
padding: 2rem;
transition: background 0.3s, color 0.3s;
}
h1 { color: var(--accent); }
header { text-align: center; padding: 3rem 0; }
section { margin: 2rem 0; }
footer { text-align: center; margin-top: 4rem; opacity: 0.6; }
git add style.css
git commit -m "style: add base CSS with CSS custom properties"
# Check our progress
git log --oneline
# e5f6a7b (HEAD -> main) style: add base CSS with CSS custom properties
# a1b2c3d feat: add portfolio index.html
Step 4 – Feature Branch: Dark Mode
The dark mode toggle will be developed on its own branch, keeping main stable while we experiment.
# Create and switch to the feature branch
git switch -c feature/dark-mode
# Verify we're on the right branch
git branch
# main
# * feature/dark-mode
// Dark mode toggle
const toggle = document.createElement('button');
toggle.textContent = '🌙 Dark Mode';
toggle.style.cssText = 'position:fixed;top:1rem;right:1rem;padding:0.5rem 1rem;cursor:pointer;border-radius:20px;border:none;background:var(--accent);color:white;font-size:0.9rem;';
document.body.appendChild(toggle);
const darkStyles = `
:root { --bg: #0d1117; --text: #e6edf3; --accent: #9b8bff; }
`;
let darkStyleEl = null;
toggle.addEventListener('click', () => {
if (darkStyleEl) {
darkStyleEl.remove();
darkStyleEl = null;
toggle.textContent = '🌙 Dark Mode';
} else {
darkStyleEl = document.createElement('style');
darkStyleEl.textContent = darkStyles;
document.head.appendChild(darkStyleEl);
toggle.textContent = '☀️ Light Mode';
}
});
git add app.js
git commit -m "feat(ui): add dark mode toggle button"
git log --oneline --all
# 8c9d0e1 (HEAD -> feature/dark-mode) feat(ui): add dark mode toggle button
# e5f6a7b (main) style: add base CSS with CSS custom properties
# a1b2c3d feat: add portfolio index.html
Step 5 – Merge Back to main
# Switch back to main
git switch main
# Merge the feature branch
git merge feature/dark-mode
# Updating e5f6a7b..8c9d0e1
# Fast-forward
# app.js | 22 ++++++++++++++++++++++
# 1 file changed, 22 insertions(+)
# Clean up the feature branch
git branch -d feature/dark-mode
# Final log
git log --oneline
# 8c9d0e1 (HEAD -> main) feat(ui): add dark mode toggle button
# e5f6a7b style: add base CSS with CSS custom properties
# a1b2c3d feat: add portfolio index.html
Step 6 – Tag the Release
# Create an annotated release tag
git tag -a v1.0.0 -m "Release v1.0.0
Initial portfolio release:
- HTML structure with About and Projects sections
- Base CSS with custom properties
- Dark mode toggle
Ready for public deployment."
# Verify the tag
git show v1.0.0
# tag v1.0.0
# Tagger: Jane Dev <jane@example.com>
# Date: Mon Jun 8 2026 ...
# Release v1.0.0 ...
Step 7 – Create GitHub Repo and Push
# On GitHub: click "+" → New repository
# Name: my-portfolio
# Leave it empty (no README, no .gitignore)
# Copy the SSH URL: git@github.com:USERNAME/my-portfolio.git
# Add the remote
git remote add origin git@github.com:USERNAME/my-portfolio.git
# Push main branch
git push -u origin main
# Enumerating objects: 7, done.
# Writing objects: 100% (7/7), ...
# Branch 'main' set up to track remote branch 'main' from 'origin'.
# Push the tag
git push origin v1.0.0
# To git@github.com:USERNAME/my-portfolio.git
# * [new tag] v1.0.0 -> v1.0.0
Step 8 – Verify on GitHub
Visit your repository on GitHub and confirm:
- All three files are visible:
index.html,style.css,app.js - The commit history shows 3 commits
- Click the "Releases" or "Tags" tab —
v1.0.0appears - GitHub automatically creates a downloadable ZIP of the code at that tag
Since this is a static HTML/CSS/JS site, you can host it for free on GitHub Pages. Go to your repo → Settings → Pages → Source: Deploy from branch → Branch: main → Folder: / (root). Your portfolio will be live at https://USERNAME.github.io/my-portfolio/ within a minute!
📋 Summary
- Started with git init and configured identity.
- Made three focused commits: HTML, CSS, then the dark mode JS (on a feature branch).
- Feature branch (
feature/dark-mode) kept main stable during development. - Merged with a clean fast-forward merge and deleted the branch.
- Tagged the finished version:
git tag -a v1.0.0 -m "message" - Connected to GitHub with git remote add origin and pushed both the branch and the tag.
- The result: a professional GitHub repository with meaningful history, a tagged release, and optionally a live GitHub Pages site.
FAQ
A fast-forward merge happens because main hadn't advanced since we created feature/dark-mode. Git simply moved the main pointer forward to the tip of the feature branch — no merge commit needed. If main had additional commits after the branch point (e.g., you had committed a hotfix directly to main), Git would create a merge commit instead. To always force a merge commit even for fast-forwards, use git merge --no-ff feature/dark-mode.
A push rejection usually means the remote has commits you don't have locally. Solution: git pull --rebase origin main to fetch and rebase your commits on top of the remote's. This is common when GitHub added a commit (like an initial README) and you also have local commits. After the rebase, git push should succeed. Note: if you created the GitHub repo without any files (empty), you won't have this issue.
For a simple HTML/CSS/JS project, create a .gitignore file in the project root: echo ".DS_Store\nThumbs.db\n*.log" > .gitignore. Stage and commit it: git add .gitignore && git commit -m "chore: add .gitignore". Then push: git push. For more comprehensive templates, visit gitignore.io and enter your editor and OS type (e.g., "macOS, VS Code").