Is your feature request related to a problem? Please describe.
After a user has turned an existing Git repository into a co-located Jujutsu+Git one, they may choose not to continue using Jujutsu in this repository and want to remove it again. There isn't currently a jj subcommand to do this, so they have to do it manually (see below for what that involves).
Describe the solution you'd like
A jj subcommand to "undo" jj git init, which would remove any trace of Jujutsu from the Git repo.
Name proposals: jj git deinit1, jj git uninit2, jj git remove, jj git wipe, jj git uninstall, jj git remove-jj-repo3, ... or something else.
Safety: It's obviously very important that this command wouldn't just drop data which the user has forgotten exists only in the form of jj commits. So it should check if all the jj refs are "empty" (in the general sense) and otherwise fail with an error. This should be possible to override with a flag like --force or --yes-i-mean-it3.
Describe alternatives you've considered
- Alternative 1: The user has to perform the removal manually and the steps to do so are just documented somewhere in the Jujutsu docs.
- The steps are:
- Remove the
.jjfolder. - Remove the
refs/jj/keep/<hash>refs. - Remove "residue in the home folder for the repo config".
- Remove the
- Drawbacks:
- 🔴 It's cumbersome for the user.
- 🔴 If the user isn't yet convinced by Jujutsu, they'll make a mental note of it as "that tool that filled my Git repo with junk and then made me remove it manually".
- 🔴 It's either a simple one-liner, which then lacks the safety features suggested above, or quite an involved script which wastes page real estate sitting in the documentation.
- The steps are:
- Alternative 2: Jujutsu is improved such that nobody ever wants to remove it.
- Drawbacks:
- 🔴 People might have their own personal reasons for choosing not to go forward with Jujutsu in a given repo, which can't be anticipated in practice and might not even be possible to solve all at once (e.g. differing tastes).
- 🔴 Even assuming that the only reason people remove Jujutsu is because it doesn't support a Git feature/extension their repo relies on (e.g. LFS or submodules), it will probably take much longer to implement all these features than the proposed removal command. In the meantime, users are left annoyed by the experience.
- 🔴 Sometimes, the reason is a 3rd party tool that only works properly with a plain-Git workflow. Jujutsu can't do anything about that.
- Drawbacks:
Additional context
This FR originally came out of this GitHub Discussions thread:
Footnotes
Activity
11Having though about it again, jj-remove-repo (EDIT: Sorry, I meant remove-jj-repo) might be better after all, because when a repo was created as a Jujutsu+Git repo from the very start (i.e. jj git init in an empty directory, not an existing Git repo), one would expect uninit to "undo" initialization of both the Jujutsu and the Git repo, neither of which were there prior to init. jj-remove-reporemove-jj-repo would be less misleading here.
And in general, it might be better to name commands so that they describe "what this actually does" (like jj-remove-reporemove-jj-repo), instead of claiming that it's the inverse of some other command (like uninit), because the latter could become inaccurate or confusing if more ways are introduced to get into the state that the command tries to get us out of.
Having though about it again,
jj-remove-repomight be better after all, because when a repo was created as a Jujutsu+Git repo from the very start (i.e.jj git initin an empty directory, not an existing Git repo), one would expectuninitto "undo" initialization of both the Jujutsu and the Git repo, neither of which were there prior toinit.jj-remove-repowould be less misleading here.
I think there is still potential for confusion here. If someone has a colocated repo (.jj/ and .git/ folders are siblings), then "remove repo" might make them think it will remove the entire repo folder, including the Git repo. I assume the intention is actually "remove the Jujutsu repo but leave the Git repo". So to me, "un-initialize" seems appropriate, since it is the inverse of the "initialize the Jujutsu repo" operation, regardless of how it was put there in the first place. It is also entirely valid to use jj git init --colocate in an empty folder, then remove the .jj/ folder and only have the Git repo left over.
Another thing to note is that the command is always allowed to just error out if it can't do something (or if it might not be what the user wants). For example you can't really "uninit" a non-colocated repo, since the Git repo is stored within the .jj/ folder itself. In that case erroring is the right action.
Having though about it again,
jj-remove-repomight be better after all
I'm not sure if you mean that as a stand-alone command or a jj git subcommand, but keep in mind that there are multiple backend storage possibilities, and so not all jj repositories have Git.
If you had a native jj repo, what would you expect this command to do?
If someone has a colocated repo (
.jj/and.git/folders are siblings), then "remove repo" might make them think it will remove the entire repo folder, including the Git repo. I assume the intention is actually "remove the Jujutsu repo but leave the Git repo".
I'm not sure if you mean that as a stand-alone command or a
jj gitsubcommand
Sorry, I wasn't clear (and jumbled up the word order; I meant remove-jj-repo, not jj-remove-repo 🤦): I was referring to jj git remove-jj-repo, as originally suggested in https://github.com/jj-vcs/jj/discussions/10330#discussioncomment-18768483. Since it's prefixed with git, that should make it clear that it's "from the perspective of Git", and hence it won't remove the Git repo as well, only "the Jujutsu parts" of it.
If you had a native
jjrepo, what would you expect this command to do?
Since it's under jj git, probably just error out saying this is not a Git repo.
Since it's prefixed with
git, that should make it clear that it's "from the perspective of Git", and hence it won't remove the Git repo as well, only "the Jujutsu parts" of it.
All of the jj git commands interface with Git. Why put this concept under jj git?
All of the
jj gitcommands interface with Git. Why put this concept underjj git?
Mainly because it was originally meant to be the reverse of jj git init, which is under jj git, but you're right: If we view the command's purpose as "remove the Jujutsu-specific parts of a repo but otherwise leave colocated VCSs alone", then just jj remove-jj-repo would make sense as well.
All of the
jj gitcommands interface with Git. Why put this concept underjj git?Mainly because it was originally meant to be the reverse of
jj git init, which is underjj git, but you're right: If we view the command's purpose as "remove the Jujutsu-specific parts of a repo but otherwise leave colocated VCSs alone", then justjj remove-jj-repowould make sense as well.
That's not necessary; each backend should / could choose to have its own "remove Jujutsu parts" functionality. I don't think it makes sense to force the jj top-level CLI to have some sort of switch statement over all possible backends; indeed this is actually impossible because some backends may be proprietary and private (such as Google's).
I would welcome a jj git remove-jj-repo command. However, I think its meaning is not yet fully spelled out.
To my understanding, there are three setups:
- colocated: .git/ beside .jj/
- internal: Git repository inside .jj/ (.jj/repo/store/git)
- external: neither colocated nor internal
jj git remove-jj-repo should be applicable to colocated and external repositories. So far, the colocated case has been addressed and the internal case has been ruled out.
Furthermore, I think it does not matter (EDIT: swallowed "not" in v1) for jj git remove-jj-repo whether the .jj/ was created with jj git init or jj git clone. So far, only jj git init has been mentioned in this thread.
jj git remove-jj-reposhould be applicable to colocated and external repositories. So far, the colocated case has been addressed and the internal case has been ruled out.
Sounds reasonable to me. Rather than "ruled out", I would say that the case where the Git repository is inside .jj/ should cause this command to fail (or require a --force flag or something), since removing the "Jujutsu" part of such a repo would remove the entire repo.
Furthermore, I think it does matter for
jj git remove-jj-repowhether the .jj/ was created withjj git initorjj git clone. So far, onlyjj git inithas been mentioned in this thread.
Does it matter? Using jj git init, you can get any one of the 3 states you mentioned (the --git-repo flag can be used to point to an external repo), and using jj git clone, you can get either colocated or internal (non-colocated). After the Jujutsu repo is created, I don't see how the method of getting to that point would matter for removing it. (Plus, we don't store that information AFAIK (besides storing the args in the op log), so there's no way to know anyway.)
Furthermore, I think it does matter for
jj git remove-jj-repowhether the .jj/ was created withjj git initorjj git clone. So far, onlyjj git inithas been mentioned in this thread.Does it matter?
Sorry, I actually wanted to point out that it does not matter, but I swallowed the “not” when typing.
Thanks for the links :) Sorry I didn't know they were legitimate words haha. In that case I think I like
uninitthe most, but of course open to other ideas.