Ad – 728×90
🛠️ Projects

Version Your First Project with Git – Step-by-Step

This project takes you from zero to a fully versioned, GitHub-hosted project. You'll build a simple personal portfolio page with HTML, CSS, and a dark mode toggle in JavaScript — versioning every step with Git. By the end you'll have a real GitHub repository with a proper commit history, a feature branch merge, and a tagged release. This is the workflow professional developers use every day.

⏱️ 45 min 🎯 Beginner 📅 Updated 2026

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

Bash
# 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

HTML (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>
Bash
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

Ad – 336×280
CSS (style.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; }
Bash
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.

Bash
# 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
JavaScript (app.js)
// 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';
  }
});
Bash
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

Bash
# 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

Bash
# 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

Bash
# 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.0 appears
  • GitHub automatically creates a downloadable ZIP of the code at that tag
💡
Enable GitHub Pages

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

Why did the merge produce a "fast-forward" instead of a merge commit? +

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.

What if git push fails with "rejected"? +

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.

How do I add a .gitignore to this project? +

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").