| name | buck2-target-determination |
| description | This skill should be used when determining which Buck2 targets are affected by code changes for incremental builds and tests. Use this when users ask to test/build changed code, find affected targets, or run incremental workflows with jj revisions. |
Buck2 Target Determination
Overview
Target determination identifies which Buck2 targets are affected by code changes between two jj revisions. This enables incremental workflows that only build/test what changed, dramatically reducing build times (often 10-100x faster than full builds).
When to Use This Skill
Use this skill when:
- User wants to "test what changed" or "test my changes"
- User asks to "build only affected targets"
- User requests "incremental build/test"
- Setting up CI/CD workflows that should only test affected code
- Analyzing impact of changes before committing
- User mentions
tdutil or target determination
How Target Determination Works
The tdutil tool:
- Accepts two single-commit jj revsets (e.g.,
'@-' and '@')
- Computes file changes between those revisions
- Builds Buck2 target graphs at both revisions
- Identifies targets whose BUILD files or sources changed
- Outputs sorted affected targets to stdout, or to a file with
--output
Critical: Always use the root// cell prefix with tdutil to avoid ambiguous cell references.
Basic Usage Pattern
TARGETS_FILE="$(mktemp "${TMPDIR:-/tmp}/tdutil-targets.XXXXXX")"
trap 'rm -f -- "$TARGETS_FILE"' EXIT
buck2 run root//buck/tools/tdutil:tdutil -- \
--output "$TARGETS_FILE" --universe depot//src/...
buck2 build "@$TARGETS_FILE"
buck2 test "@$TARGETS_FILE"
Why at-file syntax (@path)? Target lists can be extremely large (thousands of targets), exceeding command-line length limits. At-file syntax loads targets from a file. mktemp avoids collisions between concurrent workflows, and the trap removes the file when the shell exits.
Common Revset Patterns
Development Workflows
buck2 run root//buck/tools/tdutil:tdutil -- depot//src/...
buck2 run root//buck/tools/tdutil:tdutil -- \
--from 'trunk()' --to '@' --universe depot//src/...
buck2 run root//buck/tools/tdutil:tdutil -- \
--from '@---' --to '@' --universe depot//src/...
buck2 run root//buck/tools/tdutil:tdutil -- \
--from 'abc123' --to 'def456' --universe depot//src/...
CI/CD Workflows
buck2 run root//buck/tools/tdutil:tdutil -- --from 'trunk()' --to '@'
buck2 run root//buck/tools/tdutil:tdutil -- --from 'root()' --to '@'
Scope Limiting
buck2 run root//buck/tools/tdutil:tdutil -- depot//src/myproject/...
buck2 run root//buck/tools/tdutil:tdutil -- depot//src/... depot//tools/...
Complete Workflow Examples
Pre-Commit Testing
TARGETS_FILE="$(mktemp "${TMPDIR:-/tmp}/tdutil-targets.XXXXXX")"
trap 'rm -f -- "$TARGETS_FILE"' EXIT
jj new -m "feat: implement feature"
buck2 run root//buck/tools/tdutil:tdutil -- --output "$TARGETS_FILE" --universe depot//src/...
buck2 build "@$TARGETS_FILE"
buck2 test "@$TARGETS_FILE"
jj commit -m "feat: implement feature"
Impact Analysis
TARGETS_FILE="$(mktemp "${TMPDIR:-/tmp}/tdutil-targets.XXXXXX")"
trap 'rm -f -- "$TARGETS_FILE"' EXIT
buck2 run root//buck/tools/tdutil:tdutil -- --output "$TARGETS_FILE" --universe depot//src/...
wc -l "$TARGETS_FILE"
cat "$TARGETS_FILE"
buck2 query "kind('.*_test', %Ss)" "@$TARGETS_FILE"
buck2 query "kind('.*_binary', %Ss)" "@$TARGETS_FILE"
Helper Script Usage
Use scripts/tdutil_helper.py for simplified invocations:
python3 scripts/tdutil_helper.py
python3 scripts/tdutil_helper.py --pattern current
python3 scripts/tdutil_helper.py --pattern trunk
python3 scripts/tdutil_helper.py --pattern full
python3 scripts/tdutil_helper.py --from '@---' --to '@' --scope depot//src/myproject/...
python3 scripts/tdutil_helper.py --pattern current --build
python3 scripts/tdutil_helper.py --pattern current --test
python3 scripts/tdutil_helper.py --pattern trunk --build --test
The helper provides:
- Better error messages
- Target count and preview
- Optional auto-build/test
- Common pattern shortcuts
- Private temporary at-files that are retained when nonempty, with an explicit cleanup command
Troubleshooting
"No targets affected"
Possible causes:
- No files changed (check
jj diff)
- Changes only to files not in any BUILD target
- Scope too narrow (expand from
depot//src/myproject/... to depot//src/...)
- The working copy has not been snapshotted yet (check
jj status)
Solution:
jj diff
jj status
buck2 run root//buck/tools/tdutil:tdutil
"Could not find cell" error
The root// prefix is missing. Always use:
buck2 run root//buck/tools/tdutil:tdutil -- ...
buck2 run //buck/tools/tdutil:tdutil -- ...
Large target lists cause failures
Use at-file syntax (@filename) instead of passing targets directly:
TARGETS_FILE="$(mktemp "${TMPDIR:-/tmp}/tdutil-targets.XXXXXX")"
trap 'rm -f -- "$TARGETS_FILE"' EXIT
buck2 run root//buck/tools/tdutil:tdutil -- --output "$TARGETS_FILE" --universe depot//src/...
buck2 test "@$TARGETS_FILE"
buck2 test $(cat "$TARGETS_FILE")
Performance Benefits
Real-world example:
time buck2 test depot//src/...
TARGETS_FILE="$(mktemp "${TMPDIR:-/tmp}/tdutil-targets.XXXXXX")"
trap 'rm -f -- "$TARGETS_FILE"' EXIT
buck2 run root//buck/tools/tdutil:tdutil -- --output "$TARGETS_FILE" --universe depot//src/...
time buck2 test "@$TARGETS_FILE"
Best Practices
- Always use
root// prefix - Prevents cell reference errors
- Use at-file syntax - Required for large target lists
- Scope appropriately - Balance coverage vs speed
- Include working-copy changes - Leave snapshotting enabled when comparing to
@
- Reuse one temporary output - Keep
$TARGETS_FILE for multiple commands in the workflow
- Check target count -
wc -l "$TARGETS_FILE" to verify results
- Run quality tests separately -
depot//buck/tests/... aren't in tdutil scope
Resources
scripts/tdutil_helper.py
Python helper script that wraps tdutil with common patterns and better output formatting.
references/revset_patterns.md
Comprehensive guide to jj revset patterns for use with tdutil.