Chapter 25Lesson 05~220 minutes

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.

CheckpointExact buildGuarded writesGitOps state

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

  1. After the runner detaches at the requested commit, will git branch --show-current print trunk?
  2. If a human advances release-config after the bot's last fetch, should the bot's ordinary push succeed?
  3. If desired state fails validation, should applied-commit.txt advance?
  4. Can the provenance commit OID remain stable even if a human-friendly git describe result 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 HEAD exactly matched the requested BUILD_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

All checkpoint repositories/state are disposable. Verify the parent path before recursive deletion.
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.

Next chapter

Production Capstone: Design, Secure, Scale, and Recover a Governed Git Workflow

Chapter 26 integrates the entire course—collaboration, recovery, trust, performance, migration, CI/CD, and GitOps—into one governed local operating model with failure injection and handoff evidence.

Authoritative references

 git-rev-parse
 git-status
 git-fetch
 git-push
 git-tag

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.

Ethereum / ERC-20
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0 Send only Ethereum/ERC-20 compatible assets to this address.