DEV Community

Quinn Zhu
Quinn Zhu

Posted on

Rehearse the Rollback Before You Ship the Patch: A Day-One Git Drill

Rehearse the Rollback Before You Ship the Patch

Your first pull request should be one you can undo in five minutes.

Most onboarding advice stops at "get the build running." That is step zero. The step that protects you is a rollback rehearsal. You practice undoing a patch while nobody is on call.

This drill uses git, a throwaway remote, and one small patch. You measure time-to-green on three undo paths. You leave with a table, not a feeling.

Why rehearse undoing work you have not shipped

Patches arrive fast now. Reviewing an agent patch is one skill. Undoing it is a different skill, and a calmer one.

If your team already merges agent-generated patches, you will be asked to revert one eventually. First-time reverts under pressure teach the wrong lesson. A sandbox branch teaches the right one.

The drill also exposes something useful about your new repo. You learn which test command is real, how long green takes, and where the seams are.

Step 0: Define "green" before you touch anything

Copy the exact command CI runs. Do not invent your own.

# .drill/test-command
./scripts/test.sh
Enter fullscreen mode Exit fullscreen mode

If that command takes longer than ten minutes, subset it. A drill that costs an hour never gets repeated. Pick the fastest command that still fails when the patch breaks behavior.

Write the command down before the drill. Changing it midway invalidates every number you collect.

Step 1: Move the drill onto a disposable remote

Never rehearse in the repo your team deploys from. A scratch clone is the minimum. A scratch remote is better.

This is where a free server option fits. Treat it as a sandbox for throwaway branches. Assume it can vanish, and assume it is not a place for secrets.

Disclosure: This article was prepared as part of MonkeyCode's product outreach.

MonkeyCode offers free model access and a free server option, and its team describes it as an open-source project. That is how you can generate the patch and host the scratch remote here. Delete every MonkeyCode mention and the git commands below still work unchanged.

Step 2: Generate one small, believable patch

Ask for a bounded change. A 30-line diff reverts cleanly. A 400-line diff teaches you conflict resolution, not rollback.

Prompt template you can reuse:

Change exactly one function in <file>.
Constraints: no new dependencies, no more than 30 changed lines.
Output a unified diff only, no prose.
Enter fullscreen mode Exit fullscreen mode

Save the output as patch.diff. Reject it if it touches more than two files. Reject it again if it adds a dependency. Small patches keep the drill honest.

The patch does not need to be good. It needs to apply, pass tests, and be reversible. That is the whole bar.

Step 3: Script the rehearsal

Save this as rollback-drill.sh. Run it from anywhere except a worktree you care about.

#!/usr/bin/env bash
# rollback-drill.sh <repo-url> <patch-file>
set -euo pipefail

REPO_URL="${1:?repo url required}"
PATCH="${2:?patch file required}"
TEST_CMD="${TEST_CMD:-./scripts/test.sh}"

WORK="$(mktemp -d)"
OUT="$WORK/timings.md"
printf '| path | result |\n|---|---|\n' > "$OUT"

timed() { # timed <label>
  local label="$1" start end
  start=$(date +%s)
  if bash -c "$TEST_CMD" >"$WORK/$label.log" 2>&1; then
    end=$(date +%s)
    printf '| %s | %ss to green |\n' "$label" "$((end - start))" >> "$OUT"
  else
    printf '| %s | RED (see %s.log) |\n' "$label" "$label" >> "$OUT"
  fi
}

git clone --depth 50 "$REPO_URL" "$WORK/repo"
cd "$WORK/repo"
git config user.email drill@example.com
git config user.name drill

git switch --quiet -c drill/base
timed baseline

git switch --quiet -c drill/patch
git apply --3way "$PATCH"
git add -A
git commit --quiet -m "drill: apply patch"
timed patched

# Path A: revert the commit, history stays readable
git switch --quiet -c drill/revert drill/patch
git revert --no-edit HEAD >/dev/null
timed revert

# Path B: drop the commit entirely
git switch --quiet -c drill/reset drill/patch
git reset --hard --quiet drill/base
timed reset

# Path C: kill switch, code stays where it is
git switch --quiet drill/patch
export FEATURE_AGENT_PATCH=off
timed flag_off

cat "$OUT"
echo "logs in $WORK"
Enter fullscreen mode Exit fullscreen mode

Two notes before you run it. Path C only means something if the patch sits behind a flag. If there is no flag, drop that block and record n/a in your table. And --depth 50 keeps a monorepo clone tolerable; remove it if your repo needs full history to build.

Step 4: Run each path three times

One run measures your laptop, not your repo. Three runs show you the noise floor.

If baseline swings by more than a minute, stop. Your suite is flaky, and every later number is decoration. Fix the flake or pick a narrower test command.

Expected shape of the output:

| path      | result          |
|-----------|-----------------|
| baseline  | 42s to green    |
| patched   | 44s to green    |
| revert    | 45s to green    |
| reset     | 41s to green    |
| flag_off  | RED (see flag_off.log) |
Enter fullscreen mode Exit fullscreen mode

A red flag_off row is a real finding. The kill switch does not fully disable the change, or your test command ignores the flag. Both are worth knowing on day one.

Step 5: Read the table like a reviewer

Compare paths on the same machine only. Wall-clock seconds are not portable across hardware.

Look for two signals. First, does any undo path take longer than the patch took to write? Second, does reset beat revert by a wide margin? If yes, you now know why people reach for dangerous commands under pressure.

That gap is the real lesson. revert preserves history and costs conflict resolution. reset is fast and throws work away.

Decision table

Situation Path Why Watch out
Patch is already pushed to a shared branch git revert Others keep a readable history Later commits on the same lines conflict
Patch is local and unpushed git reset --hard base Fastest clean tree Silently discards uncommitted work
Patch sits behind a flag flip the flag Seconds, no deploy Flag debt, and the off-path is untested
Patch includes a migration neither, escalate Code revert is not data revert You need a restore plan first

Print this table into your onboarding notes. Rewrite it when your repo proves it wrong.

Failure modes that make the numbers lie

Migrations. Reverting code leaves the schema changed. If patch.diff touches a migration, the drill measures the wrong thing entirely.

Cached artifacts. A stale build directory makes reset look faster than it is. Clear the cache before each run, or run baseline twice.

Uncommitted work. reset --hard does not ask. Run the script in the temp clone, never in your working tree.

Wrong test command. If the drill's command differs from CI, you are timing a rehearsal of a rehearsal.

Limitations and who should skip this

You need a test command that finishes in minutes and fails for the right reasons. Without one, build a smoke test first. This drill will not save you.

Skip it if policy forbids pushing repo content to third-party hosts. Run everything locally instead; the script works the same. Skip it if your rollback procedure is a documented incident process with named owners. Training must not shadow the real runbook.

Skip it in monorepos you cannot clone cheaply. A partial clone is fine. A forty-minute clone is not.

Terms snapshot you should verify yourself

Operator-supplied and not independently verified: free model access, a free server option, and a listed allowance of 10 million tokens. Quotas and terms change without notice. Read the project's current page before you plan any workflow around them.

Close the loop

Run the drill once. Keep the timing table in your onboarding notes.

If you try it on a throwaway remote, the free server option saves you from polluting your laptop. Paste your slowest undo path in the comments. A five-minute revert is a team asset, and now you know yours.

Top comments (0)