Skip to content

Tutorial for Git users

Gustavo Chaves edited this page Aug 2, 2017 · 2 revisions

=head1 Introduction

As a Git user you may be interested in enabling some hooks for your local Git repositories. In particular, you may be interested in guaranteeing that the same policies that are being enforced by the remote repositories you push to are enforced earlier when you commit locally, so that you can avoid an onerous round trip to the common repository.

=head2 User Driver Script

Git::Hooks only need a single script to drive all hooks implemented by yourself or by the plugins you enable. If you do not need to create your own hooks, but want to use just the ones that come with Git::Hooks plugins, you can use a shared script like this for all your local repositories:

#!/usr/bin/env perl
use Git::Hooks;
run_hook($0, @ARGV);

As a user, I save this script as F<$HOME/bin/githooks.pl> and make it executable.

If you invoke the driver script directly from the inside of a Git repository it should do nothing but exit normally:

$ cd /my/git/repo
$ $HOME/bin/githooks.pl
$ echo $?
0

If you invoke it from the outside though, it should die:

$ cd ..
$ $HOME/bin/githooks.pl
fatal: Not a git repository: . at /usr/share/perl5/Git.pm line 210.

=head2 User Hook Links

Now you must create symbolic links under the F<.git/hooks> directory of your repositories pointing to the common script. So, for example, if you want to enable some C and some C hooks, you would do this:

$ cd /my/git/repo/.git/hooks
$ ln -s $HOME/bin/githooks.pl pre-commit
$ ln -s $HOME/bin/githooks.pl commit-msg
$ ln -s $HOME/bin/githooks.pl pre-rebase

=head3 Automating the creation of links

However, doing it manually for every repository is cumbersome and prone to mistakes and neglect. Fortunately, there is a better way. In order to make it easy to setup your hooks, it's useful to create a repository template for Git to use when you perform a C or a C.

In Ubuntu Linux, Git's standard repository template resides in F</usr/share/git-core/templates>. If you can't find it there, read the C

You may customize one for you like this:

$ cp -a /usr/share/git-core/templates $HOME/.git-templates
$ cd $HOME/.git-templates/hooks
$ rm *
$ for i in commit-msg post-commit pre-commit pre-rebase
> do ln -s $HOME/bin/githooks.pl $i
> done

These commands copy the default template directory to F<$HOME/.git-template> (you may choose another directory), removes all sample hooks and creates symbolic links to the Git::Hooks driver script which we created above for four hooks: C, C, C, and C. These are all the hooks I'm interested in locally. If you're setting this up for a Git server you'll want to create links for other hooks, such as C or C.

You must tell Git to use your repository template instead of its default. The best way to do it is to configure it globally like this:

$ git config --global init.templatedir $HOME/.git-templates

Now, whenever you C or C a new repository, it will automatically be configured to use Git::Hooks.

=head2 User Configuration

By default Git::Hooks does nothing. At the very least, it must be configured to enable some plugins and configure them to your taste. You should read the plugins's documentation to understand them and decide which ones you would like to enable globally and which ones you would like to enable locally for particular repositories.

Here I show my personal preferences. You are encouraged to make your own variations.

This is what I have in my global Git configuration (F<$HOME/.gitconfig>):

[githooks]
        plugin = CheckLog
        plugin = CheckRewrite
        abort-commit = 0
[githooks "checklog"]
        title-max-width = 62
[githooks "checkjira"]
        jiraurl  = https://jira.cpqd.com.br
        jirauser = gustavo
        jirapass = a-very-large-and-difficult-to-crack-password
        matchlog = (?s)^\\[([^]]+)\\]

The only plugins I want enabled for every repository are C and C. The latter is simple, as it doesn't require any configuration whatsoever. With it I feel more confident to perform C<git commit --amend> and C commands knowing that I'm going to be notified in case I'm doing anything dangerous.

The C is also useful to guarantee that I'm not deviating from the common Git policies regarding the commit messages. The only thing I change from the defaults is the C, because I think 50 characters is very constraining.

I disable the C<githooks.abort-commit> option so that C and C hooks don't abort the commit in case of errors. That's because I find it easier to amend the commit than to remember to recover my carefully crafted commit message from the F<.git/COMMIT_EDITMSG> file afterwards.

The section C<githooks "checkjira"> contains some global configuration for the C plugin, which I enable only for some repositories. Since the C plugin has to connect to our JIRA server, it needs the server URL and some credentials to authenticate. The C regex makes JIRA issue keys be looked for only inside a pair of brackets at the beginning of the commit messages's title line.

I enable other plugins for specific repositories, since they depend on the context in which they are developed.

At L<CPqD|http://www.cpqd.com.br/> we use L<JIRA|http://www.atlassian.com/software/jira> and L<Gerrit|https://code.google.com/p/gerrit/>. So, for my work-related repositories I have this in their F<.git/config>:

[githooks]
        plugin = CheckJira
        plugin = GerritChangeId
[githooks "checkjira"]
        jql = project = CDS

C doesn't require any configuration. It simply inserts a C line in the messages of all commits. These are required by Gerrit.

I use C to remind me to cite a JIRA issue in every commit message. The C filter makes it accept only issues of the CDS JIRA project for this particular repository.

=head3 Disabling plugins locally

The Git configuration follows a hierarchy, reading first the system configuration (/etc/gitconfig), then the global configuration ($HOME/.gitconfig), and then the local configuration ($GIT_DIR/config). If you have some plugins enabled globally you may disable then locally by putting the following in the .git/config of a particular repository:

[githooks]
        disable = CheckJira

=head3 Disabling plugins temporarily

If you prefer the default behaviour of having your C and C abort on errors, it's sometimes useful to disable a plugin temporarily in order to do a commit that otherwise would be rejected. For instance, if you enable C's spelling checks and it rejects a commit because you used a cute-but-not-quite-right word in its message you can disable it for the duration of the commit by defining the environment variable C as C<0> like this:

CheckLog=0 git commit

You can disable any plugin in the same manner. Just define as zero (0) an environment variable homonymous to the plugin (you can use the plugin module full name or just its last component, as in the example above) for the duration of the commit and the plugin will be disabled.

Clone this wiki locally