loading...

How I Git

andydangerous profile image Andy ・4 min read

As usual, this post initially appeared here

I'll bet you use git (or Subversion or something, but I know git so that's what I'm writing about). This post may be review for you, but I have opinions and I want to share them on the internet! Jason McCreary wrote some posts about git including this one which sums up git rebase better than I care to. Check it out.

Why do we use git; what problem are we trying to solve?

  • Revert - You want to be able to confidently undo changes that break your code.
  • Track changes - You want to be able to figure out what was necessary to implement a feature, or how various code is related to other code. Mostly, you want to know why somebody chose to write a particular piece of code.

There are obviously lots of other great features, but these two will suffice for the purposes of this post.

Formative Moments

I made two very memorable mistakes with git in my first few months as a software developer.

The first related to a feature I had been working on for several days. I was in the habit of making fairly atomic commits along with WIP (Work In Progress) commits at the end of the day. I'm not sure where my pair was when this went down, but at some point, I ended up merging my branch into master and pushing. Within half an hour or so, a chat room blew up with questions about merge commits and WIP commits in master. I was terribly embarrassed, but another developer helped explain what I should have done (squash and rebase).

The second offense was worse. I had pushed code to master that broke something. Upon seeing this, I immediately knew what the problem was and decided to fix it. My solution was to fix the tests and code, amend the commit, and (force) push back to master. This process took maybe five minutes and I figured nobody would be the wiser. Of course the chat quickly blew up again. This time somebody was wondering why they were unable to push to master, having rebased minutes before. Again, I had to identify myself as the culprit.

These were dumb things in retrospect, but you can bet that I learned my lesson. Don't be like me. Follow best practices and your colleagues won't hate you.

Some best-practices

Imagine you're working on a feature branch and are ready to submit a PR or however you prefer to submit your code for review.

  • rebase to keep your branch up to date. This is helpful to do frequently while working on a branch to ensure you have the latest commits from master. Make sure you do it before creating a PR or merging into master. I almost always complain when I see a PR for a branch that is "3 commits ahead and 30 commits behind" master*.
  • Squash many of your commits. This one is slightly contentious, but need not be. Remember that the whole point of your commits is to tell a coherent story (and be able to easily revert if something goes wrong). That means that commits destined for master should not have WIP in them and should not include stuff like "fixed more typos." Keep track of that stuff however you want when working on a branch, but squash them before the make it to master.** I like to squash through an interactive rebase. On the off chance that you do need to revert a commit, having one commit per feature will ensure that you can revert the whole thing without breaking master or dealing with merge commits.
  • 50/72: Message is 50 chars, description wraps at 72 - Here is one of about a thousand blog posts on why the 50/72 rule of git commits makes sense. Lots of tooling is built around commit messages looking a certain way. It's built into my tooling so I don't even have to think about it. One important side note here is that you should really add comments to commits. There is plenty of room to explain why you made certain choices or any other useful context.
  • Get your gross merge commits out of my master branch. If you follow the previous points then your PR will be neat and tidy and ahead of master. There is no reason for a merge commit. If you're using Github then you can just "Rebase and Merge" or if you're going cowboy-style then you can just merge your branch into master. Get that: git merge my-branch won't even create a merge commit. It's like git telling you that you're doing it right.

Finally

“Code needs to work today just once, but needs to be easy to change forever.”
-Sandi Metz

The audience for your git commit history, like your code itself, is your future self and your future colleagues. Make it easy on them. These suggestions may seem petty and annoying at first, but are really pretty easy to get used to. The benefits far outweigh any cost. Alias git blame to git praise if you have to.

* An unnamed collaborator on a project once merged (his own) PR that was in this 3 ahead, 30 behind state. He ended up merging in some commit from weeks before that broke production and was a nightmare to track down. Don't be "him."

** Sometimes people think that they need to track every single commit, change, and dead end as a way of "telling the truth" or preserving context. I argue that a clean commit history (before changes make it to master) tells a better story. If you are worried about preserving context for decisions, then spend some extra time on the commit message and tell that story explicitly.
Now, once a commit is in master then the "telling the truth" argument makes sense.

Posted on Feb 15 '17 by:

andydangerous profile

Andy

@andydangerous

Software Developer Elixir, Ruby, Vim...

Discussion

markdown guide
 

Gross merge commits out of master? No... those merge commits are telling an important story. It's incredibly easy to hide them if you don't want to see them. When you show the git log, only show the "first parent" and "hide git merges".

I'm not accusing you of not knowing how to git but I often do see people who don't really know what they're doing give advice to the masses and then we end up kind of where we are now... git hell.

 

Thanks for your input, Joe! I'll try to address some of your concerns in the next git post, whenever that comes along.

 

The problem with "first-parent" is that you have to always merge branches into master (i.e never call git merge master). This works great with what the article said about rebasing master onto your branches. I do not get the last point of how git would not create a merge commit if your branch is up to date with master. I know git does this with fast-forward, but do not understand how it would work with a branch that was up to date due to rebasing.

 

Excellent!

I was about to write that it would be nice to have a link to a rebase explainer, but then I noticed that it is already in your great post, so I squashed rebased my comment :)

Yes, I am a git culprit way too often!

 

Interesting. How do you reconcile pushing branches for CI builds with rebasing?

 

Great question. I don't actually have a good answer here. In practice, I am usually comfortable force-pushing to non-master branches. One solution could be using more ephemeral branches for development and being a bit more rigorous with branches for CI?

 

I disagree with almost everything in this post. Information hiding. rebasing introduces many issues. Use merge reset as your workflow.

 
 

Good article, thanks for experience sharing :)

 

Amazing article. I have been using git for a long time, but I just "survive" while using it. This opened up a whole new world.

 

Does backing up your $HOME directory count as a valid use? I've heard of gents silly enough to try it. XD