Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save adrianbooth-eng/4a7c7456bf7dbb29d6e82dc5b0b143c0 to your computer and use it in GitHub Desktop.

Select an option

Save adrianbooth-eng/4a7c7456bf7dbb29d6e82dc5b0b143c0 to your computer and use it in GitHub Desktop.
atomic_commit skill

Atomic Commits

Purpose

Transform a branch with messy commit history into atomic, logical commits that are easy to review. Each atomic commit should represent one coherent change that builds on the previous state.

When to Use

  • User mentions "atomic commits", "break down commits", "restructure commits"
  • User wants to "make commits easier to review" or "reorganize commit history"
  • User asks to "split up commits" or "rewrite git history"
  • User has a branch they want to clean up before creating a PR

Strategy

1. Analyze Current State

First, gather information about the branch. Detect the base branch (main or master) by running git rev-parse --verify main / master; if neither exists, ask the user before proceeding.

# List of commits on the current branch (not on base)
git log --oneline <base>..HEAD

# Detailed view of what changed
git log -p <base>..HEAD

# Full diff of all changes
git diff <base>...HEAD

2. Identify Logical Groupings

Look for natural boundaries:

  • By file/module: Changes to different files or modules
  • By concern: Refactoring vs. new features vs. bug fixes vs. tests
  • By dependency: Changes that depend on each other vs. independent changes
  • By type: Configuration, setup, implementation, tests, documentation

Typical atomic commit structure:

  1. Setup/infrastructure changes (dependencies, config)
  2. Core implementation (one feature at a time)
  3. Related tests for each feature
  4. Documentation updates
  5. Cleanup/refactoring

3. Create Interactive Rebase Plan

Use git rebase -i <base> to restructure. The strategy depends on current state:

If commits are already somewhat logical:

  • Reorder commits to group related changes
  • Squash related commits together
  • Split commits that do too much

If commits are messy (e.g., "WIP", "fix", "more changes"):

  • Squash all commits into one: git reset --soft <base> && git commit -m "WIP: all changes"
  • Then split that single commit into logical pieces (see step 4)

4. Split Large Commits

To split a commit into atomic pieces:

# Start interactive rebase
git rebase -i <base>

# Mark the commit to split with 'edit'
# When rebase pauses, reset to the previous commit
git reset HEAD^

# Stage and commit changes piece by piece
git add -p             # Interactively stage hunks
# or
git add specific/file.py
git commit -m "Clear, atomic commit message"

# Repeat until all changes are committed
git add .
git commit -m "Final piece"

# Continue the rebase
git rebase --continue

5. Craft Clear Commit Messages

Every atomic commit message must follow Conventional Commits format. This repo has a conventional-commit hook that will reject non-conforming messages, and PRs are squash-merged using the PR title — so consistent commit hygiene matters at both layers.

Format: <type>(<optional scope>): <imperative summary>

  • <type> is one of: feat, fix, refactor, perf, docs, test, chore, ci, build, style, revert
  • <scope> is optional and short (e.g. auth, coding-agents, rate-limit). Use it when it sharpens meaning; omit otherwise.
  • Summary is lowercase, imperative ("add", "fix", "drop" — not "added", "fixes"), no trailing period, ideally under 60 chars.
  • Add a ! after type/scope (e.g. feat(api)!: drop legacy /v1 endpoints) only for breaking changes.

Pick the type from the actual change, not from filenames alone:

  • feat: user-visible new capability
  • fix: bug fix
  • refactor: behaviour-preserving code change
  • perf: performance improvement
  • docs: docs only
  • test: tests only
  • chore: tooling, deps, housekeeping
  • ci: CI/CD config only
  • build: build system / external deps
  • style: formatting / whitespace only
  • revert: reverts a previous commit

Beyond the prefix, the message should:

  • Describe what and why, not how
  • Be understandable without seeing the code
  • Reference broader context in a body paragraph if needed (blank line after the summary)

Examples drawn from this repo:

  • feat: skills layer — lazy MCP fetch with nudge-based progressive disclosure
  • refactor(coding-agents): drop list_hooks/get_hook MCP tools
  • fix: project-key lookup against symbol-keyed content_paths
  • docs: skills layer + a decision guide for picking the right primitive

Avoid:

  • "Update code", "WIP", "more changes"
  • Past tense ("Added", "Fixed") — use imperative
  • Mixing types ("feat: add X and fix Y" — split into two commits)
  • Skipping the prefix on purpose — the hook will block the rebase

Implementation Workflow

# 1. Confirm the current branch
git branch --show-current

# 2. Analyze the current commits
git log --oneline <base>..HEAD
git diff --name-status <base>...HEAD

# 3. Propose a breakdown to the user (logical groupings)

# 4. Create the atomic structure
git rebase -i <base>
# or
git reset --soft <base>
git reset            # Unstage everything

# 5. Build commits one by one
# Use git add -p for fine-grained control
# or git add <specific files> for file-level commits

# 6. Verify the result
git log --oneline <base>..HEAD
git diff <base>...HEAD    # Should show the same total changes as before

Key Principles

What Makes a Good Atomic Commit

  1. Single Responsibility: Does one thing and does it completely
  2. Builds: Each commit should leave the codebase in a working state
  3. Tests Pass: All tests should pass after each commit
  4. Self-Contained: Can be understood and reviewed independently
  5. Logical Size: Not too big (overwhelming) or too small (trivial)

Common Anti-Patterns to Fix

  • "WIP", "temp", "fix" commits → Squash into meaningful commits
  • One giant commit → Split by concern/file/feature
  • Mixed concerns (feature + unrelated refactor) → Separate
  • Test and implementation in different commits → Group together
  • Commits that break the build → Reorder or squash

Reviewer-Friendly Order

Order commits so each builds on the previous:

  1. Dependencies/setup (if any)
  2. Core types/interfaces/models
  3. Implementation (one feature at a time)
  4. Tests (grouped with their feature or in a follow-up commit)
  5. Integration/wiring
  6. Documentation

This lets reviewers:

  • Review one concept at a time
  • Understand dependencies before seeing usage
  • Verify tests match implementation
  • Skip around without confusion

Safety Tips

  • Create a backup branch before starting: git branch backup-<branch-name>
  • Use git reflog if you need to undo a rebase
  • Verify the final diff matches the original: git diff <base>...HEAD should show the same total changes
  • Force push only with --force-with-lease, never --force
  • Never rebase commits that have been merged or that others are working on

Output

Guide the user through the restructuring process with:

  1. Analysis of current commits and changes
  2. Proposed atomic commit structure (wait for user confirmation before rewriting history)
  3. Step-by-step commands to execute
  4. Verification that the restructure preserves all changes
  5. Final commit messages for each atomic commit
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment