By default `git clone` will fetch all tags on a remote (unless
`--no-tags` is specified). Eventually we'll want to support the same
behavior, though since we first configure a remote and then fetch, we'll
need to configure the remote with the correct *general* tag fetching
behavior, but still perform the first fetch with all tags included.
This paves the way for the semantics of `jj undo` and `jj op revert` to
evolve independently. `jj op revert` is going to stay the low-level
command to apply the inverse of any operation. The new name is
consistent with `jj revert`, which applies the inverse of a commit.
`jj undo` on the other hand is planned to become a higher-level command,
which is more similar to, say, Ctrl+Z in typical GUI applications.
Running `jj undo` repeatedly will revert progressively older operations,
allowing the user to walk backwards in time. At the same time, `jj undo`
will lose the abilitly to revert arbitrary operations, to keep its
semantics simple and intuitive.
Related feature request "jj undo ergonomics":
https://github.com/jj-vcs/jj/issues/3700
The current implementation does linear search, which I think is good assuming
the size of the changed paths set is usually small. The next costly part of "jj
log PATH" is commit.empty() template on merge commits (#5411). We'll need a
public API to query changed-path index to optimize it.
This will allow us to "touch" change id without duplicating commits.
The caller should also do .generate_new_change_id() to not make commits
divergent. This function could do that automatically, but I'm not sure if that's
good. Alternatively, we can add mut_repo.duplicate_commit(predecessor), but
we'll need to refactor CommitRewriter.
When checking whether a file is binary, we check if the file exists a CR
character that isn't followed by a LF character. If so, we consider this
file as binary and don't apply EOL conversion unconditionally.
This commit is related to #7010.
For some reason, running `cargo update` makes clippy notice these can
be replaced with `Self`. I put this commit first, though, since it is
helpful regardless of the update.
This is the result of the following command after the `cargo update`
from the next commit (even though the refactor is valid regardless of
the `cargo update`).
```
cargo +nightly clippy --workspace --all-targets --all-features --fix
```
Tests of the indexed contents will be added with the revset engine integration.
We don't have a public interface to get the indexed changed paths right now.
I'm going to add changed-path index, and the operation link file will store a
list of segment files and a starting commit position. Suppose the link file is
small, we wouldn't need our own serialization format.
This patch adds new directory for proto-based operation link files. We could
reuse the existing directory, but that would make debugging a bit harder.
In a future commit we'll add support for controlling a git remote's tag
fetch behavior, which may result in a `tagOpt = --[no-]tags` entry in
the remote configuration.
Doing this change here means we will avoid incorrectly flagging remote
configurations as unsupported.
Most users colocate all of their repositories or none of them. A config
option is more convenient in that situation.
There are also plans to make colocated repos the default. This change
paves the way to flip the default easily.
Closes#2507.
Signed-off-by: Austin Seipp <aseipp@pobox.com>
The problem was spotted by Martin. Since we've made remove_transitive_edges()
omit "missing" edges from the set of nodes to visit at ad7c42e04b
"revset_graph: ignore missing edges thoroughly in remove_transitive_edges()", we
should also skip them in the input set.
This patch updates all test cases to run at bit-set boundary to detect other
potential issues.
This patch implements data format, serialization, and deserialization. Actual
indexing functions and disk I/O will be added later.
The data format is simple. It's basically a sorted table of paths + pointers to
the table entries per commit. Git employs Bloom filter for this purpose, but I
don't think we need a probabilistic data structure. The size of the serialized
index segments isn't big compared to the commit index segments, and the lookup
performance seems good. It's also important that we don't need to merge parent
trees when a path matches the indexed changed paths.
With git repo (77410 commits):
- changed-path segment file size: ~1.1MB
- jj log --ignore-working-copy README.md: ~0.2sec wall
Indexing takes minutes. That's not surprising because we have to merge parent
trees to get diffs.
#4674
The problem was that the calculation of the suffix was overlapping into
the the prefix for nested directories with the same name. We skipped the
prefix to avoid this issue.
Issue: #6853
Co-authored-by: Tobias Markus <tobias@miglix.eu>
We ran into a stack overflow in `merge_trees()` at Google due to
limited stack space and large stack frames caused by async code. This
patch fixes that by making `merge_trees()` non-recursive. Since I was
rewriting the algortithm anyway, I also made it concurrent, addressing
a TODO.
I'll make RevsetGraphWalk eliminate transitive edges from intermediate edges to
mitigate out-of-memory issue. This means that edges_from*() functions will call
remove_transitive_edges(). Maybe we could rewrite the whole process to not use
machine stack, but doing that would be complicated. The process wouldn't be
trivially-deterministic on where the look-ahead can terminate either.
The performance problem introduced by this patch will be fixed by later patches.
In small repo:
```
% hyperfine --sort command --warmup 3 --runs 10 -L bin jj-1,jj-2,jj-3,jj-4,jj-5 \
'target/release-with-debug/{bin} -R ~/mirrors/git --ignore-working-copy log -r "tags()"'
Benchmark 1: target/release-with-debug/jj-1 -R ~/mirrors/git --ignore-working-copy log -r "tags()"
Time (mean ± σ): 1.511 s ± 0.091 s [User: 1.296 s, System: 0.214 s]
Range (min … max): 1.432 s … 1.674 s 10 runs
Benchmark 2: target/release-with-debug/jj-2 -R ~/mirrors/git --ignore-working-copy log -r "tags()"
Time (mean ± σ): 2.467 s ± 0.142 s [User: 2.271 s, System: 0.196 s]
Range (min … max): 2.246 s … 2.588 s 10 runs
Relative speed comparison
1.32 ± 0.10 target/release-with-debug/jj-1 -R ~/mirrors/git --ignore-working-copy log -r "tags()"
2.16 ± 0.16 target/release-with-debug/jj-2 -R ~/mirrors/git --ignore-working-copy log -r "tags()"
```
In mid-size repo:
```
% hyperfine --sort command --warmup 3 --runs 10 -L bin jj-1,jj-2,jj-3,jj-4,jj-5 \
'target/release-with-debug/{bin} -R ~/mirrors/linux --ignore-working-copy log -r "tags(v5)"'
Benchmark 1: target/release-with-debug/jj-1 -R ~/mirrors/linux --ignore-working-copy log -r "tags(v5)"
Time (mean ± σ): 937.7 ms ± 68.8 ms [User: 672.1 ms, System: 265.4 ms]
Range (min … max): 868.3 ms … 1025.4 ms 10 runs
Benchmark 2: target/release-with-debug/jj-2 -R ~/mirrors/linux --ignore-working-copy log -r "tags(v5)"
Time (mean ± σ): 1.185 s ± 0.066 s [User: 0.920 s, System: 0.265 s]
Range (min … max): 1.132 s … 1.310 s 10 runs
Relative speed comparison
1.07 ± 0.11 target/release-with-debug/jj-1 -R ~/mirrors/linux --ignore-working-copy log -r "tags(v5)"
1.35 ± 0.12 target/release-with-debug/jj-2 -R ~/mirrors/linux --ignore-working-copy log -r "tags(v5)"
```
When no progress has been made, indicate that as 0.0 progress rather
than dividing by zero. Avoids in particular a display issue where the
progress bar indicates NaN% progress when fetching from slow remotes.
Fixes#7155
Change-Id: I6a6a6964d6572d1c98b5fa25285d26c07ee27a40
This allows evaluating ancestors/ranges involving filters significantly
faster. For instance, naively evaluating `::mine()` requires reading
every commit in the repo to check `mine()` on each commit, then finding
the ancestors of that set. This optimization rewrites `::mine()` to
`::heads(mine())`, since `heads(mine())` can be evaluated more
efficiently by only reading commits until the first successful match.
If someone is unaware of how revsets are implemented, this case can come
up pretty easily, such as by including `~mine()` in `immutable_heads()`
to make other people's commits immutable. In my local `jj` repo, this
optimization reduces the runtime of `jj log` with `~mine()` in
`immutable_heads()` from about 800ms down to about 50ms.
Benchmark results on Git repo:
```
::(v1.0.0..v2.40.0) 55.5% faster
author(peff).. 96.8% faster
```
ReadonlyIndexLoadError could be a wrapper of PathError instead, but that isn't
compatible with the abstraction of the current load functions. The inner load
functions may be called with an in-memory buffer.