🐙 Latest Edition
📖 Beginner to Advanced
⏱️ 50 min read
🎯 22+ Sections

⏱️ Estimated reading time: 45-50 minutes

📋 Quick Summary: Git is used by 94% of developers. GitHub hosts 200M+ repositories. Whether you’re a solo dev or part of a 10,000-person team, Git + GitHub is the standard for version control. This course takes you from zero to collaboration expert — commits, branches, pull requests, merge conflicts, CI/CD, GitHub Actions, open source contributions, and real-world workflows.

(Table of Contents)

🐙 What Is Git & GitHub?

Git is a distributed version control system created by Linus Torvalds (yes, the Linux guy) in 2005. It tracks changes to your code, lets you go back in time, and enables multiple people to work on the same project without stepping on each other’s toes.

GitHub is a cloud platform that hosts Git repositories. It adds collaboration features on top of Git: pull requests, issues, project boards, CI/CD, code reviews, and more.

Git vs GitHub — The Difference

Git (Tool) GitHub (Platform)
Runs locally on your machine Cloud service (github.com)
CLI tool with commands Web UI + API
Free & open source Free for public repos, paid plans for private
Works offline, fully without GitHub Requires internet
Alternatives: Mercurial, SVN Alternatives: GitLab, Bitbucket, Gitea

🔧 Installing Git

# Linux (Ubuntu/Debian)
sudo apt update && sudo apt install git -y

# Linux (Fedora/RHEL)
sudo dnf install git -y

# macOS
brew install git        # With Homebrew
# Or download from git-scm.com

# Windows
# Download from git-scm.com or:
winget install Git.Git

# Check installation
git --version

# First-time setup — THIS IS MANDATORY
git config --global user.name "Your Name"
git config --global user.email "your@email.com"
git config --global core.editor "vim"   # Or "code --wait" for VS Code

# View your config
git config --list
git config --global --list
cat ~/.gitconfig

📦 Git Basics — Your First Repository

Creating a Repository

# Option 1: Initialize a new repo
mkdir my-project
cd my-project
git init            # Creates .git/ directory — this IS the repository

# Option 2: Clone an existing repo
git clone https://github.com/user/repo.git
git clone git@github.com:user/repo.git  # SSH (recommended)
git clone --depth 1 https://github.com/user/repo.git  # Shallow clone (no history)

# Check status
git status          # The most-used command — shows what's happening

Your First Commit

# Create a file
echo "# My Project" > README.md
echo "node_modules/" > .gitignore

# Check what's happening
git status
# Output shows:
#   Untracked files: README.md, .gitignore (files Git doesn't know about)

# Stage files (add to the "staging area")
git add README.md              # Stage one file
git add .gitignore             # Stage another
git add .                      # Stage ALL changes (careful!)
git add *.py                   # Stage all Python files

# Commit (save a snapshot)
git commit -m "Initial commit: add README and gitignore"

# Shortcut: stage + commit in one command
git commit -am "Fix bug in login"   # Only works for TRACKED files

The Three States

Files in Git exist in one of three states:

# 1. MODIFIED — You changed the file, but haven't staged it
# 2. STAGED — You marked the file to be in the next commit (git add)
# 3. COMMITTED — The snapshot is saved in the repository (git commit)

# Workflow:
# Working Directory → git add → Staging Area → git commit → Repository (.git/)
#     Modified                Staged                   Committed

💾 Viewing History & Snapshots

# View commit history
git log                     # Full history (press q to quit)
git log --oneline           # One line per commit
git log --oneline --graph   # Show branch structure graphically
git log --oneline --all     # Show all branches
git log -5                  # Last 5 commits
git log --author="Alice"    # Commits by specific author
git log --since="2024-01-01" --until="2024-06-01"
git log --grep="fix"        # Commits with "fix" in message

# View changes
git diff                    # Unstaged changes (modified but not added)
git diff --staged           # Staged changes (added but not committed)
git diff HEAD               # Changes since last commit
git diff branch1..branch2   # Differences between branches

# View a specific commit
git show abc1234            # Show commit abc1234 details
git show HEAD               # Show latest commit
git show HEAD~1             # Show second-to-last commit
git show HEAD:file.txt      # Show file as it was in HEAD commit

# View a file as it existed in history
git log --oneline -- README.md    # History of one file
git show abc1234:README.md        # File at specific commit
git show HEAD~3:src/app.py        # File 3 commits ago

↩️ Undoing Changes

Unstaging & Unmodifying

# Unstage a file (keep changes)
git restore --staged file.txt    # Old: git reset HEAD file.txt

# Discard changes in working directory (⚠️ permanent!)
git restore file.txt             # Old: git checkout -- file.txt
git restore .                    # Restore ALL files (dangerous!)

# Unstage AND discard changes
git restore --staged file.txt    # Unstage
git restore file.txt             # Discard changes
# Or in one step:
git checkout -- file.txt         # (Old way, still works)

Amending the Last Commit

# Change the commit message
git commit --amend -m "Better message"

# Add forgotten files to last commit
git add forgotten-file.txt
git commit --amend --no-edit     # Add to last commit without changing message

# ⚠️ Never amend commits that have been pushed to a shared branch!
# (It rewrites history — makes collaborators cry)

Reset vs Revert

# git reset — MOVES the branch pointer (rewrites history)
# ⚠️ Only use on LOCAL, NOT-YET-PUSHED commits

# --soft: Keep changes staged
git reset --soft HEAD~1          # Undo last commit, keep changes staged

# --mixed (default): Keep changes in working directory
git reset HEAD~1                 # Undo last commit, keep changes unstage

# --hard: Discard everything (⚠️ permanent!)
git reset --hard HEAD~1          # Undo last commit, discard changes entirely
git reset --hard origin/main     # Reset local branch to match remote

# git revert — Creates a NEW commit that undoes the old one (SAFE for shared branches)
git revert abc1234               # Create new commit that undoes abc1234
git revert HEAD                  # Undo latest commit
git revert HEAD~3..HEAD          # Undo last 3 commits
# git revert is the SAFE way to undo published work

🌿 Branching — The Superpower

Branches let you work on features, fixes, or experiments in isolation without affecting the main codebase.

Branch Basics

# List branches
git branch                  # Local branches (current branch has *)
git branch -r               # Remote branches
git branch -a               # All branches (local + remote)

# Create branches
git branch feature-login    # Create branch (stay on current)
git checkout -b feature-login  # Create AND switch to it
git switch -c feature-login    # Modern way (Git 2.23+)

# Switch branches
git checkout main           # Old way
git switch main             # Modern way

# Delete branches
git branch -d feature-login       # Delete merged branch (safe)
git branch -D feature-login       # Force delete (even if unmerged)

# Rename branch
git branch -m old-name new-name

Merging

# Merge a branch into your current branch
# First, switch to the target branch (e.g., main)
git switch main
git merge feature-login

# Three types of merges:
# 1. Fast-forward (no new commit needed — straight line)
# 2. 3-way merge (creates a merge commit)
# 3. Squash merge (combines all commits into one)

Merge Conflicts

Conflicts happen when two branches change the same part of the same file. Git can’t decide which version wins — you have to tell it.

# When you get a merge conflict:
git merge feature-other
# Output: CONFLICT (content): Merge conflict in README.md

# Git marks the conflict in the file:
# <<<<<<< HEAD
# This is the main branch version
# =======
# This is the feature branch version
# >>>>>>> feature-other

# To resolve:
# 1. Open the file in an editor
# 2. Choose one side, edit both, or write something new
# 3. Remove the conflict markers (<<<, ===, >>>)
# 4. Stage the resolved file
git add README.md
git merge --continue         # Complete the merge
# OR
git commit                   # Complete the merge commit

# To abort a merge and go back
git merge --abort

# Visual merge tools
git mergetool                # Opens configured tool (vimdiff, vscode, meld)
git config --global merge.tool vscode
git config --global mergetool.vscode.cmd 'code --wait $MERGED'

🌐 Working with Remotes (GitHub)

Connect Local Repo to GitHub

# Create a repo on GitHub first (empty, no README), then:

# Link local repo to remote
git remote add origin https://github.com/yourusername/repo.git
git remote add origin git@github.com:yourusername/repo.git  # SSH (recommended)

# Verify remote
git remote -v               # List remotes with URLs

# Push to GitHub
git push -u origin main     # First push (-u sets upstream track)
git push origin main        # Subsequent pushes

# Push a branch to GitHub
git push origin feature-login

# Push all branches
git push origin --all

# Delete remote branch
git push origin --delete feature-login

Pulling & Fetching

# git fetch — Downloads changes but DOESN'T apply them
git fetch origin            # Get latest from remote
git fetch --prune           # Remove stale remote-tracking branches
git log origin/main         # See what's new without merging

# git pull — fetch + merge (download and apply)
git pull origin main        # Pull from remote (fetch + merge)
git pull                    # If upstream is set

# Better safe workflow:
git fetch origin
git log origin/main..main   # See what YOU have that remote doesn't
git diff origin/main        # See differences
git pull origin main        # Only then, pull

# Pull with rebase (cleaner history — recommended)
git pull --rebase origin main

# Set rebase as default
git config --global pull.rebase true

SSH Keys for GitHub

# Generate SSH key
ssh-keygen -t ed25519 -C "your@email.com"

# Start SSH agent
eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519

# Copy public key
cat ~/.ssh/id_ed25519.pub
# → Add to GitHub: Settings → SSH and GPG keys → New SSH key

# Test connection
ssh -T git@github.com
# → "Hi username! You've successfully authenticated..."

🔄 Pull Requests

Pull Requests are the heart of GitHub collaboration. They let you propose changes, discuss them, and merge them into the main branch.

Creating a Pull Request

# 1. Create a branch for your feature
git switch -c feature-user-auth

# 2. Make changes and commit
git add .
git commit -m "Add user authentication"

# 3. Push the branch to GitHub
git push -u origin feature-user-auth

# 4. On GitHub.com, you'll see a notification:
#    "feature-user-auth had recent pushes" — click "Compare & pull request"

# 5. Fill in:
#    Title: Clear description of the change
#    Description: What, why, how, testing notes
#    Reviewer: @teammate (optional)
#    Labels: bug, enhancement, etc.
#    Project: Link to project board

# 6. Create Pull Request

PR Best Practices

  • Keep PRs small — Under 200 lines of code when possible. Large PRs are hard to review and more likely to have bugs.
  • One PR = One feature/bugfix — Don’t mix refactoring with new features. Keep changes focused.
  • Write good descriptions — Explain what the PR does, why it’s needed, and how to test it.
  • Link issues — Use “Fixes #42” in the description to auto-close issues.
  • Rebase before merging — Keep a linear history: git rebase main.
  • Request reviews — Don’t merge your own PRs without review on team projects.

Reviewing a PR

# Check out someone's PR locally
git fetch origin pull/42/head:pr-42    # Fetch PR #42
git switch pr-42                       # Check it out

# Or use GitHub CLI
gh pr checkout 42                      # Much simpler

# Review the diff
git diff main...HEAD                  # Changes since branching from main

# Provide feedback
# In GitHub UI: Comment, Approve, or Request Changes

💡 Pro Tip: Use gh pr create to create PRs from the command line. Install the GitHub CLI: sudo apt install gh on Linux, brew install gh on macOS, then gh auth login.

🏗️ Branching Workflows

GitHub Flow (Simplest, Most Popular)

# Main branch (main) is always deployable
# Create feature branches from main
# Open PR → Review → Merge back to main → Deploy

main:  A---B---C---D---E
           \         /
feature:    X---Y---Z

# Used by: GitHub, Netflix, Shopify, many startups

Git Flow (More Structured, For Releases)

# Branches:
#   main       — Production (never commit directly)
#   develop    — Integration branch
#   feature/*  — New features (branch from develop)
#   release/*  — Preparing a release (branch from develop, merge to main)
#   hotfix/*   — Critical fixes (branch from main, merge to both)

# Used by: Larger teams, planned releases, enterprise

Trunk-Based Development (For CI/CD)

# All developers commit to main (trunk) multiple times a day
# Feature flags hide incomplete features
# Short-lived feature branches (max 2 days)
# Always rebase before pushing

# Used by: Google, Facebook, Amazon (high CI/CD velocity)

🏷️ Tags & Releases

# Tags mark specific points in history (usually releases)

# Create a lightweight tag
git tag v1.0.0

# Create an annotated tag (recommended — includes metadata)
git tag -a v1.0.0 -m "Production release v1.0.0"

# List tags
git tag                     # Alphabetical list
git tag -l "v2.*"           # Tags matching pattern

# Push tags to GitHub
git push origin v1.0.0      # Push specific tag
git push origin --tags      # Push ALL tags

# Delete tag
git tag -d v1.0.0                    # Delete local
git push origin --delete v1.0.0      # Delete remote

# Checkout a tag (detached HEAD state)
git checkout v1.0.0
# To make changes from a tag, create a branch:
git switch -c hotfix-from-v1.0.0

# Create a GitHub Release from a tag
gh release create v1.0.0 --title "v1.0.0" --notes "First stable release"
# GitHub Releases add release notes + downloadable binaries

Semantic Versioning (SemVer)

# Format: MAJOR.MINOR.PATCH
#   MAJOR — Breaking changes (incompatible API changes)
#   MINOR — New features (backward compatible)
#   PATCH — Bug fixes (backward compatible)

# Examples:
# v1.0.0    — First stable release
# v1.1.0    — New feature added
# v1.1.1    — Bug fix
# v2.0.0    — Breaking change
# v1.0.0-alpha.1   — Pre-release
# v1.0.0-beta.2    — Beta release

🙈 .gitignore — What NOT to Commit

# .gitignore tells Git which files to ignore (never tracked)

# OS files
.DS_Store
Thumbs.db

# Dependencies
node_modules/
vendor/
venv/
__pycache__/
*.pyc
.env

# Build output
dist/
build/
*.exe
*.dll

# IDE files
.idea/
.vscode/
*.swp
*.swo

# Logs
*.log
npm-debug.log*

# Environment files (keep template, commit actual .env)
.env
.env.local
.env.production

# Get ready-made .gitignore templates:
# https://www.toptal.com/developers/gitignore
# Or use: npx gitignore node
# If you accidentally committed something you shouldn't have:
git rm --cached secret.txt       # Remove from tracking, keep locally
echo "secret.txt" >> .gitignore  # Add to gitignore
git commit -m "Remove secret from tracking"

⚡ GitHub Actions — CI/CD

GitHub Actions automates your workflow — test, build, and deploy directly from GitHub.

Your First Workflow

# Create: .github/workflows/ci.yml
name: CI

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

jobs:
  test:
    runs-on: ubuntu-latest
    
    steps:
    - uses: actions/checkout@v4
    
    - name: Set up Python
      uses: actions/setup-python@v5
      with:
        python-version: '3.12'
    
    - name: Install dependencies
      run: |
        python -m pip install --upgrade pip
        pip install -r requirements.txt
    
    - name: Run tests
      run: pytest

    - name: Lint
      run: flake8 .

Deploy to Production

# .github/workflows/deploy.yml
name: Deploy

on:
  push:
    branches: [ main ]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v4
    
    - name: Build and push Docker
      run: |
        docker build -t myapp .
        docker tag myapp ghcr.io/myorg/myapp:latest
        docker push ghcr.io/myorg/myapp:latest
    
    - name: Deploy to server
      uses: appleboy/ssh-action@v1
      with:
        host: ${{ secrets.SERVER_HOST }}
        username: ${{ secrets.SERVER_USER }}
        key: ${{ secrets.SSH_PRIVATE_KEY }}
        script: |
          cd /opt/myapp
          docker pull ghcr.io/myorg/myapp:latest
          docker compose up -d

GitHub Actions Secrets

Store secrets in GitHub: Settings → Secrets and variables → Actions → New repository secret

# Access secrets in workflows
${{ secrets.SERVER_HOST }}
${{ secrets.AWS_ACCESS_KEY_ID }}
${{ secrets.DOCKER_PASSWORD }}

# DO NOT hardcode secrets in code!
# NEVER commit .env files with real passwords

🚀 Advanced Git

Rebase — Clean Up History

# Rebase replays your commits on top of another branch
# Creates a linear history (no merge commits)

# Instead of:
git pull origin main          # Creates a merge commit
git push origin feature

# Do:
git fetch origin
git rebase origin/main        # Replay your commits on top of latest main
git push origin feature       # --force needed if you already pushed!

# Interactive rebase — clean up commits before merging
git rebase -i HEAD~5          # Rewrite last 5 commits
# Options:
#   pick   — Keep commit as-is
#   squash — Combine with previous commit (merge messages)
#   fixup  — Combine with previous commit (discard message)
#   reword — Change commit message
#   edit   — Edit the commit
#   drop   — Delete commit

# The golden rule: NEVER rebase commits that have been PUSHED to a shared branch

Stashing — Temporary Save

# Save uncommitted work temporarily (to switch branches, etc.)
git stash                         # Save changes
git stash push -m "WIP: login"    # Save with message

# List stashes
git stash list                    # stash@{0}: On feature: WIP: login

# Apply stash
git stash pop                     # Apply + remove from stash list
git stash apply                   # Apply + keep in stash
git stash apply stash@{1}         # Apply specific stash

# Drop stash
git stash drop                    # Remove latest stash
git stash drop stash@{1}          # Remove specific stash
git stash clear                   # Remove ALL stashes

# Stash only specific files
git stash push -m "config changes" config.yaml

# Create a branch from stash
git stash branch new-branch stash@{0}

Cherry-Pick — Selective Commits

# Apply specific commits from another branch (without full merge)
git cherry-pick abc1234              # Apply commit abc1234 to current branch
git cherry-pick abc1234..def5678     # Apply a range of commits

# Cherry-pick with conflict handling:
git cherry-pick abc1234
# If conflicts:
git mergetool
git cherry-pick --continue
# OR
git cherry-pick --abort

Bisect — Find the Bug

# Binary search through commits to find where a bug was introduced
git bisect start
git bisect bad          # Current commit is broken
git bisect good v1.0    # v1.0 was working

# Git checks out a commit in the middle. Test it.
git bisect good         # If this commit works
git bisect bad          # If this commit is broken

# Repeat until Git identifies the first bad commit
git bisect reset        # Back to normal after finding it

🏗️ Real-World Project: Open Source Contribution

Let’s walk through a real open source contribution from start to finish.

Step 1: Fork & Clone

# Fork the repo on GitHub (click "Fork" button)

# Clone YOUR fork (not the original)
git clone git@github.com:yourusername/original-repo.git
cd original-repo

# Add upstream remote (the original repo)
git remote add upstream https://github.com/original-author/original-repo.git

# Verify
git remote -v
# origin    git@github.com:yourusername/original-repo.git (fetch)
# origin    git@github.com:yourusername/original-repo.git (push)
# upstream  https://github.com/original-author/original-repo.git (fetch)
# upstream  https://github.com/original-author/original-repo.git (push)

Step 2: Create a Feature Branch

# Always start from updated main
git switch main
git pull upstream main          # Get latest from original repo
git push origin main            # Sync your fork

# Create feature branch
git switch -c fix-typo-readme

# Make changes, commit
echo "# Project Name - The Best Tool" > README.md
git add README.md
git commit -m "docs: fix typo in README title"

Step 3: Push & Open PR

# Push to your fork
git push -u origin fix-typo-readme

# On GitHub, open a Pull Request:
# Base: original-author/main ← Compare: yourusername/fix-typo-readme

# Or use GitHub CLI:
gh pr create --title "docs: fix typo in README title" --body "Fixed a typo in the project description" --base main

# If reviewer asks for changes:
# Make changes locally
git add .
git commit -m "address review: update title phrasing"
git push origin fix-typo-readme

Step 4: Keep Your Fork Updated

# Regularly sync with upstream
git switch main
git fetch upstream
git rebase upstream/main     # Or: git merge upstream/main
git push origin main

❌ Common Mistakes & How to Fix Them

🔴 Mistake #1: Committing to Main

What happens: You committed directly to main instead of a feature branch.

How to fix: git switch -c feature-branch to create and move to a new branch (the commits come with you). Then git push origin feature-branch.

🔴 Mistake #2: Committing Secrets

What happens: You committed an API key or password to a public repo.

How to fix: git rm --cached .env, add to .gitignore, commit. Then: Rotate the API key immediately. Even if you remove it, it’s still in the history. Consider git filter-repo or BFG Repo Cleaner for deep removal.

🔴 Mistake #3: Force Pushing to Shared Branches

What happens: You rebased and force-pushed a branch others were working on. Their local repos are now out of sync and they hate you.

How to fix: Apologize. Then git fetch and git rebase --onto to recover. Better yet: only force-push to personal branches.

🔴 Mistake #4: Forgetting to Pull Before Pushing

git push origin main
# → ! [rejected] because remote has changes you don't have

# Fix:
git fetch origin
git rebase origin/main        # Or git merge origin/main
git push origin main

# Better habit: always pull/rebase before starting work
git pull --rebase origin main

🔴 Mistake #5: Large Files in Git

What happens: You committed a 500MB dataset. Now every clone is slow and the repo size is 5GB.

How to fix: Remove the file from history with git filter-branch or BFG. Then use Git LFS (Large File Storage) for binary files: git lfs track "*.psd", git lfs track "*.zip".

💡 Pro Tip: git reflog is your safety net. It logs every move Git makes. Even after git reset --hard, you can find your lost commits with git reflog and recover with git checkout HEAD@{index}.

🧠 Test Your Knowledge

  1. What does git status show?

    A) Your commit history

    B) Current state of working directory and staging area

    C) Differences between branches

    D) Network status

    Answer: B — Shows which files are staged, unstaged, or untracked.
  2. What’s the difference between git reset --soft and --hard?

    A) No difference

    B) –soft keeps changes staged, –hard discards everything

    C) –soft is faster, –hard is safer

    D) –soft only works on main

    Answer: B — –soft keeps changes in staging, –hard removes everything permanently.
  3. Which command creates a branch AND switches to it?

    A) git branch new-feature

    B) git checkout -b new-feature

    C) git switch new-feature

    D) git create new-feature

    Answer: B — git checkout -b (or git switch -c) creates and switches.
  4. How do you undo a commit that’s already been pushed to a shared branch?

    A) git reset --hard HEAD~1 && git push --force

    B) git revert HEAD && git push

    C) git delete HEAD~1

    D) git undo

    Answer: B — Use git revert to create a new commit that undoes the old one. Safe for shared branches.
  5. What does git stash do?

    A) Deletes your changes permanently

    B) Temporarily saves uncommitted changes

    C) Hides files from the repository

    D) Creates a backup

    Answer: B — Stash saves work-in-progress changes temporarily so you can switch branches.

❓ Frequently Asked Questions (FAQ)

Q1: What’s the difference between git pull and git fetch?

git fetch downloads the latest changes from the remote but doesn’t apply them to your working directory. git pull does fetch + merge (or fetch + rebase with --rebase). Fetch first if you want to see what’s new before merging.

Q2: How do I recover a deleted branch?

git reflog — find the commit hash where the branch pointed. Then git branch recovered-branch abc1234. If the branch was pushed to remote: git checkout -b branch-name origin/branch-name.

Q3: Should I use merge or rebase?

Use merge when merging a feature back to main (preserves history of what happened). Use rebase to keep a linear history on your feature branch before merging. Personal rule: rebase your branch before merging, use merge commits when bringing features into main.

Q4: How do I contribute to open source on GitHub?

Find projects with “good first issue” labels. Fork the repo, clone your fork, create a branch, make changes, push, and create a Pull Request. Start with documentation fixes or small bug fixes to learn the workflow. Check CONTRIBUTING.md in the repo for specific guidelines.

Q5: How do I fix a merge conflict?

Git marks the conflicted file with . Open the file, choose the correct version (or edit both), remove the markers, then git add file.txt and git merge --continue. Use git mergetool for a visual interface.

Q6: What if I committed to the wrong branch?

git switch -c correct-branch — this moves the commits to a new branch. Then switch back to the old branch and git reset --hard HEAD~N to remove the commits from the wrong branch. Or use git cherry-pick to copy commits to the right branch.

Q7: How do I clone only the latest commit (not full history)?

git clone --depth 1 https://github.com/user/repo.git — shallow clone. Great for CI/CD and large repos. If you need history later: git fetch --unshallow.

Q8: How do I rename a branch?

git branch -m old-name new-name. If already pushed: git push origin --delete old-name and git push -u origin new-name.

Q9: What is a detached HEAD state?

When you checkout a specific commit (not a branch), you’re in “detached HEAD” state. Changes you commit here won’t belong to any branch and can be lost. If you make changes, create a branch: git switch -c new-branch to save them.

Q10: How do I permanently remove a file from Git history?

Use git filter-branch or the much faster bfg (BFG Repo Cleaner): bfg --delete-files secret.txt. Then git push --force. This rewrites history completely. Coordinate with all collaborators before doing this.

📖 Glossary

Term Definition
Commit A snapshot of your files at a point in time
Branch An independent line of development
HEAD A pointer to the current commit (where you are right now)
Remote A Git repository hosted somewhere else (e.g., GitHub)
Origin Default name for your primary remote (your fork)
Upstream The original repository you forked from
Staging Area Where files go before a commit (index)
Merge Conflict When two branches modified the same part of a file differently
Fork Your personal copy of someone else’s repo on GitHub
Reflog A log of every HEAD movement — your safety net

✅ Do’s & Don’ts

✅ Do ❌ Don’t
Commit often with meaningful messages Commit everything with “fix” or “update”
Create feature branches for changes Commit directly to main
Pull before starting work Force push to shared branches
Write clear PR descriptions Open PRs with no description
Use .gitignore from the start Commit node_modules, venv, .env files
Use SSH keys for auth Use password-based Git auth
Keep PRs small and focused Merge your own PRs without review

💡 10 Pro Tips Learned the Hard Way

  1. Use git log --graph --oneline --all daily. This shows the entire branch structure. Make it an alias: git config --global alias.tree 'log --graph --oneline --all'. Then just git tree.
  2. Write good commit messages. First line is a subject (50 chars max). Then a blank line, then a body explaining WHY (not what). What is obvious from the code. Why is not. Follow the 50/72 rule: 50 chars for subject, 72 for body lines.
  3. Use branches for everything. Every feature gets a branch. Every bugfix gets a branch. It’s frictionless and undoable. git switch -c is faster than thinking “I won’t branch this time.”
  4. Master git reflog. git reflog saves you from almost every mistake. Accidentally reset –hard? Reflog has your commits. Deleted a branch? Reflog has it. It’s your emergency parachute.
  5. Never force push to shared branches. If you must, warn the team first. And use --force-with-lease instead of --force — it checks if the remote changed since you last fetched.
  6. Use gh (GitHub CLI). gh pr create, gh pr checkout 42, gh pr merge, gh release create. It’s faster than the web UI for common tasks.
  7. Keep commits small and focused. “One commit = one logical change.” It makes git log, git bisect, and code reviews easier. Use interactive rebase to squashing messy commits before pushing.
  8. Learn git aliases. Put these in ~/.gitconfig: co = checkout, br = branch, ci = commit, st = status, lg = log --graph --oneline --all, fixup = commit --amend --no-edit. Saves thousands of keystrokes.
  9. Don’t commit half-broken code. Each commit should be a complete, working state. This makes git bisect and git revert work reliably. If you need to save WIP, use git stash or a WIP branch.
  10. Document your branching strategy. Whether you use GitHub Flow, Git Flow, or trunk-based — write it down in CONTRIBUTING.md. It prevents confusion and helps new team members onboard.

🗺️ Learning Roadmap

Day Topic Goal ⏱️
1 Git Basics Install, config, init, clone, add, commit, status, log 60 min
2 Undoing & Diff restore, reset, revert, amend, diff, show 60 min
3 Branching & Merging branch, checkout, merge, merge conflicts 90 min
4 Remote & Collaboration remote, push, pull, fetch, SSH keys, PR workflow 90 min
5 GitHub Features Issues, PRs, code review, project boards, wiki 90 min
6 Advanced Git rebase -i, stash, cherry-pick, bisect, reflog, tags 120 min
7 CI/CD & Open Source GitHub Actions, fork/PR workflow, open source contribution 120 min

🔍 Troubleshooting

⚠️ Problem 🔍 Cause ✅ Solution
“Permission denied (publickey)” SSH key not added to GitHub Run ssh -T git@github.com, add public key to GitHub settings
Merge conflict nightmare Long-lived branches diverging too much Rebase frequently. Keep branches short-lived. Use smaller PRs.
Push rejected (non-fast-forward) Remote has changes you don’t have locally git fetch && git rebase origin/main && git push
Committed and want to undo Wrong commit or wrong message Not pushed: git reset --soft HEAD~1. Pushed: git revert HEAD
Git is slow with large files Large binaries in repository Use Git LFS. Remove large files from history with BFG.

💬 What’s Your Git Story?

What’s your Git story? First merge conflict panic? That time you force-pushed to main by accident? Drop a comment — every developer has been there.

Quick questions:

  • What was your most memorable Git disaster?
  • Merge vs Rebase — which camp are you in?
  • What Git command do you wish existed?
  • What took you the longest to learn?

📌 TL;DR: If You Learn Nothing Else, Learn These 5

  1. Commit Flowgit statusgit add .git commit -m "msg"git push. This is 80% of what you do.
  2. Branchinggit switch -c feature-branch for everything. Never commit directly to main.
  3. Pull Requests — Small PRs with good descriptions. Review before merging. Always sync with upstream first.
  4. Undoing Mistakes — Not pushed? git reset. Pushed? git revert. Panic? git reflog.
  5. Merge Conflicts — They’re normal. Open the file, fix the markers, git add, git merge --continue. Done.

More Free Courses on TricksPage

💭 Final Thoughts

Git is the most important tool you’ll learn as a developer — not a framework, not a language, but version control. It’s the safety net that lets you experiment without fear. It’s the collaboration tool that makes teamwork possible across time zones and continents.

🔥 Final Word: “Git is the duct tape of the internet. Everything eventually ends up held together by it.” — Anon

Now go commit something. 🐙

More Free Courses on TricksPage

If this course helped you:

  • 📌 Bookmark this page for future reference
  • 📤 Share it with someone who needs it
  • 💬 Leave a comment — I read every one
  • Follow the blog for more deep courses

Leave a Reply

Your email address will not be published. Required fields are marked *