Clean commit history in GIT - it's simple!

12 marca 2025
git

A properly maintained repository history helps you understand the progress of changes and problem-solving methods used by other programmers in the project. For many of us, a clean git history sounds just as abstract as 100% test coverage. Who hasn't encountered a repository where the history after running git log looks like this:

The image is terrible. I have a simple method that will help you avoid such a mess.

Judging by the above image, the programmer added a form to the view. They committed this change.

Then:

  • Fixed a typo in the button name. Made a commit.
  • Fixed a typo in the placeholder in the title field. Made a commit.
  • Added a span to the view to display the entire object value. Made a commit.
  • Added one more field to the form. Made a commit.
  • Changed the type of the added field. Made a commit.
  • Removed empty lines. Made a commit.
  • Fixed a typo. Made a commit.
  • Removed an unnecessary span. Made a commit.
  • In the above implementation, there were several unexpected changes, like fixing typos, logging some helper values to the view, and formatting code. We can also conclude that adding another field resulted from overlooking something when transferring business requirements to code.

    All these changes should logically be included in the scope of the first commit: "Add task form to the task edit partial." Instead, we have a totally messed up history that doesn't tell us anything, except perhaps about the sloppiness of the author of such code.

    git commit --amend

    To avoid such a mess, Git gives us the commit --amend command. After fixing a typo, just index the changes with git add --all, and then add these changes to the previous commit using git commit --amend. The default editor for commit messages will open, where you also have the option to change the content of the previous commit message.

    With a larger number of such command changes, having to open and close the editor each time (if it's VIM, many might have problems) can simply be annoying.

    That's why we have something like:

    git commit --amend --no-edit

    Add changes: git add --all, and then git commit --amend --no-edit. That's it. Changes added to the previous commit. The editor doesn't open because the --no-edit flag doesn't allow editing the commit message.

    Changing History

    You need to remember that git commit --amend and git commit --amend --no-edit overwrite the previous commit, changing its SHA identifier. What are the consequences? Well, if this commit has already been sent to the repo, when doing git push we'll get slapped with a message that the history is different and we need to pull changes from the repo first. Even though the commit message is the same, these commits are different, and git treats them as two separate changes.

    To push new changes to the repository, you must execute a command that you were forbidden to use long ago: git push --force. Let he who has never pushed with force and overwritten changes, then chomped on his keyboard with nerves, cast the first stone. In such a situation, there's a risk that by pushing changes to the repo, we might overwrite some commits that we don't have locally, e.g., work pushed by someone from our team.

    git push --force-with-lease

    Therefore, I recommend forgetting forever that there's something like git push --force, and always using git push --force-with-lease.

    Here's the difference between them:

  • force overwrites the branch in the repository with changes from our local branch.
  • -force-with-lease is a safer option that doesn't overwrite any changes on the remote branch if new commits have been added there (by another team member or contributor). It ensures you won't overwrite someone else's work with a force push.
  • Remember!

    Always use git push --force-with-lease.

    Aliases

    Typing all these commands can be cumbersome, and doing so in a hurry can be a source of frustration due to easily made typos. My solution to this problem is aliases or shortcuts added to the shell.

    I have entries ready for you to copy to .gitconfig

    Next we call

    git aa – for git add --all

    git cam – for git commit --amend

    git came – for git commit --amend --no-edit

    git puf – for git push --force-with-lease

    Bonus!

    If you don't know it yet, you definitely need to check out fish shell. https://fishshell.com/

    It has a very simple mechanism for adding shortcuts to the shell. I absolutely love fish. I most frequently use shortcuts set up in it. For the commands above, I've added my own:

    You don't have to write the git prefix :)

    It’s enough:

    gaa – for git add --all

    gam – for git commit --amend

    game – for git commit --amend --no-edit

    gpuf – for git push --force-with-lease

    Say goodbye to cluttered history! Clean commit history in Git - it's so simple!