Direct answer
A coding agent can automate a regression hunt with git bisect run, but Git should remain the component that chooses which revision to test. Give the agent a narrow, deterministic oracle; give Git one verified known-good and one verified known-bad boundary; classify an unbuildable or flaky revision as untestable; and preserve the complete decision trail. The official git-bisect documentation
defines this binary-search contract, including git bisect skip, git bisect log, git bisect replay, and git bisect reset.
Last reviewed: 2026-09-05
The useful handoff is a classifier, not a free-form debugging prompt. The agent checks out the revision selected by Git, runs the same build and regression test every time, emits a small sanitized record, and returns one of three meaningful outcomes: good, bad, or cannot test. Git treats exit code 0 as good, a nonzero status other than 125 as bad, and 125 as a request to skip the revision. That distinction keeps a broken build from becoming a false accusation against an unrelated commit.
This workflow complements CI failure triage for coding agents because bisect answers a narrower question: which revision first changed a known property? It does not replace incident scoping, dependency checks, or review of the eventual fix.
Freeze the question and boundaries
Write the symptom as a binary predicate before asking an agent to run anything. For example, regression-test exits zero means good and regression-test exits nonzero means bad. Record the known-good revision, the known-bad revision, the path or package under investigation, and any required service fixtures. If the property is performance rather than correctness, use neutral terms such as old and new; Git supports alternate bisect terms for that case.
Do not let the agent guess endpoints from a ticket. Verify both revisions manually, and confirm that the problem is reproducible at the bad endpoint and absent at the good endpoint. A vague boundary produces a precise-looking but useless answer. If the symptom is not monotonic across history, stop and redesign the oracle before starting a binary search.
Build a deterministic oracle
Put the oracle in the repository or in a separately versioned investigation directory. It should build the checkout, run the smallest test that proves the regression, and classify environmental problems explicitly. Repeated runs are useful when a test may be flaky. Three attempts are an example, not a universal threshold; choose a count that fits the test’s known variance.
#!/usr/bin/env bash
set -euo pipefail
commit=$(git rev-parse HEAD)
if ! make build >build.log 2>&1; then
echo classification=skip commit=$commit reason=build-failed >>bisect-events.log
exit 125
fi
pass_count=0
fail_count=0
for attempt in 1 2 3; do
if ./run-regression-test >test-$attempt.log 2>&1; then
pass_count=$((pass_count + 1))
else
fail_count=$((fail_count + 1))
fi
done
if [ $pass_count -eq 3 ]; then
echo classification=good commit=$commit attempts=3 >>bisect-events.log
exit 0
fi
if [ $fail_count -eq 3 ]; then
echo classification=bad commit=$commit attempts=3 >>bisect-events.log
exit 1
fi
echo classification=skip commit=$commit reason=flaky attempts=3 >>bisect-events.log
exit 125
The script deliberately avoids printing source code, environment secrets, full file paths, or request payloads. Its job is to make a repeatable decision and leave enough context for a reviewer to understand why that decision was made. If the test needs a network service, pin the fixture or replace it with a stable local double; otherwise the agent may classify infrastructure drift as a product regression.
Run the bisect in an isolated checkout
Use a disposable worktree or runner workspace. Before starting, capture the branch name, the current revision, the Git version, and the command used to invoke the oracle. Then run the bisect:
git bisect start <bad-commit> <good-commit> --
git bisect run ./scripts/bisect-oracle.sh
git bisect log >bisect.log
git show --stat --oneline refs/bisect/bad >first-bad-summary.txt
git bisect reset
The Git debugging chapter shows the same progression for manual and automated regression hunts and emphasizes resetting after the search. Keep the agent’s permissions limited to checking out revisions, building, testing, and writing evidence. It should not edit application files while the oracle is running. If the run is interrupted, preserve the current log and use the documented replay or next-step commands rather than silently starting over.
Preserve every classification
A final first-bad commit is not enough evidence. Keep the bisect log, the exact oracle script revision, per-attempt test output, build output for skipped revisions, and a summary of the selected commit. A compact event record can look like this:
run_id: bisect-20260905-01
commit: <sha>
classification: good|bad|skip
exit_code: 0|1|125
attempts: 3
duration_ms: 8420
runner: linux
git_version: 2.x
oracle_revision: <sha>
artifact_name: bisect-<sha>.tar
Use stable field names and short values so a human or another tool can compare iterations without exposing sensitive data. Include a reason whenever the classification is skip. If the agent reports a bad revision but the event record is missing, treat the result as incomplete. Keep raw logs separate from the summary so a reviewer can inspect both the concise decision and the original output.
Happy path
The happy path starts with two verified endpoints. The agent runs the oracle at each revision selected by Git. Every revision produces a classification, a log, and the command duration. Git narrows the range until it reports the first bad commit. The operator then inspects that commit, reruns the oracle outside bisect, and compares the changed files with the symptom. Only after that check should a repair agent be asked to propose a patch.
For GitHub Actions, the workflow artifacts guide
documents uploading build and test output, setting retention-days, downloading artifacts between jobs, and validating an upload with a SHA-256 digest. A minimal evidence step is:
- name: Upload bisect evidence
uses: actions/upload-artifact@v4
with:
name: bisect-evidence-${{ github.run_id }}
path: evidence/
retention-days: 14
Use a unique artifact name for each run. GitHub’s v4 artifacts are immutable, so a later job should upload a new named artifact rather than trying to replace an earlier one. Keep the digest and upload log with the investigation index.
Error path
If the build fails for an unrelated reason, the oracle records skip and exits 125; it does not label the revision bad. If repeated test attempts disagree, the oracle records flaky and also exits 125. The operator pauses the bisect, fixes the test or pins the missing fixture, and starts a new run with a fresh log. If skipped revisions surround the actual culprit, Git may be unable to identify one exact commit, so report a narrowed range rather than overstating certainty.
For GitLab, configure an artifact that survives failed jobs and expires according to the investigation window. The GitLab job artifacts documentation
describes artifacts:when: always, paths, and expire_in:
artifacts:
when: always
paths:
- evidence/
expire_in: 14 days
Jenkins operators should use stash only for small, same-run handoffs and use an archive or external artifact manager for larger logs. The Jenkins Pipeline reference
notes that stashes normally disappear at the end of a run, while preserveStashes() can retain them for a restarted pipeline. In every CI system, make the evidence upload run even when the classifier returns a failure status.
Who this is for
This guide is for developers, release engineers, and platform teams supervising coding agents in CI. It is especially useful when a regression spans many commits, when reproducing it by hand is expensive, or when several agents may otherwise produce inconsistent diagnoses. It is not a substitute for understanding the test itself; the person defining the oracle remains responsible for its meaning.
It also fits teams that need an auditable handoff between an investigation agent and a repair agent. The first agent answers where the behavior changed and records evidence. The second can answer what change should be made only after a person validates the first answer.
Key takeaways
- Define a binary property and verify known-good and known-bad endpoints before automation.
- Keep the agent’s role to building, testing, classifying, and recording evidence.
- Reserve exit code
125for revisions that cannot be tested, including unrelated build failures and flaky outcomes. - Save
git bisect log, the oracle version, per-revision output, and the final commit summary. - Reset the checkout after the run so later commands do not operate on a temporary bisect revision.
- Upload evidence on both success and failure, with retention long enough for incident review.
- Ask a human to rerun the oracle and inspect the first bad commit before changing production code.
Sources checked
- Git bisect documentation : binary search, good and bad markers, skip behavior, automated runs, logs, replay, and reset.
- Debugging with Git : practical manual and automated regression examples and cleanup guidance.
- GitHub workflow artifacts : test-output uploads, retention periods, immutable artifacts, downloads, and digest validation.
- GitLab job artifacts
: artifact paths,
expire_in, upload conditions, fetching behavior, and size controls. - Jenkins Pipeline basic steps
: stash lifecycle,
preserveStashes, archive behavior, and size considerations.
These are public, independently useful references: two explain Git’s own bisect behavior, and three document evidence handling in widely used CI systems. Check the relevant platform policy before selecting a retention period, because repository or instance limits can override a job-level setting.
Contract details to verify
Before launch, verify the following contract with the agent and the CI runner:
- The good and bad revisions are immutable references, not moving branch names.
- The oracle has no network dependency that can change between revisions, or that dependency is pinned and recorded.
- Build failure, missing fixture, timeout, and flaky output map to skip rather than bad.
- The test has a clear pass/fail predicate and does not silently swallow exceptions.
- The workspace is disposable, and the agent cannot modify the code under test during classification.
- Evidence is uploaded even when the job fails, with a retention period long enough for review.
- The artifact name identifies the run without embedding sensitive data or unbounded command output.
- A reviewer can replay the decision from
bisect.logand the stored oracle. - The cleanup step verifies the original branch and revision after
git bisect reset.
Use terminal command evidence guidance when you standardize command transcripts across repositories. For a broader handoff format, see the reviewable diffs workflow . Keep those links alongside the evidence index, not inside generated test output.
Failure modes
Wrong endpoints. If the known-good revision is already broken, Git can still produce a first bad commit, but the conclusion is invalid. Reproduce both endpoints before starting and record the observed result.
A flaky oracle. One intermittent failure can move the search boundary in the wrong direction. Repeat the test, detect disagreement, and return 125 until the test is stable enough to classify.
Unrelated build breakage. A revision may not compile because of a transient toolchain issue or a separate migration. Mark it skip, capture the build log, and document whether the skipped range touches the suspected change.
Skipped neighbors. Git’s documentation warns that skipping a commit adjacent to the sought change can prevent an exact answer. Report a candidate range when that happens, then test additional commits manually if possible.
Dirty or shared worktrees. An agent that edits files, leaves generated state behind, or shares a checkout with another job can contaminate later classifications. Use a disposable worktree, clean before each revision, and fail closed if unexpected changes appear.
Environment drift. Different compiler versions, service fixtures, or cache contents can make identical commits behave differently. Log tool versions and runner identity, pin dependencies where practical, and distinguish infrastructure failures from product failures.
Evidence that expires too soon. GitHub artifact retention is configurable but bounded by repository, organization, or enterprise policy. GitLab uses expire_in and instance defaults. Jenkins stashes are normally run-scoped. Set retention to cover the incident review period and copy long-lived evidence to an approved archive when policy permits.
Oversized evidence. Uploading entire workspaces makes review slow and may hit platform limits. Keep the oracle output, relevant logs, test reports, and commit metadata; exclude caches and generated directories. Jenkins specifically cautions that large stashes can consume controller resources.
No cleanup. A checkout left at a bisect revision can mislead a later command or agent. Always run git bisect reset, and verify the original branch and revision before handing the workspace back.
Non-monotonic behavior. If the symptom appears, disappears, and reappears across the range, binary search assumptions do not hold. Record that limitation and use a narrower question or a different investigation method rather than presenting the result as a definitive first cause.
FAQ
Why use 125 instead of another failure code? Git reserves 125 in git bisect run for a revision that cannot be tested. Git skips that revision instead of treating it as a bad source commit. Use another nonzero status for a reproducible regression.
Can the agent choose commits to skip? It can identify why a revision is untestable, but the policy should be explicit. A skip without a reason is weak evidence. Record the reason, preserve the output, and let a human decide whether to continue or narrow the range.
What if the regression is a performance change? Use alternate terms such as old and new, or custom terms that describe the property. This avoids forcing a correctness vocabulary onto a benchmark result. Keep the benchmark inputs and acceptance threshold fixed.
How many times should a flaky test run? There is no universal number. Start with enough repetitions to expose known variance, then validate the false-positive and false-negative risk on the good and bad endpoints. The example uses three attempts only to show how disagreement can be classified.
Should the coding agent fix the first bad commit automatically? No. The bisect agent should produce a candidate and evidence. A separate repair step can inspect the diff, reproduce the regression, and propose a change after a reviewer confirms that the candidate explains the symptom.
What if Git reports a range instead of one commit? Preserve that uncertainty. Adjacent skipped revisions, merges, or a non-monotonic property can make one exact culprit unknowable from the available classifications. Expand the test set or report the smallest defensible range.
How should an interrupted run continue? Save the current git bisect log and event records before changing the workspace. After correcting an incorrectly classified revision, reset and replay the edited log; otherwise resume only after verifying which checkout and boundaries are active.
Reader next step
Create scripts/bisect-oracle.sh in a disposable branch, run it manually against one verified good and one verified bad revision, and inspect the generated event record. Then launch a short git bisect run job that uploads bisect.log, the oracle, and test output as one retained artifact. Have a reviewer replay the log, rerun the oracle at the reported first bad commit, and only then open a repair task. This sequence gives your coding agent a bounded investigation and gives the rest of the team evidence they can verify.