At work we use git as source code management and Mantis as issue tracker.
In order to keep track of code changes related to a certain issue, I use a git hook to post the commit message to the Mantis issue.

This is how I commit a change:

git commit -am "Updated TID #3012"

The part TID #3012 provides the ticket/bug ID.

First I configure the git post-commit hook in the project’s .git directory:

echo "#!/bin/bash\n$HOME/bin/mantis_commit.rb -u <mantis-loginname> -p <mantis-password>" >> PROJECT/.git/hooks/post.commit
chmod 755 PROJECT/.git/hooks/post.commit

This is the ruby script which does the actual work:

#!/usr/bin/ruby
# Project: Add a note to a specific Mantis ticket.
# Date: 2012-05-23
# Authors: Nicholas Stallard (hexeract.wordpress.com), Holger Widmann (https://devnotcorp.wordpress.com)
require 'optparse'
require 'ostruct'
require 'rubygems'
require 'mechanize'

# Set base URL.
url = "https://lea.innovidata.com/"
login_url = url + "login.php"
note_url = url + "bugnote_add.php"
view_url = url + "view.php"
commit_msg = "git show --stat "

# Set default options.
opts = OpenStruct.new
opts.user = ""
opts.pass = ""
opts.tid = ""
opts.rev = "HEAD"

# Specify options.
options = OptionParser.new do |options|
 options.banner = "Usage: "+ File.basename($0) +" [options]"
 options.separator "Mandatory options:"
 options.on("-u", "--username USER", "Login name") {|u| opts.user = u}
 options.on("-p", "--password PASS", "Login password") {|p| opts.pass = p}
 options.separator "Optional options:"
 options.on("-t", "--ticket-id TID", "Ticket ID - taken from the commit message by default") {|t| opts.tid = t}
 options.on("-r", "--revision REVISION", "Revision - defaults to 'HEAD'") {|r| opts.rev = r}
 options.separator "General options:"
 options.on_tail("-h", "--help", "Show this message") do
 puts options
 exit
 end
end

# Show usage if no arguments are given.
if (ARGV.empty?)
 puts options
 exit
end

# Parse options.
begin
 options.parse!
rescue
 puts options
 exit
end

# Exit upon <control-c>.
trap("INT") { exit 1 }

# Get commit message.
commit_msg = commit_msg + opts.rev + " 2>/dev/null"
note = `#{commit_msg}`
if $?.exitstatus > 0
 puts "An error occured. Check revsion '#{opts.rev}'."
 exit 1
end

if opts.tid == ""
 note =~ /TID ?#([0-9]+)/
 opts.tid = $1
end

if opts.tid == "" || opts.tid == nil
 puts "An error occured. Check commit message of revsion '#{opts.rev}' " +
 "for a valid ticket ID (e.g. TID #0000)."
 exit 1
end

# Set up the user agent.
agent = Mechanize.new
agent.history.max_size = 0
agent.user_agent_alias = 'Mac Safari'
agent.read_timeout = 3

# Lgin to the site.
login_url = login_url + "?username=" + opts.user + "&password=" + opts.pass
page = agent.get(login_url)

# Go to specified ticket.
page = agent.get(view_url + "?id=" + opts.tid)

# Get security token.
token = page.form_with('bugnoteadd').field_with('bugnote_add_token').value

# Check for errors.
if token == nil || token == ""
 puts "An error occured. Check login (username/password) and TID##{opts.tid}."
 exit 1
end

# Add a note to specified ticket.
note_url = note_url + "?bugnote_add_token=" + token + "&bug_id=" + opts.tid +
 "&private=on&bugnote_text=" + note
#page = agent.get(note_url)
agent.post(note_url, {
 "bugnote_add_token" => token,
 "bug_id" => opts.tid,
 "bugnote_text" => note,
 "private" => "on"
})