Managing my projects’ source code I am using Git also as Mercurial. Therefore I often encounter the situation where I am creating a special branch to implement a specific user story or feature request.
Now when working on such a story branch I often enter the issue-key or a short title as a prefix for each commit message. Doing this by manually is a waste of time and error-prone and luckily for us, each of both DVCS offers us an easy API to add custom hooks to the different life-cycle events.
Commit Messages for Story Branches
Now let’s assume that we’re using an issue tracker like Jira or another similar tool to document the story so that there is an identifier like TEST-123 for the story/feature task. When we start working on the task, we’re creating a new feature branch with the name of this identifier.
This allows us to create a custom hook that fetches the branch name and prefixes each commit message with this name.
Git Example
Creating a hook in git is quite easy .. when you’re creating a new repository, git creates a set of sample hooks for you to be found in .git/hooks. To use one of the hooks simply rename the hook that matches your need and remove the sample suffix:
.git/hooks/
├── applypatch-msg.sample
├── commit-msg.sample
├── post-update.sample
├── pre-applypatch.sample
├── pre-commit.sample
├── prepare-commit-msg.sample
├── pre-rebase.sample
└── update.sample
Now let’s create a new project, initialized the repository and add a simple shell script as commit hook..
$ mkdir myproject
$ cd myproject/
$ git init
Initialized empty Git repository in /tmp/myproject/.git/
$ date >> test.txt
$ git add .
$ git commit -m "Initial release."
[master (root-commit) 461eb05] Initial release.
1 file changed, 1 insertion(+)
create mode 100644 test.txt
$ git checkout -b "Issue-123"
Switched to a new branch 'Issue-123'
$ cp .git/hooks/prepare-commit-msg.sample .git/hooks/prepare-commit-msg
Now open the .git/hooks/prepare-commit-msg in a text editor and replace the existing content with this one:
#!/bin/sh
BRANCH_NAME=$(git rev-parse --abbrev-ref HEAD)
if [ -n "$BRANCH_NAME" ] && [ "$BRANCH_NAME" != "master" ]; then
echo "[$BRANCH_NAME] $(cat $1)" > $1
fi
Now that we’ve got the hook, we should add some changes to the branch to demonstrate how our submit message is extended with the feature branch’s name:
$ date >> test.txt
$ git commit -a -m "Important feature added."
[Issue-123 18a50b5] [Issue-123] Important feature added.
1 file changed, 1 insertion(+)
$ git log
commit 18a50b53b15c12d561f9a43fface399ae748d811
Author: Micha Kops
Date: Fri Dec 7 21:59:05 2012 +0100
[Issue-123] Important feature added.
La voilà
Mercurial/Hg Example
Now let’s do something similar for mercurial .. again we’re creating a new project and initialize the repository…
$ mkdir myproject && cd myproject
$ hg init
$ date >> test.txt
$ hg ci -A -m "Initial release."
adding test.txt
test.txt
committed changeset 0:4fc464a47f2e
$ hg branch "Issue-123"
marked working directory as branch Issue-123
(branches are permanent and global, did you want a bookmark?)
Now create/edit your .hg/hgrc and add the following two lines to add a pre-commit hook:
[hooks]
precommit = python:.hg/rename-story-description.py:prefix_commit_message
Now we’re creating our hook in python – please add the following file and open it in your editor: .hg/rename-story-description.py
If you’d like to do something special then a closer look at the Mercurial Python API might be interesting.
import re,os,sys,mercurial
def prefix_commit_message(repo, **kwargs):
commitctx = repo.commitctx
def rewrite_ctx(ctx, error):
branch_name = ctx.branch()
old_text = ctx._text
ctx._text = "["+branch_name+"] "+old_text
return commitctx(ctx, error)
repo.commitctx = rewrite_ctx
Now we’re adding some changes to this branch…
$ date >> test.txt
$ hg ci -m "Important feature added."
calling hook precommit:
test.txt
committed changeset 1:2dd14dc85e1b
$ hg log
changeset: 1:2dd14dc85e1b
branch: Issue-123
tag: tip
user: Micha Kops
date: Fri Dec 07 22:28:57 2012 +0100
files: test.txt
description:
[Issue-123] Important feature added.
That’s what we wanted…
If you want to have a look which hooks do exist in your repository you may do the following
$ hg showconfig hooks
hooks.precommit=python:.hg/rename-story-description.py:prefix_commit_message
A Note on Mercurial Branches
Depending on your project and the way you’re handling your branches you might change the hook and work with bookmarks instead. With Mercurial, branches are handled differently to Git and therefore it might be better sometimes not to use a branch rather than a bookmark.
If you’re interested in some more details here I ‘d highly recommend reading Steve Losh’ excellent article A Guide to Branching in Mercurial.
Resources
-
Sarah Goff-Dupont: Story Branching and Continuous Integration: a swords-to-plowshares tale
-
Bryan O’Sullivan: Mercurial – The Definitive Guide. Handling repository events with hooks
-
Mercurial Documentation: Feature separation through named branches
-
Mercurial Documentation: Don’t treat branch names as disposable