Git Explained with Diagrams: The Visual Guide Every Developer Needs
I've taught Git to 5 people. These are the diagrams that finally made it click.
What Actually IS Git?
Git isn't GitHub. Git isn't a folder. Git is a snapshot machine.
Every time you commit, Git takes a photo of your project:
Commit 1: [πΈ photo of: index.html + style.css]
Commit 2: [πΈ photo of: index.html + style.css + app.js]
Commit 3: [πΈ photo of: index.html (edited) + style.css + app.js]
Each photo is permanent. You can go back to any photo.
You can compare any two photos.
You can branch from any photo.
That's it. Everything else is just convenience around this concept.
The Three States (This Is Where Everyone Gets Confused)
βββββββββββββββββββββββββββββββββββββββββββ
β Your Working Directory β
β (The actual files on your disk) β
β β
β You EDIT files here β
ββββββββββββββββ¬βββββββββββββββββββββββββββ
β git add
βΌ
βββββββββββββββββββββββββββββββββββββββββββ
β Staging Area β
β (The "waiting room" for commits) β
β β
β Files ready to be committed β
ββββββββββββββββ¬βββββββββββββββββββββββββββ
β git commit
βΌ
βββββββββββββββββββββββββββββββββββββββββββ
β Repository (.git) β
β (The permanent snapshot history) β
β β
β Commits live here forever β
βββββββββββββββββββββββββββββββββββββββββββ
# The daily cycle:
git add . # Move changes β Staging
git commit -m "..." # Move staging β Repository
# Repeat!
The Most Common Workflow
Day starts:
[Working Dir] ββeditβββ [modified files]
β
git add .
βΌ
[Staging Area] ββfiles readyβββ
β
git commit -m "feat: login page"
βΌ
[Repository] ββnew snapshotβββ
Day ends: push to share with team
β
git push origin main
βΌ
[Remote (GitHub)]
Branches Are Just Pointers
Before branching:
main ββββββββββββ (you're here)
After git branch feature-login:
main ββββββββββββ
β°ββfeature-login βββ (you're here now)
After some work:
main ββββββββββββ
β°ββfeature-login βββββββββ (3 new commits)
After git merge (fast-forward):
main βββββββββββββββββββββ (feature-login's commits are now in main)
(feature-login pointer is deleted or kept)
A branch = a named pointer to a commit. That's it.
Merge vs Rebase (With Pictures)
Merge: Creates a merge commit
main: A ββ B ββ C
β²
feature: D ββ E ββ F β³ββ M (merge commit)
Result: A linear history with a merge bubble
git checkout main
git merge feature-login
# Creates a merge commit combining both histories
Rebase: Rewrites history to look linear
Before rebase:
main: A ββ B ββ C
feature: D ββ E ββ F
After rebase:
main: A ββ B ββ C
feature: D' ββ E' ββ F' (replayed on top of main)
After fast-forward merge:
main: A ββ B ββ C ββ D' ββ E' ββ F'
git checkout feature-login
git rebase main # Replay my commits on top of latest main
git checkout main
git merge feature-login # Fast-forward (no merge commit needed)
Rule of thumb: Rebase local branches before merging. Merge shared branches.
Remote = Another Copy of the Repo
Your Computer: GitHub:
ββββββββββββββββ ββββββββββββββββ
β .git/ β β origin/main β
β main βββββββΌββpushβββββββββββΆβ main βββββββ
β feat βββββββ€ β β
ββββββββββββββββ ββββββββββββββββ
git push β Send your commits to remote
git pull β Get remote commits + merge them
git fetch β Get remote commits (don't merge yet)
The Danger Zone: Force Push
Normal push (safe):
Remote: A ββ B ββ C
Local: A ββ B ββ C ββ D git push β Remote gets D β
Force push (dangerous!):
Remote: A ββ B ββ C ββ X ββ Y (someone else pushed!)
Local: A ββ B ββ C ββ D git push --force β
Remote: A ββ B ββ C ββ D β X and Y are GONE!
Only force push on YOUR own branch that nobody else uses!
Common Scenarios (Cheat Sheet)
Scenario 1: "I messed up, undo!"
# Undo last commit (keep changes staged)
git reset --soft HEAD~1
# Undo last commit (keep changes unstaged)
git reset HEAD~1
# Undo last commit (LOSE changes completely)
git reset --hard HEAD~1
# Undo working directory changes (before committing)
git checkout -- file.txt
git restore file.txt # Newer command (same thing)
Scenario 2: "I committed to wrong branch"
# Move last commit to different branch
git branch new-branch # Create branch where commit currently sits
git reset --hard HEAD~1 # Remove commit from current branch
git checkout new-branch # Switch to branch with the commit
Scenario 3: "Someone pushed code I don't have"
git fetch origin # Get their commits
git rebase origin/main # Put your work on top of theirs
# Resolve conflicts if any
git push origin feature # Push clean history
Scenario 4: "I need to see what changed"
# What changed since last commit?
git diff # Unstaged changes
git diff --staged # Staged changes
# What changed between two commits?
git diff abc123 def456 # Two specific commits
git diff main..feature # Between two branches
# What did this commit change?
git show abc123 # One commit's details
# What files changed?
git diff --name-only # Just filenames
Scenario 5: "Find that thing I wrote"
# Find commit by message
git log --grep="login" --oneline
# Find commit that changed a specific line
git log -S "function login" --oneline
# Find who changed this line
git blame file.ts -L 10,20 # Lines 10-20 only
# See file history
git log --follow -- file.ts # Including renames
The .gitignore File
# Dependencies
node_modules/
# Build output
dist/
build/
*.js.map
# Environment
.env
.env.local
# IDE
.vscode/
.idea/
*.swp
*.swo
# OS files
.DS_Store
Thumbs.db
# Logs
logs/
*.log
# But keep this file!
!.env.example
Pro tip: Use gitignore.io to generate .gitignore for your stack.
My Git Config
# Essential config
git config --global user.name "Your Name"
git config --global user.email "your@email.com"
# Better defaults
git config --global init.defaultBranch main
git config --global core.editor "code --wait"
git config --global pull.rebase true # Always rebase on pull
# Useful aliases
git config --global alias.co checkout
git config --global alias.br branch
git config --global alias.ci commit
git config --global alias.st status
git config --global alias.lg "log --oneline --graph --all -15"
# Now you can type:
git co feature-login # instead of git checkout
git lg # beautiful graph view
The Git Graph (What It All Looks Like)
* abc1234 (HEAD -> main) Merge pull request #42
|\
| * def5678 Fix login validation
| * ghi9012 Add password strength checker
|/
* jkl3456 Feature: user authentication
* mno7890 Refactor API client
* pqr0123 Setup project structure
* stu4567 Initial commit
# Generate this view anytime:
git log --oneline --graph --all -20
Quick Reference Card
| Command | Does |
|---|---|
git status |
Show state of files |
git add <file> |
Stage changes |
git commit -m "msg" |
Save snapshot |
git push |
Send to remote |
git pull |
Get + merge from remote |
git branch <name> |
Create branch |
git checkout <branch> |
Switch branch |
git merge <branch> |
Combine branches |
git rebase <branch> |
Replay on top of branch |
git stash |
Temporarily save changes |
git reset --hard HEAD~1 |
Undo last commit |
git diff |
Show changes |
git log --oneline |
Commit history |
git blame <file> |
Who changed each line |
What Git concept took you the longest to understand?
Follow @armorbreak for more developer guides.
Top comments (0)