In the amazing world of software or web development, version controlling is one must-have in every developer working on a project with other developers. One of the most used version control systems is Git that helps developers in following changes, going back to previous states effectively and working as a team on your projects. But, being its working Git only proves effective if the commits are managed properly. In this article, we will go through those good and bad commits explaining you the best practices to have a clear informative helpful commit history.
What is a commit?
In Git, a commit is referring to the state of your code at one specific point in time. Commits with the metadata (author, timestamp, commit message etc). Commits are used for saving progression, stating changes and merging developed pieces with others work.
Characteristics of a Good Commit
Atomic and focused: A commit should be atomic - it has to represent one and only one logical change. Do not mix several independent changes in one commit.
Example:
# Good commit
git commit -m "Add user authentication"
# Bad commit
git commit -m "Add user authentication and update UI styles"
Descriptive Commit Message: A descriptive commit message clearly explains what the commit does and why the change was made. It should provide enough context for others (and your future self) to understand the change without reading the code.
Example:
# Good commit message
git commit -m "Fix Correct null pointer exception in user login"
# Bad commit message
git commit -m "Fix bug"
Follow Conventional Commit Guidelines: You can use the standard commit guidelines to keep your git history clean, consistent and easy to read. Usually these guidelines interpret in the form of type (feat, fix, chore, refactor docs), and short summary plus occasionally a long explanation or REF to other relative issues.
Example:
# Good commit message following conventional guidelines
git commit -m "feat(auth): add JWT-based authentication"
git commit -m "fix(login): resolve race condition in login flow"
Tested and Verified: Make sure that the changes in your commit have been tested, and properly run. Broken/untested code can disturb the flow and other members.
Properly Scoped:Scope your commits appropriately. For instance, if you’re working on a specific feature or fixing a bug, ensure that all changes related to that task are included in a single commit. Avoid partial changes that might leave the codebase in an inconsistent state.
Example:
# Good commit with proper scope
git commit -m "refactor(auth): split auth logic into separate module"
# Bad commit with mixed scope
git commit -m "refactor and minor fixes"
Characteristics of a Bad Commit
Large and Unfocused: A commit with too many changes is a bad commit. It makes difficult to understand what the commit does. Large, unfocused commits are challenging to review and debug.
Example:
# Bad commit
git commit -m "Update project"
Vague or Misleading Messages: Commit messages that are vague or misleading do not provide useful information about the changes. This lack of detail can cause confusion and make it hard to track the history of changes.
Example:
# Bad commit message
git commit -m "Stuff"
Unrelated Changes: Combining unrelated changes into a single commit makes it difficult to isolate specific changes, potentially introducing bugs and complicating the review process.
Example:
# Bad commit
git commit -m "Update readme and fix login issue"
Incomplete or Untested Code: Committing incomplete or untested code can disrupt the workflow, causing issues for other team members and potentially breaking the build.
Lack of Context: A bad commit often lacks context, making it hard to understand why a change was made. This can lead to confusion and difficulties when revisiting the code in the future.
Best Practices for Good Commits
- Commit Often, but Not Too Often: Strive for a balance between committing too frequently and not enough. Each commit should represent a meaningful change. Never push unrelated changes in a single commit.
- Write Clear and Descriptive Messages: Your commit messages should be explaining what the commit does and why you made the change.
- Use Branches Effectively: Use feature branches for new features, bug fixes, and experiments. Raise Pull Requests for those branches and project manager or admin will review you code and merge them into the main.
- Review and Squash Commits: If you are project owner, leader, admin or someone reviewing the code, before merging a branch, review and squash small or fixup commits into logical units. This practice keeps the commit history clean and easy to follow.
- Automate Testing: Use continuous integration tools to automatically test your code with each commit. This ensures that your changes are verified and reduces the risk of introducing bugs.
- Use Husky: Using a library like husky can improve you git skills. It does not allow the commit if you are breaking the rules configured in husky.
Conclusion
Good commits are important for maintaining a clean and understandable project history in Git. By following best practices such as keeping commits atomic, writing descriptive messages, and ensuring changes are tested, you can improve collaboration and make your project super maintainable. A well-managed commit history is an invaluable resource for your future self, your team or for new collaborators.
By following above guidelines, you’ll make it easier for everyone involved in the project to understand, review, and build upon your work. Happy committing!
Top comments (46)
Nice read, thanks!
Got a question tho. I've been in scenarios whereby I branched out from main and start working on a bug fix for a feature. While on that, I get a request from PM to work on another fix with a higher priority. Sometimes I'm just tempted to add that quick fix to the current fix that I'm working on. In this case would you consider it bad practice?
Thank you for your kind words!
In your scenario, while it might seem convenient to add the higher priority fix to your current branch, it can lead to confusion and make it harder to track changes. A better approach would be to stash your current changes, switch to a new branch for the higher priority fix, and then return to your original task once the urgent fix is complete. But you might got conflicts this way in the two branches. So you should have a strong command on git to resolve conflicts as well.
Otherwise stash the changes, work in the new branch on a new bug and then pull the previous branch in the new one.
I don't know if this would work and be considered a good practice. I just thought of it and needs to be fact checked -
If you don't want to stash your current progress, git clone the repository in a different directory and work higher priority task in that code. Once you are done with the priority task and merged, go back to your own work and complete that fix. That way you may be able to work on both the tasks as required.
Yes. Bad practice. I understand your temptation but it mixes two different changes. It’s ok to have small or tiny PRs if they fix the entire issue.
I think its a good idea to keep one fix or feature(or a lower classification) per commit. Helps to keep things and manageable
To handle this, use
git stash
to save your current work, then create a new branch for the high priority fix.Nice. Best practice all the way!
My approach would be since you are already working on a bug in the branch you have created it is always better to create a new branch for a higher priority issue/bug and once that is fixed merge the code from earlier low priority bug into this one and fix that. This way you a priority history of big fix and also knowing if any change has had other impacts before merging into main.
Yes, sounds good, I suggested exactly that.
But if we believe that we'll not have conflicts, it would be better to keep those branch separate and push them to main (means by creating PRs and merging obviously).
Great Article
Thank you, very insightful
Thanks for your good words, happy coding..
Thanks for this comprehensive guide on effective Git commit management. It will greatly help in maintaining a clear and organized project history.
Thanks much for your good words.
My Git history is basically a diary of my emotional state while coding.
Yes exactly, that should be it
Concise and effective. Thanks for sharing!
I think that git commit’s best practices are related or similar to clean code patterns. Atomicity at least is one of the keys.
Thanks Brother, keep supporting me like this and I'll keep writing good for you.
cool.
Good experience.
Very Insightful article to read, It is very nice to see someone sharing citing the generic but very important details of git.
I will share this post with the community.
Its pleasure when someone really supports and appreciate your efforts. It means a lot to me brother!!
Really really good! Thx very much!
My Pleasure mate!!!
Great 👍
Thanks man!!
Good but not perfect.
You should distinguish local work, remote "internal untested unstable" and finally a waterfall-like commits. Locally you can create millions of branches and commits (though it is not practical... Usually a few dozens of commits per Dev day is enough).
When pushing you replicate your code so that it is not lost if your computer goes bad. It could be pushed onto origin or any other host. But you should probably describe what it is (usually branch name is enough to do that). This is when rebase is great.
When merging to a shared workflow (ex. develop branch), you should have it tested and at least compiling (though more likely working and tested). This is where squash shines.
Normally you do not develop a single thing long. There are exceptions though. Again rebase shines and the longer you do this, the more pain it is.
Then releasing is approaching slowly. You should understand what is an annotated tag. Keep it simple or it would cause too complex.
Finally release. You need to decide your approach here: do we merge back to develop? Shall we squash, rebase, merge or do something else? What should be done when someone is merging us as a base? Ffonly?
Deployment. Is it a release or deployment?
I skipped the part with storage as each type has different approach: GitHub has forked repos and pull requests, kernel has merge requests over mail, some have pull request from branch where repo is semi-public but some branches are protected.
I also skipped branching of different releases. What to do if you need to maintain multiple versions? How to release this important security bugfix that is same for 9 versions but older versions needs different code?
You totally skipped multiline commits (first line is a summary, then empty line and an elaborate bellow). 80 or more columns? Special approach to cosmetic non-functional changes? What prefixes to use (conventional commits) and how to write release notes?
This is just a scratch on the surface of this topic.
Thanks for the article and good luck in your journey!
Good Suggestions, but see the tag #beginners on the top?
It is for beginners, not for advanced level devs. So that is information is enough for them.
Thank you for your insightful blog post on Good Commit ✔ VS. Bad Commit ❌: Best Practices for Git. I found it both engaging and informative, and I appreciate the effort you put into it. Looking forward to reading more of your work!
great article !
i recently wrote something about conventional commits
link
I would be honored if you could check it out 🫠
You have written well too. Great job.
Got a question tho. I've been in scenarios whereby I branched out from main and start working on a bug fix for a feature. While on that, I get a request from PM to work on another fix with a higher priority. Sometimes I'm just tempted to add that quick fix to the current fix that I'm working on. In this case would you consider it bad practice?
Thank you for your kind words!
In your scenario, while it might seem convenient to add the higher priority fix to your current branch, it can lead to confusion and make it harder to track changes. A better approach would be to stash your current changes, switch to a new branch for the higher priority fix, and then return to your original task once the urgent fix is complete. But you might got conflicts this way in the two branches. So you should have a strong command on git to resolve conflicts as well.
Otherwise stash the changes, work in the new branch on a new bug and then pull the previous branch in the new one.