-
Notifications
You must be signed in to change notification settings - Fork 346
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
cli split
: add experimental --restore-from
(AKA --from
) argument
#4097
base: main
Are you sure you want to change the base?
Conversation
split
: add --restore-from
(AKA --from
) argumentsplit
: add --restore-from
(AKA --from
) argument
ff24fdb
to
401c1e2
Compare
fcd81d9
to
d883f5d
Compare
My current thoughts about this are:
So, I think I'll prepare this for merging as is, in the hopes that we might improve it later (unless somebody tells me to wait). The one thing I'd like to change would be the description of the second commit. For example, for my use-cases, if the Perhaps after #3828, we'll have an interface for |
5d2758d
to
f9ac85c
Compare
split
: add --restore-from
(AKA --from
) argumentsplit
: add experimental --restore-from
(AKA --from
) argument
I think it makes sense to label this option as "Experimental", since I think the way it treats descriptions will change later, and perhaps we find a better approach for these usecases. I'll do that in a second. |
097ffa0
to
2f637c9
Compare
b40bc42
to
395fbf8
Compare
ea6e357
to
d37e443
Compare
@@ -51,6 +51,31 @@ pub(crate) struct SplitArgs { | |||
/// The revision to split | |||
#[arg(long, short, default_value = "@")] | |||
revision: RevisionArg, | |||
/// The revision to copy as the first part of the split (Experimental) |
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: I think the "The revision" makes it sound a bit like it's required. But maybe that's just me (i.e. feel free to ignore). (I know revision
just above also says "The revision" but that revision is required, it's just that its value is provided by default.)
/// This is especially useful if the FROM revision is a past version of | ||
/// REVISION, with its commit id obtained via `jj obslog` or `jj log | ||
/// --at-operation`. |
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.
Do we want a note saying that it probably doesn't do what you want if you pass it past version that has since been rebased?
I can see both diff and interdiff behaviors being useful, btw, but the interdiff behavior seems more useful, mostly because the typical use case is what the one described above.
For the regular diff/restore behavior (i.e. what's implemented), you would probably more likely do it based on a commit that's still visible, but then it's unclear why you would want to split the current commit to match a still-visible one.
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.
This is a good question.
The main advantage of the regular restore behavior that comes to mind is that it's simpler to explain and understand, it doesn't create conflicts, and it works well in many cases. It is a good point thought that, when the difference does matter, the interdiff behavior might often be preferable (thought I'd guess it's not always).
If there was no cost to switching to interdiff, I'd do it (unless I can think of or remember some other reason not to). The main thing that is giving me pause is: what do we call it? How do we document it?
There is a simple approach to solve this that is not very elegant. It would be to keep this PR as is and add a --interdiff --restore-from X
behavior. This would be easy to document, but it's a step away from "do what I mean" behavior.
In any case, I can pay attention to when it would help/hurt to interdiff as I use this.
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.
Sorry, I realized later that I think I described the cases poorly as "diff" vs "interdiff". I think a better classification is "snapshot" vs "diff". So what I previously called the "interdiff" mode could be something like jj split --copy-diff-from=X
or something like that. I think that's a pretty natural way to think of it. What do you think?
Btw, it's implied that the diff is copied to the first commit of the split. I think we can just explain that without having to call the option jj split --copy-first-commit-diff-from=X
or similar.
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.
Is it something that jj rebase -r X --insert-before Y --reparent-descendants
would do?
jj split --insert-diff-from
/--insert-snapshot-from
might be better names. I find it's confusing that jj split --restore-from
inserts a new arbitrary state in between.
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.
Is it something that jj rebase -r X --insert-before Y --reparent-descendants would do?
In theory, it's similar, though (unless we figure out a better but still consistent behavior) it would create divergence if X was hidden and Y had the same change id.
In practice, I tried this (without --reparent-descendants
) in the case of X
being hidden and having children and it's quite weird and buggy. It seems to try to rebase the children of X
. Moreover, it leads to
$ RUST_BACKTRACE=1 jj op diff
From operation 16d658cd9cdf: push all branches to git remote origin
To operation 1eb8c899850d: rebase commit c9ee0eb96f90b40e88c9a83fb3268bc16ab748f4
thread 'main' panicked at /Users/ilyagr/dev/jj/lib/src/dag_walk.rs:116:13:
graph has cycle
stack backtrace:
0: _rust_begin_unwind
1: core::panicking::panic_fmt
2: jj_cli::commands::operation::diff::show_op_diff
3: jj_cli::commands::operation::cmd_operation
4: jj_cli::commands::run_command
5: <alloc::boxed::Box<F,A> as core::ops::function::FnOnce<Args>>::call_once
6: jj_cli::cli_util::CliRunner::run
7: jj::main
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
jj split
--insert-diff-from
/--insert-snapshot-from
might be better names.
At a glance, I like these quite a bit, thank you!
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.
Is it something that jj rebase -r X --insert-before Y --reparent-descendants would do?
In theory, it's similar, though (unless we figure out a better but still consistent behavior) it would create divergence if X was hidden and Y had the same change id.
Perhaps, I should use jj duplicate
(in place of rebase
.)
fwiw, we should fix op diff
bug separately. I guess it wouldn't be robust against diverged change ids.
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.
Perhaps, I should use jj duplicate (in place of rebase.)
Indeed, that sounds great to me. duplicate
makes sense for hidden commits just as well as non-hidden ones.
I'm beginning to think that rebase
doesn't actually make much sense for hidden commits; we might want to forbid that outright and suggest duplicate
instead. If a person really, really needs it (and wants to create divergence) they could un-hide the revisions before rebasing.
If jj duplicate -r X --insert-before Y --reparent-descendants
worked, it would do exactly the same thing as jj split --insert-snapshot-from
, I think. jj duplicate -r X --insert-before Y
would correspond to jj split --insert-diff-from
. I am not sure whether the split
options would be useful if the duplicate
worked for this usecase; their only real use would be didactic. Depending on when we implement the duplicate
functionality, we might want them until then.
I am a bit confused about whether we want duplicate -s
or duplicate -b
, but that could be a completely separate discussion. We can make it work, but I think the result is confusing (I should experiment with it a bit).
Cc other discussions about more flexible duplicate
:
#3518
#3772
40d3b14
to
e0385ce
Compare
2303bda
to
9aa8627
Compare
009c954
to
8066a41
Compare
This is useful when you accidentally put some changes in the wrong commit. In the future, we could add some shortcuts for common uses. For example, we could define `current(X)` to be the current revision with the same change id as `X` (which would usually be a hidden commit) and have a shortcut for `jj split --from X -r current(X)` (only valid if `current(X)` is one commit). Or, we could have a similar operation for `obscurrent(X)`, defined as `obsheads(obsdescendants(X))` , based on the `jj obslog` graph (see also jj-vcs#4129 for a more focused discussion about implementing such operation). However, let's have the basic operation first. It should be useful with the default value of `-r @`.
Tests are TODO for now, and some more polish might be needed, but I wanted to share the idea. I've been wondering for a while what's a sensible UI for this operation, and I think I figured one out.
This is useful when you accidentally put some changes in the wrong commit.
In the future, we could add some shortcuts for common uses. For example, we could define
current(X)
to be the current revision with the same change id asX
(which would usually be a hidden commit) and have a shortcut forjj split --from X -r current(X)
(only valid ifcurrent(X)
is one commit).Or, we could have a similar operation for
obscurrent(X)
, defined asobsheads(obsdescendants(X))
, based on thejj obslog
graph (see also #4129 for a more focused discussion about implementing such operations).However, let's design/implement the basic operation first. It should be useful with the default value of
-r @
.Checklist
If applicable:
CHANGELOG.md