Skip to content

Commit 2bcf038

Browse files
committed
FAQ: detailed example for the "accidentally changed files in the wrong commit" question
It was requested on Discord once. The result is almost a tutorial; we could consider actually moving it into the tutorial and providing a link in the FAQ. That could be done separately. The `jj` commands outputs are faked in a few, hopefully inconspicuous, ways. Hopefully, this is not distracting.
1 parent b0e9bdf commit 2bcf038

File tree

1 file changed

+181
-8
lines changed

1 file changed

+181
-8
lines changed

docs/FAQ.md

Lines changed: 181 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)