165 lines
6.6 KiB
Markdown
165 lines
6.6 KiB
Markdown
# Named Remotes and Multi-Remote Workflows
|
|
|
|
For pushing to a single remote (the common case), see `references/PUSH.md`. This file covers everything else: managing named remotes, selecting which remote to push to, tracking remote bookmarks, and the two canonical multi-remote setups.
|
|
|
|
## Named remotes
|
|
|
|
When a repo has more than one remote (e.g. `origin` = your fork, `upstream` = the canonical source), you select the target with `--remote <name>`.
|
|
|
|
```bash
|
|
jj git remote list # See all remotes and their URLs
|
|
jj git remote add upstream <url> # Add a second remote
|
|
jj git remote rename origin fork # Rename a remote
|
|
jj git remote set-url origin <new-url> # Change a remote's URL
|
|
jj git remote remove old-name # Remove a remote (and forget its bookmarks)
|
|
```
|
|
|
|
**Default remote selection**: when `--remote` is omitted, `jj git push` uses:
|
|
|
|
1. The `git.push` config setting (if set), or
|
|
2. The remote named `origin` (if multiple remotes exist), or
|
|
3. The single remote (if only one exists)
|
|
|
|
There is **no built-in option to push to multiple remotes in one command** — call `jj git push` once per remote.
|
|
|
|
### Pushing the same bookmark to two remotes
|
|
|
|
```bash
|
|
jj bookmark move my-feature --to @ # Move the bookmark to current change
|
|
jj git push -b my-feature --remote fork # Push to your fork
|
|
jj git push -b my-feature --remote upstream # Push to canonical (e.g. for a PR target branch)
|
|
```
|
|
|
|
### Setting a default remote
|
|
|
|
To avoid typing `--remote` repeatedly:
|
|
|
|
```bash
|
|
# Per-repo (writes to .jj/repo/config.toml)
|
|
jj config set --repo git.push fork
|
|
|
|
# Globally (writes to ~/.config/jj/config.toml)
|
|
jj config set --user git.push origin
|
|
```
|
|
|
|
### Tracking a remote bookmark
|
|
|
|
By default, when you `jj git fetch`, remote bookmarks appear as `<name>@<remote>` (e.g. `main@upstream`). To get a local bookmark that follows it:
|
|
|
|
```bash
|
|
jj bookmark track main@upstream # Track upstream/main as a local 'main'
|
|
jj bookmark track 'glob:release/*@upstream' # Track all upstream release branches
|
|
```
|
|
|
|
Once tracked, `jj git push --tracked --remote upstream` will push all tracked bookmarks back to that remote.
|
|
|
|
### Fetching from a specific remote
|
|
|
|
```bash
|
|
jj git fetch --remote upstream # Fetch only from upstream
|
|
jj git fetch --all-remotes # Fetch from every configured remote
|
|
```
|
|
|
|
### When a push is rejected
|
|
|
|
If the remote has moved since your last fetch, `jj git push` refuses (similar to `git push --force-with-lease`). Re-sync first:
|
|
|
|
```bash
|
|
jj git fetch --remote <name> # Pull the remote's current state
|
|
# (resolve any bookmark conflicts or rebase if needed)
|
|
jj git push -b <bookmark> --remote <name> # Try again
|
|
```
|
|
|
|
### Quick reference
|
|
|
|
| Action | Command |
|
|
|---|---|
|
|
| List remotes | `jj git remote list` |
|
|
| Add a remote | `jj git remote add <name> <url>` |
|
|
| Push to specific remote | `jj git push -b <bookmark> --remote <name>` |
|
|
| Push all tracked bookmarks to a remote | `jj git push --tracked --remote <name>` |
|
|
| Set default push remote (repo) | `jj config set --repo git.push <name>` |
|
|
| Track a remote bookmark | `jj bookmark track <name>@<remote>` |
|
|
| Fetch one remote | `jj git fetch --remote <name>` |
|
|
| Fetch all remotes | `jj git fetch --all-remotes` |
|
|
|
|
## Common multi-remote workflows
|
|
|
|
Two canonical setups documented in [the jj docs](https://docs.jj-vcs.dev/latest/guides/multiple-remotes/). Pick the one that matches your relationship to the remotes; the config is one-time per repo.
|
|
|
|
**Nomenclature** (jj convention):
|
|
- `origin` = a remote you have write access to (typically where you push)
|
|
- `upstream` = the more canonical / well-known repo (you may not have push access)
|
|
- Trunk is assumed to be `main`, so remote bookmarks are `main@origin` and `main@upstream`
|
|
|
|
### Scenario 1: GitHub-style fork contributing upstream
|
|
|
|
`upstream` is the canonical project; `origin` is your fork; you open PRs from `origin` against `upstream`.
|
|
|
|
Typical actions:
|
|
- Fetch from `upstream` to get the latest changes
|
|
- Push `main` to `origin` to keep your fork's `main` in sync
|
|
- Push `my-feature` to `origin`, then open a PR targeting `upstream`
|
|
|
|
One-time setup:
|
|
|
|
```bash
|
|
# Fetch from both remotes when you run `jj git fetch`
|
|
jj config set --repo git.fetch '["upstream", "origin"]'
|
|
|
|
# Default push target is your fork
|
|
jj config set --repo git.push origin
|
|
|
|
# Track both remote bookmarks named `main`
|
|
jj bookmark track main
|
|
|
|
# Make upstream's main the trunk (treated as immutable; rebases stop here)
|
|
jj config set --repo 'revset-aliases."trunk()"' main@upstream
|
|
```
|
|
|
|
Why these specifically:
|
|
- Tracking `main@upstream` keeps your local `main` updated whenever you fetch from upstream
|
|
- Tracking `main@origin` means `jj git push` will also update your fork's `main`
|
|
- `trunk() = main@upstream` prevents jj from rewriting commits that are already in the canonical repo
|
|
|
|
### Scenario 2: Independent repository, periodically integrating from upstream
|
|
|
|
`origin` is a long-lived repository with its own divergent history; `upstream` is the source you occasionally pull changes from but don't contribute back to.
|
|
|
|
Typical actions:
|
|
- Fetch from `origin` to get the latest of your own work
|
|
- Push bookmarks to `origin`; merge PRs into `main@origin`
|
|
- Periodically fetch from `main@upstream` and merge/rebase/duplicate its changes into `main@origin`
|
|
|
|
One-time setup:
|
|
|
|
```bash
|
|
# Fetch only from origin (typical case)
|
|
jj config set --repo git.fetch '["origin"]'
|
|
# Or fetch from both if you want upstream changes visible on every fetch:
|
|
# jj config set --repo git.fetch '["upstream", "origin"]'
|
|
|
|
# Default push target is origin
|
|
jj config set --repo git.push origin
|
|
|
|
# Track only origin's main — do NOT track upstream's main
|
|
jj bookmark track main --remote=origin
|
|
jj bookmark untrack main --remote=upstream
|
|
|
|
# Your origin defines the trunk (your main is the canonical line)
|
|
jj config set --repo 'revset-aliases."trunk()"' main@origin
|
|
```
|
|
|
|
Why these specifically:
|
|
- Tracking only `main@origin` keeps `main@upstream` as a clearly separate reference you can `rebase`/`merge` from intentionally — it won't silently overwrite your local `main`
|
|
- `trunk() = main@origin` treats your divergent line (not upstream's) as the immutable history boundary
|
|
|
|
### Choosing between the scenarios
|
|
|
|
| Question | Scenario 1 | Scenario 2 |
|
|
|---|---|---|
|
|
| Do you push features back to upstream as PRs? | Yes | No |
|
|
| Should fetching from upstream update your local `main`? | Yes | No (you integrate manually) |
|
|
| Is `upstream/main` immutable from your repo's perspective? | Yes | No (you may rewrite when integrating) |
|
|
| Is `origin/main` allowed to diverge from `upstream/main`? | Minimally (just for syncing) | Yes (it's the point) |
|