-
Notifications
You must be signed in to change notification settings - Fork 1
split-commits: Add skill for non-interactive commit splitting #5
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Draft
cgwalters
wants to merge
3
commits into
bootc-dev:main
Choose a base branch
from
cgwalters:split-commits
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| __pycache__/ | ||
| *.pyc |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| # Basic development workflows | ||
| # Run `just --list` to see available targets. | ||
|
|
||
| # Python scripts to check | ||
| python_scripts := "diff-quiz/scripts/quiztool perform-forge-review/scripts/reviewtool split-commits/scripts/git-split-commits" | ||
|
|
||
| # Run basic syntax checks on all scripts | ||
| check: | ||
| #!/bin/bash | ||
| set -euo pipefail | ||
| echo "Checking Python syntax..." | ||
| for script in {{python_scripts}}; do | ||
| python3 -m py_compile "$script" && echo " ✓ $script" | ||
| done | ||
| echo "All checks passed." |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,177 @@ | ||
| --- | ||
| name: split-commits | ||
| description: Split mixed working tree changes into clean, logical commits. Use when you have intermixed changes (features, bugfixes, refactoring) that should be separate commits. | ||
| --- | ||
|
|
||
| # Split Commits | ||
|
|
||
| Non-interactive tool for splitting working tree changes into multiple clean | ||
| commits. Designed for AI agents that don't have TTY access for `git add -i`. | ||
|
|
||
| ## Problem | ||
|
|
||
| When working on code, changes for different concerns (features, bugfixes, | ||
| refactoring) often get intermixed. Creating clean, logical commits requires | ||
| splitting these changes, but the standard tools (`git add -i`, `git add -p`) | ||
| are interactive and require a TTY. | ||
|
|
||
| ## Prerequisites | ||
|
|
||
| - Python 3.10+ | ||
| - `jq` (optional, for parsing JSON output) | ||
|
|
||
| ## Workflow | ||
|
|
||
| Use `scripts/git-split-commits` for all operations. | ||
|
|
||
| ### 1. Identify the topics | ||
|
|
||
| Before starting, identify the logical groupings for your changes. Common patterns: | ||
| - `feature`, `bugfix`, `refactor` | ||
| - `api`, `models`, `tests` | ||
| - `feat-X`, `feat-Y`, `cleanup` | ||
|
|
||
| ### 2. Prepare the session | ||
|
|
||
| ```bash | ||
| scripts/git-split-commits prepare "bugfix" "refactor" "feature" | ||
| ``` | ||
|
|
||
| Output (JSON): | ||
| ```json | ||
| { | ||
| "status": "prepared", | ||
| "topics": ["bugfix", "refactor", "feature"], | ||
| "total_hunks": 6, | ||
| "files": ["api.py", "models.py", "utils.py"] | ||
| } | ||
| ``` | ||
|
|
||
| ### 3. Review hunks | ||
|
|
||
| View the session status: | ||
| ```bash | ||
| scripts/git-split-commits status | ||
| ``` | ||
|
|
||
| View the next unassigned hunk: | ||
| ```bash | ||
| scripts/git-split-commits next | ||
| ``` | ||
|
|
||
| The output includes: | ||
| - `id`: The hunk identifier | ||
| - `file`: Which file this hunk is in | ||
| - `old_start`/`new_start`: Line numbers | ||
| - `first_context`: First context line (for identification) | ||
| - `first_change`: First changed line (shows what's being modified) | ||
| - `patch`: The full unified diff for this hunk | ||
|
|
||
| ### 4. Assign hunks to topics | ||
|
|
||
| ```bash | ||
| scripts/git-split-commits assign 0 bugfix | ||
| scripts/git-split-commits assign 1 refactor | ||
| scripts/git-split-commits assign 2 feature | ||
| # ... repeat for all hunks | ||
| ``` | ||
|
|
||
| ### 5. Commit in order | ||
|
|
||
| Commit topics in logical order (usually: bugfixes first, then refactoring, | ||
| then features): | ||
|
|
||
| ```bash | ||
| scripts/git-split-commits commit bugfix "fix: Handle edge case in validation" | ||
| scripts/git-split-commits commit refactor "refactor: Rename variables for clarity" | ||
| scripts/git-split-commits commit feature "feat: Add new API endpoint" | ||
| ``` | ||
|
|
||
| ### 6. Verify | ||
|
|
||
| ```bash | ||
| git log --oneline -5 | ||
| ``` | ||
|
|
||
| ## Key Concepts | ||
|
|
||
| ### Hunk Identification | ||
|
|
||
| Each hunk is identified by: | ||
| - **ID**: A stable numeric identifier within the session | ||
| - **Line numbers**: `old_start` (original) and `new_start` (modified) | ||
| - **Fingerprints**: `first_context` and `first_change` for content verification | ||
|
|
||
| ### Staleness Detection | ||
|
|
||
| The tool validates that files haven't been modified externally: | ||
| - **Blob hash check**: Compares git blob hashes | ||
| - **Line content check**: Verifies context lines still match | ||
|
|
||
| If validation fails, you'll need to `reset` and `prepare` again. | ||
|
|
||
| ### Patch Application | ||
|
|
||
| Patches are applied using `git apply --cached`, with `--3way` fallback for | ||
| context conflicts. This handles the case where committing topic A shifts line | ||
| numbers for topic B's patches. | ||
|
|
||
| ## Commands Reference | ||
|
|
||
| | Command | Description | | ||
| |---------|-------------| | ||
| | `prepare TOPIC...` | Initialize session with topic names | | ||
| | `status` | Show all hunks and topic counts (JSON) | | ||
| | `next [ID]` | Show next unassigned hunk, or specific hunk | | ||
| | `assign ID TOPIC` | Assign a hunk to a topic | | ||
| | `stage TOPIC` | Stage all hunks for a topic (without committing) | | ||
| | `commit TOPIC "msg"` | Stage and commit a topic | | ||
| | `reset` | Clear the session | | ||
|
|
||
| ## Tips for AI Agents | ||
|
|
||
| 1. **Parse JSON output** for programmatic decisions: | ||
| ```bash | ||
| scripts/git-split-commits status | jq '.topic_counts' | ||
| ``` | ||
|
|
||
| 2. **Use fingerprints** to understand hunks without reading full patches: | ||
| ```bash | ||
| scripts/git-split-commits status | jq '.hunks[] | {id, file, first_change}' | ||
| ``` | ||
|
|
||
| 3. **Commit order matters**: Commit independent changes first, dependent | ||
| changes last. | ||
|
|
||
| 4. **When in doubt, refactor first**: Clean code is easier to add features to. | ||
|
|
||
| ## Example Session | ||
|
|
||
| ```bash | ||
| # Mixed changes in working tree | ||
| $ git diff --stat | ||
| src/api.rs | 25 +++++++++++++++++++------ | ||
| src/utils.rs | 15 +++++++++------ | ||
| 2 files changed, 28 insertions(+), 12 deletions(-) | ||
|
|
||
| # Prepare session | ||
| $ scripts/git-split-commits prepare "fix" "feat" | ||
| {"status": "prepared", "topics": ["fix", "feat"], "total_hunks": 3, ...} | ||
|
|
||
| # Review and assign | ||
| $ scripts/git-split-commits next | jq '{id, file, first_change}' | ||
| {"id": 0, "file": "src/api.rs", "first_change": "+ // Handle null case"} | ||
|
|
||
| $ scripts/git-split-commits assign 0 fix | ||
| $ scripts/git-split-commits assign 1 feat | ||
| $ scripts/git-split-commits assign 2 fix | ||
|
|
||
| # Create clean commits | ||
| $ scripts/git-split-commits commit fix "fix: Handle null pointer edge cases" | ||
| $ scripts/git-split-commits commit feat "feat: Add batch processing endpoint" | ||
|
|
||
| # Verify | ||
| $ git log --oneline -2 | ||
| abc1234 feat: Add batch processing endpoint | ||
| def5678 fix: Handle null pointer edge cases | ||
| ``` |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is a typo in the word "intentially". It should be "intentionally".