Command: git next, git prev - arxanas/git-branchless Wiki

Description

For convenience, git-branchless offers a pair of commands to navigate to the next or previous commit in a stack. They're shorthand for running git checkout with the commit ID.

These commits can be very useful for hands-on editing of the commit graph. For example, if you want to update the previous commit, you can run git prev, amend it, and run git restack to fix up its descendant commits.

Usage

git next will take you to the next child commit:

$ git next
branchless: running command: git checkout 869c6d3756249eb800e3990affffe6f927ab2605
Previous HEAD position was 91c0908 temp: move foo
branchless: processing 1 update: ref HEAD
HEAD is now at 869c6d3 temp: update foo
branchless: processing checkout
⋮
◇ 86bdeac0 45d (master) Revert "Update foo"
┃
◯ 91c09087 20d temp: move foo
┃
● 869c6d37 20d temp: update foo

And git prev will take you to the next parent commit:

$ git prev
branchless: running command: git checkout HEAD^
Previous HEAD position was 869c6d3 temp: update foo
branchless: processing 1 update: ref HEAD
HEAD is now at 91c0908 temp: move foo
branchless: processing checkout
⋮
◇ 86bdeac0 45d (master) Revert "Update foo"
┃
● 91c09087 20d temp: move foo
┃
◯ 869c6d37 20d temp: update foo

Specifying the commit

Moving by a number of commits

git next and git prev optionally take an argument indicating the number of commits to move:

$ git prev 2
branchless: running command: git checkout HEAD~2
Previous HEAD position was 869c6d3 temp: update foo
branchless: processing 1 update: ref HEAD
HEAD is now at 86bdeac Revert "Update foo"
branchless: processing checkout
⋮
◆ 86bdeac0 45d (master) Revert "Update foo"
┃
◯ 91c09087 20d temp: move foo
┃
◯ 869c6d37 20d temp: update foo

If the target commit is ambiguous (because there are multiple children or parents), then it will ask you to specify --oldest, --newest, or --interactive:

$ git next 2
Found multiple possible next commits to go to after traversing 1 children:
  • 869c6d37 temp: update foo (oldest)
  • 849bf336 temp: another commit (newest)
(Pass --oldest (-o), --newest (-n), or --interactive (-i) to select between ambiguous next commits)

$ git next 2 -n
branchless: running command: git checkout 849bf3368a5c9c53ff0f1235cc71d8b42b0700a9
Previous HEAD position was 86bdeac Revert "Update foo"
branchless: processing 1 update: ref HEAD
HEAD is now at 849bf33 temp: another commit
branchless: processing checkout
⋮
◇ 86bdeac0 45d (master) Revert "Update foo"
┃
◯ 91c09087 20d temp: move foo
┣━┓
┃ ◯ 869c6d37 20d temp: update foo
┃
● 849bf336 29s temp: another commit

Moving to the top or bottom of the stack

Sometimes it's convenient to go to either the first or last commit in a stack. You can pass -a/--all to do this:

$ git sl
⋮
◇ fcba6182 3m (master) Create foo
┃
● 9a80143b 3m Create foo
┃
◯ fa2971d7 3m (baz) Create baz
┃
◯ 2f8daf33 2m Create qux
┃
◯ 7a9883a8 2m (grault) Create grault
┃
◯ d1e3b720 2m Create xyzzy

$ git next -a
branchless: running command: git checkout d1e3b7200ecd2640db754dc52a7ae43e6d94f4ea
Previous HEAD position was 9a80143 Create foo
branchless: processing 1 update: ref HEAD
HEAD is now at d1e3b72 Create xyzzy
branchless: processing checkout
⋮
◇ fcba6182 4m (master) Create foo
┃
◯ 9a80143b 3m Create foo
┃
◯ fa2971d7 3m (baz) Create baz
┃
◯ 2f8daf33 2m Create qux
┃
◯ 7a9883a8 2m (grault) Create grault
┃
● d1e3b720 2m Create xyzzy

Notice that git prev --all will take you to the first commit in the stack, which will not be the main branch:

$ git prev -a
branchless: running command: git checkout 9a80143be0cb0a4f1d3207371f21e036e0014f60
Previous HEAD position was d1e3b72 Create xyzzy
branchless: processing 1 update: ref HEAD
HEAD is now at 9a80143 Create foo
branchless: processing checkout
⋮
◇ fcba6182 5m (master) Create foo
┃
● 9a80143b 4m Create foo
┃
◯ fa2971d7 4m (baz) Create baz
┃
◯ 2f8daf33 3m Create qux
┃
◯ 7a9883a8 3m (grault) Create grault
┃
◯ d1e3b720 3m Create xyzzy

Moving by branches

If you there are branches in your stack, you can move to the next or previous branch instead, by using the -b/--branch option:

$ git sl
⋮
◆ fcba6182 1m (master) Create foo
┃
◯ 9a80143b 1m Create foo
┃
◯ fa2971d7 1m (baz) Create baz
┃
◯ 2f8daf33 30s Create qux
┃
◯ 7a9883a8 18s (grault) Create grault
┃
◯ d1e3b720 5s Create xyzzy

$ git next -b
branchless: running command: git checkout baz
Switched to branch 'baz'
branchless: processing checkout
⋮
◇ fcba6182 2m (master) Create foo
┃
◯ 9a80143b 1m Create foo
┃
● fa2971d7 1m (baz) Create baz
┃
◯ 2f8daf33 45s Create qux
┃
◯ 7a9883a8 33s (grault) Create grault
┃
◯ d1e3b720 20s Create xyzzy

You can combine --branch with a number indicating the number of branches to move by:

$ git sl
⋮
◇ fcba6182 6m (master) Create foo
┃
● 9a80143b 5m Create foo
┃
◯ fa2971d7 5m (baz) Create baz
┃
◯ 2f8daf33 5m Create qux
┃
◯ 7a9883a8 4m (grault) Create grault
┃
◯ d1e3b720 4m Create xyzzy

$ git next -b 2
branchless: running command: git checkout grault
Previous HEAD position was 9a80143 Create foo
Switched to branch 'grault'
branchless: processing checkout
⋮
◇ fcba6182 6m (master) Create foo
┃
◯ 9a80143b 5m Create foo
┃
◯ fa2971d7 5m (baz) Create baz
┃
◯ 2f8daf33 5m Create qux
┃
● 7a9883a8 4m (grault) Create grault
┃
◯ d1e3b720 4m Create xyzzy

Or you can combine --branch with --all, to move to the first or last commit with a branch in the stack:

$ git sl
⋮
◇ fcba6182 15m (master) Create foo
┃
◯ 9a80143b 15m Create foo
┃
◯ fa2971d7 15m (baz) Create baz
┃
◯ 2f8daf33 14m Create qux
┃
◯ 7a9883a8 14m (grault) Create grault
┃
● d1e3b720 14m Create xyzzy

$ git prev -ab 
branchless: running command: git checkout baz
Previous HEAD position was d1e3b72 Create xyzzy
Switched to branch 'baz'
branchless: processing checkout
⋮
◇ fcba6182 15m (master) Create foo
┃
◯ 9a80143b 15m Create foo
┃
● fa2971d7 15m (baz) Create baz
┃
◯ 2f8daf33 14m Create qux
┃
◯ 7a9883a8 14m (grault) Create grault
┃
◯ d1e3b720 14m Create xyzzy

Amending a commit

One common use-case for git prev is to update a previous commit. You can use git commit --amend as normal:

$ git commit --amend -m 'new message'
branchless: processing 1 update: ref HEAD
branchless: processed commit: 85a1e3c2 new message
branchless: processing 1 rewritten commit
branchless: This operation abandoned 2 commits!
branchless: Consider running one of the following:
branchless:   - git restack: re-apply the abandoned commits/branches
branchless:     (this is most likely what you want to do)
branchless:   - git smartlog: assess the situation
branchless:   - git hide [<commit>...]: hide the commits from the smartlog
branchless:   - git undo: undo the operation
branchless:   - git config branchless.restack.warnAbandoned false: suppress this message
[detached HEAD 85a1e3c] new message
 Author: Waleed Khan <[email protected]>
 Date: Sat Sep 4 01:35:39 2021 -0500
 1 file changed, 0 insertions(+), 0 deletions(-)
 rename foo => bar (100%)

When you amend a commit, it abandons any descendant commits:

$ git sl
⋮
◇ 86bdeac0 45d (master) Revert "Update foo"
┣━┓
┃ ✕ 91c09087 20d (rewritten as 85a1e3c2) temp: move foo
┃ ┣━┓
┃ ┃ ◯ 869c6d37 20d temp: update foo
┃ ┃
┃ ◯ 849bf336 6m temp: another commit
┃
● 85a1e3c2 5m new message

To fix this up, run git restack afterwards:

$ git restack
Attempting rebase in-memory...
[1/2] Committed as: 67687b48 temp: update foo
[2/2] Committed as: 814b2b05 temp: another commit
branchless: processing 2 rewritten commits
In-memory rebase succeeded.
Finished restacking commits.
No abandoned branches to restack.
branchless: running command: git checkout 8d4738cdd4eab974040b93d8ff9bdb1798ad50b4
branchless: processing 1 update: ref HEAD
HEAD is now at 8d4738c new message
args are: 8d4738cdd4eab974040b93d8ff9bdb1798ad50b4 8d4738cdd4eab974040b93d8ff9bdb1798ad50b4 1
branchless: processing checkout
⋮
◇ 86bdeac0 45d (master) Revert "Update foo"
┃
● 8d4738cd 8s new message
┣━┓
┃ ◯ 814b2b05 0s temp: another commit
┃
◯ 67687b48 0s temp: update foo