Skip to content

6. Targeting slices

Bare push and pull move everything bound. Real repositories rarely want that every time — this chapter narrows a transfer to one unit, one stage, one sample, or a plan you merely want to look at.

Units and --stage

Positional unit IDs (with --stage to say where they live) target exactly one slice:

forest push plot-01 --stage raw
SKIP raw/plot-01  already synced to origin

Everything is still synced from chapter 5, so forest correctly does nothing — the targeting worked, there was just nothing to move.

Dry runs

--dry-run prints the transfer plan without moving a byte. Drop a draft file into plot 1 and ask what a push would do:

echo 'draft — do not sync' > data/raw/plot-01/scratch-notes.txt
forest push plot-01 --stage raw --dry-run
PLAN raw/plot-01  3 files, 89 B -> origin

Ad-hoc excludes

--exclude drops files matching a glob — relative to each unit's directory — for this invocation only:

forest push plot-01 --stage raw --exclude 'scratch-*' --dry-run
PLAN raw/plot-01  2 files, 67 B -> origin

Back to 2 files: the draft is excluded. --exclude can repeat, and it composes with the always-on OS-junk skip list. Clean up the draft before moving on:

rm data/raw/plot-01/scratch-notes.txt

Manifest IDs: name the sample, not the unit

Units are storage-shaped (plot-01); your domain speaks in sample IDs. A manifest — a plain CSV committed next to your code — maps one to the other:

cat > samples.csv <<'EOF'
sample_id,raw_unit,processed_unit
S-001,plot-01,processed
S-002,plot-02,processed
EOF

Then tell the checkout about it by appending a manifest: section to .forest/checkouts/survey/forest.yaml:

.forest/checkouts/survey/forest.yaml (append)
manifest:
  file: samples.csv
  id_column: sample_id
  stage_columns:
    raw: raw_unit
    processed: processed_unit

id_column is the column holding your IDs; stage_columns maps each stage to the column naming that stage's unit.

The one hand-edit

Forest's onboarding never requires hand-written config — the manifest is the exception, an opt-in feature with no CLI command (yet). It lives in the shared forest.yaml, so the whole team gets it from git.

Now --id resolves a sample to its units across all mapped stages:

forest status --id S-001
synced:origin  raw/plot-01  73 B  pushed 2026-07-02 22:32
synced:origin  raw/plot-01  73 B  pulled 2026-07-02 22:32
synced:origin  processed/processed  44 B  pushed 2026-07-02 22:32
synced:origin  processed/processed  44 B  pulled 2026-07-02 22:32
forest push --id S-001
SKIP raw/plot-01  already synced to origin
SKIP processed/processed  already synced to origin

One sample ID → the raw plot and its processed output, never the unrelated plot-02. --id works on push, pull, status, and ls.

See the whole graph: forest flow

forest flow emits a Mermaid diagram of the active checkout — checkout, manifest, stages, remote — straight to stdout (dry-run only; it never touches the network):

forest flow
flowchart LR
    project["project: survey"]
    manifest["manifest: samples.csv"]
    sync_state[".forest/sync_state.json"]
    remote_origin["remote: origin<br/>/home/user/forest-remote"]
    stage_processed["stage: processed<br/>path: /home/user/field-notes/data/processed"]
    stage_raw["stage: raw<br/>path: /home/user/field-notes/data/raw"]
    manifest -->|sample_id| project
    project --> stage_processed
    manifest -->|processed_unit| stage_processed
    project --> stage_raw
    manifest -->|raw_unit| stage_raw

Paste that into any Markdown file that renders Mermaid — like this site:

flowchart LR
    project["project: survey"]
    manifest["manifest: samples.csv"]
    stage_processed["stage: processed"]
    stage_raw["stage: raw"]
    manifest -->|sample_id| project
    project --> stage_processed
    manifest -->|processed_unit| stage_processed
    project --> stage_raw
    manifest -->|raw_unit| stage_raw

forest flow --id S-001 expands one sample down to its units and resolved paths; --stage raw expands a single stage; --direction TD flips the layout and --output PATH writes to a file instead of stdout.

Recap: positional units + --stage for one slice; --dry-run to look before you leap; --exclude for unit-relative ad-hoc globs; a manifest CSV gives you domain IDs; flow draws the map.

Next: see all of this running in the wild — dogfood.