Tools: ๐ฟ Git Mastery: The Complete Developer Guide
Why Git?
Prerequisites
Part 1: First-Time Setup
Part 2: Starting a Repository
From scratch
From an existing remote
Part 3: The Core Workflow โ Stage, Commit, Repeat
Checking status
Staging changes
Committing
Writing good commit messages
Part 4: Viewing History
Inspecting a specific commit
Comparing changes
Part 5: Branching โ Git's Superpower
Merging branches
Deleting branches
Part 6: Rebasing โ A Cleaner History
Interactive rebase โ rewrite history
Part 7: Working with Remotes
Pushing and pulling
Tracking branches
Part 8: Undoing Things
Amending the last commit
Unstaging files
Reverting commits (safe โ creates a new commit)
Resetting (rewrites history โ be careful)
The escape hatch: reflog
Part 9: Stashing โ Save Work Without Committing
Part 10: Tags โ Marking Releases
Part 11: The .gitignore File
Part 12: Branching Strategies
Git Flow
GitHub Flow
Trunk-Based Development
Git Commands Cheat Sheet
Common Pitfalls & How to Avoid Them
โ Committed secrets or credentials
โ Merge conflicts
โ Pushed to the wrong branch
โ git pull creates ugly merge commits
Wrapping Up
What's Next? From your first commit to advanced branching strategies โ everything you need to version control like a pro Every file you've ever accidentally deleted, every "final_v3_REAL_final.js" you've created โ Git is the solution to all of that. It's a distributed version control system that tracks every change to your codebase, lets you experiment without fear, and enables teams of hundreds to collaborate without stepping on each other. Git isn't just a tool โ it's the backbone of modern software development. GitHub, GitLab, Bitbucket โ they're all built on top of it. Here's the mental model before we dive in: Before your first commit, tell Git who you are. This info is embedded in every commit you make. These settings live in ~/.gitconfig and apply to every repo on your machine. You can override them per-repo by dropping the --global flag. This is the heartbeat of Git. Everything else builds on it. Pro tip: git add -p is one of Git's most underused features. It lets you review and selectively stage individual hunks of changes โ perfect for keeping commits focused and atomic. Follow the Conventional Commits format: Common types: feat, fix, docs, refactor, test, chore Branches are cheap and fast in Git (just a pointer to a commit). Use them liberally. Fast-forward vs merge commit: Use --no-ff when you want a clear record that a feature branch was merged. Rebase rewrites commit history by replaying your commits on top of another branch. The result is a clean, linear history. After git rebase main: This is the power tool. Use it to clean up commits before merging: In the editor that opens, you can: โ ๏ธ Golden Rule of Rebasing: Never rebase commits that have been pushed to a shared remote branch. Rebase rewrites history โ doing it on shared branches causes pain for everyone. Once you've set an upstream with -u, Git knows which remote branch your local branch corresponds to: This is where most developers get nervous. Don't be โ Git almost never truly deletes anything. Use revert on shared branches โ it's non-destructive. Even after a hard reset, Git keeps a log of where HEAD has been. You can recover "lost" commits: Need to switch branches but you're mid-feature? Stash it. Annotated tags store extra metadata (tagger name, date, message) and can be signed. Use them for releases. Tell Git which files to never track: Apply a gitignore to already-tracked files: Find pre-made .gitignore templates for your stack at gitignore.io. Best for projects with scheduled releases: Simpler โ best for continuous deployment: Best for mature teams with strong CI/CD: Choose the strategy that matches your team size and release cadence. GitHub Flow is the right default for most teams. Better: use git-secrets or gitleaks to prevent it happening in the first place. Here's what you've learned: Git rewards practice. The commands that seem scary now (rebase -i, reflog, reset --hard) become second nature once you've used them a few times in a safe environment. Found this useful? Drop a โค๏ธ and follow for more. Got a Git horror story or a tip I missed? Share it in the comments. Templates let you quickly answer FAQs or store snippets for re-use. Hide child comments as well For further actions, you may consider blocking this person and/or reporting abuse
$ -weight: 500;">git --version
# -weight: 500;">git version 2.x.x
-weight: 500;">git --version
# -weight: 500;">git version 2.x.x
-weight: 500;">git --version
# -weight: 500;">git version 2.x.x
-weight: 500;">git config --global user.name "Your Name"
-weight: 500;">git config --global user.email "[email protected]" # Set your default editor (VS Code shown here)
-weight: 500;">git config --global core.editor "code --wait" # Set default branch name to 'main'
-weight: 500;">git config --global init.defaultBranch main # Verify your config
-weight: 500;">git config --list
-weight: 500;">git config --global user.name "Your Name"
-weight: 500;">git config --global user.email "[email protected]" # Set your default editor (VS Code shown here)
-weight: 500;">git config --global core.editor "code --wait" # Set default branch name to 'main'
-weight: 500;">git config --global init.defaultBranch main # Verify your config
-weight: 500;">git config --list
-weight: 500;">git config --global user.name "Your Name"
-weight: 500;">git config --global user.email "[email protected]" # Set your default editor (VS Code shown here)
-weight: 500;">git config --global core.editor "code --wait" # Set default branch name to 'main'
-weight: 500;">git config --global init.defaultBranch main # Verify your config
-weight: 500;">git config --list
mkdir my-project && cd my-project
-weight: 500;">git init
# Initialized empty Git repository in .-weight: 500;">git/
mkdir my-project && cd my-project
-weight: 500;">git init
# Initialized empty Git repository in .-weight: 500;">git/
mkdir my-project && cd my-project
-weight: 500;">git init
# Initialized empty Git repository in .-weight: 500;">git/
-weight: 500;">git clone https://github.com/user/repo.-weight: 500;">git # Clone into a specific folder name
-weight: 500;">git clone https://github.com/user/repo.-weight: 500;">git my-folder # Clone only the latest snapshot (faster for large repos)
-weight: 500;">git clone --depth 1 https://github.com/user/repo.-weight: 500;">git
-weight: 500;">git clone https://github.com/user/repo.-weight: 500;">git # Clone into a specific folder name
-weight: 500;">git clone https://github.com/user/repo.-weight: 500;">git my-folder # Clone only the latest snapshot (faster for large repos)
-weight: 500;">git clone --depth 1 https://github.com/user/repo.-weight: 500;">git
-weight: 500;">git clone https://github.com/user/repo.-weight: 500;">git # Clone into a specific folder name
-weight: 500;">git clone https://github.com/user/repo.-weight: 500;">git my-folder # Clone only the latest snapshot (faster for large repos)
-weight: 500;">git clone --depth 1 https://github.com/user/repo.-weight: 500;">git
Working Tree โ Staging Area โ Repository (edit) (-weight: 500;">git add) (-weight: 500;">git commit)
Working Tree โ Staging Area โ Repository (edit) (-weight: 500;">git add) (-weight: 500;">git commit)
Working Tree โ Staging Area โ Repository (edit) (-weight: 500;">git add) (-weight: 500;">git commit)
-weight: 500;">git -weight: 500;">status # What's changed? What's staged?
-weight: 500;">git -weight: 500;">status -s # Short format: M = modified, A = added, ? = untracked
-weight: 500;">git -weight: 500;">status # What's changed? What's staged?
-weight: 500;">git -weight: 500;">status -s # Short format: M = modified, A = added, ? = untracked
-weight: 500;">git -weight: 500;">status # What's changed? What's staged?
-weight: 500;">git -weight: 500;">status -s # Short format: M = modified, A = added, ? = untracked
-weight: 500;">git add file.js # Stage a specific file
-weight: 500;">git add src/ # Stage an entire directory
-weight: 500;">git add . # Stage everything in the current directory
-weight: 500;">git add -p # Interactive: stage changes chunk by chunk
-weight: 500;">git add file.js # Stage a specific file
-weight: 500;">git add src/ # Stage an entire directory
-weight: 500;">git add . # Stage everything in the current directory
-weight: 500;">git add -p # Interactive: stage changes chunk by chunk
-weight: 500;">git add file.js # Stage a specific file
-weight: 500;">git add src/ # Stage an entire directory
-weight: 500;">git add . # Stage everything in the current directory
-weight: 500;">git add -p # Interactive: stage changes chunk by chunk
-weight: 500;">git commit -m "feat: add user authentication" # Stage all tracked files and commit in one step
-weight: 500;">git commit -am "fix: correct typo in error message" # Open your editor for a detailed commit message
-weight: 500;">git commit
-weight: 500;">git commit -m "feat: add user authentication" # Stage all tracked files and commit in one step
-weight: 500;">git commit -am "fix: correct typo in error message" # Open your editor for a detailed commit message
-weight: 500;">git commit
-weight: 500;">git commit -m "feat: add user authentication" # Stage all tracked files and commit in one step
-weight: 500;">git commit -am "fix: correct typo in error message" # Open your editor for a detailed commit message
-weight: 500;">git commit
<type>(<scope>): <short summary> <optional body> <optional footer>
<type>(<scope>): <short summary> <optional body> <optional footer>
<type>(<scope>): <short summary> <optional body> <optional footer>
# Good
-weight: 500;">git commit -m "feat(auth): add JWT refresh token rotation"
-weight: 500;">git commit -m "fix(api): handle null response from payment gateway"
-weight: 500;">git commit -m "docs: -weight: 500;">update README with Docker setup instructions" # Bad
-weight: 500;">git commit -m "stuff"
-weight: 500;">git commit -m "fix"
-weight: 500;">git commit -m "asdfgh"
# Good
-weight: 500;">git commit -m "feat(auth): add JWT refresh token rotation"
-weight: 500;">git commit -m "fix(api): handle null response from payment gateway"
-weight: 500;">git commit -m "docs: -weight: 500;">update README with Docker setup instructions" # Bad
-weight: 500;">git commit -m "stuff"
-weight: 500;">git commit -m "fix"
-weight: 500;">git commit -m "asdfgh"
# Good
-weight: 500;">git commit -m "feat(auth): add JWT refresh token rotation"
-weight: 500;">git commit -m "fix(api): handle null response from payment gateway"
-weight: 500;">git commit -m "docs: -weight: 500;">update README with Docker setup instructions" # Bad
-weight: 500;">git commit -m "stuff"
-weight: 500;">git commit -m "fix"
-weight: 500;">git commit -m "asdfgh"
-weight: 500;">git log # Full log
-weight: 500;">git log --oneline # Compact: one commit per line
-weight: 500;">git log --oneline --graph # ASCII branch graph
-weight: 500;">git log --oneline --graph --all # Include all branches # Filter by author
-weight: 500;">git log --author="Jane" # Filter by date
-weight: 500;">git log --since="2 weeks ago"
-weight: 500;">git log --after="2024-01-01" --before="2024-06-01" # Search commit messages
-weight: 500;">git log --grep="authentication" # See what changed in each commit
-weight: 500;">git log -p # Show stats (files changed, insertions, deletions)
-weight: 500;">git log --stat
-weight: 500;">git log # Full log
-weight: 500;">git log --oneline # Compact: one commit per line
-weight: 500;">git log --oneline --graph # ASCII branch graph
-weight: 500;">git log --oneline --graph --all # Include all branches # Filter by author
-weight: 500;">git log --author="Jane" # Filter by date
-weight: 500;">git log --since="2 weeks ago"
-weight: 500;">git log --after="2024-01-01" --before="2024-06-01" # Search commit messages
-weight: 500;">git log --grep="authentication" # See what changed in each commit
-weight: 500;">git log -p # Show stats (files changed, insertions, deletions)
-weight: 500;">git log --stat
-weight: 500;">git log # Full log
-weight: 500;">git log --oneline # Compact: one commit per line
-weight: 500;">git log --oneline --graph # ASCII branch graph
-weight: 500;">git log --oneline --graph --all # Include all branches # Filter by author
-weight: 500;">git log --author="Jane" # Filter by date
-weight: 500;">git log --since="2 weeks ago"
-weight: 500;">git log --after="2024-01-01" --before="2024-06-01" # Search commit messages
-weight: 500;">git log --grep="authentication" # See what changed in each commit
-weight: 500;">git log -p # Show stats (files changed, insertions, deletions)
-weight: 500;">git log --stat
-weight: 500;">git show abc1234 # Show commit details + diff
-weight: 500;">git show abc1234:src/app.js # Show a file as it was at that commit
-weight: 500;">git show abc1234 # Show commit details + diff
-weight: 500;">git show abc1234:src/app.js # Show a file as it was at that commit
-weight: 500;">git show abc1234 # Show commit details + diff
-weight: 500;">git show abc1234:src/app.js # Show a file as it was at that commit
-weight: 500;">git diff # Unstaged changes vs last commit
-weight: 500;">git diff --staged # Staged changes vs last commit
-weight: 500;">git diff main feature-branch # Diff between two branches
-weight: 500;">git diff abc1234 def5678 # Diff between two commits
-weight: 500;">git diff # Unstaged changes vs last commit
-weight: 500;">git diff --staged # Staged changes vs last commit
-weight: 500;">git diff main feature-branch # Diff between two branches
-weight: 500;">git diff abc1234 def5678 # Diff between two commits
-weight: 500;">git diff # Unstaged changes vs last commit
-weight: 500;">git diff --staged # Staged changes vs last commit
-weight: 500;">git diff main feature-branch # Diff between two branches
-weight: 500;">git diff abc1234 def5678 # Diff between two commits
-weight: 500;">git branch # List local branches
-weight: 500;">git branch -a # List local + remote branches
-weight: 500;">git branch feature/login # Create a new branch
-weight: 500;">git switch feature/login # Switch to it
-weight: 500;">git switch -c feature/login # Create AND switch in one command # Old syntax (still works everywhere)
-weight: 500;">git checkout -b feature/login
-weight: 500;">git branch # List local branches
-weight: 500;">git branch -a # List local + remote branches
-weight: 500;">git branch feature/login # Create a new branch
-weight: 500;">git switch feature/login # Switch to it
-weight: 500;">git switch -c feature/login # Create AND switch in one command # Old syntax (still works everywhere)
-weight: 500;">git checkout -b feature/login
-weight: 500;">git branch # List local branches
-weight: 500;">git branch -a # List local + remote branches
-weight: 500;">git branch feature/login # Create a new branch
-weight: 500;">git switch feature/login # Switch to it
-weight: 500;">git switch -c feature/login # Create AND switch in one command # Old syntax (still works everywhere)
-weight: 500;">git checkout -b feature/login
# Switch to the branch you want to merge INTO
-weight: 500;">git switch main # Merge feature branch
-weight: 500;">git merge feature/login # Merge with a commit even if fast-forward is possible (preserves history)
-weight: 500;">git merge --no-ff feature/login
# Switch to the branch you want to merge INTO
-weight: 500;">git switch main # Merge feature branch
-weight: 500;">git merge feature/login # Merge with a commit even if fast-forward is possible (preserves history)
-weight: 500;">git merge --no-ff feature/login
# Switch to the branch you want to merge INTO
-weight: 500;">git switch main # Merge feature branch
-weight: 500;">git merge feature/login # Merge with a commit even if fast-forward is possible (preserves history)
-weight: 500;">git merge --no-ff feature/login
Fast-forward (linear history):
main: A โ B โ C โ D โ E โ feature merged cleanly Merge commit (preserves branch context):
main: A โ B โ C โ M โ โ merge commit
feature: D โ E
Fast-forward (linear history):
main: A โ B โ C โ D โ E โ feature merged cleanly Merge commit (preserves branch context):
main: A โ B โ C โ M โ โ merge commit
feature: D โ E
Fast-forward (linear history):
main: A โ B โ C โ D โ E โ feature merged cleanly Merge commit (preserves branch context):
main: A โ B โ C โ M โ โ merge commit
feature: D โ E
-weight: 500;">git branch -d feature/login # Delete (safe โ won't delete unmerged branches)
-weight: 500;">git branch -D feature/login # Force delete
-weight: 500;">git push origin --delete feature/login # Delete remote branch
-weight: 500;">git branch -d feature/login # Delete (safe โ won't delete unmerged branches)
-weight: 500;">git branch -D feature/login # Force delete
-weight: 500;">git push origin --delete feature/login # Delete remote branch
-weight: 500;">git branch -d feature/login # Delete (safe โ won't delete unmerged branches)
-weight: 500;">git branch -D feature/login # Force delete
-weight: 500;">git push origin --delete feature/login # Delete remote branch
-weight: 500;">git switch feature/login
-weight: 500;">git rebase main
-weight: 500;">git switch feature/login
-weight: 500;">git rebase main
-weight: 500;">git switch feature/login
-weight: 500;">git rebase main
main: A โ B โ C
feature: D โ E
main: A โ B โ C
feature: D โ E
main: A โ B โ C
feature: D โ E
main: A โ B โ C
feature: D' โ E' (commits replayed on top of C)
main: A โ B โ C
feature: D' โ E' (commits replayed on top of C)
main: A โ B โ C
feature: D' โ E' (commits replayed on top of C)
-weight: 500;">git rebase -i HEAD~3 # Interactively edit the last 3 commits
-weight: 500;">git rebase -i HEAD~3 # Interactively edit the last 3 commits
-weight: 500;">git rebase -i HEAD~3 # Interactively edit the last 3 commits
-weight: 500;">git remote -v # List remotes
-weight: 500;">git remote add origin https://github.com/user/repo.-weight: 500;">git # Add a remote
-weight: 500;">git remote rename origin upstream # Rename a remote
-weight: 500;">git remote -weight: 500;">remove origin # Remove a remote
-weight: 500;">git remote -v # List remotes
-weight: 500;">git remote add origin https://github.com/user/repo.-weight: 500;">git # Add a remote
-weight: 500;">git remote rename origin upstream # Rename a remote
-weight: 500;">git remote -weight: 500;">remove origin # Remove a remote
-weight: 500;">git remote -v # List remotes
-weight: 500;">git remote add origin https://github.com/user/repo.-weight: 500;">git # Add a remote
-weight: 500;">git remote rename origin upstream # Rename a remote
-weight: 500;">git remote -weight: 500;">remove origin # Remove a remote
# Push local branch to remote
-weight: 500;">git push origin main # Push and set upstream tracking (then you can just use `-weight: 500;">git push`)
-weight: 500;">git push -u origin main # Pull = fetch + merge
-weight: 500;">git pull origin main # Pull with rebase instead of merge (cleaner)
-weight: 500;">git pull --rebase origin main # Fetch remote changes without merging
-weight: 500;">git fetch origin
-weight: 500;">git fetch --all # Fetch all remotes
# Push local branch to remote
-weight: 500;">git push origin main # Push and set upstream tracking (then you can just use `-weight: 500;">git push`)
-weight: 500;">git push -u origin main # Pull = fetch + merge
-weight: 500;">git pull origin main # Pull with rebase instead of merge (cleaner)
-weight: 500;">git pull --rebase origin main # Fetch remote changes without merging
-weight: 500;">git fetch origin
-weight: 500;">git fetch --all # Fetch all remotes
# Push local branch to remote
-weight: 500;">git push origin main # Push and set upstream tracking (then you can just use `-weight: 500;">git push`)
-weight: 500;">git push -u origin main # Pull = fetch + merge
-weight: 500;">git pull origin main # Pull with rebase instead of merge (cleaner)
-weight: 500;">git pull --rebase origin main # Fetch remote changes without merging
-weight: 500;">git fetch origin
-weight: 500;">git fetch --all # Fetch all remotes
-weight: 500;">git push # Pushes to tracked remote branch
-weight: 500;">git pull # Pulls from tracked remote branch
-weight: 500;">git branch -vv # Shows tracking info for all branches
-weight: 500;">git push # Pushes to tracked remote branch
-weight: 500;">git pull # Pulls from tracked remote branch
-weight: 500;">git branch -vv # Shows tracking info for all branches
-weight: 500;">git push # Pushes to tracked remote branch
-weight: 500;">git pull # Pulls from tracked remote branch
-weight: 500;">git branch -vv # Shows tracking info for all branches
# Fix the last commit message
-weight: 500;">git commit --amend -m "correct message" # Add a forgotten file to the last commit
-weight: 500;">git add forgotten-file.js
-weight: 500;">git commit --amend --no-edit # Keeps the original message
# Fix the last commit message
-weight: 500;">git commit --amend -m "correct message" # Add a forgotten file to the last commit
-weight: 500;">git add forgotten-file.js
-weight: 500;">git commit --amend --no-edit # Keeps the original message
# Fix the last commit message
-weight: 500;">git commit --amend -m "correct message" # Add a forgotten file to the last commit
-weight: 500;">git add forgotten-file.js
-weight: 500;">git commit --amend --no-edit # Keeps the original message
-weight: 500;">git restore --staged file.js # Unstage (keep changes in working tree)
-weight: 500;">git restore file.js # Discard working tree changes (DESTRUCTIVE)
-weight: 500;">git restore --staged file.js # Unstage (keep changes in working tree)
-weight: 500;">git restore file.js # Discard working tree changes (DESTRUCTIVE)
-weight: 500;">git restore --staged file.js # Unstage (keep changes in working tree)
-weight: 500;">git restore file.js # Discard working tree changes (DESTRUCTIVE)
-weight: 500;">git revert abc1234 # Creates a new commit that undoes abc1234
-weight: 500;">git revert HEAD # Revert the last commit
-weight: 500;">git revert HEAD~3..HEAD # Revert the last 3 commits
-weight: 500;">git revert abc1234 # Creates a new commit that undoes abc1234
-weight: 500;">git revert HEAD # Revert the last commit
-weight: 500;">git revert HEAD~3..HEAD # Revert the last 3 commits
-weight: 500;">git revert abc1234 # Creates a new commit that undoes abc1234
-weight: 500;">git revert HEAD # Revert the last commit
-weight: 500;">git revert HEAD~3..HEAD # Revert the last 3 commits
-weight: 500;">git reset --soft HEAD~1 # Undo last commit, keep changes STAGED
-weight: 500;">git reset --mixed HEAD~1 # Undo last commit, keep changes UNSTAGED (default)
-weight: 500;">git reset --hard HEAD~1 # Undo last commit, DISCARD all changes
-weight: 500;">git reset --soft HEAD~1 # Undo last commit, keep changes STAGED
-weight: 500;">git reset --mixed HEAD~1 # Undo last commit, keep changes UNSTAGED (default)
-weight: 500;">git reset --hard HEAD~1 # Undo last commit, DISCARD all changes
-weight: 500;">git reset --soft HEAD~1 # Undo last commit, keep changes STAGED
-weight: 500;">git reset --mixed HEAD~1 # Undo last commit, keep changes UNSTAGED (default)
-weight: 500;">git reset --hard HEAD~1 # Undo last commit, DISCARD all changes
-weight: 500;">git reflog # See the full history of HEAD movements
-weight: 500;">git reset --hard abc1234 # Jump back to any previous state
-weight: 500;">git reflog # See the full history of HEAD movements
-weight: 500;">git reset --hard abc1234 # Jump back to any previous state
-weight: 500;">git reflog # See the full history of HEAD movements
-weight: 500;">git reset --hard abc1234 # Jump back to any previous state
-weight: 500;">git stash # Stash all uncommitted changes
-weight: 500;">git stash push -m "wip: login form validation" # With a label -weight: 500;">git stash list # See all stashes
-weight: 500;">git stash pop # Apply most recent stash and -weight: 500;">remove it
-weight: 500;">git stash apply stash@{2} # Apply a specific stash (keep it in the list)
-weight: 500;">git stash drop stash@{0} # Delete a specific stash
-weight: 500;">git stash clear # Delete all stashes # Stash including untracked files
-weight: 500;">git stash -u # Create a branch from a stash
-weight: 500;">git stash branch feature/wip stash@{0}
-weight: 500;">git stash # Stash all uncommitted changes
-weight: 500;">git stash push -m "wip: login form validation" # With a label -weight: 500;">git stash list # See all stashes
-weight: 500;">git stash pop # Apply most recent stash and -weight: 500;">remove it
-weight: 500;">git stash apply stash@{2} # Apply a specific stash (keep it in the list)
-weight: 500;">git stash drop stash@{0} # Delete a specific stash
-weight: 500;">git stash clear # Delete all stashes # Stash including untracked files
-weight: 500;">git stash -u # Create a branch from a stash
-weight: 500;">git stash branch feature/wip stash@{0}
-weight: 500;">git stash # Stash all uncommitted changes
-weight: 500;">git stash push -m "wip: login form validation" # With a label -weight: 500;">git stash list # See all stashes
-weight: 500;">git stash pop # Apply most recent stash and -weight: 500;">remove it
-weight: 500;">git stash apply stash@{2} # Apply a specific stash (keep it in the list)
-weight: 500;">git stash drop stash@{0} # Delete a specific stash
-weight: 500;">git stash clear # Delete all stashes # Stash including untracked files
-weight: 500;">git stash -u # Create a branch from a stash
-weight: 500;">git stash branch feature/wip stash@{0}
-weight: 500;">git tag # List all tags
-weight: 500;">git tag v1.0.0 # Lightweight tag (just a pointer)
-weight: 500;">git tag -a v1.0.0 -m "Release 1.0.0" # Annotated tag (recommended) -weight: 500;">git push origin v1.0.0 # Push a specific tag
-weight: 500;">git push origin --tags # Push all tags -weight: 500;">git tag -d v1.0.0 # Delete local tag
-weight: 500;">git push origin --delete v1.0.0 # Delete remote tag
-weight: 500;">git tag # List all tags
-weight: 500;">git tag v1.0.0 # Lightweight tag (just a pointer)
-weight: 500;">git tag -a v1.0.0 -m "Release 1.0.0" # Annotated tag (recommended) -weight: 500;">git push origin v1.0.0 # Push a specific tag
-weight: 500;">git push origin --tags # Push all tags -weight: 500;">git tag -d v1.0.0 # Delete local tag
-weight: 500;">git push origin --delete v1.0.0 # Delete remote tag
-weight: 500;">git tag # List all tags
-weight: 500;">git tag v1.0.0 # Lightweight tag (just a pointer)
-weight: 500;">git tag -a v1.0.0 -m "Release 1.0.0" # Annotated tag (recommended) -weight: 500;">git push origin v1.0.0 # Push a specific tag
-weight: 500;">git push origin --tags # Push all tags -weight: 500;">git tag -d v1.0.0 # Delete local tag
-weight: 500;">git push origin --delete v1.0.0 # Delete remote tag
# Dependencies
node_modules/
vendor/ # Build output
dist/
build/
*.min.js # Environment & secrets
.env
.env.local
*.pem
*.key # OS files
.DS_Store
Thumbs.db # Editor files
.vscode/
.idea/
*.swp
# Dependencies
node_modules/
vendor/ # Build output
dist/
build/
*.min.js # Environment & secrets
.env
.env.local
*.pem
*.key # OS files
.DS_Store
Thumbs.db # Editor files
.vscode/
.idea/
*.swp
# Dependencies
node_modules/
vendor/ # Build output
dist/
build/
*.min.js # Environment & secrets
.env
.env.local
*.pem
*.key # OS files
.DS_Store
Thumbs.db # Editor files
.vscode/
.idea/
*.swp
# If you added .env to .gitignore but already committed it:
-weight: 500;">git rm --cached .env
-weight: 500;">git commit -m "chore: -weight: 500;">remove .env from tracking"
# If you added .env to .gitignore but already committed it:
-weight: 500;">git rm --cached .env
-weight: 500;">git commit -m "chore: -weight: 500;">remove .env from tracking"
# If you added .env to .gitignore but already committed it:
-weight: 500;">git rm --cached .env
-weight: 500;">git commit -m "chore: -weight: 500;">remove .env from tracking"
main โโโ stable production code
develop โโโ integration branch
feature/* โโโ new features (branch from develop)
release/* โโโ release prep (branch from develop)
hotfix/* โโโ urgent fixes (branch from main)
main โโโ stable production code
develop โโโ integration branch
feature/* โโโ new features (branch from develop)
release/* โโโ release prep (branch from develop)
hotfix/* โโโ urgent fixes (branch from main)
main โโโ stable production code
develop โโโ integration branch
feature/* โโโ new features (branch from develop)
release/* โโโ release prep (branch from develop)
hotfix/* โโโ urgent fixes (branch from main)
main โโโ always deployable
feature/* โโโ branch from main, PR back to main, deploy
main โโโ always deployable
feature/* โโโ branch from main, PR back to main, deploy
main โโโ always deployable
feature/* โโโ branch from main, PR back to main, deploy
main โโโ everyone commits here (short-lived branches only)
main โโโ everyone commits here (short-lived branches only)
main โโโ everyone commits here (short-lived branches only)
# Setup
-weight: 500;">git config --global user.name "Name"
-weight: 500;">git config --global user.email "email" # Start
-weight: 500;">git init
-weight: 500;">git clone <url> # Daily workflow
-weight: 500;">git -weight: 500;">status
-weight: 500;">git add .
-weight: 500;">git commit -m "message"
-weight: 500;">git push
-weight: 500;">git pull # Branches
-weight: 500;">git switch -c feature/name
-weight: 500;">git merge feature/name
-weight: 500;">git rebase main
-weight: 500;">git branch -d feature/name # Inspection
-weight: 500;">git log --oneline --graph --all
-weight: 500;">git diff
-weight: 500;">git show <commit> # Undo
-weight: 500;">git restore --staged <file>
-weight: 500;">git revert <commit>
-weight: 500;">git reset --soft HEAD~1
-weight: 500;">git reflog # Remote
-weight: 500;">git remote add origin <url>
-weight: 500;">git fetch --all
-weight: 500;">git push -u origin main
# Setup
-weight: 500;">git config --global user.name "Name"
-weight: 500;">git config --global user.email "email" # Start
-weight: 500;">git init
-weight: 500;">git clone <url> # Daily workflow
-weight: 500;">git -weight: 500;">status
-weight: 500;">git add .
-weight: 500;">git commit -m "message"
-weight: 500;">git push
-weight: 500;">git pull # Branches
-weight: 500;">git switch -c feature/name
-weight: 500;">git merge feature/name
-weight: 500;">git rebase main
-weight: 500;">git branch -d feature/name # Inspection
-weight: 500;">git log --oneline --graph --all
-weight: 500;">git diff
-weight: 500;">git show <commit> # Undo
-weight: 500;">git restore --staged <file>
-weight: 500;">git revert <commit>
-weight: 500;">git reset --soft HEAD~1
-weight: 500;">git reflog # Remote
-weight: 500;">git remote add origin <url>
-weight: 500;">git fetch --all
-weight: 500;">git push -u origin main
# Setup
-weight: 500;">git config --global user.name "Name"
-weight: 500;">git config --global user.email "email" # Start
-weight: 500;">git init
-weight: 500;">git clone <url> # Daily workflow
-weight: 500;">git -weight: 500;">status
-weight: 500;">git add .
-weight: 500;">git commit -m "message"
-weight: 500;">git push
-weight: 500;">git pull # Branches
-weight: 500;">git switch -c feature/name
-weight: 500;">git merge feature/name
-weight: 500;">git rebase main
-weight: 500;">git branch -d feature/name # Inspection
-weight: 500;">git log --oneline --graph --all
-weight: 500;">git diff
-weight: 500;">git show <commit> # Undo
-weight: 500;">git restore --staged <file>
-weight: 500;">git revert <commit>
-weight: 500;">git reset --soft HEAD~1
-weight: 500;">git reflog # Remote
-weight: 500;">git remote add origin <url>
-weight: 500;">git fetch --all
-weight: 500;">git push -u origin main
# Remove a file from ALL history (nuclear option)
-weight: 500;">git filter-branch --force --index-filter \ "-weight: 500;">git rm --cached --ignore-unmatch path/to/secret.env" \ --prune-empty --tag-name-filter cat -- --all # Then force push and rotate your credentials immediately
-weight: 500;">git push origin --force --all
# Remove a file from ALL history (nuclear option)
-weight: 500;">git filter-branch --force --index-filter \ "-weight: 500;">git rm --cached --ignore-unmatch path/to/secret.env" \ --prune-empty --tag-name-filter cat -- --all # Then force push and rotate your credentials immediately
-weight: 500;">git push origin --force --all
# Remove a file from ALL history (nuclear option)
-weight: 500;">git filter-branch --force --index-filter \ "-weight: 500;">git rm --cached --ignore-unmatch path/to/secret.env" \ --prune-empty --tag-name-filter cat -- --all # Then force push and rotate your credentials immediately
-weight: 500;">git push origin --force --all
# When a merge conflict occurs, Git marks the file:
<<<<<<< HEAD your changes
======= incoming changes
>>>>>>> feature/login # After resolving manually:
-weight: 500;">git add resolved-file.js
-weight: 500;">git commit # or -weight: 500;">git rebase --continue if rebasing
# When a merge conflict occurs, Git marks the file:
<<<<<<< HEAD your changes
======= incoming changes
>>>>>>> feature/login # After resolving manually:
-weight: 500;">git add resolved-file.js
-weight: 500;">git commit # or -weight: 500;">git rebase --continue if rebasing
# When a merge conflict occurs, Git marks the file:
<<<<<<< HEAD your changes
======= incoming changes
>>>>>>> feature/login # After resolving manually:
-weight: 500;">git add resolved-file.js
-weight: 500;">git commit # or -weight: 500;">git rebase --continue if rebasing
-weight: 500;">git revert HEAD # If others may have pulled it
-weight: 500;">git push origin --force # Only if no one else has the commits
-weight: 500;">git revert HEAD # If others may have pulled it
-weight: 500;">git push origin --force # Only if no one else has the commits
-weight: 500;">git revert HEAD # If others may have pulled it
-weight: 500;">git push origin --force # Only if no one else has the commits
# Use rebase by default
-weight: 500;">git config --global pull.rebase true
# Use rebase by default
-weight: 500;">git config --global pull.rebase true
# Use rebase by default
-weight: 500;">git config --global pull.rebase true - Repository (repo) โ A project tracked by Git (the .-weight: 500;">git folder)
- Commit โ A snapshot of your files at a point in time
- Branch โ An independent line of development
- Remote โ A copy of the repo hosted elsewhere (GitHub, GitLab, etc.)
- Working tree โ The files you're currently editing
- Staging area (index) โ Where you prepare changes before committing - Git installed: -weight: 500;">git-scm.com
- A terminal you're comfortable with
- (Optional) A GitHub account for remote repos - Setup โ configuring Git globally for clean commit attribution
- Core workflow โ stage, commit, push โ the heartbeat of Git
- Branching โ creating, merging, and deleting branches with confidence
- Rebasing โ rewriting history for a cleaner log
- Remotes โ pushing, pulling, fetching, and tracking
- Undoing โ revert, reset, restore, and the reflog safety net
- Stashing โ saving work-in-progress without a commit
- Tags โ marking releases with annotated tags
- Branching strategies โ Git Flow vs GitHub Flow vs Trunk-based
- Common pitfalls โ handling conflicts, secrets, and wrong-branch pushes - GitHub Actions โ automate CI/CD triggered by Git events
- Signed commits โ verify your identity with GPG keys
- -weight: 500;">git bisect โ binary search your history to find which commit introduced a bug
- Worktrees โ check out multiple branches at once in different directories