GitHub Developer Course

Technology: github · Category: tooling · Last reviewed: 2026-08-23

Source: https://tech-stack.codeamanilabs.org/guide/github

Insight:

GitHub is where code lives, ships, and gets reviewed. This is a course, not just a reference: Git fundamentals → collaboration (PRs/reviews) → automation (Actions/CI) → security → ecosystem → Claude Code. The two ideas that unlock everything: branches are cheap pointers to commits (so merge/rebase/squash are just different ways to reshape history), and a PR is a proposal gated by review + CI before it touches master. For codeAmani, a push to master is the deploy trigger — so branch protection + CI are what keep production safe. Never commit secrets; pair secret scanning + push protection with Infisical's scan in CI.

 ██████╗ ██╗████████╗██╗  ██╗██╗   ██╗██████╗
██╔════╝ ██║╚══██╔══╝██║  ██║██║   ██║██╔══██╗
██║  ███╗██║   ██║   ███████║██║   ██║██████╔╝
██║   ██║██║   ██║   ██╔══██║██║   ██║██╔══██╗
╚██████╔╝██║   ██║   ██║  ██║╚██████╔╝██████╔╝
 ╚═════╝ ╚═╝   ╚═╝   ╚═╝  ╚═╝ ╚═════╝ ╚═════╝

GitHub Developer Course

Focus: A hands-on path from git init to 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 in docs.github.com; reviewed 2026-08-23.

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

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 pull

A 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 login

The 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 branch

Remotes & 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 a README.md, commit on a feature/readme branch, 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:

gitGraph
   commit id: "A"
   commit id: "B"
   branch feature
   checkout feature
   commit id: "D"
   commit id: "E"
   checkout main
   commit id: "C"
   merge feature
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 M

Pull 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-branch

Code 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 merge

Undoing 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 revert is the safe public undo; git reset/--amend rewrite history (force-push territory). When in doubt, git reflog remembers 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 codeAmani

Branch 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/readme branch, 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.

flowchart LR
  PR["push / pull_request"] --> T["job: test<br/>matrix 22, 24"]
  T --> D["job: deploy<br/>needs: test"]
  D --> V["Vercel auto-deploy"]
# .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: [22, 24]         # run across versions in parallel (24 = Active LTS)
    steps:
      - uses: actions/checkout@v7
      - uses: actions/setup-node@v7
        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@v7
      - run: echo "Deploy step (Vercel auto-deploys on push for codeAmani)"

Key building blocks:

gh workflow list
gh workflow run ci.yml --field environment=production
gh run watch                   # live-stream the active run
gh run view 12345678 --log

Packages & 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@v7
      - uses: github/codeql-action/init@v4
        with: { languages: javascript-typescript }
      - uses: github/codeql-action/analyze@v4

Codespaces

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:24",
  "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 Code

GitHub 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@v5
  with: { path: dist }
- uses: actions/deploy-pages@v5

gh 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)"'
# Pin the REST API version for stable scripts (current default: 2026-03-10)
gh api -H "X-GitHub-Api-Version: 2026-03-10" repos/codeAmani/my-app

The REST API is date-versioned: send X-GitHub-Api-Version: 2026-03-10 (the current version) to lock behavior; the legacy 2022-11-28 stays supported until March 2028. gh targets the current version by default. GraphQL is a single evolving schema (no date version) — watch the schema changelog for deprecations.

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.yml that runs npm test on 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.

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-github is 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@v7
        with: { ref: ${{ github.head_ref }} }
      - uses: actions/setup-node@v7
        with: { node-version: '24' }
      - 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 push

Command 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/GraphQL

Troubleshooting

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

Official docs: