DEV Community

Cover image for Good Commit ✔ VS. Bad Commit ❌: Best Practices for Git
Sheraz Manzoor
Sheraz Manzoor

Posted on

Good Commit ✔ VS. Bad Commit ❌: Best Practices for Git

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"
Enter fullscreen mode Exit fullscreen mode

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"
Enter fullscreen mode Exit fullscreen mode

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"
Enter fullscreen mode Exit fullscreen mode

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"
Enter fullscreen mode Exit fullscreen mode

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"
Enter fullscreen mode Exit fullscreen mode

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"
Enter fullscreen mode Exit fullscreen mode

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"
Enter fullscreen mode Exit fullscreen mode

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

  1. 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.
  2. Write Clear and Descriptive Messages: Your commit messages should be explaining what the commit does and why you made the change.
  3. 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.
  4. 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.
  5. 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.
  6. 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)

Collapse
 
efosa_j profile image
Efosa Jeffrey

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?

Collapse
 
sheraz4194 profile image
Sheraz Manzoor

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.

Collapse
 
bajajshubham profile image
Shubham Bajaj

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.

Collapse
 
bradbodine-dev profile image
Brad Bodine

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.

Collapse
 
gauravrawat440 profile image
Gaurav Singh Rawat

I think its a good idea to keep one fix or feature(or a lower classification) per commit. Helps to keep things and manageable

Collapse
 
itsshaikhaj profile image
Shaikh AJ

To handle this, use git stash to save your current work, then create a new branch for the high priority fix.

Collapse
 
efosa_j profile image
Efosa Jeffrey

Nice. Best practice all the way!

Collapse
 
abhishekrajshah profile image
Abhishek Shah

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.

Collapse
 
sheraz4194 profile image
Sheraz Manzoor

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).

Collapse
 
soham24122003 profile image
Soham

Great Article

Collapse
 
pharmtech_muslimah profile image
Ismail ubeydat

Thank you, very insightful

Collapse
 
sheraz4194 profile image
Sheraz Manzoor

Thanks for your good words, happy coding..

Collapse
 
idrees04 profile image
idrees • Edited

Thanks for this comprehensive guide on effective Git commit management. It will greatly help in maintaining a clear and organized project history.

Collapse
 
sheraz4194 profile image
Sheraz Manzoor

Thanks much for your good words.

Collapse
 
ejcenteno_ profile image
EJ Centeno

My Git history is basically a diary of my emotional state while coding.

Collapse
 
sheraz4194 profile image
Sheraz Manzoor

Yes exactly, that should be it

Collapse
 
leandro_nnz profile image
Leandro Nuñez

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.

Collapse
 
sheraz4194 profile image
Sheraz Manzoor

Thanks Brother, keep supporting me like this and I'll keep writing good for you.

Collapse
 
ac_coder profile image
Abdullahi Ali

cool.

Collapse
 
ptcbink profile image
ptcbink

Good experience.

Collapse
 
nevin100 profile image
Nevin-Bali100

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.

Collapse
 
sheraz4194 profile image
Sheraz Manzoor

Its pleasure when someone really supports and appreciate your efforts. It means a lot to me brother!!

Collapse
 
pasquale_bassolillo_ebbd3 profile image
Pasquale Bassolillo

Really really good! Thx very much!

Collapse
 
sheraz4194 profile image
Sheraz Manzoor

My Pleasure mate!!!

Collapse
 
0403kumar profile image
kumar0403

Great 👍

Collapse
 
sheraz4194 profile image
Sheraz Manzoor

Thanks man!!

Collapse
 
adderek profile image
Maciej Wakuła

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!

Collapse
 
sheraz4194 profile image
Sheraz Manzoor

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.

Collapse
 
premkumar121 profile image
Premkumar

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!

Collapse
 
silentwatcher_95 profile image
Ali nazari

great article !
i recently wrote something about conventional commits
link
I would be honored if you could check it out 🫠

Collapse
 
sheraz4194 profile image
Sheraz Manzoor

You have written well too. Great job.

Collapse
 
afzal_51138c1816de723c229 profile image
Afzal

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?

Collapse
 
sheraz4194 profile image
Sheraz Manzoor

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.