Are you tired of seeing vague and meaningless commit messages like:
fix: close pull request discussion
fix: fix review discussion
If you're nodding your head in agreement, it might be time to introduce the "git fixup" technique to your team's workflow, or even just adopt it for yourself.
If the concept seems complicated and overwhelming, don't worry – you're about to be pleasantly surprised. Git fixup is actually quite simple, especially if you're already comfortable with making commits. Let's jump right in! 🏊♂️
Imagine you've made several commits on your working branch and have submitted a merge or pull request. However, during the code review, issues were identified—whether by your peers or during your own self-review. Instead of creating separate commits to address these problems, you can simply use the git fixup command. Here's how:
- Identify the hash of the commit where the problem was found.
- Run the command💡:
git commit --fixup=<commit hash you want to fix>
This command will generate a new commit with the original commit's subject, prefixed with fixup!
. This additional commit might seem like a slight inconvenience, but even it is already far better than having vague commit messages cluttering your history.
But we're not done yet. The next step is to incorporate the fixup commit into the original commit using the following command:
git rebase --autosquash -i main
Here's what these parameters mean:
-
-i
: Interactive mode for the rebase. -
--autosquash
: A special flag that squashes fixup commits into their respective originals. -
main
: The branch from which your current branch originated.
!!! This is a rebasing command, and you should be aware that this command will change your Git History. So, do it only if you know how it works.
After executing this command, a text editor (VIM by default) will appear. Don't worry—there's no need to make changes. Simply close it by typing :q!
.
Congratulations! Your commit history is now clean and organized. You're ready to share your changes with your team. Just use either of these commands to push your changes, depending on your circumstances:
- if you work on the branch alone:
git push --force
💪 - if you share the branch with someone:
git push --force-with-lease
🤝
To summarize:
- Copy the hash of the commit you want to fix.
- Run
git commit --fixup=<commit hash>
. - Execute
git rebase --autosquash -i main
. - Check the open text editor and close it if everything looks good (
:q!
). - Use
git push --force
to publish your changes.
Top comments (12)
I'm sorry but I think this is a bit of a misleading advice, especially to juniors, unless you'll add a warning and caveats to the post.
Like others mentioned, I would not recommend this method unless you really know what you're doing and especially not in the scenario mentioned in the post (after someone already reviewed your PR once) because it will completely destroy the git history as the commit hashes change so GitHub can't connect the PR comments to their original location in the code and the PR comments are now "orphans" and confusing.
Instead, I'd personally recommend a fresh commit for fixing issues in a PR and when the time comes to land the PR to the main branch you can squash merge it in so the PR branches are "messy" and include lots of small meaningful commits while the main branch is clean and linear.
I will, however, definitely follow this advice in cases where you found issues with your code before you pushed it to the upstream branch. As a rule of thumb, if you'll need to force push the code I'd try to avoid this method unless you absolutely know what you're doing.
Thank you for sharing your thoughts and concerns. You've raised some important points that should definitely be considered when deciding how to manage your Git workflow, especially for juniors.
The suggestion of using fresh commits and squashing when merging is a sound practice, but it might not be the best fit for every project. Some teams prefer a more streamlined approach to maintain clarity in their commit history.
Ultimately, the decision should be based on a combination of factors, including project requirements, team consensus, and individual familiarity with Git practices. It's valuable to have a range of strategies in your Git toolkit to adapt to different situations.
There is no a silver bullet for each case, and it can lead to long discussion, with my article I wanted to add one more way how handled such cases.
Thank you again. I will consider to add a disclaimer in the article based on your comment
if you have any questions, feel free to ask, I will glad to help you with optimising your workflow
Been using this since 2018 when another dev showed. A good tip is to use git config so autosquash is default behaviour for rebase.
This is totally not recommended for many reasons. The main reason is poisoning the git history, losing references to commits, basically creating a new repo on top of an old one, for simply no reason. I'm sure this is not a trick for perfect commits at all. I'm also sure ChatGPT have its finger here.
It's good that you have another opinion about it. I will be glad to see your article, or a more detailed comment about why this approach is not recommended by you, and what the side effects of it are because I need to get more details about your point to start arguing. Have a good day!
The whole point of git is to provide an audit trail of your code churn. Rebase is a special case that shouldn't be used like this. I have no idea why people are preoccupied with maintaining a clean git history, if you make a change document it in your comment and move on.
On theory will It maintain the same history (the same quantity of commits, although with new hashes )?
yes, absolutely
Awesome, thank you dude
Doesn’t this change the commit history?
If I want to change the commit message of an older commit, then all the commit history later to the changes commit will be changed. Please correct me.
Thank you for your question. Yeah, you are absolutely right, rebase command changes the commit history, and this is why later you need to push your changes with a --force flag. Technically with rebase --autosquash all of your commits will be just copied and the fixup commit will be squashed into another commit so your git history will only look like the same, but with different ssh-hashes