Migration guide
This page covers breaking changes introduced in recent releases and how to adapt to them.
josh pull moved to josh changes pull
Applies when upgrading from r26.07.28 to r26.08.28.
The top-level josh pull command has moved under josh changes. The new command requires Git
2.41 or newer, always integrates with rebase-style restacking and autostash, and no longer accepts
--rebase or --autostash.
How to migrate: Upgrade Git to 2.41 or newer, replace josh pull with
josh changes pull, and remove the --rebase and --autostash flags from scripts.
Pattern-filter construction is fallible
Applies when upgrading from r26.07.28 to r26.08.28.
Invalid globs now fail when a pattern filter is constructed rather than when it is first applied.
The Rust Filter::pattern API therefore returns an error result.
How to migrate: Update Rust callers to propagate or handle the result from
Filter::pattern(...), for example with Filter::pattern(pattern)?. Validate user-supplied
patterns at construction time instead of expecting application to report the error.
Malformed Git trees are preserved instead of normalized
Applies when upgrading from r26.07.28 to r26.08.28.
Filtering no longer sorts, deduplicates, or canonicalizes unchanged entries in fsck-invalid Git trees. Rebuilt filtered commits can consequently have different object IDs than earlier Josh versions when their source history contains malformed trees.
How to migrate: Run git fsck on source repositories that may contain malformed trees. If
external systems pin filtered commit IDs from such histories, regenerate those references with
the new Josh version or replace the malformed source trees with canonical commits.
josh publish renamed to josh changes publish
Applies when upgrading from r26.05.08 to r26.06.11.
The publish subcommand has moved under a new changes subcommand group, making room for
further changes-related subcommands alongside publish.
How to migrate: Update any scripts or CI invocations that call josh publish to use
josh changes publish instead. All arguments and flags are unchanged.
“stack” push mode removed; refs/split/... magic ref renamed to refs/publish/...
Applies when upgrading from r26.05.08 to r26.06.11.
The old “stack” push mode has been removed. The proxy’s publish magic ref has also been
renamed from refs/split/for/<branch> to refs/publish/for/<branch> so that the proxy and
the CLI use the same vocabulary.
How to migrate: If you were pushing to refs/split/for/<branch>, push to
refs/publish/for/<branch> instead. There is no replacement for the “stack” push mode; use
publish mode instead.
Requires: commit footer replaced by Change-Series:
Applies when upgrading from r26.05.08 to r26.06.11.
The downstack algorithm has been rewritten to use path intersection rather than diff
application. As part of that, the Requires: commit footer used to force ordering between
commits has been replaced with Change-Series:. Assign two or more commits to a named series
to keep them merged in order even when they touch disjoint files.
How to migrate: Replace any Requires: commit footers with Change-Series: <name>,
giving the series a stable name shared by all commits that must be merged in order.
Change footers only recognised in the trailing footer block
Applies when upgrading from r26.05.08 to r26.06.11.
Change:, Change-Id:, and Change-Series: lines are now only recognised when they appear
in the trailing block of trailers at the end of the commit message. A body line that happens
to start with one of those prefixes is no longer mis-parsed as a real trailer.
How to migrate: If a commit message body contains a line that begins with Change:,
Change-Id:, or Change-Series: outside the trailing footer block and you intended it as
a trailer, move it into the footer block at the very end of the message.
CRLF line endings in gpgsig headers preserved
Applies when upgrading from r24.10.04 to r26.04.19.
Josh previously accidentally normalized \r\n line endings to \n inside the
gpgsig header of commit objects. This was a bug — git treats gpgsig values as opaque
bytes, and the standard format uses \n throughout — and has been fixed. Josh now preserves
whichever line endings are present in the original commit.
What changed: If your upstream history contains commits with \r\n in their gpgsig
headers, the filtered commit hashes will differ from those produced by the old version.
How to restore the old behavior: Use the gpgsig="norm-lf" meta option if you need
to reproduce a history that was created with the old normalization:
:~(gpgsig="norm-lf")[:/your/filter]
See the gpgsig option for details.
Trivial merges removed by default
Applies when upgrading from r24.10.04 to r26.04.19.
Josh previously kept all merge commits in the filtered history, even when the filtered tree of a merge commit was identical to its first parent’s tree (a “trivial merge”). Trivial merges are now removed by default during history simplification.
What changed: Filtered histories produced by the same filter may differ from those produced by older versions of Josh if the upstream history contains trivial merges. The internal cache version has been bumped, so all results will be recomputed on the first run after upgrading.
How to restore the old behavior: Wrap your filter with the history="keep-trivial-merges"
meta option:
:~(history="keep-trivial-merges")[:/your/filter]
See Filter options for details.
:join filter removed
Applies when upgrading from r24.10.04 to r26.04.19.
The :join filter has been removed. It was a limited alternative to using --reverse/push
for reconstructing upstream history from a filtered view.
How to migrate: Use josh-filter --reverse or josh push to write changes back to
the upstream repository.
josh-ui (web UI) removed
Applies when upgrading from r24.10.04 to r26.04.19.
The /ui endpoint and the josh-ui component have been removed from the project.
How to migrate: There is no direct replacement. Remove any links or integrations that
pointed to the /ui endpoint.
:rev filter syntax changed; :from and :concat removed
Applies when upgrading from r24.10.04 to r26.04.19.
The :rev filter now requires an explicit match operator before each SHA, and the
zero-SHA shorthand for the default case has been replaced by _.
What changed:
The old syntax used a bare SHA for each entry:
:rev(sha0:filter0,sha1:filter1,0000000000000000000000000000000000000000:default_filter)
The new syntax requires an operator prefix and uses _ for the default case:
:rev(<=sha0:filter0,<=sha1:filter1,_:default_filter)
Available operators:
<=sha— matches the commit and all its ancestors (inclusive); equivalent to the old bare-SHA behavior<sha— matches only strict ancestors (excludes the named commit itself)==sha— matches only the exact commit
How to migrate :rev filters:
- Replace each bare
sha:filterentry with<=sha:filter - Replace
0000000000000000000000000000000000000000:filterwith_:filter
:from removed:
The :from(sha:filter) filter has been removed. It kept the original history up to and
including sha unchanged and applied filter to all later commits.
Equivalent :rev expression:
:rev(<=sha:/,_:filter)
:concat removed:
The :concat(sha:filter) filter has been removed. It was the internal building block of
:from and sometimes appeared in normalized filter output (e.g. from josh-filter -p).
Filters of the form filter:concat(sha:filter) are equivalent to :from(sha:filter) and
should be migrated to:
:rev(<=sha:/,_:filter)
Cache location changed
Applies when upgrading from r24.10.04 to r26.04.19.
The local sled cache is now stored at .git/josh/cache instead of .git/josh.
What changed: On the first run after upgrading, Josh will not find any existing cache entries and will recompute all filter results from scratch. This is a one-time cost.
No action required for most users - the cache will be rebuilt automatically. If you
have scripts or tooling that reference .git/josh directly (e.g. to delete or back up
the cache), update them to point to .git/josh/cache instead.