git status to see what's modified.git add. This lets you craft commits precisely — staging only the changes relevant to a single logical unit of work.git push syncs commits to the remote.git add (working dir → staging) → git commit (staging → repo) → git push (local repo → remote repo).
main — preserves context of when work happenedmain before opening a PRgit rebase -i)git log and git bisectgit cherry-pick <commit-sha> applies the changes from a specific commit onto your current branch without merging the entire source branch.main and you need it in the release/v2.3 branch too without merging all of maingit cherry-pick abc1234 # apply one commit git cherry-pick abc1234 def5678 # apply multiple commits git cherry-pick main~3..main # apply a rangeCherry-pick creates a new commit with a different SHA, so the same logical change appears twice in history. Use it sparingly — over-reliance is a sign of branching strategy problems.
git bisect performs a binary search through commit history to find the exact commit that introduced a bug. You mark a known-good commit and a known-bad commit, and Git checks out the midpoint. You test and mark it good or bad, narrowing the range in half each round.git bisect start git bisect bad # current commit is broken git bisect good v2.1.0 # last known good release tag # Git checks out midpoint — you test, then: git bisect good # or: git bisect bad # Repeat until Git identifies the culprit commit git bisect reset # return to original HEADAutomation: provide a test script and Git runs it automatically:
git bisect run ./test.shUseful when a regression appeared "somewhere in the last 200 commits" — bisect finds it in ~8 steps (log2(200) ≈ 7.6) instead of checking commits one by one.
--soft: moves HEAD, keeps staging area and working dir unchanged (commits disappear, changes stay staged)--mixed (default): moves HEAD, clears staging area, keeps working dir (changes appear unstaged)--hard: moves HEAD, clears staging area, discards working dir changes completely (destructive — changes are gone)git restore file.txt — discard working dir changes for a filegit restore --staged file.txt — unstage a file (was: git reset HEAD file.txt)git filter-repo --path secrets.txt --invert-paths rewrites all commits that touched the filegit filter-repo --string 'AKIAIOSFODNN7EXAMPLE' --replace-with 'REDACTED'Step 3: Force-push all branches. Coordinate with all contributors — their local clones still have the old history. Everyone must re-clone or hard-reset.
git-secrets, trufflehog, or GitHub's secret scanning. Pre-commit hooks should block commits containing high-entropy strings or known key patterns.
main, develop, feature, release, and hotfix branches. Suits teams with scheduled releases and strict versioning.
main is always deployable. Feature branches are short-lived, opened as PRs, merged with squash or merge commit.
mainmain (or merges very short-lived branches within a day or two). CI must be extremely fast and reliable.
if (featureFlags.isEnabled('new-checkout-flow', userId)) {
return newCheckout();
} else {
return legacyCheckout();
}
How they enable TBD: developers merge incomplete features into main behind a disabled flag. The code ships to production but is invisible to users. When the feature is complete and tested, the flag is enabled — no branch, no deployment needed.main at a stable tag: release/v2.4main first, then are cherry-picked into the relevant release branchesbackport: v2.4 labelmain — only cherry-pick specific commitsmain:
.github/CODEOWNERS maps file paths to teams, automatically requesting the right reviewer when a PR touches those files:
# .github/CODEOWNERS /infra/ @org/platform-team /services/auth/ @org/security-team *.tf @org/terraform-teamEnforcing at the organization level: GitHub Organization rulesets (new) or Terraform/Pulumi managing repository settings as code.
<type>[optional scope]: <description> [optional body] [optional footer(s)]Types:
feat, fix, docs, style, refactor, test, chore, ci, perfsemantic-release parse commits to auto-bump versions — fix: → patch, feat: → minor, BREAKING CHANGE: → majordocs: or chore: commitsCloses #123 auto-close GitHub issues on mergecommitlint in a pre-commit hook or CI check:
npx commitlint --from=HEAD~1 --to=HEAD --verbose
.git/hooks/ as executable scripts.pre-commit — run linters, formatters, secret scanners before a commit completescommit-msg — validate commit message format (Conventional Commits enforcement)pre-push — run tests before pushing to prevent breaking shared branchespre-receive — reject pushes that don't meet policy (force-push to main, large files)post-receive — trigger deployments after a push (legacy CD approach).git/hooks isn't committed. Use Husky (Node.js projects) or git config core.hooksPath ./hooks to store hooks in the repo and configure on clone.
# package.json with Husky
"husky": {
"hooks": {
"pre-commit": "lint-staged",
"commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
}
}
--no-verify. Real enforcement requires server-side hooks or CI status checks.git submodule update --init --recursive to fetch submodule contentgit subtree push)--recurse-submodules, causing mysterious build failures.
git clone --recurse-submodules flag. A surprisingly common CI failure is a shallow clone that doesn't initialize submodules, breaking the build.pip install git-filter-repo git filter-repo --path-glob '*.zip' --invert-paths git filter-repo --strip-blobs-bigger-than 10MRewrites entire history, removing blobs. Requires force-pushing and all contributors re-cloning. Permanent solution but disruptive.
git lfs track "*.psd" — writes to .gitattributesgit lfs pullgit lfs installgit clone --depth=1 — no full history needed for buildsgit clone --filter=blob:none — skips blob downloads until neededgit reflog records every movement of HEAD — commits, checkouts, resets, rebases — for 90 days (default). It's your local safety net when history-rewriting operations go wrong.git reflog
# Output:
# abc1234 HEAD@{0}: reset: moving to HEAD~3
# def5678 HEAD@{1}: commit: add authentication middleware
# ...
Recovery scenario — you ran git reset --hard HEAD~3 by mistake:
git reflog # find the commit SHA before the reset git reset --hard def5678 # jump back to that state # or create a new branch at that point: git checkout -b recovery def5678Recovery from bad rebase:
git reflog # find the SHA of HEAD before rebase started
git reset --hard HEAD@{5} # restore pre-rebase state
Reflog is local-only — it is not pushed to remote and is not available after a fresh clone. It doesn't protect against git gc pruning orphaned commits beyond the retention window.
git stash takes your uncommitted changes (both staged and unstaged) and saves them on a stack, returning the working directory to a clean state matching HEAD.git stash # save changes with auto-generated message
git stash push -m "auth work" # save with a descriptive name
git stash list # view all stashes
git stash pop # apply and remove top stash
git stash apply stash@{2} # apply specific stash (keep in list)
git stash drop stash@{2} # remove specific stash
git stash branch feature/auth # create branch from stash (cleaner recovery)
Stash vs. WIP commit:
git commit -m "wip: do not merge") when you need to push to a remote, or the stash may sit for days and be forgotten. WIP commits are visible to teammates and survive laptop reboots/crashes.git stash list regularly to avoid a pile-upgit clone --depth=1 <repo-url> # only latest commit, no full history git fetch --depth=1 origin main # shallow fetch on updatePartial clone (Git 2.22+) — skips large blobs until accessed:
git clone --filter=blob:none <url> # no blobs on clone git clone --filter=tree:0 <url> # no trees (for monorepos)Sparse checkout — only checkout the directories CI needs:
git sparse-checkout init git sparse-checkout set services/api infra/Clone caching between runs:
actions/checkout@v4 with fetch-depth: 1 handles shallow clones automatically.git directory between CI runs to convert clones to fetchesgit fetch --no-tags prevents downloading thousands of tags.
fetch-depth: 1 unless you actually need history (semantic-release and git log-based changelogs need full depth). Most CI jobs don't.kubectl apply or Helm. The cluster doesn't know about Git.kubectl edit deployment or kubectl scale manually# root-app/application.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: root-app
spec:
source:
repoURL: https://github.com/org/gitops-repo
path: apps/ # directory of Application manifests
destination:
server: https://kubernetes.default.svc
syncPolicy:
automated: {}
ArgoCD deploys the root app, which creates all child Application resources from the apps/ directory. Adding a new microservice = add an Application YAML to apps/ and push.envs/dev/, envs/staging/, envs/prod/envs/prod/gitops-config/
base/ # shared Kubernetes manifests
envs/
dev/
kustomization.yaml # image: app:sha-abc123
staging/
kustomization.yaml # image: app:sha-def456
prod/
kustomization.yaml # image: app:sha-789xyz
Promotion workflow:
envs/dev/ image tag — auto-merges if tests passenvs/staging/ tag (manual or automated)envs/prod/ — requires approvalkubectl apply shortcuts; all changes go through Githelm rollbackargocd app history my-app # list sync history with IDs argocd app rollback my-app 3 # roll back to sync ID 3What rollback does:
automated sync is enabled with self-healing, ArgoCD will immediately re-sync to the HEAD commit after rollback — undoing the rollback. To rollback durably with auto-sync enabled, you must either:generators:
- clusters: {} # all registered clusters
template:
spec:
source:
path: '{{path}}'
destination:
server: '{{server}}'
namespace: production
Use cases: deploying to 10 regional clusters, deploying all microservices from a monorepo, deploying per-PR preview environments.
apiVersion: argoproj.io/v1alpha1
kind: Rollout
spec:
strategy:
canary:
steps:
- setWeight: 10 # 10% traffic to new version
- pause: {duration: 5m}
- analysis: # automated analysis before proceeding
templates:
- templateName: success-rate
- setWeight: 50
- pause: {} # manual approval gate
- setWeight: 100
Blue-green: Rollouts maintains two ReplicaSets (blue and green). Traffic is switched atomically after the green environment passes analysis checks. Rollback is instant — just switch traffic back.apiVersion: image.toolkit.fluxcd.io/v1beta2
kind: ImagePolicy
spec:
imageRepositoryRef:
name: my-app
policy:
semver:
range: '>=1.0.0' # pick latest stable release
The flow:
my-app:1.2.3 to ECR1.2.3 as the new desired taggitops-config/
clusters/
us-east-1/
kustomization.yaml # imports base + cluster-specific patches
eu-west-1/
kustomization.yaml
ap-southeast-1/
kustomization.yaml
base/
deployment.yaml # shared base manifests
ArgoCD ApplicationSet cluster generator: automatically creates an Application for every registered cluster — no manual YAML per cluster.git log or the reflog# 1. SecretStore — how to authenticate to AWS
apiVersion: external-secrets.io/v1beta1
kind: SecretStore
metadata:
name: aws-secrets-manager
spec:
provider:
aws:
service: SecretsManager
region: us-east-1
auth:
jwt: # IRSA — pod identity, no static keys
serviceAccountRef:
name: external-secrets-sa
# 2. ExternalSecret — what secret to fetch
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: db-credentials
spec:
refreshInterval: 1h
secretStoreRef:
name: aws-secrets-manager
target:
name: db-credentials # creates this Kubernetes Secret
data:
- secretKey: password
remoteRef:
key: prod/myapp/db # AWS Secrets Manager path
property: password
ESO creates a Kubernetes Secret populated with the fetched value. Your app reads the standard Kubernetes Secret — no SDK or external store knowledge needed.# Fetch the cluster's public key kubeseal --fetch-cert > public-key.pem # Seal a regular Secret kubectl create secret generic db-pass \ --from-literal=password=supersecret \ --dry-run=client -o yaml | \ kubeseal --cert public-key.pem > sealed-db-pass.yaml # Safe to commit sealed-db-pass.yaml to Git git add sealed-db-pass.yaml && git commit -m "add sealed db password"The Sealed Secrets controller in the cluster decrypts the SealedSecret and creates a standard Kubernetes Secret.
kubectl annotate externalsecret db-creds force-sync=$(date +%s) --overwritedetect-secrets (Yelp): scans for high-entropy strings and known secret patterns. Integrates with pre-commit framework.git-secrets (AWS): blocks commits matching configured patterns (AWS key formats, etc.)trufflehog: deep entropy-based scanning, also scans git historytrufflehog or gitleaks on every PR as a required status check.gitignore templates blocking .env, *.pem, credentials.json