A Few git Tips

A screenshot of gitk --all
A screenshot of gitk --all

I owe thanks to Johannes Schindelin, who passed on at least three of these tips to me in the course of working on Fiji :)  Update: this page was written when I was relatively new to git – some of the general remarks about the philosophy of git are better expressed in a short tutorial I wrote recently.

gitk –all

Whenever you’re confused, use gitk –all to work out what’s going on.  The –all parameter is important so that you see all your local and remote-tracking branches. It might take a while to get used to reading the graphic representation of what’s going on, but it very often explains why things aren’t working as you might expect.

Finding text anywhere in your complete history

Particularly if you are in the habit of creating lots of branches (as I suggest below) it is easy to forget where you introduced a particular bit of code.  You can find it again simply with git log -S<search-term> –all.   For example, suppose you know that “Factory” occurred as part of the class name that you’re looking for then git log -SFactory –all will list all commits in your repository (including remote-tracking branches) that mention “Factory” in the change they introduce.  If you want to see the patch as well (which is often helpful) add -p to that command.  Update and correction: note that “git log -S<search-term>” doesn’t quite do what I said there: in fact it finds where there are different numbers of occurrences of the string in a file before and after that commit.  In git version 1.74 and later you can use -G<regex> instead, which has more obvious semantics – it displays commits where the change introduced genuinely adds or removes a line that matches the given regular expression.

If you want to find all the branches that one of those commits is on, see the next tip:

Finding commits by SHA1sum

There are a lot of common situations where it’s useful to find out all the branches that a particular commit is on.  For example, if you’re using submodules, then git submodule update will detach HEAD in each submodule in order to move it to the right commit.  You might, however, want to do some work on the branch that commit is on.  To do this, use git branch –a –contains <SHA1sum of commit>.  For example:

  $ git branch -a --contains 6f2293e7f6428
  * (no branch)
    origin/fiji

(This suggests that you should create a branch that tracks the remote-tracking branch origin/fiji, and you’ll find the commit in the history for that branch.)

git-ps1

Use __git_ps1

It’s very easy to forget which branch you’re working on, particularly once you get used to switching your working tree to different branches with git checkout.  You can use the  $(__git_ps1 ” (%s)”) in your PS1 environment variable to include some useful information about your current branch in your bash prompt.  If you are not currently in a git repository, this evaluates to the empty string.  Another very nice feature about __git_ps1 is that it will remind you if you’re in the middle of a rebase.  It’s easy to abandon a rebase but forget to do git rebase –abort at the end.  git status won’t remind you of this (a bug, IMHO) but if it’s there in your bash prompt, it’s hard to ignore.

The example in the image uses:

  PS1=' \[\033[1;37m\]: \u@\h:\w\[\033[0;37m\]$(__git_ps1 " (%s)")\n '

… which, if I recall correctly, was partly based on Tony Finch‘s.

Create lots of topic branches

In other version control systems branching and merging are awkward compared to git, and this means that people are often reluctant to create new branches.  One of the things that I love about working with git is that it’s quite easy and natural to create a new branch for every idea you have, and just merge them into your master branch when you’re happy with them.  This matches the way that I like to work on things, as well – you can work on one idea until you’re stuck, then switch to something easier for a bit, etc. all in one copy of the repository.

Only keep one copy of a repository per computer

It’s tempting when starting to use git to clone a repository several times and work on different things in each.  In general it’s much better (and more “git-like”) to just have a single repository and get used to switching about your working tree with git checkout <BRANCH NAME>.  If you want to quickly put aside what you’re working on, without having to carefully put together a commit, then use git stash.  (Beware when unstashing some local modifications with git stash appply however – you need to switch back to the right branch before running that command.)

Turn on all git’s coloured output options

There’s a nice summary on this git cheat sheet of the options you need to add to your .gitconfig to turn on git’s coloured output for terminals.

In addition, you might find the –color-words options to git log and git diff useful.  Rather than producing a line-by-line diff, it will coloured added text in green and removed text in red within a single line.  e.g. try git log -p –color-words

View a particular file from a particular commit

Fairly often, I just want to have a quick look at the version of a file in a particular revision.  The easiest way to do this is with the <COMMIT>:<FILENAME> syntax that git show understands.  For example, to see the version of a file util/TestQuantile.java from a couple of commits ago, you can do:

  git show HEAD^^:util/TestQuantile.java

… or to see it from a topic branch called “experiment” do:

  git show experiment:util/TestQuantile.java

Note that the path is always relative to the repository root – even if you’re in the “util” subdirectory, you still have to include “util/” in the <FILENAME> part.  You can use the same syntax to git diff to compare two arbitrary files from arbitrary revisions.  It’s also frequently useful to view a file from where one of your branches was at a particular date, such as:

  git show master@{2.weeks.ago}:util/TestQuantile.java

To be clear, this is where your own master branch was two weeks ago – it uses the reflog for master rather than commit dates to find the commit.

Use the git glossary

The git glossary provides a very succinct and useful summary of a lot of git concepts, and should be your first port of call if you don’t understand something in the manual pages.  Fundamentally (and perhaps contrary to its reputation)  git is built on simple ideas, and most of these can be understood from the definitions there.

One thought on “A Few git Tips”

  1. Now, if I had known ‘git log -S’ and ‘git show COMMIT:file’ I wouldn’t waste so much time :) thanks!

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>