Git & GitHub
From Zero to Pro
Master version control — the one skill every developer needs, regardless of language or field.
Never Lose Work Again
Every commit is a save point. Break something? Jump back to any moment in your project's history in seconds.
Your GitHub = Your Resume
Recruiters look at GitHub profiles. Active, well-structured repos demonstrate real-world skills better than a bullet point on paper.
Work Like a Pro
Every tech company — from startups to FAANG — uses Git. Learning it now means zero friction when you join a team.
Core Concepts & Setup
- Git vs GitHub — what's the difference
- Install and configure Git
- Key vocabulary explained simply
Your First Commits
- git init, add, commit explained
- The staging area — why it exists
- Reading git log and git status
Connect to GitHub
- Push your repo to GitHub
- git push, pull, clone, fetch
- Authentication with PAT & SSH
Branching
- Create and switch branches
- Merge branches together
- Resolve merge conflicts step-by-step
Collaboration & PRs
- Fork vs clone explained
- Open and review Pull Requests
- Issues, code review best practices
When Things Go Wrong
- Undo changes safely (restore, reset, revert)
- .gitignore — never commit secrets
- Fix: push rejected, detached HEAD, and more
GitHub Actions
- What CI/CD means and why it matters
- Write your first workflow YAML
- Auto-run tests on every push
Advanced Git
- git stash, rebase, cherry-pick
- Tags, releases, aliases
- git bisect — find the commit that broke things
Cheat Sheet
- Every command, organized by category
- Copy-to-clipboard on each command
- Quick reference during any project
The Problem Git Solves
What is Git?
Git vs GitHub — not the same thing
| Git | GitHub |
|---|---|
| Software on your computer | A website (github.com) |
| Tracks history of your files | Hosts your repos online |
| Works 100% offline | Enables collaboration & sharing |
| Free, open-source tool | Free plan + paid tiers |
Key Vocabulary
| Term | Plain English |
|---|---|
| repository (repo) | A folder Git is tracking — contains your project + all its history |
| commit | A saved snapshot of your project at one moment in time |
| branch | A parallel version of your code — like a separate timeline |
| merge | Combining two branches back together |
| remote | A copy of your repo stored somewhere else (usually GitHub) |
| clone | Download a remote repo to your computer for the first time |
| fork | Copy someone else's repo into your own GitHub account |
| pull request (PR) | A proposal to merge your changes into someone else's branch |
| HEAD | A pointer to the commit you're currently on |
Install & Configure Git
git --version # if not found, macOS will prompt you to install # OR install via Homebrew: brew install git
# Download and install from: https://git-scm.com/downloads
# Opens "Git Bash" — use that as your terminal
sudo apt update && sudo apt install git
git config --global user.name "Your Name" git config --global user.email "you@example.com" git config --global init.defaultBranch main # modern default
git config --list
- Install Git and open a terminal
- Run
git config --global user.name "Your Name" - Run
git config --global user.email "you@example.com" - Create a free account at github.com
The Three Areas of Git
git sees them as "modified"
ready to be saved
in Git history forever
Staging lets you choose exactly which changes go into a commit — even from the same file.
Staging area — a box on the desk, files you've put in to mail.
Repository — the post office archive, files that have been sent & recorded forever.
Core Commands
mkdir my-tech-wiki cd my-tech-wiki git init
A hidden .git/ folder is created — this is where Git stores all history. Never delete it.
# My Tech Wiki A personal wiki where I document things I learn about Git and GitHub. ## Topics - Git basics
git status
Red means Git sees the file but is not tracking it yet.
git add README.md # stage one file # OR stage everything in the folder: git add .
git add . stages everything — be careful not to accidentally stage passwords or secrets. We'll set up .gitignore in Module 5.git commit -m "Initial commit: add README"
git log --oneline # compact view — one line per commit
"Add login page", "Fix typo in README", "Remove unused imports". Future-you will thank past-you."Nothing to commit, working tree clean" — Git sees no changes since the last commit. Edit a file first, then add and commit.
"fatal: not a git repository" — You're in the wrong folder. Run git init first, or cd into your project directory.
I forgot to include a file in my last commit — Stage the file and run:
git add forgotten-file.txt git commit --amend --no-edit # adds to the LAST commit
"Please tell me who you are" error — Run git config from Module 0 to set your name and email.
- Create a folder called
my-tech-wikiand rungit initinside it - Create a
README.mdwith your name and a one-line description - Stage and commit it:
git add README.mdthengit commit -m "Initial commit" - Create a file
git-basics.md, add 3 things you learned, commit it - Run
git log --onelineand see your two commits
git clone = first-time download | git fetch = download without merging yet
Push your local repo to GitHub
Go to github.com → "+" → New repository.
Name it my-tech-wiki. Keep it public. Do not add a README (you already have one).
# Replace YOUR-USERNAME with your GitHub username git remote add origin https://github.com/YOUR-USERNAME/my-tech-wiki.git git push -u origin main
The -u flag links your local branch to the remote. After this, you can just type git push.
GitHub no longer accepts your account password. Use a Personal Access Token (PAT):
- Go to GitHub → Settings → Developer Settings → Personal Access Tokens → Tokens (classic)
- Generate a new token — check the repo scope
- Copy the token and paste it as your password when Git prompts you
ssh-keygen -t ed25519 -C "you@example.com" then add the public key to GitHub Settings → SSH Keys.Everyday Remote Workflow
# Before you start working — get latest changes from GitHub git pull # Do your work, then: git add . git commit -m "Describe what you did" git push
Cloning — Get Someone Else's Repo
# Download a repo to your machine (one-time)
git clone https://github.com/USERNAME/REPO-NAME.git
Cloning already sets up the remote automatically. You can immediately git pull and git push.
Key Remote Commands
| Command | What it does |
|---|---|
| git remote -v | Show where "origin" points (the GitHub URL) |
| git push | Upload your local commits to GitHub |
| git pull | Download + merge GitHub changes into your local branch |
| git fetch | Download changes but don't merge yet (inspect first) |
| git clone <url> | Copy a repo from GitHub to your computer |
"rejected: non-fast-forward" — GitHub has commits your local repo doesn't have. Run git pull first, then push again.
"Authentication failed" — Your password won't work. Create a Personal Access Token (see Step 3 above) or set up SSH.
"remote origin already exists" — Remove it and re-add: git remote remove origin then git remote add origin <url>
Wrong URL — Fix it: git remote set-url origin https://github.com/YOU/REPO.git
- Create a new repo on GitHub called
my-tech-wiki - Run
git remote add originwith your repo URL and push - Refresh github.com — you should see your files live
- Edit
README.mdto add a link togit-basics.md, commit, and push
Why branch?
main branch. When you're
happy with the result, you merge the universes back together.
Branch Commands
# See all branches (★ = where you are now) git branch # Create a new branch AND switch to it git switch -c feature/add-github-page # Switch to an existing branch git switch main # Delete a branch (after merging) git branch -d feature/add-github-page
feature/, fix/, or docs/ prefixes. Keep names short and hyphen-separated: feature/login-page, fix/typo-readme.Merging — Bringing It All Together
# Step 1: Go to the branch you want to merge INTO git switch main # Step 2: Merge the feature branch into main git merge feature/add-github-page
Merge Conflicts — Don't Panic
When a conflict happens, Git marks the file like this:
<<<<<<< HEAD## Git is a version control system
=======
=======## Git tracks changes to your files
>>>>>>> feature/add-github-page
VS Code shows conflict markers with buttons: "Accept Current", "Accept Incoming", or "Accept Both".
# The final version should look clean — no <<<, ===, or >>> lines
## Git tracks changes to your files over time
git add README.md # mark resolved git commit -m "Merge feature branch, resolve conflict"
"Detached HEAD" state — This means you're on a specific commit, not a branch. Anything you commit here could be lost. Fix it:
git switch main # go back to a branch"You have unmerged paths" — You started a merge but didn't finish resolving conflicts. Fix all files with conflict markers, then git add and git commit.
I accidentally committed to main — Move the commit to a new branch:
git switch -c my-feature # create branch with the commits git switch main git reset --hard HEAD~1 # remove the accidental commit from main
reset --hard if you haven't pushed to GitHub yet.- Create a branch:
git switch -c feature/github-page - Create
github.mdwith notes on GitHub (remotes, push, pull) - Commit it on the feature branch
- Switch back to main:
git switch main - Merge:
git merge feature/github-page - Push main to GitHub
Fork vs Clone
| Fork | Clone | |
|---|---|---|
| What | Copy a repo to YOUR GitHub account | Download a repo to your computer |
| When | Contributing to someone else's public repo | Working on any repo you have access to |
| Where | On GitHub (github.com) | In your terminal |
| Result | A new repo owned by you on GitHub | A local folder with the full history |
Pull Requests (PRs)
A Pull Request is a conversation about a proposed change. It lets teammates review your code before it's merged into main.
git switch -c feature/my-change # ... make changes, commit them ... git push -u origin feature/my-change
After pushing, GitHub shows a banner: "Compare & pull request". Click it.
Fill in a clear title and description explaining what you changed and why.
If a reviewer requests changes, just commit more to the same branch — the PR updates automatically.
# You're still on the same branch, just keep working git add . git commit -m "Address review: fix typo, improve wording" git push
git switch main git pull # get the merged changes git branch -d feature/my-change # delete local branch
Issues — Track Work
GitHub Issues are like a to-do list for your project. Great for bug reports, feature requests, and questions.
Fixes #42 or Closes #42. When the PR merges, issue #42 closes automatically.Code Review Tips
- Review logic, not style (unless style is the point)
- Ask questions instead of demanding changes: "What if we used X here?"
- Always approve something you're happy merging. Block only real problems.
- As the author, respond to every comment — even to say "done" or "disagree because..."
"This branch is X commits behind main" — Your fork is out of date. Update it:
git remote add upstream https://github.com/ORIGINAL-OWNER/REPO.git git fetch upstream git merge upstream/main
PR has conflicts — Pull the target branch into your feature branch to resolve:
git switch feature/my-change
git merge main # resolve any conflicts, commit
git pushI pushed to the wrong branch — Move the commit:
git log --oneline # find the commit hash
git switch correct-branch
git cherry-pick <commit-hash>- Create branch
feature/branching-notesand addbranching.md - Push the branch to GitHub
- Open a Pull Request on GitHub with a description
- Merge the PR on GitHub, then run
git pulllocally - Fork a classmate's repo and open a PR with an improvement
Undoing Changes — Choose the Right Tool
| Situation | Command | Safe to push? |
|---|---|---|
| Discard changes to a file (not staged) | git restore <file> | ✅ yes |
| Unstage a file (keep changes) | git restore --staged <file> | ✅ yes |
| Undo last commit (keep changes staged) | git reset --soft HEAD~1 | ⚠️ only if not pushed |
| Undo a commit with a new "reverse" commit | git revert HEAD | ✅ yes, always safe |
| Completely erase last N commits | git reset --hard HEAD~N | 🚫 never push after this |
main — it rewrites history and can permanently delete teammates' work. If you need to undo something that was already pushed, use git revert.The .gitignore File
Tell Git to completely ignore certain files — secrets, build output, OS junk.
# Python __pycache__/ *.pyc .env venv/ # Node.js node_modules/ dist/ .env.local # macOS .DS_Store # Editors .vscode/ .idea/
.env files — they contain API keys, database passwords, and secrets. If you accidentally did, the key is now public. Rotate the key immediately, then remove the file from history using git filter-repo or BFG Repo Cleaner.Fix Scenarios — Step by Step
pip install git-filter-repo git filter-repo --path .env --invert-paths
git push origin main --force
Fix: Pull first, then push again.
git pull --rebase # cleaner than a merge commit git push
You checked out a specific commit instead of a branch. Any commits you make here will be orphaned.
# Option A: just go back to main (abandon any commits here) git switch main # Option B: save your work on a new branch git switch -c my-saved-work
Not pushed yet? Remove the commit but keep the changes staged:
git reset --soft HEAD~1Already pushed? Use revert (creates a new commit that undoes the old one):
git revert HEAD git push
- Create a
.gitignorefile and add.env,.DS_Store,__pycache__/ - Make a "bad" commit, then undo it with
git reset --soft HEAD~1 - Deliberately create a merge conflict, then resolve it correctly
Walk-in for code emergencies. No appointment needed.
These 7 disasters happen to everyone — including senior engineers. Knowing how to fix them is what separates a beginner from a pro. Click any case to see the full treatment.
.env file — containing an API key or database password — is now visible to the world..gitignore was set up. Git tracked everything including secrets.# Remove the file from all Git history pip install git-filter-repo git filter-repo --path .env --invert-paths --force # Then force-push the cleaned history git push origin main --force
.gitignore as your very first file in every project. Add .env, *.key, config/secrets.* before your first commit.git push --force on main. Teammates' commits are gone from the remote. Slack is on fire.# Each teammate can recover their commits with reflog git reflog # find the lost commit hash git cherry-pick <lost-hash> # replay the lost commit # Or the teammate restores their work: git push origin main --force # now they push the recovered history
You are in 'detached HEAD' state. You make some commits and then switch branches — and your commits vanish.git log and eventually garbage-collected.# Option A: save your work — create a branch RIGHT NOW git switch -c rescue-branch # your commits are now safe # Option B: abandon the detached state (lose any commits there) git switch main
git switch <branch-name> to move between branches. Only do git checkout <commit-hash> intentionally for read-only exploration.CONFLICT (content): Merge conflict in README.md × 8 files. You panic and close VS Code.git status # shows every conflicted file # Open each file — find and resolve the <<<<<<< markers # Then mark each file as resolved: git add README.md git add other-file.md git commit # finishes the merge
git merge main or git pull daily). Small focused branches mean small conflicts. The longer you wait, the worse it gets.git switch your-branch
git fetch origin
git merge origin/main # resolve any conflicts, then commit
git pushOr for a cleaner history: replace git merge origin/main with git rebase origin/main.
git pull on main, then git merge main into your branch. Five seconds of habit saves hours of conflict resolution.git push takes 8 minutes. GitHub shows your repo is 400MB. Your node_modules (or __pycache__, .venv, build output) was committed..gitignore, so git add . swept up everything including dependency folders.# Stop tracking the folder WITHOUT deleting it locally
git rm -r --cached node_modules/
echo "node_modules/" >> .gitignore
git add .gitignore
git commit -m "Remove node_modules, add gitignore"
git push.gitignore. GitHub provides templates: when creating a repo, select a .gitignore template for your language.git log shows: "Inital comit" or "asdfgh" or "fix stuff maybe idk". Now it's in your public GitHub history.# If NOT pushed yet — rewrite the last commit message git commit --amend -m "Initial commit: add README and project structure" # If already pushed — honestly, just move on. # The commit exists. Future commits will be better. # Nobody has ever been fired for "inital comit".
<verb> <what> — "Add login page", "Fix null pointer in auth", "Remove unused imports". One sentence, present tense, no period.What is CI/CD?
CD (Continuous Deployment) = automatically deploy to production when tests pass.
GitHub Actions lets you automate these workflows directly in your repo using YAML files.
Anatomy of a Workflow File
name: CI # Name shown in GitHub UI on: # WHEN to run this workflow push: branches: [main] pull_request: branches: [main] jobs: test: # Job name (can be anything) runs-on: ubuntu-latest # Which OS to run on steps: - name: Checkout code uses: actions/checkout@v4 # Download your repo - name: Set up Python uses: actions/setup-python@v5 with: python-version: "3.12" - name: Install dependencies run: pip install -r requirements.txt - name: Run tests run: pytest
A Workflow for My Tech Wiki — Markdown Linter
name: Lint Markdown on: [push, pull_request] jobs: markdownlint: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Lint .md files uses: DavidAnson/markdownlint-cli2-action@v17 with: globs: "**/*.md"
Using Secrets — Don't Hardcode API Keys
Repository → Settings → Secrets and variables → Actions → New repository secret
- name: Deploy env: API_KEY: ${{ secrets.MY_API_KEY }} # never visible in logs run: ./deploy.sh
Workflow Triggers Reference
| Trigger | When it runs |
|---|---|
| push | Every commit pushed to any matching branch |
| pull_request | When a PR is opened, updated, or merged |
| schedule | On a cron schedule (e.g., every day at 9am) |
| workflow_dispatch | Manually via the GitHub UI |
| release | When you publish a GitHub Release |
YAML indentation errors — YAML is very sensitive to spaces (not tabs). Use a YAML linter: paste into yamllint.com before committing.
"Workflow not triggering" — Check that the file is at exactly .github/workflows/filename.yml (plural "workflows").
Workflow passes locally but fails in CI — The CI environment is fresh every time. Make sure you install all dependencies in a run step; don't assume anything is pre-installed.
Secrets show as "***" in logs — That's correct behavior. If you're not seeing them at all, make sure the secret name in the YAML matches exactly (case-sensitive).
- Create
.github/workflows/lint.ymlwith the Markdown linter above - Commit and push — watch the Action run on GitHub → Actions tab
- Introduce a markdown error, push, watch the Action fail
- Fix the error, push again, see the Action turn green ✅
git stash — Save Work Without Committing
Stash is like a temporary drawer. Useful when you need to switch branches but aren't ready to commit.
git stash # save current changes away git switch other-branch # do your other work git switch back-to-my-branch git stash pop # restore saved changes git stash list # see all stashes git stash drop # delete the stash without restoring
git rebase — Cleaner History
Rebase replays your commits on top of another branch — creates a clean linear history. Better for personal feature branches before a PR.
# Rebase your feature branch on top of latest main git switch feature/my-feature git rebase main # Interactive rebase — squash, reorder, rename commits git rebase -i HEAD~3 # edit last 3 commits
Powerful git log
git log --oneline --graph --all # visual ASCII branch graph git log --author="Your Name" # filter by author git log --since="2 weeks ago" # filter by date git log --grep="fix" # search commit messages git log -p -- README.md # history of one file
Tags & Releases
# Tag a specific commit (e.g., version 1.0) git tag -a v1.0 -m "First stable release" git push origin v1.0 # List all tags git tag
On GitHub, go to Releases → Create a new release and pick a tag to publish an official release with notes and downloadable assets.
Git Aliases — Type Less
# Set these once, use them forever git config --global alias.st "status" git config --global alias.co "switch" git config --global alias.lg "log --oneline --graph --all" # Now you can type: git st # instead of git status git lg # instead of git log --oneline --graph --all
git bisect — Find Which Commit Broke Something
git bisect start git bisect bad # current commit is broken git bisect good v1.0 # v1.0 was working # Git checks out a middle commit — test it, then: git bisect good # or: git bisect bad # Repeat until Git finds the exact breaking commit git bisect reset # go back to HEAD when done
- Run
git log --oneline --graph --allto see your full project history - Add 3 git aliases to your config
- Create a tag:
git tag -a v1.0 -m "Initial wiki complete"and push it - Publish a GitHub Release from the tag with release notes
| git config --global user.name "X" | Set your name |
| git config --global user.email "X" | Set your email |
| git config --list | Show all config |
| git init | Create a new repo |
| git clone <url> | Clone from GitHub |
| git status | What's changed? |
| git add <file> | Stage a file |
| git add . | Stage everything |
| git commit -m "msg" | Save a snapshot |
| git commit --amend | Fix last commit |
| git branch | List branches |
| git switch -c <name> | Create & switch |
| git switch <name> | Switch branch |
| git merge <branch> | Merge into current |
| git branch -d <name> | Delete branch |
| git remote -v | Show remotes |
| git remote add origin <url> | Add remote |
| git push -u origin main | First push |
| git push | Push changes |
| git pull | Pull changes |
| git fetch | Download (no merge) |
| git restore <file> | Discard changes |
| git restore --staged <file> | Unstage |
| git reset --soft HEAD~1 | Undo commit, keep files |
| git revert HEAD | Safe undo (new commit) |
| git log --oneline | Compact history |
| git log --graph --all | Visual branch graph |
| git diff | Unstaged changes |
| git diff --staged | Staged changes |
| git show <hash> | Show a commit |
| git blame <file> | Who changed each line |
| git stash | Stash dirty work |
| git stash pop | Restore stash |
| git rebase <branch> | Rebase onto branch |
| git cherry-pick <hash> | Apply one commit |
| git tag -a v1.0 | Create annotated tag |
| git bisect start | Binary search for bug |