We all know how to do git add., git commit, and git push. Some of us even let our IDEs do it for us. But is that all there is to it?
Git has been one of my passions for a long time, and that's because of how flexible and powerful it can be, when used correctly. There are three main areas of interest for me in Git, and I'd like you to invite you to explore these with me today:
- Developer Experience
- Recovering Files
This is surely the simplest area, but it is by no means the least important. Even though this is not really a Git CLI command, it should definitely be on your mind when starting a project.
Most (if not all) Git repositories providers (e.g. Github, GitLab, Bitbucket) interpret the README.md file of your project as the documentation homepage of the project. And it is crucial that your README is updated and that it is so simple that even people who don't know how to code can set up the repository on their machines.
Here is a list of questions your README should answer:
- What is the project about?
- Are there any documentation (business and API) links?
- What is the building status for each environment?
- How can I access each environment?
- What is the development stack?
- How do I install the project's dependencies?
- Are there any environment variables I need to have set up on my computer?
- How do I run the project?
- How is the code deployed?
- Is it automated or should I run some command?
- How do I contribute to the project?
- Where can I find the project's list of priorities?
- Where can I report a bug?
- Who can I talk to when I have questions?
- Is code merged via Pull Request?
- If so, who is responsible for merging the code when the PR is approved?
The reason you should be worried about making your README file as good as possible is that it will take your onboarding time to a minimum no matter the seniority level of the newcomer. Plus, it helps the newcomer get up to speed faster!
Finally, a good README will require good project documentation, which will reduce knowledge silos in your team.
The second step for Developer Experience is related to commit messages. It can be really frustrating and time consuming when you're trying to figure out when a bug was introduced and all you have in the commit messages is gibberish and it's not clear where one feature ends and another begins.
Here are a few tips:
Your git should tell the story of how the project was developed. Some people use the ID from a Kanban card as a prefix to a commit, and others simply write a nice, descriptive text regarding the changes. There is no right way to do it, really.
There is, however, a wrong way to do it. I know, sometimes we get frustrated and tired, and we commit messages such as "testing fix", "plz work now", "foo bar", "simple test," etc. However, this is not how the commit messages should be on a normal basis.
As a rule of thumb, I like to use Tim Pope's git commit message pattern as a guideline for my messages. Also, you can check out the git rebase --interactive command when you feel your commit messages are too messy or you need to transform a bunch of testing commits into one single working commit.
We've all been there: you git checkout one week's worth of work on a Friday at 5PM. But no more! There is a chance that you'll be able to recover your files.
Enter your knight in shining armor: git fsck.
Git fsck is responsible for scanning the project and finding any dangling files that are not reachable by any node in the git tree. Git creates a dangling blob the moment you run git add on your file. This file will be attached to the git tree once you run git commit, and it will no longer be dangling.
So, if you did run git add on your file, and you checked it out afterward, you would be able to see it by running the following command: git fsck --lost-found
This will return a list of all the dangling files in the project, such as:
Once you have that hash code, you can use another one of Git's beautiful lifesavers: git cat-file. It works just like the cat command on your terminal (if you don't know what that does, it prints the content of a given file), but for any git blobs. It's syntax runs something like this: git cat-file <type> <hash>.
Sometimes you will happen to have a dangling tree instead of a dangling blob (such as when you git checkout a folder). This is what the <type> parameter is for. But since you can't recover your files in bulk, the dangling trees will only be useful to remember what the files were that were inside that folder. Most of the time, your <type> parameter will be "blob".
Here is an example of the full first commit, new change, checkout, and recovery of a file:
From here you can print the contents of the file to a new file using the terminal itself, such as: git cat-file blob "your-hash" > "new-filename" (or you can simply copy and paste from the terminal into a file - it works either way).
I know, from here on, it's a bit of manual work depending on how many files you lost, but hey, at least you won't have to think about how you created that complicated logic again. Besides, it shouldn't take you more than 2 hours to recover everything, and you can always create a script to automate your recovery.
Last but not least, let's talk about flexibility. I will cover this topic in two parts: recording and retrieving.
First off, let's tackle retrieving since this is the most common use case. Imagine there's a bug you solved in a branch that will not be merged with the rest of the code. Deleting the branch will also delete the bugfix, and you can't make a branch from that branch because there's a bunch of code that cannot be used over there.
What do you do? Delete the branch and code the bugfix all over again? Copy the files for the bugfix outside of the project folder and then paste it back when you switch to another branch?
You don't need to do that. Git gives you a tool specifically for handling cases where you only need a single commit from a branch. The name is git cherry-pick.
Here's how you use it:
- You get the hash that identifies the commit you wish to move
- You switch to the branch where the commit should go
- You run: git cherry-pick <commit-hash>
Done! The commit is now on another branch, without the hassle of a file switcheroo that might overwrite any code that's already being done in the new branch. The bugfix will be added as a simple change that was committed like any regular code.
Now, this is all fun and games, but you can't do that when you create those mile long commits that create three different features at once. That's when you use git's flexibility in the way you create commits.
First off, a good commit should always leave the project working. I like to do that even on feature branches, with the exception of when you're asking for someone's help on some particular issue, but then you git rebase it after the issue is solved (see the Developer Experience section).
The ideal commit should have exactly what's needed for a feature or a bugfix to work. Nothing more, nothing less.
And you might think: "What if I have both feature changes and bug fixes in a single file?"
Worry no more, my friend! Git has got you covered with git add --patch. The --patch flag in your well-known git add allows you to add only a portion of the changes made in a file. That way, you can create one commit for your bugfix, and another one for your feature.
And that concludes our tour of some of Git's not-so-well-known tools. This is just the tip of the iceberg when it comes to Git. I am still learning it to this day. As Donald Rumsfeld said: "There are known knowns. There are things we know we know. And we also know there are known unknowns. That is to say we know there are some things we do not know. But there are also unknown unknowns, the ones we don't know we don't know".
I believe that a lot of growth can come out of the things we know we don't know very well. That way, you have a very clear list of things you need to do in order to grow as a developer. And I hope I just added Git to your list.
Do you know any other tools that are super useful? Add them in the comments section! Do you know any friends who would benefit from this article? Share it with them!
Git documentation - git-scm.com/docs
Mahezer Melo is a Software Engineer at Avenue Code. He likes to ramble about best coding practices and Functional Programming. He’s a hobbyist, from skateboarding to mixing cocktails, and right now he is learning how to fish.