Complete Guide · Novice → Professional

Master
Git &
GitHub

Every concept, every command, every workflow — from your very first commit to production-grade branching strategies, automated guardrails, and team administration.

Version Control
Branching & Merging
Rollback & Reset
GitHub Actions
Branch Protection
Git Hooks
Windows 11 Ready
git log --oneline --graph --all
* a3f9d1e (HEADmain, origin/main)
| 🚀 feat: add AI response streaming
* c7e2b84 fix: handle empty API response
|\
| * f1d4a92 (feature/auth)
| | ✨ feat: JWT authentication
| * 8b3c1f5 test: add auth unit tests
|/
* 2e7f093 refactor: extract API client
* 9d1a4b7 v1.0.0 🏷️ initial release
───────────────────────────────────
$ git status
On branch main. Nothing to commit.
Working tree clean ✓
01 · Foundation

What is Git?

Git is a distributed version control system. It tracks every change you make to your code, lets you travel back in time to any previous state, and lets multiple people work on the same project simultaneously — without overwriting each other's work.

📸

Snapshots, Not Diffs

Every time you "commit", Git takes a snapshot of all your files at that moment. Think of it like saving a game — you can always load a previous save.

🌿

Branching

Create separate "branches" to experiment or build features without touching the working code. Merge it back when it's ready. Branches are free and instant.

🤝

Collaboration

Everyone has the full history locally. You push changes to a shared server (GitHub) and pull others' changes. Conflicts are resolved explicitly — nothing is lost.

Git vs GitHub — They're Different Things

Local Tool

Git

A command-line tool installed on your computer. It manages the history of your project locally. No internet required. Created by Linus Torvalds in 2005.

Cloud Platform
🐙

GitHub

A website that hosts Git repositories in the cloud. Adds collaboration features: Pull Requests, Issues, Actions (CI/CD), team management, and code review.

The Three States — Understanding Git's Model

📝
Working Dir
Your files on disk
git add
📋
Staging Area
Changes ready to commit
git commit
🏛️
Repository
Permanent history
git push
☁️
Remote (GitHub)
Shared with team
💡
The staging area is unique to Git. It lets you craft the perfect commit. You might change 10 files but only stage 3 of them into one logical commit, then stage the other 7 into a second commit. This keeps your history clean and meaningful.
02 · Setup

Installing & Configuring Git

Get Git installed on Windows 11, configure your identity, set up SSH authentication for GitHub, and establish sane global defaults.

1

Install Git on Windows 11

Download Git from git-scm.com. During setup: choose VS Code as default editor, select "Git from the command line and also from 3rd-party software", and choose "Use Windows' default console window".

PowerShell — verify installation
PS> git --version
git version 2.45.2.windows.1
# Optional: install GitHub CLI for extra superpowers
PS> winget install GitHub.cli
Successfully installed GitHub CLI
2

Configure Your Identity

Git stamps every commit with your name and email. This is how GitHub knows which commits are yours.

Git Bash / Terminal
# Set globally (applies to all repos)
$ git config --global user.name "Your Name"
$ git config --global user.email "you@example.com"
# Set your preferred editor (VS Code)
$ git config --global core.editor "code --wait"
# Always use main as default branch name
$ git config --global init.defaultBranch main
# Better diff tool
$ git config --global diff.tool vscode
$ git config --global difftool.vscode.cmd 'code --wait --diff $LOCAL $REMOTE'
# Verify all settings
$ git config --global --list
3

Generate SSH Key & Connect to GitHub

SSH keys let you push/pull without typing your password every time. Much more secure than HTTPS with password.

Git Bash
# Generate ED25519 SSH key (modern, fast, secure)
$ ssh-keygen -t ed25519 -C "you@example.com"
Generating public/private ed25519 key pair.
Enter file: (press Enter for default ~/.ssh/id_ed25519)
Enter passphrase: (optional but recommended)
Your identification has been saved in ~/.ssh/id_ed25519
# Copy public key to clipboard
$ cat ~/.ssh/id_ed25519.pub | clip
# → Go to GitHub → Settings → SSH Keys → New SSH Key → Paste
# Test the connection
$ ssh -T git@github.com
Hi YourUsername! You've successfully authenticated.
4

The .gitconfig File — Global Settings

Your global git configuration lives at ~/.gitconfig. Here's a professional setup:

⚙️ ~/.gitconfig — complete professional setup
[user]
name = Your Name
email = you@example.com
signingkey = YOUR_GPG_KEY_ID  # for signed commits
[core]
editor = code --wait
autocrlf = true  # Windows: converts LF↔CRLF
whitespace = trailing-space,space-before-tab
[init]
defaultBranch = main
[alias]
st = status -sb
lg = log --oneline --graph --decorate --all
undo = reset HEAD~1 --mixed
wip = !git add -A && git commit -m "WIP"
pushup = push -u origin HEAD
recent = branch --sort=-committerdate --format='%(refname:short)'
[pull]
rebase = false  # merge on pull (safer default)
[push]
default = current
[commit]
gpgsign = true  # sign all commits (optional but professional)
[color]
ui = auto
03 · Core Workflow

The Daily Git Workflow

Every developer follows this cycle hundreds of times. Master these commands and you'll handle 90% of daily Git work confidently.

Working Dir
→ add →
Staging
→ commit →
Local Repo
→ push →
GitHub
Complete daily workflow walkthrough
━━━ INITIALIZE A NEW REPOSITORY ━━━━━━━━━━━━━━━━━━━━━━━━━
$ mkdir my-project && cd my-project
$ git init
Initialized empty Git repository in /my-project/.git/
━━━ OR CLONE AN EXISTING REPO ━━━━━━━━━━━━━━━━━━━━━━━━━━
$ git clone git@github.com:username/repo.git
$ git clone git@github.com:username/repo.git my-folder  # rename
$ git clone --depth 1 git@github.com:u/repo.git      # shallow clone (faster)
━━━ CHECK STATUS ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
$ git status           # full status
$ git status -sb        # short format (alias: git st)
M src/app.py           # M = modified
?? newfile.txt          # ?? = untracked
━━━ STAGE CHANGES ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
$ git add filename.py   # stage single file
$ git add src/          # stage entire folder
$ git add .             # stage everything changed
$ git add -p            # interactive: stage PARTS of files (chunks)
$ git restore --staged file.py # unstage a file
━━━ VIEW DIFFERENCES ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
$ git diff              # unstaged changes
$ git diff --staged      # staged changes (what will be committed)
$ git diff main..feature # diff between two branches
$ git diff HEAD~3..HEAD  # diff last 3 commits
━━━ COMMIT ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
$ git commit -m "feat: add user authentication"
$ git commit                # opens editor for multi-line message
$ git commit -am "fix: typo"  # stage+commit tracked files in one
$ git commit --amend          # modify the LAST commit (message or files)
━━━ VIEW HISTORY ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
$ git log                   # full log
$ git log --oneline          # compact, one line per commit
$ git log --oneline --graph --all # visual tree of all branches
$ git log -p filename.py     # history of a specific file
$ git log --author="Name" --since="2 weeks ago"
$ git show a3f9d1e           # show a specific commit's changes
$ git blame filename.py      # who wrote which line

Conventional Commits — Writing Good Commit Messages

Conventional Commits is a standard format that makes your history readable and enables automated changelogs and version bumping.

📝 Conventional Commit Format
# Format: <type>(<scope>): <short summary>
# Types:
feat: New feature for the user
fix: Bug fix for the user
docs: Documentation changes
style: Formatting, no code logic change
refactor:Code change that isn't fix or feature
test: Adding or fixing tests
chore: Build process, dependency updates
perf: Performance improvement
ci: CI/CD pipeline changes
# Good examples:
feat(auth): add JWT refresh token support
fix(api): handle null response from Kimi endpoint
docs(readme): add Docker deployment instructions
feat!: remove deprecated v1 API endpoints  # ! = breaking change
# Multi-line commit (body + footer):
feat(payments): integrate Stripe subscription billing
 
Adds monthly and annual subscription tiers.
Includes webhook handling for payment events.
 
Closes #142
BREAKING CHANGE: removes legacy PayPal integration

The .gitignore File

Tell Git which files to never track. Critical for keeping secrets and build artifacts out of your repo.

📄 .gitignore — common patterns
# Environment & Secrets — NEVER COMMIT
.env
.env.*
secrets/
*.pem
*.key
# Python
__pycache__/
*.pyc
.venv/
dist/
*.egg-info/
# Node.js
node_modules/
.next/
build/
# OS & Editor
.DS_Store
Thumbs.db
.vscode/settings.json
*.swp
# Logs & databases
*.log
*.sqlite
04 · Branching

Branching Strategies

Branches are the backbone of team collaboration. They are free, instant, and allow parallel development without interference. Understanding branching strategies separates junior developers from seniors.

●━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━●━━━━━━━━━━━━● main v1.1.0
│                              ▲            │
│ ●━━━━━━━━━━━━━━━━━━━━━●━━━━━━━━━━━━━━━━●━━━━━━━━━━━━● develop
│ │                     │                 │
│ │ ●━━━━━━━━━━━━━━━━━━━━━━┘  feature/auth
│ │        ●━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┘ hotfix/login-crash
└ ●━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┘ release/1.1
Git Flow: main ← develop ← feature branches | hotfix ← main | release ← develop

All Branch Commands

Complete branch management reference
━━━ CREATING BRANCHES ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
$ git branch feature/auth              # create (don't switch)
$ git switch -c feature/auth            # create AND switch (modern)
$ git checkout -b feature/auth           # create AND switch (classic)
$ git switch -c hotfix/bug main          # branch FROM specific branch
$ git switch -c fix/bug a3f9d1e          # branch from specific commit SHA
━━━ VIEWING & SWITCHING ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
$ git branch                            # local branches only
$ git branch -a                          # local + remote branches
$ git branch -v                          # with last commit info
$ git branch --merged                    # branches already merged
$ git branch --no-merged                 # branches NOT yet merged
$ git branch --sort=-committerdate       # sorted by most recent activity
$ git switch main                        # switch to main
$ git switch -                           # switch to previous branch (like cd -)
━━━ DELETING & RENAMING ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
$ git branch -d feature/auth            # delete (safe — only if merged)
$ git branch -D feature/auth            # force delete (unmerged ok)
$ git push origin --delete feature/auth  # delete REMOTE branch
$ git branch -m old-name new-name        # rename local branch
# Bulk-delete all merged local branches (safe):
$ git branch --merged | grep -v "main\|develop\|release" | xargs git branch -d
━━━ TRACKING & SYNCING ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
$ git push -u origin feature/auth        # push + set upstream tracking
$ git fetch --all --prune                 # update refs + remove stale remote branches
$ git pull --rebase                       # sync with linear history

Branching Strategies Compared

Most Popular

GitHub Flow

main is always deployable. Create a branch → commit → open PR → review → merge to main → deploy. Ideal for continuous delivery teams. Simple, no ceremony.

Enterprise

Git Flow

main + develop + feature/* + release/* + hotfix/*. Structured for versioned software releases. More ceremony, very controlled. Good for apps with explicit release windows.

Big Teams

Trunk-Based Development

Everyone commits directly to main or uses very short-lived branches (<2 days). Relies on feature flags to hide incomplete work. Used by Google and Meta. Requires strong CI.

Recommended

Release Flow (Microsoft)

Feature branches off main, merged via PR. Release branches cut from main at release time. Patches cherry-picked to release branches. Great balance of control and agility.

05 · Merging

Merging, Rebasing & Conflict Resolution

Getting code from one branch into another is the heart of collaboration. Three strategies exist, each with different tradeoffs for your commit history and team workflow.

Default

Merge Commit

Creates a merge commit that ties two branches together. Preserves full branching history. Use when you want to clearly see when branches diverged and rejoined.

Clean History

Squash & Merge

Squashes all commits from the feature branch into one single commit on main. Cleaner main history — each PR becomes one atomic commit. Individual commits from the branch are discarded.

Linear History

Rebase & Merge

Replays your commits on top of the target branch for a perfectly linear history. Rewrites commit SHAs — never rebase shared or public branches.

Merge, rebase, cherry-pick & conflict resolution
━━━ STANDARD MERGE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
$ git switch main
$ git merge feature/auth               # merge feature into main
$ git merge --no-ff feature/auth        # always create merge commit (even if fast-forward possible)
$ git merge --squash feature/auth       # squash all commits into one staged change (then commit)
$ git merge --abort                     # abort a conflicted merge
━━━ REBASE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
$ git switch feature/auth
$ git rebase main                       # rebase feature onto latest main
$ git rebase --interactive HEAD~4        # interactive: edit/squash/drop last 4 commits
$ git rebase --continue                  # continue after resolving conflict
$ git rebase --abort                     # cancel the rebase entirely
$ git rebase --skip                      # skip the current conflicting commit
━━━ CHERRY PICK ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# Apply a specific commit from one branch onto another
$ git cherry-pick a3f9d1e               # apply single commit
$ git cherry-pick a3f9d1e..c7e2b84      # apply a range of commits
$ git cherry-pick -n a3f9d1e            # apply changes but don't commit yet
$ git cherry-pick --abort                # cancel if conflict
━━━ RESOLVING MERGE CONFLICTS ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
$ git merge feature/auth
CONFLICT (content): Merge conflict in src/app.py
Automatic merge failed; fix conflicts and then commit.
# Git marks conflicts inside the file like this:
<<<<<<< HEAD (your current branch)
def get_user(id):
return db.find(id)
=======
def get_user(user_id):
return db.query(user_id).first()
>>>>>>> feature/auth (incoming)
# Edit the file to the desired final state, then:
$ git add src/app.py                     # mark resolved
$ git commit                               # complete the merge
# Shortcuts to accept entire file from one side:
$ git checkout --ours src/app.py         # keep our version entirely
$ git checkout --theirs src/app.py        # keep their version entirely
$ git mergetool                            # open visual 3-way merge tool
$ git diff --conflict                      # show all conflict markers in all files
⚠️
Merge vs Rebase Rule: Use rebase to keep your local feature branch up to date with main (before opening a PR). Use merge when integrating completed work. Never rebase a branch that others are working on — it rewrites history and forces everyone else to re-sync.
06 · Time Travel

Undo, Rollback & Recovery

One of Git's most powerful properties — you can undo almost anything. Knowing which tool to use is critical. Some commands rewrite history (dangerous on shared branches), others are always safe.

🔑
The Golden Rule: reset --hard, rebase, and commit --amend rewrite history — safe on private branches only. For shared branches like main or develop, always use git revert — it creates a new commit that undoes changes, preserving full history for everyone.

Undo Decision Map

What do I need to undo?
Unsaved edit / unstaged
git restore file
Staged but not committed
git restore --staged
Last commit (private branch)
git reset HEAD~1
Commit on shared branch
git revert <sha>
Lost commit / deleted branch
git reflog
Complete rollback & recovery toolkit
━━━ DISCARD UNCOMMITTED CHANGES ━━━━━━━━━━━━━━━━━━━━━━━━━━━━
$ git restore filename.py               # discard unstaged changes in one file
$ git restore .                          # discard ALL unstaged changes in repo
$ git restore --staged filename.py       # unstage (keeps changes in working dir)
$ git clean -fd                          # remove untracked files and dirs
$ git clean -fdn                         # dry run — preview what would be removed
$ git clean -fdx                         # also remove gitignored files (nuclear option)
━━━ RESET (REWRITES HISTORY — PRIVATE BRANCHES ONLY ⚠️) ━━━━━
$ git reset HEAD~1 --soft                # undo commit, keep changes STAGED
$ git reset HEAD~1 --mixed               # undo commit, keep changes UNSTAGED (default)
$ git reset HEAD~1 --hard                # undo commit AND discard all changes ⚠️
$ git reset HEAD~3 --soft                # undo last 3 commits, keep changes staged
$ git reset a3f9d1e --hard               # jump to specific commit, discard everything after ⚠️
━━━ REVERT (SAFE — ALWAYS OK ON SHARED BRANCHES ✓) ━━━━━━━━━━
$ git revert a3f9d1e                     # create a new commit that undoes this commit
$ git revert HEAD                         # revert last commit
$ git revert HEAD~3..HEAD                # revert last 3 commits (3 revert commits)
$ git revert -n a3f9d1e                  # revert but stage, don't commit yet
$ git revert --no-edit HEAD              # revert without opening message editor
━━━ STASH — PARK WORK IN PROGRESS ━━━━━━━━━━━━━━━━━━━━━━━━━━
$ git stash                              # stash all changes (working dir → clean)
$ git stash push -m "WIP: auth form refactor"# stash with a descriptive name
$ git stash push -u -m "include untracked" # stash including untracked files
$ git stash list                          # see all stashes
$ git stash show stash@{0}               # preview stash contents
$ git stash pop                           # apply latest stash and remove it
$ git stash apply stash@{2}              # apply specific stash (keeps it in list)
$ git stash drop stash@{0}               # delete a specific stash
$ git stash clear                         # wipe ALL stashes
$ git stash branch feature/new stash@{0} # create new branch from stash
━━━ REFLOG — THE ULTIMATE SAFETY NET (90 DAYS) ━━━━━━━━━━━━━━
# Reflog records EVERY movement of HEAD — even after hard reset!
$ git reflog
a3f9d1e HEAD@{0}: commit: feat: add user auth
c7e2b84 HEAD@{1}: merge feature/auth: Merge made by 'ort'
8b3c1f5 HEAD@{2}: checkout: moving from feature to main
f1d4a92 HEAD@{3}: reset: moving to HEAD~1
# Recover a deleted branch or lost commit:
$ git switch -c recovered-branch HEAD@{3}
$ git reset --hard HEAD@{2}             # undo a hard reset!
$ git cherry-pick f1d4a92               # recover a single lost commit
━━━ TAGGING VERSIONS ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
$ git tag v1.0.0                        # lightweight tag (just a pointer)
$ git tag -a v1.0.0 -m "Production release"# annotated tag (preferred — stores date, author)
$ git tag -a v0.9.1 a3f9d1e -m "Hotfix" # tag a past commit
$ git tag                                # list all tags
$ git push origin v1.0.0                # push one tag to remote
$ git push origin --tags                 # push all tags to remote
$ git tag -d v1.0.0                      # delete local tag
$ git push origin --delete v1.0.0       # delete remote tag
07 · Remote Operations

Working with Remotes

A remote is a version of your repository hosted on a server. You can have multiple — origin (your fork or primary), upstream (the original source when contributing to open source). All sync operations go through remotes.

How Remote Tracking Works

💻
Local Repo
Your machine
git push →
← git pull/fetch
☁️
origin
Your GitHub repo
← git fetch upstream
PR/merge →
🌐
upstream
Original source repo
Complete remote operations reference
━━━ MANAGE REMOTES ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
$ git remote -v                                     # list all remotes with URLs
$ git remote add origin git@github.com:you/repo.git      # add remote
$ git remote add upstream git@github.com:original/repo.git  # add upstream for fork
$ git remote set-url origin git@github.com:new/repo.git      # change URL
$ git remote rename origin old-origin                       # rename remote
$ git remote remove upstream                                  # remove remote
$ git remote show origin                                       # detailed info about a remote
━━━ FETCH — DOWNLOAD WITHOUT MERGING ━━━━━━━━━━━━━━━━━━━━━━━━
$ git fetch origin                  # download remote changes (doesn't touch working dir)
$ git fetch --all                    # fetch from ALL remotes
$ git fetch --all --prune             # fetch + remove stale remote-tracking branches
$ git fetch origin feature/auth       # fetch a single branch
━━━ PULL — FETCH + MERGE/REBASE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
$ git pull                           # fetch + merge current tracked branch
$ git pull origin main                # explicitly pull main from origin
$ git pull --rebase                   # fetch + rebase (cleaner history, recommended)
$ git pull --rebase=interactive       # pull with interactive rebase control
━━━ PUSH — UPLOAD TO REMOTE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
$ git push                           # push current branch to its tracked remote
$ git push origin main                # explicit push
$ git push -u origin feature/auth      # push new branch + set upstream tracking
$ git push -u origin HEAD               # push current branch with same name (quick alias)
$ git push origin --delete feature/old  # delete a remote branch
$ git push --force-with-lease           # safe force push — fails if someone else pushed ✓
$ git push --force                      # dangerous force push — overwrites remote ⚠️
$ git push --tags                       # push all local tags
━━━ SYNCING A FORK WITH UPSTREAM ━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# Keep your fork in sync with the original project
$ git fetch upstream
$ git switch main
$ git merge upstream/main                # or: git rebase upstream/main
$ git push origin main                   # update your fork on GitHub
08 · GitHub Platform

GitHub Pull Requests & Code Review

GitHub transforms Git into a collaboration platform. Pull Requests are the central mechanism for proposing, reviewing, discussing, and safely merging changes across teams of any size.

Create Branch
Commit & Push
Open PR
CI Checks Run
Code Review
Approve & Merge
Auto Deploy
GitHub CLI — complete gh command reference
━━━ AUTH & SETUP ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
$ gh auth login                                # login to GitHub
$ gh auth status                               # check login status
$ gh repo create my-project --public             # create repo from CLI
$ gh repo clone username/repo                    # clone any public repo
$ gh repo fork username/repo --clone             # fork + clone in one step
━━━ PULL REQUESTS ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
$ gh pr create                                  # interactive PR creation
$ gh pr create --title "feat: add auth" --body "Desc" --base main
$ gh pr create --draft                            # open as draft
$ gh pr create --reviewer alice,bob                # request reviewers
$ gh pr list                                     # list open PRs
$ gh pr list --state all --author "@me"            # your PRs all states
$ gh pr view 42                                  # view PR #42
$ gh pr view 42 --web                             # open in browser
$ gh pr checkout 42                               # check out PR locally to test
$ gh pr review --approve                          # approve current branch PR
$ gh pr review --request-changes -b "Fix X"        # request changes with comment
$ gh pr comment 42 -b "Looks good, minor nit"        # add comment
$ gh pr merge 42 --squash --delete-branch          # merge with squash + cleanup
$ gh pr merge 42 --rebase                         # merge with rebase
$ gh pr close 42                                  # close without merging
$ gh pr ready 42                                  # convert draft to ready for review
━━━ ISSUES ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
$ gh issue create --title "Bug: login 500" --label "bug,critical"
$ gh issue list                                    # list open issues
$ gh issue list --label "bug" --assignee "@me"        # filtered issues
$ gh issue close 15 --comment "Fixed in PR #42"        # close with comment
━━━ RELEASES ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
$ gh release create v1.0.0 --generate-notes            # auto-generate changelog
$ gh release create v1.0.0 --notes "See CHANGELOG.md"  # manual notes
$ gh release list                                    # list all releases
$ gh release upload v1.0.0 ./dist/app.tar.gz            # attach binary assets

PR Template

📄 .github/PULL_REQUEST_TEMPLATE.md
## Summary
<!-- What does this PR do? Why? -->
## Type of Change
- [ ] feat: New feature
- [ ] fix: Bug fix
- [ ] refactor
- [ ] docs
- [ ] BREAKING CHANGE
## Testing
- [ ] Unit tests added/updated
- [ ] Integration tests pass
- [ ] Tested manually
## Checklist
- [ ] Self-reviewed the diff
- [ ] No secrets committed
- [ ] Docs updated if needed
- [ ] Closes # (issue number)

Issue Templates

📄 .github/ISSUE_TEMPLATE/bug_report.yml
name: Bug Report
description: File a bug
labels: ["bug"]
body:
- type: textarea
id: description
label: What happened?
required: true
- type: textarea
id: steps
label: Steps to reproduce
- type: input
id: version
label: Version
09 · Automation & Guardrails

Branch Protection & Commit Guardrails

Professional teams enforce quality automatically — preventing bad commits from entering the codebase, requiring peer reviews, running tests before every merge, detecting leaked secrets, and ensuring consistent formatting across the entire team.

Git Hooks — Run Scripts on Every Commit

🪝
Git Hooks are shell scripts in .git/hooks/ that fire automatically at key moments. Key hooks: pre-commit (runs before every commit — block bad code here), commit-msg (validates the message format), pre-push (runs tests before any push), prepare-commit-msg (auto-populate message templates).
🪝 .git/hooks/pre-commit — format, lint, secret detection, block direct main commits
#!/bin/sh
echo "🔍 Running pre-commit checks..."
# ─── 1. Block direct commits to main or develop ────────────
BRANCH=$(git symbolic-ref HEAD | sed 's|refs/heads/||')
if [ "$BRANCH" = "main" ] || [ "$BRANCH" = "develop" ]; then
echo "❌ Direct commits to '$BRANCH' are not allowed."
echo " Create a feature branch and open a PR instead."
exit 1
fi
# ─── 2. Detect leaked secrets in staged files ───────────────
STAGED=$(git diff --cached --name-only 2>/dev/null)
SECRET_PATTERNS='(AKIA[0-9A-Z]{16}|sk-[a-zA-Z0-9]{32,}|ghp_[a-zA-Z0-9]{36}|xoxb-[0-9]|AIza[0-9A-Za-z]{35}|-----BEGIN RSA PRIVATE KEY-----)'
if echo "$STAGED" | xargs git show :-- 2>/dev/null | grep -qE "$SECRET_PATTERNS"; then
echo "❌ Possible API key or secret detected in staged files!"
echo " Review staged files and remove secrets before committing."
exit 1
fi
# ─── 3. Python: auto-format with Black ──────────────────────
if command -v black >/dev/null 2>&1; then
black --check --quiet . || {
echo "❌ Code is not Black-formatted. Run: black ."
exit 1
}
fi
# ─── 4. Python: Ruff linter ─────────────────────────────────
if command -v ruff >/dev/null 2>&1; then
ruff check --quiet . || {
echo "❌ Ruff lint errors found. Run: ruff check --fix ."
exit 1
}
fi
# ─── 5. JavaScript / TypeScript: ESLint ─────────────────────
if [ -f "package.json" ] && command -v npx >/dev/null 2>&1; then
npx eslint --quiet . || {
echo "❌ ESLint errors. Run: npx eslint --fix ."
exit 1
}
fi
echo "✅ All pre-commit checks passed."
🪝 .git/hooks/commit-msg — enforce Conventional Commits format
#!/bin/sh
# Validates: type(scope)!: description (max 72 chars)
COMMIT_MSG=$(cat "$1")
TYPES="feat|fix|docs|style|refactor|test|chore|perf|ci|build|revert"
PATTERN="^($TYPES)(\(.+\))?(!)?: .{1,72}$"
# Allow merge commits and revert commits to bypass
if echo "$COMMIT_MSG" | grep -qE "^(Merge|Revert)"; then
exit 0
fi
if ! echo "$COMMIT_MSG" | head -1 | grep -qE "$PATTERN"; then
echo "❌ Commit message format error."
echo " Required: type(scope): short description"
echo " Types: feat fix docs style refactor test chore perf ci"
echo " Example: feat(auth): add JWT refresh token support"
exit 1
fi
🪝 .git/hooks/pre-push — run tests before any push to remote
#!/bin/sh
# Runs full test suite before every push. Slow but safe.
echo "🧪 Running tests before push..."
if command -v pytest >/dev/null 2>&1; then
pytest --quiet || { echo "❌ Tests failed — push aborted."; exit 1; }
fi
if [ -f "package.json" ]; then
npm test -- --watchAll=false || { echo "❌ Tests failed."; exit 1; }
fi
echo "✅ Tests passed. Pushing..."
💡
Make hooks executable: Run chmod +x .git/hooks/pre-commit .git/hooks/commit-msg .git/hooks/pre-push on Linux/Mac. On Windows, Git Bash respects the executable bit automatically. Without this step, hooks won't run.

Husky + lint-staged — Team-Wide Hooks (Committed to Git)

🐶
Individual .git/hooks/ files are not tracked by Git — only your machine has them. Husky manages hooks that ARE committed to the repository, so every developer on the team gets them automatically when they clone or pull.
Full Husky + lint-staged + commitlint setup
# Install all tooling
$ npm install --save-dev husky lint-staged @commitlint/cli @commitlint/config-conventional
# Initialize Husky (creates .husky/ folder)
$ npx husky init
# Set pre-commit hook to run lint-staged
$ echo "npx lint-staged" > .husky/pre-commit
# Set commit-msg hook to validate with commitlint
$ echo "npx --no -- commitlint --edit \$1" > .husky/commit-msg
# Set pre-push hook to run tests
$ echo "npm test -- --watchAll=false" > .husky/pre-push
# Create commitlint config
$ echo "export default { extends: ['@commitlint/config-conventional'] };" > commitlint.config.js
# Commit the hooks so every teammate gets them
$ git add .husky commitlint.config.js package.json && git commit -m "chore: setup husky hooks"
# Now: every git commit on every machine runs lint-staged + commitlint
$ git commit -m "bad message"
⧗ input: bad message
✖ subject may not be empty [subject-empty]
✖ type may not be empty [type-empty]
husky - commit-msg script failed (code 1)
📋 package.json — lint-staged: only lints files in your current commit (blazing fast)
"scripts": {
"prepare": "husky"                        // installs hooks on npm install
},
"lint-staged": {
// Only staged files are linted — instant feedback
"*.{js,ts,jsx,tsx}": [
"eslint --fix --max-warnings=0",
"prettier --write"
],
"*.py": ["black", "ruff check --fix"],
"*.{json,md,yaml,yml}": ["prettier --write"],
"*.go": ["gofmt -w"],
"*.rs": ["rustfmt"]
}

GitHub Branch Protection Rules

Navigate to: GitHub → Repo → Settings → Branches → Add branch ruleset. Apply rules to main and develop.

🔒

Require PR Reviews Before Merge

Set 1–2 required approvals. Enable "Dismiss stale reviews when new commits are pushed" so every change gets a fresh pair of eyes. Combine with CODEOWNERS for domain-specific reviewers.

Require Status Checks to Pass

Block merge until all GitHub Actions CI jobs pass (lint, tests, security scan). Select "Require branches to be up to date before merging" to prevent stale merges.

📜

Require Linear History

Forces squash or rebase merges only — no merge commits on main. Keeps the history clean, readable, and easily bisectable when hunting bugs in production.

🚫

Block Force Push & Deletion

"Do not allow force pushes" and "Do not allow deletions" on protected branches. Prevents malicious or accidental history rewrites even by admins.

✍️

Require Signed Commits

Only allow GPG-signed commits to merge. Proves that commits actually came from the claimed author — critical for supply chain security in high-stakes repos.

📋

Require Conversation Resolution

All PR review comments must be marked "resolved" before merge. Ensures no feedback is silently ignored — every requested change is acknowledged.

GitHub Actions CI Pipeline

📋 .github/workflows/ci.yml — full quality gate on every PR
name: CI Quality Gate
on:
pull_request:
branches: [main, develop]
push:
branches: [main]
jobs:
# ── Job 1: Lint & Format ─────────────────────────────────
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- run: pip install black ruff
- run: black --check .
- run: ruff check .
# ── Job 2: Tests ─────────────────────────────────────────
test:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ['3.11', '3.12']    # test multiple versions
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- name: Cache pip packages
uses: actions/cache@v4
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements*.txt') }}
- run: pip install -r requirements.txt -r requirements-dev.txt
- run: pytest --cov=. --cov-report=xml --cov-fail-under=80
- uses: codecov/codecov-action@v4
# ── Job 3: Security Scan ─────────────────────────────────
security:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0    # full history for secret scanning
- name: Scan for secrets (TruffleHog)
uses: trufflesecurity/trufflehog@main
with:
path: ./
base: ${{ github.event.repository.default_branch }}
head: HEAD
- name: Dependency vulnerability check (pip-audit)
run: pip install pip-audit && pip-audit

CODEOWNERS — Automatic Reviewer Assignment

📄 .github/CODEOWNERS — maps file patterns to required reviewers
# Everyone must review all files (catch-all)
*                              @team-lead @senior-dev
# Auth and payments: security team must sign off
/src/auth/                     @security-team
/src/payments/                 @payments-team @security-team
# Infrastructure changes: DevOps team reviews
*.tf                              @devops-team
Dockerfile                        @devops-team
docker-compose*.yml              @devops-team
.github/workflows/               @devops-team @team-lead
# Frontend: frontend team owns this
/src/components/                 @frontend-team
/src/styles/                      @frontend-team
# Documentation: anyone can contribute, docs team reviews
/docs/                             @docs-team
*.md                               @docs-team
10 · Pro Techniques

Advanced Git Mastery

These commands separate senior engineers from everyone else. Master them and you'll be the person teammates come to when things go catastrophically wrong — or when they need to surgically extract one commit from a three-month-old branch.

Interactive Rebase — Rewrite History Like a Pro

✍️
Interactive rebase lets you edit, squash, reorder, rename, or delete commits before they're shared. Use it to clean up a messy feature branch before opening a PR — turn 14 "wip", "oops", and "fix typo" commits into 3 clean, logical commits.
Interactive rebase — the most powerful history editing tool
$ git rebase -i HEAD~5            # edit last 5 commits interactively
$ git rebase -i main               # edit all commits not yet on main
$ git rebase -i --root              # edit the entire repo history
# Opens your editor — each line is one commit. Change the verb:
pick a3f9d1e feat: add user authentication
squash c7e2b84 fix: typo in auth module      # ← merge into previous commit
reword f1d4a92 wip: half-done password reset  # ← keep but rename message
edit 8b3c1f5 add login endpoint            # ← pause to amend files too
fixup 2e7f093 oops forgot semicolon         # ← squash, discard its message
drop 9d1a4b7 console.log debugging         # ← delete this commit entirely
# After saving, Git replays each commit with your changes
$ git rebase --continue             # after resolving any conflicts
$ git rebase --abort                # cancel and restore original

Git Bisect — Binary Search to Find a Bug

🔬
Git bisect performs a binary search through your commit history to find exactly which commit introduced a bug. With 1000 commits to check, it finds the culprit in just 10 steps. Can be fully automated with a test script.
git bisect — find which commit broke the build
$ git bisect start                             # begin bisect session
$ git bisect bad                               # current HEAD is broken
$ git bisect good v1.2.0                       # v1.2.0 was fine (tag or SHA)
Bisecting: 127 revisions left to test (roughly 7 steps)
# Git checks out the middle commit. Test your app, then:
$ git bisect good                             # this commit is fine → move forward
$ git bisect bad                              # broken → move backward
# Repeat 5–7 times until:
a3f9d1e is the first bad commit
Author: Dev <dev@co.com> Date: Mon Feb 10
feat(payments): migrate to new Stripe SDK
$ git bisect reset                            # return to HEAD when done
━━━ AUTOMATE BISECT WITH A TEST SCRIPT ━━━━━━━━━━━━━━━━━━━━━━
# Script exits 0=good, 1=bad. Git runs it on each checkout automatically.
$ git bisect start
$ git bisect bad HEAD
$ git bisect good v1.2.0
$ git bisect run pytest tests/test_payments.py -x -q
running: pytest tests/test_payments.py -x -q
... (Git checks out ~7 commits automatically)
a3f9d1e is the first bad commit

Advanced Techniques — Full Reference

Pro-level Git commands
━━━ GIT WORKTREE — TWO BRANCHES OPEN AT THE SAME TIME ━━━━━━━
# Check out a second branch in a DIFFERENT folder without stashing
$ git worktree add ../hotfix-branch hotfix/login       # open branch in new dir
$ git worktree add -b new-feature ../feature-dir main   # create branch + worktree
$ git worktree list                                        # list all worktrees
$ git worktree remove ../hotfix-branch                   # remove worktree
$ git worktree prune                                        # clean up stale worktree entries
━━━ GIT SUBMODULES — REPOS INSIDE REPOS ━━━━━━━━━━━━━━━━━━━━━
$ git submodule add git@github.com:u/lib.git vendor/lib    # add submodule
$ git clone --recurse-submodules git@github.com:u/repo.git # clone with submodules
$ git submodule update --init --recursive                   # initialize after clone
$ git submodule foreach git pull origin main                # update all submodules
$ git submodule deinit vendor/lib && git rm vendor/lib      # remove submodule
━━━ SEARCH THROUGH ALL HISTORY ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
$ git log -S "api_key"                      # find when string was added/removed
$ git log -G "def authenticate"               # regex search in diffs
$ git grep "TODO" HEAD -- "*.py"              # grep in files at HEAD
$ git grep "TODO" $(git rev-list --all) -- "*.py" # grep in ALL commits
$ git log --all --full-history -- "**/secret*.py"  # find deleted files
━━━ SPARSE CHECKOUT — MONOREPO PARTIAL CLONE ━━━━━━━━━━━━━━━━
# Only download the folder you need from a huge monorepo
$ git clone --filter=blob:none --sparse git@github.com:u/monorepo.git
$ git sparse-checkout set services/my-service packages/utils
$ git sparse-checkout list                        # see active paths
$ git sparse-checkout add services/new-service      # add more paths
━━━ GPG SIGNED COMMITS — PROVE YOUR IDENTITY ━━━━━━━━━━━━━━━━
$ gpg --full-generate-key                         # generate GPG key pair
$ gpg --list-secret-keys --keyid-format=long
sec ed25519/ABC123DEF456 2024-01-01
$ git config --global user.signingkey ABC123DEF456
$ git config --global commit.gpgsign true           # auto-sign every commit
# Export public key and add to GitHub → Settings → SSH & GPG keys
$ gpg --armor --export ABC123DEF456
$ git log --show-signature -1                      # verify commit signatures
━━━ GIT LFS — LARGE FILE STORAGE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# For ML models, videos, datasets — Git stores a pointer, LFS stores the file
$ git lfs install                                # install LFS globally
$ git lfs track "*.psd" "*.mp4" "*.bin" "models/**" # declare large file types
$ git add .gitattributes                           # commit the LFS config
$ git lfs status                                  # which files are tracked
$ git lfs ls-files                                 # list all LFS-tracked files
$ git lfs migrate import --include="*.psd"          # migrate existing files to LFS
━━━ GIT FILTER-REPO — REWRITE REPO HISTORY ━━━━━━━━━━━━━━━━━━
# Remove a file or secret from ALL history (pip install git-filter-repo)
$ git filter-repo --path secrets.env --invert-paths # delete file from all history
$ git filter-repo --replace-text patterns.txt       # replace strings in all commits
$ git filter-repo --path src/ --path lib/           # keep only these paths
# After rewriting: force-push all branches and rotate any exposed secrets!
━━━ USEFUL ALIASES & SHORTCUTS ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
$ git config --global alias.lg "log --oneline --graph --decorate --all"
$ git config --global alias.st "status -sb"
$ git config --global alias.undo "reset HEAD~1 --mixed"
$ git config --global alias.pushup "push -u origin HEAD"
$ git config --global alias.wip "!git add -A && git commit -m 'WIP'"
$ git config --global alias.unstage "restore --staged"
$ git config --global alias.recent "branch --sort=-committerdate --format='%(refname:short)'"
$ git config --global alias.aliases "config --get-regexp alias"
11 · Organization Administration

GitHub Org Administration

Managing repositories, teams, permissions, secrets, and organization-level policies at scale — for tech leads, engineering managers, and DevOps engineers running professional GitHub organizations.

Repository & Organization Permissions

RoleWhat They Can Do
ReadView code, clone, create issues & comments
Triage+ manage issues, PRs, labels (no code write)
Write+ push to non-protected branches, manage releases
Maintain+ manage repo settings, webhooks (no sensitive)
AdminFull control — settings, teams, delete, transfer

Team Structure Best Practice

Create GitHub Teams that mirror your organization structure: @org/backend, @org/frontend, @org/devops, @org/security, @org/data.


Assign teams to repositories — not individual users. When someone joins or leaves a team, their access to all repositories updates automatically. Individual-level access is a management nightmare at scale.

Managing Secrets & Environment Variables

GitHub CLI — secrets management
━━━ REPOSITORY SECRETS ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
$ gh secret set DATABASE_URL                    # prompts for value
$ gh secret set API_KEY --body "sk-abc123"          # set directly
$ gh secret set --env production DATABASE_URL        # environment-scoped secret
$ gh secret list                                   # list all secrets (values hidden)
$ gh secret delete OLD_SECRET                     # remove a secret
━━━ ORG-LEVEL SECRETS (SHARED ACROSS REPOS) ━━━━━━━━━━━━━━━━━━
$ gh secret set DOCKER_REGISTRY_TOKEN --org myorg    # org secret
$ gh secret list --org myorg
━━━ USING SECRETS IN ACTIONS ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# In .github/workflows/*.yml:
env:
DATABASE_URL: ${{ secrets.DATABASE_URL }}
API_KEY: ${{ secrets.API_KEY }}
# Secrets are masked in logs — GitHub redacts them automatically

Automated Releases — semantic-release

🚀
semantic-release reads your Conventional Commits and automatically determines the version bump (patch/minor/major), creates a GitHub Release, generates a CHANGELOG.md, and publishes to npm/PyPI — all triggered on push to main. Zero manual versioning decisions.
📋 .github/workflows/release.yml — fully automated semantic versioning
name: Release
on:
push:
branches: [main]
permissions:
contents: write
issues: write
pull-requests: write
jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0  # full history needed
- uses: actions/setup-node@v4
with:
node-version: '20'
- name: Semantic Release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
run: npx semantic-release
# Result: feat commit → v1.1.0, fix → v1.0.1, feat! (breaking) → v2.0.0
# Automatically creates: GitHub Release + git tag + CHANGELOG.md update

Dependabot — Automated Dependency Updates

📋 .github/dependabot.yml — keep all dependencies automatically patched
version: 2
updates:
# Python: weekly PRs for outdated packages
- package-ecosystem: "pip"
directory: "/"
schedule:
interval: "weekly"
day: "monday"
time: "08:00"
labels: ["dependencies", "automated"]
reviewers: ["team-lead"]
open-pull-requests-limit: 5
ignore:
- dependency-name: "django"
versions: ["5.x"]  # pin major version
# Node.js
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "weekly"
groups:
dev-dependencies:
dependency-type: "development"  # batch devDeps into 1 PR
# GitHub Actions: keep action versions current
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "monthly"

Repository Settings Checklist

Security Settings

Enable: Dependabot security updates, Secret scanning, Push protection (blocks secrets at push time), Code scanning with CodeQL. All are free on public repos and available on private with GitHub Advanced Security.

⚙️

General Settings

Disable "Allow merge commits" — only allow squash and rebase. Enable "Automatically delete head branches" after merge. Enable "Require contributors to sign off on web-based commits."

🌍

Environments

Create staging and production environments in Settings → Environments. Add required reviewers for production, deployment branch rules (only main), and environment-specific secrets.

📊

Insights & Audit

Use the Audit Log (org level) to track who changed what branch protection rules, who added deploy keys, and who accessed secrets. Export logs to SIEM tools for compliance.

12 · Quick Reference

The Complete Cheatsheet

Every essential command organized into color-coded reference cards. Print it, bookmark it, memorize it.

⚙️ Setup & Config
git config --global user.name "Name"Set author name
git config --global user.email "x@y"Set email
git config --global --listView all config
git initInitialize repo
git clone <url>Clone repo
git clone --depth 1 <url>Shallow clone (fast)
📸 Stage & Commit
git status -sbShort status
git add .Stage all changes
git add -pStage chunks interactively
git commit -m "feat: msg"Commit
git commit --amendEdit last commit
git restore --staged <file>Unstage a file
🌿 Branching
git switch -c <name>Create + switch
git branch -aList all branches
git switch -Switch to previous
git branch -d <name>Delete (safe)
git branch -m old newRename branch
git push origin --delete <b>Delete remote branch
🔀 Merge & Rebase
git merge <branch>Merge branch in
git merge --squash <b>Squash to one commit
git rebase mainRebase onto main
git rebase -i HEAD~4Interactive rebase
git cherry-pick <sha>Apply one commit
git merge --abortCancel merge
↩️ Undo & Recovery
git restore <file>Discard unstaged changes
git reset HEAD~1 --softUndo commit, keep staged
git reset HEAD~1 --hardUndo + discard ⚠️
git revert <sha>Safe undo (shared branches)
git stash / stash popSave / restore WIP
git reflogFull recovery history
☁️ Remote & Sync
git remote -vList remotes
git fetch --all --pruneFetch + clean stale refs
git pull --rebasePull with clean history
git push -u origin HEADPush new branch
git push --force-with-leaseSafe force push
git push --tagsPush all tags
🔍 Inspect & Debug
git log --oneline --graph --allVisual branch tree
git show <sha>Show commit content
git diff --stagedWhat will be committed
git blame <file>Who wrote each line
git log -S "keyword"Search history for text
git bisect startBinary-search for bug
🏷️ Tags & Releases
git tag -a v1.0.0 -m "msg"Create annotated tag
git tagList all tags
git push origin --tagsPush all tags
git tag -d v1.0.0Delete local tag
gh release create v1.0.0Create GitHub release
gh release create --generate-notesAuto-changelog
Conventional Commits Reference
feat:
New feature → bumps MINOR version
fix:
Bug fix → bumps PATCH version
feat!: / BREAKING CHANGE:
Breaking → bumps MAJOR version
docs: / chore: / test: / ci:
No version bump
🏆 Professional Git Mindset
Commit small & often
Commit frequently during work, then use interactive rebase to clean up before sharing. Many small commits → easier bisect and revert.
Never force-push shared branches
Force-pushing main or develop rewrites history for everyone. Use git revert instead — it's always safe.
Write history for your teammates
A good commit message explains WHY, not just what. Future-you and your teammates will read this history when debugging at 2am.
Automate the boring stuff
Pre-commit hooks, CI pipelines, branch protection, and semantic-release eliminate an entire category of human error. Set them up once, benefit forever.