--- name: git-history-cleaner description: Cleans up git commit history by rebasing and combining commits that edit the same files or logical units, ensuring each logical change is isolated to a single commit. --- # Git History Cleaner This skill provides a procedural workflow and strategies for cleaning up git commit history. It details how to reorganize, reorder, and combine (squash or fixup) commits to achieve a clean history where each file, feature, or logical unit is introduced/modified in a single self-contained commit. ## Workflow 1. **Analyze Commit History**: - Identify the base commit (e.g., `origin/main`, `master`, or a specific hash where the branch diverged) and the current branch HEAD. - View the commit messages in reverse chronological order: `git log ..HEAD --oneline` - List files modified in each commit: `git log ..HEAD --name-status` 2. **Group Changes by Logical Units**: - Map files to their logical units (e.g., a specific module, script, library, or config). - Identify "fixup" commits (commits fixing errors or formatting in files that were introduced or modified in earlier commits on the branch). - Plan the squashing order: each logical unit or file set should be introduced in a single commit, incorporating all subsequent fixes to those same files. 3. **Rebase and Combine Commits**: - **Method A: Interactive Rebase (For straightforward rebases)**: - Run `git rebase -i `. - In the todo list, reorder commits so that any fixup/update commits are positioned immediately below the commit that originally introduced those changes. - Change the action of the fixup commits from `pick` to `fixup` (or `f`) to merge them into the parent commit without changing the original commit message, or `squash` (or `s`) to combine their commit messages. - **Method B: Programmatic Rebase Script (For complex histories or index files)**: - If commits frequently modify shared index files (e.g., JSON registries, lockfiles) that cause heavy conflicts during a standard interactive rebase, write a temporary helper script (Bash or Python) to rebuild the history. - Create a temporary branch starting at the base commit: `git checkout -b rebase-temp ` - For each planned clean commit: 1. Check out the final state of the relevant files from the target HEAD: `git checkout -- ` 2. If a shared index file needs to be built incrementally, extract the specific changes using command-line tools (such as `jq` for JSON files) and apply them. 3. Commit the staged changes, preserving the original author metadata and dates using environment variables: ```bash GIT_AUTHOR_DATE="" GIT_COMMITTER_DATE="" git commit -m "" ``` 4. Repeat for all logical units in the planned order. 4. **Verify the Rebased History**: - Verify that the file state at the new rebased HEAD is identical to the target HEAD: ```bash git diff HEAD ``` *The diff must be completely empty.* - Review the final commit history to ensure it contains exactly one logical commit per feature/file group: ```bash git log ..HEAD --oneline ``` 5. **Update Branch Pointer**: - Switch back to the main feature branch and hard-reset it to the rebased HEAD: ```bash git checkout git reset --hard rebase-temp git branch -D rebase-temp ```