Check Out These 5 Git Tips Before Your Next Commit
These days, just about any dev shop on earth manages its source code using some variant of Git, the decentralized version control system authored by Linus Torvalds, creator of the Linux kernel. Walmart Technology is no different and leverages Git to enable developers to work independently of one another while maintaining a shared history.
It’s important to note when discussing Git that I’m referring to the application itself, not GitHub, with which it’s often confused. Although a number of supporting applications and GUIs wrap around Git, there’s an incredible amount of value in understanding how the underlying core commands work. Until you learn what each one does, I’d highly discourage using a wrapper or supporting application. Personally, I perform all of my GitOps in the command line and only occasionally use supporting applications as a reference, mainly because I like looking at the colorful branches and marveling at the progress. Git also has its own built-in GUI that can be accessed through the gitk command.
Like many other companies, Walmart initially started out with Apache Subversion (SVN) as its source control management (SCM) solution. As a result, many teams still have an “SVN” mindset when it comes to using Git. I joined Walmart about a year ago; my team had transitioned from SVN to Git 6 months prior to my arrival, so I had a fresh outlook.
Git is a very powerful change management tool. Git is also very, very flexible in what it can do. When you match that much power with that much flexibility, you get a tool that will let you do virtually anything you want. This is purely by design. Git will accommodate any variety of workflows, branching strategies, branch naming conventions and even hooks. But with great power comes great responsibility. While there are protections in place to prevent you from losing hours of work, Git will let you develop bad habits without ever complaining.
There’s no right way to use Git, but there are a lot of ways to use Git inefficiently. Here are five core practices that will enhance your Git usage regardless of your experience as a developer.
1. Commit early, commit often
It all starts with frequency. If you are starting out fresh with Git, then you should be committing early and often to your changes. Do it until it becomes second nature. When you add a method, commit. When you change something, commit. Did you rename some files? Commit. You know that floppy disk we call a save button? When you get to the point of committing your code as often as you are saving your Word documents, only then can you start winding back to a more comfortable cadence.
2. Make your commit messages meaningful using a semantic style
Imagine a box. You can put stuff into the box. You can take stuff out of the box. This box is the staging area of Git. You can craft commits here. Committing commits is like sealing that box and sticking a label on it. The contents of that box are your changes. So, why not have the label mean something? You wouldn’t label a moving box with kitchen items “stuff.”
Commit message composition is just as important as naming your variables and methods. If you’re following the first tip above, it’s very tempting to label a commit as simply “changes” or “savepoint.” Don’t fall into that hole.
I follow a rigid commit message format that I discovered in an article by Jeremy Mack called Semantic Commit Messages. The premise is limiting your commit message to a short list of commit types. By doing so, if you find your commit falls into more than one category, then your commit should be broken up into multiple commits.
At Walmart, we use JIRA to track our user stories and GitHub Enterprise as an internal remote repository, so my team also includes our JIRA story in our commit messages. In the early months of our project, I mentioned that commit messages varied widely. Before we switched to GitHub, we used Bitbucket’s “Yet Another Commit Checker” Git hook to apply a regular expression to each incoming commit message to make sure it met my criteria.
(LICGLM)(-)(\d{2,})( )
(chore|feat|docs|fix|refactor|style|test|sonar|hack|release)(:)( )(.{0,80})
This is the expression I used. It’s not pretty or elegant, but it works. Our project ID is LICGLM, followed by a hyphen, the commit types, a colon and a space, then finally a message. The total commit length is limited to 80 characters. The idea, as I mentioned earlier, is that if you have a really long commit message, you are probably trying to cram too much into one commit. Break it up.
3. Make your changes in each commit atomic
Some of you already know where I’m going with this, but for those of you who are thinking atomic means hydrogen or carbon, let me explain. We want our commits to be, in a way, transactional. When you are committing changes to your repository, they should be as minimal as possible, but with a caveat. The changes should also be related. So, if you are changing one part of your code that affects another, make sure to include all of that in one commit. I’d caution not to include everything, though. Keep your commits as small as possible, but keep your changes in each commit related. For example, you keep your constants separate from the rest of your code and include them only when necessary. If you add or update some constants in addition to including them on that new service you wrote, you should probably include those changes together. The idea behind this is so that if you need to roll back to a previous commit, you are rolling back incrementally and not in huge swaths of changes and hours of work. See rule №1.
4. Push your code to a remote (if you have one)
Early in our project, we had some team members who would work all day before committing their code. One commit for hours of work. This is a terrible idea. Look at it like this. Your changes don’t happen until you commit them. If you are working with others, your code does not exist until you push your changes to a remote repository. Don’t put yourself in a position to lose hours of work. Commit your code and push it to a remote if you have one. It’s that important.
5. Never rewrite shared history
Did you ever wish you could go back in time and Marty McFly some of the bad code you committed? Well, with Git, you can. Should you? Not if you’re working with others and your commits have already been pushed. Otherwise, just be careful. If you’ve seen Back to the Future, you already know why it’s a bad idea to change the past.
In Git, you can go back in time, rebase different branches on to other branches. You can also delete commits, rename them, squash them into single commits, and much more. If you are the only developer and it is your local machine, you tend to have more freedom than if you are working on a team. If you are working in a team that shares the same history, rewriting that history will just upset them. Git gives you the freedom to create branches and merge them back together later on, so in many cases, rewriting history isn’t necessary. Since Git already gives you the ability to checkout any previous commit, it makes sense to not alter any of your past commits so you can use any of them as a point of reference in the future.
Conclusion
This list is in no way exhaustive and while there are many other best practices out there, following these five rules will lay a solid foundation you can build upon regardless of skill level. I encourage you to go out and discover your own tricks and share them with others. That’s really half the fun.
Did you enjoy this? Feel free to reach out to me on Twitter @sublimegeek or email jonathan.irvin@walmart.com.