Stacking at AliasExpanded node looks wonky. If we migrate error handling to
Diagnostics API, it might make sense to remove AliasExpanded node and add
node.aliases: vec![(id, span), ..] field instead.
Some closure arguments are inlined in order to help type inference.
* See #4239 for details.
* For now, update working copy before reporting repo changes, so that
potential errors in reporting changes don't leave the repo in a stale
state.
Fixes: #4239
* First fetch from remote.
* Then check tx.{base_repo(),repo}.view().remote_bookmarks_matching(<branch>, <remote>).
This has to happen after the fetch has been done so the tx.repo() is updated.
* Warn if a branch is not found in any of the remotes used in the fetch. Note that the remotes
used in the fetch can be a subset of the remotes configured for the repo, so the language
of the warning tries to point that out.
Fixes: #4293
Deprecation warnings will be printed there. auto_tracking_matcher(ui) could
be cached, but there aren't many callers right now, so it should be okay to
parse and emit warnings for each invocation. Other than that, the changes are
straightforward.
I'll make parse_<language>_template() require &Ui, but these cached templates
should be re-constructible without access to a Ui.
Maybe we can split a parsed template object into RevsetExpression-like
evaluation tree and interpreter environment, but that'll be a big challenge.
This will help simplify warning handling in future patches. I'm going to add
deprecation warnings to revset, so Ui will be required in order to parse a user
revset expression.
revset_util::parse_immutable_expression() is inlined as it's a thin wrapper
around parse_immutable_heads_expression().
I'm testing simple conflicts diffs locally, and we'll probably need to handle
consecutive context hunks when we add some form of unmaterialized conflicts
diffs. Let's buffer context hunks (up to 1 right now.) The new code looks
simpler.
`jj bookmark` is a frequently used command. Its subcommands already have
one letter aliases. Defining `jj b` as an alias for `jj bookmarks` make
bookmarks really easy to use.
"Bookmark changes" sounds like changes will be bookmarked, and "Bookmark" here
is redundant. If we add support for pushing tags, this message will have to be
generalized anyway.
This makes it easier to work with multiple remotes at once while
tracking the default branch of the remote used to create the local
repository:
```shell
$ jj git clone --remote upstream https://github.com/upstream-org/repo
$ cd repo
$ jj git remote add origin git@github.com:your-org/repo
$ jj config set --repo git.fetch upstream
```
In the example above, `upstream` is the repository containing the
reference source code that you might want to patch, while `origin` is
your fork where pull-request will be pushed. The branch `main@upstream`
will be tracked.
We missed this when we renamed `push-branch-prefix` to
`push-bookmark-prefix`. I changed the description slightly to try to
clarify that it's about the local bookmark that's created before
pushing it to the remote as a branch.
This is basically "log -p" for "op log". The flag name has "op" because --diff
and --patch mean a similar thing in this context. Since -p implies --op-diff,
user can just do "op log -p" if he's okay with verbose op + content diffs.
Note that --no-graph affects both "op log" and "op diff" parts.
We might want to do some style changes later, such as inserting/deleting blank
lines, highlighting headers, etc.
Multiple graphs will be nested in "op log" output, and things would be messy if
we had to calculate graph widths lazily. Let's simply make LogContentFormat
track the current available width no matter if ui.log-word-wrap is off.
Jujutsu's branches do not behave like Git branches, which is a major
hurdle for people adopting it from Git. They rather behave like
Mercurial's (hg) bookmarks.
We've had multiple discussions about it in the last ~1.5 years about this rename in the Discord,
where multiple people agreed that this _false_ familiarity does not help anyone. Initially we were
reluctant to do it but overtime, more and more users agreed that `bookmark` was a better for name
the current mechanism. This may be hard break for current `jj branch` users, but it will immensly
help Jujutsu's future, by defining it as our first own term. The `[experimental-moving-branches]`
config option is currently left alone, to force not another large config update for
users, since the last time this happened was when `jj log -T show` was removed, which immediately
resulted in breaking users and introduced soft deprecations.
This name change will also make it easier to introduce Topics (#3402) as _topological branches_
with a easier model.
This was mostly done via LSP, ripgrep and sed and a whole bunch of manual changes either from
me being lazy or thankfully pointed out by reviewers.
I'll use a similar setup in "op log", but for each log entry. We might want to
extract some parts to helper function, but I don't have a good idea right now.
CommandHelper::operation_template_extensions() is removed because it's unlikely
to parse operation template without loading a workspace.
I'll add an option to include diffs in "op log", and workspace_env will be used
in order to set up diff/template contexts per operation.
cmd_op_log() is split because of owned/borrowed type differences.
These functions will be used by "op log"/"diff"/"show".
This patch also changed the error type as it's obvious that there are no other
errors to be returned.
It doesn't make sense to reparse revset expression. Let's reuse the parse
result. This also simplifies error handling bits.
OnceCell is switched to the std one as we no longer need get_or_try_init().
Some "operation" commands need a workspace, plus multiple repo views. We
currently load WorkspaceCommandHelper twice for that reason. It works, but
would be messy if "op log" loaded WorkspaceCommandHelper for each log entry.
This patch starts splitting non-repo data from WorkspaceCommandHelper. The
workspace object isn't owned by the environment object so the object can be
freely discarded.
It's a pretty frequent request to have support for turning off
auto-tracking of new files and to have a command to manually track
them instead. This patch adds a `snapshot.auto-track` config to decide
which paths to auto-track (defaults to `all()`). It also adds a `jj
track` command to manually track the untracked paths.
This patch does not include displaying the untracked paths in `jj
status`, so for now this is probably only useful in colocated repos
where you can run `git status` to find the untracked files.
#323
We had both `repo()` and `mut_repo()` on `Transaction` and I think it
was easy to get confused and think that the former returned a
`&ReadonlyRepo` but both of them actually return a reference to
`MutableRepo` (the latter obviously returns a mutable reference). I
hope that renaming to the more idiomatic `repo_mut()` will help
clarify.
We could instead have renamed them to `mut_repo()` and
`mut_repo_mut()` but that seemed unnecessarily long. It would better
match the `mut_repo` variables we typically use, though.
I'm thinking of adding an option to embed operation diffs in "op log", and
"op log" shouldn't fail at the root operation. Let's make "op diff"/"show"
also work for consistency.
This flag implements three modes:
- `copy`: copy sparse patterns from parent
- `full`: do not copy sparse patterns from parent
- `empty`: clear all paths, equal to `set --clear`
This is useful for various tooling like tools that want to run a parallel
process that queries the build system (without running into locks/blocking.)
I think continuing to copy sparse patterns makes sense as the default behavior.
Signed-off-by: Austin Seipp <aseipp@pobox.com>
This enables workflows like "insert a commit that reformats the code in one of
my project directories".
`jj fix --include-unchanged-files` is an easy way to fix everything in the repo.
`jj fix --include-unchanged-files <file...>` fixes all of the `<files>` even if they are
unchanged.
This is mostly orthogonal to other features, so not many tests are added.
This is a significant and simple enough improvement that I think it's
appropriate to make it here instead of waiting for a `jj run`-based solution.
It seems everyone agrees that `obslog` is not an intuitive name. There
was some discussion about alternatives in #3592 and on #4146. The
alternatives included `evolution`, `evolutionlog`, `evolog`,
`rewritelog`, `revlog`, and `changelog`. It seemed like
`evolution-log`/`evolog` was the most popular option. That also
matches the command's current help text ("Show how a change has
evolved over time").
As reported in #4394, at least `test_show_command::test_show_basic`
can fail when run with a narrow terminal. This patch sets
`COLUMNS=100` in the environment when running tests so the CLI uses
that value instead of using the width of the user's terminal.
This doesn't provide any benefit yet bit I think we've known for a
while that we want to make the backend write methods async. It's just
not been important to Google because we have the local daemon process
that makes our writes pretty fast. Regardless, this first commit just
changes the API and all callers immediately block for now, so it won't
help even on slow backends.
When building this project with [Nix/Crane](https://github.com/ipetkov/crane/discussions/693), if the `jj-cli` dependency is specified in `Cargo.toml` as a git-based crate, `cargo vendor` splits this workspace up into sub-crate directories, which causes `cargo metadata` to fail when searching for relative deps in the workspace root.
This commit simply changes how the crate version is determined, using Cargo's built-in environment variable [`CARGO_PKG_VERSION`](https://doc.rust-lang.org/cargo/reference/environment-variables.html)
Right now, renamed and copied files don't have any color in the output
of `jj status`, and it makes them stand out. I think it's reasonable to
color renamed files the same as modified files, since renaming is like
modifying the path, and to color copied files the same as added files,
since they're basically just added files that happen to have similar
contents to an existing file.
This avoids cloning `UserSettings` and some other data. I haven't
attempted to measure the performance impact (I expect it's tiny); this
is more about clarifying that there are not multiple different
versions of these fields.
This wraps all the fields in `CommandHelper` in an `Rc` so
`CommandHelper` itself becomes cheap to clone (thanks to @yuja for the
idea). I'll use that next to avoid some cloning in
`WorkspaceCommandHelper`.
"Concurrent" operations are not necessarily actually concurrent, so
"divergent" seems like a better name. And "reconcile" seems like a
better term for merging them, though we also sometimes use "merge".
Like https://github.com/martinvonz/jj/pull/4189, this allows extensions the ability to load the repo in an environment where the local filesystem is not accessible. This change allows such extensions to exist at the CLI layer where jj is invoked as a subprocess, rather than a library (common in testing).
I played with max-inline-alternation = 3 for a couple of weeks, and it's pretty
good. I think somewhere between 2 and 4 is good default because one or two
remove + add sequences are easy to parse.
FileConflict will be changed to not materialize Merge<BString>. I also updated
the revset engine to ignore non-file conflict. It doesn't make sense to grep
conflict description.
If movement commands don't find a target commit, they fail. However,
it's usually not intuitive why they fail because in non-edit mode the
start commit is the parent of the working commit.
Adding the start commit change hash to the error message makes it easier
for the user to figure out what is going on.
Also, specifying 'No **other** descendant...' helps make it clear what
`jj` is really looking for.
Part of #3947
Not all callers need this information, but I assumed it's relatively cheap to
look up the source path in the target tree compared to diffing.
This could be represented as Regular(_)|Copied(_, _)|Renamed(_, _), but it's
a bit weird if Copied and Renamed were separate variants. Instead, I decided
to wrap copy metadata in Option.
This patch adds accessor methods as I'm going to change the underlying data
types. Since entry values are consumed separately, these methods are implemented
on CopiesTreeDiffEntryPath, not on *TreeDiffEntry.
Git reports a rename source as deleted if the rename target is excluded. I
think that's because Git restricts the search space to the specified paths. For
example, Git doesn't also recognize a rename if the source path is excluded
whereas jj does.
I don't think we need to copy the exact behavior of Git, so this patch just
moves matcher application to earlier stage. This change will help remove
collect_copied_sources().
The added get_copy_records() helper could be moved to jj_lib, but we'll probably
want a stream version of this function in library, and writing a stream adapter
isn't as simple as iterator.
In this patch, I use the number of adds<->removes alternation as a threshold,
which approximates the visual complexity of diff hunks. I don't think user can
choose the threshold intuitively, but we need a config knob to try out some.
I set `max-inline-alternation = 3` locally. 0 and 1 mean "disable inlining"
and "inline adds-only/removes-only lines" respectively.
I've added "diff.<format>" config namespace assuming "ui.diff" will be
reorganized as "ui.diff-formatter" or something. #3327
Some other metrics I've tried:
```
// Per-line alternation. This also works well, but can't measure complexity of
// changes across lines.
fn count_max_diff_alternation_per_line(diff_lines: &[DiffLine]) -> usize {
diff_lines
.iter()
.map(|line| {
let sides = line.hunks.iter().map(|&(side, _)| side);
sides
.filter(|&side| side != DiffLineHunkSide::Both)
.dedup() // omit e.g. left->both->left
.count()
})
.max()
.unwrap_or(0)
}
// Per-line occupancy of changes. Large diffs don't always look complex.
fn max_diff_token_ratio_per_line(diff_lines: &[DiffLine]) -> f32 {
diff_lines
.iter()
.filter_map(|line| {
let [both_len, left_len, right_len] =
line.hunks.iter().fold([0, 0, 0], |mut acc, (side, data)| {
let index = match side {
DiffLineHunkSide::Both => 0,
DiffLineHunkSide::Left => 1,
DiffLineHunkSide::Right => 2,
};
acc[index] += data.len();
acc
});
// left/right-only change is readable
(left_len != 0 && right_len != 0).then(|| {
let diff_len = left_len + right_len;
let total_len = both_len + left_len + right_len;
(diff_len as f32) / (total_len as f32)
})
})
.reduce(f32::max)
.unwrap_or(0.0)
}
// Total occupancy of changes. Large diffs don't always look complex.
fn total_change_ratio(diff_lines: &[DiffLine]) -> f32 {
let (diff_len, total_len) = diff_lines
.iter()
.flat_map(|line| &line.hunks)
.fold((0, 0), |(diff_len, total_len), (side, data)| {
let l = data.len();
match side {
DiffLineHunkSide::Both => (diff_len, total_len + l),
DiffLineHunkSide::Left => (diff_len + l, total_len + l),
DiffLineHunkSide::Right => (diff_len + l, total_len + l),
}
});
(diff_len as f32) / (total_len as f32)
}
```
Though this is needed only for the last line, checking it for each line is
cheap. As I'm going to add another rendering style, the condition to pad "\n"
would become more complicated.
* We started with a tristate flag where:
- Auto - Maintain current behaviour. This edits if
the wc parent is not a head commit. Else, it will
create a new commit on the parent of the wc in
the direction of movement.
- Always - Always edit
- Never - Never edit, prefer the new+squash workflow.
However, consensus the review thread is that `auto` mode where we try to infer when to
switch to `edit mode`, should be removed. So `ui.movement.edit` is a boolean flag now.
- true: edit mode
- false: new+squash mode
* Also add a `--no-edit` flag as the explicit inverse of `--edit` and
ensure both flags take precedence over the config.
* Update tests that assumed edit mode inference, to specify `--edit` explicitly.
NOTE: #4302 was squashed into this commit, so see that closed PR for review history.
Part of #3947
[VSCodium](https://vscodium.com/) is a free/libre distribution of
Microsoft's Visual Studio Code editor, it's functionally more or less
the same, but distributed under a FOSS license, unlike VS Code.
This adds VSCodium as a merge tool.
I plan to provide a richer version of `TreeDiffEntry` with copy info
(and to make `TreeDiffEntry` itself "poorer"). Most callers want to
know about copies/renames, but at least working copy implementations
probably don't. This patch adds separate `diff_stream()` and
`diff_stream_with_copies()` so we can provide the simpler interface
for callers that don't need copy info.
The tree-level conflicts have worked well in practice and we don't
want to allow users to use legacy trees for new commits. We don't
really support legacy trees very well since 0590f8bece anyway.
* Derive a bunch of standard and useful traits for `movement_util::Direction`
as it is a simple type. Importantly `Copy`.
* Return `&'static str` from Direction.cmd()
* Refactor out `MovementArgs` to reduce the number of arguments
to `movement_util::move_to_commit`.
* Implement `From<&NextArgs/&PrevArgs>` for MovementArgs
Part of #3947
This allows us to select rendering function hunk by hunk. For example, a hunk
with lots of small changes could be rendered without interleaving left/right
words. Another good thing is that context line handling can be simplified as
the whole context hunk is available.
I'm going to split color-words diffs to by_line() and by_word() stages.
Perhaps, Diff::default_refinement() can be removed once all non-test callers
are migrated.
The code in both cli/src/commands/{next,prev}.rs is identical except
for the direction of movement. This commit pull the parts that make
sense out into cli/src/movement_util.rs so it's easier to see the
differences.
Part of #3947
Add gratuitous `jj log` output to more points in the tests.
This makes it easier to understand the intended changes
by literally visualizing the commit tree we are after each movement.
This is at least useful for me since I find the new+squash workflow
confusing.
Test behaviour is not changed.
Part of #3947
I'm thinking of adding some heuristics to render hunks containing lots of
small word changes differently, in a similar manner to the unified diffs. This
patch might help add some pre/post-processing at consumer.
files::diff() is inlined to caller to get around 'self borrowing.
When rebasing a new child commit on top of the moved commit(s), the
order of the new child commit's parent commits is now correctly
preserved if the original parent commit is now a parent of the moved
commit(s).
Closes#3969.
I think they were adding too much noise to commit diffs. Only the tests
focused on skipping rebasing will include the commit and change IDs,
other tests will omit them.
* Add `builtin_immutable_heads()` in the `revsets.toml`.
* Redefine `immutable_heads()` in terms of `builtin_immutable_heads()`
* Warn if user redefines `builtin_immutable_heads()`, `mutable()` or
`immutable()`.
* Update module constant in revset_util.rs from BUILTIN_IMMUTABLE_HEADS
to USER_IMMUTABLE_HEADS to avoid confusion since it points at
`immutable_heads()` **and** we now have a revset-alias
literally named `builtin_immutable_heads()`.
* Add unittest
* Update CHANGELOG
* Update documentation.
Fixes: #4162
- add support for copy tracking to `diff --stat`
- switch `--summary` to match git's output more closely
- rework `show_diff_summary` signature to be more consistent
Add home directory expansion for SSH key filepaths. This allows the
`signing.key` configuration value to work more universally across both
Linux and macOS without requiring an absolute path.
This moved and renamed the previous `expand_git_path` function to a more
generic location, and the prior use was updated accordingly.
- force each diff command to explicitly enable copy tracking
- enable copy tracking in diff_summary
- post-process for diff iterator
- post-process for diff stream
- update changelog
- use a single commit instead of an array of them. This simplifies the
implementation. A higher level api can wrap this when an array of
commits is desired and those semantics are figured out.
- since this API is directly 1-1 on parents, there are no conflicts
- if we introduce a higher level API that handles lists of commits, we
may need to restore the conflict/resolved distinction, but for now
simplify
The "git" command appears to chdir() to the --work-tree directory first, then
read() the core.excludesFile file. There's no manual relative path resolution
in "git".
Fixes#4222
Since "op abandon" just rewrites DAG, it works no matter if the heads are
merged or not. This change will help crash recovery. "op abandon
--at-op=<one-of-the-heads>" can't be used because ancestor operations would be
preserved by the other head.
Suppose a squash node in obslog is analogous to a merge in revisions log, it
makes sense to show diffs from auto-merge (or auto-squash) parents. This
basically means a non-partial squash node no longer shows diffs.
This also fixes missing diffs at the root predecessors if there were.
As the doc comment states, this function only supports change of "a single
added and removed commit", "only a single added", or "single removed commit."
It doesn't make sense to show diffs from the parent commit ignoring multiple
removed commits for example.
I think it might be nice to have this in the upcoming release, but I'd
like to warn people that their changes will be lost if they aren't
careful, and to not rely on the syntax being fixed just yet.
This partially reverts 543036c753 "cli: run 'op log' without loading repo or
merging concurrent ops." User can now get around the issue by --at-op=@
--ignore-working-copy.
The idea is that --at-op specifies a certain operation, so --at-op=@ can be
interpreted as the option to select _the_ known head operation. This helps
eliminate special cases from "op log" which doesn't snapshot nor merge
concurrent ops.
Author dates and committer dates can be filtered like so:
committer_date(before:"1 hour ago") # more than 1 hour ago
committer_date(after:"1 hour ago") # 1 hour ago or less
A date range can be created by combining revsets. For example, to see any
revisions committed yesterday:
committer_date(after:"yesterday") & committer_date(before:"today")
To avoid always printing the rebase instructions to fix a conflict
even when a child commit to fix the conflict already exists, implement
the following:
* If working commit has conflicts:
* Continue printing the same message we print today.
* If working commit has no conflicts:
* If any parent has conflicts, we print: "Conflict in parent is resolved in working copy".
Also explicitly not printing the "conflicting parent" here, since a merge commit
could have conflict in multiple parents.
* If no parent has any conflicts: exit quietly.
* Update unittests for conflict hinting update.
* Update CHANGELOG