FR: Merge `jj new` and `jj split` into a unified command and resolve the need for `snapshot.auto-track = "none()"`
Summary
I propose merging the functionality of jj new and jj split into a single comprehensive command, likely named jj new. This consolidation would simplify the user experience and would inherently address the need for a security first and less error prone approach when creating new revisions. Effectively removing the issue that lead to making snapshot tracking configurable (e.g. snapshot.auto-track = "none()").
Motivation
Currently, the workflow for creating a new revision is a follows:
- To create an empty new revision: Use
jj new. - To create a new revision containing a subset of changes from an existing revision: Use
jj split.
This distinction feels artificial and adds unnecessary complexity. While a single jj new command would be better - "I need a new revision, I use jj new".
Currently, when a user has changes in their working copy (@), they often reach for jj new without much thought, especially new users of jj. This current default behavior of jj new often leads to accidental inclusion of temporary files, build artifacts, or secrets. It encourages users to not think about the changes in each commit. This process lead to users wanting snapshot tracking to be configurable, snapshot.auto-track, and some users opting for snapshot.auto-track = "none()" to avoid such accidental scenarios and force thinking more carefully about the files being committed.
This works okay, but the problem with not tracking files is work can more easily lost. What users really wanted was a workflow that discouraged committing unintended files before moving on to a new revision.
Proposed Solution
Merge the options and functionality of jj split into jj new.
Unified jj new Usage
Usage: jj new [OPTIONS]...
Options:
-i, --interactive Interactively choose which parts to split
--tool <NAME> Specify diff editor to be used (implies --interactive)
-t, --take <FILESETS> Take the filesets to the new revision
-l, --leave <FILESETS> Leave the filesets in the parent(s) revision
-p, --parents Parent(s) of the new change [default: @]
-r, --revision <REVSET> The revision to split [default: @]
-d, --destination <REVSETS> The revision(s) to base the new revision onto (can be repeated to create a merge commit)
-A, --insert-after <REVSETS> The revision(s) to insert after (can be repeated to create a merge commit) [aliases: --after]
-B, --insert-before <REVSETS> The revision(s) to insert before (can be repeated to create a merge commit) [aliases: --before]
-m, --message <MESSAGE> The change description to use (don't open editor)
--parallel Split the revision into two parallel revisions instead of a parent and child
-h, --help
A key distinction here is jj new has no default. It forces users to think about which changes they want with each revision. To mimic the exact same behavior of current jj new, they could use jj new -l *. For users who really like the current jj new default, a configurable setting could be provided to explicitly set this behavior. As such, users could use jj new like they do today with no friction. But the default behavior would be security first and less error prone - acknowledge what you want in the revision before moving on.
A key effect of this is it effectively removes the need for making snapshot tracking configurable and allows snapshot.auto-track = "all()" (which prevents data loss) to remain the recommended setting, while still providing an ergonomic.
If jj new and jj split are unified, the single command could handle all these cases and, crucially, would easily support an interactive mode (-i) to select changes, while directly solving the concerns about accidentally including untracked or unwanted files.
The key new features added to the unified command are:
-t, --take <FILESETS>: Move the specified filesets to the new revision.-l, --leave <FILESETS>: Keep the specified filesets in the parent revision (@by default).
New Flags -l and -t Interactions
How flags -l(--leave) and -t(--take) interact with other flags is open for discussion. But here is one option:
-
When
-land-tare used together, the more specific wins. e.g.jj new --take "src/**" --leave "src/old/**"is valid. -
When
-land-tare used with-i, the interactive tui only displays any conflict or ambiguity. e.g if-land-tare equally specific, the interactive tui should acknowledge this and allow a resolution. e.g. if some changes are not covered by-land-t, the interactive tui can be used to select such.
Benefits
-
Reduced Command Overhead: Users only need one command for creating a new revision, regardless of whether they intend for it to be empty or immediately contain a subset of changes.
-
Explicit Change Confirmation: For users with
snapshot.auto-track = "none()"or those who want to confirm changes before "committing", this proposal is a fundamental fix for the issues that lead users to setsnapshot.auto-track = "none()"https://github.com/jj-vcs/jj/issues/323I think every time I've used jj I've ended up getting grumpy at auto-adds and having to rip something out of a commit, sometimes after doing a push
simply running
jj new -iprovides an immediate and idiomatic way to curate revisions, mitigating security/correctness risks, without promoting a default behavior which does not. -
Conceptual Simplification: It aligns with the mental model of most VCS users: "I'm creating a new commit, and I want to specify what goes into it." Which would help with new user on-boarding.
-
Removes many needs for
.gitignoreand.git/info/excludefor temporary/scratch files, and related issues/feature requests -
Resolves https://github.com/jj-vcs/jj/issues/8170 https://github.com/jj-vcs/jj/issues/8168
Wasn't this already proposed recently? Oh, it was you, in 8171.
Yes I did in a comment in that chain. I think that suggestion diverged enough from the original issue/proposed solution to warrant it's own ticket. So here I also fleshed out the idea/motivation more. More time using jj and further discussions also cemented it as the right path forward in my mind.
Like you mentioned in the file track/untrack thread, configurable auto-tracking may not have been the best solution to begin with. So here I attempt to address the core reason users like myself use configurable auto-tracking.
Are you aware of this small doc change? https://github.com/jj-vcs/jj/pull/8305/files Also, this comment: comment (jj-vcs/jj#8267)