Making Git Your Partner
My last post was about keeping an engineer’s notebook, which is probably the thing that has helped me to remember meetings, tasks, and be infinitely more dependable and start acting like the senior engineer I hope to soon become. Today, I’m writing about something that has helped me grow as a developer: learning more than just the basics of git (and perforce before that).
Learning to use git more effectively (as well as being a little more thoughtful about branch naming and commit messages) has helped me grow as a developer by allowing me to try things I might have thought of as too sweeping or too big of a change to make, as well as, allowing me to save those changes when they’re not quite working and go back to a working codebase to fix another bug that has come up, then easily rebase the new fix into my experimental code when I come back to it. A lot of these exploratory branches end up being deleted without being merged, of course, but sometimes I’m able to make some big change that happens to make things better. The other thing, I always learn something, even on the experiments that don’t get merged.
Now, I know that a lot of (maybe most) developers tend to copy whole projects into new directories, or clone projects into separate directories from where they generally work, in order to avoid mishaps. They scroll through endless commits, looking for where a line of code was deleted (finding where it was last changed is usually fairly easy, and where it was introduced, as well, as long as it wasn’t moved from a different file). They do this for a host of reasons, including:
- lost work because a destructive command didn’t do what they expected
- confusing workflows, instructions, and training
- obtuse implementations in tooling (IDE’s, source hosting, etc…)
- poor understanding of best practices and why they exist
- only learning the bare minimum to get work done
I think pretty much all of those reasons stem from not learning to use git well enough to let it do the heavy lifting for them. Usually, I imagine they haven’t learned it more because we are all very busy. Our managers like to keep us chasing the next goal, driving to the next milestone. Also, learning to use your version control system a little better sounds less fun then learning a new language or programming paradigm.
Losing work is a hell of lesson… I’ve done it and it drove me nuts, but it wasn’t the end of the world. I figured it out again, probably a bit faster than the first time. It’s bound to happen now and then, regardless of your process. However, learning to use git effectively can probably actually help to reduce this (as well as help you test different solutions more effectively). By learning git, you will learn which commands are destructive and therefore, you should be a little more careful with. Rebase, merge, reset, and even checkout are some of the most common offenders.
Keep in mind,
reflog could save you in the event that you do ever
accidentally run a command deleting something you didn’t mean to. The
most sure way to get something into the reflog is to commit it. This
is why I, generally, checkout a new branch and commit my changes
before I change back to the other branch and run the command (or if
they’re already committed, checkout a new branch and run the command
there). However, beware, the reflog will not save you if the changes
never made it into the reflog, like if you accidentally discarded them
You probably already knew about the potential destructiveness of
reset. The name itself seems to drip with malice. A
--hard can and will delete code and whole files from your working
directory. However, it can also be your ally, as long as you approach
it, correctly, and maintain a good workflow (or at least create a new
branch from your changes before running your potentially destructive
Have you ever accidentally checked into master, then had to make
emergency changes before releasing the change you checked into master?
This is where
reset --hard can shine.
# Move your commit to a new branch git checkout -b my-unfinished-feature git checkout master git reset HEAD~ --hard
Now you’re back in line with master and ready to make the change and push your hotfix.
How about a careless
git add . staging changes that weren’t meant
to be checked in. This is where a plain
git reset --
dont-commit.txt will help.
Merge, Rebase, and Checkout
You know how the rest of these commands can be destructive. Just
remember to cut a new branch and commit your changes and you avoid
most of the pain. Branches are, pretty much, free, anyway. I’ve
probably lost more files to a careless
git checkout --
some-dumb-file.js than I care to remember.
Now, I remember to commit, even when I think I’ll never come back to
it. I go through my branches every once in a while. If I come across
something I haven’t touched in a while, I’ll
git branch -D
old-branch with reckless abandon. I’ve already moved on, those
changes are now dead to me. But, I’ve also come back to those branches
I never thought I’d touch again, occasionally, and I’m always glad I
git log. Seriously, it can change your life. It’s so much faster
than most web interfaces… and insanely powerful! Ever heard of the
pickaxe? I have to
duck go it every time I need it, because I don’t use it often, but
when I do… chef’s kiss. A quick check where my current branch is
(have I told you like to have lots of branches)…
--oneline. See the last couple of patches…
git log -2 -p. Want to
see a list of the files changed in a commit, how many lines were added
and removed in each file…
git log <commit-hash> --numstat -1.
Git commits have a very loose structure. A lot of times, you’ll see things can get pretty crazy in the log because of this. If you follow a few simple tips, it can save you from future headaches, as well as keep your log orderly bringing you even greater benefit.
The first line is the subject. It starts with an imperative: Add, Merge, Revert, Refactor, Remove, etc. It should be fairly short, around 50 characters or 10 words. The second line should be blank, to separate the header from the body.
After the blank line is the body. Don’t list the files you changed
(those are in the patch, remember
--numstat). Don’t rehash what
changes you made… Tell your team, future you, or whoever might be
working on this codebase in the future why you’re making this
change. Yea, a lot of these will be, “Adding a new feature,” but bug
fixes aren’t. Make a note of the bug, how it presented. Link to the
ticket if you can. Make it very clear what was fixed by this, so when
you come back in six months and try to clean it up, you can look at
the commit and think, “Oh yea!”
Here’s a couple good articles about this:
There’s a lot of good resources on the web to help you get the most out of git (or any VCS you happen to be using). I seriously recommend reading the git book. Skim it if you must, but there’s a lot to learn from that book. I read it after using git for years. I read it cover to (almost) cover. I think I stopped at the appendices, but, now that I’m looking at them again, I think I’m going to go back and read some of those, too.
Atlassian has a decent tutorial. Github has a lot of good resources, too. Do what works best for you (I think you might have noticed, I like reading the official documentation, but I know that’s not for everybody).
The trick is, don’t count on the web to give you the answer for everything, right when you need it. So often, you don’t even know what to search for, when things go wrong, if you are only using the bare minimum of the tool. Take a look at the docs, or do some more advanced tutorials. Get to know your tools and you’ll find them much more valuable.