It's now pretty easy to add a custom command. Let's have an example to
show how to do it, and to protect against regressions.
It would be nice to also have some tests of the custom command, to
check that the command works, that other commands can be run, and that
`jj debug completion` includes the custom command. I'm not sure how to
do that, however.
This commit moves much of the `commands` module that isn't specific to
a particular command into a new `cli_util`.
Much of this is actually not even CLI-specific, so we should move that
further down into the library, but that can come later. That includes
the code in `WorkspaceCommandHelper` for snapshotting the working copy
and automatically importing/exporting to a colocated Git working copy.
I'm trying to make it easier to create a custom `jj` binary with
custom commands, without having to replace the `Args` type we parse
arguments into. For that to work, we need to resolve aliases using the
`clap::Command` type instead.
Now that open commits are disabled by default, seeing `close` and
`open` in `jj help` is confusing.
I'm a little ambivalent about hiding `jj commit` because it's useful
as a way of adding a description and starting a new change with a
single command. We can always add a new command for that if we want
to.
This moves the logic for handling the root commit when writing commits
from `CommitBuilder` into the individual backends. It always bothered
me a bit that the `commit::Commit` wrapper had a different idea of the
number of parents than the wrapped `backend::Commit` had.
With this change, the `LocalBackend` will now write the root commit in
the list of parents if it's there in the argument to
`write_commit()`. Note that root commit itself won't be written. The
main argument for not writing it is that we can then keep the fake
all-zeros hash for it. One argument for writing it, if we were to do
so, is that it would make the set of written objects consistent, so
any future processing of them (such as GC) doesn't have to know to
ignore the root commit in the list of parents.
We still treat the two backends the same, so the user won't be allowed
to create merges including the root commit even when using the
`LocalBackend`.
I had made the backends unaware of the virtual root commit because
they don't need to know about it, and we could avoid some duplicated
code by putting that in `Store` instead. However, as we saw in
b21a123bc8, the root commit being virtual has some user-visible
effects (they can't create a merge with the root and some other
commit). So I'm thinking that we may want to make the root commit an
actual commit, depending on which backend is used. Specificially, when
using the Git backend, we cannot record the root commit as an actual
parent since Git would fail when trying to look it up. Backends that
don't need compatibility can make the root commit an actual commit,
however.
This commit therefore makes the backends aware of the root commit. It
makes it remain a virtual commit in the Git backend, and makes it an
actual commit in the `LocalBackend`.
This commit breaks any existing repos using the `LocalBackend`, but
there shouldn't be any such repos other than for testing.
I feel the original -------/+++++++ pair is slightly confusing because
each half can be a separator by itself. I don't know what character other
than '-'/'+' is preferred, but let's pick '%' (for "mod") per @martinvonz
suggestion.
As pointed out by IntelliJ (maybe it came from rust-analyzer or
something, I don't know). I also lifted out
`Err(CommandError::UserError())` and extracted a variable.
Commands that take both paths and revisions as arguments take paths as
positional arguments and use `-r` for revisions (or more specific
options like `--from` and `--to`). It's therefore natural for the user
to think that they can run e.g. `jj describe -r abc123`. However,
since `jj describe` doesn't accept paths, it doesn't have a `-r`
argument either. Let's allow the user to specify a superfluous `-r`
that we just ignore.
This handling means that the user could run `jj show -r` (without a
revision argument) and it would use the default revision. That's
confusing, but at least we won't accept e.g. `jj show -r README.md`
(unless `README.md` is a revision), so it's probably okay?
`wc_commit` seems clearer than `checkout` and not too much longer. I
considered `working_copy` but it was less clear (could be the path to
the working copy, or an instance of `WorkingCopy`). I also considered
`working_copy_commit`, but that seems a bit too long.
I had missed that `Ui::write_commit_summary()` still shows open
commits in green even when open commits are disabled (as they are by
default these days). This patch fixes that.
The user can still override templates to format open commits
differently, but I'm not sure it's worth fixing that.
In the current implementation, tree is diffed twice if both PATH and -p
are specified. If this adds significant cost, we'll need to reimplement
it without using a revset abstraction (or maybe adjust revset/graph API.)
This will be a basic building block of 'jj log PATH'. The implementation
is naive, but works fine for small repos like jj. For mid-size repos,
there would be various areas which need to be optimized.
Fixes two pedantic issues with this paragraph:
* "either" describing more than two things
* I am not an expert, but I suspect that Pijul
supports "automatic rebase".
Previously, using `rebase -r` on the parent of a merge commit
turned it into a non-merge commit. In other words, starting
with
```
o d
|\
o | c
o | b
| o a
|/
o
```
and doing `rebase -r c -d a` resulted in
```
o d
o b
| o c
| o a
|/
o
```
where `d` is no longer a merge commit.
For reference, here's a complete test that passed before this commit (but should NOT pass; see the diff for a test that should pass):
```
#[test]
fn test_rebase_single_revision_merge_parent() {
let test_env = TestEnvironment::default();
test_env.jj_cmd_success(test_env.env_root(), &["init", "repo", "--git"]);
let repo_path = test_env.env_root().join("repo");
create_commit(&test_env, &repo_path, "a", &[]);
create_commit(&test_env, &repo_path, "b", &[]);
create_commit(&test_env, &repo_path, "c", &["b"]);
create_commit(&test_env, &repo_path, "d", &["a", "c"]);
// Test the setup
insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###"
@
o d
|\
o | c
o | b
| o a
|/
o
"###);
let stdout = test_env.jj_cmd_success(&repo_path, &["rebase", "-r", "c", "-d", "a"]);
insta::assert_snapshot!(stdout, @r###"
Also rebased 2 descendant commits onto parent of rebased commit
Working copy now at: 3e176b54d680 (no description set)
Added 0 files, modified 0 files, removed 2 files
"###);
insta::assert_snapshot!(get_log_output(&test_env, &repo_path), @r###"
@
o d
| o c
o | b
| o a
|/
o
"###);
}
```
The workflow that was supposed to enable auto-merge for PRs from
Dependabot is failing like this:
```
Message: Resource not accessible by integration, Locations: [{Line:1 Column:72}]
```
I can't figure out why it's failing (maybe
https://github.com/cli/cli/issues/1314?), so let's just remove it.