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

421 commits

Author SHA1 Message Date
Martin von Zweigbergk
aa78f97d55 git: refactor tests by extracting some common setup (#44) 2021-12-10 23:12:22 -08:00
Martin von Zweigbergk
c678a89794 cleanup: fix some issues reported by new clippy and/or rustc 2021-12-10 14:12:45 -08:00
Martin von Zweigbergk
7b724512dd repo: don't use stale view when checking for changes
I recently (0c441d9558) made it so we don't create an operation when
nothing changed. Soon thereafter (94e03f5ac8), I broke that when I
introduced a cache-invalidation bug when I made the filtering-out of
non-heads be lazy. This patch fixes that and also adds a test to
prevent regressions.
2021-12-05 22:01:48 -08:00
Martin von Zweigbergk
f1bfe85f45 revsets: add git_head() revset
This is part of #44.
2021-12-01 11:08:53 -08:00
Martin von Zweigbergk
8a2f630ac0 git: start tracking HEAD of underlying Git repo
This patch adds a place for tracking the current `HEAD` commit in the
underlying Git repo. It updates `git::import_refs()` to record it. We
don't use it anywhere yet.

This is part of #44.
2021-12-01 11:08:53 -08:00
Martin von Zweigbergk
06bccb3387 transaction: remove Drop implementation
I can't remember when the `Drop` implementation last helped me find a
bug, so let's just remove it.
2021-12-01 10:31:35 -08:00
Martin von Zweigbergk
a27e77205a git: don't import refs/remotes/origin/HEAD as a branch called "HEAD"
`refs/remotes/origin/*` are usually (remote-tracking) branches, but
`refs/remotes/origin/HEAD` is not.
2021-12-01 08:15:36 -08:00
Martin von Zweigbergk
c6cba59c27 workspace: move creation of .jj/ directory from Repo to Workspace 2021-11-25 21:08:43 -08:00
Martin von Zweigbergk
f17aced374 workspace: move search for .jj/ directory from Repo to Workspace 2021-11-25 21:08:43 -08:00
Martin von Zweigbergk
ea172f5f24 tests: when reloading a repo, pass in repo path, not workspace root
I'm about to change `ReadonlyRepo::load()` to take the path to the
`.jj/` directory, so this patch prepares for that. It already works
because `ReadonlyRepo::load()` will search up the directory tree for
the `.jj/` entry.
2021-11-25 21:07:28 -08:00
Martin von Zweigbergk
831a0a7707 tests: remove some more calls to Repo::working_copy_path() 2021-11-25 21:07:28 -08:00
Martin von Zweigbergk
466d35d4bc workspace: add functions for initializing a repo
`ReadonlyRepo::init_*()` currently calls `WorkingCopy::init()`. In
order to remove that dependency, this patch wraps the
`ReadonlyRepo::init_*()` functions in new `Workspace` functions. A
later patch will have those functions call `WorkspaceCopy::init()`.`
2021-11-25 21:07:28 -08:00
Martin von Zweigbergk
c08adba424 repo: remove working_copy(), only used in tests
This is another step towards removing coupling between the repo and
the working copy, so we can have multiple working copies for a single
repo (#13).
2021-11-25 21:04:56 -08:00
Martin von Zweigbergk
afe3bd5c2f testutils: update write_working_copy_file() to take a Workspace 2021-11-25 21:04:56 -08:00
Martin von Zweigbergk
f82459ab1b test: remove a trivial use of Repo::working_copy_path() 2021-11-25 21:04:56 -08:00
Martin von Zweigbergk
d8626645b8 tests: avoid Repo::working_copy_path() in test_bad_locking
I'm about to remove `Repo::working_copy_path()` since I'm further
decoupling the repo from the working copy.
2021-11-25 21:04:56 -08:00
Martin von Zweigbergk
2c91af339b tests: extract variable for store in test_conflicts 2021-11-25 21:04:56 -08:00
Martin von Zweigbergk
ce094f64d5 testutils: make init_repo return a struct, including a Workspace
This is a fairly mechanical change; I'll do some minor cleanups in
later commits.
2021-11-25 21:04:56 -08:00
Martin von Zweigbergk
70073b94a8 repo: stop keeping a WorkingCopy instance
The `Repo` doesn't do anything with the `WorkingCopy` except keeping a
reference to it for its users to use. In fact, the entire lib crate
doesn't do antyhing with the `WorkingCopy`. It therefore seems simpler
to have the users of the crate manage the `WorkingCopy` instance. This
patch does that by letting `Workspace` own it. By not keeping an
instance in `Repo`, which is `Sync`, we can also drop the
`Arc<Mutex<>>` wrapping.

I left `Repo::working_copy()` for convenience for now, but now it
creates a new instance every time. It's only used in tests.

This further decoupling should help us add support for multiple
working copies (#13).
2021-11-25 21:04:56 -08:00
Martin von Zweigbergk
8cf5dd286a backend: make Vec inside CommitId non-public
The recent e5dd93cbf7, whose description says "cleanup: make Vec
inside CommitId etc. non-public", made all ID types in the `backend`
module *except* for `CommitId` non-public :P This patch makes
2021-11-19 23:19:00 -08:00
Martin von Zweigbergk
6c0f3625ff tests: avoid accessing working copy just to get its commit ID
The view has been the source of truth for the currently checked-out
commit for a long time now.
2021-11-17 12:45:18 -08:00
Martin von Zweigbergk
33b272f5fa working_copy: make some functions require mutable references
We use interior mutability for caching in `WorkingCopy`, but let's
still take mutable reference in the functions where the state change
is visible.
2021-11-17 10:15:33 -08:00
Martin von Zweigbergk
287602966e working_copy: add a method for untracking specified paths 2021-11-17 08:41:37 -08:00
Martin von Zweigbergk
ced252f766 cleanup: replace some as_slice() by & 2021-11-10 10:55:58 -08:00
Martin von Zweigbergk
27107637f2 git: fix regression in pruning of remote refs
A while ago, I replaced a call to git2-rs's `Remote::fetch()` by calls
to `Remote::download()` and `Remote::update_tips()`. The function is
documented to be a convenience for those function, but it turns out
that the pruning of deleted remote refs is a separate call
(`Remote::prune()`), so we need to call that too.
2021-11-07 16:02:18 -08:00
Martin von Zweigbergk
e901a4e66b repo: don't materialize conflicts on checkout
Since the working copy can now handle conflicts, we don't need to
materialize conflicts when checking out a commit.

Before this patch, we used to create a new commit on top whenever we
checked out a commit with conflicts. That new commit was intended just
for resolving the conflicts. The typical workflow was the resolve the
conflicts and then amend. To use the same workflow after this patch,
one needs to explicitly create a new commit on top with `jj new` after
checking out a commit with conflict.
2021-11-07 15:17:51 -08:00
Martin von Zweigbergk
ea82340654 working_copy: preserve conflicts in the working copy until markers are removed
I realized only recently that we can try to parse conflict markers in
files and leave them as conflicted if they haven't changed. If they
have changed and some conflict markers have been removed, we can even
update the conflict with that partial resolution.

This change teaches the working copy to write conflicts to the working
copy. It used to expect that the caller had already updated the tree
by materializing conflicts. With this change, we also start parsing
the conflict markers and leave the conflicts unresolved in the working
copy if the conflict markers remain.

There are some cases that we don't handle yet. For example, we don't
even try to set the executable bit correctly when we write
conflicts. OTOH, we didn't do that even before this change.

We still never actually write conflicts to the working copy (outside
of tests) because we currently materialize conflicts in
`MutRepo::check_out()`. I'll change that next.
2021-11-07 15:17:51 -08:00
Martin von Zweigbergk
cea6061f3d conflicts: add a function for parsing a materialized conflict
I initially made the working copy materialize conflicts in its
`check_out()` method. Then I changed it later (exactly a year ago, on
Halloween of 2020, actually) so that the working copy expected
conflicts to already have been materalized, which happens in
`MutableRepo::check_out`().

I think my reasoning then was that the file system cannot represent a
conflict. While it's true that the file system itself doesn't have
information to know whether a file represents a conflict, we can
record that ourselves. We already record whether a file is executable
or not and then preserve that if we're on a file system that isn't
able to record it. It's not that different to do the same for
conflicts if we're on a file system that doesn't understand conflicts
(i.e. all file systems).

The plan is to have the working copy remember whether a file
represents a conflict. When we check if it has changed, we parse the
file, including conflict markers, and recreate the conflict from
it. We should be able to do that losslessly (and we should adjust
formats to make it possible if we find cases where it's not).

Having the working copy preserve conflict states has several
advantages:

 * Because conflicts are not materialized in the working copy, you can
   rebase the conflicted commit and the working copy without causing
   more conflicts (that's currently a UX bug I run into every now and
   then).

 * If you don't change anything in the working copy, it will be
   unchanged compared to its parent, which means we'll automatically
   abandon it if you update away from it.

 * The user can choose to resolve only some of the conflicts in a file
   and squash those in, and it'll work they way you'd hope.

 * It should make it easier to implement support for external merge
   tools (#18) without having them treat the working copy differently.

This patch prepares for that work by adding support for parsing
materialized conflicts.
2021-11-07 15:17:51 -08:00
Martin von Zweigbergk
9abee0096f conflicts: propagate errors from materialize_conflict()
All current callers pass in a buffer, so it should never fail, but the
function itself can't know that.
2021-10-24 23:02:00 -07:00
Martin von Zweigbergk
b4a0e513dd revset graph: make order of edges stable
While working on demos, I noticed that `jj log` output in the
octocat/Hello-World repo was unstable: sometimes the first parent of
the merge was on the left and sometimes it was on the right. This
patch fixes that by sorting the edges by position in the index just
before returning them. It seems that most applications would want
stable output so I put it in the `RevsetGraphIterator` rather than
doing at the call site in the CLI. I ordered them with the reverse
index position rather than forward because it seemed to make the
graphs in the git.git repo slight nicer, with the left-most edge going
between subsequent releases.

There performance difference is within the noise level.
2021-10-23 20:33:59 -07:00
Martin von Zweigbergk
33bf6ce1d5 view: don't force commits pointed to by refs to be current heads
If you rewrite a commit that's also available on some remote, you'll
currently see both the old version and the new version in the view,
which means they're divergent. They're not logically divergent (the
rewritten version should replace the old version), so this is a UX
bug. I think it indicates that the set of current heads should be
redefined to be the *desired* heads. That's also what I had suspected
in the TODO removed by this change.  I think another indication that
we should hide the old heads even if they have e.g. a remote branch
pointing to them is that we don't want them to be rebased if we
rewrite an ancestor.

So that's what I decided to do: let the view's heads be the desired
heads. The user can still define revsets for showing non-current
commits pointed to by e.g. remote branches.
2021-10-23 09:15:05 -07:00
Martin von Zweigbergk
c0ae4b16e8 trees: try to resolve file conflicts after simplifying conflicts
This fixes a bug I've run into somewhat frequently. What happens is
that if you have a conflict on top of another conflict and you resolve
the conflict in the bottom commit, we just simplify the `Conflict`
object in the second commit, but we don't try to resolve the new
conflict. That shows up as an unexpected "conflict" in `jj log`
output, and when you check out the commit, there are actually no
conflicts, so you can just `jj squash` right away.

This patch fixes that bug. It also teaches the code to work with more
than 3 parts in the merge, so if there's a 5-way conflict, for
example, we still try to resolve it if possible.
2021-10-22 09:20:50 -07:00
Martin von Zweigbergk
2e4dc019d9 git: don't update public heads for now 2021-10-20 14:23:58 -07:00
Martin von Zweigbergk
c0a26f7642 conflicts: work around rust-lang/rust#89716 2021-10-13 13:41:09 -07:00
Martin von Zweigbergk
b4b64eb7e5 conflicts: add tests of conflict materialization 2021-10-13 13:40:25 -07:00
Martin von Zweigbergk
d8c0282873 revset: make head() accept candidate set to find heads within
With this change, you can do e.g. `heads(remote_branches())`. That
should currently be the same as `public_heads()`, except that we don't
yet remove public heads when remote branches have been updated. Having
this support should be generally useful, but I may use it in the short
term specifically for depending less on the public heads, until I get
around to keeping them up to date.
2021-10-13 09:41:20 -07:00
Martin von Zweigbergk
aebdd4e8fd revset: add all() function 2021-10-13 09:28:11 -07:00
Martin von Zweigbergk
5874d5abfb revset: add none() function 2021-10-13 09:24:08 -07:00
Martin von Zweigbergk
8465a578be revset: split out a new remote_branches() from branches()
It seems useful to be able to use `remote_branches()` in revsets
e.g. for filtering out commits known on remotes.
2021-10-10 12:24:48 -07:00
Martin von Zweigbergk
fdb861b957 backend: remove unused Commit::is_pruned (#32) 2021-10-06 23:53:15 -07:00
Martin von Zweigbergk
4c4e436f38 evolution: delete it now that we don't use it anymore (#32)
It's been a lot of work, but now we're finally able to remove the
`Evolution` state! `jj obslog` still works as before (it just walks
the predecessor pointers).
2021-10-06 23:28:30 -07:00
Martin von Zweigbergk
4c8beee81c Transaction: don't remove hidden heads on commit
The removal of hidden heads was just there to help with the transition
away from evolution (#32). Now that we no longer depend on evolution
for removing old heads, we can remove the hack.
2021-10-06 23:20:23 -07:00
Martin von Zweigbergk
108c38d816 evolution: don't create pruned commits (#32)
Now that we rebase descendants and remove old heads as appropriate
(without using evolution), we don't need to create pruned commits
anymore.
2021-10-06 23:20:23 -07:00
Martin von Zweigbergk
b7acbae168 DescendantRebaser: also remove old heads
This patch teaches `DescendantRebaser` to also update heads. That's
done at the end of the rebase (when `rebase_next()` starts returning
`None`), which is a little weird. We should probably change the
interface, but this will do for now.

With this change, we should no longer need to remove hidden heads when
the transaction commits. That will remove one of the last bits of
dependence on evolution from most commands (#32).
2021-10-06 22:01:39 -07:00
Martin von Zweigbergk
e26d21dc18 revset: add .commit_ids() and .commits() to RevsetIterator
This makes it a little easier to iterate over commits or commit ids.
2021-10-06 14:18:11 -07:00
Martin von Zweigbergk
9ec27645cf revsets: remove all_heads()
Now that we remove hidden heads whenever a transaction commits,
`non_obsolete_heads()` should always be the same as `all_heads()`,
except during a transaction. I don't think we depend on the difference
even during a transaction. Let's simplify a bit by removing the revset
function `all_heads()` and renaming `non_obsolete_heads()` to
`heads()`. This is part of issue #32.
2021-10-06 12:21:18 -07:00
Martin von Zweigbergk
f3bee0b12e evolution: remove support evolving orphans and divergent commits (#32) 2021-10-03 22:38:49 -07:00
Martin von Zweigbergk
fcb79ef0a6 DescendantRebaser: also update checkout (#32)
This is similar to how a recent change taught `DescendantRebaser` to
update branches pointing to rewritten commits. Now we also update the
checkout if it pointed to a rewritten commit.
2021-10-03 22:38:49 -07:00
Martin von Zweigbergk
5be75d0e31 DescendantRebaser: also update branches
This patch moves the logic for updating branches from
`update_branches_after_rewrite()` into `DescendantRebaser`. The
branches are now updated along with each rebased commit rather than
all being updated at the end. The new code uses the information about
rewritten and abandoned commits that `DescendantRebaser` gets from
`MutableRepo`. That is different from the old code, which used the
evolution state. This patch thus moves us one step closer to removing
evolution (#32).
2021-10-03 10:07:09 -07:00
Martin von Zweigbergk
a78976cd29 DescendantRebaser: allow passing divergent changes as input
I'm going to teach `DescendantRebaser` to also update local branches
pointing to rewritten commits, taking over the responsibility from
`rewrite::update_branches_after_rewrite()`. For commits that have been
rewritten as multiple new commits (divergent, not split), that
function makes local branches pointing to the old commit point to all
the new commits. To replicate that behavior in `DescendantRebaser`, it
needs to know about divergent changes. This change addresses that.
2021-10-02 23:12:46 -07:00
Martin von Zweigbergk
de0df90b66 tests: use letters instead of numbers for commits in test_rewrite
Letters let you make it clearer by using e.g. "X2" for a rewritten
commit "X"..
2021-10-02 23:12:46 -07:00
Martin von Zweigbergk
1c55c02106 Transaction: remove hidden heads on commit
I recently made the CLI remove hidden heads when a transaction is
committed (38474a9). Let's move that to `Transaction::commit()`, so
the library crate becomes more similar to how the CLI behaves and more
similar to our evolution-less future (#32).
2021-10-02 23:12:46 -07:00
Martin von Zweigbergk
41ebdea415 tests: update a test to not point a branch to an unreachable commit
The next patch would otherwise make this test fail because
"transaction 2" tries to point a branch to a commit that's not visible
(because it's created by the concurrent "transaction 1").
2021-10-02 23:08:45 -07:00
Martin von Zweigbergk
76352564ad CommitBuilder: record rewritten commits in MutableRepo
This is part of removing support for evolution (#32). Since
`CommitBuilder` now records rewritten commits in `MutableRepo`, we can
use that recorded information to automatically rebase descendants.
2021-09-29 15:45:38 -07:00
Martin von Zweigbergk
d00b805d97 MutableRepo: add support for recording rewritten and abandoned commits
When we remove support for evolution (#32), we need to still make it
easy for application code to rebase descendants of rewritten and
abandoned commits. The way applications currently do that is by using
e.g.  `CommitBuilder::for_rewrite_from()` followed by
`evolve_orphans()`. This patch puts some bookkeeping in `MutableRepo`
for rewritten and abandoned commits, along with a function for
creating a `DescendantRebaser` based on it. I'll then make
`CommitBuilder` record rewritten commits there.
2021-09-29 15:24:04 -07:00
Martin von Zweigbergk
23c3b503c0 tests: move assert_rebased() function to testutils 2021-09-29 11:41:51 -07:00
Martin von Zweigbergk
ff71af1e11 MutableRepo: accept just CommitId instead of whole Commit where possible 2021-09-29 10:13:32 -07:00
Martin von Zweigbergk
eb00981aca git: also test imported refs and branches after fetch 2021-09-24 22:42:37 -07:00
Waleed Khan
bfb5e55cfd git: properly detect default branch
The default branch relies on checking the value of `HEAD`. The `empty_git_commit` function updates the ref `refs/heads/main`, but since `HEAD` was never updated to point to that ref, the default branch can't be determined. The fix is to explicitly set `HEAD`.

Personally, this test failed reliably for me on macOS. I don't know why this behavior would be non-deterministic on other platforms.
2021-09-22 16:45:04 -07:00
Martin von Zweigbergk
a69096a4d4 git: remove test of default branch because of issue #30 2021-09-22 15:22:53 -07:00
Martin von Zweigbergk
eed715dc51 git: try to fix flaky (?) fetch tests by keeping connection open longer
It seems it wasn't Windows that behaved differently when it comes
getting the remote's default branch; the test failed on Ubuntu
too.

The documentation for `Remote::default_branch()` says that it can be
called even after the connection has been closed, but let's see if
calling it while the connection is open helps anyway. To do that, we
have to replicate what `Remote::fetch()` does.
2021-09-22 11:48:42 -07:00
Martin von Zweigbergk
2086d1a84d git: make fetch-test pass on Windows by expecting no default branch 2021-09-22 10:56:53 -07:00
Martin von Zweigbergk
f56262ce85 git: add test for default branch after fetch
This adds tests I should have added in 48f237e33e.
2021-09-22 10:28:28 -07:00
Martin von Zweigbergk
d4004fcb6f rewrite: teach DescendantRebaser to handle abandoned commits specially
Descendants of abandoned commits should be rebased onto their parents,
or the rewritten parents if they had been rewritten. This patch
teaches `DescendantRebaser` to do that. It updates `jj rebase -r` to
use the functionality. I plan to also use it in `jj abandon`
(naturally, given the name), and for rebasing descendants of deleted
refs imported from `jj git refresh/fetch/push`.
2021-09-19 22:51:12 -07:00
Martin von Zweigbergk
439fe1cfd3 rewrite: don't report skipped commits when rebasing descendants
The fact that `DescendantRebaser` visits some commits that don't need
to be rebased is mostly an implementation detail. I can't think of a
reason that callers would care about these commits.
2021-09-19 22:51:12 -07:00
Martin von Zweigbergk
ae7f00e7b1 cli: rename jj prune to jj abandon
The command's help text says "Abandon a revision", which I think is a
good indication that the command's name should be `abandon`. This
patch renames the command and other user-facing occurrences of the
word. The remaining occurrences should be removed when I remove
support for evolution.
2021-09-19 22:51:12 -07:00
Martin von Zweigbergk
ef4cb663ae cli: move logic for updating branches after rewrite to lib crate
This patch moves the function for updating branches after rewrite from
`commands.rs` into `rewrite.rs`.

It also changes the function to update branches even if they were
conflicted or become conflicted. I think that seems better than
leaving branches on old commits. For example, let's say you have start
with this:

```
C main
|
B origin@main
|
A
```

You now pull from origin, which has updated the main branch from B to
B'. We apply that change to both the remote branch and the local
branch, which results in a conflict in the local branch:

```
C main?
|
B B' main? origin@main
|/
A
```

If you now rewrite C to C', the conflicted main branch will still
point to C, which is just weird. This patch changes that so the
conflicted side of main gets repointed to C'.

I also refactored the code to reuse our existing
`MutableRepo::merge_single_ref()`, which improves the behavior in
several cases, such as the conflict-resolution case in the last test
case.
2021-09-18 10:03:26 -07:00
Martin von Zweigbergk
ca114d6d7e rewrite: add support for rebasing descendants of multiple rewritten commits
I plan to use this for rebasing descendants of rewritten remote
branches (on fetch).
2021-09-15 22:13:40 -07:00
Martin von Zweigbergk
30bcf6508e rewrite: when rebasing forward, also rebase "side branches"
As the updates test case shows, when rebasing forward, we missed
commits that fork off from the section between the source and the
destination.

As part of the fix, I also restructured the code a bit to prepare for
support for rebasing descendants of multiple rewritten commits.
2021-09-15 22:08:32 -07:00
Martin von Zweigbergk
e4bc8f5b4c tests: extract helpers to reduce repetition in test_rewrite 2021-09-15 22:02:58 -07:00
Martin von Zweigbergk
ce5e95fa80 store: rename Store to Backend and StoreWrapper to Store
For what's currently called `Store` in the code, I have been using
"backend" in plain text. That probably means that `Backend` is a good
name for it.
2021-09-12 12:02:10 -07:00
Martin von Zweigbergk
344435e90f git: add support for pushing multiple ref updates at once 2021-09-11 22:54:29 -07:00
Martin von Zweigbergk
11c0130303 index: squash an index segment into its parent more aggressively
Before this change, you could end up with an index segment with 10
commits, then a child segment with 9 commits, then another child with
8 commits, and so on. That's not what I had intended. This changes
makes it so we squash if a segment has more than half as many commits
as its parent instead.
2021-09-11 22:51:13 -07:00
Martin von Zweigbergk
20e9d29c4b CommitBuilder: remove write_to_new_transaction(), which was only used in tests 2021-09-11 10:11:15 -07:00
Martin von Zweigbergk
88fef10eac cleanup: use literal newlines in string literals
I'm about to enable `rustfmt`'s formatting of string literals, and
that makes these string literals with escaped newlines harder to read.
2021-09-02 11:01:02 -07:00
Martin von Zweigbergk
ccdd651953 working_copy: ignore .git directory/file when writing tree to store
Git doesn't want `.git` entries in its trees, so at least when using
the Git backend, we need to ignore such paths. Let's just ignore
`.git` paths regardless of backend to keep it simple.

Closes #24.
2021-09-01 08:40:28 -07:00
Martin von Zweigbergk
f27ca16a16 rewrite: when rebasing descendants, actually rebase them
When I added the function for rebasing descendants, I forgot to call
the existing `rebase()` function and instead simply created a new
commit with the new parents but the old contents.
2021-08-29 09:42:37 -07:00
Martin von Zweigbergk
4e0a89b3dd rewrite: add a function for rebasing descendant commits
This should be useful in lots of places. For example, `jj rebase -r`
currently rebases all descendants, because that's what the auto-evolve
feature does. I think it would be nice to instead copy from
Mercurial's `-s` flag for also rebasing descendants. Then `jj rebase
-r` can be made to pull a commit out of a stack, rebasing descendants
onto the rebased commit's parents. I also intend to use this
functionality for rebasing descendants when remote branches have been
rewritten.
2021-08-28 10:01:00 -07:00
Martin von Zweigbergk
e99e86e826 tests: use CommitGraphBuilder in test_refs.rs
I guess I forgot about the helper when I added these tests recently.
2021-08-18 09:58:44 -07:00
Martin von Zweigbergk
2afed65132 working_copy: move logic for creating commit to caller
The auto-rebasing of descendants doesn't work if you have an open
commit checked out, which means that you may still end up with orphans
in that case (though that's usually a short-lived problem since they
get rebased when you close the commit). I'm also about to make
branches update to successors, but that also doesn't work when the
branch is on a working copy commit that gets rewritten. To fix this
problem, I've decided to let the caller of `WorkingCopy::commit()`
responsible for the transaction.

I expect that some of the code that this change moves from the lib
crate to the cli crate will later move back into the lib crate in some
form.
2021-08-15 18:55:09 -07:00
Martin von Zweigbergk
7deba1172c tests: remove an unnecessary wc.commit() right after wc.check_out() 2021-08-15 18:37:08 -07:00
Martin von Zweigbergk
81ba65e3a5 git: force push when not known to be a fast-forward
With this change, we no longer fail if the user moves a branch
sideways or backwards and then push.

The push should ideally only succeed if the remote branch is where we
thought it was (like `git push --force-with-lease`), but that requires
rust-lang/git2-rs#733 to be fixed first.
2021-08-04 23:28:42 -07:00
Martin von Zweigbergk
8738421990 git: update own branch and tag records based on git refs
Now that we have our own representation of branches and tags, let's
update them when we import git refs. The View object's git refs are
now just a record of what the refs are in the underlying git ref last
time we imported them (we don't -- and won't -- provide a way for the
user to update our record of the git refs). We can therefore do a nice
3-way ref-merge using the `refs` module we added recently. That means
that we'll detect conflicts caused by changes made concurrently in the
underlying git repo and in jj's view.
2021-08-04 11:39:07 -07:00
Martin von Zweigbergk
044f23bc33 view: add support for ref-based branches and tags to model
I've finally decided to copy Git's branching model (issue #21), except
that I'm letting the name identify the branch across
remotes. Actually, now that I think about, that makes them more like
Mercurial's "bookmarks". Each branch will record the commit it points
to locally, as well as the commits it points to on each remote (as far
as the repo knows, of course). Those records are effectively the same
thing as Git's "remote-tracking branches"; the difference is that we
consider them the same branch. Consequently, when you pull a new
branch from a remote, we'll create that branch locally.

For example, if you pull branch "main" from a remote called "origin",
that will result in a local branch called "main", and also a record of
the position on the remote, which we'll show as "main@origin" in the
CLI (not part of this commit). If you then update the branch locally
and also pull a new target for it from "origin", the local "main"
branch will be divergent. I plan to make it so that pushing "main"
will update the remote's "main" iff it was currently at "main@origin"
(i.e. like using Git's `git push --force-with-lease`).

This commit adds a place to store information about branches in the
view model. The existing git_refs field will be used as input for the
branch information. For example, we can use it to tell if
"refs/heads/main" has changed and how it has changed. We will then use
that ref diff to update our own record of the "main" branch. That will
come later. In order to let git_refs take a back seat, I've also added
tags (like Git's lightweight tags) to the model in this commit.

I haven't ruled out *also* having some more persistent type of
branches (like Mercurials branches or topics).
2021-08-04 11:33:57 -07:00
Martin von Zweigbergk
b1e60b37ea view: add tests of merging views
I'm about to add some support for branches and tags (for issue #21)
and it seems that we didn't have explicit testing of merging of
views. There was `test_import_refs_merge()` in `test_git.rs` but
that's specifically for git refs. It seems that it's made obsolete by
the tests added by this commit, so I'm removing it.
2021-08-04 11:33:57 -07:00
Martin von Zweigbergk
9fb3521bf5 view: rename insert_git_ref() to set_git_ref()
I just feel like `set_git_ref()` is a more natural name (I was looking
for it the other day before I realized I had called it
`insert_git_ref()`).
2021-08-04 08:45:37 -07:00
Martin von Zweigbergk
2650681117 tests: randomize commit messages in test_git
I had previously created commit messages based only on the ref name,
which meant that `commit4` and `commit5` ended up being the same
commit. This fixes that problem.
2021-08-01 21:26:26 -07:00
Martin von Zweigbergk
38032b0132 cleanup: commit transactions in tests when it's simpler
There were some tests that discarded a transaction only because it
used to be easier to do that than to commit and reload the repo. We
get the new repo back when we commit the transaction these days, so
now it's often easier to commit the transaction instead.
2021-07-30 17:47:00 -07:00
Martin von Zweigbergk
6b1ccd4512 view: add support for merging git ref targets
When there are two concurrent operations, we would resolve conflicting
updates of git refs quite arbitrarily before this change. This change
introduces a new `refs` module with a function for doing a 3-way merge
of ref targets. For example, if both sides moved a ref forward but by
different amounts, we pick the descendant-most target. If we can't
resolve it, we leave it as a conflict. That's fine to do for git refs
because they can be resolved by simply running `jj git refresh` to
import refs again (the underlying git repo is the source of truth).

As with the previous change, I'm doing this now because mostly because
it is a good stepping stone towards branch support (issue #21). We'll
soon use the same 3-way merging for updating the local branch
definition (once we add that) when a branch changes in the git repo or
on a remote.
2021-07-24 19:01:56 -07:00
Martin von Zweigbergk
0aa738a518 view: add support for conflicting git refs in the model
This adds support for having conflicting git refs in the view, but we
never create conflicts yet. The `git_refs()` revset includes all "add"
sides of any conflicts. Similarly `origin/main` (for example) resolves
to all "adds" if it's conflicted (meaning that `jj co origin/main` and
many other commands will error out if `origin/main` is
conflicted). The `git_refs` template renders the reference for all
"adds" and adds a "?" as suffix for conflicted refs.

The reason I'm adding this now is not because it's high priority on
its own (it's likely extremely uncommon to run two concurrent `jj git
refresh` and *also* update refs in the underlying git repo at the same
time) but because it's a building block for the branch support I've
planned (issue #21).
2021-07-24 19:01:56 -07:00
Martin von Zweigbergk
d6a1f9848a cleanup: add explicit import of assert_matches, as required by new rustc 2021-07-24 10:48:52 -07:00
Martin von Zweigbergk
1a4d9d5644 evolution: don't create merge commits with one parent ancestor of another 2021-07-02 23:49:36 -07:00
Martin von Zweigbergk
4c416dd864 cleanup: let Clippy fix a bunch of warnings 2021-06-14 00:27:31 -07:00
Martin von Zweigbergk
06cd688181 tests: enable concurrent commit tests on Windows
I don't know why these used to fail. Perhaps it was just that the
GitHub's Windows machines were not powerful to run them with 100
threads doing concurrent commits. Maybe they will pass now that we
limit the number of threads to the number of CPUs. This change enables
the tests so we can see what GitHub CI thinks.
2021-06-13 22:02:42 -07:00
Martin von Zweigbergk
408b0dc1d8 tests: enable test of file type transactions on Windows, only skip symlinks
I think all types but symlinks should work on Windows. Let's see if
GitHub CI agrees (I don't have access to a Windows machine).
2021-06-13 21:52:16 -07:00
Martin von Zweigbergk
dd4c47f373 tree: support filtering diff by matcher
This change teaches `Tree::diff()` to filter by a matcher. It only
filters the result so far; it does not restrict the tree walk to what
`Matcher::visit()` says is necessary yet. It also doesn't teach the
CLI to create a matcher and pass it in.
2021-06-09 16:26:58 -07:00
Martin von Zweigbergk
b593e552b8 cleanup: remove some Vec<_> annotations, mostly by using collect_vec() 2021-06-09 14:21:57 -07:00
Martin von Zweigbergk
0ce50e137a store: use RepoPathComponent in Tree 2021-06-05 23:36:38 -07:00
Martin von Zweigbergk
fdeb499836 trees: merge into tree module 2021-06-05 14:20:07 -07:00
Martin von Zweigbergk
f6a9523b75 revsets: resolve symbol as change id if nothing else matches
This patch makes it so we attempt to resolve a symbol as the
non-obsolete commits in a change id if all other resolutions
fail.

This addresses issue #15. I decided to not require any operator for
looking up by change id. I want to make it as easy as possible to use
change ids instead of commit ids to see how well it works to interact
mostly with change ids instead of commit ids (I'll try to test that by
using it myself).
2021-05-31 08:32:10 -07:00
Martin von Zweigbergk
c7f701fddb revsets: make resolve_symbol() return multiple revisions
I'd like to experiment with mostly using change ids instead of commit
ids on the CLI. Then it needs to be easy to refer to the non-obsolete
commits in a change, which means we probably don't want to require any
operators (i.e. a plain change id should resolve to the non-obsolete
commits in the change). This patch prepares for letting a change id
resolve to (possibly) many commits.
2021-05-30 13:39:24 -07:00
Martin von Zweigbergk
e658cc0084 revsets: add a RevsetExpression::evaluate() method for convenience 2021-05-28 09:01:34 -07:00
Martin von Zweigbergk
54f6165ef1 repo_path: replace remaining uses of DirRepoPath by RepoPath 2021-05-19 15:11:04 -07:00
Martin von Zweigbergk
5421251e72 repo_path: change representation of RepoPath to have only a list of components 2021-05-19 15:11:04 -07:00
Martin von Zweigbergk
c66990d3a3 repo_path: rename from() to from_internal_{,dir}_string()
Since `RepoPath` can be either a file or a directory, I made its name
not include `file`.
2021-05-19 15:11:04 -07:00
Martin von Zweigbergk
03ae1b747c repo_path: remove FileRepoPath in favor of just RepoPath
I had initially hoped that the type-safety provided by the separate
`FileRepoPath` and `DirRepoPath` types would help prevent bugs. I'm
not sure if it has prevented any bugs so far. It has turned out that
there are more cases than I had hoped where it's unknown whether a
path is for a directory or a file. One such example is for the path of
a conflict. Since it can be conflict between a directory and a file,
it doesn't make sense to use either. Instead we end up with quite a
bit of conversion between the types. I feel like they are not worth
the extra complexity. This patch therefore starts simplifying it by
replacing uses of `FileRepoPath` by `RepoPath`. `DirRepoPath` is a
little more complicated because its string form ends with a '/'. I'll
address that in separate patches.
2021-05-19 15:11:04 -07:00
Martin von Zweigbergk
1fe8f6ac27 cli: on init, give a proper error message instead crashing when repo exists 2021-05-19 14:53:37 -07:00
Martin von Zweigbergk
525a5116a2 RepoLoader: stop returning Result since the functions cannot currently fail 2021-05-19 14:12:54 -07:00
Martin von Zweigbergk
6809a88d42 cleanup: use ReadonlyRepo returned from Transaction::commit()
I thought I had looked for this case and cleaned up all the places
when I made `Transaction::commit()` return a new `ReadonlyRepo`. I
must have forgotten to do that, because there we tons of places to
clean up left.
2021-05-19 14:04:52 -07:00
Martin von Zweigbergk
ecc2a6b968 cli: avoid using angle brackets in name/email placeholder, to please git
Git doesn't like seeing "<" and ">" in the user's name or email, so
let's switch to parentheses.
2021-05-19 13:02:39 -07:00
Martin von Zweigbergk
b50be04b43 tests: avoid using to_internal_string() to produce FS path 2021-05-16 22:56:18 -07:00
Martin von Zweigbergk
4d51cd96a1 repo: scan for .jj/ directory up the tree
It's kind of silly that I haven't fixed this earlier. I just don't
need it often myself.
2021-05-16 11:06:13 -07:00
Martin von Zweigbergk
d42e6c77b2 project: rename project from Jujube to Jujutsu
"Jujutsu" is probably much more familiar and relatable to most
people. Also, I'm still not sure how "jujube" is supposed to be
pronounced :P
2021-05-15 10:28:40 -07:00
Martin von Zweigbergk
a71c56e5e1 evolution: rewrite orphan resolution as iterator 2021-05-15 09:16:19 -07:00
Martin von Zweigbergk
79b5b8d681 evolution: rewrite divergence resolution as iterator
This commit rewites the divergence-resolution part of `evolve()` as an
iterator (though not implementing the `Iterator` trait). Iterators are
just much easier to work with: they can easily be stopped, and errors
are easy to propagate. This patch therefore lets us propagate errors
from writing to stdout (typically pipe errors).
2021-05-15 09:16:19 -07:00
Martin von Zweigbergk
a028f33e3b working copy: don't remove already-tracked files in ignored directories
The recent optimization to not walk ignored directories did not
account for the case where there already are files in the ignored
directory.
2021-05-15 09:15:45 -07:00
Martin von Zweigbergk
cbc3e915b7 working copy: allow overwriting untracked files
Before this commit, we would crash when checking out a commit that has
a file that's currently ignored in the working copy.
2021-05-15 08:24:56 -07:00
Martin von Zweigbergk
70b99c960e transaction: make commit() return resulting ReadonlyRepo
I've wanted the API to look like this for a while. It seems like a
good API to me. It means that the caller won't have to reload the repo
after committing. The cost seems relatively small. It involves copying
potentially a lot of data in memory (at least the View object), but it
shouldn't involve reading from disk or any other processing. To reduce
the amount of data to copy, it may be worth switching to persistent
data types. I've also wanted to do that for the copying we do when
start a transaction.

I couldn't measure any slowdown caused by this change.
2021-05-08 13:50:59 -07:00
Martin von Zweigbergk
7065cecfdc revsets: add revset yielding merge commits 2021-05-02 14:33:38 -07:00
Martin von Zweigbergk
aef27d5701 revsets: remove transitive edges in graph iterator by default
The git.git repo seems to have lots of merges from far back in the
history into newer history. That results in `jj log -r 'git_refs()'`
being completely useless because of the number of such edges. For
example, v2.31.0 has almost 600 edges going out of it and presumably
merging (forking) back into various different previous versions. Git,
unlike Mercurial, seems to remove an edge from the graph if the edge
can also be reached via a longer path. This commit makes it so we also
do that (i.e. the filtered graph is a transitive reduction of the
graph before filtering).

This slows down `jj log -r ,,v2.0.0 -T ""` by about 2%. That's still
small enough that it doesn't seem worth it to have a separate iterator
for contiguous ranges (which would be an option).
2021-05-01 23:25:33 -07:00
Martin von Zweigbergk
33da97f0bf revsets: add iterator adapter for rendering simplified graph of set
When rendering a non-contiguous subset of the commits, we want to
still show the connections between the commits in the graph, even
though they're not directly connected. This commit introduces an
adaptor for the revset iterators that also yield the edges to show in
such a simplified graph.

This has no measurable impact on `jj log -r ,,v2.0.0` in the git.git
repo.


The output of `jj log -r 'v1.0.0 | v2.0.0'` now looks like this:

```
o   e156455ea491 e156455ea491 gitster@pobox.com 2014-05-28 11:04:19.000 -07:00 refs/tags/v2.0.0
:\  Git 2.0
: ~
o c2f3bf071ee9 c2f3bf071ee9 junkio@cox.net 2005-12-21 00:01:00.000 -08:00 refs/tags/v1.0.0
~ GIT 1.0.0
```

Before this commit, it looked like this:

```
o e156455ea491 e156455ea491 gitster@pobox.com 2014-05-28 11:04:19.000 -07:00 refs/tags/v2.0.0
| Git 2.0
| o   c2f3bf071ee9 c2f3bf071ee9 junkio@cox.net 2005-12-21 00:01:00.000 -08:00 refs/tags/v1.0.0
| |\  GIT 1.0.0
```

The output of `jj log -r 'git_refs()'` in the git.git repo is still
completely useless (it's >350k lines and >500MB of data). I think
that's because we don't filter out edges to ancestors that we have
transitive edges to. Mercurial also doesn't filter out such edges, but
Git (with `--simplify-by-decoration`) seems to filter them out. I'll
change it soon so we filter them out.
2021-05-01 14:56:52 -07:00
Martin von Zweigbergk
df2caab274 tests: add a helper for building commit graphs when only topology is important 2021-04-30 22:46:20 -07:00
Martin von Zweigbergk
419002fab4 tests: use one thread per core in concurrency tests
The tests have been failing in GitHub's CI quite frequently. It's
about time I try to do something about it. Let's see if this helps.
2021-04-29 00:01:04 -07:00
Martin von Zweigbergk
46edbbef09 revsets: add revset function for getting all git refs
This adds a `git_refs()` revset that includes all commits pointed to
by a git ref. It's not very useful yet because the graph log doesn't
use the right type of edges for non-contiguous commits.
2021-04-28 23:34:17 -07:00
Martin von Zweigbergk
13134bd5a4 cleanup: address warnings reported by new clippy version 2021-04-28 09:12:48 -07:00
Martin von Zweigbergk
9dc18524fc revsets: add "ancestor difference" range operator (like git's ..) 2021-04-23 19:10:28 -07:00
Martin von Zweigbergk
49173de423 revsets: add DAG range operator (like hg's infix ::)
This lets you use the same operator as we currently have for ancestors
and descendants (`,,`) to also specify a DAG range. That's what
Mercurial uses the `::` operator for and what Git has `git log
--ancestry-path` for.
2021-04-23 19:10:26 -07:00
Martin von Zweigbergk
d8c209c82a revsets: give parents/children operators higher precedence than range operators 2021-04-23 18:45:42 -07:00
Martin von Zweigbergk
145731ec74 revsets: change operators around a bit to prepare for infix DAG range operator
I really liked the idea of having the operators for parents and
ancestors (etc.) look similar, but that turned out to be problematic
when we want to add an infix operator for a DAG range (hg's `::`
revset operator and git's `--ancestry-path` flag). Let's say we chose
`:*:` as the operator. Part of the problem is how to parse `foo:*:bar`
without eagerly parsing the `foo:`. It would also be nicer to use
exactly the same operator as prefix, postfix, and infix. Since the
"parents" operator can be repeated, we can't have it be just `:` and
the "ancestors" operator be `::`. We could make the "ancestors"
operator be something like `*:*` (or anything symmetric with the `:`
symbol on the inside). However, at that point, the operator is getting
ugly and hard to type. Another option would be to use `:` for
ancestors and `::` for parents, but that is counterintuitive and get
annoying if you want to repeat it. So it seems that the best option is
to simply pick different symbols for parents/children and
ancestors/descendants/range.

This patch changes the ancestors/descendants operators to both be
`,,`. I'm not at all attached to that particular symbol. I suspect
we'll change it later.
2021-04-23 11:11:07 -07:00
Martin von Zweigbergk
d78fd9e979 revsets: add functions and operators for children and descendants
This adds `children(<set>)` and `<set>:` for the children of the given
set, and `descendants(<set>)` and `<set>:*` for the descendants of the
given set. The children and descendants are filtered to be among
ancestors of non-obsolete commits. I haven't added a way of overriding
that yet.
2021-04-21 23:34:20 -07:00
Martin von Zweigbergk
744f209e76 revsets: move parse-tests to to revset module (from separate test module)
The tests don't need any complex set up (no repo necessary), so they
can be in the `revset` module itself. I'm sure we'll need to split up
that module later (at least separate out the parsing), but that's a
separate problem.
2021-04-21 18:53:58 -07:00
Martin von Zweigbergk
64fcf90c68 view: make root commit public 2021-04-18 23:04:15 -07:00
Martin von Zweigbergk
b52cfc156c revsets: add a public_heads() revset function 2021-04-18 22:52:31 -07:00
Martin von Zweigbergk
3a65c1d2ab revsets: add intersection operator 2021-04-18 22:45:12 -07:00
Martin von Zweigbergk
332580918c revsets: add union operator 2021-04-18 22:45:12 -07:00
Martin von Zweigbergk
2ac5d1f912 revsets: allow spaces in most places (but not after prefix operators) 2021-04-18 22:45:12 -07:00
Martin von Zweigbergk
c04f418e67 revsets: add difference operator 2021-04-18 22:45:12 -07:00
Martin von Zweigbergk
d9ae7cdd6d revsets: allow parenthesized expressions
We'll clearly want to allow parenthesized expressions once we have
infix operators (if not before). Let's prepare by allowing parentheses
already now.
2021-04-18 22:45:12 -07:00
Martin von Zweigbergk
62f0778942 revsets: add a description() revset
The revset is currently eagerly evaluated, which is clearly bad. We'll
need to fix that later.
2021-04-18 22:45:12 -07:00
Martin von Zweigbergk
05e9149157 revsets: add a non_obsolete_heads() revset
This change adds a `non_obsolete_heads(<set>)` revset, which walks up
ancestors of the input set until it gets to a non-obsolete and
non-pruned commit. That's what we do by default in `jj log`
(i.e. without `--all`). Now we can make `jj log` use revsets and teach
it a `-r` option!
2021-04-18 22:45:10 -07:00
Martin von Zweigbergk
30aa459d2a revsets: add a all_heads() revset function
This adds a `all_heads()` revset function, which contains all heads in
the view, i.e. including non-public heads and obsolete heads.
2021-04-18 22:31:46 -07:00
Martin von Zweigbergk
88904e2b63 revsets: add support for function syntax
This adds `parents(foo)` and `ancestors(foo)` as alternative ways of
writing `:foo` and `*:foo`. 

I haven't added support for for whitespace yet; the parsing is very
strict. The error messages will also need to be improved later.
2021-04-18 21:25:58 -07:00
Martin von Zweigbergk
2d6325b0f4 revsets: define grammar in pest 2021-04-18 21:25:58 -07:00
Martin von Zweigbergk
0d62a336af revsets: initial support for Mercurial-style revsets
This patch adds initial support for a DSL for specifying revisions
inspired by Mercurial's "revset" language. The initial support
includes prefix operators ":" (parents) and "*:" (ancestors) with
naive parsing of the revsets. Mercurial uses postfix operator "^" for
parent 1 just like Git does. It uses prefix operator "::" for
ancestors and the same operator as postfix operator for descendants. I
did it differently because I like the idea of using the same operator
as prefix/postfix depending on desired direction, so I wanted to apply
that to parents/children as well (and for
predecessors/successors). The "*" in the "*:" operator is copied from
regular expression syntax. Let's see how it works out. This is an
experimental VCS, after all.

I've updated the CLI to use the new revset support.

The implementation feels a little messy, but you have to start
somewhere...
2021-04-18 21:25:51 -07:00
Martin von Zweigbergk
7861968f64 index: make IndexRef::entry_by_id() etc return entry with repo's lifetime
It's useful to be able to know that given a `repo: RepoRef<'a>`, the
the lifetime of `repo.index().entry_by_id()` will also be `'a`.
2021-04-15 07:00:04 -07:00
Martin von Zweigbergk
4c3d73ff3b evolution: walk orphans using index
This actually seems to make it slightly slower, but it fixes an
important bug (we used to evolve only one topological branch per `jj
evolve` call). The slowdown seemed to be on the order of 5% when
evolving 100 commits on git.git's "what's cooking" branch.
2021-04-14 08:25:14 -07:00
Martin von Zweigbergk
783e1f6512 repo: make MutableRepo have an Arc<ReadonlyRepo> instead of a reference
I suspect that at least one reason that I didn't make
`MutableRepo::base_repo` by an `Arc<ReadonlyRepo>` before was that I
thought that that would mean that `start_transaction()` would need be
moved off of `ReadonlyRepo` so it can be given an
`&Arc<ReadonlyRepo>`, which would make it much less convenient to
use. It turns out that a `self` argument can actually be of type
`&Arc<ReadonlyRepo>`.
2021-04-11 13:42:31 -07:00
Martin von Zweigbergk
ce855bccfa repo: make reload() and reload_at() return a new ReadonlyRepo
After this patch `ReadonlyRepo` is even closer to readonly. That makes
it easier to reason about. It will allow some further cleanups too.
2021-04-11 10:39:29 -07:00
Martin von Zweigbergk
e3ca27bf77 revsets: support git refs 2021-04-10 10:10:09 -07:00
Martin von Zweigbergk
40f75ec641 revsets: don't crash if given non-hex symbol 2021-04-10 10:08:47 -07:00
Martin von Zweigbergk
9e8a7e2ba6 revsets: move code for resolving symbol to commit to new module 2021-04-10 09:46:27 -07:00
Martin von Zweigbergk
5aec8b9d77 evolution: use index for filtering out ancestors of candidates in new_parent()
This speeds up `jj evolve` of 100 linear commits of the "what's
cooking" branch in the git.git repo further, from ~700 ms to ~400 ms.
2021-03-16 23:43:44 -07:00
Martin von Zweigbergk
73f20c8696 transaction: delete write_commit() and as_repo_ref() helpers
With this patch, the simple delegating helpers are gone from
`Transaction`.
2021-03-16 22:45:58 -07:00
Martin von Zweigbergk
f9873c49ec transaction: remove add_head(), remove_head(), and set_view() helpers 2021-03-16 22:31:28 -07:00
Martin von Zweigbergk
808d0af66d transaction: remove evolution() and store() helpers 2021-03-16 22:31:24 -07:00
Martin von Zweigbergk
16d97ef8c0 transaction: remove index() and view() helpers 2021-03-16 22:05:51 -07:00
Martin von Zweigbergk
5ed14185a0 git: take a MutableRepo instead of a Transaction 2021-03-16 22:05:51 -07:00
Martin von Zweigbergk
769f88bbae tests: rename test_transaction to test_mut_repo
The test doesn't test any logic in the `Transaction` type itself
anymore.
2021-03-16 22:05:51 -07:00
Martin von Zweigbergk
2c2b5fb3b7 evolution: take a MutableRepo instead of a Transaction 2021-03-16 22:05:51 -07:00
Martin von Zweigbergk
69de4698ac tests: set $HOME in a few tests to avoid depending in developer's ~/.gitignore
I just changed my `~/.gitignore` and some tests started failing
because the working copy respects the user's `~/.gitignore`. We should
probably not depend on `$HOME` in the library crate. For now, this
patch just makes sure we set it to an arbitrary directory in the tests
where it matters.
2021-03-16 22:05:36 -07:00
Martin von Zweigbergk
f0619c07ac MutableEvolution: make MutableRepo responsible for lazy calculation
This patch continues the work from the previous pathc. From this
patch, we no longer calculate the evolution state just because a
transaction starts. We still unnecessarily calculate it when adding a
commit within the transaction, however. I'll fix that next.
2021-03-15 15:03:14 -07:00
Martin von Zweigbergk
43315bc9d2 git: fix bad formatting from commit 1e9d428406 2021-03-14 22:28:12 -07:00
Martin von Zweigbergk
1e9d428406 git: skip tags pointing to GPG keys and similar when importing refs 2021-03-14 20:14:18 -07:00
Jun Wu
d1d502c062 tests: disable tests failing on Windows
This unblocks enabling GitHub CI. I took a quick look at
some failures but the causes do not seem obvious to me.
2021-03-14 15:51:32 -07:00
Jun Wu
4cd29a2130 working_copy: avoid std::os::unix on Windows
std::os::unix::fs::PermissionsExt::mode() does not exist on Windows.
Treat files on Windows as regular files.
2021-03-14 15:49:22 -07:00
Martin von Zweigbergk
a7f4f4cf5b rustfmt: configure to merge imports by module
Perhaps we should even set the config to "Item" to reduce merge conflicts.
2021-03-14 10:53:14 -07:00
Martin von Zweigbergk
4b8484e561 rustfmt: configure to group imports 2021-03-14 10:46:25 -07:00
Martin von Zweigbergk
e9ddfdd8bc Repo: repurpose ReadonlyRepo::loader() to return loader for existing repo
It's sometimes useful to create a `RepoLoader` given an existing
`ReadonlyRepo`. We already do that in `ReadonlyRepo::reload()`. This
patch repurposes `ReadonlyRepo::reload()` for that.
2021-03-14 10:34:18 -07:00
Martin von Zweigbergk
7ea0c6a868 View: move op_id/base_op_id to Repo
This is yet another step towards making the `View` types
simpler. Perhaps we eventually won't need to wrap the types returned
from the `OpStore` at all.
2021-03-14 00:25:02 -08:00
Martin von Zweigbergk
27293829d6 Transaction: allow writing a transaction to the OpStore without publishing it
It can be useful to write an operation to the `OpStore` without also
making it visible when you load the repo. I had planned to add that
functionality at least for hooks, so the hooks can be run commands
with `jj --at-op=<operation>` and decide whether to publish the
operation. However, the immediate goal is to let us rewrite
`op_heads_store::merge_op_heads()` to use the usual `Transaction`
API. That needs to be able to just write the operation without
publishing it, since the publishing step takes a long, which
`op_heads_store::merge_op_heads()` (its caller, actually) has already
taken.
2021-03-14 00:12:57 -08:00
Martin von Zweigbergk
337b15c98d cleanup: replace #[cfg(not(windows))] by $[cfg(unix)]
I didn't realize that the `unix` configuration existed before.
2021-03-12 15:45:55 -08:00
Martin von Zweigbergk
212dd35d01 view: let repo create OpHeadsStore and pass in to view 2021-03-10 23:14:00 -08:00
Martin von Zweigbergk
2955bc4a29 repo: let repo types directly have an OpStore
I'd like to make `ReadonlyView` and `MutableView` focused on just the
state of the view (i.e. the set of heads, git refs, etc.). The
responsibility for managing the `.jj/view/op_heads/` directory should
be moved out of it. This prepares for that.
2021-03-10 20:55:56 -08:00
Martin von Zweigbergk
48d7903925 repo: simplify and clarify name of base_op_head_id() functions 2021-03-10 15:39:15 -08:00
Martin von Zweigbergk
0a4ef1030f repo: add support for loading at given operation without loading head op first
The only way to load the repo at a current operation (as with
`--at-op`) is currently to first load it at the head operation and
then call `reload()` on the repo. This patch makes it so we can load
the repo directly at the requested operation.
2021-03-06 09:52:10 -08:00
Martin von Zweigbergk
031a39ecba cleanup: fix lots of issues found in the lib crate by clippy
I had forgotten to pass `--workspace` to clippy all this time :P
2021-02-26 23:15:43 -08:00
Martin von Zweigbergk
d80903ce48 index: also index predecessors
Evolution needs to have fast access to the predecessors. This change
adds that information to the commit index.

Evolution also needs fast access to the change id and the bit saying
whether a commit is pruned. We'll add those soon.

Some tests changed because they previously added commits with
predecessors that were not indexed, which is no longer allowed from
this change. (We'll probably eventually want to allow that again, so
that the user can prune predecessors they no longer care about from
the repo.)
2021-02-26 10:33:34 -08:00
Martin von Zweigbergk
5aadbcf6fc evolve: pass Transaction to listener functions, so they see the updated state 2021-02-21 22:27:13 -08:00
Martin von Zweigbergk
62ce5782b5 index: when writing incremental index, squash into parent file if smaller
We currently write a new incremental index file every time. That means
that the stack of index files quickly gets deep, which makes it slow
to read the index. This commit makes it so that we squash the new
index segment into its parent if the parent has fewer commits. That
means we'll limit the number of files to O(log n). Writes time will
also be O(log n) on average.
2021-02-16 23:47:43 -08:00
Martin von Zweigbergk
a51543b752 index: make first level in stats be the root index
I've confused myself a few times already thinking that level 0 is the
root, so that's probably more intuitive. It also makes tests simpler
because the initial part of the list is unchanged when a new
transaction commits.
2021-02-16 23:45:54 -08:00
Martin von Zweigbergk
b122f33312 index: don't write empty incremental index file 2021-02-16 23:45:52 -08:00
Martin von Zweigbergk
a7b6bcfd79 transaction: write incremental index on commit
With this change, we start writing the incremental index to disk, so
the next reader won't have to re-read the commits and create the
index.

As of this change, we simply write a new index file for each
transaction. That will clearly mean that the stack of files gets deep
pretty quickly. For now, the user will have to do `jj debug reindex`
when things get slow. I plan to change it so instead of writing an
incremental index file every time, we first check if the new index
file would have at least as many commits as the parent file, and if it
will, we write a combined one instead. That should apply recursively,
so we'd have O(log n) index files.
2021-02-15 11:03:41 -08:00
Martin von Zweigbergk
86915f0a6f index: fix check for adding existing commit to index
The check for adding an existing commit to the index only checked if
the commit was already in the `MutableIndex`, not if it was already in
the parent `ReadonlyIndex`.
2021-02-15 10:28:18 -08:00
Martin von Zweigbergk
0f56e014b7 tests: some fixups to test_transaction as a result of reordering commits 2021-02-15 10:28:07 -08:00
Martin von Zweigbergk
713d32d803 index: keep up to date within transaction
With tons of groundwork done, wee can now finally keep the index up to
date within a transaction! That means that we can start relying on the
index to always be valid, so we can use it e.g. for finding common
ancestors within a transaction. That should help speed up `jj evolve`
immensely on large repos.

We still don't write the updated index to disk when the transaction
closes. That will come later.
2021-02-14 00:58:11 -08:00
Martin von Zweigbergk
e19a65cf14 transaction: make add_head() use incremental update of evolution in common case
`Transaction::add_head()` currently invalidates the whole evolution
state. We've had support for incrementally updating evolution since
4619942a57. We should start taking advantage of that. Let's add a
fast-path in `Transaction::add_head()` for the common case where we
add a single commit on top of an existing head. That cheap an simple
to check for. However, it won't cover the case of adding a child off
of a non-head. It's still a good start.
2021-02-14 00:56:34 -08:00
Martin von Zweigbergk
f05a12d301 index: make CompositeIndex non-public and add new IndexRef enum instead
We're getting close to finally having a `RepoRef::index()` method.
2021-02-13 13:56:26 -08:00
Martin von Zweigbergk
3066381d57 transaction: add accessors for view and evolution directly on transaction 2021-02-13 13:43:48 -08:00
Martin von Zweigbergk
72aebc9da3 view: replace View trait by enum with Readonly and Mutable variants 2021-02-13 08:31:41 -08:00
Martin von Zweigbergk
d1e5f46969 evolution: replace Evolution trait by enum with Readonly and Mutable variants 2021-02-13 08:31:41 -08:00
Martin von Zweigbergk
f1666375bd repo: replace Repo trait by enum with readonly and mutable variants
I want to keep the index updated within the transaction. I tried doing
that by adding a `trait Index`, implemented by `ReadonlyIndex` and
`MutableIndex`. However, `ReadonlyRepo::index` is of type
`Mutex<Option<Arc<IndexFile>>>` (because it is lazily initialized),
and we cannot get a `&dyn Index` that lives long enough to be returned
from a `Repo::index()` from that. It seems the best solution is to
instead create an `Index` enum (instead of a trait), with one readonly
and one mutable variant. This commit starts the migration to that
design by replacing the `Repo` trait by an enum. I never intended for
there there to be more implementations of `Repo` than `ReadonlyRepo`
and `MutableRepo` anyway.
2021-02-13 08:31:23 -08:00
Martin von Zweigbergk
51373b75ff index: use correct per-level file name in stats (previously always top-level) 2021-02-07 23:34:57 -08:00
Martin von Zweigbergk
9ffd35caf8 transaction: when checking out open commit with conflicts, create child commit
I've been confused twice that rebasing an open commit so it results in
conflicts doesn't show the conflicts in the log output. That's because
we create a successor instead if a commit with conflicts is open. I
guess I thought it would be expected that a child commit was not
created. Since it seems surprising in practice, let's change it and
we'll see if the new behavior is more or less surprising.
2021-01-22 11:41:52 -08:00
Martin von Zweigbergk
30939ca686 view: return &HashSet instead of Iterator
We want to be able to be able to do fast `.contains()` checks on the
result, so `Iterator` was a bad type. We probably should hide the
exact type (currently `HashSet` for both readonly and mutable views),
but we can do that later. I actually thought I'd want to use
`.contains()` for indiciting public-phase commits in the log output,
but of course want to also indicate ancestors as public. This still
seem like a step (mostly) in the right direction.
2021-01-16 13:00:05 -08:00
Martin von Zweigbergk
79eecb6119 git: mark imported remote-tracking branches as public 2021-01-16 12:14:42 -08:00
Martin von Zweigbergk
4db3d8d3a6 view: add tracking of "public" heads (copying Mercurial's phase concept)
Mercurial's "phase" concept is important for evolution, and it's also
useful for filtering out uninteresting commits from log
output. Commits are typically marked "public" when they are pushed to
a remote. The CLI prevents public commits from being rewritten. Public
commits cannot be obsolete (even if they have a successor, they won't
be considered obsolete like non-public commits would).

This commits just makes space for tracking the public heads in the
View.
2021-01-16 11:48:35 -08:00
Martin von Zweigbergk
265f90185e tests: simplify transaction tests slightly by using testutils more 2021-01-16 11:31:57 -08:00
Martin von Zweigbergk
f43880381f view: make sure we don't leave a dangling git ref
All commits in the view are supposed to be reachable from its
heads. If a head is removed and there are git refs pointing to
ancestors of it (or to the removed head itself), we should make that
ancestor a head.
2021-01-16 11:05:32 -08:00
Martin von Zweigbergk
1f27a78957 view: make remove_head() not add parents as heads
I think it's better to let the caller decide if the parents should be
added. One use case for removing a head is when fetching from a Git
remote where a branch has been rewritten. In that case, it's probably
the best user experience to remove the old head. With the current
semantics of `View::remove_head()`, we would need to walk up the graph
to find a commit that's an ancestor and for each commit we remove as
head, its parents get temporarily added as heads. It's much easier for
callers that want to add the parents as heads to do that.
2021-01-15 01:08:05 -08:00
Martin von Zweigbergk
315818260f git: slightly simplify a few tests 2021-01-11 00:34:04 -08:00
Martin von Zweigbergk
19b542b318 git: simplify error handling by passing git repo into git module functions 2021-01-11 00:25:39 -08:00
Martin von Zweigbergk
da0bbbe637 view: start tracking git refs
Git refs are important at least for understanding where the remote
branches are. This commit adds support for tracking them in the view
and makes `git::import_refs()` update them.

When merging views (either because of concurrent operations or when
undoing an earlier operation), there can be conflicts between git ref
changes. I ignored that for now and let the later operation win. That
will probably be good enough for a while. It's not hard to detect the
conflicts, but I haven't yet decided how to handle them. I'm leaning
towards representing the conflicting refs in the view just like how we
represent conflicting files in the tree.
2021-01-10 20:13:22 -08:00
Martin von Zweigbergk
7494a03081 repo: return error when attempting to load repo where there is none
This commits makes it so that running commands outside a repo results
in an error message instead of a panic.

We still don't look for a `.jj/` directory in ancestors of the current
directory.
2021-01-04 09:18:09 -08:00
Martin von Zweigbergk
abc9dc1733 cargo: rename crates to names available on crates.io
I'm preparing to publish an early version before someone takes the
name(s) on crates.io. "jj" has been taken by a seemingly useless
project, but "jujube" and "jujube-lib" are still available, so let's
use those.
2021-01-03 10:16:00 -08:00
Martin von Zweigbergk
14fe58e76a git: use thiserror for errors
When you run e.g. `jj st` outside of a repo, it just
crashes. That'll probably give new users a bad impression, so I
was planning to improve error handling a bit. A good place to
start is by fixing the code I recently added (which obviously
should have been using `thiserror` from the beginning). That's
what this commit does.

Also, this is the first commit in this repo created with
Jujube! I've just started dogfooding it myself.
2021-01-02 08:24:27 -08:00
Martin von Zweigbergk
e14db781b0 git: add subcommand for fetching from remote
This adds `jj git fetch` for fetching from a git remote. There remote
has to be added in the underlying git repo if it doesn't already
exist. I think command will still be useful on typical small projects
with just a single remote on GitHub. With this and the `jj git push` I
added recently, I think I have enough for my most of my own
interaction with GitHub.
2021-01-01 11:11:09 -08:00
Martin von Zweigbergk
7e65a3d589 git: restructure test a bit to make the functions more reusable 2020-12-31 23:28:02 -08:00
Martin von Zweigbergk
ff3b20c537 git: import git refs as anonymous heads when creating Git-backed repo
The fact that no commits from the underlying Git repo were imported
when creating a new Jujube repo from it was quite surprising. This
commit finally fixes that.
2020-12-29 23:59:35 -08:00
Martin von Zweigbergk
4235ea975d tests: clarify a test slightly by moving assertion of out helper 2020-12-29 23:37:09 -08:00
Martin von Zweigbergk
8377000fd9 git: add a function for updating heads from git refs
When using Git as a store, new commits created in the underlying Git
repo are only made visible by making changes on top of them (e.g by
checking them out, so a working copy commit is created on top). That's
especially confusing when creating a new repo backed by an existing
Git repo, because the commits from that repo don't show up.

This commit prepares for fixing that by adding a function for updating
heads based on git refs. Since we don't yet track git refs (or
anything similar), the function just makes sure the refs are visible
in the Jujube repo by making them (anonymous) heads.
2020-12-29 23:30:34 -08:00
Martin von Zweigbergk
905a5c97d6 transaction: make sure set of heads has only heads
`Transaction::add_head()` and others would let the caller add
non-heads to the set (i.e. ancestors of others heads) and the the
non-heads were filterd out when the transaction was committed. That's
a little surprising, so let's try to keep the set valid even within a
transaction. That will surely make commands that add many commits
noticeably slower in large repos. Hopefully we can improve that
later.
2020-12-29 20:44:17 -08:00
Martin von Zweigbergk
a8a9f7dedd init: add support for creating new repo backed by bare git repo in .jj/git/
It's annoying to have to have the Git repo and Jujube repo in separate
directories. This commit adds `jj init --git`, which creates a new
Jujube repo with an empty, bare git repo in `.jj/git/`. Hopefully the
`jj git` subcommands will eventually provide enough functionality for
working with the Git repo that the user won't have to use Git commands
directly. If they still do, they can run them from inside `.jj/git/`,
or create a new worktree based on that bare repo.

The implementation is quite straight-forward. One thing to note is
that I made `.jj/store` support relative paths to the Git repo. That's
mostly so the Jujube repo can be moved around freely.
2020-12-28 00:54:03 -08:00
Martin von Zweigbergk
e82197d981 git: extract function for pushing commit to remote branch, and test it 2020-12-28 00:53:41 -08:00
Martin von Zweigbergk
6807407814 evolution: fix it so pruned commits can be divergent
A pruned commit just indicates that its predecessors should be evolved
onto the pruned commit's parent instead of onto the pruned commit
itself. The pruned commit itself can be divergent. For example, if
there are several pruned sucessors of a commit, then it's unclear
where the predecessor's children should be rebased to.
2020-12-23 18:01:01 -08:00
Martin von Zweigbergk
66ba74cf5a evolution: use updated state when resolving descendants of orphans
Before this commit, when the `evolve()` evolved a stack of orphans, it
would use the evolve state from the beginning of the function to
calculate where they should go. That meant that only the bottom-most
orphan(s) would get evolved to their right place. This commit fixes
that by use the Transaction's evolution state.
2020-12-23 17:32:32 -08:00
Martin von Zweigbergk
c41251eaff working_copy: fix test to show that already tracked files are not ignored
The point of having the `modified` and `removed` files in the test was
to show that they don't get untracked, but I forgot to include them in
the `.gitignores`, so there was no reason they would have gotten
untracked anyway.
2020-12-22 10:03:42 -08:00
Martin von Zweigbergk
3b326a942c working_copy: add support for .gitignore files
The project's source of truth is now in Git and I really miss support
for anonymous heads and evolution (compared to when the code was in
Mercurial). I'm therefore more motivated to make the tool useful for
day-to-day work on small repos, so I can use it myself. Until now, I
had been more focused on improving performance when it was used as a
read-only client for medium-to-large repos.

One important feature for my day-to-day work is support for
ignores. This commit adds simple and effective, but somewhat hacky
support for that. libgit2 requires a repo to check if a file should be
ignored (presumably so it can respect `.git/info/excludes`). To work
around that, we create a temporary git repo in `/tmp/` whenever the
working copy is committed. We set that temporary git repo's working
copy to be shared with our own working copy. Due to
https://github.com/libgit2/libgit2sharp/issues/1716 (which seems to
apply to the non-.NET version as well), this workaround unfortunately
leaves a .git file (pointing to the deleted temporary git repo) around
in every Jujube repo. That's always ignored by libgit2, so it's not
much of a problem.
2020-12-20 00:37:43 -08:00
Martin von Zweigbergk
9ad225b3b5 trees: make entries() function be the recursive one, since it's more common 2020-12-20 00:26:06 -08:00
Martin von Zweigbergk
4734eb6493 working_copy: let WorkingCopy and TreeState have the working copy path
I don't know why I didn't do it this way from the beginning.
2020-12-18 23:56:32 -08:00
Martin von Zweigbergk
00fb670c9c index: make Index::load() return Arc<IndexFile> instead of Index
This removes one level of indirection, which is nice because it was
visible to the callers. The `Index` struct is now empty. The next step
is obviously to delete it (and perhaps rename `IndexFile` to `Index`
or `ReadonlyIndex`).
2020-12-18 16:12:45 -08:00
Martin von Zweigbergk
6b1427cb46 import commit 0f15be02bf4012c116636913562691a0aaa7aed2 from my hg repo 2020-12-12 00:23:38 -08:00