What is Version Control?
Before writing a single Git command, you need to understand the problem it solves — and why it exists in the first place.
The Problem
Imagine you're writing code on a project. You make changes, and something breaks. Without version control, your only option is to frantically undo — or worse, rely on a backup folder called project_FINAL_v3_really_final2.
This is how most people start. It works, until it doesn't.
Manual versioning with folders is error-prone, wastes space, can't track what changed or why, and completely breaks down when more than one person is involved.
Enter Version Control
A Version Control System (VCS) is software that tracks changes to files over time. It lets you:
- Record every change, with a message explaining why
- Revert any file — or the whole project — to a previous state
- See exactly who changed what and when
- Work on multiple features simultaneously without conflict
- Collaborate with a team without overwriting each other
What is Git?
Git is the world's most widely used version control system. Created by Linus Torvalds in 2005 (the same person who created Linux), it is:
Git vs GitHub
This is a common point of confusion. They are not the same thing.
| Git | GitHub |
|---|---|
| git | Software tool — runs on your machine |
| github.com | A cloud platform that hosts Git repositories |
| Free & open source | Owned by Microsoft |
| Command-line tool | Website + web interface + collaboration features |
| The engine | The garage (where you park & share your engine) |
Git is like Microsoft Word's track-changes feature, but infinitely more powerful and for any type of file. GitHub is like Google Drive — it's where you store and share your Word documents.
Key Concepts to Know
Quick Check
What is the key difference between Git and GitHub?
Installing & Configuring Git
Get Git installed on your system and configured correctly before writing a single command.
Installation
Windows
Download the installer from git-scm.com. During setup, choose "Git from the command line and also from 3rd-party software" when prompted. This also installs Git Bash — a terminal emulator that works great on Windows.
macOS
# Option 1: via Homebrew (recommended) brew install git # Option 2: Xcode Command Line Tools xcode-select --install
Ubuntu / Debian Linux
sudo apt update && sudo apt install git -y
Verify Installation
git --version git version 2.44.0
Configure Your Identity
Before using Git, you must tell it who you are. This identity is embedded in every commit you make — it cannot be skipped.
# Set your name (use your real name) git config --global user.name "Your Name" # Set your email (use same email as your GitHub account) git config --global user.email "[email protected]" # Set your default editor (VS Code example) git config --global core.editor "code --wait" # Set the default branch name to 'main' (modern standard) git config --global init.defaultBranch main # Verify all settings git config --list
--global applies your setting to all repositories on your machine. Use --local inside a specific project folder to override settings just for that project (useful for work vs personal email).
Set Up SSH Authentication (Recommended)
SSH keys allow you to push to GitHub without typing a password every time. This is the professional setup.
ssh-keygen -t ed25519 -C "[email protected]" # Press Enter to accept default location # Optionally set a passphrase
# macOS cat ~/.ssh/id_ed25519.pub | pbcopy # Linux cat ~/.ssh/id_ed25519.pub # Then manually copy the output
Go to github.com → Settings → SSH and GPG Keys → New SSH Key. Paste your public key and save.
ssh -T [email protected] Hi yourusername! You've successfully authenticated.
Your First Repository
Learn the Git working model — the three stages every change goes through before becoming part of history.
The Three Stages
Understanding this model is fundamental. Every file in a Git repository is in one of these three states:
Files you edit
Snapshot prepared
Permanent history
- Working Directory — Where you actually edit files. Changes here are not tracked yet.
- Staging Area (Index) — A holding area. You choose exactly which changes go into the next commit.
- Repository (.git) — The permanent record. Once committed, changes are part of history.
Initializing a Repository
# Create a new project folder mkdir my-project && cd my-project # Initialize Git in this folder git init Initialized empty Git repository in /my-project/.git/ # Check current status (run this often!) git status On branch main Nothing to commit, working tree clean
git init creates a hidden .git/ folder inside your project. This is where Git stores everything — the entire history, configuration, and internal data. Never manually edit files inside it.
Adding Files & Making Your First Commit
# Create a file echo "# My Project" > README.md # Check status — Git sees an untracked file git status Untracked files: README.md # Stage the file (add to staging area) git add README.md # Stage ALL changed files at once git add . # Commit with a message git commit -m "Initial commit: add README" [main (root-commit) a3b4c5d] Initial commit: add README 1 file changed, 1 insertion(+)
The .gitignore File
Some files should never be committed — secrets, compiled output, dependencies, OS files. List them in a .gitignore file.
# Dependencies node_modules/ # Environment variables (NEVER commit secrets!) .env .env.local # Build output dist/ build/ # OS files .DS_Store Thumbs.db # IDE files .vscode/ *.suo
API keys, passwords, tokens, and .env files must always be in .gitignore. If you accidentally commit a secret, assume it's compromised — rotate it immediately. GitHub scans public repos for exposed secrets.
Essential Status Commands
| Command | What it does |
|---|---|
| git status | Show the state of your working directory and staging area |
| git diff | Show unstaged changes (what changed but not yet staged) |
| git diff --staged | Show staged changes (what's ready to commit) |
| git log | Show commit history |
| git log --oneline | Compact one-line history view |
Commits & History
Commits are the heartbeat of Git. Learn how to write great commit messages, navigate history, and undo mistakes safely.
Anatomy of a Commit
Every commit stores:
- A snapshot of all tracked files at that moment
- A unique SHA hash (e.g.
a3f4c5d) as its ID - Your name and email
- A timestamp
- A commit message
- A pointer to the parent commit (forming a chain)
Writing Great Commit Messages
A good commit message is a gift to your future self and your teammates.
Write your commit message to complete the sentence: "If applied, this commit will..."
→ "Add user authentication with JWT tokens" ✓
→ "Fix login bug" ✓
→ "stuff" ✗ "wip" ✗ "asdf" ✗
# Format: type(scope): description feat: add user login endpoint fix: resolve null pointer in auth middleware docs: update README installation guide style: format code with prettier refactor: extract payment logic into service class test: add unit tests for cart module chore: update dependencies to latest versions
Navigating History
# View full history git log # Compact one-liner view git log --oneline a3f4c5d feat: add login page b2e3d4c fix: correct form validation c1d2e3f docs: add README # Visual branch graph git log --oneline --graph --all # Show what changed in a specific commit git show a3f4c5d # See who last changed each line of a file git blame index.html
Undoing Mistakes
This is where Git really saves you. There are several ways to undo, depending on what you need.
| Situation | Command | Notes |
|---|---|---|
| git restore <file> | Discard unstaged changes | Permanently loses changes in working dir |
| git restore --staged <file> | Unstage a file | Keeps your changes, just removes from staging |
| git commit --amend | Fix the last commit | Only use before pushing! |
| git revert <hash> | Undo a commit safely | Creates a new "undo" commit — safe for shared repos |
| git reset --soft HEAD~1 | Undo last commit, keep staged | Commit disappears but files are staged |
| git reset --hard HEAD~1 | Undo last commit, discard files | ⚠️ Destructive — files are gone |
Never rewrite (amend, reset, rebase) commits that have already been pushed to a shared remote repository. This breaks history for everyone else. Only revert or add new commits instead.
Saving Work Temporarily — git stash
Need to switch context quickly but don't want to commit half-done work? Use stash.
# Save current changes to a temporary stack git stash # With a message git stash push -m "WIP: half-done payment form" # List all stashes git stash list # Restore the most recent stash git stash pop # Drop a stash without restoring git stash drop
Branching & Merging
Branches are Git's killer feature. They let you work on anything — bugs, features, experiments — completely independently, then bring it all together.
What is a Branch?
A branch is simply a lightweight, movable pointer to a specific commit. Creating a branch costs almost nothing — it's just a file with a commit hash in it. This is what makes Git branches radically different from older VCS systems.
Branch Commands
# List all branches (* marks current) git branch * main feature/login # Create a new branch git branch feature/login # Switch to a branch git switch feature/login # Create AND switch in one command (recommended) git switch -c feature/user-dashboard # Delete a branch (after merging) git branch -d feature/login # Force delete (even if not merged) git branch -D feature/login
Use feature/, fix/, hotfix/, chore/ prefixes followed by a short description. Examples: feature/user-auth, fix/login-crash, hotfix/payment-bug
Merging Branches
When your work on a branch is done, you merge it back into main (or another base branch).
# 1. Go to the branch you want to merge INTO git switch main # 2. Merge your feature branch in git merge feature/login Updating a3b4c5d..f6e7d8c Fast-forward login.html | 45 ++++++++++++ 1 file changed, 45 insertions(+) # 3. Delete the merged branch (clean up) git branch -d feature/login
Merge Conflicts
A conflict happens when two branches modify the same lines of the same file differently. Git can't decide which version to keep — it asks you.
<<<<<<< HEAD Welcome to the site! ======= Welcome to our platform! >>>>>>> feature/homepage
To resolve: edit the file to keep what you want (remove the conflict markers), then git add the file and git commit.
# After manually editing the conflicted file... git add index.html git commit -m "merge: resolve homepage text conflict"
Rebasing (Alternative to Merging)
Rebasing moves your branch's commits to start from the tip of another branch, creating a cleaner linear history. Use with caution on shared branches.
Only rebase branches that exist only on your local machine. Never rebase main or any branch others are working on. It rewrites commit history and causes chaos for teammates.
Remote Repositories
Connect your local work to the cloud. Push, pull, and sync with remote repositories hosted on GitHub.
What is a Remote?
A remote is a version of your repository hosted on a server (like GitHub). Your local repo can be linked to one or more remotes. The convention is to name your main remote origin.
local repo
remote repo
local repo
Connecting to a Remote
# Add a remote (after creating repo on GitHub) git remote add origin [email protected]:username/my-project.git # Verify remotes git remote -v origin [email protected]:username/my-project.git (fetch) origin [email protected]:username/my-project.git (push) # Push and set upstream tracking (first time) git push -u origin main # After that, just: git push
Cloning an Existing Repository
To download an existing project from GitHub to your machine:
# Clone via SSH (requires SSH key setup) git clone [email protected]:username/repo-name.git # Clone via HTTPS git clone https://github.com/username/repo-name.git # Clone into a specific folder name git clone [email protected]:username/repo.git my-folder
The Daily Sync Commands
| Command | What it does |
|---|---|
| git fetch | Download changes from remote WITHOUT merging — safe, just updates your remote-tracking branches |
| git pull | Download AND merge remote changes into your current branch (= fetch + merge) |
| git push | Upload your local commits to the remote |
| git push origin branch-name | Push a specific branch to remote |
| git pull --rebase | Pull and rebase instead of merge — keeps cleaner history |
Make it a habit: git pull before starting new work and before pushing. This reduces merge conflicts and keeps you in sync with your team.
Working with Remote Branches
# See all remote branches git branch -r # Checkout a remote branch locally git switch -c feature/api origin/feature/api # Push a local branch to remote git push origin feature/my-feature # Delete a remote branch git push origin --delete feature/old-branch
GitHub Essentials
GitHub is more than just a place to store code. It's a collaboration platform with powerful tools for managing projects and working with teams.
Creating a Repository on GitHub
Top-right corner → "+" icon → "New repository"
- Repository name — use kebab-case (e.g.
my-project) - Public or Private — Public is visible to everyone; Private is restricted
- Initialize with README — Check this if starting fresh
- Add .gitignore — Choose a template for your tech stack
- Choose a license — MIT is common for open source
git remote add origin [email protected]:you/repo.git git push -u origin main
Key GitHub Features
GitHub Issues — Best Practices
Issues are your project's task tracker. Use them well:
- Use Labels:
bug,enhancement,documentation,good first issue - Use Milestones to group issues into sprints or versions
- Reference issues in commits:
fix: resolve login crash (closes #42)— this auto-closes the issue on merge - Use Issue Templates to standardize bug reports and feature requests
GitHub Actions — Automation
GitHub Actions runs automated workflows (CI/CD pipelines) triggered by events like pushing code. Here's a minimal example:
name: Run Tests on: push: branches: [main] pull_request: jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: '20' - run: npm install - run: npm test
Every time someone pushes to main or opens a Pull Request, GitHub automatically installs dependencies and runs your tests. Failed tests block merging — this is Continuous Integration (CI).
Pull Requests
Pull Requests (PRs) are the standard way to propose, review, and merge code in any team. Master this and you master professional collaboration.
What is a Pull Request?
A Pull Request is a proposal to merge changes from one branch into another. It opens a discussion thread where teammates can:
- Review your code line-by-line
- Leave comments, suggestions, and approvals
- See automated test results
- Request changes before merging
Pull Requests don't exist in Git itself — they're a feature of GitHub (and similar platforms like GitLab, Bitbucket). In GitLab they're called Merge Requests — same concept, different name.
Creating a Pull Request
git switch -c feature/new-login # ... make your changes, commit them ... git push origin feature/new-login
Go to your repository on GitHub. You'll see a banner: "feature/new-login had recent pushes — Compare & pull request". Click it. Alternatively: Pull requests → New pull request.
A great PR description includes: what the changes do, why you made them, how to test them, and links to related issues.
Assign team members as reviewers. They'll comment, approve, or request changes. Address all feedback, push more commits if needed, then merge once approved.
PR Description Template
## What does this PR do? Adds JWT-based authentication to the login endpoint. ## Why? Closes #42 — Users reported session persistence issues. ## Testing 1. Run `npm test` — all 24 tests should pass 2. POST to `/api/login` with valid credentials 3. Check that JWT is returned and stored in cookie ## Screenshots [Optional: attach before/after screenshots] ## Checklist - [x] Tests added/updated - [x] Documentation updated - [x] No secrets or sensitive data committed
Code Review Best Practices
As the Reviewer
- Focus on logic, security, and maintainability — not personal style
- Ask questions rather than making demands: "Could this be extracted into a function?" vs "Do this."
- Distinguish blocking issues from non-blocking suggestions using labels (Nitpick, Suggestion, Blocker)
- Approve promptly — don't leave PRs sitting for days
As the Author
- Keep PRs small and focused — one feature or fix per PR
- Respond to all comments, even if you disagree (explain why)
- Don't take code review personally — it's about the code, not you
Merge Strategies
| Strategy | When to use | Result |
|---|---|---|
| Merge commit | Default — preserves all commits and history | Adds a merge commit |
| Squash and merge | Combine all PR commits into one clean commit on main | Cleaner main history |
| Rebase and merge | Apply commits linearly without a merge commit | Cleanest history, no merge commit |
Collaboration Workflows
Learn the team workflows used by professional developers — from open source contribution to enterprise development practices.
The Feature Branch Workflow
The most common workflow for teams. Simple, effective, and easy to enforce.
- Pull latest
main - Create a feature branch from
main - Commit your work on the feature branch
- Push the branch and open a Pull Request
- Reviewer approves → Merge into
main - Delete the feature branch
Gitflow Workflow
A more structured workflow with defined branch types. Common in projects with scheduled releases.
Forking Workflow (Open Source)
Used for contributing to open source projects where you don't have write access to the main repo.
Click "Fork" on GitHub — this creates your own copy of the repo under your account.
git clone [email protected]:YOUR_USERNAME/repo.git cd repo # Add the original repo as 'upstream' git remote add upstream [email protected]:ORIGINAL/repo.git
git switch -c fix/typo-in-readme # ... make changes ... git push origin fix/typo-in-readme
GitHub detects your push and offers to create a PR back to the original repository. The maintainer reviews and merges.
git fetch upstream git switch main git merge upstream/main git push origin main
Branch Protection Rules
On GitHub, you can protect important branches (like main) to enforce team policies:
- Require Pull Request reviews before merging
- Require status checks (tests) to pass before merging
- Require branches to be up-to-date before merging
- Prevent force-pushing or deleting the branch
- Restrict who can push to the branch
Set these at: Repository → Settings → Branches → Add branch protection rule
Pro Tips & Complete Cheatsheet
Power-user techniques, aliases, and the complete reference you'll keep coming back to.
Pro Tips
1 — Useful Git Aliases
git config --global alias.st status git config --global alias.co switch git config --global alias.br branch git config --global alias.lg "log --oneline --graph --all --decorate" git config --global alias.last "log -1 HEAD --stat" git config --global alias.undo "reset --soft HEAD~1" # Usage: git lg, git st, git co main, etc.
2 — Interactive Staging
# Stage only specific parts of a file (chunk by chunk) git add -p # Press y=yes, n=no, s=split chunk, e=edit manually
3 — Cherry-Pick
Apply a specific commit from one branch to another without merging the whole branch.
git cherry-pick a3f4c5d
4 — Find a Bug with git bisect
Binary search through commits to find which one introduced a bug.
git bisect start git bisect bad # current commit is broken git bisect good v1.2.0 # this tag was working # Git checks out the midpoint. Test it, then: git bisect good # or git bisect bad # Repeat until Git finds the culprit commit git bisect reset
5 — Reflog — Your Safety Net
Git's reflog records every movement of HEAD. Even after a reset, you can get your work back.
git reflog a3f4c5d HEAD@{0}: reset: moving to HEAD~1 b2e3d4c HEAD@{1}: commit: feat: add login page ... # Recover a "lost" commit git reset --hard b2e3d4c
Complete Cheatsheet
What to Learn Next
- GitHub CLI (
gh) — manage PRs, issues from your terminal - Signing commits with GPG — verified identity on GitHub
- GitHub Actions advanced — matrix builds, caching, deployment
- Semantic Versioning + tags — structured release management
- Monorepo tooling — Turborepo, Nx for large projects
- Git hooks — run scripts automatically on commit, push (use with Husky)
Final Knowledge Check
A teammate committed sensitive API keys to the shared main branch and pushed. What's the correct first step?
You've completed the module!
You now have the foundational knowledge to use Git and GitHub professionally. The best way to cement this: use it daily, on every project, starting today.