A git pre-commit hook script for checking gofmt and unit tests

1,427 views
Skip to first unread message

Risto Saarelma

unread,
Dec 20, 2009, 4:14:06 AM12/20/09
to golang-nuts
I wrote a pre-commit script for git that checks that all unit tests
pass and none of the .go files in the repository need a pass through
gofmt before allowing a commit to proceed. The script is in Python
since I don't know bash scripting well enough to do even this level of
complexity.

Use for whatever you like: http://gist.github.com/260411

befelemepeseveze

unread,
Dec 20, 2009, 4:46:15 AM12/20/09
to golang-nuts
On 20 pro, 10:14, Risto Saarelma <rsaar...@gmail.com> wrote:
> I wrote a pre-commit script for git that checks that all unit tests
> pass and none of the .go files in the repository need a pass through
> gofmt before allowing a commit to proceed.

AFAIK, the codereview extension in the Go tree already has the
functionality of guaranteeing all CL sources to be gofmt'ed prior to
upload.

Risto Saarelma

unread,
Dec 20, 2009, 6:30:33 AM12/20/09
to golang-nuts
On Dec 20, 11:46 am, befelemepeseveze <befelemepesev...@gmail.com>
wrote:

> AFAIK, the codereview extension in the Go tree already has the
> functionality of guaranteeing all CL sources to be gofmt'ed prior to
> upload.

Looks like it does. Hadn't noticed that before. And now I know that
the idiomatic way of checking if a file needs gofmt is running "gofmt -
l" instead of diffing the gofmt output with the original file like my
script does. Still, the codereview extension seems pretty Mercurial-
centric, while my script has some Git-specific logic, so mine may
still be useful for people who have Go stuff in Git.

Pat Notz

unread,
Dec 22, 2009, 3:56:54 PM12/22/09
to Risto Saarelma, golang-nuts
Here's a pretty simple shell script pre-commit hook for checking the
formatting. This doesn't run tests like your python script because
some of my git repositories are laid out differently. Still, this is
pretty short and simple so I thought others might find it useful.

To use this, put this in the file .git/hooks/pre-commit and make it executable.

#!/bin/sh
status=0
for file in $(git diff --cached --name-only | grep -e '\.go$'); do
badfile=$(gofmt -l $file)
if test -n "$badfile" ; then
echo "git pre-commit check failed: file needs gofmt: $badfile"
status=1
fi
done
exit $status

Kevin Ballard

unread,
Dec 22, 2009, 4:59:07 PM12/22/09
to Pat Notz, Risto Saarelma, golang-nuts
I suspect this script will fail on files with spaces in the name. The simplest solution is probably to do something like

IFS=$'\n'

before the for loop.

Pat Notz

unread,
Dec 22, 2009, 6:05:49 PM12/22/09
to Kevin Ballard, Risto Saarelma, golang-nuts
On Tue, Dec 22, 2009 at 2:59 PM, Kevin Ballard <kbal...@gmail.com> wrote:
> I suspect this script will fail on files with spaces in the name. The
> simplest solution is probably to do something like
> IFS=$'\n'
> before the for loop.

Excellent tip (your suspicion was correct). For the sake of internet
posterity, here's the corrected script. To use this, put this in the


file .git/hooks/pre-commit and make it executable.

#!/bin/sh
status=0
IFS=$'\n'

Risto Saarelma

unread,
Dec 23, 2009, 3:22:28 PM12/23/09
to golang-nuts
On Dec 22, 10:56 pm, Pat Notz <patn...@gmail.com> wrote:
> Here's a pretty simple shell script pre-commit hook for checking the
> formatting.  This doesn't run tests like your python script because
> some of my git repositories are laid out differently.  Still, this is
> pretty short and simple so I thought others might find it useful.

Doesn't this check the working directory instead of the staging area?
Meaning that if you gofmt a file going in the commit in the working
dir but don't "git add" it after the formatting, the check will pass,
but an un-goformatted file from the staging area will be committed?

Kevin Ballard

unread,
Dec 23, 2009, 4:30:35 PM12/23/09
to Risto Saarelma, golang-nuts
That's a good point.
Indeed you are correct. Here is a revised script that fixes this issue. I also added some extra quoting in places where, while I'm not certain its required, I believe it may be in the case of files with spaces and certainly won't hurt:

#!/bin/sh
status=0
IFS=$'\n'
for file in $(git diff --cached --name-only | grep -e '\.go$'); do
   badfile="$(git --no-pager show :"$file" | gofmt -l)"
   if test -n "$badfile" ; then
       echo "git pre-commit check failed: file needs gofmt: $file"
       status=1
   fi
done
exit $status

Julian Phillips

unread,
Dec 23, 2009, 8:20:24 PM12/23/09
to golang-nuts
On Dec 23, 9:30 pm, Kevin Ballard <kball...@gmail.com> wrote:
> That's a good point.
>
> On Wed, Dec 23, 2009 at 3:22 PM, Risto Saarelma <rsaar...@gmail.com> wrote:
> > On Dec 22, 10:56 pm, Pat Notz <patn...@gmail.com> wrote:
> > > Here's a pretty simple shell script pre-commit hook for checking the
> > > formatting.  This doesn't run tests like your python script because
> > > some of my git repositories are laid out differently.  Still, this is
> > > pretty short and simple so I thought others might find it useful.
>
> > Doesn't this check the working directory instead of the staging area?
> > Meaning that if you gofmt a file going in the commit in the working
> > dir but don't "git add" it after the formatting, the check will pass,
> > but an un-goformatted file from the staging area will be committed?
>
> Indeed you are correct. Here is a revised script that fixes this issue. I
> also added some extra quoting in places where, while I'm not certain its
> required, I believe it may be in the case of files with spaces and certainly
> won't hurt:

Having found this useful little script, I thought I would just post
back the slightly tweaked version that I am actually using which also
checks the initial commit:

#!/bin/sh
status=0
IFS=$'\n'
if git rev-parse HEAD >/dev/null 2>&1; then
FILES=$(git diff --cached --name-only | grep -e '\.go$');
else
FILES=$(git ls-files -c | grep -e '\.go$');
fi
for file in $FILES; do

Reply all
Reply to author
Forward
0 new messages