This addresses issue #3317, where as discussed we want to show the paths to
configuration files if they contain errors, to make it easier for the user to
locate them.
As we discovered in the `jj fix` tests,
`MergedTreeBuilder::write_tree()` doesn't try to resolve conflicts,
not even trivial ones. This patch fixes that.
The goal is to remove special case from parsing functions and provide slightly
better error message. I don't know if we'd want to use "all:" in aliases, but
there are no strong reasons to disable it.
This commit adds an optional flag to be able to push commits with an
empty description to a remote git repo. While the default behavior is
ideal we might need to interact with a repo that has an empty commit
description in it. I ran into this issue a few weeks ago pushing commits
from an open source repo to an empty repo and had to go back to using
git for that push as I would not want to rewrite the history which was
many many years long just for that.
This flag allows users an escape hatch for pushing empty descriptions
for commits and they're sure that they want that behavior.
This commit adds the flag to the `git push` command and updates the docs
for the command. It also updates the original test to make sure that the
flag works as intended to reject the commit when not set and to allow
the commit when the flag is set.
Closes#2633
This simplifies the interface of helper functions. While revset doesn't have
top-level string pattern or integer literal, these parsing helpers could be
used to parse array subscript or n-th parent operator if any.
Previously, it sounded like `jj git` might only include highly-technical
commands, while IMO the most important commands in here are `jj git
fetch` and `jj git push`.
This will allows us to parse "file(..)" arguments as fileset expression by
transforming AST for example. I'm not sure if that's good or bad, but we'll
probably want to embed fileset expressions without quoting.
parse_expression_rule() is split to the first str->ExpressionNode stage and
the second ExpressionNode->RevsetExpression stage. The latter is called
"resolve_*()" in fileset, but we have another "symbol" resolution stage in
revset. So I choose "lower_*()" instead.
Otherwise, newly created default branch would be re-imported as a new Git HEAD.
This could be addressed by cmd_git_init(), but the same situation can be
crafted by using "git checkout -b".
It's copied from test_git_colocated.rs, and switched to commit_id.short()
because full-length commit_id looked too verbose. "all()" history isn't needed,
but it's easier to follow.
Some backends, like the one we have at Google, can restrict access to
certain files. For such files, if they return a regular
`BackendError::ReadObject`, then that will terminate iteration in many
cases (e.g. when diffing or listing files). This patch adds a new
error variant for them to return instead, plus handling of such errors
in diff output and in the working copy.
In order to test the feature, I added a new commit backend that
returns the new `ReadAccessDenied` error when the caller tries to read
certain objects.
I'm going to add a similar message for access denied. That will want
an error message printed at the end. For consistency, let's do the
same for non-file paths.
Clear the rest of the cursor line (from the cursor to the end of the
row) after drawing the progress bar rather than clearing the entire line
before drawing. This reduces flickering on terminal emulators which are
able to redraw rapidly.
I recently needed to test something on top of a two branches at the
same time, so I created a new commit on top of both of them (i.e. a
merge commit). I then ran tests and made some adjustments to the
code. These adjustments belonged in one of the parent branches, so I
used `jj squash --into` to squash it in there. Unfortunately, that
meant that my working copy became a single-parent commit based on one
of the branches only. We already had #2859 for tracking this issue.
This patch changes the behavior so we create a new working-copy commit
with all of the previous parents.
This should be a no-op, though that is not necessarily obvious in corner
cases.
Note that libgit2 already performs the push negotiation even when
pushing without force (without `+` in the refspec).
As explained in the commit, our logic is a bit more complicated than
that of `git push --force-with-lease`. This is to match the behavior of
`jj git fetch` and branch conflict resolution rules.
This tests `git push` attempting to create a branch when the branch
already unexpectedly exists on the remote. This should (and does)
fail.
Also changes another test to use `jj_cmd_failure`.
We want to move UI-independent logic that's currently in `jj-cli` into
`jj-lib`. `WorkspaceCommandHelper` is perhaps the most important part
to start moving. As I was looking into what to move from
`WorkspaceCommandHelper`, the first thing I saw there was the
`cwd`. It might seem like a good candidate to start moving. However,
when running a server, you might be running operations on repos stored
in database, so `cwd` and the workspace root don't make sense then
(because the repo is not stored at a particular path).
So, instead, this patch starts abstracting out our uses of those two
paths by adding an enum for converting between `RepoPath` and paths as
they are presented in the UI. I added a variant for repos stored in a
file system, and made `WorkspaceCommandHelper` use that to show that
it works. We'll probably add a server variant later.
I put the new type in `repo_path.rs` because at least the
file-system-based implementation is closely related to
`RepoPath::parse_fs_path()`.
It's been about six months since we started using tree-level conflicts
by default. I can't imagine we would switch back. So let's continue
the migration by always using tree-level conflicts when merging trees,
even if all inputs were legacy trees.
The original expand_node() body is migrated as follows:
- Identifier -> fold_identifier()
- FunctionCall -> fold_function_call()
expand_defn() now manages states stack by itself, which simplifies lifetime
parameters.
The templater implementation of FoldableExpression is a stripped-down version
of expand_node(). It's visitor-like because I'm going to write generic alias
substitution rules over abstract expression types (template, revset, fileset.)
Naming comes from rustc.
https://rust-unofficial.github.io/patterns/patterns/creational/fold.html
This is basically the same as the previous patch, but for error types. Some
of these functions could be encoded as "E: From<AliasExpandError<'i>>", but
alias substitution logic is recursive, so it would have to convert E back and
force.
Perhaps, the original intent was to abandon non-empty working-copy commit
assuming it was rewritten by git (therefore it should be superseded by the
current working-copy content.) However, there are other reasons that could
make the HEAD out of sync (including concurrent jj operations), and abandoning
non-empty commit can be a disaster. This patch turns it to safer side, and let
user abandon non-empty commit manually.
Fixes#3747
I'm going to extract generic alias substitution functions, and these AST types
will be accessed there. Revset parsing will also be migrated to the generic
functions.
This will help extract common FunctionCallNode<'i, T> type. We don't need
freedom of arbitrary error type choices, but implementing From<_> is the
easiest option I can think of. Another option is to constrain error type by
the expression type T through "T::ParseError: ArgumentsParseError" or
something, but it seemed a bit weird that we have to use trait just for that.
"config list NAME" argument is now parsed as TOML key, but it's still broken
since config.get() expects a query expression in different syntax.
The other config commands will be migrated later.
I add them as aliases, since a user may instead choose to define `immutable_heads()`, for example, as `heads(immutable())`, and the define `immutable()` instead.
This revset correctly implements "reachability" from a set of source commits following both parent and child edges as far as they can go within a domain set. This type of 'bfs' query is currently impossible to express with existing revset functions.
This follows up on https://github.com/martinvonz/jj/pull/3459 and adds a
label to the closing delimeter of each conflict, e.g. "Conflict 1 of 3
ends".
I didn't initially put any label at the ending delimeter since the
starting delimeter is already marked with "Conflict 1 of 3". However,
I'm now realizing that when I resolve conflicts, I usually go from top
to bottom. The first thing I do is delete the starting conflict
delimeter. It is when I get to the *end* of the conflict that I wonder
whether there are any more conflicts left in the file.
I'll probably rewrite expand_aliases() in visitor-like interface, and tree
traversal logic will be implemented on ExpressionKind. That's why I made
expand_node() destructure ExpressionNode first.
This consolidates the type of substitution results. Before, symbol substitution
can return inner ExpressionKind internally, but function-parameter substitution
couldn't.
This should avoid regression caused by upcoming changes. An alias function
parameter will be wrapped with AliasExpanded, and type errors in it should
be reported with its alias expansion stack.
I'm trying to extract generic alias substitution functions, and some of them
will take ExpressionKind or Box<FunctionCallNode> by value, then return it or
substituted value of the same type. The cost of moving values wouldn't matter
in practice, but I think it's better to keep the value types small.
Now ExpressionKind is 4-word long.
previously, aliases to built-in commands were silently ignored. this matches git's behavior, but seems unhelpful, especially if the user doesn't know that a command with that name already exists.
give a warning rather than silently ignoring it.
I've added a wrapper struct in order to get around too many arguments warning.
It captures &dyn Repo as CommitTemplateLanguage would do. OTOH, &Ui is passed
by argument because the caller might need &mut Ui after the renderer object was
configured.
I've added a struct similar to RevsetWorkspaceContext. It can be a closure,
but we'll need to duplicate format_file_path() function anyway if we add
commit.diff() template.
The function now returns an iterator over `Result`s, matching
`Operation::parents()`.
I updated callers to also propagate the error where it was trivial.
When using `ui.color = "debug"`, changes in the output style
additionally include delimiters << and >>, as well as all active labels
at this point separated by ::. The output is otherwise unformatted and
the delimiters and labels inherit the style of the content they apply
to.
Not all "branch list --all-remotes" callers are replaced because I'm going to
make get_branch_output() suppress hints by default, and there should be tests
for the hints.
This also means "all:" is allowed in default revsets (such as "revsets.log"),
but that seems okay. In revset aliases, "all:" isn't allowed because aliases
may be expanded to sub-expression position.
Closes#3654
Perhaps, this can be used to generate parsable branches list.
The hint for deleted branches isn't migrated to the template. I'm thinking of
moving it out of the loop and printed once at the end. If we want to generate
a hint in template, we'll probably need local_ref.tracking_remote_refs(), etc.
that return a list of RefNames.
Perhaps, this make it a bit clearer when "deleted" local branches should be
displayed. In practice, this change is noop since remote_ref.target should
never be absent.
More tests will be added later as "branch list" templates.
In "log" template, we might want to see the number of "local" commits ahead
of any tracked remotes. It can be implemented later in a similar way (or as a
nested remote_refs list.)
Because template is declarative language, and is evaluated as a tree, there
will be multiple copies of the same RefName object. This patch allows us to
cache ahead/behind counts which will be lazily calculated.
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