Developers can be encouraged to do the right thing, or developers can be forced to do the right thing; however, in the end, developers need to spend time coding. So, if a good commit message is required, we can use the prepare-commit-msg hook to assist the developer.
In this example, we will create a commit message for developers that contains information about the state of the work area. It will also insert some information from a web page; this could just as well be defect information from Bugzilla for instance.
To start with this exercise, we will not be cloning a repository, but we will be creating one. For doing this, we will be using git init
, as shown in the following code. You can use git init <directory>
to create a new repository somewhere, or you can also go to a directory and execute git init
, and Git will create a repository for you.
$ git init chapter7 Initialized empty Git repository in c:/Users/Rasmus/repos/chapter7/.git/ $ cd chapter7
We have our chapter7
directory where we just initialized our repository. In this directory, the hooks are already available. Just look into the .git/hooks
directory. We will be using the prepare-commit-msg hook. Perform the following steps:
$ ls .git/hooks/ applypatch-msg.sample pre-applypatch.sample pre-rebase.sample commit-msg.sample pre-commit.sample prepare-commit-msg.sample post-update.sample pre-push.sample update.sample
prepare-commit-msg
, rename the file as shown in the following code:$ cd .git/hooks/ $ mv prepare-commit-msg.sample prepare-commit-msg $ cd ../..
prepare-commit-msg
file in you preferred editor; I prefer gVim.#!/bin/bash echo "I refuse to commit" exit 1
--allow-empty
option, you can create an empty commit as follows:$ git commit --allow-empty I refuse to commit
prepare-commit-msg
script file. You can check whether we don't have a commit by using git log -1
as follows:$ git log -1 fatal: bad default revision 'HEAD'
There is no commit, and we get an error message that we have not seen before. The message has to be there because there is no commit so far in this repository. Before we make further changes to the script, we should know that the prepare commit message hook takes some arguments depending on the situation. The first argument is always .git/COMMIT_EDITMSG
, and the second argument can be merge, commit, squash, or template, depending on the situation. We can use these in the script.
#!/bin/bash if [ "$2" == "commit" ]; then echo "Not allowed to amend" exit 1 fi
$ echo "alot of fish" > fishtank.txt $ git add fishtank.txt $ git commit -m "All my fishes are belong to us" [master (root-commit) f605886] All my fishes are belong to us 1 file changed, 1 insertion(+) create mode 100644 fishtank.txt
git commit --amend
:$ git commit --amend Not allowed to amend
#!/bin/bash if [ "$2" == "commit" ]; then echo "Not allowed to amend" exit 1 fi MESSAGE=$(curl http://whatthecommit.com | grep "<p>" | sed 's/<p>//') sed -i -r "s/# Please/$MESSAGE &/" $1:
$ echo "gravel, plants, and food" >>fishtank.txt $ git add fishtank.txt $ git commit
git log -1
, verify whether we have the commit as follows:git log -1 commit c087f75665bf516af2fe30ef7d8ed1b775bcb97d Author: Rasmus Voss <[email protected]> Date: Wed Mar 5 21:12:13 2014 +0100 640K ought to be enough for anybody
# You have the following artifacts assigned # Remove the # to add the artifact ID to the commit message #[artf23456] Error 02 when using update handler on wlan #[artf43567] Enable Unicode characters for usernames #[artf23451] Use stars instead of & when keying pword
You can extend the functionalities of the prepare commit message hook very easily, but you should bear in mind that the waiting time for fetching some information should be worth the benefits. One thing that is usually easy to check is a dirty work area.
Here, we need to use the git status
command in the prepare commit message hook, and we need to predict whether we will have modified files after the commit:
$ git status On branch master nothing to commit, working directory clean
fishtank.txt
file:$ echo "saltwater" >>fishtank.txt
git status --porcelain
to check the work area:$ git status --porcelain M fishtank.txt
git add
:$ git add fishtank.txt
git status –porcelain
:$ git status --porcelain M fishtank.txt
M
the first time we use the --porcelain
option for git status
. The porcelain
option provides a machine-friendly output that shows the state of the files for git status. The first character is the status in the staging area, whereas the second character is the status in the work area. So, MM fishtank.txt
would mean the file is modified in the work area and in the staging area. So, if you modify fishtank.txt
again, the following is the result you can expect:$ echo "sharks and oysters" >> fishtank.txt $ git status --porcelain MM fishtank.txt
git status
is MM fishtank.txt
. We can use this in the hook to tell whether the work area will have uncommitted changes after we commit. Add the following command to the prepare-commit-msg
file:for file in $(git status --porcelain) do if [ ${file:1:1} ]; then DIRTY=1 fi done if [ "${DIRTY}" ]; then sed -i -r "s/# Please/You have a dirty workarea are you sure you wish to commit ? &/" $1 fi
git status --porcelain
. Then, for each of these, we check whether there is a second character. If this is true, we will have a dirty work area after the commit. In the end, we just insert the message in the commit message so that it is available for the developer to see. Let's try and commit the change by using the following command:$ git commit
somebody keeps erasing my changes. You have a dirty workarea are you sure you wish to commit ? # Please enter the commit message for your changes. Lines starting # with '#' will be ignored, and an empty message aborts the commit. # On branch master # Changes to be committed: # modified: fishtank.txt # # Changes not staged for commit: # modified: fishtank.txt #
git log -1
as follows:$ git log -1 commit 70cad5f7a2c3f6a8a4781da9c7bb21b87886b462 Author: Rasmus Voss <[email protected]> Date: Thu Mar 6 08:25:21 2014 +0100 somebody keeps erasing my changes. You have a dirty workarea are you sure you wish to commit ?
HEAD
as follows:$ git reset --hard HEAD HEAD is now at 70cad5f somebody keeps erasing my changes.
Now, it is just a matter of finding out what suits you. Is there any information you would like to check before you commit and potentially push the code to a remote? I can think of the following options:
There are several other items, probably one for every organization or development team in the world. However, this clearly is one way of taking tedious manual work away from the developer so that he or she can focus on coding.