external/ag-shared/prompts/skills/git-bisect/SKILL.md
You are an expert software engineer helping to identify the commit that introduced test failures or flakiness using git bisect.
Your goal is to systematically bisect the git history to find the exact commit that introduced the issue.
If the user provides a command option of help:
nx test, yarn test).NX_DAEMON=false to avoid async Nx daemon project graph re-calculation from affecting execution stability.The user provides ${ARGUMENTS} which should contain:
HEAD or latest)origin/bX.Y.Z)${ARGUMENTS} if it looks like a test command)Parse ${ARGUMENTS} to extract:
BAD_REF: Commit/branch where tests failGOOD_REF: Commit/branch where tests passTEST_COMMAND: Command to execute for each bisect stepExample argument formats:
bad=HEAD good=origin/b12.3.0 test="yarn nx test package-name --testPathPattern='test.test.ts'"HEAD origin/b12.3.0 "yarn nx test package-name --testPathPattern='test.test.ts'""yarn nx test package-name --testPathPattern='test.test.ts'" (uses HEAD as bad, prompts for good)Check current state:
git status
git log -1 --oneline
REPO_ROOT=$(git rev-parse --show-toplevel)
Validate test files exist (if test command references specific files):
# Extract test file patterns from TEST_COMMAND if possible
# This helps catch issues early (e.g., testing wrong package)
Verify the issue exists on the bad commit:
git checkout ${BAD_REF}
export NX_DAEMON=false
# Handle node_modules for worktrees
REPO_ROOT=$(git rev-parse --show-toplevel)
if [ ! -d "${REPO_ROOT}/node_modules/.bin" ]; then
MAIN_WORKTREE=$(git rev-parse --git-dir | sed 's|/\\.git/worktrees/.*|/.git|' 2>/dev/null)
if [ -n "$MAIN_WORKTREE" ] && [ -d "$MAIN_WORKTREE/../node_modules/.bin" ]; then
export PATH="$(dirname "$MAIN_WORKTREE")/node_modules/.bin:$PATH"
fi
fi
${TEST_COMMAND}
Initialize bisect:
git bisect start
git bisect bad ${BAD_REF}
git bisect good ${GOOD_REF}
Verify bisect range:
git bisect visualize --oneline | head -20
This shows the commits that will be tested.
Determine repository root (handles worktrees):
# Get the git root directory (works for both regular repos and worktrees)
REPO_ROOT=$(git rev-parse --show-toplevel)
echo "Repository root: $REPO_ROOT"
# Check if we're in a worktree and find main worktree if needed
GIT_DIR=$(git rev-parse --git-dir)
MAIN_WORKTREE=""
if echo "$GIT_DIR" | grep -q worktrees; then
echo "Detected git worktree"
# Extract main worktree path
MAIN_GIT_DIR=$(echo "$GIT_DIR" | sed 's|/\\.git/worktrees/.*|/.git|')
if [ -d "$MAIN_GIT_DIR" ]; then
MAIN_WORKTREE=$(cd "$MAIN_GIT_DIR/.." && pwd)
fi
fi
Create a test script:
# Use a workspace-relative temp directory
BISECT_SCRIPT="${REPO_ROOT}/tmp/bisect_test.sh"
mkdir -p "$(dirname "$BISECT_SCRIPT")"
cat > "$BISECT_SCRIPT" << EOF
#!/bin/bash
set -e
cd "${REPO_ROOT}"
# Export NX_DAEMON=false to avoid async daemon issues
export NX_DAEMON=false
# Handle node_modules location (for worktrees that share node_modules)
if [ ! -d "node_modules/.bin" ] && [ -n "${MAIN_WORKTREE}" ] && [ -d "${MAIN_WORKTREE}/node_modules/.bin" ]; then
export PATH="${MAIN_WORKTREE}/node_modules/.bin:$PATH"
fi
# Run the test command
${TEST_COMMAND}
EOF
chmod +x "$BISECT_SCRIPT"
Run automated bisect:
git bisect run "$BISECT_SCRIPT"
Handle special cases:
git bisect skip
git bisect skip
If automated bisect encounters issues, proceed manually:
Check current commit:
git log -1 --oneline
Run tests:
export NX_DAEMON=false
${TEST_COMMAND}
Mark result:
git bisect good
git bisect bad
git bisect skip
Repeat until git bisect identifies the culprit commit.
Get the culprit commit:
git bisect log
git log -1 --oneline
Examine the commit:
git show --stat ${CULPRIT_COMMIT}
git show ${CULPRIT_COMMIT}
Reset bisect:
git bisect reset
Provide a summary:
## Git Bisect Results
**Issue:** ${TEST_COMMAND} failures
**Bad commit:** ${BAD_REF} (${BAD_COMMIT_HASH})
**Good commit:** ${GOOD_REF} (${GOOD_COMMIT_HASH})
**Culprit commit:** ${CULPRIT_COMMIT_HASH}
**Culprit commit details:**
- Author: ${AUTHOR}
- Date: ${DATE}
- Message: ${COMMIT_MESSAGE}
- Files changed: ${FILES_CHANGED}
**Next steps:**
1. Review the changes in ${CULPRIT_COMMIT_HASH}
2. Identify the specific change that introduced the issue
3. Fix the issue or revert the problematic change
timeout 60 ${TEST_COMMAND}
&&:
yarn nx test package1 --testPathPattern="test1.test.ts" && \
yarn nx test package2 --testPathPattern="test2.test.ts"
for i in {1..3}; do ${TEST_COMMAND} && break; doneAlways skip commits that:
NX_DAEMON=false to avoid async daemon issues--testPathPattern to limit test scope# Test files in different packages
TEST_COMMAND="yarn nx test package1 --testPathPattern='test1.test.ts' && \
yarn nx test package2 --testPathPattern='test2.test.ts'"
Important: When testing files in different packages, ensure:
--passWithNoTests flag if a test file might not exist in older commitsTEST_COMMAND="yarn nx test package-name --testPathPattern='test.test.ts' --testNamePattern='specific test name'"
If bisect gets stuck or produces unexpected results:
Check bisect state:
git bisect log
git bisect visualize
Reset and restart if needed:
git bisect reset
# Start over from Phase 2
Narrow the range manually:
# Test a commit in the middle manually
git checkout ${MIDDLE_COMMIT}
${TEST_COMMAND}
# Then restart bisect with narrower range
Format: ${ARGUMENTS} can be:
bad=<ref> good=<ref> test="<command>" - Full specification<bad-ref> <good-ref> "<test-command>" - Positional arguments"<test-command>" - Test command only (prompts for bad/good refs)Examples:
/git/bisect bad=HEAD good=origin/b12.3.0 test="yarn nx test package-name --testPathPattern='test.test.ts'"/git/bisect HEAD origin/b12.3.0 "yarn nx test package-name --testPathPattern='test.test.ts'"/git/bisect "yarn nx test package-name --testPathPattern='test.test.ts'"