jj-ryu 0.0.1-alpha.11

Stacked PRs for Jujutsu with GitHub/GitLab support
Documentation
# jj-ryu

<img width="366" height="366" alt="image" src="https://github.com/user-attachments/assets/1691edfc-3b65-4f8d-b959-71ff21ff23e5" />

Stacked PRs for [Jujutsu](https://jj-vcs.github.io/jj/latest/). Push bookmark stacks to GitHub and GitLab as chained pull requests.

## What it does

```
       [feat-c]
    @  mzpwwxkq a1b2c3d4 Add logout       -->   PR #3: feat-c -> feat-b
    |
       [feat-b]
    o  yskvutnz e5f6a7b8 Add sessions     -->   PR #2: feat-b -> feat-a
    |
       [feat-a]
    o  kpqvunts 9d8c7b6a Add auth         -->   PR #1: feat-a -> main
    |
  trunk()
```

Each bookmark becomes a PR targeting the previous bookmark (or trunk). When you update your stack, `ryu` updates the PRs.

## Install

```sh
# npm (prebuilt binaries)
npm install -g jj-ryu

# cargo
cargo install jj-ryu
```

Binary name is `ryu`.

## Quick start

```sh
# View your current stack
ryu

# Track bookmarks for submission
ryu track --all

# Submit tracked bookmarks as PRs
ryu submit

# Sync stack with remote
ryu sync
```

## Authentication

### GitHub

Uses (in order):
1. `gh auth token` (GitHub CLI)
2. `GITHUB_TOKEN` env var
3. `GH_TOKEN` env var

For GitHub Enterprise: `export GH_HOST=github.mycompany.com`

### GitLab

Uses (in order):
1. `glab auth token` (GitLab CLI)
2. `GITLAB_TOKEN` env var
3. `GL_TOKEN` env var

For self-hosted: `export GITLAB_HOST=gitlab.mycompany.com`

### Test authentication

```sh
ryu auth github test
ryu auth gitlab test
```

## Usage

### Viewing your stack

Running `ryu` with no arguments shows the current stack (bookmarks between trunk and working copy):

```
$ ryu

Stack: feat-c

       [feat-c]
    @  yskvutnz e5f6a7b8 Add logout endpoint
    |
       [feat-b] ^
    o  mzwwxrlq a1b2c3d4 Add session management
    |
       [feat-a] *
    o  kpqvunts 7d3a1b2c Add user authentication
    |
  trunk()

3 bookmarks

Legend: * = synced, ^ = needs push, @ = working copy
```

### Tracking bookmarks

Before submitting, bookmarks must be tracked. This gives you control over which bookmarks become PRs:

```sh
# Interactive selection (opens multi-select picker)
ryu track

# Track specific bookmarks
ryu track feat-a feat-b

# Track all bookmarks in trunk()..@
ryu track --all

# Untrack a bookmark
ryu untrack feat-a
```

Tracking state is stored in `.jj/ryu/tracking.json` per workspace.

### Submitting

```sh
ryu submit
```

This pushes all tracked bookmarks in the current stack, creates PRs for any without one, updates PR base branches, and adds stack navigation comments. Untracked bookmarks are skipped with a warning.

Each PR gets a comment showing the full stack:

```
* #13
* **#12 👈**
* #11

---
This stack of pull requests is managed by jj-ryu.
```

### Syncing

```sh
ryu sync
```

This fetches from remote and syncs the current stack.

## Workflow example

```sh
# Start a feature
jj new main
jj bookmark create feat-auth

# Work on it
jj commit -m "Add user model"

# Stack another change on top
jj bookmark create feat-session
jj commit -m "Add session handling"

# View the stack
ryu

# Track bookmarks for submission
ryu track --all

# Submit both as PRs (feat-session -> feat-auth -> main)
ryu submit

# Make changes, then update PRs
jj commit -m "Address review feedback"
ryu submit

# After feat-auth merges, rebase and re-submit
jj rebase -d main
ryu submit
```

## Advanced options

### Preview and confirmation

```sh
ryu submit feat-c --dry-run    # Preview without making changes
ryu submit feat-c --confirm    # Preview and prompt before executing
```

### Controlling submission scope

```sh
# Submit only up to a specific bookmark (excludes descendants)
ryu submit feat-c --upto feat-b

# Submit only one bookmark (parent must already have a PR)
ryu submit feat-b --only

# Include all descendants in submission
ryu submit feat-a --stack

# Only update existing PRs, don't create new ones
ryu submit feat-c --update-only

# Interactively select which bookmarks to submit
ryu submit feat-c --select
```

### Draft PRs

```sh
# Create new PRs as drafts
ryu submit feat-c --draft

# Publish draft PRs (mark as ready for review)
ryu submit feat-c --publish
```

## CLI reference

```
ryu [OPTIONS] [COMMAND]

Commands:
  submit   Submit tracked bookmarks as PRs
  track    Track bookmarks for submission
  untrack  Stop tracking bookmarks
  sync     Sync all stacks with remote
  auth     Authentication management

Options:
  -p, --path <PATH>  Path to jj repository
  -h, --help         Print help
  -V, --version      Print version
```

### submit

```
ryu submit [OPTIONS]

Options:
      --dry-run          Preview without making changes
  -c, --confirm          Preview and prompt for confirmation
      --upto <BOOKMARK>  Submit only up to this bookmark
      --only <BOOKMARK>  Submit only this bookmark (parent must have PR)
      --update-only      Only update existing PRs
  -s, --stack            Include all descendants in submission
      --draft            Create new PRs as drafts
      --publish          Publish draft PRs
  -i, --select           Interactively select bookmarks
      --remote <REMOTE>  Git remote (default: origin)
```

### track

```
ryu track [BOOKMARKS]... [OPTIONS]

Options:
  -a, --all              Track all bookmarks in trunk()..@
  -f, --force            Re-track already-tracked bookmarks
      --remote <REMOTE>  Associate with specific remote
```

### untrack

```
ryu untrack <BOOKMARKS>...

Options:
  -a, --all              Untrack all bookmarks
```

### sync

```
ryu sync [OPTIONS]

Options:
      --dry-run          Preview without making changes
  -c, --confirm          Preview and prompt for confirmation
      --stack <BOOKMARK> Only sync this stack
      --remote <REMOTE>  Git remote (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
```

## Coming from Graphite?

Ryu's CLI is inspired by Graphite. Here's how commands map:

| Graphite | Ryu |
|----------|-----|
| `gt track` | `ryu track` |
| `gt submit` | `ryu submit` |
| `gt submit --stack` | `ryu submit --stack` |
| `gt submit --only` | `ryu submit --only <bookmark>` |
| `gt submit --draft` | `ryu submit --draft` |
| `gt submit --publish` | `ryu submit --publish` |
| `gt submit --confirm` | `ryu submit --confirm` |
| `gt sync` | `ryu sync` |
| `gt branch create` | `jj bookmark create` |
| `gt restack` | `jj rebase` |

Key differences:
- Ryu requires explicit tracking before submit (`ryu track`)
- Stack management uses jj commands (`jj bookmark`, `jj rebase`), not ryu
- `ryu sync --stack <bookmark>` syncs a single stack (Graphite syncs all)

## License

MIT