Skip to content

split: the second commit keeps the change id #6466

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

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

glehmann
Copy link
Contributor

@glehmann glehmann commented May 6, 2025

based on: #6458

Checklist

If applicable:

  • I have updated CHANGELOG.md
  • I have updated the documentation (README.md, docs/, demos/)
  • I have updated the config schema (cli/src/config-schema.json)
  • I have added tests to cover my changes

@glehmann glehmann requested a review from a team as a code owner May 6, 2025 11:26
@glehmann glehmann force-pushed the gln/split-command-flags-uoov branch 2 times, most recently from 96bca11 to 252108e Compare May 6, 2025 11:49
@glehmann glehmann force-pushed the gln/split-command-flags-uoov branch 3 times, most recently from b742f09 to 9f1da45 Compare May 6, 2025 20:38
@@ -300,6 +309,9 @@ pub(crate) fn cmd_split(
if legacy_bookmark_behavior {
tx.repo_mut()
.set_rewritten_commit(target.commit.id().clone(), second_commit.id().clone());
} else {
tx.repo_mut()
.set_rewritten_commit(target.commit.id().clone(), first_commit.id().clone());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't closely follow the -A/-B/-d discussion, but it seems odd that we need to add this workaround to non-"legacy" code path. Suppose our goal is to remove special case like this, I think we should either make the first commit inherit the original change id (so descendants will be rebased onto it), or make the second commit inherit both change id and descendants.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's more the other way around: we don't need it for the “legacy” code.
At first I completely removed the legacy bookmark config and used this call to change the parent in the rewrite. Then I reintroduced the legacy bookmark config and had to set the parent explicitly in the rewrite, making this call useless.

But I wonder if I understood the intent of the legacy bookmark config properly. Was it to

  1. keep the bookmark on the same change id;
  2. or to have the bookmark on the first commit?

I assumed 2. If it's 1., then this PR already does that, and legacy-bookmark-behavior=false should only have an effect when used with legacy-change-id=true.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

from #5618, which introduced this behavior

Since the first revision inherits the change id of the target revision, moving the bookmarks to the first revision is less surprising (i.e. the bookmarks stay with the change id). This no-implicit-move behavior also aligns with how jj abandon drops bookmarks instead of moving them to the parent revision.

so the intent was clearly option 1.

@PhilipMetzger would that work for you if the only way to have the bookmark on the first commit is to set both legacy-bookmark-behavior=false and legacy-change-id-behavior=true?

Copy link
Contributor

@PhilipMetzger PhilipMetzger May 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@PhilipMetzger would that work for you if the only way to have the bookmark on the first commit is to set both legacy-bookmark-behavior=false and legacy-change-id-behavior=true?

In my opinion, this change shouldn't introduce a flag since it is controversial by itself and we ideally only should support one variant of jj split -r X -B X or jj split -r X -A X as a default, this PR makes jj split -r X -B X the default. See Martins comment in your other PR #6458 (comment). I'd also hold off on landing this until we have a consensus on #3419.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it's about jj split -r X -B X vs jj split -r X -A X, but rather which commit keeps the change id: the one with the selected changes or the other one?

With jj split -A/-B/-d and the selected changes that may be moved anywhere, the commit with the non-selected changes is the only one that makes sense (to me) to keep the change id.
That's why I originally included it in the jj split -A/-B/-d PR.

We could also discuss if the commit with the selected changes should go before or after the other commit by default, but that's not the point of this PR.

Anyway, you seem quite opposed to that change, and I don't remember why. I'll see if I find that info in #3419, and maybe continue the discussion there.

Copy link
Contributor

@yuja yuja May 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With jj split -A/-B/-d and the selected changes that may be moved anywhere, the commit with the non-selected changes is the only one that makes sense (to me) to keep the change id.

That makes sense. Specifying -A/-B/-d effectively means that the "legacy" option is turned off. I think it's similar to how we implemented jj duplicate -A/-B/-d.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With jj split -A/-B/-d and the selected changes that may be moved anywhere, the commit with the non-selected changes is the only one that makes sense (to me) to keep the change id.
That's why I originally included it in the jj split -A/-B/-d PR.

I still agree with that.

We could also discuss if the commit with the selected changes should go before or after the other commit by default, but that's not the point of this PR.

Anyway, you seem quite opposed to that change, and I don't remember why. I'll see if I find that info in #3419, and maybe continue the discussion there.

I currently don't think that rebase -r X -B X should be default which happens to be the current implementation, although this opinion is a minority but that's talk for #3419.

Copy link
Contributor

@ilyagr ilyagr May 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think most of these points were already covered by others, but I thought I'd summarize my opinions.

It seems that Yuya's original comment in this thread is already addressed. Re-iterating #3419 (comment), my opinion was that the change id, the bookmarks, and the descendants should all go to the second commit by default (so, with legacy-split-behavior=false, presumably). This seems to agree with Yuya's comment and also seems to match what this PR does right now, so yay!

If we decide to not go with this PR, Philip's suggestion (as I understood it) to have no default and to rely fully on -A/-B/-d seems reasonable to me. IMO (as a bit of a minor aside), that would be blocked on significantly improving1 the docs for -A/-B/-d, which would be good regardless, but would become urgent and crucial if we remove the default.

However, that does not stop people in the know from experimenting, seeing how convenient that UI is, and how common/useful split -r X -B X (which does seem to match my preferred behavior) is.

Footnotes

  1. The main reason I'm complaining about the docs is that I couldn't tell from them whether the behavior I want is split -r X -B X or split -r X -A X; I had to experiment. Again, I think this is not a huge problem unless we remove the default and people are thus required to learn these flags.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we decide to not go with this PR, Philip's suggestion (as I understood it) to have no default and to rely fully on -A/-B/-d seems reasonable to me. IMO (as a bit of a minor aside), that would be blocked on significantly improving1 the docs for -A/-B/-d, which would be good regardless, but would become urgent and crucial if we remove the default.

That's correct, but as I mentioned in the issue it should be a temporary stopgap before the users (people who are less involved in the decision process) decide on which behavior they want, this can take up to at least 6 months but that should be no issue (it is extremely likely that -r X -B X will win, since -r X -A X is a minority position).

Copy link
Member

@cenviity cenviity May 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently, with split.legacy-bookmark-behavior set to true, jj split -r X (i.e. the default) and jj split -r X -B X both insert a new commit before X, but the change ID behaviour is different. So it would make sense to me either to a) remove the default and warn if none of -A/-B/-d are supplied or b) keep the default and merge this PR to make the change ID behaviour consistent.

And with split.legacy-bookmark-behavior set to false, it is even harder to reconcile the behaviour of jj split -r X vs jj split -r X -B X. With jj split -r X, it "appears" as though a new commit was inserted after "X", not before, since the selected changes and bookmarks have moved to the newly created commit now with change ID X.

@glehmann glehmann force-pushed the gln/split-command-flags-uoov branch 2 times, most recently from 4c6b342 to ac0bb82 Compare May 7, 2025 21:23
@cenviity cenviity mentioned this pull request May 8, 2025
4 tasks
work_dir.write_file("file2", "bar\n");
work_dir.run_jj(["describe", "-m", "my feature"]).success();

let output = work_dir.run_jj([
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to snapshot the output and log output before running this command to demonstrate the legacy behaviour of the revision with the selected changes (i.e. the 'first commit') keeping the change ID.

Comment on lines 1174 to 1194
let output = work_dir.run_jj([
"split",
"-m",
"file1",
"-r",
"qpvuntsmwlqt",
"--insert-before",
"qpvuntsmwlqt",
"file1",
]);
Copy link
Member

@cenviity cenviity May 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(not actionable)

See my comment at #6458 (comment) comparing the same set of tests here with differing log outputs for why I think the revision with remaining changes (i.e. the 'second commit') keeping the change ID makes more sense. So I am in favour of this PR.

Here, the command indicates we are inserting a revision before qpvuntsmwlqt, and that is what the log output below shows – vruxwmqvtpmx is the newly inserted revision with the changes that have been split out.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven’t been following the latest discussions, so just to reiterate my quite strong view at this point: jj split -r X -d/-B/-A … is creating a new commit from extracted parts of X. The commit that remains behind, containing the parts that were not split out, should be the one to keep the change ID and bookmarks. So in jj split -r X -B X, the second commit should inherit the change ID; in jj split -r X -A X, the first commit should. (I’d rather not speak of “the first/second commit” at all, for this reason, but rather the original commit and the split‐out commit, or similar.)

I think we have pretty strong consensus around this at this point, when operating within the -d/-B/-A framework (but if anyone disagrees they should say so). I believe the remaining disagreement is only about what the default action should be.

I haven’t read the PR or played with the implementation to check if it agrees with my intuitions on how the flags should work, so I don’t know if this comment is useful.

Copy link
Member

@cenviity cenviity May 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven’t been following the latest discussions, so just to reiterate my quite strong view at this point: jj split -r X -d/-B/-A … is creating a new commit from extracted parts of X. The commit that remains behind, containing the parts that were not split out, should be the one to keep the change ID and bookmarks.

In case it weren't apparent, I agree and am in favour of this PR. I was pointing out another way of reasoning that arrives at the same conclusion.

So in jj split -r X -B X, the second commit should inherit the change ID; in jj split -r X -A X, the first commit should.

For the benefit of others following this thread, IIUC I think you meant to say 'the second commit' in both cases, in the context of this PR and the previous paragraph where 'the second commit' is the revision with the parts that weren't split out (the remaining changes). Maybe here you meant 'the second commit' as in the child commit after jj split -r X -B X and 'the first commit' as in the parent commit after jj split -r X -A X.

(I’d rather not speak of “the first/second commit” at all, for this reason, but rather the original commit and the split‐out commit, or similar.)

Agreed. See my comment at #6458 (comment) for cleaning up the terminology now that jj split -A/-B/-d is possible and the 'order' of the 'first' and 'second' commits is less clear and becomes rather arbitrary.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe here you meant 'the second commit' as in the child commit after jj split -r X -B X and 'the first commit' as in the parent commit after jj split -r X -A X.

Right. (A good example of why the terminology becomes inadequate with the new flags.)

@cenviity
Copy link
Member

cenviity commented May 8, 2025

See my other comment at #6458 (comment) for a suggestion on cleaning up the ‘first commit’ / ‘second commit’ terminology.

@glehmann glehmann force-pushed the gln/split-command-flags-uoov branch 4 times, most recently from 30db138 to 9a8c1c0 Compare May 11, 2025 12:48
@glehmann glehmann force-pushed the gln/split-command-flags-uoov branch 7 times, most recently from dca26ed to 7d50be8 Compare May 16, 2025 09:36
Copy link
Contributor

@ilyagr ilyagr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, @glehmann for working on this and on #6458! Even though I missed most of the discussion, I really appreciate it!

Upon a quick test, unless I missed something, this PR's behavior at the moment is exactly what I thought the default behavior should be. So, it SGTM, but it sounds like we need to decide between this and Philip's suggestion of having no default behavior (see my other comment; perhaps there are also other suggestions I am less aware of), and there's no rush on that.

Whatever we decide in the end, having the option to play with all the behaviors we were discussing is really nice!

* `jj split` assigns the change id and the bookmarks of the source revision
to the second revision.
You can opt out of this change by setting `split.legacy-bookmark-behavior = true`,
but this will likely be removed in a future release.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reminder: let's make sure the commit description, this changelog entry, and the docs are all consistent before merging (if we get to that point).

Currently, the commit description still says that split.legacy-bookmark-behavior defaults to true, but it actually defaults to false. It seems this might change, but whatever we do, we should double-check that we are consistent before merging.

@@ -300,6 +309,9 @@ pub(crate) fn cmd_split(
if legacy_bookmark_behavior {
tx.repo_mut()
.set_rewritten_commit(target.commit.id().clone(), second_commit.id().clone());
} else {
tx.repo_mut()
.set_rewritten_commit(target.commit.id().clone(), first_commit.id().clone());
Copy link
Contributor

@ilyagr ilyagr May 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think most of these points were already covered by others, but I thought I'd summarize my opinions.

It seems that Yuya's original comment in this thread is already addressed. Re-iterating #3419 (comment), my opinion was that the change id, the bookmarks, and the descendants should all go to the second commit by default (so, with legacy-split-behavior=false, presumably). This seems to agree with Yuya's comment and also seems to match what this PR does right now, so yay!

If we decide to not go with this PR, Philip's suggestion (as I understood it) to have no default and to rely fully on -A/-B/-d seems reasonable to me. IMO (as a bit of a minor aside), that would be blocked on significantly improving1 the docs for -A/-B/-d, which would be good regardless, but would become urgent and crucial if we remove the default.

However, that does not stop people in the know from experimenting, seeing how convenient that UI is, and how common/useful split -r X -B X (which does seem to match my preferred behavior) is.

Footnotes

  1. The main reason I'm complaining about the docs is that I couldn't tell from them whether the behavior I want is split -r X -B X or split -r X -A X; I had to experiment. Again, I think this is not a huge problem unless we remove the default and people are thus required to learn these flags.

The first commit contains the split out changes.
The second commit usually keeps most of the changes, the change id and
the attached bookmarks.

This no-implicit-move behavior aligns with other jj commands.

With the -A/-B/-d options, the split-out commit may be moved anywhere.
With commit tree

    @  pmpklomk (empty) (no description set)
    ○  pzskstlk *letters* fileB
    ○  kmvzrqtu fileA
    │ ○  lyzvpymy *numbers* file3&C
    │ ○  kpmxxkwk file2
    │ ○  xzvtlrrt file1
    ├─╯
    ◆  zzzzzzzz root()

when splitting `fileC` out of `lyzvpymy` to the other branch with

    jj split -r lyzvpymy -d pzskstlk

the change id and the bookmark stay in the branch with the source commit.

    @  pmpklomk (empty) (no description set)
    ○  vowztxqo fileC
    ○  pzskstlk *letters* fileB
    ○  kmvzrqtu fileA
    │ ○  lyzvpymy *numbers* file3
    │ ○  kpmxxkwk file2
    │ ○  xzvtlrrt file1
    ├─╯
    ◆  zzzzzzzz root()
@glehmann glehmann force-pushed the gln/split-command-flags-uoov branch from 7d50be8 to e58b7ad Compare May 17, 2025 21:33
Copy link
Member

@cenviity cenviity left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With the -A/-B/-d options, the split-out commit may be moved anywhere.
With commit tree

@  pmpklomk (empty) (no description set)
○  pzskstlk *letters* fileB
○  kmvzrqtu fileA
│ ○  lyzvpymy *numbers* file3&C
│ ○  kpmxxkwk file2
│ ○  xzvtlrrt file1
├─╯
◆  zzzzzzzz root()

when splitting fileC out of lyzvpymy to the other branch with

jj split -r lyzvpymy -d pzskstlk

the change id and the bookmark stay in the branch with the source commit.

@  pmpklomk (empty) (no description set)
○  vowztxqo fileC
○  pzskstlk *letters* fileB
○  kmvzrqtu fileA
│ ○  lyzvpymy *numbers* file3
│ ○  kpmxxkwk file2
│ ○  xzvtlrrt file1
├─╯
◆  zzzzzzzz root()

I noticed that in the current commit message the command says -d pzskstlk but the resulting tree looks like -A pzskstlk was applied instead (the new change vowztxqo is inserted between pzskstlk and its child. So, either the command or the resulting tree needs to be updated.

Another nit – perhaps use diff summaries rather than descriptions to show the before and after states? The description for lyzvpymy should remain the same after the split.

@ilyagr
Copy link
Contributor

ilyagr commented May 20, 2025

Is this issue with -d related to this PR (beyond its commit description) as it is now, or should it be a separate issue?

Perhaps we should remove the discussion of -d/-A/-B from the commit description, assuming that this PR does not change what -d/-A/-B do?

@cenviity
Copy link
Member

Is this issue with -d related to this PR (beyond its commit description) as it is now, or should it be a separate issue?

Perhaps we should remove the discussion of -d/-A/-B from the commit description, assuming that this PR does not change what -d/-A/-B do?

I think the example is useful to demonstrate that the change ID lyzvpymy stays in place rather than get taken by the newly created commit, which is what this PR changes. It's just that the argument used in the command there doesn't match the output tree.

@yuja
Copy link
Contributor

yuja commented May 20, 2025

Is this PR still relevant for review? or are we just discussing a potential default to be introduced later? iirc, the idea was to try out the new -A/-B/-d flags for a couple of weeks, and pick one as the default.

@glehmann
Copy link
Contributor Author

iirc, the idea was to try out the new -A/-B/-d flags for a couple of weeks, and pick one as the default.

yes, no hurry to review this PR

@glehmann
Copy link
Contributor Author

I noticed that in the current commit message the command says -d pzskstlk but the resulting tree looks like -A pzskstlk was applied instead (the new change vowztxqo is inserted between pzskstlk and its child. So, either the command or the resulting tree needs to be updated.

Good catch!
On the other hand, I think that @ilyagr is right: this PR is not about the behavior with -A/-B/-d. This behavior is already this one when using these flags.
I'll use another example that doesn't use the -A/-B/d flags

@cenviity
Copy link
Member

On the other hand, I think that @ilyagr is right: this PR is not about the behavior with -A/-B/-d. This behavior is already this one when using these flags.

Ah yes, I'd forgotten that the new flags already exhibit the behaviour in this PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants