Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

gg split

Split a commit in the stack into two commits. The selected hunks become a new commit inserted before the original in the stack, while the remaining changes stay in the original commit.

gg split [OPTIONS] [FILES...]

Options

  • -c, --commit <TARGET>: Target commit — position (1-indexed), short SHA, or GG-ID. Defaults to the current commit (HEAD).
  • -m, --message <MESSAGE>: Commit message for the new (first) commit. Skips the editor prompt.
  • --no-edit: Keep the original message for the remainder commit without prompting.
  • --no-tui: Disable TUI, use sequential prompt instead (legacy git add -p style).
  • -f, --force (alias --ignore-immutable): Override the immutability guard. Splitting a merged or base-ancestor commit is refused by default. See Core concepts · Immutable commits.
  • FILES...: Files to include in the new commit. When provided, all hunks from those files are auto-selected (skips the interactive picker).

How It Works

When you split commit K into two:

  1. New commit (K’) — Contains only the selected hunks. Inserted before K in the stack. Gets a new GG-ID.
  2. Remainder (K’’) — Contains the remaining hunks. Stays in K’s original position. Keeps the original GG-ID (preserving PR association).

All descendant commits are automatically rebased onto the remainder.

BEFORE                    AFTER
  4: "Fix tests"            5: "Fix tests"       (rebased)
  3: "Add auth+logging"     4: "Add logging"      ← remainder (keeps GG-ID)
  2: "Setup DB"             3: "Add auth"         ← NEW commit (selected changes)
  1: "Init project"         2: "Setup DB"
                             1: "Init project"

Interactive Hunk Selection

Running gg split without file arguments opens the interactive hunk picker:

# Split the current commit — opens hunk selector
gg split

# Split a specific commit in the stack
gg split -c 3

TUI Mode (Default)

When run with a TTY, gg split opens a two-panel TUI for hunk selection:

┌── Files (1/3 width) ──┬── Diff (2/3 width) ──────────────┐
│ [✓] src/auth.rs (3)   │ @@ -10,6 +10,12 @@               │
│ [ ] src/logging.rs (1)│ +  // Validate token              │
│ [~] src/tests.rs (2)  │ +  if token.is_empty() {          │
│                        │ +      return false;               │
│                        │ +  }                               │
├────────────────────────┴────────────────────────────────────┤
│ 5/12 hunks selected │ [Space] toggle · [Tab] switch panel │
└─────────────────────────────────────────────────────────────┘

TUI Keyboard Shortcuts

KeyIn File PanelIn Diff Panel
↑/↓ or j/kNavigate filesNavigate hunks
SpaceToggle all hunks for fileToggle current hunk
aSelect all hunks (all files)Select all hunks (this file)
nDeselect all hunks (all files)Deselect all hunks (this file)
sSplit current hunk into sub-hunks
Tab / ← / →Switch to diff panelSwitch to file panel
EnterEnter commit messageEnter commit message
q / EscAbort (cancel split)Abort (cancel split)

Inline Commit Message

After pressing Enter to confirm your hunk selection, an inline text input appears at the bottom of the TUI for the commit message. It’s pre-filled with Split from: <original commit title>.

KeyAction
EnterConfirm message and create the split
EscGo back to hunk selection
← / →Move cursor
Home / EndJump to beginning/end
Backspace / DeleteDelete characters
Ctrl+A / Ctrl+EJump to beginning/end (emacs-style)
Ctrl+UClear from cursor to beginning
Ctrl+KClear from cursor to end

After confirming the new commit message, a second inline input appears for the remainder commit message (pre-filled with the original commit’s message). This replaces the external editor for both messages, keeping the entire split workflow inside the TUI.

KeyAction
EnterConfirm remainder message and complete the split
EscGo back to the new commit message input

The -m flag still works and bypasses the TUI input for the new commit. The --no-edit flag skips the remainder message input entirely, keeping the original message as-is.

File Panel Indicators

  • [✓] — All hunks selected (green)
  • [~] — Some hunks selected (yellow)
  • [ ] — No hunks selected

Sequential Prompt Mode (--no-tui)

Use --no-tui to fall back to the legacy git add -p style sequential prompt:

gg split --no-tui

This mode is automatically used when no TTY is available (e.g., in CI pipelines or when piping).

For each hunk, you’ll see the diff with colored output and a prompt:

--- a/src/auth.rs
+++ b/src/auth.rs
@@ -10,6 +10,12 @@ fn authenticate(user: &str) -> bool {
+    // Validate token
+    if token.is_empty() {
+        return false;
+    }

Include this hunk? [y]es/[n]o/[a]ll file/[d]one file/[s]plit/[q]uit/?help:

Sequential Mode Actions

KeyActionDescription
yYesInclude this hunk in the new commit
nNoSkip this hunk (stays in remainder)
aAll fileInclude all remaining hunks from this file
dDone fileSkip all remaining hunks from this file
sSplitSplit this hunk into smaller hunks
qQuitStop; all remaining hunks stay in remainder
?HelpShow this help

File-Based Splitting

When file arguments are provided, all hunks from those files are auto-selected without opening the interactive picker:

# Move auth files to a new commit before the current one
gg split -m "Add authentication" src/auth.rs src/auth_test.rs

# Split a specific commit with explicit files
gg split -c 3 src/config.rs

# Non-interactive with both messages
gg split -c 2 -m "Extract helpers" --no-edit helpers.rs utils.rs

# Split by GG-ID
gg split -c c-abc1234 src/config.rs

Hunk Splitting

If a hunk contains multiple logical changes separated by unchanged lines, pressing s will break it into smaller hunks. You can then select each sub-hunk individually. If the hunk is already atomic (contiguous changes), you’ll see “This hunk cannot be split further.”

Edge Cases

  • All changes selected — Warning: the original commit will be empty.
  • No changes selected — Error.
  • Dirty working directory — Error. Commit or stash changes first.
  • Merge conflicts during rebase — Split is aborted, original state restored.