jj-ryu
Stacked PRs for Jujutsu. Push bookmark stacks to GitHub and GitLab as chained pull requests.
What it does
trunk() PR #1: feat-a → main
│ PR #2: feat-b → feat-a
○ feat-a ──────────────────► PR #3: feat-c → feat-b
│
○ feat-b
│
○ feat-c
Each bookmark becomes a PR. Each PR targets the previous bookmark (or trunk). When you update your stack, ryu updates the PRs.
Install
# npm (includes prebuilt binaries)
# or with npx
# cargo
Binary name is ryu.
macOS: If you see "ryu can't be opened", run:
Quick start
# View your bookmark stacks
# Submit a stack as PRs
# Preview what would happen
# Sync all stacks
Usage
Visualize stacks
Running ryu with no arguments shows your bookmark stacks:
$ ryu
Bookmark Stacks
===============
Stack #1: feat-c
trunk()
│
○ kpqvunts 7d3a1b2c Add user authentication
│ └─ [feat-a] ✓
│
○ mzwwxrlq a1b2c3d4 Add session management
│ └─ [feat-b] ↑
│
@ yskvutnz e5f6a7b8 Add logout endpoint
│ └─ [feat-c]
1 stack, 3 bookmarks
Legend: ✓ = synced with remote, ↑ = needs push, @ = working copy
To submit a stack: ryu submit <bookmark>
Submit a stack
This will:
- Push all bookmarks in the stack to remote
- Create PRs for bookmarks without one
- Update PR base branches if needed
- Add stack navigation comments to each PR
Output:
Submitting 3 bookmarks in stack:
- feat-a (synced)
- feat-b
- feat-c
Pushing bookmarks...
- feat-a already synced
✓ Pushed feat-b
✓ Pushed feat-c
Creating PRs...
✓ Created PR #12 for feat-b
https://github.com/you/repo/pull/12
✓ Created PR #13 for feat-c
https://github.com/you/repo/pull/13
Updating stack comments...
Done!
Successfully submitted 3 bookmarks
Created 2 PRs
Stack comments
Each PR gets a comment showing the full stack:
This PR is part of a stack of 3 bookmarks:
1. `trunk()`
1. [feat-a](https://github.com/you/repo/pull/11)
1. **feat-b ← this PR**
1. [feat-c](https://github.com/you/repo/pull/13)
Comments update automatically when you re-submit.
Dry run
Preview without making changes:
Sync all stacks
Push all stacks to remote and update PRs:
Authentication
GitHub
Uses (in order):
gh auth token(GitHub CLI)GITHUB_TOKENenv varGH_TOKENenv var
For GitHub Enterprise, set GH_HOST:
GitLab
Uses (in order):
glab auth token(GitLab CLI)GITLAB_TOKENenv varGL_TOKENenv var
For self-hosted GitLab, set GITLAB_HOST:
Test authentication
Workflow example
# Start a feature
# Work on it
# Stack another change on top
# View the stack
# Submit both as PRs (feat-session → feat-auth → main)
# Make changes, then update PRs
# After feat-auth merges, rebase and re-submit
Limitations
- Bookmarks with merge commits in their history are excluded
- Linear stacks only (no diamond-shaped dependencies)
- One remote per operation
CLI reference
ryu [OPTIONS] [COMMAND]
Commands:
submit Submit a bookmark stack as PRs
sync Sync all stacks with remote
auth Authentication management
Options:
-p, --path <PATH> Path to jj repository
-V, --version Print version
-h, --help Print help
submit
ryu submit <BOOKMARK> [OPTIONS]
Arguments:
<BOOKMARK> Bookmark to submit
Options:
--dry-run Preview without making changes
--remote <REMOTE> Git remote to use (default: origin)
sync
ryu sync [OPTIONS]
Options:
--dry-run Preview without making changes
--remote <REMOTE> Git remote to use (default: origin)
auth
ryu auth github test # Test GitHub auth
ryu auth github setup # Show setup instructions
ryu auth gitlab test # Test GitLab auth
ryu auth gitlab setup # Show setup instructions
License
MIT