Commit graph

2738 commits

Author SHA1 Message Date
Yuya Nishihara
d17166628f revset, templater: simplify parse error impls by using thiserror
This patch moves all "source" errors to the source field to conform to
thiserror API. It will probably help to keep ErrorKind enums comparable.
2024-03-28 10:53:06 +09:00
Yuya Nishihara
2cd70bdf14 revset, templater: render parse error as usual error chain
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.
2024-03-28 10:53:06 +09:00
Yuya Nishihara
844d3d0ff0 revset, templater: allow any kind of error as parse error source
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.
2024-03-28 10:53:06 +09:00
Yuya Nishihara
32efb4034d revset: make span of parse error mandatory, remove Option<_>
Since all callers of RevsetParseError have some reasonable span, we don't
need a special case for WorkingCopyWithoutWorkspace error.
2024-03-28 10:53:06 +09:00
Yuya Nishihara
8ad0a703d4 repo_path: accept from_relative_path("."), make "".to_fs_path("") return "."
It's common to normalize an empty directory path as ".". This change unblocks
the use of from_relative_path() in edit_sparse().

There are a couple of callers who do to_fs_path(Path::new("")), but they all
translate non-directory paths, which should never be empty.
2024-03-28 10:52:51 +09:00
Martin von Zweigbergk
9c382fd8c6 rewrite: exclude already rewritten commits from set to rebase
We currently include the commits in `parent_mapping` and `abandoned`
in the set of commits to visit when rebasing descendants. The reason
was that we used to update branches and working copies when we visited
these commits. Since we started updating refs after rebasing all
commits, there's no need to even visit these commits.
2024-03-26 09:50:50 -07:00
Martin von Zweigbergk
49ff818e97 rewrite: calculate branches later, remove it from state 2024-03-26 09:50:50 -07:00
Martin von Zweigbergk
718e54b01a rewrite: calculate heads_to_add later, remove it from state
Similar to the previous two commits.
2024-03-26 09:50:50 -07:00
Martin von Zweigbergk
2ee1147145 rewrite: calculate heads_to_remove later, remove it from state
Similar to the previous commit.
2024-03-26 09:50:50 -07:00
Martin von Zweigbergk
b3dd038907 rewrite: calculate new_commits later, remove it from state
We only use `new_commits` in `update_heads()`, so let's calculate it
there. It should also be more correct in case other commits were
created after we initialized `DescendantRebaser`.
2024-03-26 09:50:50 -07:00
Martin von Zweigbergk
5e7a4a2028 rewrite: update heads outside update_references()
Now that we only call `update_references()` in one place, there's no
reason to have it also update `heads_to_add` and `heads_to_remove`. By
moving it out of the function, we can consolidate the logic in one
place.
2024-03-26 09:50:50 -07:00
Martin von Zweigbergk
9511de486e rewrite: extract a function for updating heads 2024-03-26 09:50:50 -07:00
Martin von Zweigbergk
0f7a86d725 rewrite: move new_parents() to MutableRepo
The function only uses state from `MutableRepo`, so it should be
implemented on that type.
2024-03-26 09:50:50 -07:00
Martin von Zweigbergk
cfdb341c6b rewrite: make rebase_commit_with_options() mark abandoned commit
When `rebase_commit_with_options()` decides to abandons a commit, it
records the new parents in the `MutableRepo`, but it's currently the
caller's responsibility to remember to mark it as abandoned. Let's
move that logic into the function to reduce the risk of future bugs.
2024-03-26 09:50:50 -07:00
Martin von Zweigbergk
3ddf9f4329 repo: add parents of abandoned commit to parent_mapping
By adding the abandoned commit's parents to `parent_mapping`, we can
remove a bit more of the special handling of abandoned commitsin
`DescendantRebaser`.
2024-03-26 09:50:50 -07:00
Martin von Zweigbergk
0481e67dfd rewrite: drop now-unnecessary updating of branches map
Since we update all branches at the end now, we never update them in
several steps, so there are no intermediate locations we need to
remember.
2024-03-25 23:00:44 -07:00
Martin von Zweigbergk
5e8d7f8c6f rewrite: update references after rewriting all commits 2024-03-25 23:00:44 -07:00
Martin von Zweigbergk
e55ebd4fe6 rewrite: drop redundant update of parent_mapping after rebasing commit
In the normal case when we don't abandon a commit because it became
empty, then `CommitBuilder::write()` will have recorded the new commit
as a rewrite of the old commit. We don't need to do that again in
`rebase_one()`.
2024-03-25 23:00:44 -07:00
Martin von Zweigbergk
4406005dce rewrite: make DescendantRebaser use state stored in MutableRepo
A subset of the state in `DescendantRebaser` now matches exactly what
`MutableRepo` already stores, so we can avoid copying that state and
have `DescendantRebaser` use it directly instead. Having a single
source of truth for the state will enable further simplifications and
improvements.
2024-03-25 23:00:44 -07:00
Martin von Zweigbergk
ad16bec3a6 rewrite: move an assertion a little earlier
I'm going to make `DescendantRebaser` share the state about rewritten
commits with `MutableRepo` next. That means that the call to
`rebase_commit_with_options()` will update that state, which would
make this assertion fail. So let's move it a little earlier to avoid
that.
2024-03-25 23:00:44 -07:00
Martin von Zweigbergk
a6857a7a8f repo: rename abandoned_commits to abandoned
This is just to match `DescendantRebaser`, to make the next commit a
bit simpler. I think `MutableRepo` still has few enough fields that
just `abandoned` is clear enough. Maybe we'll move the three
rewrite-related fields into a new struct at some point.
2024-03-25 23:00:44 -07:00
Martin von Zweigbergk
6e3ceb4d1c repo: store separate divergent field, pass into DescendantRebaser
With this patch, `MutableRepo` has the same tracking of rewritten
commits as `DescendantRebaser`, so we can simply pass that state into
`DescendantRebaser` when we create it. The next step is to remove the
state from `DescendantRebaser`.
2024-03-25 23:00:44 -07:00
Ilya Grigoriev
de0de4013d hex_utils: fix typo found by clippy 2024-03-25 21:23:09 -07:00
Martin von Zweigbergk
890a8e282f repo: update working copy to first divergent commit 2024-03-25 06:53:14 -07:00
Martin von Zweigbergk
d2043f069e repo: delete record_rewritten_commit()
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.
2024-03-25 06:53:14 -07:00
Martin von Zweigbergk
e55168fa3e repo: make record_rewritten_commit() accept only one replacement id
All callers now pass a single new commit and I would like to keep it
that way.
2024-03-25 06:53:14 -07:00
Martin von Zweigbergk
af7ef4d04e repo: add a method for explicitly recording divergent rewrite
I plan to remove `record_rewritten_commit()` and instead make repeated
rewrites replace the rewrite state.
2024-03-25 06:53:14 -07:00
Martin von Zweigbergk
b54ace4954 rewrite: mark divergent commits in parent_mapping too
When rebasing descendants, we generally move branches, child commits,
the working copy to the rewritten commit(s). However, we don't move
the working copy to the new rewritten commit (s) if the old commit had
been abandoned, and we don't move child commits if the rewriten was
divergent.

This patch aims to make it clearer that there's only one mapping from
old to new parents, and that is in `parent_mapping`. It does so by
merging the current `divergent` map into it, and makes the `divergent`
just a set instead. When finding the new parents for a child, we leave
the existing parent if it's in the set.

My longer-term goal is to move `parent_mapping`, `abandoned`, and
`divergent` into `MutableRepo` (maybe in a nested struct), so we can
do some transformations on descendants as we rebase them. By having
the state in a single place (not moving it from `MutableRepo` to
`DescendantRebaser` as we currently do), I hope it will be easier to
write a `MutableRepo::transform_descendants(callback)`, where the
callback gets a `CommitBuilder` and can change parents of the commit,
for example.
2024-03-25 06:53:14 -07:00
Martin von Zweigbergk
ba244423e8 rewrite: avoid an unnecessary clone 2024-03-25 06:53:14 -07:00
Yuya Nishihara
c311131ee2 log: encode elided node as None
Since elided graph entry has no associated commits, it makes some sense to
represent as None?
2024-03-24 10:32:15 +09:00
Benjamin Tan
3034dbba3f git-push: Display messages from remote
The implementation of sideband progress message printing is aligned with
Git's implementation. See
43072b4ca1/sideband.c (L178).

Closes #3236.
2024-03-23 20:17:04 +08:00
Ilya Grigoriev
02a04d0d37 test_conflicts and test_resolve_command: use indoc! to indent conflict markers in tests
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`.
2024-03-22 23:27:25 -07:00
Anton Älgmyr
e2eb5bddf9 Make node symbols templatable in the graphs.
Adds config options
* templates.log_graph_node
* templates.log_graph_node_elided
* templates.op_log_graph_node
2024-03-21 17:41:31 +01:00
dploch
9380f9d529 rewrite: move handling of simplified ancestry into rebase_commit_with_options
It seems incorrect that `simplify_ancestor_merge` is ignored when it's part of the helper's input.
2024-03-20 11:57:54 -04:00
Ilya Grigoriev
4fbe6aecc9 clippy: remove some unused code beta clippy/rustc compain about
There are still some warnings from (seemingly) clippy bugs. Quoting
myself from Discord:

> PSA: the latest beta cargo clippy (from Rust 1.78) has some problems
> that affect jj: https://github.com/rust-lang/rust-clippy/issues/12467
> and https://github.com/rust-lang/rust-clippy/issues/12377.  You could
> disable clippy::assigning_clones and clippy::empty_docs as a workaround.
> VS Code can disable them in rust-analyzer, you can also use
> https://github.com/ericseppanen/cargo-cranky (you can put Cranky.toml in
> the per-user gitignore).
2024-03-19 18:33:29 -07:00
Martin von Zweigbergk
f865c1bc5d index: print a milder "Reindexing..." message on version mismatch
Closes #3323.
2024-03-18 13:50:14 -07:00
Yuya Nishihara
50363419fb revset: substitute '~(::x)' to 'x..'
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.
2024-03-17 14:50:48 +09:00
Yuya Nishihara
9207314173 revset: add substitution rule for "::x & ~(::y-)"
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'.
2024-03-17 14:50:48 +09:00
Yuya Nishihara
39a460a077 revset: extract helper function that substitutes "::x & ~(::y)"
I'm going to add a similar substitution rule for "~(::y)".
2024-03-17 14:50:48 +09:00
Yuya Nishihara
3f9ac78215 revset: update legacy range syntax in comment 2024-03-17 14:50:48 +09:00
Yuya Nishihara
a777cfe98e index: remove topo_order() which is no longer used
The same thing can be achieved by evaluating the input as a revset.
2024-03-17 11:44:41 +09:00
Martin von Zweigbergk
c55e08023e workspace: don't lose sparsed-away paths when recovering workspace
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.
2024-03-16 07:30:36 -07:00
Alexis (Poliorcetics) Bourget
93c707a469 lib: improve error message for invalid string pattern, suggesting to use one of the known one 2024-03-16 14:22:16 +01:00
Evan Mesterhazy
f30857190e Add more test cases for Index::common_ancestors 2024-03-14 12:54:13 -04:00
Evan Mesterhazy
adaedd5556 Add documentation to lib/src/index.rs and lib/src/default_index/ 2024-03-14 12:54:13 -04:00
Yuya Nishihara
5806dbfd32 revset_graph: detach CompositeIndex, reimplement as RevWalk
For API consistency. It wouldn't practically matter unless we want to reuse
.iter_graph() in lazy event-driven GUI context.

I don't see significant performance difference:
- jj-0: original impl with look-ahead IndexEntry<'_> buffer
- jj-1: this patch

With dense graph
```
% hyperfine --sort command --warmup 3 --runs 10 -L bin jj-0,jj-1 \
  "target/release-with-debug/{bin} -R ~/mirrors/git --ignore-working-copy log -r.. -T ''"
Benchmark 1: target/release-with-debug/jj-0 -R ~/mirrors/git --ignore-working-copy log -r.. -T ''
  Time (mean ± σ):      1.367 s ±  0.008 s    [User: 1.261 s, System: 0.105 s]
  Range (min … max):    1.357 s …  1.380 s    10 runs

Benchmark 2: target/release-with-debug/jj-1 -R ~/mirrors/git --ignore-working-copy log -r.. -T ''
  Time (mean ± σ):      1.344 s ±  0.017 s    [User: 1.245 s, System: 0.099 s]
  Range (min … max):    1.313 s …  1.369 s    10 runs

Relative speed comparison
        1.02 ±  0.01  target/release-with-debug/jj-0 -R ~/mirrors/git --ignore-working-copy log -r.. -T ''
        1.00          target/release-with-debug/jj-1 -R ~/mirrors/git --ignore-working-copy log -r.. -T ''
```

With sparse graph
```
% hyperfine --sort command --warmup 3 --runs 10 -L bin jj-0,jj-1 \
  "target/release-with-debug/{bin} -R ~/mirrors/git --ignore-working-copy log -r'tags()' -T ''"
Benchmark 1: target/release-with-debug/jj-0 -R ~/mirrors/git --ignore-working-copy log -r'tags()' -T ''
  Time (mean ± σ):      1.347 s ±  0.017 s    [User: 1.216 s, System: 0.130 s]
  Range (min … max):    1.321 s …  1.379 s    10 runs

Benchmark 2: target/release-with-debug/jj-1 -R ~/mirrors/git --ignore-working-copy log -r'tags()' -T ''
  Time (mean ± σ):      1.379 s ±  0.023 s    [User: 1.238 s, System: 0.140 s]
  Range (min … max):    1.328 s …  1.403 s    10 runs

Relative speed comparison
        1.00          target/release-with-debug/jj-0 -R ~/mirrors/git --ignore-working-copy log -r'tags()' -T ''
        1.02 ±  0.02  target/release-with-debug/jj-1 -R ~/mirrors/git --ignore-working-copy log -r'tags()' -T ''
```
2024-03-14 10:07:19 +09:00
Yuya Nishihara
3c8f22456b revset_graph: remove lifetimed IndexEntry<'_> from look_ahead buffer
Prepares for removing &CompositeIndex from the RevsetGraphIterator struct.
The input iterator will also be changed to position-based.

I've turned self.look_ahead.get().unwrap() into assertion, but it's not super
important here. It's just for sanity that we've mapped missing edges properly.
FWIW, we could say RevsetGraphIterator is an example of iterating *and* testing
membership of the input revset (though the yielded entries are discarded.)
2024-03-14 10:07:19 +09:00
Yuya Nishihara
699707905c index: reorganize revset_graph_iterator as private module of default_index
The RevsetGraphIterator type is hidden so that the Iterator trait can be
implemented differently.
2024-03-14 10:07:19 +09:00
Yuya Nishihara
17e46e0932 revset: extend lifetime of CommitId/ChangeId iterators
For the same reason as the previous commit. Since self.inner.positions()
basically clones the underlying evaluation tree, there is no reason to stick
to &self lifetime. Perhaps, some of the CLI utility can be changed to not
collect() the iterator.

Migrating iter_graph() requires non-trivial changes, so it will be done
separately.
2024-03-13 10:47:58 +09:00
Yuya Nishihara
3bf41d0c52 revset: extend lifetime of containing_fn()
This allows callers to cache the returned function at 'index lifetime. It's
important in templater. It also means the returned function could be 'static
if the index were Arc<_> and we had a trait interface to achieve that.

Option<Box<dyn ..>> is removed since RevWalk is fused.
2024-03-13 10:47:58 +09:00