一键导入
undo-squash
Restore commits to their pre-squash state. Use when: squash grouping was wrong, need original commit history back, or want to try different grouping.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Restore commits to their pre-squash state. Use when: squash grouping was wrong, need original commit history back, or want to try different grouping.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Use before pushing a branch, opening a PR, updating an existing PR, or merging. Use when GitHub Codex review cycles feel unbounded, when AI-flagged findings include false positives, when the team is finding adjacent-file issues each push, or when a chunk of work feels finished and you're about to ask whether to push.
Use when fixing bugs, resolving issues, or addressing small improvements found in testing, user reports, or code audits
Use when any API project (Flask, FastAPI, Express, NestJS, Django, Go) needs YAML integration tests for go-runner, when test coverage is shallow or missing, or when generating CI/CD pipelines to deploy a temp instance and run those tests
Use when starting new work (feature or fix branch), or when commit message validation fails. Provides branch creation wizard and commit format reference.
Dispatch parallel reviewers to validate implementation against the plan. Use for post-implementation verification in a fresh session.
Internal skill — not invoked directly. Use /session-status, /session-persist, or /session-handoff instead.
| name | undo-squash |
| description | Restore commits to their pre-squash state. Use when: squash grouping was wrong, need original commit history back, or want to try different grouping. |
Restores the original commits from before the last squash operation. Works as long as backups exist (preserved until next /start-work or explicit cleanup).
Check in order of preference:
BRANCH=$(git branch --show-current)
SANITIZED_BRANCH=$(echo "$BRANCH" | sed 's#/#%2F#g') # percent-encode "/" (feat/x ≠ feat-x)
SESSION_DIR=".claude/sessions/${SANITIZED_BRANCH}"
if [ -f "$SESSION_DIR/last-squash.json" ]; then
BACKUP_TAG=$(jq -r .backupTag "$SESSION_DIR/last-squash.json")
ORIGINAL_HEAD=$(jq -r .originalHead "$SESSION_DIR/last-squash.json")
BUNDLE_PATH=$(jq -r .bundlePath "$SESSION_DIR/last-squash.json")
SQUASH_TIME=$(jq -r .squashedAt "$SESSION_DIR/last-squash.json")
echo "Found squash from: $SQUASH_TIME"
echo "Original HEAD: $ORIGINAL_HEAD"
fi
BACKUP_TAG=$(git tag -l "_squash-backup-*" | sort | tail -1)
if [ -n "$BACKUP_TAG" ]; then
echo "Found backup tag: $BACKUP_TAG"
fi
if [ -f "$SESSION_DIR/pre-squash.bundle" ]; then
echo "Found backup bundle"
fi
# If all else fails, check reflog
git reflog | grep -E "reset.*moving to" | head -5
echo "Manual recovery possible via reflog"
UPSTREAM=$(git rev-parse --abbrev-ref @{u} 2>/dev/null)
if [ -n "$UPSTREAM" ]; then
# Check if current HEAD matches remote
LOCAL_HEAD=$(git rev-parse HEAD)
REMOTE_HEAD=$(git rev-parse "$UPSTREAM" 2>/dev/null)
if [ "$LOCAL_HEAD" = "$REMOTE_HEAD" ]; then
echo "Warning: Squashed commits already pushed."
echo "Undo would require force push."
echo "Continue anyway? [y/n]"
# Only proceed if user explicitly confirms
fi
fi
if [ -n "$BACKUP_TAG" ] && git rev-parse "$BACKUP_TAG" >/dev/null 2>&1; then
echo "Restoring from backup tag: $BACKUP_TAG"
# Get the SHA before reset for confirmation
RESTORE_SHA=$(git rev-parse "$BACKUP_TAG")
COMMIT_COUNT=$(git log HEAD.."$BACKUP_TAG" --oneline | wc -l | tr -d " ")
echo "Will restore $COMMIT_COUNT commits"
echo "Target: $RESTORE_SHA"
git reset --hard "$BACKUP_TAG"
echo "Restored to: $(git log -1 --oneline)"
fi
if [ -f "$BUNDLE_PATH" ] && [ -n "$ORIGINAL_HEAD" ]; then
echo "Restoring from bundle..."
# Unbundle to make commits available
git bundle unbundle "$BUNDLE_PATH"
# Reset to original HEAD
git reset --hard "$ORIGINAL_HEAD"
echo "Restored to: $(git log -1 --oneline)"
fi
# Show reflog entries for user to choose
git reflog | head -20
echo "Enter the SHA or reflog entry to restore to:"
# User provides SHA like "HEAD@{2}" or "abc123"
# git reset --hard <user-provided-sha>
# Remove backup tag (used)
if [ -n "$BACKUP_TAG" ]; then
git tag -d "$BACKUP_TAG" 2>/dev/null
fi
# Remove backup files
rm -f "$SESSION_DIR/pre-squash.bundle"
rm -f "$SESSION_DIR/last-squash.json"
rm -f "$SESSION_DIR/squash-in-progress.json"
echo "Undo complete. Backup artifacts cleaned up."
Squash undone successfully!
Restored: 15 original commits
HEAD now at: abc123 "feat: original commit message"
Backup artifacts: cleaned up
You can now:
- Run /squash-commits again with different grouping
- Continue working and make more commits
- Push the original commits as-is
If no backup tag or bundle exists:
git reflog | head -20reset: moving to _session-start-*git reset --hard <sha>The tag might point to a garbage-collected commit:
ls -la $SESSION_DIR/*.bundlegit bundle unbundle <bundle>If you really need to undo after pushing:
/undo-squashgit push --force-with-lease