-
Notifications
You must be signed in to change notification settings - Fork 343
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Colocated workspaces using git worktrees #4588
Conversation
aaebbbb
to
44d144f
Compare
44d144f
to
4919138
Compare
963b134
to
72283b8
Compare
@@ -1630,6 +1657,7 @@ impl<'a> DefaultSymbolResolver<'a> { | |||
.iter() | |||
.flat_map(|ext| ext.as_ref().new_resolvers(repo)) | |||
.collect(), | |||
workspace_ctx, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
HEAD@git
would have to be translated to CommitRef::GitHead(WorkspaceId)
or something at lower_expression()
(where we know the current workspace.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
BTW, it might be okay to deprecate HEAD@git
symbol since it can no longer be abstracted as a remote ref of the local @git
remote. It serves as an indicator of colocated repo, but I've never used the HEAD@git
symbol, which should usually point to @-
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had to add the workspace id to the resolver anyway, because the resolver needs to be able to generate HEAD@git as a did-you-mean suggestion, and must do that only when the current workspace is colocated. Since it had to be added to the resolver anyway, it was simple to resolve GitHead
without changing CommitRef.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, good point. I lean towards deprecating HEAD@git
then.
As I said, it's no longer a valid abstraction, and the HEAD revision can be queried by git_head()
. IIRC, HEAD@git
resolution was added just because git_head
template is rendered as such, not because we have a real use case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should be able to undo that operation. Maybe it's enough that we print a hint about that? Or was there some other consequence I'm missing? |
0a149ed
to
cd66e02
Compare
…rktrees This also tests that new workspaces area colocated if the repo is. Creating the worktree will not be enough to satisfy this test -- we need JJ to advance commits and use the worktrees.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here's another batch of mostly minor nits.
cli/src/commands/workspace/add.rs
Outdated
/// This flag works even if a repository was not | ||
/// originally initialised with `--colocate`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: Remove this note and write it positively in the second paragraph.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated, following a bit of the wording from jj git init --help
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As a TODO until the PR is ready but this should have a good motivation for the change. See https://github.com/martinvonz/jj/blob/main/docs/contributing.md#code-reviews particularly this section
We are not particularly strict about the style, but please do explain the reason for the change unless it's obvious.
43ef037
to
a2ca03c
Compare
The main substantive question I have left is, when we import and export from git, should this always do it for every single worktree? Or just the current one? The approach I have taken so far is to do it for the current one. But I think this is spreading out the import over too many operations when the worktrees are, in fact, all right there, readable, and iterable. |
And workspaces might not always be accessible. They might be on USB stick or some network drive. So no, not all worktrees, but just the current one. |
Previously, only the default workspace could be colocated. This adds logic to the colocation-detection code to support finding a worktree as well as a full-on .git directory. Secondly, in a couple of places, this discovered worktree is opened instead of always opening the backing repo. This is so that when you import HEAD, you import it from the current worktree. This work can't be finished until we can store multiple git HEADs in the view, but is continued in the following few diffs.
…t worktree Now that workspaces exist, it is necessary to distinguish the two kinds of git repository `jj` might open. There's the git backend (which is either a bare repository or a colocated one) and the worktrees for all the colocated workspaces. Both of these are a `gix/git2::Repository`, the difference is just which path you opened. So you have to distinguish them with names. The worktree git repo is now mostly used instead of always opening the backend repo. This is so that when you import HEAD, you import it from the current worktree.
a2ca03c
to
19d7bdf
Compare
This forms the basis of `jj workspace add --colocate`. The libraries don't quite have the functionality we need - gix doesn't do it at all - git2 does (Repository::worktree(name, opts)), but it always has to check out a commit. This implementation - can create in an already-existing directory; - writes a dummy HEAD and index; and - does not check out any files. JJ handles the rest.
E.g. you create a workspace, but there is already a git worktree of the same name. JJ should give you a hint as to what to do.
64c334e
to
c6ad91e
Compare
New flag: jj workspace add --colocate. We simply add a worktree.
Previously, JJ's view of the git head (HEAD@git) could only track one HEAD, for only one workspace, specifically the one colocated with the main .jj/repo. Since we now allow workspaces to be colocated, we need to track a separate git HEAD per workspace. This allows us to import HEAD for only the current workspace, and export HEAD to the current workspace when @- moves. Thereby allowing git tools to behave correctly in those workspaces. This affects a lot of stuff. And a lot of tests. A lot more things need to know the current workspace ID, including e.g. the revset resolvers, and the commit templater.
This comes with a couple of tweaks to make `cargo insta review`-ing rehashes easier in future.
…spaces Pretty straightforward. Previously there was only `git_head()`, which a previous diff updated to use the HEAD for the current workspace.
Fails on the second snapshot assertion. The problem with not removing HEADs is that they'll just hang around forever if you don't cull them.
This fixes the test in the previous diff. But we do not remove when merging views, yet. I have another series of patches to do what the TODO describes, but it fails too many tests in pretty perplexing ways, so that's not in this PR.
We need this for when we forget colocated workspaces, so that users do not have to `git worktree remove` manually. The validation / removal separation is so we can two-phase-commit the removals during a multi-workspace forget operation, checking they're all valid and able to be removed during the transaction and removing the worktrees afterwards. Missing worktrees (like when the user has ALREADY run `git worktree remove`) are ignored.
The CLI analogue of the previous diff. We need this for when we forget colocated workspaces, so that users do not have to `git worktree remove` manually.
`jj workspace rename` exists now. This means that people currently using JJ with colocated repos and renaming their default workspace may lose their git HEAD briefly when they next upgrade. This guesswork limits that to cases where they both: - rename their default workspace - AND create a second workspace (which cannot be --colocate as that is being added in the same PR as View.git_heads) But it's not a huge deal -- JJ will re-add the git HEAD when it next does almost anything.
It's long-winded, but at least now we can test deprecated fields in the View end to end.
Is there anyone who can test on windows? I don't have a machine handy. Edit: never mind, I made a failing test and got the CI to tell me how git does it. Details
That path, de-backslashed, is
which is a Verbatim path prefix. I suspect Git likes its paths in the gitfile ( ; git init repo
; cd repo
; touch file.txt && git add file.txt && git commit -m 'initial commit'
; git workspace add ../abc
; cat ../abc/.git
; cat .git/worktrees/abc/commondir
; cat .git/worktrees/abc/gitdir |
aadc9e1
to
3db4851
Compare
We're getting paths like this, I think. gitdir: \\?\C:\Users\runneradmin\AppData\Local\Temp\jj-test-fy26a2\second But I don't know what git does, and I don't have access to a windows machine. Adding this so the CI windows build can tell us what's wrong.
Before gitdir: \\?\C:\Users\runneradmin\AppData\Local\Temp\jj-test-fy26a2\second After gitdir: C:/Users/runneradmin/AppData/Local/Temp/jj-test-fy26a2/second And same for the other worktree bits and pieces. We also change the way the tests run git commands, because of yet another error to do with Git being unable to handle verbatim paths: command=`"git" "worktree" "add" "\\\\?\\C:\\Users\\runneradmin\\AppData\\Local\\Temp\\jj-test-ti0MHE\\second"` code=128 stdout="" stderr=``` Preparing worktree (new branch \'second\') fatal: could not create leading directories of \'//?/C:/Users/runneradmin/AppData/Local/Temp/jj-test-ti0MHE/second/.git\': Invalid argument
3db4851
to
6047297
Compare
Could you somehow split this PR into two or three units? This looks too big to run multiple review rounds, and GitHub UI doesn't support per-patch acceptance. One idea (not sure if this is the easiest/simplest option):
|
Closing to split in half, next is #4644 |
Fixes #4436
Checklist
If applicable:
CHANGELOG.md