🐙 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.
🐙 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 createto create PRs from the command line. Install the GitHub CLI:sudo apt install ghon Linux,brew install ghon macOS, thengh 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 reflogis your safety net. It logs every move Git makes. Even aftergit reset --hard, you can find your lost commits withgit reflogand recover withgit checkout HEAD@{index}.
🧠 Test Your Knowledge
- What does
git statusshow?
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. - What’s the difference between
git reset --softand--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. - 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(orgit switch -c) creates and switches. - 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 — Usegit revertto create a new commit that undoes the old one. Safe for shared branches. - What does
git stashdo?
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
- Use
git log --graph --oneline --alldaily. This shows the entire branch structure. Make it an alias:git config --global alias.tree 'log --graph --oneline --all'. Then justgit tree. - 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.
- Use branches for everything. Every feature gets a branch. Every bugfix gets a branch. It’s frictionless and undoable.
git switch -cis faster than thinking “I won’t branch this time.” - Master git reflog.
git reflogsaves you from almost every mistake. Accidentally reset –hard? Reflog has your commits. Deleted a branch? Reflog has it. It’s your emergency parachute. - Never force push to shared branches. If you must, warn the team first. And use
--force-with-leaseinstead of--force— it checks if the remote changed since you last fetched. - 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. - 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. - 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. - Don’t commit half-broken code. Each commit should be a complete, working state. This makes
git bisectandgit revertwork reliably. If you need to save WIP, usegit stashor a WIP branch. - 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
- Commit Flow —
git status→git add .→git commit -m "msg"→git push. This is 80% of what you do. - Branching —
git switch -c feature-branchfor everything. Never commit directly to main. - Pull Requests — Small PRs with good descriptions. Review before merging. Always sync with upstream first.
- Undoing Mistakes — Not pushed?
git reset. Pushed?git revert. Panic?git reflog. - Merge Conflicts — They’re normal. Open the file, fix the markers,
git add,git merge --continue. Done.
More Free Courses on TricksPage
- Linux Commands Course — Master the command line from beginner to pro.
- Docker & Swarm Course — Containers, Dockerfiles, Compose, Swarm.
- n8n Automation Course — Workflow automation with 400+ integrations.
- Python Course — Master Python from beginner to pro.
- Agentic AI Course — Build intelligent AI agents.
💭 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
- Linux Commands Course — Master the command line from beginner to pro.
- Docker & Swarm Course — Containers, Dockerfiles, Compose, Swarm.
- n8n Automation Course — Workflow automation with 400+ integrations.
- Python Course — Master Python from beginner to pro.
- Agentic AI Course — Build intelligent AI agents.
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