diff --git a/src/commands.rs b/src/commands.rs index cdd123d6f..62474a5d3 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -1041,7 +1041,8 @@ fn get_app<'a, 'b>() -> App<'a, 'b> { .alias("working_copy") .alias("workingcopy") .about("Show help about the working copy"), - ); + ) + .subcommand(SubCommand::with_name("operations").about("Show help about operations")); let help_message = "Print help information"; let mut app = App::new("Jujutsu") .global_setting(clap::AppSettings::ColoredHelp) @@ -3171,6 +3172,63 @@ You probably don't want build outputs and temporary files to be under version co or equivalent way (maybe `.jj/gitignore`) of specifying per-clone ignores is not \ yet supported.", )); + } else if sub_matches.is_present("operations") { + sections.push(( + "INTRODUCTION:", + "\ +Jujutsu records each operation that modifies the repo in the \"operation log\". You can see the \ + log with `jj op log`. Each operation object contains a snapshot of how the repo \ + looked at the end of the operation. We call this snapshot a \"view\" object. The \ + view contains information about where each branch, tag, and Git ref (in Git-backed \ + repos) pointed, as well as the set of heads in the repo, and the current checkout. \ + The operation object also (in addition to the view) contains pointers to the \ + operation(s) immediately before it, as well as metadata about the operation, such as \ + timestamps, username, hostname, description. + +The operation log allows you to undo an operation (`jj op undo`), which doesn't need to be the \ + most recent one. It also lets you restore the entire repo to the way it looked at an \ + earlier point (`jj op restore`).", + )); + sections.push(( + "CONCURRENT OPERATIONS:", + "\ +One benefit of the operation log (and the reason for its creation) is that it allows lock-free \ + concurrency -- you can run concurrent `jj` commands without corrupting the repo, \ + even if you run the commands on different machines that access the repo via a \ + distributed file system (as long as the file system guarantees that a write is only \ + visible once previous writes are visible). When you run a `jj` command, it will \ + start by loading the repo at the latest operation. It will not see any changes \ + written by concurrent commands. If there are conflicts, you will be informed of them \ + by subsequent `jj st` and/or `jj log` commands. + +As an example, let's say you had started editing the description of a change and then also update \ + the contents of the change (maybe because you had forgotten the editor). When you \ + eventually close your editor, the command will succeed and e.g. `jj log` will \ + indicate that the change has diverged (`jj evolve` will automatically resolve the \ + divergence).", + )); + sections.push(( + "LOADING AN OLD VERSION OF REPO:", + "\ +The top-level `--at-operation/--at-top` option allows you load the repo at a specific operation. \ + This can be useful for understanding how your repo got into the current state. It \ + can be even more useful for understanding why someone else's repo got into its \ + current state. + +When you use `--at-op`, the automatic snapshotting of the working copy will not take place. When \ + referring to a revision with the `@` symbol (as many commands do by default), that \ + will resolve to the current checkout recorded in the operation's view (which is \ + actually how it always works -- it's just the snapshotting that's skipped with \ + `--at-op`). + +As a top-level option, `--at-op`, it can be passed to any command. However, you will typically \ + only want to run read-only commands. For example, `jj log`, `jj st`, and `jj diff` \ + all make sense. It's still possible to run e.g. `jj --at-op= \ + describe`. That's equivalent to having started `jj describe` back when the specified \ + operation was the most recent operation and then let it run until now (which can be \ + done for that particular command by not closing the editor). There's practically no \ + good reason to do that other than to simulate concurrent commands.", + )); } else { panic!("unhandled help concept: {:#?}", command.root_matches()); }