Skip to content

FR: Allow jj duplicate to partially duplicate changes #9935

Description

@Tijs-B

Is your feature request related to a problem? Please describe.
jj duplicate always copies the entire diff of the source revisions. There's no way to partially duplicate changes in revisions besides running jj duplicate and then a jj restore command.

Concrete use case: I created a revision for a bug fix which included a new test exercising the bug. I'd like the new test to make sure it would fail against the older code. To know that, I'd like to duplicate the change onto a new revision on top of an older revision in which the bug still existed, including only the new test in the change. Then, I can easily abandon the duplicated revision.

Describe the solution you'd like
jj duplicate should take an optional fileset positional argument and a -i/--interactive option. Because only one positional argument is possible, the revset argument should move to an option -f/--from:

  • jj duplicate <revset> becomes jj duplicate --from <revset>, --from defaulting to @ if not supplied.
    • This is a breaking change.
  • jj duplicate --from <revset> <fileset> should duplicate all revisions its in revset, restricting each newly created revision only to changes in the fileset. This could result in empty new revisions, with which I'm not sure what should happen.
  • jj duplicate --from <revset> --interactive should open an interactive diff editor to select the diff to duplicate into the new revisions, like jj squash --interactive does. jj squash --interactive can handle multiple revisions by invoking the diff editor for each revision, so jj duplicate can do the same.

This makes jj duplicate more orthogonal to jj squash: squash moves changes andduplicate copies changes.

Describe alternatives you've considered

  • jj duplicate <source> + jj restore "~<fileset>" -r <duplicated change>: this requires two commands and a negative fileset to restore unwanted changes.
  • jj new <target> + jj restore -f <source> <fileset>: this requires two commands
  • jj squash -f <source> -o <target> <fileset>: this will lose the change in the source revision.

Additional context
I personally think adding a -f flag is an improvement, because many other commands take a fileset as positional parameter and a source revset in -f, like absorb and squash; consolidating the design of the CLI.

duplicate could also be made even more orthogonal to squash if it would also accept a --into argument to duplicate changes from one revision into another, not creating new revisions. But I am not sure if that is a good idea to include here.

There's an open PR to do the same for revert: #8893

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions