agentsclimarketplace

Commits squash

Skill neumie/almanac/skills/git/commits-squash

Personal agent toolkit — curated skills for LLM coding agents

Install
npx -y skills add neumie/almanac --skill commits-squash

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Use when squashing commits on the current branch into fewer logical commits. Triggers: squash, clean up commits, combine commits, tidy history before push or PR.

SKILL.md

8.7 KB, ~2.1k tokens by cl100k_base, as published. Nobody here has run it

Commits Squash

Squash commits on the current branch into fewer, logically grouped commits. Each resulting commit must be independently revertable — reverting any single commit leaves the codebase in a working state.

The Revertability Rule

Every resulting commit must satisfy: git revert <sha> produces a working codebase. This means:

  • A commit that adds a function AND its call site must include both — never split them
  • A commit that changes an interface must update all callers in the same commit
  • A commit that adds a dependency must include the code using it
  • Test changes go with the code they test

Group by code dependency, not just by topic or file proximity. Read the actual diffs to trace what depends on what.

Critical: anchor on the merge-base, never on origin/<base>

If origin/<base> has moved forward since the branch was created, the branch is diverged. In that case:

  • git diff origin/<base>..HEAD shows main's new files as deletions in your branch — they were never on the branch, but they exist on main.
  • git reset --soft origin/<base> followed by a commit would commit those deletions, wiping out work that was merged into main while the branch existed.

Always compute the merge-base of the branch and origin/<base> first, and use that SHA as the anchor for the diff, log range, and soft-reset. The merge-base is the point where the branch actually started; squashing onto it preserves exactly the work your branch contributed and touches nothing else.

If you want the squashed branch to also be up-to-date with origin/<base>, that is a rebase, not a squash — run the rebase skill after squashing.

Phase 1 — Analyze

These commands run automatically when the skill loads — output replaces each line below:

  • PR base (if any): !gh pr view --json baseRefName -q '.baseRefName' 2>/dev/null || true
  • origin/main exists: !git rev-parse --verify origin/main 2>/dev/null && echo origin/main || true
  • origin/master exists: !git rev-parse --verify origin/master 2>/dev/null && echo origin/master || true
  • Working tree status: !git status
  • Branch commits: !git log "origin/$(gh pr view --json baseRefName -q '.baseRefName' 2>/dev/null || (git rev-parse --verify origin/main >/dev/null 2>&1 && echo main || echo master))..HEAD" --oneline 2>/dev/null || true
  • Divergence (ahead/behind base): !git fetch origin "$(gh pr view --json baseRefName -q '.baseRefName' 2>/dev/null || (git rev-parse --verify origin/main >/dev/null 2>&1 && echo main || echo master))" --quiet 2>/dev/null; git rev-list --left-right --count "origin/$(gh pr view --json baseRefName -q '.baseRefName' 2>/dev/null || (git rev-parse --verify origin/main >/dev/null 2>&1 && echo main || echo master))...HEAD" 2>/dev/null || true
  • Merge-base SHA: !git merge-base "origin/$(gh pr view --json baseRefName -q '.baseRefName' 2>/dev/null || (git rev-parse --verify origin/main >/dev/null 2>&1 && echo main || echo master))" HEAD 2>/dev/null || true

Step 1: Determine base and anchor

Pick <base> from the pre-run output:

  1. PR base if gh pr view returned one
  2. Otherwise main if it exists
  3. Otherwise master

Then set <anchor> to the Merge-base SHA from the pre-run output. Every command in the rest of the skill — diff, log range, reset — uses <anchor>, not origin/<base>. If the divergence line shows 0 on the left (base hasn't moved), <anchor> equals origin/<base> and behavior is unchanged; if it shows a non-zero left count, using <anchor> is what prevents data loss.

If Merge-base SHA is empty (no shared history), STOP and report — the branch is not based on <base> and squashing is unsafe.

Step 2: Check prerequisites

  • From git status output: if uncommitted changes exist, follow the commit skill first, then continue.
  • Check for in-progress rebase: .git/rebase-merge or .git/rebase-apply. If found, STOP and report.
  • From the commit list: if 0 or 1 commits, report "nothing to squash" and stop.

Step 3: Gather context

  • Read all commits with full diffs: git log <anchor>..HEAD --format='%H %s' --reverse then git show <sha> for each
  • Sanity-check scope: git diff --stat <anchor>..HEAD — this is the exact set of changes the squash must preserve. Compare it to your mental model of the branch; if files appear that you don't recognize as part of this branch's work, investigate before proceeding.
  • Map which files and symbols each commit touches
  • Trace dependencies: if commit A adds a function and commit B calls it, they're linked

Phase 2 — Plan groups

Analyze commits and decide which ones belong together based on code dependencies:

  1. Build a dependency graph — for each commit, identify what it introduces (new functions, exports, types, files) and what it consumes (calls, imports, references). Commits that produce/consume the same symbols are linked.
  2. Form groups — connected commits become one group. Also merge:
    • Fix-then-fix-again → one fix
    • WIP/checkpoint commits → fold into the feature they belong to
    • Tests → group with the code they test
  3. Verify each group is self-contained — mentally simulate: if this group's commit were reverted, would remaining commits still work? If not, the group boundary is wrong — merge the dependent groups.
  4. Order groups — if group B depends on group A, A must come first. Independent groups go in logical order (infrastructure before features, setup before usage).

If all commits are already logically clean and independently revertable, report "nothing to squash — commits already clean" and stop.

Phase 3 — Execute

Use the soft-reset pattern since interactive rebase is unavailable. Reset onto <anchor> (the merge-base SHA from Phase 1) — never onto origin/<base> directly, or you risk committing deletions of work that landed on the base while the branch existed.

Process groups from oldest to newest:

# Reset all commits to the merge-base anchor (NOT origin/<base>)
git reset --soft <anchor>

# Unstage everything
git reset HEAD .

# For each logical group, stage its files and commit:
git add <files-for-group-1>
git commit -m "type(scope): summary for group 1"

git add <files-for-group-2>
git commit -m "type(scope): summary for group 2"
# ... etc

If all commits collapse into a single group, the simpler pattern works:

git reset --soft <anchor>
git commit -m "type(scope): summary"

Commit message rules

  • Follow the commit skill format: <type>(<scope>): <summary>
  • Synthesize a message per group — don't concatenate originals
  • Keep first line under 72 characters
  • Add body with bullet points if the group combined 3+ commits
  • Preserve any Co-Authored-By trailers from original commits

Phase 4 — Verify

Step 1: Diff integrity

  • git diff --stat <anchor>..HEAD — must match the Phase 1 Step 3 sanity-check output exactly. If not, STOP — something was lost or extra was pulled in.
  • Also run git diff --stat origin/<base>...HEAD (three dots) as a cross-check — it should match too, since three-dot diff is also anchored on the merge-base.

Step 2: Revertability check

For each new commit, verify it's revertable by reading the diff and confirming:

  • No dangling references (calls to functions defined only in other new commits)
  • No orphaned definitions (code that only makes sense with another commit present)
  • Imports/exports are consistent within the commit

If a commit fails this check, go back and regroup.

Step 3: Report

  • git log <anchor>..HEAD --oneline — show new commit history
  • Report: "Squashed N commits into M"
  • If divergence was non-zero, also report: "Branch is still behind <base> by X commits — run rebase skill if you want to catch up."

Edge Cases

  • Single commit on branch: Nothing to squash. Report and stop.
  • No commits ahead of base: Nothing to squash. Report and stop.
  • Uncommitted changes: Commit first (via commit skill), then squash.
  • Already pushed: Warn that squashing will require force-push to update remote. Proceed — the push skill handles force-push safely.
  • Merge commits on branch: Warn that squash will flatten merge history. Proceed.
  • All commits already clean: Report and stop — don't squash for the sake of it.
  • Branch diverged from base (base moved forward): Handled by anchoring on the merge-base — do not mix in a rebase. If the user wants the branch caught up to <base>, hand off to the rebase skill after squashing.
  • No merge-base found: Branch has no shared history with <base>. STOP and report — likely the wrong base.

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.