Commit graph

610 commits

Author SHA1 Message Date
Martin von Zweigbergk
27a7fccefa revset: add a method returning a change id index
One of the remaining places we depend on index positions is when
creating a `ChangeIdIndex`. This moves that into the revset engine
(which is coupled to the commit index implementation) by adding a
`Revset::change_id_index()` method. We will also use this function
later when add support for resolving change id prefixes within a small
revset.

The current implementation simply creates an in-memory index using the
existing `IdIndex` we have in `repo.rs`.

The custom implementation at Google might do the same for small
revsets that are available on the client, but for revsets involving
many commits on the server, it might use a suboptimmal implementation
that uses longer-than-necessary prefixes for performance reasons. That
can be done by querying a server-side index including changes not in
the revset, and then verifying that the resulting commits are actually
in the revset.
2023-03-23 20:49:15 -07:00
Martin von Zweigbergk
d3cf543abc revset: move revset_for_commits() to test
The function is only used in tests, so it doesn't belong in
`default_revset_engine`. Also, it's not specific to that
implementation, so I rewrote as a revset evaluation.
2023-03-23 04:50:33 -07:00
Martin von Zweigbergk
5f74dd5db3 repo: implement Repo on ReadonlyRepo instead of its Arc
I'd like to be able to pass a `self` of `type `&ReadonlyRepo` to
functions that take a `&dyn Repo`. For that, we need `ReadonlyRepo`
itself to implement `Repo` instead of having `Arc<ReadonlyRepo>`
implement it. I could have solved it in a different way, but the `Arc`
requirement seems like an unnecessary constraint.
2023-03-21 21:43:44 -07:00
Martin von Zweigbergk
01d7239732 revset: make graph iterator yield commit ids (not index entries)
We only need `CommitId`s, and `IndexEntry` is specific to the default
index implementation.
2023-03-20 01:45:54 -07:00
Martin von Zweigbergk
2f876861ae graphlog: key by commit id (not index position)
The index position is specific to the default index implementation and
we don't want to use it in outside of there. This commit removes the
use of it as a key for nodes in the graphlog.

I timed it on the git.git repo using `jj log -r 'all()' -T commit_id`
(the worst case I can think of) and it slowed down from ~2.02 s to
~2.20 s (~9%).
2023-03-20 01:45:54 -07:00
Martin von Zweigbergk
91df7ec4c5 revset: rename graph iterator test to match implementation 2023-03-20 01:45:54 -07:00
Martin von Zweigbergk
f758b646a9 commit_builder: add accessors for most fields
I'd like to be able to access the current committer on a
`CommitBuilder`.
2023-03-19 00:48:05 -07:00
Martin von Zweigbergk
70d4a0f42e revset: remove context parameter from evaluate()
The `RevsetWorkspaceContext` argument is now instead used by the new
`resolve_symbol()` function.
2023-03-17 22:42:41 -07:00
Martin von Zweigbergk
d971148e4e revset: move resolve_symbol() back to revset module
The only caller is now in `revset.rs`.
2023-03-17 22:42:41 -07:00
Martin von Zweigbergk
94aec90bee revset: resolve symbols earlier, before passing to revset engine
For large repos, it's useful to be able to use shorter change id and
commit id prefixes by resolving the prefix in a limited subset of the
repo (typically the same subset that you'd want to see in your default
log output). For very large repos, like Google's internal one, the
shortest unique prefix evaluated within the whole repo is practically
useless because it's long enough that the user would want to copy and
paste it anyway.

Mercurial supports this with its `revisions.disambiguatewithin` config
(added in https://www.mercurial-scm.org/repo/hg/rev/503f936489dd). I'd
like to add the same feature to jj. Mercurial's implementation works
by attempting to resolve the prefix in the whole repo and then, if the
prefix was ambiguous, it resolves it in the configured subset
instead. The advantage of doing it that way is that there's no extra
cost of resolving the revset defining the subset if the prefix was not
ambiguous within the whole repo. However, there are two important
reasons to do it differently in jj:

* We support very large repos using custom backends, and it's probably
  cheaper to resolve a prefix within the subset because it can all be
  cached on the client. Resolving the prefix within the whole repo
  requires a roundtrip to the server.

* We want to be able to resolve change id prefixes, which is always
  done in *some* revset. That revset is currently `all()`, i.e. all
  visible commits. Even on local disk, it's probably cheaper to
  resolve a small revset first and then resolve the prefix within that
  than it is to build up the index of all visible change ids.

We could achieve the goal by letting each revset engine respect the
configured subset, but since the solution proposed above makes sense
also for local-disk repos, I think it's better to do it outside of the
revset engine, so all revset engines can share the code.

This commit prepares for the new functionality by moving the symbol
resolution out of `Index::evaluate_revset()`.
2023-03-17 22:42:41 -07:00
Martin von Zweigbergk
5afe5091a0 revset: add default_ prefix to graph iterator module
The current revset graph iterator is the default one, which the
default revset engine provides.
2023-03-14 05:32:02 -07:00
Martin von Zweigbergk
3871efd2f9 revset: move ReverseRevsetGraphIterator into revset module
The iterator is not specific to the implementation in
`revset_graph_iterator`, so it belongs in the standard `revset`
module.
2023-03-14 05:32:02 -07:00
Martin von Zweigbergk
f62fac24ac revset: move graph iteration onto Revset trait
We want to allow custom revset engines define their own graph
iterator. This commit helps with that by adding a
`Revset::iter_graph()` function that returns an abstract iterator.

The current `RevsetGraphIterator` can be configured to skip or include
transitive edges. It skips them by default and we don't expose option
in the CLI. I didn't bother including that functionality in the new
`iter_graph()` either. At least for now, it will be up to the
implementation whether it includes such edges (it would of course be
free to ignore the caller's request even if we added an option for it
in the API).
2023-03-14 05:32:02 -07:00
Martin von Zweigbergk
eed0b23009 revset: move current implementation to new module
We want to allow customization of the revset engine, so it can query
server indexes, for example. The current revset implementation will be
our default implementation for now. What's left in the `revset` module
after this commit is mostly parsing code.
2023-03-14 05:32:02 -07:00
Martin von Zweigbergk
ada48c6f71 revset: rename file() test for consistency
This should have been part of bbd6ef0c7b.
2023-03-13 07:20:35 -07:00
Martin von Zweigbergk
0a7de2540f tests: call num_commits() on specific implementation
This removes the last calls to `Index::num_commits()`.
2023-03-12 22:08:31 -07:00
Martin von Zweigbergk
5423feb8e1 tests: call stats() on specific implementation
This removes the remaining calls to `Index::stats()`.
2023-03-12 22:08:31 -07:00
Martin von Zweigbergk
59b40d8380 tests: avoid some unnecessary calls to index().stats()
The tests adding and removing heads to the repo mostly want to verify
that the set of heads is expected. Some of them also check that
commits are available in the index. But they shouldn't care about the
exact index stats.
2023-03-12 22:08:31 -07:00
Martin von Zweigbergk
121b86c89c tests: remove an obsolete TODO about unreachable commits in index
I don't think there's much to gain from making the index match exactly
what's reachable from the view. FWIW, our cloud-based implementation
at Google will probably make everyone's commits visible in the index
regardless of which operation they're at.
2023-03-12 22:08:31 -07:00
Martin von Zweigbergk
37151e0ff9 index: load store based on type recorded in .jj/repo/index/type
This is another step towards allowing a custom `jj` binary to have its
own index type. We're going to have a server-backed index
implementation at Google, for example.
2023-03-11 22:22:46 -08:00
Samuel Tardieu
182919ff6f git: add function to import a selection of the git refs 2023-03-02 10:09:08 +01:00
Samuel Tardieu
0ca4e2dad2 git: absence of globs is None rather than &[]
In `git_fetch()`, any glob present in `globs` is an "allow" mark. Using
`&[]` to represent an "allow-all" may be misleading, as it could
indicate that no branch (only the git HEAD) should be fetched.

By using an `Option<&[&str]>`, it is clearer that `None` means that
all branches are fetched.
2023-03-02 10:09:08 +01:00
Martin von Zweigbergk
bbd6ef0c7b revset: remove filter_by_diff(), have caller intersect expression
To be able to make e.g. `jj log some/path` perform well on cloud-based
repos, a custom revset engine needs to be able to see the paths to
filter by. That way it is able pass those to a server-side index. This
commit helps with that by effectively converting `jj log -r foo
some/path` into `jj log -r 'foo & file(some/path)'`.
2023-02-28 17:45:34 -08:00
Martin von Zweigbergk
346e3c849b repo: propagate error when failing to look up backend type 2023-02-27 09:44:28 -08:00
Martin von Zweigbergk
491ecc6b2e repo: replace load_at_head() by helper in tests
I'm about to make `RepoLoader::init()` return a `Result`, and I don't
want to have to wrap that in a new error in
`ReadonlyRepo::load_at_head()` since that's only used in tests.
2023-02-27 09:44:28 -08:00
Yuya Nishihara
da16bf340c conflicts: fix off-by-one error in materialize_merge_result()
This should fix #1304. I think the added test simulates the behavior of
multiple rebase conflicts, but I don't have expertise around this.

add_index could be replaced with a peekable iterator, but the iterator version
wouldn't be as readable as the current implementation.
2023-02-24 19:58:10 +09:00
Ilya Grigoriev
30d03a66e6 cmd: --branch option for git fetch.
Thanks to @samueltardieu for noticing a subtle bug in the refspecs, providing
the fix, as well as the two `conflicting_branches` tests.
2023-02-21 18:33:40 -08:00
Martin von Zweigbergk
bc9f66dad3 revset: replace RevsetIterator wrapper by extension
The type doesn't seem to provide any benefit. I don't think I had a
good reason for creating it in the first place; it was probably just
unfamiliarity with Rust.
2023-02-19 21:37:26 -08:00
Martin von Zweigbergk
30160f4d20 revset: pass revset, not iterator, into RevsetGraphIterator
I was thinking of replacing `RevsetIterator` by a regular
`Iterator<Item=IndexEntry>`. However, that would make it easier to
pass in an iterator that produces revisions in a non-topological order
into `RevsetGraphIterator`, which would produce unexpected results (it
would result in nodes that are not connected to their parents, if
their parents had already been emitted). I think it makes sense to
instead pass in a revset into `RevsetGraphIterator`.

Incidentally, it will also be useful to have the full revset available
in `RevsetGraphIterator` if we rewrite the algorithm to be more
similar to Mercurial's and Sapling's algorithm, which involves asking
the revset if it contains parent revisions.
2023-02-19 21:37:26 -08:00
Martin von Zweigbergk
f70e6987b5 conflicts: preserve order of adds in materialized conflict
We write conflict to the working copy by materializing them as
conflict markers in a file. When the file has been modified (or just
the mtime has changed), we parse the markers to reconstruct the
conflict. For example, let's say we see this conflict marker:

```
<<<<<<<
+++++++
b
%%%%%%%
-a
+c
>>>>>>>
```

Then we will create a hunk with ["a"] as removed and ["b", "c"] as
added.

Now, since commit b84be06c08, when we materialize conflicts, we
minimize the diff part of the marker (the `%%%%%%%` part). The problem
is that that minimization may result in a different order of the
positive conflict terms. That's particularly bad because we do the
minimization per hunk, so we can end up reconstructing an input that
never existed.

This commit fixes the bug by only considering the next add and the one
after that, and emitting either only the first with `%%%%%%%`, or both
of them, with the first one in `++++++++` and the second one in
`%%%%%%%`.

Note that the recent fix to add context to modify/delete conflicts
means that when we parse modified such conflicts, we'll always
consider them resolved, since the expected adds/removes we pass will
not match what's actually in the file. That doesn't seem so bad, and
it's not obvious what the fix should be, so I'll leave that for later.
2023-02-18 22:01:25 -08:00
Martin von Zweigbergk
975350f73b conflicts: demo bad roundtripping of conflict 2023-02-18 22:01:25 -08:00
Martin von Zweigbergk
fe0eb9137c conflicts: use snapshot testing for conflict-parsing 2023-02-18 22:01:25 -08:00
Martin von Zweigbergk
a87125d08b backend: rename ConflictPart to ConflictTerm
It took a while before I realized that conflicts could be modeled as
simple algebraic expressions with positive and negative terms (they
were modeled as recursive 3-way conflicts initially). We've been
thinking of them that way for a while now, so let's make the
`ConflictPart` name match that model.
2023-02-17 23:28:50 -08:00
Martin von Zweigbergk
e48ace56d1 conflicts: replace missing files by empty in materialized conflict
When we materialize modify/delete conflicts, we currently don't
include any context lines. That's because modify/delete conflicts have
only two sides, so there's no common base to compare to. Hunks that
are unchanged on the "modify" side are therefore not considered
conflicting, and since they they don't contribute new changes, they're
simply skipped (here:
3dfedf5814/lib/src/files.rs (L228-L230)).

It seems more useful to instead pretend that the missing side is an
empty file. That way we'll get a conflict in the entire file.

We can still decide later to make e.g. `jj resolve` prompt the user on
modify/delete conflicts just like `hg resolve` does (or maybe it
actually happens earlier there, I don't remember).

Closes #1244.
2023-02-17 22:19:04 -08:00
Martin von Zweigbergk
e1d71c3713 conflicts: add test for materializing modify/delete conflict 2023-02-17 22:19:04 -08:00
Martin von Zweigbergk
dfcc7a9cee conflicts: merge modify/delete and delete/modify tests
The two tests only differ in the order of the changes in the input, so
let's reuse some of the setup code.
2023-02-17 22:19:04 -08:00
Martin von Zweigbergk
af3f8b6cfd conflicts: create a helper for creating a ConflictPart in test 2023-02-17 22:19:04 -08:00
Martin von Zweigbergk
d8997999f2 repo: replace RepoRef by Repo trait 2023-02-15 19:15:17 -08:00
Martin von Zweigbergk
f6a4cb57da repo: extract a Repo trait for Arc<ReadonlyRepo> and MutableRepo
This will soon replace the `RepoRef` enum, just like how the `Index`
trait replaced the `IndexRef` enum.
2023-02-15 19:15:17 -08:00
Martin von Zweigbergk
8a067282c8 repo: make ReadonlyRepo::index() return a &dyn Index
This is just a little preparation for extracting a `Repo` trait that's
implemented by both `ReadonlyRepo` and `MutableRepo`. The `index()`
function in that trait will of course have to return the same type in
both implementations, and that type will be `&dyn Index`.
2023-02-15 19:15:17 -08:00
Martin von Zweigbergk
2d8aa2d90e index: delete IndexRef, use Index trait
I don't know why I didn't create a trait to begin with. Maybe I had
trouble with lifetimes or object-safety.
2023-02-14 06:51:49 -08:00
Martin von Zweigbergk
b955e3de03 index: extract a trait for the index
Even though we don't know the details yet, we know that we want to
make the index pluggable like the commit and opstore
backends. Defining a trait for it should be a good step. We can refine
the trait later.
2023-02-14 06:51:49 -08:00
Martin von Zweigbergk
a474c688a8 index: simplify a test helper by specializing it
We apparently always have an `&Arc<ReadonlyIndex>` where we call the
`generation_number()` function.
2023-02-14 06:51:49 -08:00
Martin von Zweigbergk
9261bfe5fc revset: resolve change ids only using the new hex digits
Now that we use the new hex digits when we display change ids, we no
longer need to be able to resolve the old (conventional) digits.
2023-02-13 22:49:21 -08:00
Martin von Zweigbergk
39640cc288 revset: allow resolving change id using hex digits from reverse alphabet
By separating the value spaces change ids and commit ids, we can
simplify lookup of a prefix. For example, if we know that a prefix is
for a change id, we don't have to try to find matching commit ids. I
think it might also help new users more quickly understand that change
ids are not commit ids.

This commit is a step towards that separation. It allows resolving
change ids by using hex digits from the back of the alphabet instead
of 0-f, so 'z'='0', 'y'='1', etc, and 'k'='f'. Thanks to @ilyagr for
the idea. The regular hex digits are still allowed.
2023-02-13 22:49:21 -08:00
Martin von Zweigbergk
fafa9b70fc view: also merge git_heads when merging views
I don't know if I had just forgotten to merge `git_heads` when I added
it to the view object, but it seems like it should be merged just like
refs.
2023-01-30 09:05:03 -08:00
Martin von Zweigbergk
4e8fbaa210 git: allow conflicts in "HEAD@git"
Git's HEAD ref is similar to other refs and can logically have
conflicts just like the other refs in `git_refs`. As with the other
refs, it can happen if you run concurrent commands importing two
different updates from Git. So let's treat `git_head` the same as
`git_refs` by making it an `Option<RefTarget>`.
2023-01-30 09:05:03 -08:00
Glen Choo
3418c8ff73 git: add git.auto-local-branch
Add a new git.auto-local-branch config option. When set to false, a
remote-tracking branch imported from Git will not automatically create a
local branch target. This is implemented by a new GitSettings struct
that passes Git-related settings from UserSettings.

This behavior is particularly useful in a co-located jj and Git repo,
because a Git remote might have branches that are not of everyday
interest to the user, so it does not make sense to export them as local
branches in Git. E.g. https://github.com/gitster/git, the maintainer's
fork of Git, has 379 branches, most of which are topic branches kept
around for historical reasons, and Git developers wouldn't be expected
to have local branches for each remote-tracking branch.
2023-01-29 20:17:49 -08:00
Glen Choo
4716c1e9e2 git: test import of remote-only branch
This test coverage will become more important when we make changes to
remote branch importing.
2023-01-29 20:17:49 -08:00
Yuya Nishihara
824f2106fd repo: migrate revset::resolve_change_id() to use IdIndex for ReadonlyRepo
The MutableRepo implementation is the same as before.
2023-01-26 14:10:26 +09:00
Martin von Zweigbergk
10725c095f cleanup: update more "checkout" to "working-copy commit" and similar
I've preferred "working-copy commit" over "checkout" for a while
because I think it's clearer, but there were lots of places still
using "checkout". I've left "checkout" in places where it refers to
the action of updating the working copy or the working-copy commit.
2023-01-25 11:02:59 -08:00
Martin von Zweigbergk
37ba17589d simple_op_heads_store: rename storage directory
`SimpleOpHeadsStore` currently stores its files in
`.jj/repo/op_heads/simple_op_heads/`. The `.jj/repo/op_heads/type`
file indicates the type of op-heads backend. If that contains
"simple_op_head_store", we use the `SimpleOpHeadsStore`
backend. There's no need for the `simple_op_heads` directory to also
indicate the type of backend in its name. I kept just the `heads` in
the name to make it less redundant with the parent directory (which is
`op_heads)`. We could alternatively call the directory `values` or
similar.
2023-01-25 09:22:38 -08:00
Daniel Ploch
bd43580437 op_heads_store: remove LockedOpHeads
Make op resolution a closed operation, powered by a callback provided by the
caller which runs under an internal lock scope. This allows for greatly
simplifying the internal lifetime structuring.
2023-01-20 15:18:08 -08:00
Vamsi Avula
60d1537731 let branches and remote_branches revset functions take needles as arguments
- branches has the signature branches([needle]), meaning the needle is optional (branches() is equivalent to branches("")) and it matches all branches whose name contains needle as a substring
- remote_branches has the signature remote_branches([branch_needle[, remote_needle]]), meaning it can be called with no arguments, or one argument (in which case, it's similar to branches), or two arguments where the first argument matches branch names and the second argument matches remote names (similar to branches, remote_branches(), remote_branches("") and remote_branches("", "") are all equivalent)
2023-01-16 12:15:30 +05:30
Ilya Grigoriev
aef0801917 Fix random seed in all tests that use testutils::user_settings
This doesn't change any tests, but could prevent change ids
randomly matching commit id prefixes from causing tests
to fail in the future.

Follows up on bbd49cdf29, https://github.com/martinvonz/jj/issues/1024
and https://github.com/martinvonz/jj/pull/1033.
2023-01-15 10:15:44 -08:00
Yuya Nishihara
bbd49cdf29 tests: stabilize change id in test_resolve_symbol_commit_id()
Hopefully fixes #1024.
2023-01-14 23:49:16 +09:00
Yuya Nishihara
40a9f75441 workspace: do not look up ancestor paths by Workspace::load()
I don't think Workspace::load() should be permissive in that regard.
WorkspaceLoader could provide such function, but I feel it's more like
CLI business. CLI can also look for parent '.git' directory to suggest
'jj init --git-repo=..' if needed.
2023-01-10 23:31:26 +09:00
Waleed Khan
e299963fae backend: remove PartialEq/Eq implementations
As soon as we start tracking the `#[source]` for error variants, we won't be able to rely on the presence of `Eq` implementations.
2023-01-02 12:28:51 -06:00
Waleed Khan
7f8a196ab2 backend: create ObjectId trait
This lets us operate over various kinds of objects polymorphically (e.g. call `.hex()` on any kind of object hash).
2023-01-02 12:28:51 -06:00
Yuya Nishihara
996ac22921 matchers: simplify FilesMatcher::new() to take slice of paths 2022-12-30 14:15:27 +09:00
Martin von Zweigbergk
d86ba708a3 repo: add MutableRepo::rewrite_commit() returning CommitBuilder
Same reasoning as the previous commit.
2022-12-26 23:30:52 -08:00
Martin von Zweigbergk
812ef97adb repo: add MutableRepo::new_commit() returning CommitBuilder
Since `CommitBuilder` now has a reference to `MutableRepo`, it's
convenient to create instances of it by calling a method on
`MutableRepo`.
2022-12-26 23:30:52 -08:00
Martin von Zweigbergk
f3208f59c4 store: propagate error from Backend::write_commit() 2022-12-26 23:30:52 -08:00
Martin von Zweigbergk
f1d7bbe508 testutils: create a function for writing a random commit to MutableRepo
We already have `create_random_commit()`, which returns a
`CommitBuilder`. Most callers directly write that to a
`MutableRepo`. That currently returns a `Commit`, but I'm about to
make it propagate errors from the backend. That would add an
`unwrap()` to this sequence, making it longer. Let's create a simple
helper for these callers to simplify this common pattern.
2022-12-26 23:30:52 -08:00
Martin von Zweigbergk
49b2f3b6ca commit_builder: keep MutableRepo reference
When you're done with the `CommitBuilder`, you're going to have to
call `write_to_repo()`, passing it a mutable `MutableRepo`
reference. It's a bit simpler to pass that reference when we create
the `CommitBuilder` instead, so that's what this patch does.

A drawback of passing in the mutable reference when we create the
builder is that we can't have multiple unfinished `CommitBuilder`
instance live at the same time. We don't have any such use cases yet,
and it's not hard to work around them, so I think this change is worth
it.
2022-12-26 23:30:52 -08:00
Yuya Nishihara
986649623d commit_builder: relax type of description parameter
The next commit will introduce a newtype for -m/--message argument which
can be converted Into<String>.

Since CommitBuilder is a thin wrapper, code bloat caused by generic parameters
wouldn't matter. I have another set of commits that makes all builder methods
accept Into/IntoIterator, which will remove some of .clone() calls from tests.
2022-12-22 14:59:03 +09:00
Daniel Ploch
e9bd6fbeae op_heads_store: give the OpHeadsStore factory semantics 2022-12-16 10:47:48 -08:00
Daniel Ploch
90a66ec262 op_heads_store: move op_heads into a subdir, to make room for the 'type' marker 2022-12-16 10:47:48 -08:00
Martin von Zweigbergk
fb396e6b45 cleanup: address unnecessary_borrow lints reported by Clippy 1.66
Interestingly, the nightly release doesn't complain about this. One
instance in `test_working_copy.rs` is a bug in Clippy.
2022-12-15 12:38:01 -08:00
Martin von Zweigbergk
7f9a0a2820 cleanup: let new Clippy move variables into format strings
I ran an upgraded Clippy on the codebase. All the changes seem to be
about using variables directly in format strings instead of passing
them as separate arguments.
2022-12-14 21:30:58 -08:00
Daniel Ploch
bd31bfd2d7 repo: give OpStore factory load semantics 2022-12-14 14:10:30 -08:00
Daniel Ploch
7cbea42a24 repo: rename BackendFactories to StoreFactories 2022-12-14 14:10:30 -08:00
Yuya Nishihara
6237f3cdfd revset: fold nested parents expressions
Some other ancestors() expressions can also be substituted. Practically,
this is the rule to fold repeated '-' operators to evaluate them lazily.
2022-12-13 15:55:18 +09:00
Yuya Nishihara
4a889b986c index: implement generation filter on RevWalkGenerationRange
This will be a building block of 'parents(base)' revset. 'base---' will
be .filter_by_generation(3..4) for example. I think 'ancestors(base)' can
also have an optional generation parameter, but I haven't considered any
particular syntax yet.
2022-12-11 13:14:19 +09:00
Yuya Nishihara
951eb0b61a revset: use filter intersection for tree containing filter
This basically transforms 's1 & (f() | s2)' to
's1.iter().filter(all && f || s2)'. Still the predicate part includes "all",
the filter function doesn't need to load commit data for every entry since
's1.iter().filter(all)' is tested first. To optimize "all" predicate out,
maybe we can add a wrapper that returns '|_: &IndexEntry| true'.

Instead of inserting AsFilter(_) node, I could add a recursive is_filter()
function. That would also work so long as the height of RevsetExpression tree
is limited. I chose node insertion just for ease of snapshot testing.
2022-12-07 11:01:59 +09:00
Ilya Grigoriev
55762e3681 Rename FileConflictData to ConflictHunk, use it in files.rs.
There's no point in having two identical types used for the same
purpose in two different places.
2022-12-03 15:12:40 -08:00
Martin von Zweigbergk
8a440d8042 git: on export, use repo view's git_refs as record of old export state
@yuja asked on #701 about the difference between the state in the
`git_export_view` and what we have in `mut_repo.view()`. It's true
that the branches in `mut_repo.view().git_refs()` should match what we
wrote to disk. We can therefore remove the on-disk storage and
simplify quite a bit. For now, I create the `last_export_view` from
the `mut_repo.view().git_refs()` before calling
`export_changes()`. I'll clean up a bit more next.

I think this is correct even considering e.g. undo. Let's consider
what would happen in a non-colocated Git repo (not because tricky
cases cannot happen there but because the explicit exports and imports
make it easier to discuss, and more cases can occur). If the user
moved a branch and then did `jj git export`, `jj undo`, and then `jj
git export` again, we would think on the second export that we should
perform the same changes to the Git repo, which should have no effect.

This patch also fixes the bug we were forced to work around in the
test case in the previous patch.

This removes one of our uses of Thrift.
2022-12-03 09:32:49 -08:00
Martin von Zweigbergk
39792368ba git: when exporting, don't overwrite changes made by git
This fixes the bugs shown by the tests added in the previous patch by
checking that the git branches we're about to update have not been
updated by git since our last export. If they have, we fail those
branches. The user can then re-import from the git repo and resolve
any conflicts before exporting again.

I had to update the `test_export_import_sequence` to make it
pass. That shows a new bug, which I'll fix next. The problem is that
the exported view doesn't get updated on import, so we would try to
export changes compared to an earlier export, even though we actually
knew (because of the `jj git import`) that the state in git had
changed.
2022-12-03 09:32:49 -08:00
Martin von Zweigbergk
9b59461242 git: add test for concurrent change in git repo between exports
If you update a branch using regular `git` (or some Git-based tool)
between two `jj git export`, we will overwrite that change if you had
also changed the branch in jj land. There's a similar problem if you
delete the branch in jj land. Let's have a test for that. I'm going to
make us not overwrite it soon. This patch adds a test for those cases,
plus many other cases in consistent way. Since the new test covers
some cases tested by existing tests, I removed those tests.
2022-12-03 09:32:49 -08:00
Martin von Zweigbergk
b80c39d77c view: test that merging divergent rewrites results in both commits visible
It seems that we didn't have a test for this simple case. I wrote this
test case while working on #111 but I don't know why I didn't push it
back then.
2022-12-01 19:20:38 -08:00
Pranay Sashank
47067c1368 git: do not delete or track git submodules.
A new FileType, GitSubmodule is added which is ignored. Files or
directories having this type are not added to the work queue and
are ignored in snapshot. Submodules are not created by jujutsu
when resetting or checking out a tree, they should be currently
managed using git.
2022-12-01 23:14:55 +05:30
Yuya Nishihara
48d10d648c revset: add unary negate (or set complement) operator '~y'
Because a unary negation node '~y' is more primitive than the corresponding
difference node 'x~y', '~y' is easier to deal with while rewriting the tree.
That's the main reason to add RevsetExpression::NotIn node.

As we have a NotIn node, it makes sense to add an operator for that. This
patch reuses '~' token, which I feel intuitive since the other set operators
looks like bitwise ops. Another option is '!'.

The unary '~' operator has the highest precedence among the set operators,
but they are lower than the ranges. This might be counter intuitive, but
useful because a prefix range ':x' can be negated without parens.

Maybe we can remove the redundant infix operator 'x ~ y', but it isn't
decided yet.
2022-11-29 15:46:15 +09:00
Martin von Zweigbergk
d8feed9be4 copyright: change from "Google LLC" to "The Jujutsu Authors"
Let's acknowledge everyone's contributions by replacing "Google LLC"
in the copyright header by "The Jujutsu Authors". If I understand
correctly, it won't have any legal effect, but maybe it still helps
reduce concerns from contributors (though I haven't heard any
concerns).

Google employees can read about Google's policy at
go/releasing/contributions#copyright.
2022-11-28 06:05:45 -10:00
Yuya Nishihara
e40c041384 revset: merge AmbiguousChange/CommitIdPrefix error into one
Follows up c5ed3e1477. Now change/commit ids are resolved at the same
precedence, which means there are at least three types of ambiguity.
I don't think we would need to discriminate these.
2022-11-28 22:49:07 +09:00
Yuya Nishihara
c5ed3e1477 revset: for short hash, look up both commit and change ids to disambiguate
Because the use of the change id is recommended, any operation should abort
if a valid change id happens to match a commit id. We still try the commit
id lookup first as the change id lookup is more costly.

Ambiguous change/commit id is reported as AmbiguousCommitIdPrefix for now.
Maybe we can merge AmbiguousCommit/ChangeIdPrefix errors into one?

Closes #799
2022-11-28 17:30:53 +09:00
Yuya Nishihara
7632466cc0 revset: add table of symbol aliases and pass around parse functions
The CLI will load aliases from config, insert them one by one, and warn if
declaration part is invalid. That's why RevsetAliasesMap is a public struct
and needs to be instantiated by the caller.
2022-11-27 20:12:22 +09:00
Martin von Zweigbergk
a90ef20976 git: on export, delete deleted refs before adding added refs
To reduce conflicts between branches like `main` and `main/sub`, it's
better to first delete refs in git that have been deleted in jj, and
then add/update refs that have been added/updated in jj.
2022-11-26 06:05:29 -10:00
Martin von Zweigbergk
4a03b94d65 git: on export, skip failed refs instead of failing whole export
Since we now write a (partial) view object of the exported branches to
disk (since 7904474320), we can safely skip exporting some
branches. We already skip conflicted branches. This commit makes us
also skip branches that we fail to write to the backing Git repo,
instead of failing the whole operation (after possibly updating some
Git refs).

I made the `export_refs()` function return the branches that
failed. We should probably make that a struct later and have a
separate field for branches that we skipped due to conflicts.

Closes #493.
2022-11-26 06:05:29 -10:00
Martin von Zweigbergk
6a2f295ae4 git: add test for exporting refs that fail
This adds a test for attempting to export both a branch called `main`
and one called `main/sub` (#493), as well as for exporting a branch
with an empty string as name (reported directly to me by @lkorinth).
2022-11-26 06:05:29 -10:00
Martin von Zweigbergk
2a87815006 cleanup: remove a few unnecessary borrows, as reported by Clippy 2022-11-26 06:05:29 -10:00
Yuya Nishihara
84efed420f revset: allow empty string literal "" 2022-11-20 13:11:28 +09:00
Yuya Nishihara
a81ebeb85e revset: add empty() predicate to find commits with no file change
The expression 'x ~ empty()' is identical to 'x & file(".")', but more
intuitive.

Note that 'x ~ empty()' is slower than 'x & file(".")' since the negative
intersection isn't optimized right now. I think that can be handled as
follows: 'x ~ filter(f)' -> 'x & filter(!f)' -> 'filter(!f, x)'
2022-11-16 08:50:33 +09:00
Martin von Zweigbergk
780d7fb59c backend: rename NormalFile to just File
There are no "non-normal" files, so "normal" is not needed. We have
symlinks and conflicts, but they are not files, so I think just "file"
is unambiguous.

I left `testutils::write_normal_file()` because there it's used to
mean "not executable file" (there's also a `write_executable_file()`).

I left `working_copy::FileType::Normal` since renaming `Normal` there
to `File` would also suggest we should rename `FileType`, and I don't
know what would be a better name for that type.
2022-11-14 23:36:43 -08:00
Martin von Zweigbergk
9502d84872 operations: make hostname and username configurable
We currently get the hostname and username from the `whoami` crate. We
do that in lib crate, without giving the caller a way to override
them. That seems wrong since it might be used in a server and
performing operations on behalf of some other user. This commit makes
the hostname and username configurable, so the calling crate can pass
them in. If they have not been passed in, we still default to the
values from the `whoami` crate.
2022-11-14 10:02:04 -08:00
Martin von Zweigbergk
26a554818a git: update our record of Git branches on export
When we export branches to Git, we didn't update our own record of
Git's refs. This frequently led to spurious conflicts in these refs
(e.g. #463). This is typically what happened:

 1. Import a branch pointing to commit A from Git
 2. Modify the branch in jj to point to commit B
 3. Export the branch to Git
 4. Update the branch in Git to point to commit C
 5. Import refs from Git

In step 3, we forgot to update our record of the branch in the repo
view's `git_refs` field. That led to the import in step 5 to think
that the branch moved from A to C in Git, which conflicts with the
internal branch target of B.

This commit fixes the bug by updating the refs in the `MutableRepo`.

Closes #463.
2022-11-13 15:06:10 -08:00
Martin von Zweigbergk
9cf8a3684b git: make export_refs() act on mutable repo
When exporting refs, we should update our record of Git's refs. For
that, we need a mutable repo.
2022-11-13 15:06:10 -08:00
Martin von Zweigbergk
5eba305844 git: when exporting, skip conflicted branches 2022-11-13 15:06:10 -08:00
Martin von Zweigbergk
759ddd1e60 git: on initial export, export all branches
As I said in the previous patch, I don't know why I made the initial
export to Git a no-op. Exporting everything makes more sense to
(current-)me. It will make it slightly easier to skip exporting
conflicted branches (#463). It also lets us remove a `jj export` call
from `test_templater.rs`.
2022-11-13 15:06:10 -08:00
Martin von Zweigbergk
979b46b006 tests: test exporting to Git after deleting a branch 2022-11-13 15:06:10 -08:00
Martin von Zweigbergk
ebfe0a4823 tests: add test for export of conflicted branches
To fix #463, I think we want to skip conflicted branches when we
export instead of erroring out. It seems we didn't have test case for
the current behavior, so let's add one.
2022-11-13 15:06:10 -08:00
Martin von Zweigbergk
18a25a7c2b tests: demonstrate spurious branch conflict after git export
This is a test case for #463. It's not exactly the same case, but I'm
confident that the root cause is the same (that the
`.jj/repo/git_export_operation_id` doesn't include the git refs we
just updated).
2022-11-13 15:06:10 -08:00
Martin von Zweigbergk
ec46ae11ad tests: extract function for getting git Oid from jj Commit 2022-11-13 15:06:10 -08:00
Martin von Zweigbergk
eb89f6b6ca tests: consistently import create_random_tree()
These calls often appear in expressions long enough that not having to
qualify it means that we can sometimes avoid wrapping a line. I
noticed because IntelliJ told me that `test_git.rs` had some
unnecessary qualificiations (the function was already imported there).
2022-11-13 15:06:10 -08:00
Martin von Zweigbergk
3c7c4e9f5c tests: move testutils module into separate crate
The `testutils` module should ideally not be part of the library
dependencies. Since they're used by the integration tests (and the CLI
tests), we need to move them to a separate crate to achieve that.
2022-11-08 07:29:35 -08:00
Yuya Nishihara
fa3ad16bf2 revset: add present(set) predicate that suppresses NoSuchRevision error
This is copied from Mercurial. Typical use case I have in mind is
"present(master) | present(main)" in stock revset.
2022-11-07 21:41:54 +09:00
Benjamin Saunders
88a4f83cf8 git: factor ssh key lookup out of lib 2022-11-06 17:31:29 -08:00
Benjamin Saunders
b55c4ae0a3 git: move progress callback into a struct 2022-11-06 17:31:29 -08:00
Martin von Zweigbergk
61468ed126 commit_builder: remove redundant for_open_commit()
The function is now the same as `for_new_commit()`, except that it
accepts only one parent.
2022-11-05 06:14:37 -07:00
Martin von Zweigbergk
6703810c6e backend: remove Commit::is_open field from data model 2022-11-05 06:14:37 -07:00
Martin von Zweigbergk
6dd91cf1c1 test_mut_repo: also run tests with Git backend
I haven't tried to figure out when it happened, but these tests seem
to consistently pass now.
2022-11-05 06:14:37 -07:00
Yuya Nishihara
78c0cf81bf revset: pass workspace context around parse() functions
The next commit will move file path resolution to parse().
2022-11-02 01:02:37 +09:00
Martin von Zweigbergk
416a36a59c git: don't abandon root commit when all refs are gone
If you remove all refs from the backing Git repo and then run `jj git
import`, we would see that all commits disappeared from the Git repo,
so we would remove them from the jj repo too. However, we do that by
doing a history walk from old heads to the new heads, which includes
the root commit when the new heads is an empty set. That means that we
mark the root commit as abandoned, which led to a crash in
`rewrite.rs` (when we try pick the root commit's first parent to use
as parent for rebased commits).
2022-10-29 03:02:26 -07:00
Martin von Zweigbergk
20eb9ecec1 git: don't abandon HEAD commit when it loses a branch
I was trying to create a reproduction script for #412, but the script
ran into another bug first. The script removed all the local and
remote branches from the backing Git repo. I noticed that we would
then try to abandon all commits. We should still count Git HEAD's
target as visible and not try to abandon it. This patch fixes that.
2022-10-29 03:02:26 -07:00
Benjamin Saunders
3d1ac8b933 repo: propagate I/O errors gracefully from ReadonlyRepo::init 2022-10-28 11:51:53 -07:00
Benjamin Saunders
cfa46c50e2 workspace: propagate I/O errors gracefully 2022-10-28 11:51:53 -07:00
Yuya Nishihara
59717aa187 revset: remove redundant candidates argument from merges()
Since 'merges()' just filters the candidates set per item, it doesn't need
a candidates argument. Perhaps, 'merges(x)' could be a predicate to select
merge commits within a subgraph 'x', but I don't know if that would be
useful.
2022-10-27 21:33:35 +09:00
Yuya Nishihara
373c63b414 revset: remove redundant candidates argument from filter predicates 2022-10-27 21:33:35 +09:00
Yuya Nishihara
f48675ad90 revset: evaluate optimized expression 2022-10-27 21:33:35 +09:00
Benjamin Saunders
c03c746f8d cli: report fetch progress continuously 2022-10-23 12:13:25 -07:00
Martin von Zweigbergk
c366795d80 tests: remove obsolete workaround for WorkingCopy reading from $HOME
Since d56ae79d3f, `WorkingCopy` no longer reads `.gitignores`
directly from `$HOME/.gitignore`, so we don't need the workaround to
prevent it in the tests.
2022-10-23 11:08:22 -07:00
Yuya Nishihara
cb2fcde560 revset: implement file(pattern[, candidates]) predicate
The name "file()" is just copied from hg. I'm not sure if it's good in
jj's context, but I couldn't find a better name.
2022-10-24 01:48:00 +09:00
Yuya Nishihara
d5cf2582dc revset: instantiate Workspace in tests where workspace_id is needed
This makes resolve_commit_ids_in_workspace() reusable for file() revset
tests.
2022-10-24 01:48:00 +09:00
Yuya Nishihara
5c52b4e819 revset: introduce wrapper struct to pass around workspace information
More workspace-derived parameters will be added, and I don't think wrapping
with Option for each makes sense because all parameters should be available
if workspace exists.
2022-10-24 01:48:00 +09:00
Yuya Nishihara
efb8c5e58a revset: make filter_by_diff() accept either borrowed or owned matcher
So filter_by_diff() can also be used to evaluate file() revset.

I've never seen Borrow<T> for this sort of abstraction, but it seems a valid
use case of Borrow<T>.

https://stackoverflow.com/a/69318514
https://github.com/rust-lang/rust/blob/1.64.0/compiler/rustc_mir_dataflow/src/framework/cursor.rs#L45
2022-10-24 01:48:00 +09:00
Benjamin Saunders
037eaaf36c repo: forbid checking out the root commit
Prevents `jj edit root` from succeeding, which would otherwise place
the repo in a state where every operation panics.
2022-10-21 10:10:07 -07:00
Benjamin Saunders
b009019d8d cli: add git remote rename subcommand 2022-10-20 11:04:16 -07:00
Yuya Nishihara
f5d0419384 working_copy: return {operation_id, workspace_id} by reference
Let WorkspaceCommandHelper clone it. WorkspaceCommandHelper could return
workspace_id by reference, but doing that would introduce noisy .clone()
calls and lifetime mess.
2022-10-03 21:41:20 -07:00
Yuya Nishihara
1800354465 working_copy: remove .clone() from TreeState proxy methods
Let the caller .clone() as needed.
2022-10-02 22:46:09 +09:00
Martin von Zweigbergk
3fc7b549ec cleanup: rename some more variables from checkout_* to ~wc_ 2022-09-29 23:51:34 -07:00
Martin von Zweigbergk
3e0d49e847 workspace: make capable of loading with out-of-tree backend 2022-09-25 09:40:42 -07:00
Martin von Zweigbergk
87bcee6cf2 repo: make capable of loading repo with out-of-tree backend
This changes `RepoLoader` to take a map of functions that load a
specific type of backend, keyed by the backend type. The backend type
is read from `.jj/repo/store/backend`.
2022-09-25 09:40:42 -07:00
Martin von Zweigbergk
c02f87170d repo: remove init_*() functions used only in tests
The `ReadonlyRepo::init_*()` functions were unused or used only in
tests. Let's remove them, thereby making the repo less aware of
specific backend implementations.
2022-09-25 09:40:42 -07:00
Martin von Zweigbergk
ea5aa0a96d cleanup: replace some PathBuf args by &Path
In many of these places, we don't need an owned value, so using a
reference means we don't force the caller to clone the value. I really
doubt it will have any noticeable impact on performance (I think these
are all once-per-repo paths); it's just a little simpler this way.
2022-09-25 09:40:42 -07:00
Martin von Zweigbergk
0108673087 backend: let each backend handle root commit on write
This moves the logic for handling the root commit when writing commits
from `CommitBuilder` into the individual backends. It always bothered
me a bit that the `commit::Commit` wrapper had a different idea of the
number of parents than the wrapped `backend::Commit` had.

With this change, the `LocalBackend` will now write the root commit in
the list of parents if it's there in the argument to
`write_commit()`. Note that root commit itself won't be written. The
main argument for not writing it is that we can then keep the fake
all-zeros hash for it. One argument for writing it, if we were to do
so, is that it would make the set of written objects consistent, so
any future processing of them (such as GC) doesn't have to know to
ignore the root commit in the list of parents.

We still treat the two backends the same, so the user won't be allowed
to create merges including the root commit even when using the
`LocalBackend`.
2022-09-20 21:20:57 -07:00
Martin von Zweigbergk
76fd6a830d CommitBuilder: take parents as argument in for_new_commit()
It's rare to want to create a commit directly off of the root commit,
so let's have the caller tell us which parents they want.
2022-09-20 21:20:57 -07:00
Yuya Nishihara
16f2b82feb conflicts: change diff line marker to %%%%%%%
I feel the original -------/+++++++ pair is slightly confusing because
each half can be a separator by itself. I don't know what character other
than '-'/'+' is preferred, but let's pick '%' (for "mod") per @martinvonz
suggestion.
2022-09-20 15:26:29 +09:00
Martin von Zweigbergk
6812bd9584 cleanup: rename checkout to wc_commit
`wc_commit` seems clearer than `checkout` and not too much longer. I
considered `working_copy` but it was less clear (could be the path to
the working copy, or an instance of `WorkingCopy`). I also considered
`working_copy_commit`, but that seems a bit too long.
2022-09-18 16:19:58 -07:00
Yuya Nishihara
98a66002b0 revset: add function to filter commits by matcher
This will be a basic building block of 'jj log PATH'. The implementation
is naive, but works fine for small repos like jj. For mid-size repos,
there would be various areas which need to be optimized.
2022-09-16 13:02:58 +09:00
Josh Soref
fd3f8afe1a spelling: nonexistent
Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>
2022-09-09 11:58:37 -07:00
Josh Soref
e0bd06818e spelling: commit
Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>
2022-09-09 11:58:37 -07:00
Yuya Nishihara
3b835df66e tests: do not use TempDir::into_path() which would persist the directory
https://docs.rs/tempfile/3.3.0/tempfile/struct.TempDir.html#method.into_path
2022-09-07 23:49:46 +09:00
Yuya Nishihara
872081c867 tests: use testutils::new_temp_dir() thoroughly 2022-09-07 23:49:46 +09:00
Yuya Nishihara
51520bc87b working_copy: don't follow symlinks while creating parent directories
Otherwise a file could be created out of the working copy directory.

This only works for untracked symlinks and sequentially "added" symlinks
and files. For "removed" and "modified" entries, the parent directories are
considered valid and fs::remove_file() will be called. This also doesn't
prevent race conditions caused by concurrent checkouts.

New create_parent_dirs() would be slightly slower than the original because
it traverses directories from the root whereas fs::create_dir_all() does that
from the leaf and exits when reached to a directory.
2022-08-17 13:22:51 +09:00
Martin von Zweigbergk
21f5bf8b15 cleanup: fix some things reported by clippy 1.63 2022-08-12 09:10:32 -07:00
Yuya Nishihara
cc860f771c working_copy: do not overwrite ignored file
Since the file should have been removed on Diff::Modified case, we can always
expect that write_file/conflict() creates new file.
2022-08-07 15:06:30 +02:00
Yuya Nishihara
0ac8d370df tests: leverage fs::read() in test_gitignores_checkout_overwrites_ignored() 2022-08-07 15:06:30 +02:00
Martin von Zweigbergk
b84be06c08 conflicts: minimize diffs in materialized conflicts
One advantage of our conflict marker style (compared to the usual
3-way markers) is that they provide the user with the diff between the
base and one side so the user doesn't have to do that in their head
(which is how I use 3-way markers anyway). However, since we currently
always use the "first" side for the diff, that diff can be larger than
if we had picked the other side, which makes the marker style worse
than the usual 3-way markers. This has bothered me many times and it's
about time we fix it.
2022-07-12 07:46:45 -07:00
Martin von Zweigbergk
fc578a2dd7 conflicts: use insta in conflict tests 2022-07-12 07:46:45 -07:00
Martin von Zweigbergk
1b5cd140d5 CommitBuilder: remove unneeded store arguments
The `CommitBuilder::store` field is used only in
`CommitBuilder::write_to_repo()`, but we can easily get access to the
`Store` from the `repo` argument there, so let's remove the field.
2022-07-06 07:21:57 -07:00
Martin von Zweigbergk
6952b4f91e rewrite: create new checkout on top iff commit abandoned
When rebasing commits after rewrites, we also update all workspaces'
checkouts. If the new commit is closed, we create a new commit on
top. Since we're hoping to remove the open/closed concept, we need a
new condition. I considered creating a new commit on top if the change
ID was different from before the rewrite. However, that would make at
least `jj split` more complicated because it makes the first commit
keep the change ID but it wants the second commit to be checked
out. This patch instead creates the new commit on top only when the
original commit was abandoned.
2022-07-01 08:58:08 +08:00
Martin von Zweigbergk
bd1a8bd930 repo: split out an edit() function from MutableRepo::check_out() 2022-07-01 08:58:08 +08:00
Martin von Zweigbergk
0fe203ce8f cleanup: fix an unused import on Windows
`OperationId` is only used in `test_snapshot_special_file()`, which
doesn't run (or even  build) on Windows.
2022-06-29 07:21:24 +08:00
Martin von Zweigbergk
29a71c619a working_copy: ignore special files
This patch makes us treat special files (e.g. Unix sockets) as absent
when snapshotting the working copy. We can consider later reporting
such files back to the caller (possibly via callback) so it can inform
the user about them.

Closes #258
2022-06-20 09:26:29 +07:00
Martin von Zweigbergk
bcf94bd70e CommitBuilder: when rewriting commit, replace placeholder user/email
If a commit's author field has the placeholder user/email values
(i.e. "(no name configured)" and "(no email configured)"), and they
have now configured their email and username, they probably want us to
update the author field with the new information, so that's what this
patch does. Thanks to durin42@ for the suggestion on #322.
2022-06-06 17:31:01 -07:00
Martin von Zweigbergk
fa4b5aa2c7 working_copy: propagate most errors on checkout 2022-05-25 11:51:18 -07:00
Martin von Zweigbergk
5c6f82ec7b tests: remove &UserSettings argument from TestRepo::init()
We don't even have any settings that affect the repo, so there's no
point in passing the settings. I think this was a leftover from before
we separated out the "workspace" concept; now we no longer create a
working-copy commit when we initialize a repo (we do that when we
attach the workspace).
2022-05-21 22:33:16 -07:00
Martin von Zweigbergk
4cf04f373e tests: move init_{repo,workspace} functions onto types
I tried to create a `TestRepo` and was surprised that I couldn't do
that by calling a function on it.
2022-05-21 22:33:16 -07:00
Martin von Zweigbergk
6c6e6cb423 checkout: don't abandon old commit if it has non-empty description
If the user entered a description, we shouldn't abandon it even if it
has no changes to the content.
2022-05-21 22:12:15 -07:00
Martin von Zweigbergk
0747da0491 revset_graph_iterator: add a mode for generating reverse graph
The request to show the log output with more recent commits at the
bottom comes up once in a while (among Mercurial users, and now also
for jj from @arxanas). It's pretty easy to implement by adding an
adapter to the current `RevsetGraphIterator`. It works by first
collecting all nodes and edges into a vector and then yielding them in
reverse order and with reversed edges. That means it's no longer lazy,
but that seems fine since the feature is optional. Also, it's only the
subset of nodes that are in the selected revset that will be
collected.

Making the CLI use the new iterator adapter will come in a later
patch.
2022-05-15 05:17:54 -07:00
Martin von Zweigbergk
7268e5608e working_copy: propagate errors when snapshotting
Closes #258
2022-05-02 11:23:38 -07:00
Martin von Zweigbergk
543a95c653 rewrite: propagate backend errors in DescendantRebase::rebase_next() 2022-05-02 08:05:24 -07:00
Martin von Zweigbergk
96b3e05bc5 working_copy: rename write_tree() to snapshot()
I think I copied the name `write_tree()` from Git, but I find it quite
confusing, since it's not clear if it write a tree to the working copy
or reads the working copy and writes a tree to the store (it's the
former).
2022-05-02 08:00:15 -07:00
Martin von Zweigbergk
57ba9a9409 git: when importing refs, abandon commits that were abandoned in git
Now that I'm using GitHub PRs instead of pushing directly to the main
branch, it's quite annoying to have to abandon the old commits after
GitHub rebases them. This patch makes it so we compare the remote's
previous heads to the new heads and abandons any commits that were
removed on the remote. As usual, that means that descendants get
rebased onto the closest remaining commit.

This is half of #241. The other half is to detect rewritten branches
and rebase on top.
2022-04-28 11:28:09 -07:00
Martin von Zweigbergk
e3254fa5c4 rewrite: don't rewrite the "removed" side of a branch conflict
Let's say we have a simple history like this:

```
B C D
 \|/
  A
```

Branch `main` initially points to commit B. Two concurrent operations
then move the branch to commits C and D. When the two concurrent
operations get merged, the branch will be recorded as pointing to
"C+D-B". If a subsequent operation now abandons commit B, we would
update the "removed" side of the branch conflict. That seems a little
dishonest. I think the reason I did it that way was in order to not
keep B visible back when having it present in the "removed" side would
keep it visible (before 33bf6ce1d5).

I noticed this issue while working on #241 because
`test_import_refs_reimport()` started failing. That test case is
pretty much exactly the case above.
2022-04-28 11:28:09 -07:00
Martin von Zweigbergk
18a64c365a working_copy: respect sparse patterns when writing tree (#52) 2022-04-26 14:52:17 -07:00
Martin von Zweigbergk
0d881de56c working_copy: allow updating sparse patterns (#52)
With this patch, we add support for setting the sparse patterns, and
we respect it when updating the working copy.
2022-04-26 14:52:17 -07:00
Martin von Zweigbergk
ceb6c152a1 working_copy: record sparse patterns in the tree state (#52)
This patch makes room for sparse patterns in the `TreeState` proto
message. We also start setting that value to a list of just the
pattern `.` when we create new working copies. Old working copies
without the sparse patterns are also interpreted as having that single
pattern. Note that this absence of sparse patterns is different from a
present list of no patterns. The latter is a valid state and means
that no paths are included in the sparse checkout.
2022-04-26 14:52:17 -07:00
Martin von Zweigbergk
04f11c0dc3 rebase: update bookkeeping for branches as we rebase descendants
The `DescendantRebaser` keeps a map of branches from the source
commit, so it gets efficient lookup of branches to update when a
commit has been rebased. This map was not kept up to date as we
rebased. That could lead to branches getting left on hidden
intermediate commits. Specifically, if a commit with a branch was
rewritten by some command, and an ancestor of it was also rewritten,
then we'd only update the branch only the first step and not update it
again when rebasing onto the rewritten ancestor.
2022-04-25 14:05:27 -07:00
Martin von Zweigbergk
21d8c501e3 cleanup: replace .tree().id() by tree_id() to avoid looking up trees 2022-04-21 21:54:52 -07:00
Martin von Zweigbergk
762c8984c6 trees: when merging trees and one is missing, treat it as empty
When a directory is missing in one merge input (base or one side), we
would consider that a merge conflict. This patch changes that so we
instead merge trees by treating the missing tree as empty.
2022-04-20 13:47:03 -07:00
Martin von Zweigbergk
53911b076b working_copy: fix crash when updating and only executable bit changed 2022-04-14 23:46:28 -07:00
Martin von Zweigbergk
7e79f25508 revset: add a roots() function 2022-04-13 23:24:51 -07:00
Martin von Zweigbergk
9ff21d8924 revset: add a connected() function
This introduces a `connected(x)` function, which is simply the same as
`x:x`. It's occasionally useful if `x` is a long expression. It's also
useful as a building block for `root(x)` (coming soon).
2022-04-13 23:24:51 -07:00
Martin von Zweigbergk
fa6b14f166 revset: rename internal head() to visible_heads() 2022-04-13 23:24:51 -07:00
Martin von Zweigbergk
600aad62f4 tests: extract some variables for repeated expressions 2022-03-31 10:23:33 -07:00
Martin von Zweigbergk
f16d2a237b backend: pass in path when reading/writing conflicts as well
We do it for all the other kinds of objects already. It's useful to
have the path for backends that store objects by path (we don't have
any such backends yet). I think the reason I didn't do it from the
beginning was because we had separate `RepoPath` types for files and
directories back then.
2022-03-31 10:23:33 -07:00
Martin von Zweigbergk
fd5bc7966c tests: pass around &RepoPath instead of &str in working copy test
This is a leftover from when there were separate `RepoPath` types for
directories and files.
2022-03-31 10:23:33 -07:00
Martin von Zweigbergk
a9d1b16937 workspace: canonicalize workspace and repo paths internally
We depend on comparing the workspace root with the Git repo's path to
know if we're sharing the working copy with it. For that to work
reliably, we need the paths to be canonicalized, so that's what this
patch tries to do.
2022-03-30 22:09:55 -07:00
Martin von Zweigbergk
6cd4e03c25 cleanup: use canonicalize() method instead of free function
I had somehow not noticed that `Path` and `PathBuf` have
`canonicalize()` methods. Using them saves a few characters of code.
2022-03-30 22:09:55 -07:00
Martin von Zweigbergk
662297acc3 tests: add test for delete/modify branch-conflict case (#32)
There was a TODO about adding a test case for a delete/modify conflict
in a branch target that got resolved by abandoning a commit. The
resolution is to delete the branch. That case couldn't happend with
our old evolution-based mechanism for tracking rewrites (because we
couldn't un-prune a commit then).
2022-03-27 21:11:55 -07:00
Martin von Zweigbergk
04ad9a3628 repo: when merging in removed head, rebase descendants (#111) 2022-03-26 22:31:49 -07:00
Martin von Zweigbergk
ec84de7779 repo: clarify that some repo functions load the repo at head (#111) 2022-03-26 22:31:49 -07:00
Martin von Zweigbergk
a38dd9d693 repo: make resolution of concurrent operations a separate step (#111)
This is yet another refactoring step to allow the UI layer to inspect
and control how concurrent operations are resolved.
2022-03-26 22:31:49 -07:00
Martin von Zweigbergk
e384f97b20 transaction: check that we haven't forgotten to rebase descendants (#111)
If we have recorded in `MutableRepo` that commits have been abandoned
or rewritten, we should always rebase descendants before committing
the transaction (otherwise there's no reason to record the
rewrites). That's not much of a risk in the CLI because we already
have that logic in a central place there (`finish_transaction()`), but
other users of the library crate could easily miss it. Perhaps we
should automatically do any necessary rebasing we commit the
transaction in the library crate instead, but for now let's just have
a check for that to catch such bugs.
2022-03-26 22:31:49 -07:00
Martin von Zweigbergk
a663a5d89c repo: don't abandon empty commit if it has descendants
It's unusual for the current commit to have descendants, but it can
happen. In particular, it can easily happen when you run `jj new`. You
probably don't want to abandon it in those cases.
2022-03-26 21:11:42 -07:00
Martin von Zweigbergk
3f24411bbf cargo: upgrade the config crate from 0.11.0 to 0.12.0
This required a bit of work.
2022-03-18 22:33:04 -07:00
Martin von Zweigbergk
d56ae79d3f working_copy: let caller pass in base Git ignores (#65, #87)
The library crate shouldn't look up the user's `$HOME` directory
(maybe the library is used by a server process), so let's have the
caller pass it into the library crate instead.
2022-03-12 10:48:06 -08:00
Waleed Khan
dd3272fe90 build: use assert_matches crate
The `assert_matches` feature is nightly-only, so use this crate as a shim.
2022-02-20 22:21:14 -08:00
Martin von Zweigbergk
03e6b8c0e6 working_copy: take Tree, not CommitId, as argument to check_out()
We no longer need the commit ID, so we shouldn't make the callers pass
it. This lets us simplify several tests, because they no longer to
create commits just to check out a tree in the working copy.
2022-02-13 12:14:34 -08:00
Martin von Zweigbergk
315e5e87a3 working_copy: take a tree object instead of ID in TreeState::check_out()
The callers mostly have the tree object available anyway.
2022-02-13 12:12:08 -08:00
Martin von Zweigbergk
00c9a1ae11 working_copy: stop taking commit ID in LockedWorkingCopy::finish()
We used to use the value to detect races, but we use the tree ID and
the operation ID these days, so we don't need the commit ID.

By changing this, we can avoid creating some commit IDs in tests,
which is why I tackled this issue now.
2022-02-12 23:48:06 -08:00
Martin von Zweigbergk
e098c01935 working_copy: replace commit ID by tree ID for checking for changes
What matters for the working copy is the tree ID. We should be able to
remove the commit ID. This patch gets us close.
2022-02-12 17:16:19 -08:00
Martin von Zweigbergk
537b1de7d9 working_copy: move check of old commit ID on checkout to higher level
There are only two callers of `LockedWorkingCopy::check_out()`. One is
in `commands.rs`. That caller already checks after taking the lock
that the old commit ID is as expected. The other caller is
`WorkingCopy::check_out()`. We can simply move the check to that level
since it's the only caller that cares now.
2022-02-12 14:27:40 -08:00
Martin von Zweigbergk
dabfd04da6 tests: attempt to de-flake operation-merging test
We resolve checkouts in favor of the first-committed operation (which
is more likely to have managed to update the working copy). The test
case has been flaky on GitHub lately. I've run it 1000 times on my
machine without failure. I don't know if GitHub's machines are just
faster in some way (SSD, maybe) that makes them finish the two
operations in the test in the same millisecond. Let's add a
1-millisecond sleep to see if that helps. If it doesn't, then maybe
the issue is that the clock has lower precision (or their clocks can
go backwards?).
2022-02-09 11:15:10 -08:00
Martin von Zweigbergk
b74851e005 working_copy: make sure discarded update is not visible
`LockedWorkingCopy::discard()` shouldn't result in changes to the
on-disk state, but `LockedWorkingCopy::check_out()` may have already
written a state file, which is surprising. The changes also remain in
memory, which is also surprising. Let's fix both of those issues.
2022-02-09 10:40:51 -08:00
Martin von Zweigbergk
d24cf15f2d tests: in .gitignore test, explicitly save working copy state
One of the .gitignore tests writes a tree from the working copy
twice. However, it discards the `LockedWorkingCopy` instance after the
first write, so the second write shouldn't really see the changes from
the first write. It does see them because we don't clear them in
memory (and we also surprisingly write them to disk). I'm about to fix
that, so the test needs to be fixed first.
2022-02-09 10:34:52 -08:00
Martin von Zweigbergk
3c787459dc tests: remove a leftover removal of a checkout in a revset test
The test setup no longer attaches a workspace to the repo, so there's
also no need remove it.
2022-02-05 20:11:50 -08:00
Martin von Zweigbergk
f294df6e8e view: inline checkout() into remaining few callers 2022-02-05 15:43:37 -08:00
Martin von Zweigbergk
9b275a406c tests: don't create workspaces in CommitBuilder tests 2022-02-05 15:39:03 -08:00
Martin von Zweigbergk
980e80618c tests: don't create workspaces in conflict tests 2022-02-05 15:39:03 -08:00