I have just installed Trac 1.0.1 on a server that also holds a Git repository. I’d like to be able to close Trac tickets by including things like “fixes #3” in the Git commit messages. This should pretty easy—by including a post-receive
hook in my repository, I can execute some piece of code (e.g. a Python script) after each git push
to the server. But what piece of code to use?
After running around for a while and following a couple of dead ends (including the Trac Git page, which is vague on this topic, and the Git plugin, which won’t actually work (?!) until bug #7301 is fixed), I found the solution.
Connect your Git repository to Trac through the steps at “setting up a Trac environment”.
Enable the Commit Ticket Updater plugin, either through the “Admin” section of Trac or by editing trac.ini
.
Create a file called post-receive
in the hooks
directory of your Git repository, with the following content:
#!/usr/bin/ruby
ARGF.lines do |line|
fields = line.split
oldrev = fields[0]
newrev = fields[1]
refname = fields[2].chomp
if oldrev =~ /^0+$/
revspec = newrev
else
revspec = oldrev + '..' + newrev
end
other_branches = `git for-each-ref --format='%(refname)' refs/heads/ | grep -F -v "#{refname}"`
other_branches = other_branches.chomp.gsub /[\r\n]+/, ' '
commits = `git rev-parse --not #{other_branches} | git rev-list --stdin #{revspec}`
commits.each_line do |commit|
system "trac-admin .../trac changeset added '(default)' #{commit.chomp}"
end
end
Of course, replace “.../trac” with the absolute path to your Trac installation.
I’m actually using Trac through Virtualenv. If you are too, add this to the top of the file:
require 'tempfile'
def virtualenv_system(cmd)
script = Tempfile.new('post_receive')
script.write 'source .../virtualenvs/trac/bin/activate'
script.write "\n"
script.write cmd
script.close
system "bash #{script.path}"
script.unlink
end
and replace the system
call with virtualenv_system
.
Make this post-receive
file executable.
This is inspired by the approach given on the Repository Administration page, combined with this SO answer about getting all of the new commits in a post-receive script. I believe that this script, while long, behaves correctly when you are pushing multiple commits and/or pushing commits to branches other than the currently-checked-out one. (The script given on the Repository Administration page does not behave correctly in these situations—it only looks at the most recent commit message from HEAD.)
After this setup process, any Git commits that contain strings like “fixes #7” will close the corresponding tickets in Trac. You can configure this a little with the options listed on the Commit Ticket Updater page. Specifically, you might want to change the value of commit_ticket_update_envelope
; it’s not completely clear, but I think the default is set so that you have to include your commands in square brackets, like “Refactored MyAwesomeClass [fixes #42]”.