266 Commits

Author SHA1 Message Date
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
1f68de64d4 debug: upgrade Drop implementations to non-debug assert!
I think these remaining implementations of `Drop` are for types that
are infrequently dropped (unlike `Transaction`), so it be fine to be
more strict about them.
2021-12-01 10:32:11 -08:00
Martin von Zweigbergk
8cf5dd286a backend: make Vec inside CommitId non-public
The recent e5dd93cbf712, 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
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
e5dd93cbf7 cleanup: make Vec inside CommitId etc. non-public 2021-11-10 10:46:10 -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
856b219943 working_copy: if a file's recorded mtime is equal to the state's mtime, set to 0 early 2021-11-07 15:17:51 -08:00
Martin von Zweigbergk
033bfe7d5b working_copy: fix an incorrect comment about timestamps 2021-11-07 15:17:51 -08:00
Martin von Zweigbergk
9ac643ed1a working_copy: rename confusingly named read_time field 2021-11-07 15:17:51 -08:00
Martin von Zweigbergk
baa403b41e working_copy: clarify code for preserving current file state
On Windows, we preserve the executable bit. I plan to also teach the
working copy to preserve conflict state. This refactoring prepares for
that by simplifying how we preserve parts of the current file state.
2021-11-07 15:17:51 -08:00
Martin von Zweigbergk
7c12014513 working_copy: extract a function for updating the file state and tree if dirty 2021-11-07 15:17:51 -08:00
Martin von Zweigbergk
730c442462 working_copy: move file_state() off of TreeState
The function doesn't use `self`, so let's move it off of
`TreeState`. That way we can call it even while holding a mutable
reference.
2021-11-07 15:17:51 -08:00
Martin von Zweigbergk
f86ffbd47b working_copy: take advantage of DirEntry::path() 2021-11-07 15:17:51 -08:00
Martin von Zweigbergk
5dce6e9884 working_copy: avoid using file_state() for getting mtime of tree_state file
I want to change the signature of `file_state()` and this caller is
different from the others and only needs the mtime.
2021-11-07 15:17:51 -08:00
Martin von Zweigbergk
efe7316354 working_copy: make FileType variants more similar to TreeValue variants
This change doesn't make much difference yet, but I think it will
enable further improvements.
2021-11-07 15:17:51 -08:00
Martin von Zweigbergk
bf61e9cf3e working_copy: don't stat ignored files 2021-11-07 15:17:51 -08: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
49e1462fe5 working_copy: delete two obsolete TODOs about ignores
We have had support for ignores via `.gitignore` files since
3b326a942c91, and we haven't had the problem with the temporary
`.git/` directory created by libgit2 since 88f7f4732bb6.
2021-09-03 23:10:45 -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
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
7360589246 working_copy: consider it an error if temp file cannot be renamed to target
Unlike the other places I fixed in 134940d2bb05, the calls in
`working_copy.rs` should not simply use an existing file if the target
file was open. They should probably try again instead, but I'll leave
that for later.
2021-06-16 10:52:55 -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
134940d2bb windows: don't fail when concurrent threads/processes fail to rename file
On Windows, it seems that you can't rename a file if the target file
is open (Stebalien/tempfile#131). I think that's the reason for our
failing tests on Windows. This patch adds a simple wrapper around
`NamedTempFile::persist()` that returns the existing file instead of
failing, if there is one.
2021-06-14 00:09:22 -07:00
Martin von Zweigbergk
f26c9f01ce working_copy: silence some warnings about unused code on Windows 2021-06-13 22:34:33 -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
fdeb499836 trees: merge into tree module 2021-06-05 14:20:07 -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
69664f57fe working_copy: use RepoPath in write_tree() 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
ef726be78b repo_path: rename to_internal_string() to separate names for dir vs 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
525a5116a2 RepoLoader: stop returning Result since the functions cannot currently fail 2021-05-19 14:12:54 -07:00
Martin von Zweigbergk
1cdac0f902 working copy: use system path separator when creating file system path
Hopefully this fixes the failing Windows CI.
2021-05-15 10:04:09 -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
df175f549f working copy: don't assume that $HOME exists (it doesn't on Windows CI) 2021-05-13 23:02:56 -07:00
Martin von Zweigbergk
c1060610bd working copy: optimize simple case of entire directory being ignored
This makes the workging copy walk skip an entire ignored directory if
there are no negative patterns later in the ignore file. That speeds
up `jj st` in this repo with ~13k files in `target/` from ~100 ms to
~25 ms (6.0dB). This closes issue #8.
2021-05-13 22:28:38 -07:00
Martin von Zweigbergk
88f7f4732b gitignores: add own implementation and stop using libgit2's
This is to address issue #8. I haven't added the optimization to avoid
walking all the files in `target/` yet. Even so, this patch still
speeds up `jj st` in this repo, with ~13k files in `target/`, from
~320 ms to ~100 ms (-5.1dB). The time actually checking if paths match
gitignores seems to go down from 116 ms to 6 ms. I think that's mostly
because libgit2 has to look for `.gitignore` files in every parent
directory every time we ask it about a file, while the rewritten code
looks for a `.gitignore` file only when visiting a new directory.
2021-05-13 22:23:59 -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
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
f4a41f3880 trees: make tree diff return an iterator instead of taking a callback
This is yet another step towards making it easy to propagate
`BrokenPipe` errors. The `jj diff` code (naturally) diffs two trees
and prints the diffs. If the printing fails, we shouldn't just crash
like we do today.

The new code is probably slower since it does more copying (the
callback got references to the `FileRepoPath` and `TreeValue`). I hope
that won't make a noticeable difference. At least `jj diff -r
334afbc76fbd --summary` didn't seem to get measurably slower.
2021-04-07 23:18:00 -07:00
Martin von Zweigbergk
06df609482 transaction: delete check_out() and set_checkout() helpers 2021-03-16 22:31:28 -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
81a0e0bd2a protobuf: upgrade to version 2.22.0
I only noticed that there was a newer version when running `cargo
install --path .`, which resulted in warnings about deprecated
functions. There's no other reason I'm aware of to upgrade now.
2021-03-15 17:09:29 -07:00