Split a mixed working tree into clean commits
This is the playbook to memorize. You sat down meaning to fix a bug. Three hours later, the working tree contains: the actual bug fix, a typo you fixed in passing, a debug log you added and forgot to remove, an unrelated config tweak, and a refactor of one helper that "while I was here" felt obvious. Pushing that as one commit is sloppy and pollutes history. The job is to split the result into clean, separate commits without losing any change.
The procedure. 1. git status -sb to see what is in front of you. 2. git diff to actually read every modified line and decide which logical group it belongs to (bug fix vs typo vs refactor). 3. git stash push -k to set the unstaged work aside while you commit the staged piece — or skip stashing and go straight to git add -p, picking only the hunks that belong to the first concern. 4. git commit with a focused message. 5. Repeat for the next concern: git add -p, commit. 6. When the working tree is clean, run git log --oneline -p -n 5 and read the result — three or four commits should each tell one coherent story.
If something goes wrong mid-split — you accidentally staged the wrong hunk and committed it — you have options. git reset --soft HEAD~1 undoes the commit while keeping the changes staged. From there, git restore --staged --worktree on specific files lets you reset state and start over. Nothing destructive happens until you discard or push.
The discipline that prevents the situation: never sit down to "make changes" without a clear sentence saying which change you are making. "I am fixing the empty-search bug" is a good intent. "I will work on the code" is how you end up with the mixed tree. When something incidental needs to happen — refactor, typo — note it on a TODO list and address it in a separate, deliberate commit afterwards. Discipline is cheaper than splitting later.