Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

josh CLI

The josh command is the primary tool for working with filtered git repositories. It provides projection-aware equivalents of the common git operations.

Installation

cargo install josh-cli --locked --git https://github.com/josh-project/josh.git

josh clone

Clone a repository, optionally applying a filter projection.

josh clone <url> <filter> <out> [options]
ArgumentDescription
<url>Remote repository URL (HTTPS, SSH, or local path)
<filter>Filter spec to apply (e.g. :/docs, :workspace=workspaces/myproject)
<out>Local directory to clone into

Options:

FlagDescription
-b, --branch <ref>Branch or ref to clone (default: HEAD)
--forge <name>Forge integration to use (e.g. github)
--no-forgeDisable forge integration

Examples:

# Clone only the docs/ subdirectory
josh clone https://github.com/josh-project/josh.git :/docs ./josh-docs

# Clone a workspace projection
josh clone https://github.com/myorg/monorepo.git :workspace=workspaces/frontend ./frontend

# Clone the full repository (no filter)
josh clone https://github.com/josh-project/josh.git :/ ./josh

josh fetch

Fetch from a remote and update the filtered local refs. Equivalent to git fetch but filter-aware.

josh fetch [options]

Options:

FlagDescription
-r, --remote <name>Remote name or URL to fetch from (default: origin)
-R, --ref <ref>Ref to fetch (default: HEAD)

josh push

Push commits back to the upstream repository. Josh reverses the filter and reconstructs the correct upstream commits, so your changes land in the right place in the monorepo.

josh push [<remote>] [<refspecs>...] [options]
ArgumentDescription
<remote>Remote name to push to (default: origin)
<refspecs>Refs to push (default: current branch)

Options:

FlagDescription
-f, --forceForce-push (non-fast-forward)
--atomicAtomic push (all-or-nothing)
--dry-runShow what would be pushed without actually pushing

josh changes publish

Push each commit as an independent, minimal diff (stacked changes workflow). Each commit with a Change ID is pushed to its own ref and, when forge integration is configured, gets its own pull request.

The push uses git push --porcelain and prints a curated summary instead of git’s per-ref noise: a single published N changes (M new) line for the stacked-changes refs, with the internal @base/…/@heads/… refs hidden. Git’s stderr (progress, rejection details) is still forwarded verbatim. When a pull request is created or updated and stderr is a terminal, the PR #N reference is printed as a clickable hyperlink (OSC 8; supported by iTerm2, kitty, WezTerm and others).

josh changes publish [<remote>] [<refspecs>...] [options]
ArgumentDescription
<remote>Remote name to push to (default: origin)
<refspecs>Refs to push (default: current branch)

Options:

FlagDescription
-f, --forceForce-push (non-fast-forward)
--atomicAtomic push (all-or-nothing)
--dry-runShow what would be pushed without actually pushing

josh changes pull

Fetch and integrate changes from a remote (stacked changes workflow). Like git pull --rebase --autostash, but filter-aware and change-aware.

The fetch uses git fetch --porcelain (requires git >= 2.41) and prints a curated summary instead of git’s per-ref noise: one line per updated branch, plus a change count for stacked-changes refs (@changes/…). A republished change only counts as updated when its content actually changed — compared via git patch-id --stable — so restacking without edits does not inflate the count.

Integration is rebase-style and linear-only:

  • If the local branch can be fast-forwarded, it is fast-forwarded.
  • Local commits whose Change-Id trailer already appears in the updated upstream history (e.g. landed by a merge queue) are skipped; the remaining changes are restacked (cherry-picked) on top of the upstream tip.
  • Uncommitted changes are stashed before integrating and re-applied afterwards (autostash).
  • Anything more complex — merge commits in the local stack, diverged commits without a Change-Id, or restack conflicts — fails with an error and leaves the branch untouched.
josh changes pull [options]

Options:

FlagDescription
-r, --remote <name>Remote name or URL to pull from (default: origin)
-R, --ref <ref>Ref to pull (default: HEAD)

josh remote

Manage josh-aware remotes.

Note: josh remote add can be used in any existing git repository, not only ones originally cloned with josh clone. This is the standard way to add josh filtering to a repository you already have checked out.

josh remote add

Add a remote with an associated filter projection.

josh remote add <name> <url> <filter> [options]
ArgumentDescription
<name>Remote name
<url>Remote repository URL
<filter>Filter spec to associate with this remote

Options:

FlagDescription
--forge <name>Forge integration (e.g. github)
--no-forgeDisable forge integration

Example:

# Add a second remote scoped to the backend/ subdirectory
josh remote add backend https://github.com/myorg/monorepo.git :/services/backend

The filter may carry semantic meta args, e.g. :~(history="keep-trivial-merges")[:/services/backend]; they are applied whenever the remote’s filter is used (fetch, push, cache). The meta keys url, fetch and forge are reserved: the remote config stores its transport settings under these keys, so josh remote add rejects a filter that sets one of them.


josh filter

Re-apply the filter for an existing remote to update the local filtered refs. Useful after manually modifying the filter configuration without fetching.

josh filter <remote>
ArgumentDescription
<remote>Remote name whose filter should be re-applied

josh auth

Manage authentication credentials for forge integrations. Forge integration is optional and used for automatic pull request management — see Forge integration for details.

josh auth login <forge>
josh auth logout <forge>

The only currently supported forge is github. See Forge integration for full documentation.


josh cache

Manage the distributed filter cache. The distributed cache stores filter results inside a ref in the git repository, allowing a warm cache to be shared between machines via ordinary git push/fetch.

The cache subcommand requires a josh remote to be configured (see josh remote add).

josh cache build

Apply the configured filter to all already-fetched refs and populate the local distributed cache with the results.

josh cache build [remote]
ArgumentDescription
[remote]Remote name to build cache for (default: origin)

Run this before josh cache push to ensure the cache is up to date.

josh cache push

Push the local distributed cache and the filtered refs to the backing remote, so that other machines can fetch them.

josh cache push [remote]
ArgumentDescription
[remote]Remote name to push cache to (default: origin)

josh cache fetch

Fetch the distributed cache and filtered refs from the remote, warming the local cache without re-computing filters from scratch.

josh cache fetch [remote]
ArgumentDescription
[remote]Remote name to fetch cache from (default: origin)

Typical workflow:

# On the machine that computes the cache (e.g. CI):
josh cache build
josh cache push

# On another machine (e.g. a developer workstation):
josh cache fetch
# subsequent josh fetch / clone operations use the pre-built cache

Note: The distributed cache is currently only available through the josh CLI. It is not yet supported by josh-proxy.


josh compose run

Experimental: requires JOSH_EXPERIMENTAL_FEATURES=1.

Run a workspace in an isolated, automatically-cached container. See josh compose run for full documentation.

josh compose run [OPTIONS] [REFERENCE] [FILTER]
ArgumentDescription
[REFERENCE]Git ref to build from: . (working tree), + (index), HEAD, or any ref (default: .)
[FILTER]Filter selecting the workspace to run (default: :+compose, reads compose.josh in the repo root)

Options:

FlagDescription
--cleanRemove cached images and output volumes
--clean-allRemove cached images, output volumes, and persistent cache volumes

Examples:

# Run the default workspace defined in compose.josh
josh compose run

# Run the test workspace against the working tree
josh compose run . :+ws/test

# Run using only staged changes
josh compose run + :+ws/test

josh-filter (standalone binary)

josh-filter is a lower-level command that rewrites git history using Josh filter specs. It is intended for scripting and one-off history rewriting tasks rather than day-to-day development workflows.

Input: the second positional argument selects what to filter. It defaults to HEAD but can be any of:

  • . - the working tree (including uncommitted changes)
  • + - the index (staged changes only)
  • A full or abbreviated commit SHA
  • A ref name (e.g. main, refs/heads/feature)

Output: the filtered commit SHA is printed to stdout. The filtered history is also written to the ref given by --update (default: FILTERED_HEAD).

Basic usage:

# Filter HEAD through :/docs and write result to FILTERED_HEAD
josh-filter :/docs

# Filter the working tree and print the resulting SHA
josh-filter :/docs .

# Filter a specific commit SHA
josh-filter :/docs abc1234 --update refs/my/filtered

Options:

FlagDescription
--update <ref>Ref to update with the filtered result (default: FILTERED_HEAD)
--file <path>Read filter spec from a file
--squash-pattern <pattern>Squash commits matching the pattern
--squash-file <path>Read squash patterns from a file
--singleProduce a single squashed commit
-dDiscovery mode: populate cache with probable filters
-tOutput Chrome tracing data
-pPrint the filter spec (and exit)
-iPrint the filter ID (and exit)
-sPrint cache statistics
-nSkip loading the cache
--distributed-cacheEnable the distributed cache backend
--reverseReverse-apply the filter (unapply): reconstruct upstream commits from filtered ones
--check-roundtripWhen used with --reverse, verify that applying the filter to the reverse result reproduces the original commit. Exits with code 1 if the check fails.