Back to list
cowwoc

git-squash

by cowwoc

AI Agents that land on their feet

2🍴 0📅 Jan 25, 2026

SKILL.md


name: git-squash description: Safely squash multiple commits into one with automatic backup and verification

Git Squash Skill

Purpose: Safely squash multiple commits into one with automatic backup, verification, and cleanup.

Safety Pattern: Backup-Verify-Cleanup

ALWAYS follow this pattern:

  1. Create timestamped backup branch
  2. Execute the squash
  3. Verify immediately - no changes lost or added
  4. Cleanup backup only after verification passes

Workflow Selection

CRITICAL: Choose workflow based on commit position.

# Check if commits are at tip of branch
LAST_COMMIT="<last-commit-to-squash>"
BRANCH_TIP=$(git rev-parse HEAD)

if [ "$(git rev-parse $LAST_COMMIT)" = "$BRANCH_TIP" ]; then
    echo "Commits at tip → Use Quick Workflow (soft reset)"
else
    echo "Commits in middle of history → Use Interactive Rebase Workflow"
fi

Quick Workflow (Commits at Branch Tip Only)

Use ONLY when squashing the most recent commits on a branch.

# 1. Verify commits are at tip
git log --oneline -1  # Should show <last-commit-to-squash>

# 2. Create backup
BACKUP="backup-before-squash-$(date +%Y%m%d-%H%M%S)"
git branch "$BACKUP"

# 3. Verify clean working directory
git status --porcelain  # Must be empty

# 4. Soft reset to base (parent of first commit to squash)
git reset --soft <base-commit>

# 5. Verify no changes lost
git diff --stat "$BACKUP"  # Must be empty

# 6. Create squashed commit (see git-commit skill for message guidance)
git commit -m "Unified message describing what code does"

# 7. Verify result
git diff "$BACKUP"  # Must be empty
git rev-list --count <base-commit>..HEAD  # Must be 1

# 8. Cleanup backup
git branch -D "$BACKUP"

Interactive Rebase Workflow (Commits in Middle of History)

Use when commits to squash have other commits after them.

# 1. Create backup of current branch
BACKUP="backup-before-squash-$(date +%Y%m%d-%H%M%S)"
git branch "$BACKUP"

# 2. Create sequence editor script
FIRST_COMMIT="<first-commit-to-squash>"  # Keep this one, squash others into it
COMMITS_TO_SQUASH="<second-commit> <third-commit> ..."  # These get squashed

cat > /tmp/squash-editor.sh << EOF
#!/bin/bash
$(for c in $COMMITS_TO_SQUASH; do echo "sed -i 's/^pick $c/squash $c/' \"\$1\""; done)
EOF
chmod +x /tmp/squash-editor.sh

# 3. Create commit message editor script
cat > /tmp/msg-editor.sh << 'EOF'
#!/bin/bash
cat > "$1" << 'MSG'
<your unified commit message here>
MSG
EOF
chmod +x /tmp/msg-editor.sh

# 4. Run interactive rebase
BASE_COMMIT="<parent-of-first-commit>"
GIT_SEQUENCE_EDITOR=/tmp/squash-editor.sh EDITOR=/tmp/msg-editor.sh git rebase -i $BASE_COMMIT

# 5. Verify no changes lost
git diff "$BACKUP"  # Must be empty

# 6. Cleanup
git branch -D "$BACKUP"
rm /tmp/squash-editor.sh /tmp/msg-editor.sh

Critical Rules

Use Correct Workflow for Commit Position

# WRONG - Using soft reset workflow for mid-history commits
git checkout <mid-history-commit>
git reset --soft <base>
git branch -f main HEAD  # LOSES all commits after the squash range!

# CORRECT - Use interactive rebase for mid-history commits
GIT_SEQUENCE_EDITOR=... git rebase -i <base>  # Preserves all commits

Position HEAD First (Quick Workflow Only)

# WRONG - HEAD beyond squash range
git reset --soft <base>  # Squashes ALL commits to current HEAD!

# CORRECT - Checkout last commit first
git checkout <last-commit>
git reset --soft <base>  # Squashes only intended range

Write Meaningful Commit Messages with Task ID

# WRONG - Concatenated messages, no Task ID
feature(auth): add login
feature(auth): add validation
bugfix(auth): fix typo

# CORRECT - Unified message with Task ID footer
feature: add login form with validation

- Email/password form with client-side validation
- Server-side validation with descriptive messages

Task ID: v2.1-implement-user-auth

MANDATORY: Include Task ID: v{major}.{minor}-{task-name} as the last line.

See git-commit skill for detailed message guidance.

Verify Immediately After Commit

# Check no changes lost
git diff "$BACKUP"  # Empty = success

# Check commit count
git rev-list --count <base>..HEAD  # Should be 1

Squash vs Fixup

CommandMessage BehaviorWhen to Use
squashCombines all messagesDifferent features being combined
fixupDiscards secondary messagesTrivial fixes (typos, forgotten files)

When in doubt, use squash - you can edit the combined message.

Non-Adjacent Commits

For commits separated by others, use interactive rebase:

git rebase -i <base-commit>

# In editor: Move commits to be adjacent, mark with 'squash'
# Example:
#   pick abc123 Target commit
#   squash def456 Commit to combine (MOVED here)
#   pick ghi789 Other commit (unchanged)

Error Recovery

# If anything goes wrong:
git reset --hard $BACKUP

# Or check reflog:
git reflog
git reset --hard HEAD@{N}

Success Criteria

  • Backup created before squash
  • HEAD positioned at correct last commit
  • No changes lost (diff with backup is empty)
  • Single commit created with all changes
  • Meaningful commit message (not "squashed commits")
  • Backup removed after verification

Score

Total Score

65/100

Based on repository quality metrics

SKILL.md

SKILL.mdファイルが含まれている

+20
LICENSE

ライセンスが設定されている

+10
説明文

100文字以上の説明がある

0/10
人気

GitHub Stars 100以上

0/15
最近の活動

1ヶ月以内に更新

+10
フォーク

10回以上フォークされている

0/5
Issue管理

オープンIssueが50未満

+5
言語

プログラミング言語が設定されている

+5
タグ

1つ以上のタグが設定されている

+5

Reviews

💬

Reviews coming soon