diff --git a/.githooks/pre-commit b/.githooks/pre-commit
new file mode 100755
index 0000000000000000000000000000000000000000..3ae5c2a03a4045e13a7c805b0d0f9e9ab2e759a0
--- /dev/null
+++ b/.githooks/pre-commit
@@ -0,0 +1,334 @@
+#!/usr/bin/env bash
+#=============================================================================
+# Copyright 2010-2011 Kitware, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#=============================================================================
+
+die() {
+	echo 'pre-commit hook failure' 1>&2
+	echo '-----------------------' 1>&2
+	echo '' 1>&2
+	echo "$@" 1>&2
+	exit 1
+}
+
+zero='0000000000000000000000000000000000000000'
+
+#-----------------------------------------------------------------------------
+# Check for committer identity.
+advice='
+Use the commands
+
+	git config --global user.name '\''Your Name'\''
+	git config --global user.email '\''you@yourdomain.com'\''
+
+to introduce yourself to Git before committing.'
+
+# Ensure name and email are available.
+git config --get user.name > /dev/null &&
+git config --get user.email > /dev/null ||
+die 'Identity not configured!' "$advice"
+
+# Validate the name and email.
+git config --get user.name | grep ' ' > /dev/null ||
+die 'Set user.name to your Real Name (with a space), not a userid.' "$advice"
+git config --get user.email | grep '^[^@]*@[^@]*$' > /dev/null ||
+die 'Set user.email to an email address (userid@validdomain.com).' "$advice"
+
+#-----------------------------------------------------------------------------
+# Check content that will be added by this commit.
+
+if git rev-parse --verify -q HEAD > /dev/null; then
+	against=HEAD
+else
+	# Initial commit: diff against an empty tree object
+	against=4b825dc642cb6eb9a060e54bf8d69288fbee4904
+fi
+
+# Merge ("git commit" after "git merge" with conflicts or --no-commit)
+merge_head=$(git rev-parse -q --verify MERGE_HEAD) || merge_head=''
+
+# Disallow non-ascii file names.  The printable range starts at the
+# space character and ends with tilde.
+if test "$(git diff --cached --name-only --diff-filter=A -z $against |
+	   LC_ALL=C tr -d '[ -~]\0')"; then
+	die 'Non-ascii file names may not be added:
+'"$(git diff --cached --name-only --diff-filter=A $against)"
+fi
+
+#-----------------------------------------------------------------------------
+# Builtin whitespace checks.
+bad=$(git diff-index --check --cached $against -- --ignore-space-at-eol) || die "$bad"
+
+# Approximate whitespace=tab-in-indent check with Git < 1.7.2.
+git --version | grep -q " \(1\.[0-6]\|1\.7\.[01]\)" &&
+approx_tab_in_indent=true || approx_tab_in_indent=false
+check_tab() {
+	lines=$(git diff-index -p --cached $against -- "$1" |
+	        grep '^+	') &&
+	echo "$lines" |
+	while read line; do
+		echo "$1: tab in indent." &&
+		echo "$line"
+	done
+}
+
+# Reject addition of a line without a newline at end-of-file.
+check_no_lf_at_eof() {
+	lines=$(git diff-index -p --cached $against -- "$1" | tail -2)
+	if echo "$lines" | head -1 | grep -q '^+' &&
+	   echo "$lines" | tail -1 | grep -q '^\\ No newline'; then
+		echo "$1: No newline at end of file"
+	fi
+}
+
+# Custom whitespace checks.
+check_whitespace() {
+	ws=$(git check-attr whitespace -- "$file" |
+	     sed 's/^[^:]*: whitespace: //')
+	if $approx_tab_in_indent; then
+		case ",$ws," in
+			*,tab-in-indent,*) check_tab "$1" ;;
+		esac
+	fi
+	case ",$ws," in
+		*,no-lf-at-eof,*) check_no_lf_at_eof "$1" ;;
+	esac
+}
+bad=$(git diff-index --name-only --cached $against -- |
+while read file; do
+	check_whitespace "$file"
+done)
+test -z "$bad" || die "$bad"
+
+#-----------------------------------------------------------------------------
+# Check file modes and sizes.
+mode_looks_exe() {
+	case "$1" in
+		*.bat) return 0 ;;
+		*.cmd) return 0 ;;
+		*.exe) return 0 ;;
+		*.com) return 0 ;;
+	esac
+	git cat-file blob "$2" | head -1 | grep "^#\!/" > /dev/null
+}
+mode_not_exe () {
+	echo "The file '$file' has looks executable but does not have an executable mode."
+}
+mode_bad_exe () {
+	echo "The file '$file' has executable mode but does not look executable."
+}
+mode_non_file () {
+	echo "The path '$file' has a non-file mode."
+}
+check_mode() {
+	case "$dst_mode" in
+		100755) mode_looks_exe "$file" "$dst_obj" || mode_bad_exe ;;
+		100644) mode_looks_exe "$file" "$dst_obj" && mode_not_exe ;;
+		160000) ;;
+		*)	mode_non_file ;;
+	esac
+}
+
+size_max_KiB=$(git config hooks.MaxObjectKiB)
+test -n "$size_max_KiB" || size_max_KiB=1024
+size_too_large_once=""
+size_too_large_once() {
+	test -z "$size_too_large_once" || return ; size_too_large_once=done
+	echo 'At least one file is staged for commit with size larger than the limit.
+We prefer to keep large files out of the main source tree, especially
+binary files that do not compress well.  This hook disallows large files.
+
+If it is vital that this file enters the repository, speak to a dev lead.
+Remember that unit tests should typically not require loading files (see
+http://www.mantidproject.org/Unit_Test_Good_Practice#Using_files_in_Unit_tests).
+'
+# Instructions for allowing ESSENTIAL files only:
+#   A limit for specific files or patterns may be set in ".gitattributes" with
+#   the "hooks.MaxObjectKiBYYMMDD" attribute (where YYMMDD is the current date).
+#   For example, the line
+#
+#     *.c              hooks.MaxObjectKiB121207=2048
+#
+#   sets a limit of 2048 KiB for C source files, but WILL ONLY WORK on the date
+#   matching the entry. This avoids the previous behaviour that once set the
+#   hook was forever disabled if the entry was not removed afterwards.
+#   See "git help attributes" for details on the .gitattributes format.
+}
+size_too_large() {
+	size_too_large_once
+	echo "The path '$file' has size $file_KiB KiB, greater than allowed $max_KiB KiB."
+}
+size_validate_max_KiB() {
+	test "$max_KiB" -ge "0" 2>/dev/null && return 0
+	echo "The path '$file' has invalid attribute \"hooks-MaxObjectKiB=$max_KiB\"."
+	return 1
+}
+check_size() {
+	test "$dst_obj" != "$zero" || return
+	datesuffix=`date +%y%m%d`
+	hookname='hooks.MaxObjectKiB'$datesuffix
+	max_KiB=$(git check-attr $hookname -- "$file" |
+		  sed "s/^[^:]*: ${hookname}: //")
+	case "$max_KiB" in
+		'unset')       return ;; # No maximum for this object.
+		'set')         max_KiB="$size_max_KiB" ;; # Use local default.
+		'unspecified') max_KiB="$size_max_KiB" ;; # Use local default.
+		*) size_validate_max_KiB || return ;;
+	esac
+	if test "$max_KiB" -gt "0"; then
+		file_KiB=$(expr '(' $(git cat-file -s "$dst_obj") + 1023 ')' / 1024)
+		test "$file_KiB" -le "$max_KiB" || size_too_large
+	fi
+}
+
+short_commit() {
+	git rev-parse --short "$1" 2>/dev/null || echo "$1"
+}
+
+lookup_config_module_update() {
+	update=$(git config "hooks.$1.update")
+
+	# Special-case "true" to accept any update.
+	test "{$update}" = "{true}" && echo '.' && return
+
+	# Format is "aaaaaa..bbbbbb" for update aaaaaa => bbbbbb.
+	# Convert to regex "^aaaaaa[a-z0-9]* bbbbbb[a-z0-9]*$".
+	sha1ex='[a-z0-9][a-z0-9][a-z0-9][a-z0-9][a-z0-9][a-z0-9][a-z0-9]*'
+	regex='^\('"$sha1ex"'\)\.\.\('"$sha1ex"'\)$'
+	echo "$update" |
+	sed -n "/$regex/ {s/$regex/"'^\1[a-z0-9]* \2[a-z0-9]*$/;p;}' |
+	grep '.' # Return false if result is empty.
+}
+
+check_module() {
+	enabled=$(git config --get --bool hooks.submodule) || enabled=true
+	test "$enabled" = "false" && return
+
+	# Allow merged submodule updates.
+	test -n "$merge_head" &&
+	merge_obj=$(git rev-parse -q --verify "$merge_head:$file") &&
+	test "$merge_obj" = "$dst_obj" && return
+
+	# Allow module-only commits without extra work.
+	test -z "$diffs_normal" && return
+
+	# Check if module update is allowed with other changes.
+	allow=$(lookup_config_module_update "$file") || allow='none'
+	if echo "$src_obj $dst_obj" | grep "$allow" > /dev/null; then
+		return
+	fi
+	src_short=$(short_commit "$src_obj")
+	dst_short=$(short_commit "$dst_obj")
+	echo 'A submodule link is staged for commit (among other changes):
+
+  "'"$file"'"  '"$src_short => $dst_short"'
+
+This may occur by accident so we require an extra step to commit.
+If you intend to include this change in your commit, run
+
+  git config "hooks.'"$file"'.update" '"$src_short..$dst_short"'
+
+to explicitly allow the change and try the commit again.  Otherwise run
+
+  git reset HEAD -- "'"$file"'"
+
+to unstage the change.  Furthermore, if you did not intend to modify
+the submodule at all, also run
+
+  git submodule update -- "'"$file"'"
+
+to checkout the current version of the submodule in your work tree.
+Test your changes again to see if they still work with the module.
+Finally, try the commit again.
+'
+	return 1
+}
+
+check_module_rewind() {
+	parent_name="$1"
+	parent_commit="$2"
+	base=$(GIT_DIR="$file/.git" \
+	       git merge-base $src_obj $dst_obj 2>/dev/null) || base=''
+	test "$base" != "$dst_obj" && return
+	parent_short=$(short_commit "$parent_commit")
+	src_short=$(GIT_DIR="$file/.git" short_commit "$src_obj")
+	dst_short=$(GIT_DIR="$file/.git" short_commit "$dst_obj")
+	echo 'This commit would rewind a submodule link:
+
+  "'"$file"'"  '"$src_short => $dst_short"'
+
+from the newer version in '"$parent_name"' ('"$parent_short"').  Run
+
+  git reset '"$parent_name"' -- "'"$file"'"
+  git submodule update -- "'"$file"'"
+
+to checkout the newer version of the submodule in your work tree.
+Then try the commit again.
+'
+	return 1
+}
+
+diffs=$(git diff-index --cached $against -- |
+        sed -n '/^:[^:]/ {s/^://;p;}')
+diffs_normal=$(echo "$diffs" | grep -v '^...... 160000')
+diffs_module=$(echo "$diffs" | grep    '^...... 160000')
+bad=$(
+test -n "$diffs_normal" && echo "$diffs_normal" |
+while read src_mode dst_mode src_obj dst_obj status file; do
+	if test "$src_mode" != "$dst_mode" -a "$dst_mode" != "000000"; then
+		check_mode
+	fi
+	if test "$dst_mode" != "160000" -a "$dst_mode" != '000000'; then
+		check_size
+	fi
+done
+test -n "$diffs_module" && echo "$diffs_module" |
+while read src_mode dst_mode src_obj dst_obj status file; do
+	check_module_rewind HEAD "$against" &&
+	check_module ||
+	break
+done
+)
+test -z "$bad" || die "$bad"
+
+#-----------------------------------------------------------------------------
+# Merge checks.
+if test -n "$merge_head"; then
+	merge_diffs=$(git diff-index --cached $merge_head -- |
+	              sed -n '/^:[^:]/ {s/^://;p;}')
+else
+	merge_diffs=''
+fi
+merge_diffs_normal=$(echo "$merge_diffs" | grep -v '^...... 160000')
+merge_diffs_module=$(echo "$merge_diffs" | grep    '^...... 160000')
+bad=$(
+test -n "$merge_diffs_module" && echo "$merge_diffs_module" |
+while read src_mode dst_mode src_obj dst_obj status file; do
+	check_module_rewind MERGE_HEAD "$merge_head" ||
+	break
+done
+)
+test -z "$bad" || die "$bad"
+
+#-----------------------------------------------------------------------------
+# Style hooks.
+#. "$GIT_DIR/hooks/pre-commit-style"
+
+#-----------------------------------------------------------------------------
+# Chain to project-specific hook.
+#. "$GIT_DIR/hooks/hooks-chain.bash"
+#hooks_chain pre-commit "$@"
+
+# vim: set filetype=sh tabstop=8 softtabstop=8 shiftwidth=8 noexpandtab :