Commit graph

86 commits

Author SHA1 Message Date
Matt Stark
3f0a49dafe Ensure you never drop the working commit with --skip-empty
See #2766 for discussions
2024-01-04 13:33:24 +11:00
Matt Stark
a4aed2391f Rewrite instead of abandoning empty commits.
Fixes #2760


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

We were previously marking B as abandoned, despite the comment stating that we were marking it as being succeeded by B2. This resulted in a call to `rewrite(rewrites={}, abandoned={B})` instead of `rewrite(rewrites={B=>B2}, abandoned={})`, which then made the new parent of `C` into `A` instead of `B2`
2024-01-04 13:33:24 +11:00
Ilya Grigoriev
45cd0bf11b test_rewrite.rs: stop using DescendantRebaser when testing EmptyBehavior
This completes the process of removing DescendantRebaser-related APIs from
tests. It requires creating some new test utils and a new
`rebase_descendants_with_option_return_map`.
2024-01-01 18:51:36 -08:00
Ilya Grigoriev
4461d61254 test_rewrite: test branches of descendants of divergent commits
A TODO left over from a previous PR
2024-01-01 18:51:36 -08:00
Ilya Grigoriev
b2abba07e9 tests: (mostly) stop using soon-to-be-private DescendantRebaser-related APIs
This removes uses of `DescendantRebaser::new` or
`MutRepo::create_descendant_rebaser` from most tests. The exceptions  are the
tests having to do with abandoning empty commits on rebase, since adjusting
those is a bit more elaborate (see follow-up commits).
2024-01-01 18:51:36 -08:00
Ilya Grigoriev
1fb9df252b split.rs: stop using DescendantRebaser::new
This requires creating a new public API as a substitute. I took the opportunity
to also add some comments to the
`MutRepo::record_rewritten_commit`/`record_abandoned_commit` functions.

I imade the simplest possible addition to the API; it is not a very elegant
one. Eventually, the entire `record_rewritten_commit` API should probably be
refactored again.

I also added some comments explaining what these functions do.
2023-12-24 19:25:16 -08:00
Martin von Zweigbergk
60fae3114e transaction: take description at end instead of start
It seems better to have the caller pass the transaction description
when we finish the transaction than when we start it. That way we have
all the information we want to include more readily available.
2023-12-13 08:12:49 -08:00
Ilya Grigoriev
316ab8efb8 rewrite.rs: refactor new_parents to depend only on parent_mapping
Previously, the function relied on both the `self.parent_mapping` and
`self.rebased`. If `(A,B)` was in `parent_mapping` and `(B,C)` was in `rebased`,
`new_parents` would map `A` to `C`.

Now, `self.rebased` is ignored by `new_parents`. In the same situation,
DescendantRebaser is changed so that both `(A,B)` and `(B,C)` are in
`parent_mapping` before. `new_parents` now applies `parent_mapping` repeatedly,
and will map `A` to `C` in this situation.

## Cons

- The semantics are changed; `new_parents` now panics if `self.parent_mapping`
  contain cycles. AFAICT, such cycles never happen in `jj` anyway, except for
one test that I had to fix. I think it's a sensible restriction to live with;
if you do want to swap children of two commits, you can call
`rebase_descendants` twice.

## Pros

- I find the new logic much easier to reason about. I plan to extract it into a
function, to be used in refactors for `jj rebase -r` and `jj new --after`. It
will make it much easier to have a correct implementation of `jj rebase -r
--after`, even when rebasing onto a descendant.

- The de-duplication is no longer O(n^2). I tried to keep the common case fast.

## Alternatives

- We could make `jj rebase` and `jj new` use a separate function with the
algorithm shown here, without changing DescendantRebaser. I believe that the new
algorithm makes DescendatRebaser easier to understand, though, and it feels more
elegant to reduce code duplication.

- The de-duplication optimization here is independent of other changes, and
could be used on its own.
2023-12-12 19:35:51 -08:00
Yuya Nishihara
28ab9593c3 repo_path: split RepoPath into owned and borrowed types
This enables cheap str-to-RepoPath cast, which is useful when sorting and
filtering a large Vec<(String, _)> list by using matcher for example. It
will also eliminate temporary allocation by repo_path.parent().
2023-11-28 07:33:28 +09:00
Yuya Nishihara
0a1bc2ba42 repo_path: add stub RepoPathBuf type, update callers
Most RepoPath::from_internal_string() callers will be migrated to the function
that returns &RepoPath, and cloning &RepoPath won't work.
2023-11-28 07:33:28 +09:00
Yuya Nishihara
d322df0c8d matchers: make Files/PrefixMatcher constructors accept slice of borrowed paths
RepoPath will become slice type (like str), and it doesn't make sense to
require &[RepoPathBuf] here.
2023-11-28 07:33:28 +09:00
Yuya Nishihara
b7543f8a08 rewrite: fix check for newly-empty commit in optimized path
'old_base_tree_id == None' means the rebased tree is unchanged, so the commit
shouldn't be considered newly-empty.
2023-11-26 14:42:17 +09:00
Matt Stark
0a95e20ebe lib: Implement skipping of empty commits 2023-11-24 14:48:06 +11:00
Martin von Zweigbergk
3a378dc234 cli: add a function for restoring part of a tree from another tree
We had similar code in two places for restoring paths from one tree to
another. Let's reuse it instead.

I put the new function in the `rewrite` module. I'm not sure if that's
right place. Maybe it belongs in `tree`?
2023-11-02 06:07:45 -07:00
Yuya Nishihara
a697175674 view: add tracking state to RemoteRef
The state field isn't saved yet. git import/export code paths are migrated,
but new tracking state is always calculated based on git.auto-local-branch
setting. So the tracking state is effectively a global flag.

As we don't know whether the existing remote branches have been merged in to
local branches, we assume that remote branches are "tracking" so long as the
local counterparts exist. This means existing locally-deleted branch won't
be pushed without re-tracking it. I think it's rare to leave locally-deleted
branches for long. For "git.auto-local-branch = false" setup, users might have
to untrack branches if they've manually "merged" remote branches and want to
continue that workflow. I considered using git.auto-local-branch setting in the
migration path, but I don't think that would give a better result. The setting
may be toggled after the branches got merged, and I'm planning to change it
default off for better Git interop.

Implementation-wise, the state enum can be a simple bool. It's enum just
because I originally considered to pack "forgotten" concept into it. I have
no idea which will be better for future extension.
2023-10-16 23:21:05 +09:00
Yuya Nishihara
8b46712bcb view: add stub method to set remote branch target and state, migrate callers
Since set_remote_branch_target() is called while merging refs, its tracking
state shouldn't be reinitialized. The other callers are migrated to new setter
to keep the story simple.
2023-10-16 05:12:19 +09:00
Yuya Nishihara
35ea607abd view: make get_remote_branch() return RemoteRef instead of RefTarget
I'm going to add tracking state to RemoteRef, and we should compare both
target and state in the tests.
2023-10-16 05:12:19 +09:00
Martin von Zweigbergk
380e204e73 test: use test backend in most remaining tests too
I don't think the backend should matter for any of these tests, so
let's test with only one, and let's make that the strictest one - the
new test backend.

This reduces the number of tests by 74 (from 974 to 900), but saves no
measurable run time.
2023-09-24 21:24:01 -07:00
Martin von Zweigbergk
0f7054e8c3 tests: wherever we test with only one backend, use the test backend
I don't think there's any reason to use the local backend in tests
instead of using the stricter test backend.

I think we should generally use the test backend in tests and only use
the local backend or git backend when there's a particular reason to
do so (such as in `test_bad_locking` where the on-disk directory
structure matters). But this patch only deals with the simpler cases
where we were only testing with the local backend.
2023-09-19 20:49:41 -07:00
Martin von Zweigbergk
9c30d7500b testutils: delete bool-typed init() in favor of enum-typed version
It makes the call sites clearer if we pass the `TestRepoBackend` enum
instead of the boolean `use_git` value. It's also more extensible (I
plan to add another backend for tests).
2023-09-18 07:15:37 -07:00
Martin von Zweigbergk
145b0b24d8 commit: drop merged_ prefix from tree() and tree_id()
The old `tree()` and `tree_id()` functions are now gone, so we can use
those names for the new functions.
2023-08-29 08:32:04 -07:00
Martin von Zweigbergk
d9ce70c176 tests: make create_tree() return MergedTree
I think most tests want a `MergedTree`, so this makes `create_tree()`
return that. I kept the old function as `create_single_tree()`. That's
now only used in `test_merge_trees` and `test_merged_tree`.

I also consistently imported the functions now, something I've
considered doing for a long time.
2023-08-29 07:01:52 -07:00
Martin von Zweigbergk
6e3590f5cd tests: remove last uses of Commit:tree() and delete it 2023-08-29 07:01:52 -07:00
Martin von Zweigbergk
1674a421ec commit_builder: take MergedTreeId for root id argument 2023-08-28 15:58:34 -07:00
Yuya Nishihara
2bbaa4352a refs: rename RefTarget::is_conflict() to has_conflict()
Copied from MergedTree::has_conflict(). I feel it's slightly better since
RefTarget "is" always a Conflict-based type. It could be inverted to
RefTarget::is_resolved(), but refs are usually resolved, and all callers
have special case for !is_resolved() state.
2023-07-23 22:25:57 +09:00
Yuya Nishihara
4da8483228 refs: reimplement RefTarget as Conflict<Option<CommitId>> wrapper
ContentHash is preserved at this point. I'll update it together with the
serialization format changes.
2023-07-18 18:12:09 +09:00
Yuya Nishihara
0461a8575a refs: add stub constructors for absent RefTarget, replace None with it
Now we're mostly ready to reimplement RefTarget on top of
Conflict<Option<CommitId>>.
2023-07-17 08:24:24 +09:00
Yuya Nishihara
9c69a7cb15 refs: leverage Option<RefTarget> extension methods
is_fast_forward() has any() loop that defaults to true, so comment added.
2023-07-17 08:24:24 +09:00
Yuya Nishihara
4cfe2591b6 refs: turn RefTarget::adds()/removes() into iterator, rename accordingly
Since RefTarget will be reimplemented on top of Conflict<Option<CommitId>>,
we won't be able to simply return a slice of type &[CommitId]. These functions
are also renamed in order to disambiguate from Conflict::adds()/removes().
2023-07-17 08:24:24 +09:00
Yuya Nishihara
a1e92563ae refs: add constructor of Some(RefTarget::Conflict { .. })
It's named after Conflict::from_legacy_form(). If RefTarget is migrated to
new Conflict type, from_legacy_form([], [add]) will create a normal target,
and from_legacy_form([], []) will be equivalent to the current None target.
That's why this function isn't named as RefTarget::conflict().
2023-07-17 01:13:21 +09:00
Yuya Nishihara
e55c533add refs: add constructor of Some(RefTarget::Normal(id))
If RefTarget is migrated to new Conflict type, this function will create
RefTarget(Conflict::resolved(Some(id))).

We still need some .unwrap() to insert Option<RefTarget> into map, but maps
will be changed to store new RefTarget type, and their mutation API will
guarantee that Conflict::resolved(None) is eliminated.
2023-07-17 01:13:21 +09:00
Yuya Nishihara
d80a719042 view: unify set/remove_local_branch() functions to take Option<RefTarget> 2023-07-15 05:57:49 +09:00
Yuya Nishihara
78eea06c36 view: unify set/remove_remote_branch() functions to take Option<RefTarget> 2023-07-15 05:57:49 +09:00
Yuya Nishihara
fc609a6d8d view: unify set/remove_tag() functions to take Option<RefTarget> 2023-07-15 05:57:49 +09:00
Yuya Nishihara
ddaf226108 tests: make RefTarget::Conflict { .. } assertion not rely on id order
Here we don't need to care about the order at all. We have test_refs.rs
to ensure that the order is stable.
2023-07-12 21:29:41 +09:00
Martin von Zweigbergk
aac5b7aa25 cargo: rename crates from jujutsu/jujutsu-lib to jj-cli/jj-lib
Almost everyone calls the project "jj", and there seeems to be
consensus that we should rename the crates. I originally wanted the
crates to be called `jj` and `jj-lib`, but `jj` was already
taken. `jj-cli` is probably at least as good for it anyway.

Once we've published a 0.8.0 under the new names, we'll release 0.7.1
versions under the old names with pointers to the new crates names.
2023-07-09 06:40:43 +02: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
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
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
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
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
Martin von Zweigbergk
6703810c6e backend: remove Commit::is_open field from data model 2022-11-05 06:14:37 -07: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
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