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

553 commits

Author SHA1 Message Date
Martin von Zweigbergk
62f541e8cd tests: check that workspace's repo path match canonicalized source path
Hopefully this will fix the failing test on Windows.
2022-02-02 22:22:52 -08:00
Martin von Zweigbergk
c09a4e15c5 workspace: add a function for initializing additional workspace (#13) 2022-02-02 17:00:03 -08:00
Martin von Zweigbergk
5fd060ca18 workspace: load repo from another workspace if .jj/repo is a file (#13)
In workspaces added after the initial one, the idea is to have
`.jj/repo` be a file whose contents is a path to the location of the
repo directory in some other workspace.
2022-02-02 13:47:07 -08:00
Martin von Zweigbergk
a6ef792ba6 repo: initialize without checkouts, let Workspace add it (#13)
As part of creating a new repository, we create an open commit on top
of the root and set that as the current checkout. Now that we have
support for multiple checkouts in the model, we also have support for
zero checkouts, which means we don't need to create that commit on top
of the root when creating the repo. We can therefore move out of
`ReadonlyRepo`'s initialization code and let `Workspace` instead take
care of it. A user-visible effect of this change is that we now create
one operation for initilizing the repo and another one for checking
out the root commit. That seems fine, and will be consistent with the
additional operation we will create when adding further workspaces.
2022-02-02 11:09:12 -08:00
Martin von Zweigbergk
012b4c4d8e revsets: add syntax for a particular workspace's checkout (#13)
Because we record each workspace's checkout in the repo view, we can
-- unlike other VCSs -- let the user refer to any workspace's checkout
in revsets. This patch adds syntax for that, so you can show the
contents of the checkout in workspace "foo" with `jj show foo@`. That
won't automatically commit that workspace's working copy, however.
2022-02-02 10:05:31 -08:00
Martin von Zweigbergk
a41fcb39eb repo: respect workspace ID for old checkout (#13)
When checking out a new commit, we look at the old checkout to see if
it's empty so we should abandon it. We current use the default
workspace's checkout. We need to respect the workspace ID we're given
in `MutableRepo::check_out()`, and we need to be able to deal with
that workspace not existing yet (i.e. this being the first checkout in
that workspace).
2022-02-02 08:15:22 -08:00
Martin von Zweigbergk
ac0d040bb5 rewrite: update all checkouts, not just the default workspace's (#13) 2022-02-02 08:15:22 -08:00
Martin von Zweigbergk
6d3e2017f8 view: merge checkouts for all workspaces, not just the default one (#13) 2022-02-02 08:15:22 -08:00
Martin von Zweigbergk
766c01a6d9 view: add workspace_id argument to set_checkout() (#13) 2022-02-02 08:15:22 -08:00
Martin von Zweigbergk
fb8fbdc4b3 working_copy: keep track of workspace ID (#13)
This patch makes it so the workspace ID can be stored in
`.jj/working_copy/checkout`. The workspace ID is still always
"default".
2022-02-02 08:15:22 -08:00
Martin von Zweigbergk
0098edd3d2 op_store: add support for tracking multiple workspaces (#13)
This patch teaches the `View` object to keep track of the checkout in
each workspace. It serializes that information into the `OpStore`. For
compatibility with existing repos, the existing field for a single
workspace's checkout is interpreted as being for the workspace called
"default".

This is just an early step towards support for multiple
workspaces. Remaining things to do:

 * Record the workspace ID somewhere in `.jj/` (maybe in
   `.jj/working_copy/`)

 * Update existing code to use the workspace ID instead of assuming
   it's always "default" as we do after this patch

 * Add a way of indicating in `.jj/` that the repo lives elsewhere and
   make it possible to load a repo from such workspaces

 * Add a command for creating additional workspaces

 * Show each workspace's checkout in log output
2022-02-02 08:15:22 -08:00
Martin von Zweigbergk
ca055d91d9 workspace: store repo in .jj/repo/ (#13)
The `.jj/` directory contains information about two distinct parts:
the repo and the working copy. Most subdirectories are related to the
repo; only `.jj/working_copy/` is about the working copy. Let's move
the repo-related bits into a new `.jj/repo/` subdirectory. That makes
it clearer that they're related to the repo. It will probably also be
easier to manage when we have support for multiple workspaces backed
by a single repo.
2022-02-02 08:15:22 -08:00
Martin von Zweigbergk
35e0b855a9 tests: avoid depending on .jj/ structure in test_bad_locking (#13) 2022-01-28 22:28:32 -08:00
Martin von Zweigbergk
35f0c17380 workspace: rename some symbols related to .jj/ to jj_dir (#13) 2022-01-28 21:31:51 -08:00
Martin von Zweigbergk
0725d4326d repo: don't create unused .jj/view/ directory 2022-01-28 21:27:13 -08:00
Martin von Zweigbergk
81edd92523 workspace: take over creation of .jj/working_copy/ from repo.rs (#13)
It's clearly `Workspace`'s job to create `.jj/working_copy/`, I must
have just forgotten to move it there.
2022-01-28 20:35:13 -08:00
Martin von Zweigbergk
0c8a116771 rewrite: fix auto-rebasing after "branchy" rewrites
The `DescendantRebaser` was designed to help with rebasing in two
different use cases: 1) after regular rewriting of commits where the
change ID is preserved, and 2) after importing moved branches from
other repo (e.g. backing Git repo or remote). Many of the tests are
for the second use case, such as where a branch was moved
forward. However, I just noticed that there's a pretty common scenario
from the first use case that is not supported.

Let's say you have this history:

```
D
|
C C'
|/
B B'
|/
A
```

Here we want C' to be rebased onto B' and then D to be rebased onto
C''. However, because of the support for moving branches forward, we
would not rebase commits that were already rewritten, such as C' here
(see affected tests for details), which resulted in D getting rebased
onto C', and both B and B' remaining visible.

I think I was thinking when I designed it that it would be nice if you
could just tell `DescendantRebaser` that any descendants of a commit
should be moved forward. That may be useful, but I don't think we'll
want that for the general case of a branch moving forward. Perhaps
we'll want to make it configurable which branches it should happen
for. Either way, the way it was coded by not rebasing already
rewritten commits did not work for the case above. We may be able to
handle both cases better by considering each rewrite separately
instead of all destinations at once. For now, however, I've decided to
keep it simple, so I'm fixing the case above by sacrificing some of
the potentially useful functionality for moving branches forward.

Another fix necessary for the scenario shown above was to make sure we
always rebase C' before D. Before this patch, that depended on the
order in the index. This patch fixes that by modifying the topological
order to take rewrites into account, making D depend not only on C but
also on C'. (I suppose you could instead say that C depends on both B
and C'; I don't know if that'd make a difference.)
2022-01-27 22:20:14 -08:00
Martin von Zweigbergk
5b93ae6d4b rewrite: make it possible to rebase descendants multiple times
Despite what the documentation said, we don't clear the record of
rewritten and abandoned commits at the end. This change fixes that,
and adds a test showing that it's possible to call
`MutableRepo::rebase_descendants()` multiple times.
2022-01-27 22:11:07 -08:00
Martin von Zweigbergk
10ebf35c27 repo: add a convenience function for rebasing all descendants
All non-test users of `create_descendant_rebaser()` just want to
rebase all commits, so let's make that easy.
2022-01-27 08:28:44 -08:00
Martin von Zweigbergk
9f8c6fe07d clippy: return_self_not_must_use is now disabled (pedantic) by default 2022-01-26 22:13:09 -08:00
Martin von Zweigbergk
38180555de working_copy: keep track of operation ID (#13)
When there are concurrent operations that want to update the working
copy, it's useful to know which operation was the last to successfully
update the working copy. That can help use decide how to resolve a
mismatch between the repo view's record and the working copy's
record. If we detect such a difference, we can look at the working
copy's operation ID to see if it was updated by an operation before or
after we loaded the repo.

If the working copy's record says that it was updated at operation A
and we have loaded the repo at operation B (after A), we know that the
working copy is stale, so we can automatically update it (or tell the
user to run some command to update it if we think that's more
user-friendly).

Conversely, if we have loaded the repo at operation A and the working
copy's record says that it was updated at operation B, we know that
there was some concurrent operation that updated it. We can then
decide to print a warning telling the user that we skipped updating
because of the conflict. We already have logic for not updating the
working copy if the repo is loaded at an earlier operation, but maybe
we can drop that if we record the operation in the working copy (as
this patch does).
2022-01-19 19:15:29 -08:00
Martin von Zweigbergk
419efb88f9 working_copy: update stale comment on LockedWorkingCopy
The recent refactoring introducing `WorkgingCopy::start_mutation()`
(25d19e8a65) made this comment incorrect.
2022-01-19 15:12:45 -08:00
Martin von Zweigbergk
45a00e819d working_copy: pass only a TreeId to LockedWorkingCopy::check_out()
It only needs a `TreeId`.
2022-01-19 09:04:01 -08:00
Martin von Zweigbergk
fabaf8b608 working_copy: move logic of check_out() onto LockedWorkingCopy
Having the checkout functionality in `LockedWorkingCopy` makes it a
little more flexible (one could imagine using it for udating working
copy files and then discarding the state changes, for example). It
also lets us reuse a few lines of code for locking. I left
`WorkingCopy::check_out()` for convenience because that's what all
current users want.
2022-01-19 09:04:01 -08:00
Martin von Zweigbergk
9e1869dcef working_copy: pass in old commit ID to check_out()
`WorkingCopy::check_out()` currently fails if the commit recorded on
disk has changed since it was last read. It fails with a "concurrent
checkout" error. That usually works well in practice, but one can
imagine cases where it's not correct. For an example where the current
behavior is wrong, consider this sequence of events:

 1. Process A loads the repo and working copy.

 2. Process B loads the repo at operation A. It has not loaded the
    working copy yet.

 3. Process A writes an operation and updates the working copy.

 4. Process B loads the working copy and sees that it is checked out
    to the commit process B set it to. We don't currently have any
    checks that the working copy commit matches the view's checkout
    (though I plan to add that).

 5. Process B finishes its operation (which is now divergent with the
    operation written by process A). It updates the working copy to
    the checkout set in the repo view by process B. There's no data
    loss here, but the behavior is surprising because we would usually
    tell the user that we detected a concurrent update to the working
    copy.

We should instead check that the working copy's commit on disk matches
what the previous repo view said, i.e. the view at the start of the
operation we just committed. This patch does that by having the caller
pass in the expected old commit ID.
2022-01-19 09:04:01 -08:00
Martin von Zweigbergk
8c97fdf5d6 working_copy: remove untrack() now that we have more flexible reset() 2022-01-19 09:04:01 -08:00
Martin von Zweigbergk
cd4fbd3565 working_copy: add a reset() function for Git-like reset
We already have two usecases that can be modeled as updating the
`TreeState` without touching the working copy:

 1. `jj untrack` can be implemented as removing paths from the tree
    object and then doing a reset of the working copy state.

 2. Importing Git HEAD when sharing the working copy with a Git repo.

This patch adds that functionality to `TreeState`.
2022-01-19 08:32:59 -08:00
Martin von Zweigbergk
9a640bfe13 working_copy: save TreeState later, just before releasing lock
I was surprised that we save the `TreeState` before
`LockedWorkingCopy::finish()`. That means that even if the caller
instead decides to discard the changes, some changes will already have
been written.
2022-01-19 08:32:59 -08:00
Martin von Zweigbergk
25d19e8a65 working_copy: start improving interface for mutations
This patch changes the interface for making changes to the working
copy by replacing `write_tree()` and `untrack()` by a single
`start_mutation()` method. The two functions now live on the returned
`LockedWorkingCopy` object instead. That is more flexible because the
caller can make multiple changes while the working copy is locked. It
also helps us reduce the risk of buggy callers that read the commit ID
before taking the lock, because we can now make it accessible only on
`LockedWorkingCopy`.
2022-01-19 08:32:59 -08:00
Martin von Zweigbergk
2916dc3423 working_copy: make a &mut self argument not mutable 2022-01-19 08:32:51 -08:00
Martin von Zweigbergk
1fc19dbbaf working_copy: take initial commit in init() function
The working copy object knows the currently checked out commit ID. It
is set to `None` when the object is initialized. It is also set to
`None` when an existing working copy is loaded. In that case, it's
used only to facilitate lazy loading. However, that means that
`WorkingCopy::current_commit_id()` fails if the working copy has been
initalized but no checkout has been specified. I've never run into
that case, but it's ugly that it can happen. This patch fixes it by
having `WorkingCopy::init()` take a `CommitId`.
2022-01-17 14:12:55 -08:00
Martin von Zweigbergk
0fadac38d6 working_copy: remove current_commit() (leaving current_commit_id()
`WorkingCopy::current_commit()` has been there from the beginning. It
has made less sense since we made the repo view keep track of the
current checkout. Let's remove it.
2022-01-15 17:11:56 -08:00
Martin von Zweigbergk
8a0afc3016 gitignore: don't apply patterns to parent directories
If you create a `dir/.gitignore` file with pattern "dir" in it, it'll
currently match the parent directory, making e.g. the `dir/.gitignore`
file itself ignored. That was quite confusing, and it doesn't match
how Git behaves. This patch fixes the bug.
2022-01-12 11:27:49 -08:00
Martin von Zweigbergk
5b84e192fc gitignore: ignore a single CR at EOL
I ran into a tool that produced a `.gitignore` file with CRLF line
endings. I had not considered that case when implementing support for
`.gitignore`, so we interpreted the CR as part of the string, which of
course made the files not match.

This patch fixes the bug by ignoring a single CR at EOL. That seems to
be what Git does (I didn't see any information about it in the
documentation).
2022-01-12 10:58:09 -08:00
Martin von Zweigbergk
1e07b95e7b gitignore: derive Debug on structs 2022-01-12 09:37:36 -08:00
Martin von Zweigbergk
2d6b66a274 stacked_table: rename start_modification() to start_mutation()
`start_mutation()` better matches the return type's name.
2022-01-05 15:17:24 -08:00
Martin von Zweigbergk
69ff505338 view: replace start_modification() by Clone impl
I'm pretty sure the `start_modification()` function is a leftover from
when there was `ReadonlyView` and `MutableView`.
2022-01-05 15:11:07 -08:00
Martin von Zweigbergk
91e471cb73 clippy: disable return_self_not_must_use
A new Clippy version added a new warning when a function that returns
`Self` doesn't have `#[must_use]`. I feel like all the cases reported
by it were false positives. Most were functions on `CommitBuilder`,
where we take `mut self` and return `Self`. I don't think I've ever
forgotten to use the result of those.
2022-01-03 21:34:39 -08:00
Martin von Zweigbergk
277f42d98a revsets: add author() and committer() functions (#46)
Filtering by the author or committer is quite common.
2021-12-15 22:50:29 -08:00
Martin von Zweigbergk
7d3d0fe83c revsets: allow the .. operator to be used as prefix or suffix (#46)
It makes sense to omit either of the arguments of the `..` operator,
even though `..x` is equivalent to `:x`. `x..`, with a implied right
argument of `heads()` is more useful.
2021-12-15 22:16:22 -08:00
Martin von Zweigbergk
bc92b82ed4 revsets: use a single grammar rule for the : operator (#46) 2021-12-15 21:57:55 -08:00
Martin von Zweigbergk
60c43cfc0d cargo: upgrade to Rust 2021 (just to stay up to date) 2021-12-13 21:47:00 -08:00
Martin von Zweigbergk
c185b395f6 revsets: swap meaning of operators ~ and - (#46)
As suggested by @arxanas, this makes `-` symmetric with `+` and `-` is
easier to type than `~`.
2021-12-12 23:02:29 -08:00
Martin von Zweigbergk
35a712cc48 revsets: change Git-like range operator ,,, operator to .. (#46) 2021-12-12 00:20:00 -08:00
Martin von Zweigbergk
98659a16e1 revsets: change DAG range operator ,, operator to : (#46) 2021-12-12 00:20:00 -08:00
Martin von Zweigbergk
63c90c04c8 revsets: change parent/children operators to foo~/foo+ (#46) 2021-12-11 23:47:34 -08:00
Martin von Zweigbergk
ccfaf0f601 git: on import, only add ref target as head if target changed (#44)
If you import Git refs, then rebase a commit pointed to by some Git
ref, and then re-import Git refs, you don't want the old commit to be
made a visible head again. That's particularly annoying when Git refs
are automatically updated by every command.
2021-12-11 11:03:40 -08:00
Martin von Zweigbergk
63d1a87ef3 cli: automatically update Git refs and HEAD after command if collocated (#44) 2021-12-11 11:03:40 -08:00
Martin von Zweigbergk
cd0192e1b3 cli: extract a function for importing Git refs and HEAD (#44)
`WorkspaceCommandHelper::for_loaded_repo()` was getting a bit long.
2021-12-11 10:20:30 -08:00
Martin von Zweigbergk
47b3abd0f7 git: add function for exporting to underlying Git repo (#44) 2021-12-11 09:30:12 -08:00