ok/jj
1
0
Fork 0
forked from mirrors/jj
Commit graph

2879 commits

Author SHA1 Message Date
Yuya Nishihara
7d43a5c2c0 tests: alias index.as_composite() in revset combinator/accumulator tests 2024-03-12 20:59:38 +09:00
Aleksey Kuznetsov
6fd15dc7e5 graphlog: refactor out node symbols from GraphLog
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.
2024-03-12 08:25:58 +05:00
Yuya Nishihara
9c1d5d155e index: remove HRTB stuff by implementing RevWalkIndex for CompositeIndex 2024-03-11 17:24:10 +09:00
Yuya Nishihara
3d0952b316 index: implement AsCompositeIndex for CompositeIndex, not for &CompositeIndex
Just a minor code cleanup. We still need Index for &CompositeIndex because the
type is unsized, and unsized type cannot be converted to another dyn reference.
2024-03-11 17:24:10 +09:00
Yuya Nishihara
243675b793 index: turn CompositeIndex into transparent reference type
This helps to eliminate higher-ranked trait bounds from RevWalkRevset and
RevWalk combinators to be added. Since &CompositeIndex is now a real reference,
it can be passed to functions as index: &T.
2024-03-11 17:24:10 +09:00
Yuya Nishihara
c8be8c3edd index: add type alias for "dyn IndexSegment" to clarify it's 'static
This helps to migrate CompositeIndex<'_> wrapper to &CompositeIndex. If
the wrapped reference had a lifetimed field, it couldn't be represented as
a trivial reference type.
2024-03-11 17:24:10 +09:00
Yuya Nishihara
64e0be2477 revset: consolidate early-return condition of PositionsAccumulator
Since consume_to() checks the bottom position yielded from the source iterator,
it makes sense to add the same check for the cached positions.
2024-03-11 17:24:01 +09:00
Martin von Zweigbergk
4d42604913 git_backend: write trees involved in conflict in git commit header
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.
2024-03-10 20:51:05 -07:00
Aleksey Kuznetsov
cd3d75ebf6 revset: introduce more performant way to check if a commit is in a revset
Initially we were thinking to have `Revset` return something like
`CachedRevset`:

```
pub trait CachedRevset {
  fn iter(&self) -> Box<dyn Iterator<Item = Commit>>;
  fn contains(&self, &CommitId) -> bool;
}
```

But we weren't sure what use case for `iter` would be, so we dropped the `iter`
method. `CachedRevset` with single `contains` method needed a better name. We
weren't able to come up with one, so we decided instead to have a method on
`Revset` that returns a closure to check if a commit is in a revset.
2024-03-11 08:27:35 +05:00
Yuya Nishihara
8a406358af index: migrate RevWalkRevset to be based off new RevWalk trait
"for<'index> RevWalk<CompositeIndex<'index>, .." works as of now, but it won't
be composed well. So I'll turn CompositeIndex<'_> into &CompositeIndex in the
next batch, and remove "for<'index>".
2024-03-11 11:25:54 +09:00
Yuya Nishihara
4107cad80e index: migrate RevWalkDescendants to new RevWalk trait
Just for consistency. Descendants are always evaluated eagerly, so this change
isn't strictly needed.
2024-03-11 11:25:54 +09:00
Yuya Nishihara
b6cbd8b90b index: add trait and adaptor types to detach index from RevWalk*
This eliminates lifetimed fields from RevWalk objects, and the RevWalk object
will be embedded directly in RevWalkRevset.

This patch adds two separate iterator adapters. They are identical at this
point, but I'm going to add detach/reattach methods only to the borrowed
version. I'm also planning to change CompositeIndex<'_> to &CompositeIndex
to get around higher-ranked trait bound restrictions.
2024-03-11 11:25:54 +09:00
Yuya Nishihara
d780910bec index: make RevWalk yield IndexPosition instead of IndexEntry
This simplifies the RevWalkIndex API. It would probably add fractional msecs of
overhead per next() call, but I don't see significant difference in revset
benches.
2024-03-11 11:25:54 +09:00
Anton Älgmyr
099f06bf71 Add configuration options for node symbols in the graphs. 2024-03-09 21:16:58 +01:00
Yuya Nishihara
f51c5d7e57 index: consistently use IntoIterator in RevWalk builder API
Since the return type is no longer "impl Iterator<..>", there isn't lifetime
issue anymore.
2024-03-10 01:45:30 +09:00
Yuya Nishihara
2615fed5be index: handle cut-off position of RevWalk by queue
I'm going to make CompositeIndex<'_> detachable from the RevWalk, and
"F: Fn(CompositeIndex) -> Box<dyn Iterator<..>>" of RevWalkRevset<F> will
be replaced with "W: RevWalk<CompositeIndex>". This will simplify the code
structure, but also means that we can no longer apply .take_while() here and
convert it back to RevWalk. Fortunately, ancestors_until_roots() is the only
function I need to reimplement.
2024-03-10 01:45:30 +09:00
Yuya Nishihara
34fbaaaad6 index: construct RevWalk queue after item type is settled
It doesn't make sense to build BinaryHeap with intermediate type, and I'm
going to reimplement take_until_roots() in a way that the queue drops
uninteresting items.
2024-03-10 01:45:30 +09:00
Yuya Nishihara
8480ee9e05 index: migrate RevWalk constructors to builder API
The current RevWalk constructors insert intermediate items to BinaryHeap
and convert them as needed. This is redundant, and I'm going to add another
parameter that should be applied to the queue first. That's why I decided
to factor out a builder type. I considered adding a few set of factory
functions that receive all parameters, but they looked messy because most of
the parameters are of [IndexPosition] type.

This patch also adds must_use to the builder and its return types, which are
all iterator-like.
2024-03-10 01:45:30 +09:00
Yuya Nishihara
008adecf23 index: rename ancestors iterators from RevWalk* to RevWalkAncestors*
I'm planning to add RevWalk trait, and this patch frees up the name. It seems
also good for consistency as we have RevWalkDescendants*.
2024-03-10 01:45:30 +09:00
Yuya Nishihara
fa60026f25 repo_path: don't panic on invalid UTF-8 path component
Although watchman client appears to fail at decoding non-UTF-8 path (somewhere
in serde), jj shouldn't panic if watchman could deal with that.

The outer error message "path not in the repo" would sounds odd, but I think
that's okay because 1. it's unlikely that a user input is not UTF-8, and 2.
it's technically correct that a non-UTF-8 path is not contained in the repo.
2024-03-09 11:01:43 +09:00
Yuya Nishihara
a224d0f172 repo_path: show more detailed error if filesystem path failed to parse
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
2024-03-09 11:01:43 +09:00
Yuya Nishihara
a76f716cd1 index: remove RevWalk newtypes that were necessary to hide impl types/traits
Some of the RevWalk methods could be generalized, but I decided to not try that
for now. I'll probably need to do more cleanup to (hopefully) remove 'index
lifetime from these types.
2024-03-08 10:07:40 +09:00
Yuya Nishihara
8451453f3a index: hide walk_revs() and related types
They are now implementation details of the default index backend.
2024-03-08 10:07:40 +09:00
Yuya Nishihara
f5eb172769 tests: remove last use of walk_revs() from integration tests 2024-03-08 10:07:40 +09:00
Martin von Zweigbergk
5ce5022ee9 cargo: mark the jj-lib-proc-macros crate for publish
I don't think we can publish a new version of the other crates without
publishing `jj-lib-proc-macros`.
2024-03-06 20:35:38 -08:00
Thomas Castiglione
d661f59f9d working_copy: implement symlinks on windows with a helper function
enables symlink tests on windows, ignoring failures due to disabled developer mode,
and updates windows.md
2024-03-05 15:16:38 +08:00
Austin Seipp
bd551099f0 cargo: update whoami dependency to 1.5.0
This requires a code tweak to avoid clippy failures, as `whoami` 1.5.0 has
deprecated the default `hostname()` function.

Signed-off-by: Austin Seipp <aseipp@pobox.com>
2024-03-04 18:35:21 -06:00
Yuya Nishihara
c8023dbd8b signing: insert tracing events to command invocation paths
This might help debug command failure.
2024-03-05 09:23:15 +09:00
Yuya Nishihara
fa7864edeb signing: ensure child processes are wait()ed on I/O error
This will also provide a better error indication. If write() failed, the child
process would presumably have exited with non-zero status and error message to
stderr.
2024-03-05 09:23:15 +09:00
Evan Mesterhazy
a09ee4b9a3 Make URLs in docs hyperlinks
`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.
2024-03-04 16:05:42 -05:00
Yuya Nishihara
24868e5192 gpg_signing: handle early termination of gpg command in verify path
Also fixes missing wait() on I/O error. We have the same problem in several
places. I'll fix them in another batch.
2024-03-03 18:35:10 +09:00
Yuya Nishihara
a0c31134ba gpg_signing: split run_command() into sign/verify variants 2024-03-03 18:35:10 +09:00
Yuya Nishihara
093f61607e gpg_signing: leverage Command builder API to eliminate type casting noises 2024-03-03 18:35:10 +09:00
Yuya Nishihara
dbe99c8fe0 gpg_signing: extract bottom half of run() to helper function
I'll split it further to fix EPIPE handling.
2024-03-03 18:35:10 +09:00
Evan Mesterhazy
ff4a5aa491 Store OpHeadsStore in UnpublishedOperation instead of RepoLoader
The only thing we need from the `RepoLoader` is the `OpHeadsStore`, so we can
extract it in UnpublishedOperation::new instead of keeping the entire
`RepoLoader` around.
2024-03-02 23:08:57 -05:00
Evan Mesterhazy
1439c902be Replace NewRepoData with ReadonlyRepo in the UnpublishedOperation struct
`NewRepoData` is just a container that holds data used to construct a
`ReadonlyRepo`. The `ReaonlyRepo` is always constructed before the
`UnpublishedOperation` is dropped, so we can simply construct the
`ReadonlyRepo` upfront and delete the `NewRepoData` type.
2024-03-02 23:08:57 -05:00
Evan Mesterhazy
c4cbf25545 Remove the std::Option around UnpublishedOperation::data
The Option is unnecessary now since `UnpublishedOperation` doesn't implement
the Drop trait (the `MustClose` member implements it instead).
2024-03-02 23:08:57 -05:00
Evan Mesterhazy
962b188b76 Replace custom Drop impl for UnpublishedOperation with #[must_use]
The custom Drop impl prevents us from moving members of UnpublishedOperation,
and is the reason why `NewRepoData` is wrapped in an `Option`. We don't use
custom Drop functions like this for debugging elsewhere in the codebase, and in
some ways #[must_use] provides better protection since it will typically cause
a compiler error if the UnpublishedOperation isn't used.
2024-03-02 23:08:57 -05:00
Evan Mesterhazy
6ee19589e9 Adjust visibility of codependent MutableRepo and CommitBuilder functions
MutableRepo and CommitBuilder both define public (now crate-public) functions
which should only be called by each other. This commit adds documentation and
restricts visibility of these functions to the jj_lib crate. It might be even
better to move CommitBuilder to the same module as MutableRepo so that these
codependent functions can be private to the module to avoid misuse.
2024-03-02 22:41:47 -05:00
Ilya Grigoriev
96bf190234 Nightly clippy fixes
There are a few additional warnings because of
https://github.com/rust-lang/rust-clippy/issues/12377, which is a
nightly-only bug that will hopefully be fixed.
2024-03-02 18:19:14 -08:00
Evan Mesterhazy
2f7b15b7b1 Add documentation comments for operation, transaction, and view types 2024-03-02 15:35:41 -05:00
Evan Mesterhazy
a335321c45 Add documentation comments for several types
These comments are intended to make it easier for new developers to get up to
speed with the project. This is just a starting point... there are other types
and functions that could benefit from documentation.
2024-03-02 15:01:55 -05:00
Evan Mesterhazy
b8aa9a1a2b Make a minor simplification to CommitBuilder::write
There's no need to have a block of code at the beginning of the function to
cache the rewrite source id. We can simply check the necessary condition before
calling record_rewritten_commit.

This tweak makes the function a little easier to read since we don't check the
condition until we're ready to do the work.
2024-03-02 13:40:18 -05:00
Evan Mesterhazy
276276ea01 Reorder functions in impl Repo for MutableRepo to match trait
This is just a clean-up to silence a lint that complains that the functions are
defined in a different order than they are in the trait.
2024-03-02 13:40:04 -05:00
Yuya Nishihara
5df7a42915 merge_tools: move "ui.diff-instructions" to CLI and config/misc.toml
There are no users of this option in jj-lib. Let's simplify it.
2024-03-02 23:33:45 +09:00
Evan Mesterhazy
5c252bd8e4 Add test cases where HexPrefix::new fails due to invalid inputs 2024-03-01 10:00:22 -05:00
Yuya Nishihara
4c16c05be1 cli: move --git-repo path normalization back from workspace
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.
2024-02-28 09:03:16 +09:00
Evan Mesterhazy
a28beb5b8f Allow id_type! to capture doc comments
This allows us to define documentation comments for types implemented using the
id_type! macro. Comments defined above the type inside the macro will be
captured and visible in generated docs.

Example:

```
id_type!(
    /// Stable identifier for a [`Commit`]. Unlike the `CommitId`, the `ChangeId`
    /// follows the commit and is not updated when the commit is rewritten.
    pub ChangeId
);
```

This commit also adds documentation for the `CommitId` and `ChangeId` types
defined using the `id_type!` macro.
2024-02-27 10:37:05 -05:00
Yuya Nishihara
ef9d22887c tests: disable gpg unknown_key() test on Windows as well
Follows up 7552f939c6 "tests: disable most gpg integration tests on Windows."
I couldn't find this test failing in a few samples before, but it does now.
2024-02-27 00:55:06 +09:00
Martin von Zweigbergk
1cbf2b4acf rewrite: allow working-copy to be abandoned
This removes the special handling of the working-copy commit. By
recording when an empty/emptied commit was abanoned, we rebase
descendants correctly and create a new empty working-copy commit on
top.
2024-02-25 16:39:05 -08:00
Martin von Zweigbergk
3bc3a63411 rewrite: move decision about abandoned commit into update_references() 2024-02-25 16:39:05 -08:00
Yuya Nishihara
7552f939c6 tests: disable most gpg integration tests on Windows
These tests often stuck on Windows CI for unknown reasons. Let's mark them
ignored for the moment. The unknown_key test is allowed because it somehow
appears to pass.

https://github.com/martinvonz/jj/actions/runs/8009950119/job/21879789008?pr=3123#step:7:1487

#3140
2024-02-25 17:07:05 +09:00
Yuya Nishihara
e588a9babc backend: allow cheap copy of MillisSinceEpoch(i64)
It's unlikely this type will become uncopyable.
2024-02-25 09:00:56 +09:00
Yuya Nishihara
ebf90384f6 operation: add shorthand for .store_operation().metadata 2024-02-25 09:00:56 +09:00
Yuya Nishihara
a67aa08995 gitignore: make objects chain be more Arc friendly
This partially reverts changes in a9f489ccdf "Switch to ignore crate for
gitignore handling." Since child ignore object no longer needs to access the
root to resolve the prefix path, it's simpler to store a matcher per node.
2024-02-24 15:55:10 +09:00
Yuya Nishihara
febae9f9e8 gitignore: fix prefix handling when chaining .gitignore in sub directory
The prefix is relative to the root, not to the parent .gitignore file.

Fixes #3126
2024-02-24 15:55:10 +09:00
Yuya Nishihara
2f25848883 gitignore: update file ordering test to not use relative path in patterns
With the current implementation, the file3 pattern is set to the prefix
"foo/foo/bar". I don't know if (unrooted) "baz" prefixed with "foo/foo/bar"
should match "foo/bar/baz", but apparently it is. Anyway, that wouldn't be
the case in practice because adjacent .gitignore files shouldn't be loaded.
2024-02-24 15:55:10 +09:00
Yuya Nishihara
073310547c operation: make Operation object cheaply clonable
We do clone Operation object in several places, and I'm going to add one more
.clone() in the templater. Since the underlying metadata has many fields, I
think it's better to wrap it with Arc just like a Commit object.
2024-02-23 10:13:25 +09:00
Yuya Nishihara
62f0cb8c3f cli: change default log revset to not include all tagged heads
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
2024-02-23 00:25:58 +09:00
Yuya Nishihara
f21c078249 revset: ad-hoc optimization for range queries containing unwanted wanted heads
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
2024-02-22 23:26:29 +09:00
Yuya Nishihara
f71f065b17 revset: rename InternalRevset::iter() to ::entries() 2024-02-22 23:26:29 +09:00
Yuya Nishihara
1572c251ef revset: add positions() iterator to InternalRevset
I just wanted to clean up the callers, but this might also be marginally
faster.
2024-02-22 23:26:29 +09:00
Yuya Nishihara
33c7e18ac8 revset: flip ordering of generic combination iterators
As a general-purpose iterator combinator, ascending order makes more sense.
2024-02-22 23:26:29 +09:00
Yuya Nishihara
22933563e8 revset: extract generic combination iterators
I'm going to add pre-filtering to the 'roots..heads' evaluation path, and
difference_by() will be used there to calculate 'heads ~ roots'.

Union and intersection iterators are slightly changed so that all iterators
prioritize iter1's item.
2024-02-22 23:26:29 +09:00
Julien Vincent
f97e929cbf sign: Skip gpg tests if gpg is not installed
This adds a guard to the gpg signing tests which will skip the test if
`gpg` is not installed on the system.

This is done in order to avoid requiring all collaborators to have setup
all the tools on their local machines that are required to test commit
signing.
2024-02-21 13:22:53 +00:00
Yuya Nishihara
9f05aa8c46 tests: fix fun typo "singing" -> "signing" 2024-02-21 22:04:41 +09:00
Yuya Nishihara
e3d2ff2b75 signing: change default gpg program, add --keyid-format option accordingly
This is the default of Git, and Debian sid doesn't install the gpg2 symlink
by default.

https://github.com/git/git/blob/v2.43.2/gpg-interface.c#L92
https://github.com/martinvonz/jj/pull/3007#discussion_r1496877808
https://packages.debian.org/bookworm/gnupg2
2024-02-21 22:04:41 +09:00
Austin Seipp
6c31bab0d3 fsmonitor: allow core.fsmonitor = "none" to disable
When doing things like testing snapshot performance differences,
this allows you to turn off the monitor, no matter what the enabled
user or repository configuration has, e.g.

    jj st --config-toml='core.fsmonitor="none"'

Signed-off-by: Austin Seipp <aseipp@pobox.com>
2024-02-20 20:19:47 -06:00
Evan Mesterhazy
79518eafce Output better error messages when deriving ContentHash for an enum fails
Consider this code:
```
struct NoContentHash {}

#[derive(ContentHash)]
enum Hashable {
    NoCanHash(NoContentHash),
    Empty,
}
```

Before this commit, it generates an error like this:
```
error[E0277]: the trait bound `NoContentHash: ContentHash` is not satisfied
   --> lib/src/content_hash.rs:150:10
    |
150 | #[derive(ContentHash)]
    |          ^^^^^^^^^^^ the trait `ContentHash` is not implemented for `NoContentHash`
151 | enum Hashable {
152 |     NoCanHash(NoContentHash),
    |     --------- required by a bound introduced by this call
    |
    = help: the following other types implement trait `ContentHash`:
              bool
              i32
              i64
              u8
              u32
              u64
              std::collections::HashMap<K, V>
              BTreeMap<K, V>
            and 35 others

For more information about this error, try `rustc --explain E0277`.
```

After this commit, it generates a better error message:
```
error[E0277]: the trait bound `NoContentHash: ContentHash` is not satisfied
   --> lib/src/content_hash.rs:152:15
    |
152 |     NoCanHash(NoContentHash),
    |               ^^^^^^^^^^^^^ the trait `ContentHash` is not implemented for `NoContentHash`
    |
    = help: the following other types implement trait `ContentHash`:
              bool
              i32
              i64
              u8
              u32
              u64
              std::collections::HashMap<K, V>
              BTreeMap<K, V>
            and 35 others

For more information about this error, try `rustc --explain E0277`.
error: could not compile `jj-lib` (lib) due to 1 previous error
```

It also works for enum variants with named fields:
```
error[E0277]: the trait bound `NoContentHash: ContentHash` is not satisfied
   --> lib/src/content_hash.rs:152:23
    |
152 |     NoCanHash { named: NoContentHash },
    |                       ^^^^^^^^^^^^^ the trait `ContentHash` is not implemented for `NoContentHash`
    |
    = help: the following other types implement trait `ContentHash`:
              bool
              i32
              i64
              u8
              u32
              u64
              std::collections::HashMap<K, V>
              BTreeMap<K, V>
            and 35 others

For more information about this error, try `rustc --explain E0277`.
```
2024-02-20 16:29:25 -05:00
Evan Mesterhazy
e8f324ffde Replace uses of content_hash! with #[derive(ContentHash)]
This is a pure refactor with no behavior changes.

#3054
2024-02-20 14:18:13 -05:00
Evan Mesterhazy
966a5505e2 Add support for deriving ContentHash for Enums
Here's an example of what the derived output looks like for an enum:

```rust
pub enum TreeValue {
    File { id: FileId, executable: bool },
    Symlink(SymlinkId),
    Tree(TreeId),
    GitSubmodule(CommitId),
    Conflict(ConflictId),
}
#[automatically_derived]
impl ::jj_lib::content_hash::ContentHash for TreeValue {
    fn hash(&self, state: &mut impl digest::Update) {
        match self {
            Self::File { id, executable } => {
                state.update(&0u32.to_le_bytes());
                ::jj_lib::content_hash::ContentHash::hash(id, state);
                ::jj_lib::content_hash::ContentHash::hash(executable, state);
            }
            Self::Symlink(field_0) => {
                state.update(&1u32.to_le_bytes());
                ::jj_lib::content_hash::ContentHash::hash(field_0, state);
            }
            Self::Tree(field_0) => {
                state.update(&2u32.to_le_bytes());
                ::jj_lib::content_hash::ContentHash::hash(field_0, state);
            }
            Self::GitSubmodule(field_0) => {
                state.update(&3u32.to_le_bytes());
                ::jj_lib::content_hash::ContentHash::hash(field_0, state);
            }
            Self::Conflict(field_0) => {
                state.update(&4u32.to_le_bytes());
                ::jj_lib::content_hash::ContentHash::hash(field_0, state);
            }
        }
    }
}
```


#3054
2024-02-20 12:59:35 -05:00
Evan Mesterhazy
8e1a6c708f Add support for generics to #[derive(ContentHash)]
#3054
2024-02-20 12:48:25 -05:00
Daehyeok Mun
a9f489ccdf Switch to ignore crate for gitignore handling.
Co-authored-by: Waleed Khan <me@waleedkhan.name>
2024-02-20 09:12:46 -08:00
Evan Mesterhazy
965d6ce4e4 Implement a procedural macro to derive the ContentHash trait for structs
This is a no-op in terms of function, but provides a nicer way to derive the
ContentHash trait for structs using the `#[derive(ContentHash)]` syntax used
for other traits such as `Debug`.

This commit only adds the macro. A subsequent commit will replace uses of
`content_hash!{}` with `#[derive(ContentHash)]`.

The new macro generates nice error messages, just like the old macro:

```
error[E0277]: the trait bound `NotImplemented: content_hash::ContentHash` is not satisfied
   --> lib/src/content_hash.rs:265:16
    |
265 |             z: NotImplemented,
    |                ^^^^^^^^^^^^^^ the trait `content_hash::ContentHash` is not implemented for `NotImplemented`
    |
    = help: the following other types implement trait `content_hash::ContentHash`:
              bool
              i32
              i64
              u8
              u32
              u64
              std::collections::HashMap<K, V>
              BTreeMap<K, V>
            and 38 others
```

This commit does two things to make proc macros re-exported by jj_lib useable
by deps:

1. jj_lib needs to be able refer to itself as `jj_lib` which it does
   by adding an `extern crate self as jj_lib` declaration.

2. jj_lib::content_hash needs to re-export the `digest::Update` type so that
   users of jj_lib can use the `#[derive(ContentHash)]` proc macro without
   directly depending on the digest crate. This is done by re-exporting it
   as `DigestUpdate`.


#3054
2024-02-20 11:29:05 -05:00
Ilya Grigoriev
106483ad6a clippy: run nightly cargo clippy --fix 2024-02-19 23:38:33 -08:00
Martin von Zweigbergk
11c67cf979 op_store: add metadata flag for ops representing working-copy snapshot
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.
2024-02-19 22:44:38 -08:00
Julien Vincent
23e5fba737 sign: Add SSH backend tests 2024-02-20 00:02:08 +00:00
Julien Vincent
5e24677301 sign: Implement SSH signing backend 2024-02-20 00:02:08 +00:00
Julien Vincent
7c11a61c23 sign: GPG backend tests 2024-02-20 00:02:08 +00:00
Anton Bulakh
0efaef2da9 sign: Implement GPG signing backend
Now it is actually possible to set GPG as the main backend and have jj
"preserving" signatures on rewrites. Just no way to make signatures yet
2024-02-20 00:02:08 +00:00
Martin von Zweigbergk
3f1d75f518 rewrite: default to not simplifying ancestor merges
This means auto-rebase will no longer simplify ancestor merges.
2024-02-19 14:20:18 -08:00
Martin von Zweigbergk
a9d0300b11 rewrite: make simplification of ancestor merges optional
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.
2024-02-19 14:20:18 -08:00
Yuya Nishihara
0c0eb37f2e index: don't store commit ids in sorted lookup table to save disk space
This reduces the index file size. In my linux mirror repo containing 1591524
commits, the initial index file shrank from 122MB to 92MB. In theory, this
makes commit id lookup slow because of additional indirection and cache miss,
but I don't see significant difference. In mid-size repo, this is actually a
bit faster thanks to smaller index reads.

Alternatively, the commit id field could be removed from the CommitGraphEntry,
but doing that would introduce indirect lookup there, and the index disk size
isn't as small as this change.

- jj-0 baseline                         122MB
- jj-1 shrink CommitLookupEntry (this)   92MB
- jj-3 shrink CommitGraphEntry           98MB

Mid-size repo, "log" with default template
```
% hyperfine --sort command --warmup 3 --runs 20 -L bin jj-0,jj-1,jj-2,jj-3 \
  -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 ± σ):     177.7 ms ±  12.9 ms    [User: 96.3 ms, System: 81.5 ms]
  Range (min … max):   156.8 ms … 191.2 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 ± σ):     169.8 ms ±  13.8 ms    [User: 93.3 ms, System: 76.6 ms]
  Range (min … max):   151.1 ms … 191.5 ms    20 runs

Benchmark 4: target/release-with-debug/jj-3 -R ~/mirrors/linux --ignore-working-copy log -r.. -l100 --config-toml='revsets.short-prefixes=""'
  Time (mean ± σ):     170.3 ms ±  13.4 ms    [User: 90.1 ms, System: 79.7 ms]
  Range (min … max):   154.8 ms … 186.2 ms    20 runs

Relative speed comparison
        1.05 ±  0.11  target/release-with-debug/jj-0 -R ~/mirrors/linux --ignore-working-copy log -r.. -l100 --config-toml='revsets.short-prefixes=""'
        1.00          target/release-with-debug/jj-1 -R ~/mirrors/linux --ignore-working-copy log -r.. -l100 --config-toml='revsets.short-prefixes=""'
        1.00 ±  0.11  target/release-with-debug/jj-3 -R ~/mirrors/linux --ignore-working-copy log -r.. -l100 --config-toml='revsets.short-prefixes=""'
```

Small repo, "log" thousands of commits with -T"commit_id.shortest()"
```
% hyperfine --sort command --warmup 3 --runs 100 -L bin jj-0,jj-1,jj-2,jj-3 \
  -s "target/release-with-debug/{bin} -R ~/mirrors/git debug reindex" \
  "target/release-with-debug/{bin} -R ~/mirrors/git --ignore-working-copy log -r.. -l5000 -T'commit_id.shortest()' --config-toml='revsets.short-prefixes=\"\"'"
Benchmark 1: target/release-with-debug/jj-0 -R ~/mirrors/git --ignore-working-copy log -r.. -l5000 -T'commit_id.shortest()' --config-toml='revsets.short-prefixes=""'
  Time (mean ± σ):     179.3 ms ±  12.8 ms    [User: 149.7 ms, System: 29.6 ms]
  Range (min … max):   155.2 ms … 191.0 ms    100 runs

Benchmark 2: target/release-with-debug/jj-1 -R ~/mirrors/git --ignore-working-copy log -r.. -l5000 -T'commit_id.shortest()' --config-toml='revsets.short-prefixes=""'
  Time (mean ± σ):     179.1 ms ±  13.7 ms    [User: 148.5 ms, System: 30.5 ms]
  Range (min … max):   157.2 ms … 196.7 ms    100 runs

Benchmark 4: target/release-with-debug/jj-3 -R ~/mirrors/git --ignore-working-copy log -r.. -l5000 -T'commit_id.shortest()' --config-toml='revsets.short-prefixes=""'
  Time (mean ± σ):     178.2 ms ±  13.6 ms    [User: 148.7 ms, System: 29.6 ms]
  Range (min … max):   156.5 ms … 191.7 ms    100 runs

Relative speed comparison
        1.01 ±  0.11  target/release-with-debug/jj-0 -R ~/mirrors/git --ignore-working-copy log -r.. -l5000 -T'commit_id.shortest()' --config-toml='revsets.short-prefixes=""'
        1.01 ±  0.11  target/release-with-debug/jj-1 -R ~/mirrors/git --ignore-working-copy log -r.. -l5000 -T'commit_id.shortest()' --config-toml='revsets.short-prefixes=""'
        1.01 ±  0.11  target/release-with-debug/jj-3 -R ~/mirrors/git --ignore-working-copy log -r.. -l5000 -T'commit_id.shortest()' --config-toml='revsets.short-prefixes=""'
```
2024-02-19 11:36:45 +09:00
Vladimir Petrzhikovskii
06d67f02d8 cli: list new remote branches during git fetch 2024-02-18 17:36:01 +01:00
Yuya Nishihara
a1b16c5583 index: build reachable change ids set lazily
Instead of abstracting RevWalk over borrowed/Arc-ed index types, I decided to
implement bitset-based ancestor traversal. It's simpler and probably faster so
long as the set isn't sparse.

"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 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

Benchmark 3: target/release-with-debug/jj-2 -R ~/mirrors/linux --ignore-working-copy log -r.. -l100 --config-toml='revsets.short-prefixes=""'
  Time (mean ± σ):     177.5 ms ±  12.6 ms    [User: 94.6 ms, System: 82.9 ms]
  Range (min … max):   154.4 ms … 188.7 ms    20 runs

Relative speed comparison
        1.53 ±  0.12  target/release-with-debug/jj-1 -R ~/mirrors/linux --ignore-working-copy log -r.. -l100 --config-toml='revsets.short-prefixes=""'
        1.00          target/release-with-debug/jj-2 -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 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

Benchmark 3: target/release-with-debug/jj-2 -R ~/mirrors/linux status --config-toml='revsets.short-prefixes=""'
  Time (mean ± σ):     214.7 ms ±  15.0 ms    [User: 117.4 ms, System: 96.1 ms]
  Range (min … max):   198.4 ms … 243.3 ms    20 runs

Relative speed comparison
        1.48 ±  0.12  target/release-with-debug/jj-1 -R ~/mirrors/linux status --config-toml='revsets.short-prefixes=""'
        1.00          target/release-with-debug/jj-2 -R ~/mirrors/linux status --config-toml='revsets.short-prefixes=""'
```
2024-02-19 00:54:43 +09:00
Yuya Nishihara
adcb01ef95 index: move RevWalk tests to inner module
The main tests module is getting bigger, and these tests are very specific
to the RevWalk* implementations.
2024-02-19 00:54:43 +09:00
Yuya Nishihara
924a5fc842 index: inline entry size calculation
There aren't many callers now, and using self.commit_id_length might help
compiler remove redundant bounds checking in CommitLookupEntry.
2024-02-19 00:47:46 +09:00
Yuya Nishihara
d5c75da4f5 index: precompute base data offsets
These offsets are getting messier, so let's calculate them in one place. This
will probably help compiler optimization.
2024-02-19 00:47:46 +09:00
Yuya Nishihara
3c7aa75b9b index: switch to persistent change id index
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=""'
```
2024-02-18 09:44:57 +09:00
Yuya Nishihara
5f3a31300b index: implement index-level change id lookup methods
These methods are basically the same as the commit_id versions, but
resolve_change_id_prefix() is a bit more involved as we need to gather matches
from multiple segments.
2024-02-18 09:44:57 +09:00
Yuya Nishihara
f73e590837 index: implement segment-level change id lookup methods
In resolve_change_id_prefix(), I've implemented two different ways of
collecting the overflow items. I don't think they impact the performance,
but we can switch to the alternative method as needed.
2024-02-18 09:44:57 +09:00
Yuya Nishihara
8cdf6d752c index: move change ids to sstable, build change-id-to-pos lookup table
This basically means that the change ids are interned. We'll implement binary
search over the sorted change ids table. The table could be sorted differently
for better cache locality, but it is in lexicographical order for simplicity.
With my testing, the cost of the id lookup isn't dominant.

Unlike the parent entries, the size of the per-id overflow items isn't saved.
That's s because the number of the same-change-id commits is either 1 or many.
It doesn't make sense to allocate 8 bytes for each change id. Instead, we'll
pay extra indirection cost to determine the size.
2024-02-18 09:44:57 +09:00
Yuya Nishihara
9974a46327 index: clarify parent entries are global positions
I'm going to add change id overflow table whose elements are of LocalPosition
type. Let's make sure that the serialization code would break if we changed
the underlying data type.
2024-02-18 09:44:57 +09:00
Thomas Castiglione
aaa5d6bc4f working_copy: add Send supertrait
If WorkingCopy: Send, then Workspace is Send, which is useful for long-running
servers. All existing impls are Send already, so this is just a marker.
2024-02-17 15:13:25 +08:00
Yuya Nishihara
5eea88d26a tests: fix concurrent git read/write test to retry on ref lock contention
Apparently, gix has 100ms timeout. Since this test tries to create contended
situation, it's possible that the ref lock can't be acquired. I've added
upper bound to the retry loop at b37293fa68 "tests: add upper bound to
test_concurrent_read_write_commit() loop", so ignoring arbitrary errors
should be okay.

The problem can be reproduced on my Linux machine by inserting 10ms sleep() to
gix and increasing the concurrency.

Fixes #3069
2024-02-17 15:09:27 +09:00
Yuya Nishihara
ce295f8bc2 op_store: remove unneeded repr(u8) from RemoteRefState
It no longer makes sense after e1fd402d39 "Fix the ContentHash implementations
for std::Option, MergedTreeId, and RemoteRefState."
2024-02-17 02:13:44 +09:00
Yuya Nishihara
718d080e7a index: make reindexing message less scary 2024-02-17 01:45:23 +09:00
Evan Mesterhazy
a80d0183a2 Implement ContentHash for u32 and u64
This is for completeness and to avoid accidents such as someone calling
`ContentHash::hash(1234u32.to_le_bytes())` and expecting it to hash properly as
a u32 instead of a 4 byte slice, which produces a different hash due to hashing
the length of the slice before its contents.
2024-02-16 10:23:39 -05:00
Evan Mesterhazy
e1fd402d39 Fix the ContentHash implementations for std::Option, MergedTreeId, and RemoteRefState
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
2024-02-16 09:27:32 -05:00
Yuya Nishihara
903f18acfd index: extract helper functions for id lookup in mutable table
Similar to the previous commit, these functions will be reused by the change id
lookup methods. The return value isn't cloned because resolve_id_prefix() will
return (key, value) pair, and the current caller doesn't need a cloned value.
2024-02-16 11:12:53 +09:00
Yuya Nishihara
000cb41c7e index: extract helper struct for post processing binary search result
This code will be shared among commit id and change id lookup functions.
2024-02-16 11:12:53 +09:00
Yuya Nishihara
6fa660d9a8 index: extract inner binary search function
The callback returns Ordering instead of &[u8] due to lifetime difficulty.
2024-02-16 11:12:53 +09:00
Yuya Nishihara
2e64bf83fd index: pass bytes prefix to binary search function
This helps extract common binary search helper to be used by change id index.
2024-02-14 23:34:47 +09:00
Yuya Nishihara
91a68b950d index: adjust binary search function to conform to std behavior
This removes redundant case from resolve_neighbor_commit_ids(). The returned
position should never be lower than the prefix id.

The implementation is basically a copy of slice::binary_search_by(). We still
use (low + high) / 2 as the size wouldn't exceed 2^31.

https://github.com/rust-lang/rust/blob/1.76.0/library/core/src/slice/mod.rs#L2825
2024-02-14 23:34:47 +09:00
Yuya Nishihara
e2c8a8fabd index: fix change id resolution test to not depend on deterministic order
Since IdIndex sorts the entries by using .sort_unstable_by_key(), the order of
the same-key elements is undefined. Perhaps, it's stable for short arrays, and
the test passes because of that.
2024-02-14 23:22:23 +09:00
Yuya Nishihara
8b1dfa7157 index: compact parent encoding, inline up to two parents
This saves 4 more bytes per entry, and more importantly, most commit parents
can be resolved with no indirection to the overflow table.

IIRC, Git always inlines the first parent, but that wouldn't be useful in jj
since jj diffs merge commit against the auto-merge parent. The first merge
parent is nothing special.

I'll use a similar encoding in change id sstable, where only one position
will be inlined (to optimize for imported commits.)

Benchmark number measuring the cost of change id index building:
```
% hyperfine --sort command --warmup 3 --runs 20 -L bin jj-0,jj-1 \
  -s "target/release-with-debug/{bin} -R ~/mirrors/linux \
      --ignore-working-copy debug reindex" \
  "target/release-with-debug/{bin} -R ~/mirrors/linux \
    --ignore-working-copy log -r@ --config-toml='revsets.short-prefixes=\"\"'"
Benchmark 1: target/release-with-debug/jj-0 -R ~/mirrors/linux --ignore-working-copy log -r@ --config-toml='revsets.short-prefixes=""'
  Time (mean ± σ):     342.9 ms ±  14.5 ms    [User: 202.4 ms, System: 140.6 ms]
  Range (min … max):   326.6 ms … 360.6 ms    20 runs

Benchmark 2: target/release-with-debug/jj-1 -R ~/mirrors/linux --ignore-working-copy log -r@ --config-toml='revsets.short-prefixes=""'
  Time (mean ± σ):     325.0 ms ±  13.6 ms    [User: 196.2 ms, System: 128.8 ms]
  Range (min … max):   311.6 ms … 343.2 ms    20 runs

Relative speed comparison
        1.06 ±  0.06  target/release-with-debug/jj-0 -R ~/mirrors/linux --ignore-working-copy log -r@ --config-toml='revsets.short-prefixes=""'
        1.00          target/release-with-debug/jj-1 -R ~/mirrors/linux --ignore-working-copy log -r@ --config-toml='revsets.short-prefixes=""'
```
2024-02-14 22:33:48 +09:00
Yuya Nishihara
89928ffdd8 index: remove local-global pos round trip from entry_by_id() 2024-02-14 22:33:48 +09:00
Yuya Nishihara
249449ff1a index: store local position in lookup table 2024-02-14 22:33:48 +09:00
Yuya Nishihara
1d11cffcfa index: use local position in segment-local operations
I'm going to change the index format to store local positions in the lookup
table. That's not super important, but I think it makes sense because the
lookup table should never contain inter-segment links.

The mutable segment now stores local positions in its lookup map. The readonly
segment will be updated later.
2024-02-14 22:33:48 +09:00
Yuya Nishihara
3e43108abb index: remove unused flag field from readonly index segment
This is remainder of fdb861b957 "backend: remove unused Commit::is_pruned."
As I'm going to change the index format, let's remove unused fields, too.
2024-02-14 22:33:48 +09:00
Yuya Nishihara
26528091e6 revset: drop now unused is_legacy flag from dag ranges 2024-02-14 10:04:56 +09:00
Yuya Nishihara
815670a4ad revset: add parsing rule and expression node dedicated for kind:"pattern"
This unblocks removal of 'is_legacy: bool' fields.

Note that all legacy dag range expressions can't be accepted by the new grammar.
For example, 'x:y()' is parsed as ('x:y', error) because 'x:y' is a valid string
pattern expression, and '(' isn't an infix operator. The old compat_dag_range_op
is NOT removed as it can still translate 'x():y' or 'x:(y)' to a better error,
and we might make the string pattern syntax stricter #2101.
2024-02-14 10:04:56 +09:00
Yuya Nishihara
815437598f revset: disable parsing rules of legacy dag range operator
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.
2024-02-14 10:04:56 +09:00
Yuya Nishihara
2905a70b18 doc, tests: drop use of deprecated revset dag range operator 2024-02-14 10:04:56 +09:00
Yuya Nishihara
1f6d1de62d index: on reindexing, print error details to stderr
It's not ideal to print the error there, but using stderr should be slightly
better. It could be a tracing message, but tracing won't be displayed by
default.
2024-02-12 19:38:36 +09:00
Yuya Nishihara
b0e8e2a1af index: move segment files to sub directory, add version number
I'm going to introduce breaking changes in index format. Some of them will
affect the file size, so version number or signature won't be needed. However,
I think it's safer to detect the format change as early as possible.

I have no idea if embedded version number is the best way. Because segment
files are looked up through the operation links, the version number could be
stored there and/or the "segments" directory could be versioned. If we want to
support multiple format versions and clients, it might be better to split the
tables into data chunks (e.g. graph entries, commit id table, change id table),
and add per-chunk version/type tag. I choose the per-file version just because
it's simple and would be non-controversial.

As I'm going to introduce format change pretty soon, this patch doesn't
implement data migration. The existing index files will be deleted and new
files will be created from scratch.

Planned index format changes include:
 1. remove unused "flags" field
 2. inline commit parents up to two
 3. add sorted change ids table
2024-02-12 19:38:36 +09:00
Yuya Nishihara
4b541e6c93 index: on reinit(), don't remove "operations" directory itself
This should be slightly safer as the store may be accessed concurrently from
another process.
2024-02-12 19:38:36 +09:00
Yuya Nishihara
81837897dc index: extract dir.join("operations") to private method 2024-02-12 19:38:36 +09:00
Martin von Zweigbergk
48a9f9ef56 repo: use Transaction for creating repo-init operation
Since the operation log has a root operation, we don't need to create
the repo-initialization operation in order to create a valid
`ReadonlyRepo` instance. I think it's conceptually simpler to create
the instance at the root operation id and then add the initial
operation using the usual `Transaction` API. That's what this patch
does.

Doing that also brought two issues to light:

 1. The empty view object doesn't have the root commit as head.
 2. The initialized `OpHeadsStore` doesn't have the root operation as
     head.

Both of those seem somewhat reasonable, but maybe we should change
them. For now, I just made the initial repo (before the initial
operation) have a single op head (to compensate for (2)). It might be
worth addressing both issues so the repo is in a better state before
we create the initial operation. Until we do, we probably shouldn't
drop the initial operation.
2024-02-11 21:19:30 -08:00
Martin von Zweigbergk
305a507ae3 repo: move creation of repo-init operation to end of init()
Since we now have a root operation, we don't need the
repo-initialization operation to create the repo. Let's move it later
to clarify that.
2024-02-11 21:19:30 -08:00
Ilya Grigoriev
a9c3af8153 test_local_working_copy: use std::fs:write instead of OpenOptions 2024-02-10 16:06:28 -08:00
Ilya Grigoriev
b2e37d448b clippy: add truncate option as suggested by clippy
In the next commit, I replace the whole thing with
std::fs::write, but I'll leave this here in case
the next commit is somhow incorrect
2024-02-10 16:06:28 -08:00
Ilya Grigoriev
a88c06068e clippy: new nightly fixes
For some reason, clippy also suggested surrounding
`self.value` with parentheses. Not sure whether
that's a clippy bug.

Cc: https://github.com/rust-lang/rust-clippy/issues/12268
2024-02-10 16:06:28 -08:00
dependabot[bot]
6d1faf9b03 Update strsim (changes tests), clap, clap_complete
This is #3002 with tests rerun to account for changes
to `strsim`, as @thoughtpolice noticed in
https://github.com/martinvonz/jj/pull/3002#issuecomment-1936763101

The string similarity changes include an example that
seems better and one that seems worse. Decreasing
the threshold definitely makes things worse.
2024-02-10 00:01:47 -08:00
Yuya Nishihara
e908bd9a17 simple_op_store: use TryFrom<i32> instead of deprecated from_i32() 2024-02-10 09:15:30 +09:00
Yuya Nishihara
421ab592be cargo: bump gix to 0.58.0, migrate to ObjectId::try_from()
The panicking conversion function appears to be renamed, and try_from() is
added instead.
2024-02-10 09:15:30 +09:00
Austin Seipp
5b517b542e rust: bump MSRV to 1.76.0
Signed-off-by: Austin Seipp <aseipp@pobox.com>
2024-02-09 15:48:01 -06:00
Martin von Zweigbergk
6c1aeff7a9 working copy: materialize symlinks on Windows as regular files
I was a bit surprised to learn (or be reminded?) that checking out
symlinks on Windows leads to a panic. This patch fixes the crash by
materializing symlinks from the repo as regular files. It also updates
the snapshotting code so we preserve the symlink-ness of a path. The
user can update the symlink in the repo by updating the regular file
in the working copy. This seems to match Git's behavior on Windows
when symlinks are disabled.
2024-02-09 09:20:24 -08:00
Martin von Zweigbergk
b253a28788 merge: add as_normal(), taken from RefTarget
The `RefTarget::as_normal()` function is not specific to `RefTarget`,
and I plan to use it from `local_working_copy`.
2024-02-09 09:20:24 -08:00
Martin von Zweigbergk
5a898b16a8 working_copy: handle symlink outside write_path_to_store()
The `write_path_to_store()` has almost no overlapping code between the
handling of symlinks and regular files, which suggests that we should
move out the handling of symlinks to the caller (there's only one).
2024-02-09 09:20:24 -08:00
Jonathan Tan
33f3a420a1 workspace: recover from missing operation
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.
2024-02-09 00:38:47 -08:00
Ilya Grigoriev
12c3be70f4 lib refs.rs: rename TrackingRefPair to LocalAndRemoteRef
As discussed in
https://github.com/martinvonz/jj/pull/2962#discussion_r1479384841, the
previous name is confusing since the struct is used for pairs where the
remote branch is not tracked by the local branch.
2024-02-07 17:06:28 -08:00
jyn
d66fcf2ca0 compile integration tests as a single binary
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.
2024-02-06 18:19:41 -08:00
Ilya Grigoriev
1741ab22e4 view.rs: clarify some internal function docstrings
Mostly, I was a bit confused that some of these functions return a
`TrackingRefPair` but don't seem to take into account whether the remote
branch is being tracked or not.
2024-02-06 17:52:01 -08:00
Martin von Zweigbergk
b343289238 working_copy: make reset() take a commit instead of a tree
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.
2024-02-06 12:41:09 -08:00
Yuya Nishihara
77ceadbfd0 cleanup: remove remaining ": {source}" from error message templates 2024-02-04 09:13:21 +09:00
Yuya Nishihara
1efadd96c8 git: remove ": {source}" from FailedRefExportReason, walk chain by caller
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.
2024-02-04 09:13:21 +09:00
Yuya Nishihara
a0cefb8b7b revset, template: remove ": {source}" from parse error message template
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.
2024-02-04 09:13:21 +09:00
Ilya Grigoriev
d439de073d rewrite.rs: revert commits cfcc7c5e and becbc889
This mostly reverts https://github.com/martinvonz/jj/pull/2901 as well as its
fixup https://github.com/martinvonz/jj/pull/2903. The related bug is reopened,
see https://github.com/martinvonz/jj/issues/2869#issuecomment-1920367932.

The problem is that while the fix did fix #2869 in most cases, it did
reintroduce the more severe bug https://github.com/martinvonz/jj/issues/2760
in one case, if the working copy is the commit being rebased.

For example, suppose you have the tree

```
root -> A -> B -> @ (empty) -> C
```

### Before this commit

#### Case 1

`jj rebase -s B -d root --skip-empty` would work perfectly before this
commit, resulting in

```
root -> A
  \-------B -> C
           \- @ (new, empty)
```

#### Case 2

Unfortunately, if you run `jj rebase -s @ -d A --skip-empty`, you'd have the
following result (before this commit), which shows the reintroduction of #2760:

```
root -> A @ -> C
         \-- B
```

with the working copy at `A`. The reason for this is explained in
https://github.com/martinvonz/jj/pull/2901#issuecomment-1920043560.

### After this commit

After this commit, both case 1 and case 2 will be wrong in the sense of #2869,
but it will no longer exhibit the worse bug #2760 in the second case.

Case 1 would result in:

```
root -> A
  \-------B -> @ (empty) -> C
```

Case 2 would result in:

```
root -> A -> @ -> C
         \-- B
```

with the working copy remaining a descendant of A
2024-02-03 15:56:44 -08:00
Essien Ita Essien
8423c63a04 cli: Refactor workspace root directory creation
* Add file_util::create_or_reuse_dir() which is needed by all init
  functionality regardless of the backend.
2024-02-03 14:15:05 +00:00
Yuya Nishihara
ec0f2753ae repo: mark inner error of EditCommitError as source 2024-02-01 16:59:44 +09:00
Martin von Zweigbergk
7c87fe243c backends: implement as_any() on OpStore and OpHeadsStore too
It's useful for custom commands to be able to downcast to custom
backend types.
2024-01-31 00:15:29 -08:00
Ilya Grigoriev
cfcc7c5e34 test_rewrite: Fixup test comment after becbc88 2024-01-30 23:43:05 -08:00
Martin von Zweigbergk
9efa66e8c9 rewrite: remove return value from rebase_next()
`rebase_next()` returns an `Option<RebasedDescendant>`, but the only
way we use it is to decide whether to terminate the loop over
`to_visit`. Let's simplify by making the caller iterate over
`to_visit` instead.
2024-01-30 23:27:48 -08:00
Martin von Zweigbergk
881d75e899 rewrite: drop TODO about changing the API
The `rebase_next()` method is private, so I think we've addressed the
TODO.
2024-01-30 23:27:48 -08:00
Ilya Grigoriev
becbc88915 rewrite.rs: fix working copy position after jj rebase --abandon-empty
Fixes #2869
2024-01-30 22:53:55 -08:00
Ilya Grigoriev
1fff6e37a1 rewrite.rs DescendantRebaser: rename variable for clarity
The `edit` argument seems to be true if and only if the
old commit was *not* abandoned. So, I flipped its value
and renamed it to `abandoned_old_commit`.
2024-01-30 22:53:55 -08:00
Yuya Nishihara
976b801208 index: on reinit(), delete all segment files to save disk space
Perhaps, reinit() will evolve to gc() function? It's basically a gc() with
empty operation set.
2024-01-31 09:40:52 +09:00
Yuya Nishihara
3d68601c01 index: remove redundant stat() of operation link file, handle error instead
This wouldn't matter in practice, but the operation link file could be deleted
after testing the existence.
2024-01-31 09:40:52 +09:00
Yuya Nishihara
3d0b3d57d8 git_backend: on gc(), remove unreachable no-gc refs and compact them
With my jj repo, the number of jj/keep refs went down from 87887 to 27733.
The .git directory size is halved, but we'll need to clean up extra and index
files to save disk space. "git gc --prune=now && jj debug reindex" passed, so
the repo wouldn't be corrupted.

#12
2024-01-27 10:18:11 +09:00
Yuya Nishihara
351487b9f5 backend: pass Index and keep_newer timestamp parameters to gc()
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.
2024-01-27 10:18:11 +09:00
Yuya Nishihara
845eb4ce01 git_backend: when running "git gc", chdir instead of specifying it by GIT_DIR
Hopefully this will be more reliable on Windows where path/environment stuff
is messy.
2024-01-27 10:18:11 +09:00
Yuya Nishihara
4e54021930 backend: have gc() return BackendError instead of opaque error type
The gc() implementation is likely to call other backend functions, which
return BackendError.
2024-01-27 10:18:11 +09:00
Yuya Nishihara
84949dd551 backend: mark BackendError::Other as transparent
The inner error should be the source, and I don't think the "Error:" prefix
gives additional context.
2024-01-27 10:18:11 +09:00
Yuya Nishihara
8a67191d25 git: simplify import_head() as it doesn't have to process multiple head commits 2024-01-27 00:01:59 +09:00
Yuya Nishihara
fc114ef217 git: extract Git HEAD handling bits from import_some_refs()
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.
2024-01-27 00:01:59 +09:00
Yuya Nishihara
5a88180720 git_backend: fix import_head_commits() to not issue duplicated ref edits
This was broken at afa72ff496 "git_backend: inline prevent_gc() to bulk-update
refs." Since no-gc refs are created within a transaction, duplicated edits are
no longer allowed.
2024-01-27 00:00:57 +09:00
Ilya Grigoriev
dff440c4a8 clippy: Fix nightly warnings about "useless use of vec!" 2024-01-25 22:00:26 -08:00
Daniel Ploch
20cbe77bf5 workspace: support creating shares of custom workspaces 2024-01-25 11:46:07 -08:00
Daniel Ploch
cb889f0b45 workspace: combine working copy functions into a trait 2024-01-25 11:46:07 -08:00
Yuya Nishihara
5a7d8ac596 working_copy: don't follow symlinks when visiting files in gitignored directory
Fixes #2878
2024-01-24 16:38:48 +09:00
Yuya Nishihara
d0d4496258 tests: add executable files and symlinks to gitignored directory test 2024-01-24 16:38:48 +09:00
Martin von Zweigbergk
502150b2f4 conflicts: test materialization with with negative snapshots
We didn't have any tests with negative snapshots (after a `-------`
line). I initially thought we couldn't produce such conflict markers
anymore. I'm not sure we want to render conflicts like the one in the
test like this. I don't think I intended for `add_index` in the code
to be able to be two steps ahead of the remove. Maybe we should
rewrite the algorithm to not do that and thus never produce negative
snapshots.
2024-01-23 07:18:54 -08:00
Ilya Grigoriev
d168fd2b09 test_rebase_abandoning_empty: add children of an empty @ to the test case
This demonstrates the minor bug discussed in
https://github.com/martinvonz/jj/pull/2766#discussion_r1442365389
AKA https://github.com/martinvonz/jj/issues/2869.

It's also interesting whether changing the definition of "discardable" commit
would affect this test, see
https://github.com/martinvonz/jj/issues/2859#issuecomment-1903275884

(I think it won't, but still)
2024-01-22 18:36:49 -08:00
Jonathan Tan
0bc1341fd0 revset: add count_estimate() to Revset trait
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.
2024-01-22 15:07:00 -08:00
Yuya Nishihara
c7be4d019c index: add all_heads_for_gc() that iterates heads of all indexed commits
GitBackend::gc() will recreate no-gc refs for the indexed heads. We could
collect all historical heads by traversing operation log, but it isn't enough
because there may be predecessor links to hidden commits, and "git gc" isn't
aware of predecessors.
2024-01-17 23:07:14 +09:00
Yuya Nishihara
afa72ff496 git_backend: inline prevent_gc() to bulk-update refs 2024-01-17 10:43:25 +09:00
Yuya Nishihara
96ee9bdb9f git_backend: ensure no-gc refs are created for all imported head commits
This also means that we can implement GC without taking care of extra
metadata. I haven't tried, but it wouldn't be easy to keep Git refs and extra
table in sync.
2024-01-17 10:43:25 +09:00
Yuya Nishihara
2e1aa6c49c git_backend: remove fast path testing imported commits, filter them by caller
The idea is that GC, if implemented, will clean up objects based on the Index
knowledge. It's probably okay to leave some extra metadata of unreachable
objects, but GC-ed refs should be recreated if the corresponding heads get
reimported. See also the next patch.
2024-01-17 10:43:25 +09:00
Yuya Nishihara
48c4985e34 git_backend: ensure that no-gc ref target never conflicts 2024-01-17 10:43:25 +09:00
Yuya Nishihara
f66c859fe4 git_backend: use lower-level API to create no-gc refs
This will allow us to issue multiple prevent_gc() requests all at once. It's
not important here, but will be unavoidable when implementing GC. Deleting
tons of refs from packed refs is super slow if the requests were processed one
by one.
2024-01-17 10:43:25 +09:00
Yuya Nishihara
34956f17e5 op_walk: assert that virtual root op is not reparented
This is enforced by the caller, but it's scary if it weren't.
2024-01-16 21:46:54 +09:00
Yuya Nishihara
fb3e006a45 op_store: add special case for root id resolution 2024-01-16 21:46:54 +09:00
Yuya Nishihara
660806ffed tests: set up unparented operations for id prefix tests
Otherwise we can't easily pick i to create operation id starting with "0".
2024-01-16 21:46:54 +09:00
Yuya Nishihara
df1be14aa8 tests: split op id resolution tests, don't require merged op for prefix tests
This makes it easy to set up crafted environment for prefix resolution tests.
2024-01-16 21:46:54 +09:00
Essien Ita Essien
dc074363d1 no-op: Move external git repo canonicalization into Workspace::init_git_external
* 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.
2024-01-16 10:46:02 +00:00
Yuya Nishihara
da218d19db repo: optimize enforce_view_invariants() to not traverse ancestors until root
Because the default index cuts off the traversal at min(generations), including
the root id means all ancestors will be visited. This could be worked around at
the index side, but I think it's the repo/view's responsibility. That being
said, it's not uncommon to pad a revset with "root()", so it might make sense
for the index to special case the root id.

I also removed the redundant .clone().
2024-01-15 09:57:02 +09:00
Martin von Zweigbergk
6e302bb3a2 op_store: add a virtual root operation, similar to root commit
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.
2024-01-14 10:15:14 -08:00
Martin von Zweigbergk
c9af8bf43a view: drop tracking of public heads
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.
2024-01-13 22:23:57 -08:00
Martin von Zweigbergk
a66e2a0a6d working_copy: mark commit_id field in proto reserved
By marking it reserved, we prevent accidental use. We can still read
working copy protos that have the field.
2024-01-12 17:38:23 -08:00
Yuya Nishihara
543036c753 cli: run "op log" without loading repo or merging concurrent ops
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.
2024-01-13 10:38:10 +09:00
Yuya Nishihara
831a530283 op_walk: make walk_ancestors() sort head ops to stabilize output
I thought this would be done by dag_walk::topo_order_reverse_lazy_ok(), but
apparently I made it preserve the input order in a way topo_order_reverse()
would do.
2024-01-13 10:38:10 +09:00
Yuya Nishihara
b7eb551cf7 index: fix reindexing to scan all referenced commits such as hidden remote refs
Since hidden commits can be looked up by remote_branches() revset for example,
reindexing should traverse ancestors from all named refs in addition to the
visible heads.
2024-01-12 12:53:16 +09:00
Yuya Nishihara
805046ceba op_walk: extract function that resolves op expression with preloaded head op
I'm going to make "op abandon" not load the repo, and this function will
be used there instead of resolve_op_with_repo().
2024-01-12 08:01:13 +09:00
Yuya Nishihara
83ede241e3 op_walk: don't resolve heads beyond @ operation
Since `jj undo --at-op=OP @` resolves @ to OP, I think OP should be the head
in that context, and the descendants of OP shouldn't be accessible by @+.
2024-01-12 08:01:13 +09:00
Yuya Nishihara
ba42b37a67 operation: remove operation::View wrapper in favor of view::View
view::View doesn't track ViewId, but there are no callers of cheap Eq/Hash
functions.
2024-01-12 08:01:02 +09:00
Yuya Nishihara
d5a98df046 git_backend: teach "format.tree-level-conflicts" config by constructor
Since GitBackend constructors now depend on &UserSettings, it makes sense to
initialize the formatting options there.
2024-01-10 08:57:51 +09:00
Yuya Nishihara
e5286aed08 index: move lifetimed change_id_index() to MutableIndex, rename 'static version
change_id_index() is only used by Readonly/MutableRepo, so we don't need an
abstraction at Index. evaluate_revset() is somewhat similar, but the callers
rely on &dyn Repo.
2024-01-09 10:38:00 +09:00
Yuya Nishihara
dc68f1eeb2 revset: remove unused lifetime parameter from Revset<'index> 2024-01-09 10:37:43 +09:00
Yuya Nishihara
e9d31177cb op_store: implement GC of unreachble operations and views
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
2024-01-09 10:37:03 +09:00
Yuya Nishihara
5894f3dfba operation: add shorthand for &store_operation().view_id 2024-01-09 10:37:03 +09:00
Martin von Zweigbergk
c98b0d76af index: move Revset::change_id_index() to Index
We current have `Revset::change_id_index()` for creating a
`ChangeIdIndex` for a given revset. I think it will be hard to make it
performant for general revsets, especially in very large repos and
with custom index implementations, like the one we have at Google. If
we instead restrict it to including all ancestors of a set of heads, I
think it will be much easier to implement. We only use
`Revset::change_id_index()` with revsets including all visible commits
today, so we won't lose any current functionality by making it more
restricted.
2024-01-08 06:06:47 -08:00
Martin von Zweigbergk
2f4594540a tests: move ChangeIdIndex test from test_revset to test_index 2024-01-08 06:06:47 -08:00
Martin von Zweigbergk
1508f28567 tests: update ChangeIdIndex test to include ancestors in set
I plan to replace `Revset::change_id_index()` by
`Index::change_id_index(heads)`, but one of the tests currently uses a
set of commits that does not include ancestors. This patch updates it
to include ancestors (and changes the set of heads to keep the set
small enough for the test).
2024-01-08 06:06:47 -08:00
Martin von Zweigbergk
f9dc00704d index: specialize evaluate_revset_static() to change_id_index_static()
I'd like to move `change_id_index()` from `Revset` to `Index` (and
make it take the set of visible heads as argument). We currently use
`evaluate_revset_static()` only to get a `ChangeIdIndex`, so a good
place to start is to convert that into `change_id_index_static()`.
2024-01-08 06:06:47 -08:00
Martin von Zweigbergk
b549090acc index: adopt ChangeIdIndex and relatives from revset module
The `ChangeIdIndex` type is currently in defined in the `revset`
module because that's the only placed it's used. However, I'd like to
start using it directly from `index`. The idea is to make it possible
to create a `ChangeIdIndex` given a set of heads, without first
creating a `Revset`.
2024-01-08 06:06:47 -08:00
Martin von Zweigbergk
f0182ad4b8 default_index: adopt revset engine and graph iterator modules
The revset engine and the graph iterator are specific to the default
index implementation, so they belong in the same module.
2024-01-07 05:37:47 -08:00
Yuya Nishihara
a6616e9cea object_id: don't allow ObjectId::from_hex() a dynamically allocated string
This isn't technically needed, but it prevents API misuse. Another option
is to do some compile-time substitution, but most callers are tests and the
runtime performance wouldn't matter.
2024-01-06 00:26:36 +09:00
Yuya Nishihara
837ac15052 op_store: add resolve_operation_id_prefix() trait method that uses readdir()
The OpStore backends should have a better way to look up operation by id than
traversing from the op heads. The added method is similar to the commit Index
one, but returns an OpStoreResult because the backend operation can fail.

FWIW, if we want .shortest() in the op log template, we'll probably need a
trait method that returns an OpIndex instead.
2024-01-05 23:36:57 +09:00
Yuya Nishihara
95ea352b0a object_id: add fallible version of ObjectId::from_hex() 2024-01-05 23:36:57 +09:00
Yuya Nishihara
95d83cbfe5 object_id: make ObjectId constructors non-trait methods
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.
2024-01-05 23:36:57 +09:00
Yuya Nishihara
31b236a70d object_id: move HexPrefix and PrefixResolution from index module 2024-01-05 10:20:57 +09:00
Yuya Nishihara
fa5e40719c object_id: extract ObjectId trait and macros to separate module
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.
2024-01-05 10:20:57 +09:00
Yuya Nishihara
dbaee198e6 hex_util: move common_hex_len() from backend module
This function predates the hex_util module. If there were hex_util, I would
add it there.
2024-01-05 10:20:57 +09:00
Yuya Nishihara
e5255135bb op_walk: add function that reparents (and abandons) operation range
This will be used in "jj op abandon ..op_id" command. The "op_id..@" range will
be reparented onto the root operation.

The current implementation is good enough for local repos, but it won't scale.
We might want to extract it as a trait method or introduce OpIndex for
efficient DAG operation.
2024-01-04 11:44:36 +09:00
Yuya Nishihara
392e83be42 op_heads: ensure that update_op_heads([id], id) fails
The doc states it's invalid, but I made such bug.
2024-01-04 11:44:36 +09:00
Matt Stark
3f0a49dafe Ensure you never drop the working commit with --skip-empty
See #2766 for discussions
2024-01-04 13:33:24 +11:00
Matt Stark
a4aed2391f Rewrite instead of abandoning empty commits.
Fixes #2760


Given the tree:
```
A-B-C
 \
  B2
```
And the command `jj rebase -s B -d B2`

We were previously marking B as abandoned, despite the comment stating that we were marking it as being succeeded by B2. This resulted in a call to `rewrite(rewrites={}, abandoned={B})` instead of `rewrite(rewrites={B=>B2}, abandoned={})`, which then made the new parent of `C` into `A` instead of `B2`
2024-01-04 13:33:24 +11:00
Ilya Grigoriev
6edaa97517 DescendantRebaser: change rebased() method to into_map() that consumes the rebaser
This prevents a clone and does not affect the public API, as suggested
in https://github.com/martinvonz/jj/pull/2738#discussion_r1438903463.
2024-01-01 21:55:18 -08:00
Ilya Grigoriev
ddec3f91b2 lib: mild refactoring made possible by previous commit
Inline `create_descendant_commits`, move some functionality of
`DescendantRebaser::rebase_next` to `rebase_all`, a seemingly more logical
location.
2024-01-01 18:51:36 -08:00
Ilya Grigoriev
277b81ff6f lib: make DescendantRebaser-related APIs private.
Finally, there are no test uses of these APIs. `DescendantRebaser` is made
`pub(crate)`, since it is used by `MutRepo`. Other functions are made private.
2024-01-01 18:51:36 -08:00
Ilya Grigoriev
45cd0bf11b test_rewrite.rs: stop using DescendantRebaser when testing EmptyBehavior
This completes the process of removing DescendantRebaser-related APIs from
tests. It requires creating some new test utils and a new
`rebase_descendants_with_option_return_map`.
2024-01-01 18:51:36 -08:00
Ilya Grigoriev
7cef879ef6 lib repo.rs & rewrite.rs: Move clearing of rewritten/abandoned commits
This commit is a little out of place in this sequence, but
it seems to make more sense for MutRepo to own these maps.

@yuja [pointed out] that any tests written using `create_descendant_rebaser` now
need to do this cleanup, but there are no longer any such tests after the
previous commits and a follow-up commit removes `create_descendant_rebaser`
entirely.

[pointed out]: https://github.com/martinvonz/jj/pull/2737#discussion_r1435754370
2024-01-01 18:51:36 -08:00
Ilya Grigoriev
4461d61254 test_rewrite: test branches of descendants of divergent commits
A TODO left over from a previous PR
2024-01-01 18:51:36 -08:00
Ilya Grigoriev
b2abba07e9 tests: (mostly) stop using soon-to-be-private DescendantRebaser-related APIs
This removes uses of `DescendantRebaser::new` or
`MutRepo::create_descendant_rebaser` from most tests. The exceptions  are the
tests having to do with abandoning empty commits on rebase, since adjusting
those is a bit more elaborate (see follow-up commits).
2024-01-01 18:51:36 -08:00
Yuya Nishihara
3eafca65ea op_walk: add support for op_id+ (children) operator
A possible use case is when doing some archaeology around a certain operation.

The current implementation is quadratic if + is repeated. Suppose op_id is
usually close to the current op heads, I think it'll practically work better
than building a reverse lookup table.
2024-01-02 10:30:08 +09:00
Yuya Nishihara
ab299a6af5 op_walk: reimplement prefix lookup by using walk_ancestors() and HexPrefix
Perhaps, OpStore should provide prefix resolution method, but let's think
that later.
2024-01-02 10:30:08 +09:00
Yuya Nishihara
c53748d732 op_walk: allow walk_ancestors() from more than one head operations 2024-01-02 10:30:08 +09:00
Yuya Nishihara
51691ea22c tests: add lib tests for op id resolution, migrate some from cli
CLI testing is slow and harder to set up crafted environment.
2024-01-02 10:30:08 +09:00
Yuya Nishihara
dad890b960 operation: make parent_ids() return slice instead of Vec reference 2024-01-02 02:47:41 +09:00
Yuya Nishihara
c9b581589c op_walk: simplify arguments passed to high-level "opset" query functions 2024-01-01 10:22:23 +09:00
Yuya Nishihara
26b5f38f45 op_walk: move "opset" query functions from jj_cli 2024-01-01 10:22:23 +09:00
Yuya Nishihara
e4460d5386 op_walk: add error types for fake "opset" expression
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.
2024-01-01 10:22:23 +09:00
Yuya Nishihara
94fc32ab47 op_walk: extract walk_ancestors() to new module
I'm going to extract fake "opset" resolution functions there, and I think
walk_ancestors() belongs to the same category.
2024-01-01 10:22:23 +09:00
Yuya Nishihara
6dd936f72f op_heads: let caller decide resolve_op_heads() error type
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>.
2024-01-01 10:22:23 +09:00
Martin von Zweigbergk
90744fb770 working copy: read files ahead when updating
If the commit backend has high latency, it can make a big difference
to read files concurrently. This patch updates the working copy code
to do that in the update code (when reading files from the backend to
write to the working copy). Because our backend at Google reads files
from a local daemon process that already does a lot of prefetching,
this patch doesn't actually help us. I think it's still the right
thing to do for backends that don't do the same kind of
prefetching. It speeds up `jj sparse set --add` by >10x when I disable
the prefetching in our daemon (our `Backend::concurrency()` is 100).
2023-12-29 13:37:13 -08:00
Yuya Nishihara
f9e9058b9b index: show bad operation id if commit lookup failed during reindexing
My jj repo contains such head commits, and "jj debug reindex" fails. To address
this problem, we'll probably need to implement GC, and the user will discard
operations before the first bad op id.
2023-12-29 13:05:58 +09:00
Yuya Nishihara
43e016a7d1 index: add explicit reindexing method that can propagate error 2023-12-29 13:05:58 +09:00
Yuya Nishihara
ab1c8656a4 index: rename private index_at_operation methods, reorder arguments
I'm going to add a public method that rebuilds index, and its return type will
be different. I also added "build_" because "index" could be misinterpreted
as noun.

The method arguments are reordered to follow the public IndexStore interface.
2023-12-29 13:05:58 +09:00
Yuya Nishihara
3abe6be384 index: propagate DefaultIndexStore::init/reinit() errors 2023-12-29 13:05:58 +09:00
Yuya Nishihara
955f6e356a repo: add error propagation path to IndexStore initialization and loading
The error types are shared with the commit store backend. We could add per-store
error types, but it's unlikely that the caller needs to discriminate them.
2023-12-29 13:05:58 +09:00
Yuya Nishihara
bb73cd491f clenaup: don't use debug format to embed ObjectId in error message
Also fixed typo, s/a/an/.
2023-12-29 13:05:58 +09:00
Martin von Zweigbergk
d06764eb7c op heads: remove now-unused methods for adding/removing op heads 2023-12-28 09:17:42 -08:00
Martin von Zweigbergk
65a6aa61db op heads: replace last use of remove_op_head() by update_op_heads() 2023-12-28 09:17:42 -08:00
Martin von Zweigbergk
76516bb46b op heads: inline handle_ancestor_ops()
This gets us closer to being able to use the new `update_op_heads()`
function here (without calling it multiple times).
2023-12-28 09:17:42 -08:00
Martin von Zweigbergk
4221c7cf5c op heads: remove handle_ancestor_ops() from trait
I think the idea behind `handle_ancestor_ops()` was to let our backend
at Google delegate the work to the server, which could then avoid
walking ancestors. However, we're now thinking that we're going to
make our server resolve divergent operations on its own instead, so
the client will never see more than one op head, unless it manually
creates the second op head itself (e.g. because the user ran two
concurrent commands). In those cases it should be fine to do the
walk. So let's simplify the trait by removing the function.
2023-12-28 09:17:42 -08:00
Martin von Zweigbergk
f969f4b0b0 op heads: remove lifetime from OpHeadsStoreLock 2023-12-28 09:17:42 -08:00
Martin von Zweigbergk
c304777a35 op heads: remove promote_new_op()
`OpHeadsStoreLock::promote_new_op()` doesn't add much over the new
`update_op_heads()`, so let's switch to the latter.
2023-12-28 09:17:42 -08:00
Martin von Zweigbergk
b8e45d196f op heads: add a new trait method combining add and remove of op heads
Consider how one would implment the current `OpHeadsStore` interface
for a cloud-based backend. After `OpHeadsStore::add_op_head()` is
called, the set of op heads temporarily contains two heads (typically)
until `OpHeadsStore::remove_op_head()` is called. That's not invalid,
but it's annoying to have to deal with that state more than
necessary. Also, it's unnecessarily inefficient to send the addition
and removal of op heads as separate RPCs. This patch therefore adds a
`update_op_heads()` method that takes a list of old heads to remove
and a single new head to add. Coming patches will start migrating to
that method.
2023-12-28 09:17:42 -08:00
Martin von Zweigbergk
8137975785 op heads: drop support for old location/format
We move `.jj/repo/op_heads/*` into `.jj/repo/op_heads/heads/*` almost
a year ago, in commits 90a66ec262 and 37ba17589d. We said we would
drop support for it in 0.9+. I think we said that before we started
doing monthly releases, but I we're still past the goal of 6 months
(which is what I think we were aiming for).
2023-12-28 09:17:42 -08:00
Yuya Nishihara
dde42b9c05 index: rename resolve_prefix() to resolve_commit_id_prefix()
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.
2023-12-26 01:03:10 +09:00
Yuya Nishihara
0f2f566188 index: remove "segment_" prefix from IndexSegment methods
Since Readonly/MutableIndexSegment no longer implement Index trait, there's
no ambiguity between segment-local and index-global operations. Let's shorten
the method names.
2023-12-26 01:03:10 +09:00
Yuya Nishihara
c9b9e2864e index: introduce newtype that represents segment-local position
I'm thinking of changing some IndexSegment methods to return LocalPosition
instead of global IndexPosition, and using u32 there would be a source of bugs.
2023-12-26 01:03:10 +09:00
Yuya Nishihara
ee8d5e279a index: make segment-level lookup return neighbor commit ids instead of positions
Both readonly and mutable segments know the commit ids to return, and the
caller only needs the ids. Since segment_commit_id(local_pos) scans the graph
entries, doing that would increase the chance of cache miss.
2023-12-26 01:03:10 +09:00
Yuya Nishihara
0e7834feb9 index: inline segment_entry_by_pos()
There's no reasonable way to abstract the IndexEntry construction.
2023-12-26 01:03:10 +09:00
Ilya Grigoriev
1fb9df252b split.rs: stop using DescendantRebaser::new
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.
2023-12-24 19:25:16 -08:00
Ilya Grigoriev
6bfd09009f move.rs: remove use of MutRepo::create_descenant_rebaser.
After this, the internal function is only used in tests.
2023-12-24 19:25:16 -08:00
Ilya Grigoriev
cde8ea8985 Make CommitBuilder constructors private to the library crate
The implementation of `CommitBuilder::write` is tightly bound to the MutRepo,
so only MutRepo should construct CommitBuilder-s.
2023-12-24 19:25:16 -08:00
Yuya Nishihara
b954bab0ca index: fix partial reindexing to not lose commits only reachable from one side
Spotted while adding error propagation there. This wouldn't likely be a real
problem because "jj debug reindex" removes all of the operation links.

The "} else {" condition is removed because it doesn't make sense to exclude
only the exact parent_op_id operation. This can be optimized to not walk
ancestors of the parent_op_id operation, but I don't see a motivation to add
tests covering such scenarios. It's pretty rare that an intermediate operation
link is missing.
2023-12-24 23:31:16 +09:00
Yuya Nishihara
320d15412b index: let caller of segment-level save-in() squash segments explicitly
There are many unit tests that call mutable_segment.save_in(), but I don't
think these callers expect that the segment file could be squashed depending
on the size. Let's make it caller's responsibility.

maybe_squash_with_ancestors() should be cheap if segment_num_commits() == 0,
so it's okay to call it before checking the emptiness.
2023-12-24 00:22:47 +09:00