Checkpoint Lab — Git in CI/CD, Infrastructure as Code, Release Automation, and GitOps
Checkpoint the complete local automation model: exact detached build, provenance, supplemental tag/history context, release-state bot with stale-write rejection, desired-state reconciliation, failure preservation, rollback documentation, and role-based least privilege.
Learning objectives
- Predict and verify detached HEAD, immutable OID, and shallow/tag behavior.
- Generate a reproducible source provenance report and exact-commit source artifact.
- Use a dedicated automation branch and normal fast-forward pushes instead of force authority.
- Demonstrate stale bot rejection and safe integration of newer human state.
- Keep desired, candidate, applied, and observed deployment concepts separate through failure/rollback.
1. Checkpoint scenario — exact source, guarded automation, explicit reconciliation state
You operate a local simulation of a production delivery system. A bare Git server holds source and release-state refs. A developer publishes desired state. An isolated runner builds one immutable commit in detached HEAD and writes provenance. A release bot updates only its dedicated branch using normal fast-forward semantics. A reconciler applies desired state only after validation and records the last successful commit outside source Git.
2. Predict before executing
-
After the runner detaches at the requested commit, will
git branch --show-currentprinttrunk? -
If a human advances
release-configafter the bot's last fetch, should the bot's ordinary push succeed? -
If desired state fails validation, should
applied-commit.txtadvance? -
Can the provenance commit OID remain stable even if a
human-friendly
git describeresult changes after more tags/history are fetched?
3. Create server and source clone
mkdir git-cicd-checkpoint
cd git-cicd-checkpoint
git init --bare -b trunk server.git
git clone server.git source
git -C source config user.name "Learner Example"
git -C source config user.email "learner@example.invalid"
mkdir -p source/app source/environments/lab
printf "message=checkpoint\n" > source/app/app.conf
printf "replicas=2\nversion=1\n" > source/environments/lab/service.env
cat > source/validate.sh <<'EOF'
#!/bin/sh
replicas=$(sed -n 's/^replicas=//p' environments/lab/service.env)
version=$(sed -n 's/^version=//p' environments/lab/service.env)
test -n "$replicas" && test "$replicas" -ge 1 && test -n "$version"
EOF
git -C source add .
git -C source commit -m "seed delivery source"
git -C source tag -a v1.0 -m "checkpoint v1.0"
printf "message=checkpoint-build\n" > source/app/app.conf
git -C source commit -am "prepare checkpoint build"
git -C source push -u origin trunk
git -C source push origin v1.0
BUILD_OID=$(git -C source rev-parse HEAD)
4. Preflight source/server state
git -C source status --short --branch
git -C source show -s --format='%H %s' "$BUILD_OID"
git -C server.git show-ref
git -C server.git fsck --full
The checkpoint records BUILD_OID as the immutable build
request.
5. Create an isolated shallow/no-tags runner
SERVER_URL="file://$(pwd)/server.git"
git clone --depth=1 --no-tags --branch trunk "$SERVER_URL" runner
test "$(git -C runner rev-parse HEAD)" = "$BUILD_OID"
git -C runner switch --detach "$BUILD_OID"
git -C runner branch --show-current
git -C runner rev-parse --symbolic-full-name HEAD
git -C runner rev-parse --is-shallow-repository
Prediction 1 verification: current branch is empty while HEAD
exactly equals BUILD_OID.
6. Generate the build/provenance report
cd runner
COMMIT=$(git rev-parse --verify HEAD^{commit})
TREE=$(git rev-parse --verify HEAD^{tree})
SHORT=$(git rev-parse --short HEAD)
if test -z "$(git status --porcelain=v1)"; then CLEAN=true; else CLEAN=false; fi
SHALLOW=$(git rev-parse --is-shallow-repository)
printf "commit=%s\ntree=%s\nshort=%s\nclean=%s\nshallow=%s\n" \
"$COMMIT" "$TREE" "$SHORT" "$CLEAN" "$SHALLOW" | tee provenance.txt
sh validate.sh
test "$COMMIT" = "$BUILD_OID"
test "$CLEAN" = true
cd ..
7. Demonstrate version context is supplemental to commit identity
git -C runner describe --tags HEAD
echo "before fetch describe exit=$?"
git -C runner fetch --unshallow origin
git -C runner fetch --tags origin
git -C runner describe --tags --always HEAD
test "$(git -C runner rev-parse HEAD)" = "$BUILD_OID"
The human-readable description becomes richer; the commit provenance remains unchanged.
8. Export exact source artifact
git -C runner archive --format=tar \
-o build-"$(git -C runner rev-parse --short HEAD)".tar HEAD
9. Initialize automation-owned release state
git -C source switch -c release-config
printf "release_commit=%s\nstatus=candidate\n" "$BUILD_OID" > source/release.env
git -C source add release.env
git -C source commit -m "initialize release state"
git -C source push -u origin release-config
git -C source switch trunk
This checkpoint keeps release state on a dedicated branch so ordinary fast-forward rules can protect concurrent updates. Server-side permissions would restrict that branch to the intended automation/operator identities in production.
10. Bot writes only its dedicated branch
git clone "$SERVER_URL" bot
git -C bot config user.name "Release Automation"
git -C bot config user.email "release-bot@example.invalid"
git -C bot switch release-config
printf "release_commit=%s\nstatus=released\n" "$BUILD_OID" > bot/release.env
git -C bot add release.env
git -C bot commit -m "release exact build"
git -C bot fetch origin release-config
BASE=$(git -C bot rev-parse refs/remotes/origin/release-config)
git -C bot merge-base --is-ancestor "$BASE" HEAD
git -C bot push --dry-run --porcelain origin HEAD:refs/heads/release-config
git -C bot push origin HEAD:refs/heads/release-config
No force/lease bypass is needed because automation history is monotonic.
11. Prediction 2 — prove stale-write protection
git clone "$SERVER_URL" operator
git -C operator config user.name "Release Operator"
git -C operator config user.email "operator@example.invalid"
git -C operator switch release-config
printf "operator=manual-review\n" > operator/manual-review.env
git -C operator add manual-review.env
git -C operator commit -m "record manual release review"
git -C operator push origin release-config
printf "bot=post-release-record\n" > bot/post-release.env
git -C bot add post-release.env
git -C bot commit -m "record post-release metadata"
git -C bot push origin HEAD:refs/heads/release-config
echo "expected stale push exit=$?"
Expected: non-zero exit and non-fast-forward rejection.
12. Resolve concurrency without force authority
git -C bot fetch origin release-config
git -C bot merge --no-edit refs/remotes/origin/release-config
git -C bot push --dry-run --porcelain origin HEAD:refs/heads/release-config
git -C bot push origin HEAD:refs/heads/release-config
13. Reconcile desired state and record success separately
mkdir deployed
printf "none\n" > deployed/applied-commit.txt
DESIRED=$(git -C runner rev-parse HEAD)
BEFORE=$(cat deployed/applied-commit.txt)
if sh runner/validate.sh; then
cp runner/environments/lab/service.env deployed/service.env
printf "%s\n" "$DESIRED" > deployed/applied-commit.txt
fi
AFTER=$(cat deployed/applied-commit.txt)
printf "before=%s\ndesired=%s\nafter=%s\n" "$BEFORE" "$DESIRED" "$AFTER"
test "$AFTER" = "$DESIRED"
14. Prediction 3 — failed desired state must not advance applied state
git -C source switch trunk
printf "replicas=0\nversion=2\n" > source/environments/lab/service.env
git -C source add environments/lab/service.env
git -C source commit -m "inject invalid desired state"
git -C source push origin trunk
BAD_OID=$(git -C source rev-parse HEAD)
git -C runner fetch origin trunk
git -C runner switch --detach "$BAD_OID"
APPLIED_BEFORE=$(cat deployed/applied-commit.txt)
if sh runner/validate.sh; then
cp runner/environments/lab/service.env deployed/service.env
printf "%s\n" "$BAD_OID" > deployed/applied-commit.txt
else
echo "validation failed; applied marker intentionally unchanged"
fi
APPLIED_AFTER=$(cat deployed/applied-commit.txt)
test "$APPLIED_BEFORE" = "$APPLIED_AFTER"
test "$APPLIED_AFTER" != "$BAD_OID"
15. Write the rollback/failure runbook
Build failure
- preserve requested OID + runner HEAD/status/log
- do not move source refs to hide the failure
- repair code/toolchain and create a new commit
Release-state push rejection
- fetch current release-config
- inspect human/bot commits
- recompute/merge from latest state
- normal fast-forward push; no blind force
Desired-state validation/apply failure
- keep applied marker at last successful commit
- capture candidate OID and error evidence
- either fix/revert desired state in Git or re-apply known-good artifact
- advance applied marker only after success
Credential incident
- revoke/rotate exposed credential
- remove from logs/config and fix injection path
- do not treat Git history cleanup as credential rotation
16. Verification checklist
-
Runner
HEADexactly matched the requestedBUILD_OID. - Detached checkout had no current branch but remained valid.
- Provenance contained full commit/tree IDs and clean-state evidence.
- Tag/history fetch changed version context but not the build OID.
- Artifact was created from exact detached HEAD.
- Release bot used a dedicated branch and no force option.
- Stale bot push was rejected after operator advancement.
- Bot merged latest remote state before retrying.
- Applied marker advanced only after successful validation.
- Invalid desired state remained distinct from last successful applied state.
17. Production recommendation by automation role
| Role | Read/write scope | Required provenance |
|---|---|---|
| Build/test runner | read-only | exact source OID + clean/toolchain data |
| Release packager | read source; artifact registry write | source OID/tag/signature policy |
| Release-state bot | write dedicated ref only | base remote OID + new commit OID |
| GitOps reconciler | read desired state; target-system permission | desired/candidate/applied/observed identities |
18. Cleanup
cd ..
pwd
rm -rf git-cicd-checkpoint
PowerShell equivalent:
Set-Location ..; Remove-Item -Recurse -Force
git-cicd-checkpoint.
19. Knowledge check
Question 1. The runner is detached and
branch --show-current is empty, but HEAD equals
BUILD_OID. Is provenance valid?
Question 2. A release bot's push is rejected after an operator commit. What protected the human work?
Question 3. Why did fetching tags/history not change the build identity?
Question 4. A bad desired commit exists on trunk. Why must the applied marker remain on the older commit?
Question 5. Which server controls remain outside this local Git lab?
20. What Chapter 25 adds to a production Git operating model
You can now make CI source identity branch-independent, budget shallow/partial fetches from actual job needs, generate immutable provenance, treat bot authentication/authorization/signing separately, update automation-owned refs without force, and model GitOps as desired-state reconciliation whose success is tracked independently.
21. Chapter checkpoint summary
Git is the coordination substrate for delivery, not the delivery engine itself. Reliable automation converts requested refs into exact commits, validates clean source, records provenance, guards writes, and refuses to claim deployment success until the target state has actually reconciled.
Authoritative references
Keep the academy open
Support free, practical DevOps education.
Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0
Send only Ethereum/ERC-20 compatible assets to this
address.