@@ -298,14 +298,185 @@ jj config set --user git.private-commits "'''description(glob:'private:*')'''"
298298
299299### I accidentally changed files in the wrong commit, how do I move the recent changes into another commit?
300300
301- Use ` jj evolog -p ` to see how your working-copy commit has evolved. Find the
302- commit you want to restore the contents to. Let's say the current commit (with
303- the changes intended for a new commit) are in commit X and the state you wanted
304- is in commit Y. Note the commit id (normally in blue at the end of the line in
305- the log output) of each of them. Now use ` jj new ` to create a new working-copy
306- commit, then run ` jj restore --from Y --into @- ` to restore the parent commit
307- to the old state, and ` jj restore --from X ` to restore the new working-copy
308- commit to the new state.
301+ Let's say we are editing a commit for "featureA", and we forgot to run `jj
302+ new` or ` jj commit` before doing some work that belongs in a new commit:
303+
304+ ``` console
305+ $ jj log
306+ @ lnvvtrzo [email protected] 2025-02-28 21:01:10 31a347e0 307+ │ featureA
308+ ◆ zzzzzzzz root() 00000000
309+ $ cat file # Oh no, the work on "feature B" should be in a separate commit!
310+ Done with feature A
311+ Working on feature B
312+ ```
313+
314+ #### Step 1: Find the commit id for the "last good version"
315+
316+ <!-- TODO: Reorganize the two related questions, this one and
317+ -- the one linked below
318+ -->
319+ You can find [ all the past versions of the working copy revision that ` jj ` has
320+ saved] ( #jj-is-said-to-record-the-working-copy-after-jj-log-and-every-other-command-where-can-i-see-these-automatic-saves )
321+ by running ` jj evolog ` . The obsolete versions will be marked as "hidden" and
322+ will have the same change id, but will have different commit ids. This
323+ represents different [ commits] that are all parts of the same [ change] .
324+
325+ For example, this is what the evolog might look like after you made two edits to
326+ the same change:
327+
328+ ``` console
329+ $ # Note the word "hidden", the commit ids on the right,
330+ $ # and the unchanging change id on the left.
331+ $ jj evolog
332+ @ lnvvtrzo [email protected] 2025-02-28 21:01:10 31a347e0 333+ │ featureA
334+ ○ lnvvtrzo hidden [email protected] 2025-02-28 21:00:51 b8004ab8 335+ │ featureA
336+ ○ lnvvtrzo hidden [email protected] 2025-02-28 20:50:05 e4d831d 337+ (no description set)
338+ ```
339+
340+ Since commit ` b800 ` is hidden, it is considered obsolete and ` jj log ` (without
341+ arguments) will not show it, nor can it be accessed by its change id. However,
342+ most ` jj ` operations work normally on such commits if you refer to them by their
343+ commit id.
344+
345+ To find out which of these versions is the last time before we started working
346+ on feature B (the point where we should have created a new change, but failed
347+ to do so), we can look at the actual changes between the ` evolog ` commits by
348+ running ` jj evolog -p ` :
349+
350+ ``` console
351+ $ # When was the last saved point before we started working on feature B?
352+ $ jj evolog -p --git # We use `--git` to make diffs clear without colors
353+ @ lnvvtrzo [email protected] 2025-02-28 21:01:10 31a347e0 354+ │ featureA
355+ │ diff --git a/file b/file
356+ │ index 2b455c4207..2a7e05a01a 100644
357+ │ --- a/file
358+ │ +++ b/file
359+ │ @@ -1,1 +1,2 @@
360+ │ Done with feature A
361+ │ +Working on feature B
362+ ○ lnvvtrzo hidden [email protected] 2025-02-28 21:00:51 b8004ab8 363+ │ featureA
364+ │ diff --git a/file b/file
365+ │ index cb61245109..2b455c4207
366+ │ --- a/file
367+ │ +++ b/file
368+ │ @@ -1,1 +1,1 @@
369+ │ -Working on feature A
370+ │ +Done with feature A
371+ ○ lnvvtrzo hidden [email protected] 2025-02-28 20:50:05 e4d831d 372+ (no description set)
373+ diff --git a/file b/file
374+ index 0000000000..cb61245109
375+ --- /dev/null
376+ +++ b/file
377+ @@ 0,0 +1,1 @@
378+ +Working on feature A
379+ ```
380+
381+ In this example, the version of the change when we were actually done with
382+ feature A is when we edited the file to say "Done with feature A". This state
383+ was saved in the commit with id ` b80 ` (the second one in the list). The
384+ following edit (commit ` 31a ` ) belongs in a new change.
385+
386+ #### Step 2: Create a new change for the current state and restore the existing change to the older state
387+
388+ The "featureA" change is currently at commit ` 31a ` :
389+
390+ ``` console
391+ $ jj log
392+ @ lnvvtrzo [email protected] 2025-02-28 21:01:10 31a347e0 393+ │ featureA
394+ ◆ zzzzzzzz root() 00000000
395+ ```
396+
397+ We'd like to create a new "featureB" change with the contents of the current
398+ commit ` 31a ` , and we'd like the "featureA" change to be reverted to its former
399+ state at commit ` b80 ` (see step 1 above for how we found that commit id).
400+
401+ First, we create a new empty child commit. Since it is empty, it has the same
402+ contents as ` 31a ` .
403+
404+ ``` console
405+ $ jj new -m " featureB"
406+ Working copy now at: pvnrkl 47171aa (empty) featureB
407+ Parent commit : lnvvtr 31a347e featureA
408+ $ cat file
409+ Done with feature A
410+ Working on feature B
411+ ```
412+
413+ Now, we ` jj restore ` the change ` lnvvtr ` to its state at commit ` b80 ` . We use
414+ the ` --restore-descendants ` flag so that the * file contents* (AKA snapshot) of
415+ the "featureB" change is preserved.
416+
417+ ``` console
418+ $ # We refer to `lnvvtr` as `@-` for brevity
419+ $ jj restore --from b80 --into @- --restore-descendants
420+ Created lnvvtr 599994e featureA
421+ Rebased 1 descendant commits (while preserving their content)
422+ Working copy now at: pvnrkl 468104c featureB
423+ Parent commit : lnvvtr 599994e featureA
424+ ```
425+
426+ Even though ` @- ` was modified, ` --restore-descendants ` preserved the contents of
427+ the current change:
428+
429+ ``` console
430+ $ jj file show -r @ file # Same as `cat file`
431+ Done with feature A
432+ Working on feature B
433+ $ jj file show -r @- file
434+ Done with feature A
435+ ```
436+
437+ ??? info "More details on what ` --restore-descendants ` does"
438+
439+ When we ran the `jj restore` command, the working copy change `@` was
440+ at commit `471` and `@` was the only child of `@-`. In this situation,
441+
442+ ```shell
443+ jj restore --from b80 --into @- --restore-descendants
444+ ```
445+
446+ is equivalent to
447+
448+ ```shell
449+ jj restore --from b80 --into @-
450+ jj restore --from 471 --into @
451+ ```
452+
453+ Now, we have achieved the exact state we desired:
454+
455+ ```
456+ $ jj log -p --git
457+ @ pvnrklkn [email protected] 2025-02-28 21:39:29 468104c2 458+ │ featureB
459+ │ diff --git a/file b/file
460+ │ index 2b455c4207..2a7e05a01a 100644
461+ │ --- a/file
462+ │ +++ b/file
463+ │ @@ -1,1 +1,2 @@
464+ │ Done with feature A
465+ │ +Working on feature B
466+ ○ lnvvtrzo [email protected] 2025-02-28 21:39:29 599994ee 467+ │ featureA
468+ │ diff --git a/file b/file
469+ │ new file mode 100644
470+ │ index 0000000000..2b455c4207
471+ │ --- /dev/null
472+ │ +++ b/file
473+ │ @@ -0,0 +1,1 @@
474+ │ +Done with feature A
475+ ◆ zzzzzzzz root() 00000000
476+ $ jj diff --from b80 --to @- # No output means these are identical
477+ $ jj diff --from 31a --to @ # No output means these are identical
478+ ```
479+
309480
310481### How do I resume working on an existing change?
311482
@@ -392,9 +563,11 @@ detect custom backends and more).
392563
393564[ bookmarks_conflicts ] : bookmarks.md#conflicts
394565
566+ [ change ] : glossary.md#change
395567[ change ID ] : glossary.md#change-id
396568[ co-located ] : glossary.md#co-located-repos
397569[ commit ID ] : glossary.md#commit-id
570+ [ commits ] : glossary.md#commit
398571[ config ] : config.md
399572
400573[ gerrit-integration ] : https://gist.github.com/thoughtpolice/8f2fd36ae17cd11b8e7bd93a70e31ad6
0 commit comments