Five Useful Git Tips

Let's start with a simple one:

1. Autocorrect

git config --global help.autocorrect 1

Now when you make a simple typo, git will correct it automatically!

But a bigger typo will fail:

2. Tab-completion

Or you can let bash complete commands for you!

  1. Download this file to your home directory and name it .git-completion.bash.

  2. Add this to your .bash_profile: source ~/.git-completion.bash

Now bash will tab-complete git commands!

3. And my pickaxe!

So you can grep through your code base. But what if the code you're grepping for lives in history? Git allows you to grep through your entire project history quickly and easily using git pickaxe:

git log -S[search term]
git log -Saws_secret_key # did this repo ever have an aws_secret_key?

That will show you all the commits including aws_secret_key. You can see the diff of each commit too by passing the -p flag:

git log -Saws_secret_key -p

Now these next two are a little complex but still good. Bear with me.

4. Stripping whitespace

Hey! Don't you hate when you check in code with trailing whitespace? And then your co-workers stab you to death?

You can have git strip whitespace for you automatically.

First, make a .gitattributes file in your project root with these contents:

* filter=trimWhitespace

This says every file will go through the trimWhitespace filter. You could apply it to ruby files only like this:

*.rb filter=trimWhitespace

Now define the filter:

$ git config filter.trimWhitespace.clean trim_whitespace

Every filter can be run at two different hooks: right after you pull, or right before you push. The smudge filter is for right after pulling and the clean filter is for right before pushing. This says

  1. create a new filter called trimWhitespace
  2. for the "clean" action, run my code through the trim_whitespace utility.

Save this ruby script as trim_whitespace somewhere in your PATH and make it executable:

#!/usr/bin/env ruby
lines = STDIN.readlines
lines.each do |line|
  puts line.rstrip
end

That's it! Now every time you do a push from this repo, git will automatically trim all the whitespace for you. You can see it in action: add a bunch of trailing whitespace somewhere and do a git diff. That line should show up in the diff with the trailing whitespace removed!

5. How to recover lost data

This is an important one. Here's the golden rule of git: if you lose data but you checked it in somewhere, you can probably recover it. If you didn't check it in, you probably can't. So check in often!

When you make a commit, git takes a snapshot of your repo in that state:

Each commit has a SHA1 hash that you can use to reference the commit. And each commit points to its parent:

A "branch" is just a pointer to a commit:

So when you say git checkout master, you're saying "give me the commit that the master pointer points to".

Now, let's say you accidentally do a git reset --hard and you are stuck on an older commit. You look at your log and it looks like you've lost a couple of commits! What's happened? They are there, but just that master doesn't point to them anymore so you can't get to them:

But they're still there! And you can get to any commit if you know its SHA1 hash! Well lucky for you, there are a couple of ways to figure out the SHA1. One way if to use the reflog:

reflog

Any action you take that updates a branch head will get logged in your reflog. Check it out by running git log -g:

commit ee68d62d4cbac3ffefc38398a63d70e4dd518e7d
Reflog: HEAD@{0} (Aditya Bhargava <bluemangroupie@gmail.com>)
Reflog message: commit: Finish writing the kernel
Author: Aditya Bhargava <bluemangroupie@gmail.com>
Date:   Tue Aug 13 15:10:55 1991 -0700

    Finish writing the kernel

commit 2f9eaea2ce5e6306cb37897417cf63a8d8c63ec4
Reflog: HEAD@{1} (Aditya Bhargava <bluemangroupie@gmail.com>)
Reflog message: checkout: moving from master to adit/experimental
Author: Linus Torvalds <linus@git.com>
Date:   Tue Aug 13 14:27:36 1991 -0700

    CSS Tweaks

Do you see your lost commits in here? If you do, grab the SHA1 of the newest commit, and do:

git branch lost_data [SHA1]

Now the lost_data branch should have all of your lost commits! Merge it into your branch:

git merge lost_data

Ta-da! Lost data recovered!

fsck

Here's another way:

git fsck --full

This shows you all the objects that aren't pointed to by another object. One of your commits should be in this list, and you can get the SHA1 hash!

Conclusion

Linus is happy that you know git better

Thanks for reading! Check out my other posts.

Privacy Policy