We'll probably add binary comparison operators at some point, but this patch
also adds size_hint.zero() method. Otherwise, we'll have to write
"if(x.upper() && x.upper() == 0, ..)" to deal with None.
The resulting "branch list" template will look like:
```
separate(", ",
if(!ref.tracking_ahead_count().zero(),
if(ref.tracking_ahead_count().exact(),
"ahead by " ++ ref.tracking_ahead_count().exact() ++ " commits",
"ahead by at least " ++ ref.tracking_ahead_count().lower() ++ " commits")),
if(!ref.tracking_behind_count().zero(),
if(ref.tracking_behind_count().exact(),
"behind by " ++ ref.tracking_behind_count().exact() ++ " commits",
"behind by at least " ++ ref.tracking_behind_count().lower() ++ " commits")),
)
```
In order to port "branch list" to template, we need to somehow represent
revset.count_estimate() result as a template property. I'm going to add
SizeHint template type for that, and its .upper() and .exact() methods will
have to return optional integers.
Fortunately, the Integer type has no implicit conversion to bool, so
"if(optional_integer, ..)" is not ambiguous.
This is a remainder of the previous refactoring series. into_template() could be
implemented as a non-extension method, which allows us to get rid of .clone()
from Literal property extraction. However, there wasn't measurable difference.
Let's not try to overly optimize things. It's probably simpler to switch to
Rc<str> if .clone() really matters.
This is instead of https://github.com/martinvonz/jj/pull/3292, which would make
`diffedit3` built into `jj`. I still have some hope of eventually making
`diffedit3` into the default diff editor that is available without any
configuration, which probably requires building it into `jj`, but this may not
happen, and it wouldn't hurt to test `diffedit3` first. Some examples of
concerns (see also the discussion in that PR):
- It is only a guess on my part that this would make a good default. The editor
might not be polished enough, and most users are not used to 3-pane diff
editing. I think most users would like it if they tried it, but this might be
plain wrong.
- There are concerns about adding a heavyweight dependency on `jj`. While I
tried to make it as lightweight as possible, it still unavoidably includes a web
server.
- There may be ways to bundle `diffedit3` with `jj` without combining them in a
single binary.
For example,
```
<<<<<<< Conflict 1 of 3
+++++++ Contents of side #1
left 3.1
left 3.2
left 3.3
%%%%%%% Changes from base to side #2
-line 3
+right 3.1
>>>>>>>
```
or
```
<<<<<<< Conflict 1 of 1
%%%%%%% Changes from base to side #1
-line 3
+right 3.1
+++++++ Contents of side #2
left 3.1
left 3.2
left 3.3
>>>>>>>
```
Currently, there is no way to disable these, this is TODO for a future
PR. Other TODOs for future PRs: make these labels configurable. After
that, we could support a `diff3/git`-like conflict format as well, in
principle.
Counting conflicts helps with knowing whether you fixed all the
conflicts while you are in the editor.
While labeling "side #1", etc, does not tell you the commit id or
description as requested in #1176, I still think it's an improvement.
Most importantly, I hope this will make `jj`'s conflict format less
scary-looking for new users.
I've used this for a bit, and I like it. Without the labels, I would see
that the two conflicts have a different order of conflict markers, but I
wouldn't be able to remember what that means. For longer diffs, it can
be tricky for me to quickly tell that it's a diff as opposed to one of
the sides. This also creates some hope of being able to navigate a
conflict with more than 2 sides.
Another not-so-secret goal for this is explained in
https://github.com/martinvonz/jj/pull/3109#issuecomment-2014140627. The
idea is a little weird, but I *think* it could be helpful, and I'd like
to experiment with it.
I've heard of one instance of a person being confused by the error.
Previously, the error was:
```
Error: Failed to load tool configuration
Caused by: To use `diffedit3` as a merge tool, the config `merge-tools.diffedit3.merge-args` must be defined (see docs for details)
```
Now, it is:
```
Error: The tool `diffedit3` cannot be used as a merge tool with `jj resolve`.
Hint: To use `diffedit3` as a merge tool, the config `merge-tools.diffedit3.merge-args` must be defined (see docs for details)
```
TODO for future PR: allow setting `merge-tools.TOOL.edit-args = false` so that
attempting to use TOOL as a diff editor fails. This would be helpful, for
example, for the `vscode` tool.
I considered adding RefTarget template type, but some of the methods naturally
fit to RefName. For example, a conflicted branch name is decorated as "??", so
it makes sense to add branch.conflict() instead of branch.target().conflict().
I'm not pretty sure how many RefName methods we'll need to add to port the
current branch listing, but there will be .tracked(), .tracking_local_present(),
.ahead_by(), and .behind_by().
I'm going to add more detailed output there. This is a step towards "branch
list" template. "tag list -T" wouldn't be that useful, but it shares primitives
with "branch list -T".
I'm going to add ref_name.target*() template methods so the commit templater
can be reused for branches/tags templates. RefTarget could be looked up by
(name, kind) pair, but it's simpler to store it in RefName.
Before this patch, we would abandon the source commit if it became
empty after applying the reverse diff. This changes that condition to
the equivalent condition of the selected tree being the source
commit's original tree. This will help us rewrite the code to use
`transform_descendants()`.
The `move_commits` function accepts a set of target commits to shift to
a new location given by `new_parents` and `new_children`. The roots of
the target set will be reparented onto `new_parents`. `new_children`
will then be reparented onto the heads of the target set.
The commits will be rebased in reverse topological order based on the
new set of parents of each commit, which avoids the need for multiple
sets of rebase operations.
Spotted while experimenting with "jj tag list -T". The description_placeholder
alias could be changed to function taking a Commit object, but I feel it's odd.
Conceptually, the placeholder could also be used in "op log" templates.
Since fileset/revset/template expressions are specified as command-line
arguments, it's sometimes convenient to use single quotes instead of double
quotes. Various scripting languages parse single-quoted strings in various ways,
but I choose the TOML rule because it's simple and practically useful. TOML is
our config language, so copying the TOML syntax would be less surprising than
borrowing it from another language.
https://github.com/toml-lang/toml/issues/188
While I like strict parsing, it's not uncommon that we have to deal with file
names containing spaces, and doubly-quoted strings such as '"Foo Bar"' look
ugly. So, this patch adds an exception that accepts top-level bare strings.
This parsing rule is specific to command arguments, and won't be enabled when
loading fileset aliases.
When you use e.g. `git switch` to check out a conflicted commit,
you're going to end up with the `.jjconflicts-*` directories in your
working copy. It's probably not obvious what those mean. This patch
adds a README file to the root tree to try to explain to users what's
going on and how to recover.
The authoritative information about conflicts is stored in the
`jj:trees` commit header. The contents of conflicted commits is only
used for preventing GC. We can therefore add contents to the tree
without much consequence.
I will be updating `rebase -r` to avoid simplifying ancestor merges in a
subsequent commit, which will cause existing tests to fail for the Git
backend due to ancestor merges with the root commit.
I'm not sure if this was an intentional omission, but I think it would be
useful to have `-e` as a short flag for `--edit`. I don't usually edit commits,
but I do use `prev` and `next` with edit to navigate to a commit that I want to
squash. Often this is easier than typing `--from` and `--into` plus the change
IDs.
If people want to edit commits we shouldn't stand in their way.
This is following on the rewrite for `parallelize`.
- https://github.com/martinvonz/jj/pull/3521
Since rebase_descendants from rebase.rs is no longer used outside of that file,
it can be made private again.
In a future commit these tests will run with both `jj commit` and `jj new` since
both will have the same semantics for advancing the branch pointer.
Parameterizing the tests allows us to run both variants without duplicating the
test bodies. Since the commit IDs are different when `jj describe` + `jj new`
is used instead of `jj commit`, this commit also drops the commit IDs from the
test snapshots. This is fine because the commit IDs are not important for these
tests.
## Feature Description
If enabled in the user or repository settings, the local branches pointing to the
parents of the revision targeted by `jj commit` will be advanced to the newly
created commit. Support for `jj new` will be added in a future change.
This behavior can be enabled by default for all branches by setting
the following in the config.toml:
```
[experimental-advance-branches]
enabled-branches = ["glob:*"]
```
Specific branches can also be disabled:
```
[experimental-advance-branches]
enabled-branches = ["glob:*"]
disabled-branches = ["main"]
```
Branches that match a disabled pattern will not be advanced, even if they also
match an enabled pattern.
This implements feature request #2338.
Maybe it's personal preference, but the hash sign looks bigger compared to
the normal "o" nodes, and is slanted. This makes immutable commits stand out
too much. I think "+" is closer to the diamond character used in the unicode
template.
Since we have two separate "immutable" calls in the builtin node template, and
user might add a few more to their text template, it seems reasonable to cache
the containing_fn globally.
It's reasonable for a `WorkingCopy` implementation to want to return
an error. `LocalWorkingCopyFactory` doesn't because it loads all data
lazily. The VFS-based one at Google wants to be able to return an
error, however.
This one just tests with a larger value and a human-readable string (10KB).
Signed-off-by: Austin Seipp <aseipp@pobox.com>
Change-Id: If9e5d62146b369d3a1b7efe4e56a1b6b4338c720
For new users this results in a significantly better error output, that
actually shows them how to solve the problem, and why it happened.
Signed-off-by: Austin Seipp <aseipp@pobox.com>
Change-Id: Ide0c86fdfb40d66f970ceaef7b60a71392d2cd4b
Previously, this command would work:
jj --config-toml='snapshot.max-new-file-size="1"' st
And is equivalent to this:
jj --config-toml='snapshot.max-new-file-size="1B"' st
But this would not work, despite looking like it should:
jj --config-toml='snapshot.max-new-file-size=1' st
This is extremely confusing for users.
This config value is deserialized via serde; and while the `HumanByteSize`
struct allegedly implemented Serde's `visit_u64` method, it was not called by
the deserialize visitor. Strangely, adding an `visit_i64` method *did* work, but
then requires handling of overflow, etc. This is likely because TOML integers
are naturally specified in `i64`.
Instead, just don't bother with any of that; implement a `TryFrom<String>`
instance for `HumanByteSize` that uses `u64::from_str` to try parsing the string
immediately; *then* fall back to `parse_human_byte_size` if that doesn't work.
This not only fixes the behavior but, IMO, is much simpler to reason about; we
get our `Deserialize` instance for free from the `TryFrom` instance.
Finally, this adjusts the test for `max-new-file-size` to now use a raw integer
literal, to ensure it doesn't regress. (There are already in-crate tests for
parsing the human readable strings.)
Signed-off-by: Austin Seipp <aseipp@pobox.com>
Change-Id: I8dafa2358d039ad1c07e9a512c1d10fed5845738
This replaces `.map(|c| c.id().clone())` with `.ids().cloned()` to use nicer
syntax for getting `CommitId`s from an iterator of commits using the
`CommitIteratorExt` trait.
In one case we can actually call `.parent_ids()` directly. I also pluralized a
variable to make it clearer that it's a vec of IDs and not a single ID.
The rewritten code is already a no-op when there's a single input. I
don't think the case is common enough to warrant having a special case
for performance reasons either. Also, by not having the special case,
`jj parallelize <immutable commit>` fails consistently with the
non-singleton case.
I'm going to make some `jj parallelize` cases that currently error out
instead be successful. Some of the will result in ancestor merges with
the root commit. This patch updates those tests to avoid that.
`jj parallelize` was a good example of a command that can be
simplified by the new API, so I decided to rewrite it as an example.
The rewritten version is more flexible and doesn't actually need the
restrictions from the old version (such as checking that the commits
are connected). I still left the check for now to keep this patch
somewhat small. A subsequent commit will remove the restrictions.
`CommitRewriter` wraps 3 of the arguments, so I think it makes sense
to pass it instead. More importantly, I hope to continue refactoring
so many of the callers already have a `CommitRewriter`.
It was removed at 522025e091 "log: remove unused and inconsistent `log`
label", but obslog had the same inconsistency. Since it's now easy to label
the template output, let's re-add the "log" label.
The change in test_templater_upper_lower() is noop. Formatter no longer
emits reset sequence in the middle because the template is still labeled.
These labels could be renamed to "log_node"/"op_log_node" for consistency, but
I'm not sure if that's a good idea. A single "node" namespace is practically
more convenient.
It's not uncommon to label the whole template output with command or template
name. If the output doesn't have to be captured, we can simply push the label
to the formatter. cmd_config_list() is an example of such cases, but it's also
migrated for consistency.
Mercurial appears to resolve cwd-relative path first, so "glob:*.c" could be
parsed as "**/*.c" if cwd was literally "**". It wouldn't practically matter,
but isn't correct. Instead, jj's parser first splits glob into literal part
and pattern. That's mainly because we want to parse the user input texts into
type-safe objects, and (RepoPathBuf, glob::Pattern) pairs are the simplest
ones. The current parser can't handle patterns like "foo/*/.." (= "foo" ?),
and errors out. I believe this restriction is acceptable.
Unlike literal paths, the 'glob:' pattern anchors to the whole file path. I
don't think "prefix"-matching glob is useful, and making it the default would
be rather confusing.
It's cheap to look up commits again from the cache in `Store` but it
can be expensive to look up commits we didn't end up needing. This
will make it easier to refactor further and be able to cheaply set
preliminary parents for a rewritten commits and then let the caller
update them.
I'm going to add a helper struct to help with rewriting commits. I
want to make that struct own the old commit and the new parents to
simplify lifetimes. This patch prepares for that by passing the
commits by value to `rebase_commit()`.
Running `cargo publish` from a non-colocated repo (such as my usual
repo) is currently quite scary because it uploads all non-hidden
files, even if they're ignored by `.gitignore`
(https://github.com/rust-lang/cargo/issues/2063). I noticed this a
while ago and have always run the command from a fresh clone since
then. To avoid the need for that, let's use the workaround mentioned
on the bug, which is to explicitly list patterns we want to publish.
This fixes several issues that made working with empty files difficult using
the builtin diff editor.
1. The scm-record library used for the editor expects each file to have at
least one section. For new empty files this should be a file mode section. jj
wasn't rendering this mode section, which prevented empty files from being
selected at all.
2. The scm-record library returns `SelectedContents::Absent` if the file has no
contents after the diff editor is invoked. This can be because of several
reasons: 1) the file is new and empty; 2) the file was empty before and is
still empty; 3) the file has been deleted. Perhaps this is a bug in scm-record
and it should return `SelectedContents::Unchanged` or
`SelectedContents::Present` if the file hasn't been deleted. Until this is
patched upstream, we can work around it by disambiguating these cases.
See https://github.com/arxanas/scm-record/issues/26 for the upstream bug.
Fixes#3016
This is the last non-debug command that doesn't support file patterns. It
wouldn't make much sense to "cat" multiple files (despite the command name),
but doing that should be harmless.
Prepares for migrating to the matcher API. "Path exists but is not a file"
error is turned into a warning because the loop shouldn't terminate there.
"No such path" error message is also updated for consistency.
if `--use-destination-message/-u` is passed to `jj squash`, the resulting
revision will use the description of the destination revision and the
description(s) of the source revision(s) will be discarded.
If we ever implement some sort of ABI for dynamic extension loading, we'll need these underlying APIs to support multiple extensions, so we might as well do that first.
If this doesn't work out, maybe we can try one of these:
a. fall back to bare file name if expression doesn't contain any operator-like
characters (e.g. "f(x" is an error, but "f x" can be parsed as bare string)
b. introduce command-line flag to opt in (e.g. -e FILESET)
c. introduce pattern prefix to opt in (e.g. set:FILESET)
Closes#3239, #2915, #2286
This is the same as the `test_split_siblings_with_merge_child` added in
https://github.com/martinvonz/jj/pull/3485, but without the siblings flag. I
forgot to add the non-siblings version in that PR.
#3485
This command checks not only whether Watchman works, but also whether
it's enabled in the config. Also, the output is easier to understand
than that of the other `jj debug watchman` commands.
It would be nice if `jj debug watchman` called `jj debug watchman
status`, but it's not trivial in `clap` to have a default subcommand.
Ilya reported this in https://github.com/martinvonz/jj/issues/3483.
The bug was introduced in 976320726d.
Before this fix, `jj split` dropped any parents what weren't involved in the
split when it rebased the children of the commit being split. This meant that
any children which were merge commits lost their other parents unintentionally.
Fixes#3483
Maybe we can optimize it to check paths during diffing, but I think it's okay
to add extra lookup cost at the end. The size of the path arguments is usually
small.
Closes#505
Path parsing will be migrated to parse_union_filesets(), but I haven't decided
how we'll go forward:
a. migrate everything to fileset
b. require flag like "-e FILESET" (note -p conflicts with log -p)
c. require flag like "-e FILESET" and deprecate positional PATHs #2554
d. require prefix like "set:FILESET" (not consistent with -r REVSET)
I'm currently dogfooding (a). It works for me, but I don't use exotic file
names that would require quoting in zsh.
#3239
Before this commit `jj prev` fails if the current working copy commit is a
merge commit. After this commit it will prompt the user to choose the ancestor
they want to select.
#2126
This commit adds commit graphs to most of the tests for `jj prev` to make it
clearer where `@` points before and after `prev` is run.
In addition, there were a couple of tests where the comments suggested the test
meant to have `@` pointing to a specific commit, but it actually pointed to an
empty child of that commit.
This sort of issue also exists in `test_prev_editing`. The test is supposed to
check that `--edit` is implied if you run `jj prev` on an interior commit, but
it actually caused a new empty commit to be created since `@` was sitting on a
tip commit.
Expose the information we now record, to allow changing the default "snapshot
working copy" message or to make snapshots more compact/less distracting in
the log
This will hopefully make it clear that `jj prev` does not
move by [OFFSET] relative to `@`, which is a misconception
that I had and I think others may also have.
I am suggesting this change as a result of the vigorous discussion in
these two issues:
- https://github.com/martinvonz/jj/issues/3426
- https://github.com/martinvonz/jj/pull/3445
We should make similar changes to `jj next` as well since
it follows similar rules.
This patch adds "string_" prefix to the related rules to discriminate them from
integer_literal. I also renamed "raw_literal" because it sounds like a raw
string literal that preserves backslash characters.
This is basically the same as string kind:pattern syntax in CLI. This will
hopefully be superseded by filesets, but I'm not sure if that will work out.
A file name is more likely to contain whitespaces, which will have to be
quoted as '"Documents and Settings"'.
There are no more callers of parse_function_argument_to_string(), so it's
removed. This function was a thin wrapper of literal parser, and can be
easily reintroduced if needed.
Parallelize revisions by making them siblings
Running `jj parallelize 1::2` will transform the history like this:
```text
3
| 3
2 / \
| -> 1 2
1 \ /
| 0
0
```
Each of the target revisions is rebased onto the parents of the root(s) of
the target revset (not to be confused with the repo root). The children of
the head(s) of the target revset are rebased onto the target revisions.
The target revset is the union of the REVISIONS arguments.
The target revset being parallelized must satisfy several conditions,
otherwise the command will fail.
1. The heads of the target revset must not have different children.
2. The roots of the target revset must not have different parents.
3. The parents of all target revisions except the roots must also be
parallelized. This means that the target revisions must be connected.
The nightly compiler has several clippy fix-its that, if applied, break the
build. There are various bugs about this, but there isn't enough space in the
margins to detail it all.
Just ignore these on a per-function basis; about 70% of them are just multiple
instances happening inside a single function.
This makes `cargo clippy --workspace --all-targets` run clean, even with the
nightly compiler.
Signed-off-by: Austin Seipp <aseipp@pobox.com>
Change-Id: Ic26a025d3c62b12fbf096171308b56e38f7d1bb9
This lets users use "large" revsets in commands such as `jj rebase`, without
needing the `all:` modifier.
Signed-off-by: Austin Seipp <aseipp@pobox.com>
Change-Id: Ica80927324f3d634413d3cc79fbc73057ccefd8a
After upgrading pest from 2.7.8 to 2.7.9, I noticed CLI tests got significantly
slow (something around 40sec -> 60sec on my laptop.) I suspect this would be
caused by detailed error state tracking introduced in 2.7.9, but it's also true
that our template grammar exercises such code path.
My understanding is that PEG is basically a top down parsing with unlimited
lookahead. Before this change, the default commit_summary template would be
parsed as follows:
1. parse the outermost separate(..) as "term"
2. "concat" rule can't continue, so
3. reparse the whole string as "expression"
Because this pattern is not uncommon, I think it's better to rewrite the
grammar to avoid large retry.
With this patch, our tests runs within ~50sec under debug build. It appears to
save a few milliseconds in release build, but my development environment isn't
quiet enough to say the difference is significant.
Offset is a more descriptive noun for this argument. This commit also tweaks
the help message for the argument.
This isn't an option/flag, so this change should be transparent to users.
This function doesn't actually need commits, it only needs their IDs. In some
contexts we may only have commit IDs, so there's no need to require an iterator
of Commits.
This commit also adds a `CommitIteratorExt` that makes it easy to convert an
iterator of `&Commit` to an iterator of `&CommitId`.
I'm going to make all WorkspaceCommandHelper::parse/resolve_revset functions
accept &RevisionArg, so I want a convenient way to unwrap Option<RevisionArg>.
Another option is to add an associated function that returns
RwvisionArg("@".to_owned()). As we wouldn't care for the allocation cost, either
approach should work fine.
I keep typing `--to` since I'm used to `jj move` interface. It is
also shorter.
Currently, if I type `--to`, clap unhelpfully suggests whether I
meant `--tool`.
Like -r/--revisions, it should be okay to filter synced/non-tracking remote
branches by name.
conflicts_with_all = "tracked" is redundant, so removed as well. The tracked
field declares that it conflicts with --all-remotes.
Since "all:" implies that the user doesn't care about the order of the
revisions within that argument, it should be okay if two "all:" sets overlapped.
resolve_revset_default_single() will be inlined instead. Since "default_single"
evaluation can return multiple revisions, the CLI interface usually accepts
multiple arguments. This suggests that there would be no external callers of
the singular resolve_revset_default_single().
I'm going to reorganize "single"/"default_single" revset functions in a way
that resolve_single_rev_with_hint_about_all_prefix() is inlined.
evaluate_revset_to_single_commit() could be a private method of
WorkspaceCommandHelper, but I want to minimize the code that has to be hosted
there.
When a commit is split, any branches pointing to it are moved to the second
commit created by the split. This is true even if the --siblings option is
used.
#3419
If the --siblings option is used, the target commit is split into two sibling
commits instead of parent and child commits. Any children of the original
commit will have both siblings as their new parents.
#2274
This refactor will allow us to reuse new `rebase_descendants` function for the
`jj split --siblings` feature (#2274) and later possibly for `jj parallelize`
(#1079).
Note that `jj resolve` already had its own `--quiet` flag. The output
with `--quiet` for that command got a lot quieter with the global
`--quiet` also taking effect. That seems reasonable to me.
When the caller needs a formatter, it's because they're doing
something non-trivial. When the user passed `--quiet` (see upcoming
patch), we should ideally skip doing related work for print the
formatting output. It helps if the `Ui` object doesn't even return a
`Formatter` then, so the caller is forced to handle the quiet case
differently.
Thanks to Yuya for the suggestion.
I'm about to make hints not get printed with `--quiet`, but error
hints are probably still useful to get. They shouldn't be a problem
for scripts since the script would have to deal with the error anyway.
evaluate_programmatic() should be allowed here. AFAIK, the contract is that
the expression should never contain any bare symbols and "fallible" symbol-like
expressions, which doesn't apply to branches() and remote_branches() functions.
evaluate_revset() is removed because there are no callers. However, it's simple
and basic function, so we might want to reintroduce it if needed.
Many callers of resolve_revset() and evaluate_revset() will be migrated to
this wrapper. "single" and "default_single" APIs won't be replaced because
they require more contexts to construct error messages.
id_prefix_context() now uses bare revset::parse() to avoid dependency cycle.
Templater doesn't have the one yet, but I think it belongs to the same
category.
For clap::Error, we could use clap's own mechanism to render suggestions as
"tip: ...", but I feel "Hint: ..." looks better because our error/hint message
is capitalized.
I'm going to add RevsetParseError constructor for InvalidFunctionArguments,
with/without a source error, and I don't want to duplicate code for all
combinations. The templater change is just for consistency.
I couldn't find a good naming convention for the builder-like API, so it's
called .with_source(mut self, _). Another option was .source_set(source).
Apparently, it's not uncommon to name consuming constructor as
with_<something>().
If "all:" is specified, an empty set should be allowed within that expression.
So the additional check we need here is to ensure that the resulting set is not
empty.
One less CLI revset helper. It might look odd that "jj rebase" says "Merge
failed" whereas "jj new" doesn't, but that depends on where the BackendError
is detected.
This commit moves the parse_string_pattern helper function into the
str_util module in jj lib and adds tests for it.
I'd like to reuse this code in a function defined by `UserSettings`, which is
part of the jj lib crate and cannot use functions from the cli crate.
The idea is that, if .extract() succeeded in static context, it means the
property can be evaluated as constant. This will potentially eliminate
expect_string_literal_with(), though I'm not too sure if it's a good idea.
If needed, maybe we can extend the idea to suppress type/name resolution errors
by "if(some_static_config_knob, x, y)".
This allows us to propagate property evaluation error to a string property. For
instance, "s.contains(x ++ y)" will be an error if "y" failed to evaluate,
whereas bare "x ++ y" shouldn't.
The other implementation ideas:
a. add Template::into_string_property() to enable strict evaluation
=> it's tedious to implement it for each printable type
b. pass (formatter, error_handler) arguments separately
=> works, but most implementors don't need error_handler argument
c. pass strict=bool flag around build_*() functions
=> didn't tried, but it would be more complicated than this patch
Because Template trait is now implementation detail of the templater, it
should be okay to use a non-standard formatter wrapper.
Commands like `new`, `duplicate`, and `abandon` can take multiple revset
arguments which results in their collective union. They take the revisions
directly as arguments. But for consistency with many other commands, they can
also take the `-r` argument, which is a no-op. However, due to the flag being
specified as a `bool`, the `-r` option can only be specified once, so e.g.
`abandon -r x -r y` often fails. I normally use `-r` for consistency and muscle
memory, so this bites me often.
Instead, use `clap::ArgAction::Count` in order to allow `-r` to be specified
multiple times. It remains unused, of course.
With this change, all the following invocations are equivalent. Before this
change, the second example would fail due to giving `-r` multiple times.
jj abandon x y
jj abandon -r x -r y
jj abandon -r 'x | y'
Note: `jj new` already supported this exact case actually, but it used an
awkward trick where it used `.overrides_with()` in order to override *itself* so
it could be specified multiple times. I believe this is a bit clearer.
Signed-off-by: Austin Seipp <aseipp@pobox.com>
Change-Id: Ib36cf81d46dae4f698f06d0a32e8fd3120bfb4a4
This makes the summary line more informative. Even though it just duplicates
the message printed later, I think it's easier to follow.
This patch also adjusts some RevsetParseError messages because it seemed
redundant to repeat "revset function", "argument", etc.
Because the CLI error handler now prints error sources in multi-line format,
it doesn't make much sense to render Revset/TemplateParseError differently.
This patch also fixes the source() of the SyntaxError kind. It should be
self.pest_error.source() (= None), not self.pest_error.
I'm going to make TemplateParseError hold RevsetParseError as Box<dyn _>, but
Box<dyn std::error::Error ..> doesn't implement Eq. I could remove Eq from
ErrorKind enums, but it's handly if these enums remain as value types.
This change will also simplify fmt::Display and error::Error impls.
This can be used to flatten nested "if()"s. It's not exactly the same as "case"
or "switch" expression, but works reasonably well in template. It's not uncommon
to show placeholder text in place of an empty content, and a nullish value
(e.g. empty string, list, option) is usually rendered as an empty text.
A formatted error is not a string containing ANSI escape sequences because 1.
the output may be differently colored inside "hint", 2. the caller might not
be accessible to ui.new_formatter().
Highlighting "{n}: " will help to follow error sources containing multi-line
messages. I'm going to make revset/template alias errors be formatted as plain
error chain.
It's inconsistent that some warnings have headings and some don't, and it seems
the choice is arbitrary. Let's unify the style. There are two exceptions:
1. continued line following labeled message,
2. "unrecognized response" followed by prompt.
The lowercase "warning: " is unified to "Warning: " as it is the jj's
convention afaik.
The _default() suffix could be dropped from these methods, but it's probably
better to break the existing codebase for the moment. Otherwise, the caller
might do writeln!(ui.warning(), "Warning: ..").
The existing .hint() method is renamed to .hint_no_heading() to clarify that
it's not the default choice to print a hint. I'll add .hint_default() later,
which will be the shorthand for .hint_with_heading("Hint: ").
This will be used to label "Error: " heading and content differently. I want
to see an error message in the default (white) color because it's easier to
read, but I still want to highlight the "Error: " heading.
We can achieve that without introducing new wrapper, but the resulting code
would look something like "writeln!(ui.error("Error: ")?, ..)?", and it would
get messier if the caller had to suppress io::Error.
I don't think we have any callers left that call
`record_rewritten_commit()` multiple times within a transaction and
expect it to result in divergence. I think we should consider it a bug
to do that.
I'm going to introduce two changes: 1. indent commit summary, 2. colorize
output. The former can be implemented without using the templater API, but the
latter can't.
IntoTemplate will be cleaned up later. Perhaps, the lifetime parameter can be
removed at this point, but I'm planning to remove the IntoTemplate trait at all.
The type parameter 'C' will be removed from the Template trait, making it
represent a printable type or compiled template.
TemplateRenderer now holds Box<dyn _> template because it's unlikely that the
inner template type can be statically determined.
This fixes --change/--branch conflicts by making --change precede --branch. I
don't think this is the most obvious behavior, but it's the easiest workaround.
It could be moved before set_local_branch_target() to not update the local
branch, but it seemed weird that --change is silently ignored. This
inconsistency will be addressed later.
This helps to implement CommandError::add_hint(). The inner errors could be
embedded in the enum as before, but they're mostly of the same type. And I think
it's okay to use downcast_ref() to deal with the clap::Error special case.
I'm going to reorganize CommandError as (kind, err, hints) tuple so that we
can add_hint() to the constructed error object.
Some config error messages are slightly adjusted because the inner error is
now printed in separate line.
I think Option<Commit> is the simplest encoding of the log node.
The behavior of an Option type is closer to nullable types rather than the
Option in Rust. I don't think we would want to write opt.map(|x| x.f()) or
opt.unwrap().f(). We can of course add opt?.f() syntax, but it will be a short
for "if(opt, opt.f())"?
As requested in #1471, I added a new flag for `jj branch list` to only show branches that are conflicted.
Adds a unit test to check for listing only conflicted branches and regenerates the cli output to incorporate the new flag.
Closes#1471
reformat
These two are common when implementing methods. Fortunately, the
"return-position impl Trait in traits" feature is stabilized in Rust 1.75.0,
so we don't need another variant of TemplateFunction.
Apart from (IMO) looking nicer, this will also sidestep the potential problem
that if the file contains actual jj conflict markers (`>>>>>>>` in the beginning
of a line, for example), jj would currently have trouble materializing and
subsequently parsing conflicts in the file if it actually became conflicted.
I'll demo this bug in either this or a subsequent PR. It's the kind of bug that
sounds serious in theory but might never cause a problem in practice.
After this PR, only `docs/tutorial.md` has a conflict marker that's not indented.
There's only one there, so hopefully it won't be too much of a pain to deal with.
I also indented other strings in `test_conflicts.rs`. IMO, this looks nice and
more consistent with the `insta::assert_snapshot` output. I didn't spend the
time to do the same for `test_resolve_command`.
Now a compiled template doesn't have a static Context type internally. A
property is basically of "Fn() -> Result<O, _>" type, and a type-erased "self"
variable will be injected as needed.
Template<C> types will be refactored separately.
In short, this enables compilation of template of e.g. Vec<Commit> type by
using CommitTemplateLanguage.
A Template<C> was originally compiled for a specific type C, and invoked as
"Fn(&C) -> _". It was simple and intuitive, but we had to define the context
type C statically. Things got even worse by extensions support because we had
to provide object-safe hook point for each context type C.
This patch basically removes the Context type from compiled templates. The
"self" variable is injected through RefCell<Option<C>> placeholder. A compiled
template knows its "self" type, but the type can be decided per instance, not
per TemplateLanguage type. A drawback is that the "self" variable will have to
be cloned one more time.
The Template<C> abstraction no longer makes sense, and will be split to inner
Template<()> implementations (which usually represent printable types) and the
outer Template<C>.
The idea is basically the same as list.map(|x| ...) template. It compiles the
inner template with a placeholder variable of type 'C', and evaluate it for
each instance variable by injecting the variable through RefCell.
Because GenericTemplateLanguage doesn't support any global resources, it no
longer makes sense to pass the language instance around to 0-ary keyword
functions.
These .wrap_<type>() functions aren't supposed to capture resources from the
language instance. It was convenient that wrap_() could be called without fully
spelling the language type, but doing that would introduce lifetime issue in
later patches.
I added type alias L to several places because the language type is usually
called L in generic code.
As discussed in #2900, the milliseconds are rarely useful, and it can
be confusing with different timezones because it makes harder to
compare timestamps.
I added an environment variable to control the timestamp in a
cross-platform way. I didn't document because it exists only for tests
(like `JJ_RANDOMNESS_SEED`).
Closes#2900
Changes the formatter to accept not only existing color names (such as "red" or
"green") but also those in the form #rrggbb, where rr, gg, and bb are two-digit
hexadecimal numbers. This allows much finer control over colors used.
"-r REVISIONS" here specifies the search space of the branches to push, and
warned if no branches are found in that space. I don't think an empty set
should be an error, but a warning for consistency. The warning message will be
improved by the subsequent patches.
This command belongs to the same category as "duplicate".
We might want a plural version of resolve_revset(), but I'm not sure whether
it should return Vec<Commit> or Revset. Let's revisit it later when we get
more callers.
Suppose we have an alias 'immutable()' = '::immutable_heads()', user can
express (visible) mutable set as '~immutable()'. 'immutable_heads()..' can
terminate early, but a generic difference 'all() & ~immutable()' can't.
Suppose the generation value is usually small, it should be faster to do
bounded range look up first 'y-', then walk ancestors with the unwanted set
'y-..x'.
There's a subtle behavior change that an empty revset is no longer rejected
individually, but I think that's good for "jj duplicate".
cmd_duplicate() was the last caller of index.topo_order().
When an operation is missing and we recover the workspace, we create a
new working-copy commit on top of the desired working-copy commit (per
the available head operation). We then reset the working copy to an
empty tree because it shouldn't really matter much which commit we
reset to. However, when the workspace is sparse, it does matter, as
the test case from the previous patch shows. This patch fixes it by
replacing the `reset_to_empty()` method by a new `recover(&Commit)`,
which effectively resets to the empty tree and then resets to the
commit. That way, any subsequent snapshotting will result keep the
paths from that tree for paths outside the sparse patterns.
As shown by the updated test case, when we recover from a working copy
pointing to a lost operation, the new working-copy commit after
snapshotting will have lost any files outside the sparse patterns.
AST substitution is technically closer to parsing, but the parsed expression
can be modified further by caller. So I think it's better to do optimize() in
later pass.
revset_util::parse() is inlined.
Spotted while moving revset::optimize() around. Since we don't include the
parsing cost of the target expression, we shouldn't include parsing/evaluation
cost of the short-prefixes either. The IdPrefixContext is currently populated
by WorkspaceCommandHelper::new(), but it's hard to tell.
The original plan was to extend the globals table to implement "revset(expr)".
I'm not sure if that's more discoverable than "self.contained_in(revset_expr)"
method, but we can decide that later. Anyways, this patch adds typo suggestion
for global functions.
Prepares for migrating to table-based lookup. It's unlikely that the
implementor handles global function calls differently, but the core doesn't
have an access to the customized symbol table.
This is preparation for #3292, which will use these functions. The main
goal is to merge the parts of #3292 that are likely to cause merge
conflicts with other PRs while I polish it up.
This will be reused for integration with the new `:builtin-web` diff editor in #3292.
`instructions-path_to_cleanup` is moved into DiffWorkingCopies.
DiffWorkingCopies: add instructions_path_to_cleanup
This change updates the language of `jj edit`'s help message to be
more clear as to the nature of the command. It also adds a
recommendation for a more idiomatic/safer workflow.
I just wanted to remove CommandError from parse_immutable_expression(), which
will be called from the templater, but the new error message looks also better.
Some of them will be called directly from the commit templater which shouldn't
know WorkspaceCommandHelper. All parameters are passed as function arguments
instead of having a nicer wrapper struct. That's because some resources (e.g.
repo and id prefix context) are also used for different purposes, and it seemed
uneasy to introduce high-level abstraction satisfying all the use cases.
Now you can do e.g. `jj squash --from 'foo+::' --into foo` to squash a
whole series into one commit. It doesn't need to be linear; you can
squash a bunch of siblings into another siblings, for example.
Now as default and elided node symbols come from the config, the next logical
step is to use them directly bypassing GraphLog. Note that commands like `jj op
log` and `jj obslog` do not use the elided node symbol at all.
This was proposed by @Brixy in
https://github.com/martinvonz/jj/discussions/2882 a while ago. There
seems to be pretty strong consensus that it's a good idea.
I've copied the added test cases from `test_move_command.rs`, just
replacing `move` by `squash`, `--to` by `--into`, and deleting the
test of a no-arg invocation (`jj move` fails, `jj squash` does not -
it defaults to squashing into the parent).
This patch makes `jj squash` us the helper I just extracted from `jj
move`. I had a to add a few small features to it for that.
The `test_squash_command.rs` test changed in a few cases where we do a
partial squash. After this patch, we include the rebased child in the
count of rebased descendants. That seems reasonable and consistent
with partial squash/move further than 1 generation.
This is just a little step towards reusing the helper I just extracted
from `jj move`. I had to update `test_immutable_commits.rs` because it
would otherwise fail because of the merge rather than failing because
of the immutable commit.
I'm soon going to make `jj squash` accept either `-r` or
`--from/--to`, which means `-r` will then be optional. This patch
prepares for that already, since it also simplifies the code a little
(and improves it so we warn if the user does `jj squash -r @
nonexistent`).
This matches what we do for `jj squash`, whether it's a
full or partial move.
I didn't add a test since we're planning to deprecate `jj move`, and
this will soon be tested via the `jj squash` tests.
The `destination` variable we use when creating the operation log may
have been replaced earlier in the code. I think this was a regression
when I moved the setting of the description from `start_transaction()`
to `finish_transaction()` a while ago.
We haven't used custom Git commit headers for two main reasons:
1. I don't want commits created by jj to be different from any other
commits. I don't want Git projects to get annoyed by such commit
and reject them.
2. I've been concerned that tools don't know how to handle such
headers, perhaps even resulting in crashes.
The first argument doesn't apply to commits with conflicts because
such commits would never be accepted by a project whether or not they
use custom commit headers. The second argument is less relevant for
conflicted commits because most tools will be confused by such commits
anyway.
Storing conflict information in commit headers means that we can
transfer them via the regular Git wire protocol. We already include
the tree objects nested inside the root-level tree, so they will also
be transferred.
So, let's start by writing the information redundantly to the commit
header and to the existing storage. That way we can roll it back if we
realize there's a problem with using commit headers.
The `amend/unamend` aliases exist for smoothen onboarding for
Git/Mercurial users; I don't think we should recommend that users use
them, so I think it's fine if users override them as they
like. Therefore, I think they belong in the config.
This should address both use cases:
1. If from_relative_path() is directly called, the error says ".." shouldn't
be included in the (normalized) relative path.
2. If parse_fs_path() is used, the error message contains paths relative to
cwd. #3216
There's a caveat: "jj config list -Tname" will concatenate all names in a
single line. That's correct but useless. We might want some option or config
knob to complete missing "\n". This also applies to "log --no-graph".
This serves the role of the formatter in Mercurial, but the provided features
are rather restricted compared to mercurial.formatter. That's because both
implementation language "Rust" and jj's template language are statically typed.
The current implementation works well for simple commands like "config list -T",
but it might be not okay for "branch list -T". If we implement branch templating
by using the generic mechanism, the commit summary part would have to be
evaluated as a separate template:
-T 'branch_name ++ target_commit_summary' (target_commit_summary: Template)
instead of
-T 'branch_name ++ commit_summary(target_commit)' (target_commit: Commit)
where the branch template language is a superset of the commit template
language.
I'm going to add generic templating support for basic value types, and
"jj config list -T" will use CommandHelper::parse_template().
CommandHelper::load_template_aliases() is made private instead.
This will help deduplicate template parsing functions. We don't care about the
cost of config.get_string(), but I don't want to copy the config key to every
caller.
This could be a provided method of the TemplateLanguage trait, but it's
unlikely that this method would have to be customized by implementors. And
I'm going to add thin wrapper method to CommandHelper, so no users would
write language.parse(..) anyway.
I'm going to split commit/operation_templater::parse() into two parts, and
the first half will be Commit/OperationTemplateLanguage::new(..). This patch
also makes CommitTemplateLanguage::wrap_() functions public because extension
methods should be able to return property of these types.
`cargo doc` complains that two URLs aren't actually links:
```
warning: this URL is not a hyperlink
--> lib/src/fsmonitor.rs:66:6
|
66 | /// (https://facebook.github.io/watchman/). Requires `watchman` to already be
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://facebook.github.io/watchman/>`
|
= note: bare URLs are not automatically turned into clickable links
= note: `#[warn(rustdoc::bare_urls)]` on by default
warning: `jj-lib` (lib doc) generated 1 warning (run `cargo fix --lib -p jj-lib` to apply 1 suggestion)
Documenting jj-cli v0.14.0 (/Users/emesterhazy/oss/github.com/martinvonz/jj/cli)
Documenting testutils v0.14.0 (/Users/emesterhazy/oss/github.com/martinvonz/jj/lib/testutils)
warning: this URL is not a hyperlink
--> cli/src/cli_util.rs:2077:41
|
2077 | /// To get started, see the tutorial at https://github.com/martinvonz/jj/blob/main/docs/tutorial.md.
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://github.com/martinvonz/jj/blob/main/docs/tutorial.md.>`
|
= note: bare URLs are not automatically turned into clickable links
= note: `#[warn(rustdoc::bare_urls)]` on by default
warning: `jj-cli` (lib doc) generated 1 warning (run `cargo fix --lib -p jj-cli` to apply 1 suggestion)
```
This commit fixes the warnings by making the watchman URL a hyperlink and by
disabling the lint for the jj-cli error. Disabling the link is the right thing
to do because the comment is captured by clap and printed when `jj --help`
runs and any markdown formatting like `<>` is passed through.
The ExternalMergeTool struct has four 24-byte fields plus one bool. It could
be shrunk by dropping Vec/String capacity, but the resulting type would still
be bigger compared to the default Builtin variant.
I considered inlining tx.select_diff(), but that looked a bit cryptic because
the arguments orders are reasonably different. This thin wrapper will help
enforce the common interactive editing behavior.
This constructor has too many arguments enough to introduce a parameter struct,
which would be identical to the CommandHelper type. Let's simply inline it as
there are no external callers.
write!(ui.hint(), ..) error is suppressed because it seemed weird if the
configuration error had io::Error variant. The write error isn't important
anyway.
This moves the config loading closer to CLI args where --tool=<name> option
will be processed. The factory function are proxied through the command helper
so that the base_ignores can be attached there later.
I'm going to make them be loaded by caller, and these newtypes will provide
extra compile-time safety (plus nicer API to be added later.) The error types
will be cleaned up later patches.
This gets rid of the last UserSettings dependency from edit_diff_external().
I'm going to remove it from edit_diff() too, and let callers pass a
preconfigured MergeTool struct instead.
These changes will make it easier to add --tool=<name> argument #2575.
Because the snapshot directory is removed at the end of the function, it doesn't
make sense to enable watchman in it. The max_new_file_size parameter might be
somewhat useful, but it's unlikely that the temporary directory contains
gigantic node_modules tree for example. OTOH, the base_ignores matters since it
may contain common ignore patterns like *~.
This eliminates most of the UserSettings dependencies from this function.
I'm going to add string.len() method which will return a length in bytes. The
number of the UTF-8 code points is useless metrics, and strings here are often
ASCII bytes, so let's simply use byte indices in substr().
If the given index is not at a char boundary, it will be rounded. I considered
making it an error, but that would be annoying. I would want to see something
printed by author.name().substr() even if it contained latin characters.
I've extracted index normalization function which might be used by other string
methods. The remaining part of substr() is trivial, so inlined it.
Before, --tool=:builtin argument was ignored and the tool was loaded from
"ui.diff.tool" option. Since there is no single builtin diff format, :builtin
doesn't make sense here. Maybe we can translate ":<format>" to the internal
diff format instead, but that will also mean "ui.diff.tool" and ".format" can
be merged.
This partially reverts 409356fa5b "merge_tools: enable `:builtin` as default
diff/merge editor."
I'm going to split get_tool_config() to fix "diff --tool=:builtin", and it
doesn't make sense to duplicate get_tool_config_from_args() per backing
get_tool_config() functions.
This make :builtin render conflicts as conflict markers instead of
panicking. To support conflicts properly, we also need to parse the
conflict markers (calling `update_from_content()`) after the user
closes the editor.
A runtime error will be printed inline. This simplifies error handling, and I
think it's better behavior overall. "jj log" won't be terminated just because
"gpg" crashed during signature verification for example. When property
evaluation failed, the error propagates to the closest template expression, and
the error message is printed there. Then, template output continues as long as
the output stream is open.
If we add revset() function for example, dynamic revset evaluation error will be
displayed inline. Static revset expression will still be processed at parsing
phase (to cache the evaluation result), and the error will be reported early.
One caveat: a string argument passed to e.g. .contains(needle) can be a
template, so the evaluation error would be swallowed there.
It was moved to CLI at 42252a2f00 "cli: on `jj init --git-repo=.`, use
relative path to `.git/`." As far as I can tell, .canonicalize() is needed
to calculate relative path, which is now processed differently in
Workspace::init_external_git() and GitBackend::init_external().
This reverts dc074363d1 "no-op: Move external git repo canonicalization into
Workspace::init_git_external." As I said in the PR comment, appending ".git"
is normalization of the user input, which is IMHO more appropriate to be done
in the CLI layer.
The translation from method error to keyword error can go wrong if the context
object had n-ary methods (n > 0), which isn't the case as of now. For
simplicity, arguments error is mapped to "self.<name>(..)" suggestion.
Local variables and "self" could be merged without using extra method, but
we'll need extend_*_candidates() to merge in symbol/function aliases anyway.
This seems more useful if aliases are nested. The innermost error usually
contains the problem, and the outer errors are contexts where aliases are
expanded.
Except for the generic list and template methods. We'll need a bit more
refactoring to migrate List<T> method builders to be compatible with
non-capturing fn() type.
The recovery commit we create when we run into a stale working copy
with a missing operation currently has an empty tree. Our commit
backend at Google creates an index of which files changed in each
commit. That gets really expensive when a commit deletes all files in
the repo, as these recovery commits do. So for our backend, it is much
better to make the recovery commit empty instead. That's what this
patch does.
It almost doesn't matter functionally what tree we use for it since we
don't care much about the current tree when snapshotting the working
copy. It does matter in a few cases, however. One case is for
conflicts. In that case, it's likely better to use the recovery
commit's parent as base tree (as we do by making the recovery commit
empty) than to use an empty tree, as that would guarantee that all
conflicts would be considered resolved. (Side note: perhaps we should
start looking at the current commit's parent instead of looking at the
current commit when snapshotting, but that's a topic for another day.)
When we abandon a working-copy commit, we create a new working-copy
commit on top. This behave is very useful, but it's not obvious. Let's
document it.
Thankfully, 2bbefcc338 (rewrite: default to not simplifying ancestor
merges) means that there are much fewer commands where we need to
document this behavior.
There are two major goals:
* provide typo hints in a similar way to revset
* make methods extensible
The created method table is bound to the 'repo lifetime because of the problem
described in the inline comment. It would be nice if we can build cachable
core method table for<'repo> CommitTemplateLanguage<'repo, '_>, but I couldn't
figure out how.
Add an option to list tracked branches only
This option keeps most of the current `--all` printing logic, but:
- Omits local Git-tracking branches by default (can be extended to
support filtering by remote).
- Skip over the branch altogether if it doesn't contain tracked remotes
- Don't print the untracked_remote_refs at the end
Usage:
`jj branch list -t`
`jj branch list --tracked`
`jj branch list --tracked <branch name>`
I think the user usually wants to abandon only newly empty commits. I
think they should use `jj abandon` if they want to get rid of already
empty commits. By keeping already empty commits, we don't need to
special-case the working copy and merge commits.
This allows us to call alias function with the top-level object.
For convenience, all self.<method>()s are available as keywords. I don't think
we'll want to deprecate them. It would be tedious if we had to specify
-T'self.commit_id()' instead of -Tcommit_id.
If I remember correctly, wrap_fn() was added to help type inference. It no
longer makes sense because the type is coerced by TemplateFunction::new()
and language.wrap_*().
The description of `jj diff` was lost in commit b5e4e670. We later got
a short description for it in b5e4e670. This patch restores the
original description.
This eliminates the separate keywords table. All keywords are resolved through
the pseudo "self" property. Maybe we'll add "self" keyword/variable later.
This is copied from the commit templater. I'm going to extract the "self"
property handling to the core template builder, and build_keyword() methods
will be replaced with that.
The default immutable_heads() includes tags(), which makes sense, but computing
heads(tags()) can be expensive because the tags() set is usually sparse. For
example, "jj bench revset 'heads(tags())'" took 157ms in my linux stable
mirror. We can of course optimize the heads evaluation by using bit set or
segmented index, but the query includes many historical heads if the repository
has per-release branches, which are uninteresting anyway. So, this patch
replaces heads(immutable_heads()) with trunk().
The reason we include heads(immutable_heads()) is to mitigate the following
problem. Suppose trunk() is the branch to be based off, I think using trunk()
here is pretty good.
```
A B
*---*----* trunk() ⊆ immutable_heads()
\
* C
```
https://github.com/martinvonz/jj/pull/2247#discussion_r1335078879
In my linux stable mirror, this makes the default log revset evaluation super
fast. immutable_heads(), if configured properly, includes many historical
branch heads which are also the visible heads.
revsets/immutable_heads()..
---------------------------
0 12.27 117.1±0.77m
3 1.00 9.5±0.08m
It should be useful at least in the presentation layer to know which
operations correspond to working-copy snapshots. They might be
rendered differently in the graph, for example. Or maybe an undo
command wants to warn if you just undid a snapshot operation. This
patch just introduces a field in the metadata to store the
information.
I think I prefer this behavior because it's less lossy. The user can
manually simplify the history with `jj rebase -s <merge commit> -d
<one of the parents>` afterwards. We can roll this change back later
if we find it annoying.
We now have lots of tests of ancestor merges in `test_bug_2600()`, so
we don't need the ones in `test_basics()`. Since it doesn't have the
"nottherootcommit" commit, it would break when we change the default
to preserve ancestor merges.
I think the conclusion from #2600 is that at least auto-rebasing
should not simplify merge commits that merge a commit with its
ancestor. Let's start by adding an option for that in the library.
The shortest change id prefix will become a few digits longer, but I think
that's acceptable. Entries included in the "revsets.short-prefixes" set are
unaffected.
The reachable set is calculated eagerly, but this is still faster as we no
longer need to sort the reachable entries by change id. The lazy version will
save another ~100ms in mid-size repos.
"jj log" without working copy snapshot:
```
% hyperfine --sort command --warmup 3 --runs 20 -L bin jj-0,jj-1,jj-2 \
-s "target/release-with-debug/{bin} -R ~/mirrors/linux debug reindex" \
"target/release-with-debug/{bin} -R ~/mirrors/linux \
--ignore-working-copy log -r.. -l100 --config-toml='revsets.short-prefixes=\"\"'"
Benchmark 1: target/release-with-debug/jj-0 -R ~/mirrors/linux --ignore-working-copy log -r.. -l100 --config-toml='revsets.short-prefixes=""'
Time (mean ± σ): 353.6 ms ± 11.9 ms [User: 266.7 ms, System: 87.0 ms]
Range (min … max): 329.0 ms … 365.6 ms 20 runs
Benchmark 2: target/release-with-debug/jj-1 -R ~/mirrors/linux --ignore-working-copy log -r.. -l100 --config-toml='revsets.short-prefixes=""'
Time (mean ± σ): 271.3 ms ± 9.9 ms [User: 183.8 ms, System: 87.7 ms]
Range (min … max): 250.5 ms … 282.7 ms 20 runs
Relative speed comparison
1.99 ± 0.16 target/release-with-debug/jj-0 -R ~/mirrors/linux --ignore-working-copy log -r.. -l100 --config-toml='revsets.short-prefixes=""'
1.53 ± 0.12 target/release-with-debug/jj-1 -R ~/mirrors/linux --ignore-working-copy log -r.. -l100 --config-toml='revsets.short-prefixes=""'
```
"jj status" with working copy snapshot (watchman enabled):
```
% hyperfine --sort command --warmup 3 --runs 20 -L bin jj-0,jj-1,jj-2 \
-s "target/release-with-debug/{bin} -R ~/mirrors/linux debug reindex" \
"target/release-with-debug/{bin} -R ~/mirrors/linux \
status --config-toml='revsets.short-prefixes=\"\"'"
Benchmark 1: target/release-with-debug/jj-0 -R ~/mirrors/linux status --config-toml='revsets.short-prefixes=""'
Time (mean ± σ): 396.6 ms ± 10.1 ms [User: 300.7 ms, System: 94.0 ms]
Range (min … max): 373.6 ms … 408.0 ms 20 runs
Benchmark 2: target/release-with-debug/jj-1 -R ~/mirrors/linux status --config-toml='revsets.short-prefixes=""'
Time (mean ± σ): 318.6 ms ± 12.6 ms [User: 219.1 ms, System: 94.1 ms]
Range (min … max): 294.2 ms … 333.0 ms 20 runs
Relative speed comparison
1.85 ± 0.14 target/release-with-debug/jj-0 -R ~/mirrors/linux status --config-toml='revsets.short-prefixes=""'
1.48 ± 0.12 target/release-with-debug/jj-1 -R ~/mirrors/linux status --config-toml='revsets.short-prefixes=""'
```
When adding a new workspace, I would expect that it inherits the
patterns from the workspace I ran the command in. We currently don't
do that. That's quite annoying when your repo has very many files
(like at Google).
`graphlog::Edge` is used somewhat inconsistently. I've replaced `Edge::Present`
with two distinct `Edge::Direct` and `Edge::Indirect` which simplifies the
construction of the enum.
The `ContentHash` documentation specifies that implementations for enums should
hash the ordinal number of the variant contained in the enum as a 32-bit
little-endian number and then hash the contents of the variant, if any.
The current implementations for `std::Option`, `MergedTreeId`, and
`RemoteRefState` are non-conformant since they hash the ordinal number as a u8
with platform specific endianness.
Fixes#3051
The legacy parsing rules are turned into compatibility errors. The x:y rule
is temporarily enabled when parsing string patterns. It's weird, but we can't
isolate the parsing function because a string pattern may be defined in an
alias.
This adds a config to render a synthetic node with a "(elided
revisions)" description for elided segments of the graph.
I didn't add any templating support for the elided nodes because I'm
not sure how we would want that to work. In particular, I don't know
what `commit_id` and most other keywords should return for elided
revisions.
Users who edit non-head commits usually expect `jj next/prev` to
continue to edit the next/previous commit, so let's make that the
default behavior. This should not confuse users who don't edit
non-head commits since they will simply not be in this state. My main
concern is that doing `jj next; jj prev` will now usually take you
back to the previous commit, but not if you started on the parent of a
head commit.
The main goal is to avoid having a symlink in our source tree. Currently, there
is no good way to work with the `jj` repo with `jj` on Windows. Currently `jj`
just crashes with symlinks. This is being worked on, see e.g. #2939, but it will
always depend on whether Developer Mode is enabled in Windows or whether
symlinks are materialized as text files with symlinks. Finally, MkDocs has
trouble following symlinks on Windows, so building docs wouldn't work there.
Another advantage is that, previously, we were lucky that MkDocs treats `insta`
header in `cli-reference@.md.snap` as a Markdown header and follows symlinks at
all. Now, we no longer depend on that.
Follows up 9702a425e5 "Allow negative numbers in the template grammar."
Since we've added parsing rules for operator expressions, it makes sense to
parse unary '-' as operator.
If the operation corresponding to a workspace is missing for some reason
(the specific situation in the test in this commit is that an operation
was abandoned and garbage-collected from another workspace), currently,
jj fails with a 255 error code. Teach jj a way to recover from this
situation.
When jj detects such a situation, it prints a message and stops
operation, similar to when a workspace is stale. The message tells the
user what command to run.
When that command is run, jj loads the repo at the @ operation (instead
of the operation of the workspace), creates a new commit on the @
commit with an empty tree, and then proceeds as usual - in particular,
including the auto-snapshotting of the working tree, which creates
another commit that obsoletes the newly created commit.
There are several design points I considered.
1) Whether the recovery should be automatic, or (as in this commit)
manual in that the user should be prompted to run a command. The user
might prefer to recover in another way (e.g. by simply deleting the
workspace) and this situation is (hopefully) rare enough that I think
it's better to prompt the user.
2) Which command the user should be prompted to run (and thus, which
command should be taught to perform the recovery). I chose "workspace
update-stale" because the circumstances are very similar to it: it's
symptom is that the regular jj operation is blocked somewhere at the
beginning, and "workspace update-stale" already does some special work
before the blockage (this commit adds more of such special work). But it
might be better for something more explicitly named, or even a sequence
of commands (e.g. "create a new operation that becomes @ that no
workspace points to", "low-level command that makes a workspace point to
the operation @") but I can see how this can be unnecessarily confusing
for the user.
3) How we recover. I can think of several ways:
a) Always create a commit, and allow the automatic snapshotting to
create another commit that obsoletes this commit.
b) Create a commit but somehow teach the automatic snapshotting to
replace the created commit in-place (so it has no predecessor, as viewed
in "obslog").
c) Do either a) or b), with the added improvement that if there is no
diff between the newly created commit and the former @, to behave as if
no new commit was created (@ remains as the former @).
I chose a) since it was the simplest and most easily reasoned about,
which I think is the best way to go when recovering from a rare
situation.
A subsequent commit will need to handle the return value of
check_stale_working_copy() in 3 different ways, so a boolean will soon
not be sufficient. In preparation for that, inline is_stale() into its
caller, converting it into a "match".
These operator symbols are different from the ones in the revset language. I
have no idea if we need bitwise operators, but we'll probably add comparison
operators. It would look weird if 'x == y & z' were parsed as '(x == y) & z'.
this greatly speeds up the time to run all tests, at the cost of slightly larger recompile times for individual tests.
this unfortunately adds the requirement that all tests are listed in `runner.rs` for the crate.
to avoid forgetting, i've added a new test that ensures the directory is in sync with the file.
## benchmarks
before this change, recompiling all tests took 32-50 seconds and running a single test took 3.5 seconds:
```
; hyperfine 'touch lib/src/lib.rs && cargo t --test test_working_copy'
Time (mean ± σ): 3.543 s ± 0.168 s [User: 2.597 s, System: 1.262 s]
Range (min … max): 3.400 s … 3.847 s 10 runs
```
after this change, recompiling all tests take 4 seconds:
```
; hyperfine 'touch lib/src/lib.rs ; cargo t --test runner --no-run'
Time (mean ± σ): 4.055 s ± 0.123 s [User: 3.591 s, System: 1.593 s]
Range (min … max): 3.804 s … 4.159 s 10 runs
```
and running a single test takes about the same:
```
; hyperfine 'touch lib/src/lib.rs && cargo t --test runner -- test_working_copy'
Time (mean ± σ): 4.129 s ± 0.120 s [User: 3.636 s, System: 1.593 s]
Range (min … max): 3.933 s … 4.346 s 10 runs
```
about 1.4 seconds of that is the time for the runner, of which .4 is the time for the linker. so
there may be room for further improving the times.
It tries to push all deleted branches, but can only succeed for tracked
branches.
Closes#2946, as there's probably no need to have `--deleted --tracked`
that would only be different in that the warnings wouldn't be printed.
Thanks to @yuja for pointing this out.
Our virtual file system at Google (CitC) would like to know the commit
so it can scan backwards and find the closest mainline tree based on
it. Since we always record an operation id (which resolves to a
working-copy commit) when we write the working-copy state, it doesn't
seem like a restriction to require a commit.
When the user doesn't have a configured default command, we show a
hint saying to set `ui.default-command`. I think the user is very
likely to want to set that in the user-wide config, so let's include
the command in the hint.
I'll probably add infix logical operators later, but the surround() function
is still useful because we don't have to repeat the condition:
if(x || y, "<" ++ separate(" ", x, y) ++ ">")
surround("<", ">", separate(" ", x, y))
It can't be used if we want to add placeholder text, though:
if(x || y, "<" ++ separate(" ", x, y) ++ ">", "(none)")
Closes#2924
This reimplements the change 9faa4670d5 "cli: on init, import git refs prior
to importing HEAD." Initialization is special because the HEAD ref isn't
available to jj yet, and there is an empty working-copy commit.
The initialization function could be refactored to go through the common code
path, but I think doing that would make future improvement harder. We might
want to initialize tracking branches based on .git/config for example.
Fixes#2942
This initializes a git backed repo.
* It does the same thing as `jj init --git` except that it
has a --colocated flag to explicitly specify that we want
the .git repo to be side-by-side the .jj repo in the working
directory.
* `jj init --git` will keep the current behaviour and will not
be able to create colocated git backed repos.
* Update test snapshots.
A few minor updates after 0f27152 AKA #2945
Specifically, I tried to change the help text so that it looks better as
Markdown. I also reworded the deprecation warning and added a hint.
this has two main advantages:
- it makes it clear that the shells are mutually exclusive
- it allows us to extend the command with shell-specific options in the future if necessary
as a happy accident, it also adds support for `elvish` and `powershell`.
for backwards compatibility, this also keeps the existing options as hidden flags.
i am not super happy with how the new help looks; the instructions for setting up the shell are
squished together and IMO a little harder to read. i'm open to suggestions.
it's somewhat confusing to me that the `--bash` flag exists at all, since it does nothing - maybe it makes sense to give a hard error? or just remove the flag?
but in any case, it seems good to document the existing behavior.
previously, `jj diff` would show the full contents of binary files such as images.
after this change, it instead shows "(binary)". it still shows the filename and metadata so that
users can open the file in the viewer of their choce.
future work could involve showing binary files as Sixel or similar; finding a way to compare large
non-binary files without filling up the screen; or extending the data backends to avoid having to
read the whole file contents into memory.
Previously, `jj git push; jj git push` would tell the user that "No
branches point to the specified revisions.". I found this confusing,
even though strictly speaking it is correct (as the default revset only
considers revisions that haven't been pushed to the remote).
Closes#2241
The error output gets more verbose because all gix error sources are printed.
Maybe we'll need a better formatting, but changing to multi-line output doesn't
look nice either.
These error types are special because the message is embedded in ASCII art. I
think it would be a source of bugs if some error types had ": {source}" but
others don't. So I'm going to remove all ": {source}"s, and let the callers
concatenate them when needed.
Summary: As discussed in Discord, on GitHub, and elsewhere, this change
deprecates the use of `jj merge` and suggests users use `jj new` exclusively
instead. `merge` isn't completely unfit as a name; but we think it obscures
the generality of `new` and we want people to use it instead.
To further drive the bit home, by default, `jj merge` is now hidden. This will
hopefully stop new users from running into it.
Signed-off-by: Austin Seipp <aseipp@pobox.com>
Change-Id: I94938aca9d3e2aa12d1394a5fbc58acce3185b56
Summary: As discussed in Discord, on GitHub, and elsewhere, this change
deprecates the use of `jj checkout` and suggests users use `jj new` exclusively
instead. The verb `checkout` is a relic of a bygone era the — days of RCS
file locking, before 3-way merge — and is not a good, fitting name for the
functionality it provides.
To further drive the bit home, by default, `jj checkout` (and `jj co`) is now
hidden. This will hopefully stop new users from running into it.
Signed-off-by: Austin Seipp <aseipp@pobox.com>
Change-Id: I7a1adfc9168fce1f25cf5d4c4c313304769e41a1
These didn't really need to use `jj checkout`, and it will be deprecated in a
future change anyway. Move them out of there and into `new`.
Ideally this would go into `test_conflicts.rs`, but that exists in `jj-lib`, so
it doesn't have `TestEnvironment` available to it.
Signed-off-by: Austin Seipp <aseipp@pobox.com>
Change-Id: If0173b27ab4d1f6036a4ec632ec77b6824f310c3
* Move git_init() to cli/src/commands/git.rs and call it from there.
* Move print_trackable_remote_branches into cli_util since it's not git specific,
but would apply to any backend that supports remote branches.
* A no-op change. A follow up PR will make use of this.
* Create a git_init() function in cli/src/commands/init.rs where all git related work is done.
This function will be moved to cli/src/commands/git.rs in a subsequent PR.
I'm going to rewrite the error output to print source chain one by one.
The "{message}: {err}" pattern is wrapped in an error struct. InternalError
variant could be a { message, source } pair, but not all errors need an
additional message. This will also apply to UserError.
This prevents rust doctests from trying to compile the code blocks.
I don't think we use doctests much or at all, but I'd like
`cargo insta test --test-runner nextest --accept --workspace`
to pass.
Unfortunately, this affects the output of `jj help` as well, but I
can't think of a workaround for that.
I am using a very hacky approach, using `insta` to generate the markdown help.
This is based on a lucky coincidence that `insta` chose to use a header
format for snapshot files that MkDocs interprets as a Markdown header (and
ignores).
I considered several other approaches, but I couldn't resist the facts that:
- This doesn't require new developers to install any extra tools or run any
extra commands.
- There is no need for a new CI check.
- There is no need to compile `jj` in the "Make HTML docs" GitHub action,
which is currently very fast and cheap.
Downside: I'm not sure how well MkDocs will work on Windows, unless the
developer explicitly enables symbolic links (which IIUC is not trivial).
### Possible alternatives
My next favorite approaches (which we could switch to later) would be:
#### `xtask`
Set up a CI check and a [Cargo `xtask`] so that `cargo xtask cli-help-to-md`
essentially runs `cargo run -- util markdown-help > docs/cli-reference.md` from
the project root.
Every developer would have to know to run `cargo xtask cli-help-to-md` if
they change the help text.
Eventually, we could have `cargo xtask preflight` that runs `cargo +nightly
fmt; cargo xtask cli-help-to-md; cargo nextest run`, or `cargo insta`.
#### Only generate markdown for CLI help when building the website, don't track it in Git.
I think that having the file in the repo will be nice to preview changes to
docs, and it'll allow people to consult the file on GitHub or in their repo.
The (currently) very fast job of building the website would now require
installing Rust and building `jj`.
#### Same as the `xtask`, but use a shell script instead of an `xtask`
An `xtask` might seem like overkill, since it's Rust instead of a shell script.
However, I don't want this to be a shell script so that new contributors on
Windows can still easily run it ( since this will be necessary for the CI to
pass) without us having to support a batch file.
#### Cargo Alias
My first attempt was to set up a [cargo alias] to run this, but that doesn't
support redirection (so I had to change the `jj util` command to output to a
file) and, worse, is incapable of executing the command *in the project root*
regardless of where in the project the current directory is. Again, this seems
to be too inconvenient for a command that every new PR author would have to run
to pass CI.
Overall, this just seems a bit ugly. I did file
https://github.com/rust-lang/cargo/issues/13348, I'm not really sure that was
worthwhile, though.
**Aside:** For reference, the alias was:
```toml
# .cargo/config.toml
alias.gen-cli-reference = "run -p jj-cli -- util markdown-help docs/cli-reference.md"
```
### Non-alternatives
#### Clap's new feature
`clap` recently obtained a similarly-sounding feature in
https://github.com/clap-rs/clap/pull/5206. However, it only prints short help
for subcommands and can't be triggered by an option AFAICT, so it won't help us
too much.
[Cargo `xtask`]: https://github.com/matklad/cargo-xtask
[cargo alias]: https://doc.rust-lang.org/cargo/reference/config.html#alias
This uses the [`clap-markdown`] library. It's not very flexible, but seems to
work. Its implementation is not difficult. If needed, we could later
reimplement the part that iterates over all subcommands and have a different
output (e.g., the boring version of each help text inside its own code block,
or a different file per subcommand, or some fancy template in handlebars or
another rust-supported templating language). I don't want to do it right now,
though.
The library does turn out to have some annoying bugs, e.g.
https://github.com/ConnorGray/clap-markdown/pull/18, but I think that's not a
deal-braker. The fix seems to be 3 lines; if the fix doesn't get merged soon, we
could vendor the library maybe?
[`clap-markdown`]: https://docs.rs/clap-markdown/latest/clap_markdown/
GitBackend::gc() will need to check if a commit is reachable from any
historical operations. This could be calculated from the view and commit
objects, but the Index will do a better job.
The "::HEAD" set is usually smaller than "::git_refs". If these sets were
imported in that order, "HEAD..git_refs" commits would be indexed on top of
the "::HEAD" commits. It's not a problem, but undesirable.
I'm going to make WorkspaceCommandHelper::maybe_snapshot() snapshot the working
copy before importing refs. git::import_some_refs() can rebase the working copy
branch and therefore @ can be moved. git::import_head() doesn't, and it should
be invoked before snapshotting.
git::import_head() is inserted to some of the git:import_refs() callers where
HEAD seems to matter. I feel it's a bit odd that the HEAD ref is imported to
non-colocated repo, but "jj init --git-repo" relies on that, and I think the
existence of HEAD@git is harmless. It's merely a ref to the revision checked
out somewhere else.
This is a convenient command, for scripting things like `cd $(jj root)
&& do something`, and it seems better to allow people to find it
before they learn about workspaces.
This goes with `c`, `s`, `f`. I feel like it's a relatively
common command now that `auto-local-branch` defaults to
`false`.
I didn't add `u` for `untrack` because it seems a little
ambiguous (un-what?); there may be other `branch` commands that undo
something in the future.
The count() function in this trait is used by "jj branch" to determine
(and then report) how many commits a certain branch is ahead/behind
another branch. This is currently implemented by walking all commits
in the revset, counting how many were encountered. But this could be
improved: if the number is large, it is probably sufficient to report
"at least N" (instead of walking all the way), and this does not scale
well to jj backends that may not have all commits present locally (which
may prefer to return an estimate, rather than access the network).
Therefore, add a function that is explicitly documented to be O(1)
and that can return a range of values if the backend so chooses.
Also remove count(), as it is not immediately obvious that it is an
expensive call, and callers that are willing to pay the cost can obtain
the exact same functionality through iter().count() anyway. (In this
commit, all users of count() are migrated to iter().count() to preserve
all existing functionality; they will be migrated to count_estimate() in
a subsequent commit.)
"branch" needed to be updated due to this change. Although jj
is currently only available in English, I have attempted to keep
user-visible text from being assembled piece by piece, so that if we
later decide to translate jj into other languages, things will be easier
for translators.
A subsequent commit will teach more variants of ahead/behind messages,
so refactor the existing code to avoid code duplication and a future
combinatorial explosion.
Gerrit also needs to be able to push low-level refs into upstream remotes, just
like `jj git push` does. Doing so requires providing callbacks e.g. for various
password entry mechanisms, which was private to the `git` command module.
Pull these out to a new module `git_utils` so we can reuse it across the two
call sites.
This also moves a few other strictly Git-related functions into `git_utils`
as well, just for the sake of consistency.
Signed-off-by: Austin Seipp <aseipp@pobox.com>
* Move canonicalization of the external git repo path into the Workspace::init_git_external().
This keeps necessary code together.
* Add a new variant of WorkspaceInitError for reporting path not found errors. The user error
string is written to pass existing tests.
It seems obvious in hindsight to have a virtual root operation just
like we have a virtual root commit. It removes the same kind of
problems by making sure there's always a common ancestor (or multiple)
between any two commits.
I think the reason I didn't add a root operation from the beginning
was that there used to be a mandatory working-copy commit in the view
(this was before support for multiple workspaces).
Perhaps we should remove the "initialize repo" operation now. The only
difference between their view objects is that the "initialize repo"
operation adds the root commit as a head. We could add that to the
root operation, but then the root operation's value depends on the
commit backend.
We've had the public_heads for as long as we've had the View object,
IIRC (I didn't check), but we still don't use it for anything. I don't
have any concrete plans for using it either. Maybe our config for
immutable commits is good enough, or maybe we'll want something more
generic (like Mercurial's phases). For now, I think we should simplify
by removing it the storage for public heads.
This function respects --ignore-working-copy and --at-op arguments, but the
name snapshot() sounds like it could forcibly trigger the snapshotting. Let's
clarify the actual behavior.
import_git_refs_and_head() and snapshot_working_copy() are unchecked functions,
and there are no external callers.
When debugging behavior of badly-GCed repos, I find it's annoying that "op log"
fails because the index can't be loaded. Since "op log" doesn't need a repo, I
think it's better to display the exact op-heads state without merging.
I'm going to make "op log" not load a repo nor resolve concurrent operations,
so there will be the case where no unique "current" operation exists. Since the
"current" operation represents the repo to be loaded, I think it's better to
not consider multi-head operations as the "current" ones. That's why the
templater field isn't Vec<_> but Option<_>.
If indexing failed due to missing commit objects, the repo won't be loadable
without --ignore-working-copy (at least in colocated environment.) In that
case, we can use "op abandon" to recover, but we had to work around the failed
index loading by --ignore-working-copy. Since "op abandon" isn't a repo-level
command, it's better to bypass working-copy snapshot and import of git refs at
all.
--at-op is rejected because it's useless and we'll need extra care for "@"
expression resolution and working-copy updates.
The formatting is closer to hg than git just because it's easier to
conditionalize the whole line per keyword. Our template language doesn't
have infix logical operators.
Unlike the other default templates, all remote branches are displayed because
it's "detailed" output.
Closes#2509
If the existing index was corrupt, it would have to be rebuilt while loading a
repo (at least in colocated environment.) Then, the index will be rebuilt again.
Since new operations and views may be added concurrently by another process,
there's a risk of data corruption. The keep_newer parameter is a mitigation
for this problem. It's set to preserve files modified within the last 2 weeks,
which is the default of "git gc". Still, a concurrent process may replace an
existing view which is about to be deleted by the gc process, and the view
file would be lost.
#12
It doesn't make sense to do gc from a non-head operation because that means
either the head operation would be corrupted or the --at-op argument is
ignored.
We would like to use a non-static version string at Google. We have a
workaround using Lazy, but it seems unfortunate to have to do
that. Using dynamic strings requires Clap's `string` feature, which
increases the binary size by 140 kiB (0.6%).
I'm going to add try_from_hex(), which requires Self: Sized. Such trait bound
could be added, but I don't think we'll need abstracted ObjectId constructors
at all.
I'm going to add a prefix resolution method to OpStore, but OpStore is
unrelated to the index. I think ObjectId, HexPrefix, and PrefixResolution can
be extracted to this module.
In order to implement GC (#12), we'll need to somehow prune old operations.
Perhaps the easiest implementation is to just remove unwanted operation files
and put tombstone file instead (like git shallow.) However, the removed
operations might be referenced by another jj process running in parallel. Since
the parallel operation thinks all the historical head commits are reachable, the
removed operations would have to be resurrected (or fix up index data, etc.)
when the op heads get merged.
The idea behind this patch is to split the "op log" GC into two steps:
1. recreate operations to be retained and make the old history unreachable,
2. delete unreachable operations if the head was created e.g. 3 days ago.
The latter will be run by "jj util gc". I don't think GC can be implemented
100% safe against lock-less append-only storage, and we'll probably need some
timestamp-based mechanism to not remove objects that might be referenced by
uncommitted operation.
FWIW, another nice thing about this implementation is that the index is
automatically invalidated as the op id changes. The bad thing is that the
"undo" description would contain an old op id. It seems the performance is
pretty okay.
This removes CommandError dependency from these resolution functions. We might
want to refactor the error types again if we introduce a real "opset" evaluator.
The error message for unresolved op heads now includes "@" instead of the whole
expression.
The resolver callback usually returns wider error type, which I don't think
is a variant of OpHeadResolutionError.
To help type inference, resolver's error type is E, not E1 where E: From<E1>.
I'll probably add change id lookup methods to CompositeIndex. The Index trait
won't gain resolve_change_id_prefix(), but I also renamed its resolve_prefix()
for consistency.
This requires creating a new public API as a substitute. I took the opportunity
to also add some comments to the
`MutRepo::record_rewritten_commit`/`record_abandoned_commit` functions.
I imade the simplest possible addition to the API; it is not a very elegant
one. Eventually, the entire `record_rewritten_commit` API should probably be
refactored again.
I also added some comments explaining what these functions do.
At some point, I tried `new_commit` instead of `rewrite_commit` in the split
command. That seemed to work, but messed up the dates in a subtle way.
This commit should prevents repeats of this mistake and emphasize the
importance of the author dates being preserved.
This partially reverts 6c627fb30d "cli: default to log when no subcommand is
provided." We could reject an empty alias at all, but we would still need to
ensure that the expanded alias contained a subcommand name.
The help output is a bit odd as the <COMMAND> can be omitted, but I think
that's acceptable. If we do care about that, maybe we can override_usage().