From a30df323bdb6286504697bf014a3b100ad999be5 Mon Sep 17 00:00:00 2001 From: Ilya Grigoriev Date: Mon, 8 Apr 2024 14:18:58 -0700 Subject: [PATCH] `jj git push` docs: document safety checks As discussed in https://discord.com/channels/968932220549103686/1226363798483636265/1226415448615288864 --- cli/src/commands/git.rs | 12 ++++++++++ cli/tests/cli-reference@.md.snap | 6 +++++ docs/branches.md | 38 ++++++++++++++++++++++++++++++++ 3 files changed, 56 insertions(+) diff --git a/cli/src/commands/git.rs b/cli/src/commands/git.rs index 994868fbf..7c4672b4d 100644 --- a/cli/src/commands/git.rs +++ b/cli/src/commands/git.rs @@ -189,6 +189,18 @@ pub struct GitCloneArgs { /// `remote_branches(remote=)..@`. Use `--branch` to push specific /// branches. Use `--all` to push all branches. Use `--change` to generate /// branch names based on the change IDs of specific commits. +/// +/// Before the command actually moves, creates, or deletes a remote branch, it +/// makes several [safety checks]. If there is a problem, you may need to run +/// `jj git fetch --remote ` and/or resolve some [branch +/// conflicts]. +/// +/// [safety checks]: +/// https://martinvonz.github.io/jj/latest/branches/#pushing-branches-safety-checks +/// +/// [branch conflicts]: +/// https://martinvonz.github.io/jj/latest/branches/#conflicts + #[derive(clap::Args, Clone, Debug)] #[command(group(ArgGroup::new("specific").args(&["branch", "change", "revisions"]).multiple(true)))] #[command(group(ArgGroup::new("what").args(&["all", "deleted", "tracked"]).conflicts_with("specific")))] diff --git a/cli/tests/cli-reference@.md.snap b/cli/tests/cli-reference@.md.snap index c74cbbfa5..e4390d2f6 100644 --- a/cli/tests/cli-reference@.md.snap +++ b/cli/tests/cli-reference@.md.snap @@ -914,6 +914,12 @@ Push to a Git remote By default, pushes any branches pointing to `remote_branches(remote=)..@`. Use `--branch` to push specific branches. Use `--all` to push all branches. Use `--change` to generate branch names based on the change IDs of specific commits. +Before the command actually moves, creates, or deletes a remote branch, it makes several [safety checks]. If there is a problem, you may need to run `jj git fetch --remote ` and/or resolve some [branch conflicts]. + +[safety checks]: https://martinvonz.github.io/jj/latest/branches/#pushing-branches-safety-checks + +[branch conflicts]: https://martinvonz.github.io/jj/latest/branches/#conflicts + **Usage:** `jj git push [OPTIONS]` ###### **Options:** diff --git a/docs/branches.md b/docs/branches.md index ce38cc0ed..6e7754668 100644 --- a/docs/branches.md +++ b/docs/branches.md @@ -152,6 +152,44 @@ met: You could describe the movement as following along the change-id of the current branch commit, even if it isn't entirely accurate. +## Pushing branches: Safety checks + +Before `jj git push` actually moves, creates, or deletes a remote branch, it +makes several safety checks. + +1. `jj` will contact the remote and check that the actual state of the remote + branch matches `jj`'s record of its last known position. If there is a + conflict, `jj` will refuse to push the branch. In this case, you need to run + `jj git fetch --remote ` and resolve the resulting branch + conflict. Then, you can try `jj git push` again. + + If you are familiar with Git, this makes `jj git push` similar to `git + push --force-with-lease`. + + There are a few cases where `jj git push` will succeed even though the remote + branch is in an unexpected location. These are the cases where `jj git fetch` + would not create a branch conflict and would not move the local branch, e.g. + if the unexpected location is identical to the local position of the branch. + +2. The local branch must not be [conflicted](#conflicts). If it is, you would + need to use `jj branch set`, for example, to resolve the conflict. + + This makes `jj git push` safe even if `jj git fetch` is performed on a timer + in the background (this situation is a known issue[^known-issue] with some + forms of `git push --force-with-lease`). If the branch moves on a remote in a + problematic way, `jj git fetch` will create a conflict. This should ensure + that the user becomes aware of the conflict before they can `jj git push` and + override the branch on the remote. + +3. If the remote branch already exists on the remote, it must be + [tracked](#remotes-and-tracked-branches). If the branch does not already + exist on the remote, there is no problem; `jj git push` will create the + remote branch and mark it as tracked. + +[^known-issue]: See "A general note on safety" in + + + ## Conflicts Branches can end up in a conflicted state. When that happens, `jj status` will