Cuando uno trabaja en una rama de desarrollo con git, es bastante habitual que haya que cambiar multitud de detalles hasta que se mezcla en la rama principal. A veces lo que estás desarrollando incluye varios commits lógicos, pero se acaban diluyendo entre multitud de "quitar basura", "wip", "typo", "PR review", etc.

Para que luego se quede el historial limpio, normalmente se hará un rebase manual, pero en tales circunstancias es un rollo.

Para evitar tener que hacer estas cosas, podemos hacer cualquiera de estos 2 comandos:

$ git commit --all --fixup $COMMIT
$ git commit --all --squash $COMMIT

El primero marcará el nuevo commit como para desaparecer y mezclarse con $COMMIT (ante las dudas, COMMIT=HEAD). El segundo hará lo mismo, pero en modo squash, es decir que mezclará no solo el código que ha cambiado sino el mensaje del commit (salvo la primera línea).

Cuando haya que hacer el squash final:

$ git rebase -i --autosquash

Y los commits que hayas marcado previamente te aparecerán en orden y ya premarcados con la acción correspondiente.

También puedes hacer este comportamiento el por defecto de rebase:

$ git config --global rebase.autoSquash true