Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

The key is to be cowboy until you’re happy with things, and then get clean, just like with git. It’s way easier to slice and dice commits with jj and so you can be sloppy at first and it’s easy to turn beautiful afterward.


That’s not how I use git, at all. I have a messy workspace with a lot of things going on simultaneously, and only selectively stage when something crosses the finish line. Sounds very difficult to do this in jj.


You can work exactly this way using the “gitpatch” diff editor[1].

1. Your working copy contains whatever mish-mash of changes you want.

2. When you’re ready to stage and commit these changes, run `jj commit --tool gitpatch`

3. The iterative “stage this hunk?” UI from git lets you choose what to commit.

4. Your editor opens for a commit message.

5. The changes you selected are now in a new parent commit of your working copy, and the remaining changes are left in the working copy commit.

In addition to the _same_ workflow, jj makes it easier to have other workflows as well (you may be interested in the megamerge workflow if you’re always working on multiple tasks at once).

[1]: https://zerowidth.com/2025/jj-tips-and-tricks/#hunk-wise-sty...


Selectively staging is easier in jj. I loved git’s index, jj does it better.


How? The jj documentation seems to be pretty clear about getting rid of the staging area.


There are a couple main ways to achieve a workflow similar to Git's staging area.

#1: Squashing

Create a revision for the feature, then create another revision atop that.

  $ jj new main -m 'feature'
  $ jj new
  $ jj
  @  trtpzvno [email protected] 2025-09-01 12:32:33 9ac76a0f
  │  (empty) (no description set)
  ○  wvzltyyr [email protected] 2025-09-01 12:32:31 80b2d5d0
  │  (empty) feature
  ◆  zxrulorx [email protected] 2024-12-11 03:44:38 main 351a2b30
  │  all the stuff
  $ vim
  $ jj
  @  trtpzvno [email protected] 2025-09-01 12:34:50 5516c2b9
  │  (no description set)
  ○  wvzltyyr [email protected] 2025-09-01 12:32:31 80b2d5d0
  │  (empty) feature
  ◆  zxrulorx [email protected] 2024-12-11 03:44:38 main 351a2b30
  │  all the stuff
  ~
  $ jj squash -i
  # interactively choose hunks to squash into parent
  $ jj
  @  oxqnumku [email protected] 2025-09-01 12:35:48 8694aa34
  │  (empty) (no description set)
  ○  wvzltyyr [email protected] 2025-09-01 12:35:48 47110bff
  │  feature
  ◆  zxrulorx [email protected] 2024-12-11 03:44:38 main 351a2b30
  │  all the stuff
  ~
#2: Splitting

Create a revision for the feature, then split it up retroactively.

  $ jj new main -m 'feature'
  $ jj
  @  snomlyny [email protected] 2025-09-01 12:38:39 84c6ecaa
  │  (empty) feature
  ◆  zxrulorx [email protected] 2024-12-11 03:44:38 main 351a2b30
  │  all the stuff
  ~
  $ vim
  $ jj
  @  snomlyny [email protected] 2025-09-01 12:39:51 8038bdd4
  │  feature
  ◆  zxrulorx [email protected] 2024-12-11 03:44:38 main 351a2b30
  │  all the stuff
  ~
  $ jj split
  # interactively choose hunks to keep, splitting the rest into a new revision
  $ jj
  @  zpnpvvzl [email protected] 2025-09-01 12:41:47 5656f1c5
  │  debugging junk
  ○  snomlyny [email protected] 2025-09-01 12:41:44 1d17740b
  │  feature
  ◆  zxrulorx [email protected] 2024-12-11 03:44:38 main 351a2b30
  │  all the stuff
  ~


Because it’s not a distinct feature, it’s just another commit. Which means you can bring all of the usual tools for modifying commits to bear. My sibling has some details, but at the high level, that’s the idea.


staging isn't needed since everything including the working copy is a commit you can split, rebase, etc. without any checkin step. yes, it does make sense and yes, it works in practice - the uncommitted vs staged vs committed states are very git-specific and don't need to be special in any way. if you check in the wrong thing (note - your working copy is a commit, so by definition you can't not have wrong things checked in at times) you split it (stage and/or commit in git).


> Sounds very difficult to do this in jj.

Pretty easy. While inaccurate, it's useful to think of jj as two separate repositories. One is the "clean" one that has everything nice and neat. The other is a repository of all your (very) incremental changes.

You have to actively decide what goes in the "clean" one. jj automatically puts stuff in the messy one. Any time you actively commit something, you're committing to the clean one. So you decide what goes in there.

When you do a push, only the "clean" commits are pushed.




Consider applying for YC's Summer 2026 batch! Applications are open till May 4

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: