Skip to content
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

FR: jj file subcommand for file operations #3812

Open
arxanas opened this issue Jun 1, 2024 · 24 comments
Open

FR: jj file subcommand for file operations #3812

arxanas opened this issue Jun 1, 2024 · 24 comments
Labels
polish🪒🐃 Make existing features more convenient and more consistent

Comments

@arxanas
Copy link
Collaborator

arxanas commented Jun 1, 2024

Is your feature request related to a problem? Please describe.

  • Unix-style names like jj cat are not descriptive and quite unintuitive for the uninitiated.
  • We will one day probably want to have a specific command for renaming files in such a way that jj can record the file rename; that should go under a jj file subcommand for uniformity as well.

Describe the solution you'd like

Commands of forms like this should one day be grouped together under a single subcommand:

  • jj file print(jj file show?) (alias jj file cat)
  • jj file move/jj file rename (alias jj file mv)
  • jj file delete(/jj file remove?) (alias jj file rm)
  • jj file track/jj file untrack
  • jj file chmod (but chmod is a Unix-ism so we might want to use a different term)

Describe alternatives you've considered

  • Existing Git and Mercurial interfaces for manipulating files are scattered around several subcommands for some reason, which is unorganized/undiscoverable.

Additional context
N/A

@arxanas arxanas added enhancement New feature or request polish🪒🐃 Make existing features more convenient and more consistent and removed enhancement New feature or request labels Jun 1, 2024
@fowles
Copy link
Collaborator

fowles commented Jun 5, 2024

jj file chmod too, please

@fowles
Copy link
Collaborator

fowles commented Jun 12, 2024

I am interested in adding a move/rename command. I would be willing to do the work, but need a few pointer in the code base for where to poke.

Also, I would appreciate some indication that this work would be accepted before I go and start doing it.

@martinvonz
Copy link
Owner

I am interested in adding a move/rename command. I would be willing to do the work, but need a few pointer in the code base for where to poke.

That command will not be very useful until we support copies and renames (but maybe still a tiny bit useful?). Do you mean that you wanted to implement that feature too? Or do you see a use for the command that I'm not seeing?

I think our canonical bug for copy/rename support is #3386. @torquestomp has started working on a design for it (and maybe I'll take that over from him). I don't think there's much work to parallelize in the beginning but maybe there will be a little later, I'm not sure.

@fowles
Copy link
Collaborator

fowles commented Jun 13, 2024

I am willing to start with the command stuff as that is going to be a good deal simpler. If I finish the command stuff I can take a crack at implementing the underlying thing as follow. Since git auto-detects copies, it seems like it would be useful as it stands.

@arxanas
Copy link
Collaborator Author

arxanas commented Jun 13, 2024

  • For moving/renaming files, there's an interesting question of what to do when the source or destination would be ignored. If there's not an obvious solution, it might be worth opening another thread to discuss the semantics.
  • For the location in the codebase, you'd probably want to adjust cli/src/commands/cat.rs (assuming that we would make the canonical form into jj file print) and add additional subcommands. You can see e.g. BranchCommand for an example of subcommands.

@ilyagr
Copy link
Collaborator

ilyagr commented Jun 13, 2024

One command that I keep wondering about adding is a command that "moves" a file in one side of a conflict.

When jj doesn't realize a move-edit conflict happened (which it currently never does), jj presents it as a delete-edit conflict and a new file. The reason I want that command is that it would let the user turn that mess into an edit-edit conflict at the new path.

@martinvonz
Copy link
Owner

I am willing to start with the command stuff as that is going to be a good deal simpler. If I finish the command stuff I can take a crack at implementing the underlying thing as follow. Since git auto-detects copies, it seems like it would be useful as it stands.

It seems like a regular mv would usually have the same effect. Ilya pointed out one possible use case for a jj mv command. Another is that you can run it on an arbitrary commit. But other than those two, it wouldn't help with renames AFAICT. Again, that doesn't mean it won't be useful; I'm just trying to make sure you don't expect the command to help more with renames than it actually will. In particular, note that git mv has no effect on renames (which you seem to know already since you mentioned auto-detection).

  • For moving/renaming files, there's an interesting question of what to do when the source or destination would be ignored.

When would the source or destination be ignored?

@fowles
Copy link
Collaborator

fowles commented Jun 14, 2024

When would the source or destination be ignored?

I think when it is in the .gitignore file.

@martinvonz
Copy link
Owner

When would the source or destination be ignored?

I think when it is in the .gitignore file.

Ah, that kind of ignored path :) Makes sense.

Good question. If we don't give such paths any special treatment, then we'd just update the commit as usual, and when update the working copy to match (as we always do at the end of a command), we'd leave the ignored file alone, which might mean that the file appears modified afterwards. For attempting to move an ignored-and-untracked file, the command would just error out because the file doesn't exist in the commit, but it would be nice if we printed an error if the command was run on the working-copy commit.

@fowles
Copy link
Collaborator

fowles commented Jun 14, 2024

Do folks want me to deprecate the existing file cat at the same time?

@ilyagr
Copy link
Collaborator

ilyagr commented Jun 15, 2024

When jj doesn't realize a move-edit conflict happened (which it currently never does), jj presents it as a delete-edit conflict and a new file. The reason I want that command is that it would let the user turn that mess into an edit-edit conflict at the new path.

Replying to myself, I realized that there's a natural way to implement this as part of normal jj file move/cp commands.

If you jj file move a b, and b already exists, jj file move can create a conflict with sides a and b and the base being no file. This is as though there was a separate commit where you created a file called b but with value a from nothing, and then rebased that commit on top of the current one.

If b happened to be a conflicted path with an edit-deletion conflict, this will turn b into a more complicated conflict that would immediately simplify to an edit-edit conflict. Similarly, if b is a normal file and a was an edit-deletion conflict, it should also work correctly.

There could also be a jj file move a b --overwrite that disables that behavior, but that would be very similar to using the Unix mv command (unless a is conflicted, in which case the Unix mv a b command would do the wrong thing -- for technical reasons, the resulting file b would be considered non-conflicted even though it has conflict markers. There are few usecases where people would want to use it in that way, though.)


Update: I have a bit of unease to picking the conflict base in what I describe above. Another option would be for jj file move a b to create a conflict at b with sides old_value_of_b, a, and base value_of_b_in_parent_commit, or with base value_of_a_in_parent_commit. This seems tempting theoretically, but I'm not sure which to pick, so I'd rather just pick an absence of a file as bases unless we get a better idea.


More generally, I feel like a lot of jj file commands have to do with conflicts in my mind, perhaps except for file cat. I'm thinking of noting this in the help for jj file, but keeping it called jj file (as opposed to jj conflict), since all the commands seem useful for not-conflicts, especially if we have move tracking one day.

@yuja
Copy link
Collaborator

yuja commented Jun 15, 2024

Do we also rename jj files to jj file list? It would be confusing if there were jj file and jj files.

I'm not sure about jj diff. On one hand, it's superior version of jj files. However, it can also be seen as a subset of jj show/jj log. In any case, I think the top-level jj diff alias should be preserved.

@ilyagr
Copy link
Collaborator

ilyagr commented Jun 15, 2024

jj file list sounds great to me!

jj diff feels like it should not be in jj file to me, to the point that I was wondering why I felt so strongly about it. One way to make sense of this that I like is to declare that jj file should be restricted to operations that work on a single commit's tree, while jj diff compares trees from more than one commit.

This also justifies a vague feeling I had that we could make jj resolve and alias for jj file resolve. I don't think making this change is very important, but we discussed this on Discord briefly, and now I have an answer to the question of why I feel that resolve should be in jj file and diffedit shouldn't.


One version of jj file move I described (as an aside) in #3812 (comment) would also look at a parent commit's tree. Perhaps this is a reason to lean away from that version of jj file move.

@fowles
Copy link
Collaborator

fowles commented Jun 15, 2024

I am happy to rename files to file list but I would like ot do that in a separate PR.

@fowles
Copy link
Collaborator

fowles commented Jun 15, 2024

https://github.com/fowles/jj/tree/file_list is built on top of https://github.com/fowles/jj/tree/file_cli (#3812), so I have that ready to go next

@arxanas
Copy link
Collaborator Author

arxanas commented Jun 16, 2024

I'll add them to the top-level issue.

@ilyagr
Copy link
Collaborator

ilyagr commented Jun 17, 2024

(This is all an aside)

Another thing in common for jj file commands is that they very much treat a commit as a snapshot as opposed to a patch.

In theory, commands like diff, show, diffedit, squash could be moved to jj patch, e.g. jj diff could be an alias for jj patch diff. I'm not sure this is useful, but it would be consistent. One case where this would be mildly useful is that jj patch show sounds better to me than jj show, but that's not a sufficient reason create jj patch IMO.

Perhaps abandon and rebase would belong to jj patch too.

It's also curious that most, but not all, of these potential jj patch commands work not only on one patch but also on the diff between arbitrary two commits.

@joyously
Copy link

In theory, commands like diff, show, diffedit, squash could be moved to jj patch, e.g. jj diff could be an alias for jj patch diff. I'm not sure this is useful, but it would be consistent. One case where this would be mildly useful is that jj patch show sounds better to me than jj show, but that's not a sufficient reason create jj patch IMO.

I kind of like this concept. It reminds me of how some Git help (i don't remember where) was organized: commands that affect the graph and commands that affect files.

@yuja
Copy link
Collaborator

yuja commented Jun 18, 2024

  • jj file print(jj file show?) (alias jj file cat)

iirc, someone said they like show, and I also vote for show.

  • jj file chmod (but chmod is a Unix-ism so we might want to use a different term)

maybe jj file set-mode? (assuming we'll add jj git remote set-url.)

@ilyagr
Copy link
Collaborator

ilyagr commented Jun 26, 2024

maybe jj file set-mode?

I wonder whether jj file kind or jj file mode would work. It could print the file mode without an argument of what to set the mode to.

Or it could be jj file kind set/ jj file kind get.

Though, I feel like all of these are harder to remember than chmod. So, I'd keep chmod as an alias probably.


I'm slightly itching to add Unix-y aliases to all of these (e.g. jj file ls for jj file list, cat for print/show, etc.). Is this something we want? I feel like it will be easier to remember, but for commands other than chmod, the current names are OK too.

I also initially considered Windows-y aliases (jj file dir), but the alias for print/show would be type, which I think is confusing.

@ilyagr
Copy link
Collaborator

ilyagr commented Jun 26, 2024

Also, did we consciously decide to go with jj file print instead of jj file show?

While print is OK, I still like show quite a bit better; it feels clearer. I'm happy to keep print as an alias, or get rid of it. If we go with UNIXy aliases for everything, it would also have jj file cat as an alias.

@fowles
Copy link
Collaborator

fowles commented Jun 26, 2024

I personally like ls and cat as aliases, but I don't feel strongly.

@martinvonz
Copy link
Owner

Also, did we consciously decide to go with jj file print instead of jj file show?

I don't think we did. I'm fine with renaming it to jj file show. We should do that before the release next week if we're going to do it at all, so we don't have 0.19.0 renaming jj print to jj file print and then 0.20. renaming it again.

I wonder whether jj file kind or jj file mode would work. It could print the file mode without an argument of what to set the mode to.

Probably better to have separate commands for query and mutation. That's an argument I've heard before at least.

@yuja
Copy link
Collaborator

yuja commented Jun 26, 2024

maybe jj file set-mode?

I wonder whether jj file kind or jj file mode would work. It could print the file mode without an argument of what to set the mode to.

I expect jj file list will gain a flag or template to show file modes.

jj file mode <set|get> might be okay, but I prefer somewhat flattened structure.

I'm slightly itching to add Unix-y aliases to all of these (e.g. jj file ls for jj file list, cat for print/show, etc.). Is this something we want? I feel like it will be easier to remember, but for commands other than chmod, the current names are OK too.

I like Unix-y aliases, but I would rather want them in top-level (i.e. jj cat and jj ls), which is easier to remember and can be defined by user.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
polish🪒🐃 Make existing features more convenient and more consistent
Projects
None yet
Development

No branches or pull requests

6 participants