GitHub Developer Course
What is GitHub?
Commit DAG + PR-gated trunk; automate with Actions, secure with the built-in suite, drive from Claude Code.
Master is protected; work happens on branches merged via PRs that must pass review + required status checks. Choose your integration deliberately: merge (preserve shape), rebase (linear, local-only before pushing), squash (one tidy commit — codeAmani's default into master). Actions runs CI on `on: [push, pull_request]` with jobs/needs/matrix and least-privilege `permissions`. Turn on secret scanning + push protection so a leaked Daraja key never lands. Claude Code drives PRs/issues/Actions via the GitHub MCP, and a push to master fires the Vercel deploy — so green CI + branch protection are what keep production safe.
Six things to master
From commits to CI to Claude Code. Tap a card for the commands + gotchas.
Branch & PR simulator — merge vs squash vs rebase
The concept new developers most often get wrong. Switch the integration strategy and watch the commit graph redraw — then walk a pull request from open to deployed, and toggle a failing check to see branch protection block the merge.
merge --squashD + E collapse into one commit S on master. The branch detail is discarded — master reads as one tidy commit per feature. codeAmani's default.- 1Open
- 2Review
- 3CI checks
- 4Merged
Push a branch and `gh pr create`. The PR is a proposal — nothing has touched master yet.
██████╗ ██╗████████╗██╗ ██╗██╗ ██╗██████╗
██╔════╝ ██║╚══██╔══╝██║ ██║██║ ██║██╔══██╗
██║ ███╗██║ ██║ ███████║██║ ██║██████╔╝
██║ ██║██║ ██║ ██╔══██║██║ ██║██╔══██╗
╚██████╔╝██║ ██║ ██║ ██║╚██████╔╝██████╔╝
╚═════╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═════╝GitHub Developer Course
Focus: A hands-on path from
git initto shipping with confidence — Git fundamentals, collaboration on GitHub, Actions/CI-CD, security, the wider ecosystem, and driving it all from Claude Code. Built to enhance your capabilities, not just list commands. Grounded indocs.github.com; reviewed 2026-06-07.
How this course works
Three levels, each ending with a ✅ capability checkpoint ("you can now…") and a 🛠 exercise. Work top-to-bottom the first time; use the command cheat-sheet and Table of Contents as reference after. The interactive learn module above this page — a branch & PR lifecycle simulator — is your illustration for Level 2; play with it before reading the merge/rebase section.
Table of Contents
- Level 1 — Git fundamentals → Git vs GitHub · Setup · The core loop · Branches · Remotes
- Level 2 — Collaboration → Merge vs rebase vs squash · Pull requests · Code review · Conflicts · Undoing things · Issues & Projects · Branch protection
- Level 3 — Automation & ecosystem → GitHub Actions · Packages & Releases · Security · Codespaces · Pages · gh CLI & API · Tokens & scopes
- Level 4 — GitHub + Claude Code → MCP server · Automations · Claude in CI
- Command cheat-sheet · Troubleshooting · codeAmani notes
Official Documentation
| Resource | URL |
|---|---|
| GitHub Docs (root) | https://docs.github.com |
| Get started | https://docs.github.com/en/get-started |
| GitHub Actions | https://docs.github.com/en/actions |
| Code security | https://docs.github.com/en/code-security |
gh CLI manual | https://cli.github.com/manual |
| REST API | https://docs.github.com/en/rest |
| GraphQL API | https://docs.github.com/en/graphql |
| GitHub MCP server | https://github.com/github/github-mcp-server |
Level 1 — Git fundamentals
Git vs GitHub
Git is the version-control tool that runs on your machine — it records snapshots (commits) of your files. GitHub is the hosted home for Git repositories that adds collaboration: pull requests, reviews, issues, CI/CD, and security.
your machine (Git) GitHub (remote)
┌────────────────────┐ git push ┌────────────────────┐
│ working dir │ ─────────────▶ │ origin/master │
│ └ staging (index)│ │ PRs · Actions · │
│ └ .git/ (commits, branches) │ Issues · Security │
└────────────────────┘ ◀───────────── └────────────────────┘
git pullA file moves through three states: working directory → staging area (git add) → committed history (git commit).
Setup & first-time config
# Install Git + the GitHub CLI
winget install Git.Git GitHub.cli # Windows
brew install git gh # macOS
sudo apt install git gh # Debian/Ubuntu (incl. WSL)
# One-time identity
git config --global user.name "Your Name"
git config --global user.email "you@codeamani.com"
git config --global init.defaultBranch main
git config --global pull.rebase false # merge on pull (or 'true' to rebase)
# Authenticate the CLI (browser flow; stores a token securely)
gh auth loginThe core loop
git init # start a repo here (or: gh repo clone owner/name)
git status # what changed?
git add file.ts # stage a change (git add -A for everything)
git commit -m "feat: add login form"
git log --oneline --graph # see history as a graph
git diff # unstaged changes (git diff --staged for staged)Write good commit messages — a short imperative summary (fix: handle null token), optionally a body explaining why. The codeAmani convention follows Conventional Commits (feat:, fix:, chore:, docs:).
Branches: the cheap pointer
A branch is just a movable pointer to a commit — creating one is instant and free. This is the mental model that makes everything else click.
git switch -c feature/mpesa-stk # create + switch (old: git checkout -b)
git switch master # switch back
git branch # list local branches
git branch -d feature/mpesa-stk # delete a merged branchRemotes & pushing to GitHub
gh repo create codeAmani/my-app --private --source=. --push # create + link + push
# …or link an existing remote
git remote add origin https://github.com/codeAmani/my-app.git
git push -u origin master # -u sets the upstream once
git pull # fetch + merge remote changes
git fetch origin # download without merging# .gitignore — never track secrets or build junk
.env*
node_modules/
.next/
*.log✅ Checkpoint: You can initialise a repo, stage and commit changes, branch, and push to GitHub. 🛠 Exercise: Create a repo with
gh repo create, add aREADME.md, commit on afeature/readmebranch, and push it.
Level 2 — Collaboration
Merge vs rebase vs squash
The three ways to integrate a branch — the concept developers most often get wrong. Play with the simulator above to see the commit graph redraw for each. Here's a feature branch being merged back, drawn as a real commit graph:
| Strategy | What it does | History | Use when |
|---|---|---|---|
| Merge | Creates a merge commit joining both lines | Preserves true branch shape | Shared/long-lived branches; you want the full record |
| Rebase | Replays your commits on top of the target | Linear, no merge commits | Cleaning up your local branch before a PR |
| Squash | Combines all branch commits into one | One tidy commit per feature | Merging a PR into master (the codeAmani default) |
git merge feature/x # merge feature/x into current branch
git rebase master # replay current branch on top of master
git rebase -i HEAD~3 # interactively squash/reorder last 3 commits
# Golden rule: never rebase commits you've already pushed to a shared branch.merge: A───B───C (master) rebase: A───B───C───D'──E' (master)
\ (D,E replayed cleanly on top)
D───E (feature) ──▶ merge commit MPull requests: the unit of collaboration
A PR proposes merging one branch into another, gated by review + CI before it lands. Lifecycle: open → review → CI checks → approve → merge.
gh pr create --title "feat: M-Pesa STK push" --body "Implements Daraja STK flow"
gh pr create --fill # use branch name + last commit as title/body
gh pr list # open PRs
gh pr view 42 --web # open in browser
gh pr checks 42 # CI status for the PR
gh pr merge 42 --squash --delete-branchCode review
gh pr diff 42 # read the changes
gh pr review 42 --approve
gh pr review 42 --request-changes --body "Validate the phone format (2547…)"
gh pr review 42 --comment --body "Nice — one nit inline"A good review checks: correctness, security (no secrets, input validated), tests, and clarity. Keep PRs small — they get reviewed faster and merge cleaner.
Resolving conflicts
git switch feature/x
git merge master # conflict markers appear in files
# Edit the <<<<<<< / ======= / >>>>>>> sections, choosing the right code, then:
git add resolved-file.ts
git commit # completes the mergeUndoing things safely
| Goal | Command | Safe on shared history? |
|---|---|---|
| Discard unstaged file change | git restore file | ✅ |
| Unstage a file | git restore --staged file | ✅ |
| Amend the last commit | git commit --amend | ❌ (rewrites) |
| Undo a commit, keep changes | git reset --soft HEAD~1 | ❌ |
| Revert a pushed commit | git revert <sha> | ✅ (new inverse commit) |
| Stash work-in-progress | git stash / git stash pop | ✅ |
| Recover "lost" commits | git reflog | ✅ (your safety net) |
git revertis the safe public undo;git reset/--amendrewrite history (force-push territory). When in doubt,git reflogremembers where everything was.
Issues, labels & Projects
gh issue create --title "Bug: STK callback times out" --label bug,priority:high
gh issue list --assignee @me
gh issue close 17 --comment "Fixed in #42"
# Projects (v2) — track work on a board; manage via the GraphQL API or the UI
gh project list --owner codeAmaniBranch protection
Protect master so nothing merges unreviewed or red. Set via Settings → Branches or the API:
gh api -X PUT repos/codeAmani/my-app/branches/master/protection \
-F required_pull_request_reviews.required_approving_review_count=1 \
-F required_status_checks.strict=true \
-F enforce_admins=true✅ Checkpoint: You can open a PR, review it, resolve conflicts, undo mistakes safely, and protect a branch. 🛠 Exercise: Open a PR from your
feature/readmebranch, request a change on it, push a fix, then squash-merge it.
Level 3 — Automation & ecosystem
GitHub Actions (CI/CD)
Workflows are YAML in .github/workflows/. Structure: events (on) → jobs → steps. Jobs run in parallel unless chained with needs.
# .github/workflows/ci.yml
name: CI
on:
push: { branches: [master] }
pull_request: { branches: [master] }
workflow_dispatch: # manual "Run workflow" button
permissions:
contents: read # least privilege by default
concurrency: # cancel superseded runs on the same ref
group: ci-${{ github.ref }}
cancel-in-progress: true
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
node: [20, 22] # run across versions in parallel
steps:
- uses: actions/checkout@v5
- uses: actions/setup-node@v4
with: { node-version: ${{ matrix.node }}, cache: npm }
- run: npm ci
- run: npm test
deploy:
needs: test # only after test passes
if: github.ref == 'refs/heads/master'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- run: echo "Deploy step (Vercel auto-deploys on push for codeAmani)"Key building blocks:
- Triggers —
push,pull_request,workflow_dispatch(manual),schedule(cron). needs— declare job dependencies and passoutputsbetween jobs.matrix— fan a job across versions/OSes ([20,22] × [ubuntu,windows]= N jobs).permissions— scope the built-inGITHUB_TOKEN; start atread.- Caching —
actions/cache@v5, orcache: npmonsetup-node. - Secrets —
${{ secrets.NAME }}; prefer OIDC over long-lived cloud keys. - Reusable workflows —
uses: org/repo/.github/workflows/deploy.yml@mainwithwith:inputs.
gh workflow list
gh workflow run ci.yml --field environment=production
gh run watch # live-stream the active run
gh run view 12345678 --logPackages & Releases
# Releases (auto-generate notes from merged PRs)
gh release create v1.2.0 --generate-notes
gh release list
# Packages — publish to GitHub Packages (npm/Container/etc.)
# npm: set "publishConfig": { "registry": "https://npm.pkg.github.com" } then `npm publish`Security (shift left)
GitHub's built-in developer security suite (enable under Settings → Code security):
| Feature | What it does |
|---|---|
| Dependabot alerts | Flags dependencies with known vulnerabilities |
| Dependabot security updates | Auto-opens PRs to patch vulnerable deps |
| Dependabot version updates | Auto-opens PRs to keep deps current (dependabot.yml) |
| Secret scanning | Detects hardcoded credentials committed to the repo |
| Push protection | Blocks a push if it contains a detected secret |
| Code scanning (CodeQL) | Static analysis for vulns/bugs in new or changed code |
| Dependency graph | Maps what your repo depends on (and what depends on it) |
| Security advisories | Privately discuss + fix, then publish a vulnerability alert |
# .github/dependabot.yml — keep npm deps current weekly
version: 2
updates:
- package-ecosystem: "npm"
directory: "/"
schedule: { interval: "weekly" }# .github/workflows/codeql.yml — CodeQL code scanning
name: CodeQL
on: { push: { branches: [master] }, pull_request: { branches: [master] } }
jobs:
analyze:
runs-on: ubuntu-latest
permissions: { security-events: write, contents: read }
steps:
- uses: actions/checkout@v5
- uses: github/codeql-action/init@v3
with: { languages: javascript-typescript }
- uses: github/codeql-action/analyze@v3Codespaces
A cloud dev environment (a container in the browser or VS Code) defined by a devcontainer.json — instant, reproducible onboarding.
// .devcontainer/devcontainer.json
{
"image": "mcr.microsoft.com/devcontainers/javascript-node:22",
"features": { "ghcr.io/devcontainers/features/github-cli:1": {} },
"postCreateCommand": "npm install",
"customizations": { "vscode": { "extensions": ["dbaeumer.vscode-eslint"] } }
}gh codespace create -r codeAmani/my-app
gh codespace code # open in VS CodeGitHub Pages
Free static hosting from a repo (great for docs/landing pages). Enable under Settings → Pages, or deploy via Actions:
# publishes ./dist to Pages
permissions: { pages: write, id-token: write }
# … build, then:
- uses: actions/upload-pages-artifact@v3
with: { path: dist }
- uses: actions/deploy-pages@v4gh CLI & API mastery
# REST — anything the API exposes
gh api repos/codeAmani/my-app/pulls --jq '.[].title'
gh api -X POST repos/codeAmani/my-app/issues -f title="From the CLI" -f body="…"
# GraphQL — precise, fewer round-trips
gh api graphql -f query='query { viewer { login } }'
# Aliases + JSON output power scripting
gh pr list --json number,title,author --jq '.[] | "\(.number) \(.title)"'Tokens & scopes
| Token type | Use it for |
|---|---|
| Fine-grained PAT | Preferred — per-repo, least-privilege, expiring |
| Classic PAT | Legacy; broad scopes (repo, workflow, read:org) |
GITHUB_TOKEN (Actions) | Auto-injected, scoped per-workflow via permissions: |
| OIDC | Keyless cloud auth from Actions — no stored secrets |
export GITHUB_TOKEN=github_pat_... # gh + MCP read this (GH_TOKEN also works)
# Generate at: https://github.com/settings/tokens✅ Checkpoint: You can write a CI workflow with matrix + job dependencies, enable Dependabot + CodeQL + push protection, spin up a Codespace, and script the API. 🛠 Exercise: Add a
ci.ymlthat runsnpm teston every PR, then turn on secret scanning + push protection for the repo.
Level 4 — GitHub + Claude Code
The GitHub MCP server
The official github/github-mcp-server lets Claude open PRs, comment on issues, trigger workflows, and read security alerts in-session.
HTTP transport (recommended — no Docker)
claude mcp add -s user --transport http github \
https://api.githubcopilot.com/mcp \
-H "Authorization: Bearer ${GITHUB_TOKEN}"// .mcp.json
{
"mcpServers": {
"github": {
"type": "http",
"url": "https://api.githubcopilot.com/mcp",
"headers": { "Authorization": "Bearer ${GITHUB_TOKEN}" }
}
}
}Docker transport (full toolset control)
claude mcp add github -- docker run -i --rm \
-e GITHUB_PERSONAL_ACCESS_TOKEN \
-e GITHUB_TOOLSETS="repos,issues,pull_requests,actions,code_security" \
ghcr.io/github/github-mcp-server| Toolset | Tools |
|---|---|
repos | create, read files, commit, push |
issues | create, comment, label, close |
pull_requests | create, review, merge, comment |
actions | list + trigger workflows |
code_security | read Dependabot + code-scanning alerts |
The npm package
@modelcontextprotocol/server-githubis deprecated (April 2025). Use HTTP or the Docker image above.
Claude Code automations
<!-- .claude/commands/review-pr.md -->
Review pull request #$ARGUMENTS.
1. Use the GitHub MCP to fetch the PR diff + description and existing comments.
2. Analyse for bugs, security issues, missing tests, and convention drift.
3. Post a review: approve if safe, else request changes with specific line notes.Usage: /project:review-pr 42
// scripts/auto-pr.js — open a PR after a feature branch is pushed (Stop hook)
import { execFileSync } from "child_process"; // execFileSync = no shell injection
const branch = execFileSync("git", ["branch", "--show-current"]).toString().trim();
if (branch === "main" || branch === "master") process.exit(0);
if (execFileSync("git", ["status", "--porcelain"]).toString()) process.exit(0);
try { execFileSync("gh", ["pr", "create", "--fill"], { stdio: "inherit" }); } catch {}Claude Code in CI
# .github/workflows/ai-fix.yml — headless Claude fixes lint on new PRs
name: AI Auto-fix
on: { pull_request: { types: [opened] } }
jobs:
fix:
runs-on: ubuntu-latest
permissions: { contents: write, pull-requests: write }
steps:
- uses: actions/checkout@v5
with: { ref: ${{ github.head_ref }} }
- uses: actions/setup-node@v4
with: { node-version: '22' }
- run: npm install -g @anthropic-ai/claude-code
- env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: claude -p "Fix all ESLint errors" --allowedTools "Bash,Edit,Read,Glob,Grep" --output-format text
- run: |
git config user.name "Claude Code Bot"; git config user.email "noreply@github.com"
git add -A && git diff --staged --quiet || git commit -m "fix: auto-fix ESLint errors"
git pushCommand cheat-sheet
# Daily loop
git status / git add -A / git commit -m "…" / git push
git switch -c feature/x # branch git switch master
git pull --rebase # update cleanly git stash / git stash pop
# History
git log --oneline --graph --all
git revert <sha> # safe undo of a pushed commit
git reflog # find lost commits
# GitHub via gh
gh pr create --fill / gh pr checks 42 / gh pr merge 42 --squash --delete-branch
gh issue create / gh run watch / gh release create vX --generate-notes
gh api repos/OWNER/REPO/... # raw REST/GraphQLTroubleshooting
| Issue | Fix |
|---|---|
gh: command not found | Install via winget/brew/apt |
| 401 on MCP HTTP | Regenerate PAT; ensure repo scope (or correct fine-grained perms) |
| Push rejected (non-fast-forward) | git pull --rebase then push |
| Push blocked by push protection | A secret was detected — remove it, rotate it, recommit |
| Merge conflict | Edit markers, git add, git commit (or git merge --abort) |
| Rebase went wrong | git rebase --abort, or recover via git reflog |
| Workflow didn't run | Check the on: triggers + branch/path filters |
| Accidentally committed a secret | Rotate it immediately; history rewrite (git filter-repo) + force-push |
codeAmani notes
masteris the deploy trigger. A push tomasterfires the Vercel build, somastermust always be green and reviewed. Enforce branch protection (1 review + required CI) and merge via squash for a clean, revertable history.- Secrets never touch the repo. Keep them in
.env.local(git-ignored) and a secret manager; turn on secret scanning + push protection, and pair with Infisical'sscanin CI to catch leaks before they reach the remote. If a secret does land, rotate it first — scrubbing history is secondary. - AI routing. Use the GitHub MCP for PR/issue/Actions work in-session; reserve heavier review with
claude -pin CI for auto-fixing lint/format. See anthropic for model/key setup. - African-market workflow. CI runs on GitHub's hosted runners regardless of local bandwidth — push small, let Actions do the heavy build/test. Pair with the vercel deploy and the chrome-devtools CI Lighthouse budget to guard 2G/3G performance on every PR.
- Run it from WSL. Keep repos on the Linux filesystem for fast
git, and let Git Credential Manager bridge your Windows auth.