Skip to content

Home

   ┌─────────────────┐
   │ git-stage-batch │
   └─────────────────┘

       o───o
      /
  o───o───o

 stage patches in batches
Writing code is messy.
Git history doesn't have to be.
During development we experiment, refactor, backtrack, and fix mistakes. If every step ends up as a commit, the history becomes noise. A curated history turns that process into a clear sequence of logical changes. Each commit captures one idea, and the message explains why it exists. This clarity assists contributors explore the codebase, maintainers review changes, and your future self try to understand how the system evolved.
git-stage-batch helps you build that history incrementally by letting you stage changes hunk-by-hunk or line-by-line, shaping commits around meaning instead of the order the edits happened.
Batch of patches - hacker preparing atomic commits

🎧 git-stage-batch featured on the Deep Dive podcast!

  • Command-Based Workflow


    Perfect for automation and AI coding assistants. Chain commands together for precise control.

    Quick Start

  • Line-Level Control


    Stage specific lines within a hunk for maximum granularity. Perfect for separating mixed changes.

    Commands Reference

  • Machine-Readable Output


    --porcelain flag for scripting. Integrate into your tools and workflows.

    See Examples

  • Interactive Mode


    Menu-driven hunk-by-hunk workflow inspired by git add -p. Review and stage changes in a continuous session.

    Interactive Mode

  • Named Batches


    Defer and label changes for later processing. Advanced patch-series organization for complex workflows.

    Batch Operations

See it in Action

git-stage-batch demo

Creating atomic commits: bug fix, validation feature, and build artifact exclusion

Why git-stage-batch?

Similar to git add -p but more granular and flexible:

  • Interactive mode - Continuous hunk-by-hunk workflow with menus
  • Command-based mode - Perfect for automation and AI assistants
  • Line-by-line staging - Stage specific lines within a hunk
  • State persistence - Resume staging across multiple invocations
  • Colored output - Clear visual distinction in your terminal
  • File operations - Stage/skip entire files at once
  • No dependencies - Pure Python standard library

Quick Start

Installation

❯ uv tool install git-stage-batch
❯ pipx install git-stage-batch
❯ pip install git-stage-batch
# Clone and build
❯ git clone https://github.com/halfline/git-stage-batch.git
❯ cd git-stage-batch
❯ meson setup build
❯ meson compile -C build

# Install to system
❯ sudo meson install -C build

Basic Usage

# Start reviewing hunks
❯ git-stage-batch start

# Include the selected hunk (stage it)
❯ git-stage-batch include
# Or use the short alias:
❯ git-stage-batch i

# Skip it for now
❯ git-stage-batch skip    # or: s

# Discard it (remove from working tree)
❯ git-stage-batch discard # or: d

# For fine-grained control, stage specific lines
❯ git-stage-batch include --line 1,3,5-7  # or: il 1,3,5-7
❯ git-stage-batch skip --line 2,4         # or: sl 2,4

# Replacement text must use one contiguous displayed line-ID span
❯ git-stage-batch include --line 1-2 --as 'replacement'

# Exact unchanged edge-overlap lines are stripped by default for line-scoped --as
❯ git-stage-batch include --line 1-2 --as 'keep1\nreplacement\nkeep4'

# Keep those edge-overlap lines literally with --no-edge-overlap
❯ git-stage-batch include --line 1-2 --as 'keep1\nreplacement\nkeep4' --no-edge-overlap

# Or stage full replacement text for one file-scoped path
❯ git-stage-batch include --file path.txt --as 'full staged file text'

# Or replace one file-scoped working-tree path without staging it
❯ git-stage-batch discard --file path.txt --as 'full working tree text'

# Or preserve exact stdin text, including trailing newlines
❯ git-stage-batch include --file path.txt --as-stdin < replacement.txt
❯ git-stage-batch discard --file path.txt --as-stdin < replacement.txt

# Check status
❯ git-stage-batch status  # or: st

# Start fresh after committing
❯ git-stage-batch again   # or: a

# Stop after one action instead of selecting the next hunk
❯ git-stage-batch include --no-auto-advance
❯ git-stage-batch show

# For advanced workflows, defer changes to named batches
❯ git-stage-batch include --to feature-work  # Save to batch for later

See batch operations for advanced patch-series organization. See commands reference for the --as contiguous-range rules.

AI Assistant Quick Start

For Claude Code, install the tool and the bundled commit skills in the repository where the assistant will work:

❯ python -m pipx install git-stage-batch
❯ git-stage-batch install-assets claude-skills --filter 'commit-*'

If you want the Claude assets to stay local, keep them out of reviews without changing the project .gitignore:

❯ git-stage-batch block-file --local-only .claude/

Then ask Claude Code to split and commit the current unstaged work:

❯ claude "/commit-unstaged-changes"

Omit --filter when installing Claude skills if you also want the larger /decompose-and-commit-unstaged-changes workflow. See the AI assistant guide for Codex setup and fuller assistant configuration.

Example Workflow

# You have changes in multiple files
❯ git status
modified:   auth.py
modified:   config.py

# Start staging process
❯ git-stage-batch start
auth.py :: @@ -10,5 +10,5 @@
[#1] - old_hash_function()
[#2] + new_hash_function()
      validate_user()

# Include this for first commit
❯ git-stage-batch i
config.py :: @@ -20,3 +20,4 @@
[#1] + DEBUG = True
      TIMEOUT = 30

# This debug flag shouldn't be committed, skip it
❯ git-stage-batch s
No pending hunks.

# Create first commit
❯ git commit -m "auth: Upgrade to new hash function"

# Go through skipped hunks for next commit
❯ git-stage-batch a
config.py :: @@ -20,3 +20,4 @@
[#1] + DEBUG = True
      TIMEOUT = 30

# Discard this debug line instead
❯ git-stage-batch d
No pending hunks.

# Working tree is now clean
❯ git status
nothing to commit, working tree clean

Important: Commit Early, Commit Often

git-stage-batch is designed for an incremental workflow:

  1. Stage hunks that belong in the selected logical commit (include)
  2. Create that commit (git commit)
  3. Continue with remaining hunks (again)
  4. Repeat

The again command shows you only the hunks you skipped - it doesn't re-show hunks you already included and committed.

Features

Hunk-by-Hunk Staging

Review and stage individual hunks one at a time. Each hunk shows changed lines with IDs for easy reference.

Line-by-Line Staging

Stage specific lines within a hunk:

❯ git-stage-batch include --line 1,3,5-7

Perfect for separating orthogonal changes that ended up in the same hunk.

Colored Output

Automatic color support with TTY detection:

  • 🟢 Green for additions
  • 🔴 Red for deletions
  • 🔵 Cyan for headers
  • ⚫ Gray line numbers for easy scanning

State Persistence

Track processed/skipped hunks across multiple command invocations. Resume where you left off.

Stale State Detection

Automatically detects and clears cached state when files are committed or modified externally. No more misleading status!

FAQ

Is this rewriting Git history?

Usually no.

git-stage-batch is intended for organizing draft patch sets before they are committed or shared. It helps you turn a messy working tree into a clean sequence of logical commits.

The normal workflow stages selected working-tree changes into new commits rather than rewriting existing commits. Assistant decomposition workflows may polish commits they have just created while rebuilding a local series, but that rewriting is limited to fresh draft history.

It is not meant to modify shared history or protected branches. Think of it as helping you prepare commits before they become part of reviewable project history, with any assistant-side polishing confined to local draft commits.

When should I use this?

Use it while preparing commits for a branch you are working on locally.

A typical workflow looks like:

edit code
edit more code
experiment
fix mistakes

Then run:

❯ git-stage-batch start

to turn those edits into a clean set of commits.

Once the commits are ready, you can push or open a pull request as usual.

Why not just use git add -p?

git add -p is great for staging individual changes, but it is designed for single-pass staging.

git-stage-batch is designed for multi-pass commit curation:

stage changes
make a commit
run again
stage the next logical change
repeat

This makes it easier to organize a large working tree into a series of clean commits.

How does this compare to Jujutsu and jj-hunk?

Jujutsu (jj) is a Git-compatible version control system with a different workflow model. It can use Git repositories and Git remotes, but it does not center the workflow on Git's index and staging area. Instead, it treats the working copy as a commit and provides commit-first tools for splitting, squashing, moving, and rewriting changes.

jj-hunk builds on that model by adding programmatic hunk selection for jj. It can list hunks and apply a JSON or YAML selection spec when splitting, committing, or squashing changes. That makes it especially useful for automation and AI agents in repositories where jj is already the chosen workflow.

The overlap is the goal: turning messy development into logical, reviewable commits. The niche is different:

  • git-stage-batch is for Git-native repositories and workflows. It works with Git's index, regular Git commits, and existing Git hosting without asking the project or contributor to adopt a new VCS workflow.
  • jj is a broader replacement workflow for people who want Jujutsu's commit model, operation log, automatic rebasing, and history-editing primitives.
  • jj-hunk is the hunk-selection layer for that jj workflow, especially when an agent or script needs to select hunks non-interactively.

If your project and collaborators use Git, git-stage-batch fills the automation-friendly gap between git add -p and larger history-rewrite tools. If your project already uses jj, jj-hunk may be the more natural tool for the same kind of commit curation.

Is this safe for protected branches?

Yes — because you should not use it there.

This tool is meant for local development branches before merging.

Once commits are pushed or merged into protected branches, standard Git practices apply and history should normally remain stable.

Is this similar to git rebase -i?

It solves a related problem but at a different stage.

  • git rebase -i reorganizes existing commits
  • git-stage-batch helps you create better commits in the first place

Many developers will still use rebase -i occasionally, but with curated commits it becomes much less necessary.

Why curate Git history at all?

Because Git history is read by people.

A raw commit log is a transcript of development: experiments, mistakes, and partial fixes.

A curated history is documentation of how the system evolved. It is far easier for contributors, reviewers, and your future self to understand.

When should I use batches?

Most workflows don't need batches. The core commands (include, skip, discard) handle typical staging scenarios.

Use batches when you need to: - Defer specific changes for a separate commit while continuing to process other hunks - Group related changes across multiple files for thematic organization - Temporarily set aside changes you're uncertain about

See the batch operations guide for detailed workflows and examples.

Next Steps