Expert GitHub Interview Questions and Answers

๐Ÿ“‹ Table of Contents โ–พ
  1. Questions & Answers
  2. 📝 Knowledge Check

🐱‍⬛ Expert GitHub Interview Questions

This lesson targets senior engineers and platform/DevOps architects. Topics include Git internals (packfiles, DAG, three-way merge), OIDC for keyless CI/CD, merge queues, GitHub Advanced Security, Sigstore artifact signing, monorepo strategies, GitOps, self-hosted runners, and Git anti-patterns. These questions reveal whether you understand Git and GitHub at a platform level.

Questions & Answers

01 How does Git store objects internally? What is the packfile format?

Git Internals Git stores all data as content-addressable objects. Initially each object is stored as a loose file (zlib-compressed). When there are too many loose objects, Git packs them into packfiles using delta compression.

# Loose objects: .git/objects/ab/cdef1234...
# SHA is the content hash: SHA1(type + space + size + NUL + content)
# Content is zlib-compressed
# All four object types (blob, tree, commit, tag) follow this format

# Inspect a loose object
git cat-file -p HEAD                       # the HEAD commit
git cat-file -p HEAD^{tree}                # its root tree
git cat-file -p abc1234                    # any object by SHA

# Packfiles: .git/objects/pack/pack-SHA.pack + .idx
# Created by: git gc, git repack, git push/fetch (server sends packfiles)
# Format:
# - Header: "PACK" magic + version + object count
# - Objects: each object is delta-compressed against a base object
#   - COPY instructions: copy N bytes from base starting at offset
#   - ADD instructions: insert new bytes
# - SHA-1 checksum of the entire file

# Delta compression example:
# version1.txt (300 bytes) โ†’ version2.txt (305 bytes, minor edit)
# Instead of storing full version2, store:
# "delta against version1: change bytes 45-52 to 'new text'"
# Saves ~295 bytes

# Inspect packfiles
git verify-pack -v .git/objects/pack/pack-*.idx | sort -k3 -n | tail -20
# Shows: SHA type size compressed-size depth base-SHA

# Repack with aggressive delta compression
git repack -a -d -f --depth=50 --window=250
# -a: repack all objects
# -d: delete old packfiles
# -f: force re-delta even already-packed objects

# Reachability bitmaps (for fast server-side operations)
git repack -b               # create bitmap index
# .git/objects/pack/pack-*.bitmap
# Allows: fast "which objects are reachable from these tips?" queries

02 How does Git’s three-way merge algorithm work?

Git Internals Git uses a three-way merge to combine two branches. It finds the common ancestor (merge base) and compares how each branch diverged from it to produce the merged result.

# Three-way merge uses three trees:
# 1. Merge base -- the common ancestor commit (most recent common commit)
# 2. HEAD (ours) -- current branch
# 3. MERGE_HEAD (theirs) -- branch being merged

# Algorithm for each file/line:
# If ours == base and theirs != base: take theirs (they changed it, we didn't)
# If ours != base and theirs == base: take ours (we changed it, they didn't)
# If ours != base and theirs != base: CONFLICT (both changed it)
# If ours == theirs (both changed to same): take either (same result)

# Find the merge base
git merge-base main feature/auth           # prints the common ancestor SHA

# Example
# base:    line 5: "const timeout = 5000;"
# ours:    line 5: "const timeout = 10000;" (we doubled it)
# theirs:  line 5: "const TIMEOUT = 5000;"  (they renamed it)
# Result:  CONFLICT (both changed line 5 in different ways)

# Recursive merge strategy -- handles criss-cross merges
# When there are multiple common ancestors, Git creates a virtual merge base
# by recursively merging the candidates
git merge -s recursive feature/auth        # default for two-branch merges

# ORT strategy (Optimised Recursive Trees) -- default since Git 2.34
# Same algorithm but more efficient (doesn't need to checkout virtual base)
git merge -s ort feature/auth

# Other merge strategies
git merge -s octopus feature1 feature2 feature3  # merge multiple branches at once
git merge -s ours feature/old            # keep ours entirely (discard theirs)
git merge -X ours                        # resolve conflicts by preferring ours
git merge -X theirs                      # resolve conflicts by preferring theirs
git merge -X diff3                       # show 3-way conflict markers (base included)

03 How does git rerere work?

Git Internals rerere (Reuse Recorded Resolution) remembers how you resolved a merge conflict and automatically applies the same resolution next time it sees the identical conflict. Invaluable for long-running topic branches.

# Enable rerere
git config --global rerere.enabled true
git config --global rerere.autoupdate true  # auto-stage rerere resolutions

# How it works:
# 1. On conflict: Git records the conflict's "pre-image" in .git/rr-cache/
# 2. After you resolve: Git records the "post-image"
# 3. Next time: same conflict โ†’ Git applies the recorded resolution automatically

# Inspect rerere cache
ls .git/rr-cache/
# SHA-of-conflict-context/
#   preimage   (what the conflict looked like)
#   postimage  (how you resolved it)

git rerere status      # show what rerere is tracking
git rerere diff        # show conflicts rerere knows how to resolve

# Forget a recorded resolution (if it was wrong)
git rerere forget src/auth.js

# Practical scenario: feature branch regularly rebased on main
# main gets a conflict with feature every rebase (same code changed by both)
# Without rerere: resolve the same conflict every rebase
# With rerere: resolve once, subsequent rebases apply it automatically

# Works with: merge, rebase, cherry-pick

# Clear all rerere data
rm -rf .git/rr-cache

04 What is GitHub’s OIDC for keyless, secretless CI/CD?

Security GitHub Actions can use OIDC (OpenID Connect) to authenticate to cloud providers (AWS, GCP, Azure) without storing long-lived credentials as secrets. GitHub mints a short-lived JWT for each workflow run, which is exchanged for a cloud access token.

# How it works:
# 1. GitHub mints a JWT signed by GitHub's OIDC provider for each job
# 2. The JWT contains claims: repo, branch, workflow, job, ref, sha, actor
# 3. The workflow exchanges the JWT for a cloud-provider token
# 4. The cloud access token is short-lived (15 minutes) and scoped

# GitHub Actions workflow (AWS example)
permissions:
  id-token: write    # REQUIRED: allow job to request OIDC JWT
  contents: read

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::123456789:role/github-actions-deploy
          aws-region: eu-west-1
          # NO secret needed! Exchanges OIDC JWT for AWS credentials

      - name: Deploy to S3
        run: aws s3 sync dist/ s3://my-bucket/

# AWS IAM Role Trust Policy (configured in AWS, not GitHub)
{
  "Principal": { "Federated": "arn:aws:iam::123456789:oidc-provider/token.actions.githubusercontent.com" },
  "Condition": {
    "StringEquals": {
      "token.actions.githubusercontent.com:sub": "repo:myorg/myrepo:ref:refs/heads/main",
      "token.actions.githubusercontent.com:aud": "sts.amazonaws.com"
    }
  }
}

# Benefits over static secrets:
# - No secret rotation needed (tokens expire in 15 min)
# - No secret leak risk (no long-lived credentials in GitHub Secrets)
# - Claim-based: only specific repos/branches/workflows can assume the role
# Works with: AWS, GCP, Azure, HashiCorp Vault, and any OIDC-compatible provider

05 What are merge queues on GitHub and why do they solve merge conflicts at scale?

GitHub Merge queues (GitHub) prevent merge races โ€” the problem where two PRs both pass CI individually but break main when merged together. The queue serialises merges, testing each combination before landing.

# The problem without merge queues:
# PR #1 passes CI (tested against main@abc)
# PR #2 passes CI (tested against main@abc)
# PR #1 merges (main = def)
# PR #2 merges without being re-tested against def
# โ†’ main is broken (PR #2 conflicts with PR #1's changes)

# Merge queue solution:
# 1. Author clicks "Add to merge queue" (not "Merge")
# 2. GitHub creates a temporary branch: main + PR#1 + PR#2
# 3. CI runs against that combined branch
# 4. If CI passes: both PRs merge atomically
# 5. If CI fails: both are removed, failing PR is identified and re-queued alone

# Enable in GitHub Settings โ†’ Branches โ†’ Edit branch protection
# โœ… Require merge queue

# Merge queue configuration (.github/mergequeue.yml or in branch protection UI)
# merge_method: squash (or merge, rebase)
# max_entries_to_build: 5       (max PRs tested together in one batch)
# max_entries_to_merge: 5       (max PRs merged in one atomic merge)
# min_entries_to_merge: 1
# check_response_timeout_minutes: 90

# Benefits:
# - main is ALWAYS green (CI ran against the final combined state)
# - Scales to hundreds of PRs/day (big tech teams)
# - Eliminates "rebase and re-run CI" cycle for busy repos

# Similar: Bors-ng, Mergify, Aviator (third-party merge queue tools)

06 What is GitHub Advanced Security (GHAS)?

Security GitHub Advanced Security is a suite of security features: CodeQL code scanning, secret scanning, and dependency review โ€” integrated into the GitHub pull request workflow.

# 1. CodeQL Code Scanning -- static analysis for security vulnerabilities
# .github/workflows/codeql.yml
name: CodeQL
on:
  push:    { branches: [main] }
  pull_request: { branches: [main] }
  schedule: [{ cron: "0 2 * * 1" }]  # weekly scan

jobs:
  analyze:
    runs-on: ubuntu-latest
    permissions:
      security-events: write
      actions: read
    strategy:
      matrix:
        language: [javascript-typescript, python]
    steps:
      - uses: actions/checkout@v4
      - uses: github/codeql-action/init@v3
        with:
          languages: ${{ matrix.language }}
          queries: security-and-quality   # extended query suite
      - uses: github/codeql-action/analyze@v3
# Detects: SQL injection, XSS, path traversal, SSRF, 100+ vulnerability types

# 2. Secret Scanning -- detects secrets committed by accident
# Scans all pushes for 200+ secret patterns (AWS keys, Stripe tokens, etc.)
# Enabled for all public repos automatically
# Push protection: BLOCKS the push if a secret is detected (before it's committed!)
# Settings โ†’ Security โ†’ Secret scanning โ†’ Push protection: ON

# 3. Dependency Review -- shows vulnerable deps in PR diff
# .github/workflows/dependency-review.yml
- uses: actions/dependency-review-action@v4
  with:
    fail-on-severity: moderate
    deny-licenses: GPL-2.0, AGPL-3.0  # license compliance

# 4. Security Advisories -- private vulnerability reporting
# Repository โ†’ Security โ†’ Advisories
# Coordinate private disclosure before public announcement (CVE assignment)

# Available for: GitHub Enterprise, GitHub Teams (GHAS as add-on)
# All three features free for public repositories

07 What is Sigstore and how do you sign GitHub Actions artifacts?

Security Sigstore (Linux Foundation) provides keyless artifact signing using OIDC identities. GitHub natively supports artifact attestation (provenance) via attest-build-provenance โ€” proving an artifact came from a specific workflow run.

# GitHub's native artifact attestation (SLSA Level 2 provenance)
jobs:
  build:
    runs-on: ubuntu-latest
    permissions:
      id-token: write      # for OIDC
      contents: read
      attestations: write  # to create attestations

    steps:
      - uses: actions/checkout@v4

      - name: Build
        run: npm ci && npm run build && npm pack
        # Produces: my-lib-1.2.0.tgz

      - uses: actions/attest-build-provenance@v1
        with:
          subject-path: my-lib-1.2.0.tgz
        # Creates a signed SLSA provenance attestation
        # Stored in GitHub's immutable attestation log

# Verify an attestation
gh attestation verify my-lib-1.2.0.tgz \
    --owner myorg \
    --repo myrepo
# Verifies: artifact hash, workflow that produced it, repo, ref, SHA

# cosign (Sigstore tool) for container images
# Sign a container image
cosign sign --yes ghcr.io/myorg/myapp:1.2.0
# Cosign uses OIDC to get an ephemeral signing key from Fulcio
# Signature and certificate stored in Rekor transparency log

# Verify
cosign verify ghcr.io/myorg/myapp:1.2.0 \
    --certificate-identity-regexp "^https://github.com/myorg/myapp/.github/workflows/.*" \
    --certificate-oidc-issuer "https://token.actions.githubusercontent.com"

# SLSA (Supply chain Levels for Software Artifacts) framework:
# Level 1: provenance exists
# Level 2: hosted build, signed provenance (achievable with GitHub Actions)
# Level 3: hardened build, non-falsifiable provenance

08 What are GitOps workflows and how do they use GitHub?

DevOps GitOps is an operational model where the desired state of infrastructure and applications is declared in Git. Changes to Git trigger automated reconciliation to bring the actual state in line.

# GitOps principles:
# 1. Declarative: desired state described in Git (Kubernetes YAML, Terraform HCL)
# 2. Versioned: Git is the single source of truth, all changes have history
# 3. Immutable: never modify running config directly -- change Git and let the agent sync
# 4. Automatically pulled: agent (Flux/Argo) watches Git and reconciles continuously

# App-of-apps structure (ArgoCD / Flux)
# github.com/myorg/gitops-config/
#   apps/
#     production/
#       auth-service.yaml    (points to ghcr.io/myorg/auth:v2.1.0)
#       api-gateway.yaml
#     staging/
#       auth-service.yaml    (points to ghcr.io/myorg/auth:main-abc1234)
#   infra/
#     ingress.yaml
#     certificates.yaml

# Promotion workflow
# 1. Developer merges PR to app repo โ†’ GitHub Actions builds and pushes image
# 2. Actions workflow updates gitops-config repo:
git clone https://github.com/myorg/gitops-config
cd gitops-config
sed -i "s|tag: .*|tag: $NEW_TAG|" apps/staging/auth-service.yaml
git commit -m "chore(staging): promote auth-service to $NEW_TAG"
git push
# 3. Flux/ArgoCD detects the change and deploys to staging
# 4. After testing: create a PR to promote staging โ†’ production
# 5. Merge PR โ†’ agent deploys to production

# GitHub Actions + Flux integration
- uses: fluxcd/flux2-sync-action@v1     # trigger sync after image push
- uses: argoproj/argocd-action@v1       # trigger ArgoCD sync

# Benefits:
# - Complete audit trail (who changed what, when, why -- it's all in Git)
# - Easy rollback: git revert the PR
# - Drift detection: agent alerts if actual state != Git state

09 What is a monorepo strategy on GitHub? What are the tradeoffs?

Architecture A monorepo stores multiple related projects in a single Git repository. Used by Google, Meta, Microsoft, and Vercel. Enables atomic cross-service changes but requires tooling to manage scale.

# Monorepo structure
my-company/
  apps/
    web-frontend/        (Next.js app)
    mobile/              (React Native)
    admin-portal/
  services/
    auth/                (Node.js)
    billing/             (Go)
    notifications/       (Python)
  libs/
    ui-components/       (shared React lib)
    api-client/          (generated SDK)
    eslint-config/
  infra/
    terraform/
    kubernetes/

# Tools for monorepo:
# Nx (JavaScript): affected analysis, caching, task orchestration
# Turborepo (JavaScript): fast builds with caching (Vercel)
# Bazel (polyglot): Google's build system, fine-grained dependency tracking
# Rush (JavaScript/Microsoft)

# Affected builds -- only rebuild/test what changed
# GitHub Actions with Nx
- name: Get affected apps
  run: |
    AFFECTED=$(npx nx show projects --affected --type app | tr '\n' ',')
    echo "affected=$AFFECTED" >> $GITHUB_OUTPUT
  id: affected

- name: Test affected
  if: ${{ steps.affected.outputs.affected != '' }}
  run: npx nx run-many --target=test --projects=${{ steps.affected.outputs.affected }}

# Tradeoffs:
# PROS: atomic cross-service commits, shared tooling, single CI, easier refactoring
# CONS: slow git operations on huge repos, CI must be smart (affected analysis),
#       repo access control is harder (everyone can see everything)

# Partial clone + sparse checkout essential for monorepos at scale
git clone --filter=blob:none --sparse https://github.com/org/monorepo.git
git sparse-checkout set services/auth libs/shared

10 What are GitHub’s self-hosted runners and runner groups?

GitHub Actions Self-hosted runners are machines you control that GitHub Actions jobs can run on. Used for compliance, performance, custom hardware, VPC access, or cost reduction.

# Register a self-hosted runner
# GitHub Settings โ†’ Actions โ†’ Runners โ†’ New self-hosted runner
# Supports: Linux, macOS, Windows, ARM, Docker containers

# Install runner on a machine
mkdir actions-runner && cd actions-runner
curl -o actions-runner-linux-x64-2.316.0.tar.gz -L \
    https://github.com/actions/runner/releases/download/v2.316.0/actions-runner-linux-x64-2.316.0.tar.gz
tar xzf ./actions-runner-linux-x64-2.316.0.tar.gz
./config.sh --url https://github.com/myorg --token ABC123
./run.sh   # or: sudo ./svc.sh install && sudo ./svc.sh start

# Use in a workflow
jobs:
  build:
    runs-on: self-hosted           # any self-hosted runner
    # OR
    runs-on: [self-hosted, linux, x64, production]  # label-based selection

# Ephemeral runners (just-in-time, more secure)
./config.sh --ephemeral    # runner deletes itself after one job
# Best practice: one runner per job, no state contamination

# Kubernetes-based scaling (Actions Runner Controller)
# ARC: GitHub's official Kubernetes operator
# Scales runners up/down based on workflow queue depth
# apiVersion: actions.github.com/v1alpha1
# kind: AutoscalingRunnerSet
# spec:
#   githubConfigUrl: https://github.com/myorg
#   maxRunners: 20
#   minRunners: 0

# Runner groups (Enterprise/Teams)
# Organise runners into groups with repo access policies
# Settings โ†’ Actions โ†’ Runner groups
# Group: "production-deployers" โ†’ only allow production-deploy.yml workflow

# Security:
# Always use ephemeral runners for public repos (fork PRs can run your workflows)
# For private repos: can use persistent runners safely
# Network isolation: self-hosted runners can reach your VPC/on-prem systems

11 What is git bundle and when do you use it?

Git Internals A git bundle packs a set of objects and references into a single portable file that can be transferred and used like a remote. Used for offline/air-gapped environments or large initial transfers.

# Create a bundle containing everything
git bundle create repo.bundle --all
# Creates a single file with all branches, tags, and objects

# Create an incremental bundle (since last bundle)
git bundle create update.bundle main ^v1.0.0
# Only contains commits reachable from main but NOT from v1.0.0
# "--branches" equivalent: only new commits since the tag

# Verify a bundle
git bundle verify repo.bundle

# Use a bundle as a remote
git clone repo.bundle my-project         # clone from a bundle
git remote add bundle-remote repo.bundle
git fetch bundle-remote

# Pull updates from a bundle
git pull repo.bundle main                # fetch + merge from bundle

# List what's in a bundle
git bundle list-heads repo.bundle

# Incremental backup workflow:
# Monday: git bundle create backup-full.bundle --all
# Tuesday: git bundle create backup-tue.bundle main ^backup-full-tip
# Apply on restore:
# git clone backup-full.bundle repo
# cd repo; git fetch ../backup-tue.bundle main:main

# Air-gapped environment use case:
# Developer: git bundle create changes.bundle feature/auth ^main
# Transfer via USB drive to air-gapped server
# Server: git fetch /mnt/usb/changes.bundle feature/auth:feature/auth

12 What is GitHub’s API rate limiting and how do you work with it?

GitHub API

# GitHub REST API rate limits:
# Unauthenticated:       60 requests/hour per IP
# Personal Access Token: 5,000 requests/hour
# GitHub App:            5,000 req/hour + 15,000 for orgs with 20+ seats
# GitHub Actions GITHUB_TOKEN: 1,000 requests/hour per repo

# Rate limit headers in every response
# X-RateLimit-Limit:     5000       (total allowed)
# X-RateLimit-Remaining: 4956       (remaining in window)
# X-RateLimit-Reset:     1713888000 (Unix timestamp when it resets)
# X-RateLimit-Used:      44
# Retry-After:           30         (on 429: seconds to wait)

# Check your rate limit status
curl -H "Authorization: Bearer $GITHUB_TOKEN" \
     https://api.github.com/rate_limit

# GraphQL API: 5,000 points/hour (complex queries cost more points)

# Best practices to avoid hitting limits:
# 1. Use conditional requests (304 Not Modified)
curl -H "If-None-Match: \"abc123\"" https://api.github.com/repos/owner/repo
# If unchanged: 304 response, does NOT count against rate limit

# 2. Cache responses with ETag
ETag=$(curl -sI https://api.github.com/repos/owner/repo | grep ETag | cut -d' ' -f2)

# 3. Use GitHub App instead of PAT (higher limits)
# 4. GraphQL: fetch exactly what you need in one request
# 5. Webhooks instead of polling (push not pull)
# 6. Paginate efficiently: use Link header, don't use small page sizes

# GitHub CLI (gh) handles rate limiting automatically
gh api repos/owner/repo --paginate    # auto-paginates all pages

# Secondary rate limits (abuse detection):
# - Creating many resources in rapid succession
# - Making many concurrent requests
# Solution: add jitter/backoff, max 1 request/second for writes

13 What is GitHub Enterprise and GHES?

GitHub Enterprise

  • GitHub Enterprise Cloud (GHEC) โ€” GitHub.com with enhanced security, compliance, and SSO features. Data stays on GitHub’s infrastructure. Includes SAML SSO, audit log API, EMUs (Enterprise Managed Users), data residency options.
  • GitHub Enterprise Server (GHES) โ€” self-hosted GitHub deployment on your own infrastructure (VMs, AWS, Azure, GCP). Full control over data, air-gap possible. You manage upgrades. Lacks some GitHub.com features.
# GHES considerations
# Runs on: VMware, Hyper-V, AWS EC2, Azure VM, GCP
# Setup: download OVA/AMI, deploy, configure via web UI or ghe-config-apply
# Clustering: available for HA (primary + replica + Elasticsearch nodes)
# Backups: ghe-backup-utils for point-in-time snapshots

# GHES-specific features:
# - LDAP / SAML / CAS authentication integration
# - License management (seat-based)
# - Pre-receive hooks (server-side enforce commit policies)
# - GitHub Connect (link GHES to GitHub.com for Actions runners, Dependabot)
# - Custom certificate authorities
# - Network isolated (no egress required)

# Actions on GHES:
# By default GHES has no actions marketplace
# Option 1: Use GitHub Connect to sync selected actions from GitHub.com
# Option 2: Self-host actions in your GHES org
# Option 3: actions-sync tool to download and push action packages

# EMUs (Enterprise Managed Users):
# GitHub.com accounts fully managed by your IdP (Okta, Azure AD)
# Users have separate enterprise accounts (username_enterprise format)
# Cannot contribute to public GitHub repos (isolation guarantee)
# Ideal for: regulated industries, high-security environments

# Audit log streaming (Enterprise)
# Stream all events to SIEM: Splunk, Azure Event Hub, AWS S3, Google Cloud Storage
gh api /enterprises/my-enterprise/audit-log --paginate

14 What is git notes and how is it used?

Git Internals git notes attaches metadata to commits without changing the commit SHA. Notes are stored separately in refs/notes/commits and can be shared via push/fetch.

# Add a note to a commit
git notes add -m "Code reviewed by Alice on 2026-04-22" HEAD
git notes add -m "Deployed to production at 14:30 UTC"  abc1234

# View notes
git log --show-notes          # show notes in git log output
git notes show HEAD           # show note for specific commit
git notes show abc1234

# Edit a note
git notes edit HEAD           # opens editor
git notes append -m "Additional context" HEAD  # add to existing note

# Remove a note
git notes remove HEAD

# Push notes to remote (not pushed by default!)
git push origin refs/notes/commits

# Fetch notes from remote
git fetch origin refs/notes/commits:refs/notes/commits

# Configure to always push/fetch notes
git config --add remote.origin.push "refs/notes/commits"
git config --add remote.origin.fetch "refs/notes/commits:refs/notes/commits"

# Multiple notes namespaces
git notes --ref=build-info add -m '{"build": 4521, "pipeline": "main-ci"}' abc1234
git notes --ref=security   add -m "CVE-2026-1234 not affected" abc1234

# Use cases:
# - CI/CD: attach build metadata to commits (build number, test results, coverage)
# - Security: attach SBOM or vulnerability scan results to commits
# - Deployment tracking: record when and where a commit was deployed
# - Code review metadata without amending commits

15 What are common Git anti-patterns and how do you fix them?

Best Practices

# 1. Committing secrets
# BAD: AWS keys, DB passwords, API tokens in code
# FIX: Immediately rotate the secret (assume compromised)
#       git filter-repo --path-glob "*.env" --invert-paths
#       Enable: GitHub secret scanning + push protection

# 2. Giant commits ("megacommits")
# BAD: git commit -m "everything I did this week"
# FIX: git add -p (interactive staging)
#       atomic commits: one logical change per commit

# 3. Force-pushing to main
# BAD: git push --force origin main (destroys shared history)
# FIX: git push --force-with-lease (safer: fails if someone else pushed)
#       Enable branch protection to prevent force pushes entirely

# 4. Long-lived feature branches
# BAD: feature/redesign branch that's 3 months old and 1000 commits behind main
# FIX: feature flags (merge small pieces, disable in prod)
#       regular rebasing: git pull --rebase
#       trunk-based development: small PRs, merge fast

# 5. .git/config credentials in commit history
# BAD: git commit .git/config
# FIX: .gitignore should always include .git/ (it usually does but double-check)

# 6. Binary files in Git
# BAD: tracking 100MB design files, compiled binaries, generated assets
# FIX: git-lfs for large files (replaces blob with pointer)
#      git lfs track "*.psd" "*.pdf" "*.mp4"

# 7. Not using .gitignore from the start
# BAD: accidentally tracking node_modules/, __pycache__, .env
# FIX: gitignore.io to generate standard ignores
#       git rm --cached -r node_modules/  (untrack after adding to .gitignore)

# 8. "git push --force" instead of "--force-with-lease"
git push --force-with-lease   # fails if remote was updated since you last fetched

# 9. Rebasing public/shared branches
# BAD: git rebase main while feature/auth is pushed and others have it
# FIX: only rebase local/personal branches; use merge for shared branches

# 10. Not signing commits for high-security repos
git config --global commit.gpgsign true
git config --global user.signingkey KEY_ID
# or SSH signing (simpler)
git config --global gpg.format ssh
git config --global user.signingkey ~/.ssh/id_ed25519.pub

16 What is SLSA and how does GitHub Actions achieve supply chain security?

Security SLSA (Supply chain Levels for Software Artifacts) is a security framework that defines levels of supply chain integrity. GitHub Actions can achieve SLSA Level 3 with proper workflow hardening.

# SLSA Levels:
# Level 0: No guarantees
# Level 1: Provenance exists (who built it, from what source)
# Level 2: Hosted build + signed provenance (GitHub Actions achieves this easily)
# Level 3: Hardened build (non-falsifiable provenance, isolated builds)

# GitHub Actions best practices for SLSA:
# 1. Pin actions to EXACT SHA (not tag -- tags can be moved!)
# BAD:  uses: actions/checkout@v4          (tag, mutable)
# GOOD: uses: actions/checkout@b4ffde65f46... (SHA, immutable)
# Tool: Dependabot/Renovate can automatically update pinned SHAs

# 2. Restrict permissions (principle of least privilege)
permissions:
  contents: read          # only read, not write
  packages: write         # only what's needed

# Default: no permissions (set explicitly per job)
# Top-level permissions: read-all is safer default than write-all

# 3. Use third-party actions from verified publishers only
# GitHub Marketplace shows "Verified creator" badge

# 4. Freeze the action runner environment
runs-on: ubuntu-latest    # mutable (changes OS version)
runs-on: ubuntu-22.04     # pinned version (more stable)

# 5. Code signing for releases
- uses: actions/attest-build-provenance@v1  # SLSA provenance

# 6. Dependency review on every PR
- uses: actions/dependency-review-action@v4

# 7. Secrets least privilege
# Use environment secrets (not repo secrets) to restrict to specific envs
# Use OIDC instead of static secrets where possible

# OpenSSF Scorecard: automated security assessment of GitHub repos
- uses: ossf/scorecard-action@v2.3.3
  with:
    results_file: results.sarif
    results_format: sarif

17 How do you design an efficient GitHub Actions caching strategy?

GitHub Actions

# Cache key strategy: must include the lock file hash
# so cache is invalidated when dependencies change
- uses: actions/cache@v4
  with:
    path: ~/.npm                            # what to cache
    key: ${{ runner.os }}-npm-${{ hashFiles('**/package-lock.json') }}
    restore-keys: |                         # fallback keys (prefix match)
      ${{ runner.os }}-npm-

# Multi-level keys
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
  ${{ runner.os }}-cargo-

# Key hierarchy:
# Exact hit: uses cache exactly                     โ†’ fastest
# Partial hit (restore-key): restores closest match โ†’ good (partial reuse)
# Miss: no cache                                    โ†’ starts from scratch

# Setup actions with built-in caching (simpler, preferred)
- uses: actions/setup-node@v4
  with:
    node-version: '22'
    cache: 'npm'              # automatically caches node_modules

- uses: actions/setup-python@v5
  with:
    python-version: '3.12'
    cache: 'pip'

- uses: actions/setup-java@v4
  with:
    java-version: '21'
    cache: 'maven'

# Cache Docker layers for faster builds
- uses: actions/cache@v4
  with:
    path: /tmp/.buildx-cache
    key: ${{ runner.os }}-buildx-${{ github.sha }}
    restore-keys: ${{ runner.os }}-buildx-

- uses: docker/build-push-action@v5
  with:
    cache-from: type=local,src=/tmp/.buildx-cache
    cache-to: type=local,dest=/tmp/.buildx-cache-new,mode=max

# Cache limits: 10GB per repo, entries expire after 7 days of no access
# Cache is NOT shared across PRs by default (security isolation)
# main branch cache is accessible from PRs (restore only, not write)

18 What is trunk-based development (TBD) and how does it differ from Gitflow?

Workflow

# --- Gitflow (complex, long branches) ---
# Branches: main, develop, feature/*, release/*, hotfix/*
# Release cycle: develop accumulates features โ†’ release branch โ†’ merge to main
# Long-lived branches: feature branches live for weeks/months
# Suitable for: versioned products with infrequent scheduled releases

#   main โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ—
#   release/1.2 โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ—โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
#   develop โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
#   feature/x โ”€โ”€โ”€โ”€โ”€โ—โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€

# --- Trunk-Based Development (TBD, recommended) ---
# Single trunk: main (or trunk)
# Feature branches: very short-lived (hours to 1-2 days max)
# Merge frequently: PRs merged to main multiple times per day
# Feature flags: hide incomplete features from users in production
# Suitable for: SaaS, continuous delivery, high-velocity teams

#   main โ”€โ”€โ”€โ”€โ”€โ—โ”€โ”€โ”€โ”€โ—โ”€โ”€โ”€โ”€โ—โ”€โ”€โ”€โ”€โ—โ”€โ”€โ”€โ”€โ—โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
#   feature/x โ”€โ”€โ—โ”€โ”€
#   feature/y โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ—โ”€โ”€
#   fix/bug โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ—โ”€โ”€

# Feature flags enable TBD
# - New code is deployed but feature is toggled off
# - Gradually roll out to 1%, 10%, 100%
# - Instant kill switch if issues arise
# Tools: LaunchDarkly, Unleash, PostHog, home-grown env vars

# GitHub Flow (simpler than Gitflow, close to TBD):
# main: always deployable
# feature/* branches: short-lived, merged via PR
# No develop or release branches
# Deploy from main after every PR merge (or tag for versioned releases)

# Which to choose:
# TBD: high-velocity SaaS, CI/CD, teams comfortable with feature flags
# Gitflow: versioned libraries, apps with long release cycles, larger enterprise teams

19 What is the Git DAG and how does history traversal work?

Git Internals Git history forms a Directed Acyclic Graph (DAG) where each commit is a node and parent references are directed edges. The acyclic property means you can never form a cycle โ€” no commit can be its own ancestor.

# Visualise the DAG
git log --oneline --graph --all --decorate
# * a1b2c3d (HEAD -> main) feat: payment
# * d4e5f6a feat: cart
# |\ 
# | * g7h8i9j (feature/auth) feat: login
# | * j0k1l2m feat: signup
# |/
# * m3n4o5p init

# Traversal algorithms Git uses:
# 1. Reachability: "what commits are reachable from this ref?"
#    BFS/DFS from the tip following parent edges
git rev-list main            # all commits reachable from main
git rev-list --count main    # count them

# 2. Common ancestor (for merge base):
#    Walk both sides simultaneously, first intersection = merge base
git merge-base main feature/auth    # most recent common ancestor

# 3. Symmetric difference (for git fetch):
#    "What commits are on remote but not local (and vice versa)?"
git rev-list main..origin/main       # on remote, not local
git rev-list origin/main..main       # on local, not remote
git rev-list main...origin/main      # symmetric (both directions)

# Commit-graph file (performance optimisation)
# .git/objects/info/commit-graph
# Pre-computes: generation numbers, bloom filters for path queries
# Used by: git log, git merge-base, git push (reachability)
git commit-graph write --reachable    # build commit-graph
git commit-graph write --reachable --changed-paths  # with bloom filters
git config core.commitGraph true      # enable
git config fetch.writeCommitGraph true  # auto-update on fetch

20 How do you optimise GitHub Actions for speed and cost?

GitHub Actions

# 1. Fail fast -- run cheapest checks first
jobs:
  lint:           # fastest, cheapest -- runs first
    runs-on: ubuntu-latest
    steps: [npm run lint]
  unit-test:
    needs: lint   # only if lint passes
    steps: [npm test]
  e2e-test:
    needs: unit-test  # most expensive last
    steps: [playwright test]

# 2. Parallelise across jobs
jobs:
  test-unit:    { runs-on: ubuntu-latest, ... }  # runs simultaneously
  test-e2e:     { runs-on: ubuntu-latest, ... }  # runs simultaneously
  type-check:   { runs-on: ubuntu-latest, ... }  # runs simultaneously
  build:
    needs: [test-unit, test-e2e, type-check]     # waits for all

# 3. Cache aggressively (see previous question)
# 4. Use larger runners for parallelisable work
runs-on: ubuntu-latest-4-cores   # 4x faster for parallel npm test

# 5. Skip unnecessary runs
on:
  push:
    paths:
      - 'src/**'
      - 'tests/**'
      - 'package*.json'
      # Ignore docs changes: 'docs/**' is not listed, so pushes to docs/ don't trigger

# 6. Concurrency: cancel in-progress runs when a new commit is pushed
concurrency:
  group: ci-${{ github.ref }}
  cancel-in-progress: true      # new push cancels old run (saves minutes)

# 7. Reuse workflows and composite actions to avoid duplication

# 8. Use ubuntu over macos/windows (10x cheaper)
# macOS runner: 10 free minutes per month (paid after)
# ubuntu: 2x the free minutes
# Self-hosted: free compute (you pay for the hardware)

# 9. Conditional steps
- name: Deploy to prod
  if: github.ref == 'refs/heads/main' && github.event_name == 'push'
  run: ./deploy.sh

# 10. Timeout to prevent stuck jobs
jobs:
  test:
    timeout-minutes: 15    # kill job after 15 min (prevents billing runaway)

21 What is GitHub’s required status checks and how do they integrate with CI?

GitHub Required status checks prevent PRs from being merged unless specific CI checks pass. Combined with branch protection, they enforce quality gates.

# Branch protection setting: "Require status checks to pass before merging"
# Add specific check names (the exact name shown in GitHub's PR page)

# Status checks come from:
# 1. GitHub Actions (job names)
# 2. Third-party CI (CircleCI, Jenkins, Travis via API/OAuth app)
# 3. Manual via GitHub Statuses API

# GitHub Actions: the check name = job name (or job name / step name)
jobs:
  test:     # check name: "test"
  build:    # check name: "build"
  security: # check name: "security"

# For matrix jobs: individual checks per matrix entry
# matrix: { os: [ubuntu, windows] }
# Check names: "test (ubuntu)", "test (windows)"

# Custom status via GitHub API
curl -X POST \
  -H "Authorization: Bearer $GITHUB_TOKEN" \
  -H "Content-Type: application/json" \
  https://api.github.com/repos/owner/repo/statuses/$SHA \
  -d '{
    "state": "success",
    "description": "All integration tests passed",
    "context": "my-ci/integration-tests",
    "target_url": "https://ci.example.com/build/123"
  }'
# state: pending | success | failure | error

# "Require branches to be up to date before merging"
# Forces the PR branch to include all commits from the base branch
# Before merging, GitHub checks: is main HEAD reachable from PR branch?
# If not: must click "Update branch" (merge or rebase)
# This + merge queue = gold standard for main branch health

# Bypass required status checks (emergency use)
# Settings โ†’ Branch protection โ†’ "Allow specified actors to bypass required pull requests"
# Keep this list very short (CTO, platform leads only)

📝 Knowledge Check

🧠 Quiz Question 1 of 5

How does Git’s three-way merge determine when a conflict must occur?





🧠 Quiz Question 2 of 5

What is the security benefit of using GitHub OIDC instead of long-lived secrets for cloud deployments?





🧠 Quiz Question 3 of 5

What problem do GitHub merge queues solve that branch protection alone cannot?





🧠 Quiz Question 4 of 5

Why should GitHub Actions workflow steps pin actions to a full commit SHA rather than a tag like @v4?





🧠 Quiz Question 5 of 5

What is the key advantage of trunk-based development over long-lived feature branches like Gitflow?





Tip: Expert Git interviews reward deep internals knowledge. For the three-way merge, draw the merge base diagram before explaining the algorithm. For packfiles, describe the delta compression approach before talking about performance. For OIDC, explain the JWT exchange flow step by step. For merge queues, describe the race condition problem before the solution. Context, depth, and the ability to explain the why behind the how — these separate expert answers.