
Clean commit history in GIT - it's simple!
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:
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!