Last active
August 23, 2023 17:44
-
-
Save jeremy-w/818b2980f0d9768da83249458aa67678 to your computer and use it in GitHub Desktop.
A git hook to tag your commits with the JIRA issue ID. Requires a git client that runs the hook like Git Fork, Git Kraken, or anything TUI/CLI.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# | |
# jira-prepare-commit-msg: Easy commit tagging for Jira | |
# | |
# https://gist.github.com/jeremy-w/818b2980f0d9768da83249458aa67678 | |
# | |
# If you name your branch to include the Jira issue key, | |
# this hook will automatically add the issue key to your commit messages. | |
# This makes it easy to trace work back to Jira, and it also means | |
# your commits show up in the Activity tab for that issue. | |
# | |
# To enable this hook: | |
# | |
# cd gitRepoParentDirectory | |
# ln -sf PATH/TO/jira-prepare-commit-msg */.git/hooks/prepare-commit-msg | |
# | |
# Execution context: | |
# | |
# - called by `git commit` in the git directory | |
# | |
# Parameters: | |
# | |
# - $1 is the filename holding the commit message. It already has stuff in it. | |
# - $2 is the commit message source (message, template, squash, commit, ...) | |
# - $3 is a commit ID - it's only present committing with -c, -C, or --amend | |
# | |
# The hook's purpose is to edit the commit | |
# message file, $1. If the hook fails with a non-zero status, | |
# the commit is aborted. | |
# | |
# Jeremy W. Sherman (@jeremy-w on GitHub) | |
# 2019-04-05 | |
# | |
# 2020-05-19: | |
# * NEW: Use jira.baseUrl config variable, if present, to include a link rather | |
# than just the issue ID in the commit messages. | |
# Example: git config --set jira.baseUrl https://YourCorp.atlassian.net/browse | |
# | |
# 2021-11-02: | |
# * FIXED: With newer git versions, the first commit on a branch was not | |
# picking up the branch name. | |
# | |
# 2023-08-23: | |
# * FIXED: A detached head rebase only saw the branch as HEAD, so failed to | |
# read the ticket ID from the branch name. Now checks several files for the | |
# branch name; see the rebasing-branch function for details. | |
PROGNAME=$0 | |
function debug() { | |
# comment out next line to shut it up, uncomment to get some output | |
# echo "$PROGNAME: $*" >&2 | |
: # empty functions aren't allowed, so here's a NOP | |
} | |
debug "Begun. Args: $*" | |
# Project Key format is configurable, but defaults to roughly this. | |
# https://confluence.atlassian.com/adminjiraserver/changing-the-project-key-format-938847081.html | |
ISSUE_REGEX="([A-Z]{1}[A-Z0-9_]{1,}-[0-9]{1,})" | |
if test "x$ISSUE_ID" = x; then | |
# Infer from tail end of branch name. | |
# While rev-parse is more accurate, it used to not work during rebase, but on | |
# recent versions, reports HEAD, while describe reports a hash alone. | |
# See: https://github.com/git/git/blob/041f5ea1cf987a4068ef5f39ba0a09be85952064/contrib/completion/git-prompt.sh#L446-L447 | |
branch=$(git rev-parse --abbrev-ref HEAD || git describe --contains --all --always) | |
debug "Issue ID unset; inferring from branch: $branch" | |
if [[ "$branch" = "HEAD" ]]; then | |
debug "Branch is just HEAD. Scrounging around." | |
# See answer: https://stackoverflow.com/a/59115583 | |
# To question: https://stackoverflow.com/questions/34213120/find-branch-name-during-git-rebase | |
rebasing-branch() { | |
for location in rebase-merge rebase-apply BISECT_HEAD; do | |
path=$(git rev-parse --git-path ${location}) | |
if test -d "${path}"; then | |
revision=$(<"${path}/head-name") | |
echo "${revision##refs/heads/}" | |
return 0 | |
fi | |
done | |
} | |
branch="$(rebasing-branch)" | |
fi | |
if [[ "$branch" =~ $ISSUE_REGEX$ ]]; then | |
ISSUE_ID=${BASH_REMATCH[1]} | |
debug "Inferred ISSUE_ID=$ISSUE_ID" | |
fi | |
fi | |
case "$2,$3" in | |
merge,) | |
debug "Commenting out those conflicts lines for ya." | |
/usr/bin/perl -i.bak -ne 's/^/# /, s/^# #/#/ if /^Conflicts/ .. /#/; print' "$1" | |
;; | |
# The checks here are: | |
# - do we have an issue id to inject? | |
# - is there already one in the message body that's not commented out? | |
# (this avoids treating the ID in the branch name as an already-present ID) | |
*) if test \! "x$ISSUE_ID" = x && ! grep "^[^#]" "$1" | grep -E -q "$ISSUE_REGEX"; then | |
debug "Detected no issue ID in commit body. Adding it now as $ISSUE_ID." | |
# If we have URL info, then use that. | |
JIRA_ISSUE_URL_BASE=$(git config --get jira.baseUrl) | |
if test \! "x$JIRA_ISSUE_URL_BASE" = x; then | |
debug "Detected JIRA_ISSUE_URL_BASE of $JIRA_ISSUE_URL_BASE." | |
ISSUE_ID="$JIRA_ISSUE_URL_BASE/$ISSUE_ID" | |
debug "ISSUE_ID has been updated to $ISSUE_ID." | |
fi | |
# Place the issue ID after the commit message. | |
printf '\n\n%s\n' "$ISSUE_ID" >>"$1" | |
# If GIT_EDITOR is literally a colon character, there is no editor. | |
# Otherwise, append some comments to help the person editing the | |
# commit message. | |
if test \! "$GIT_EDITOR" = :; then | |
debug "Running interactive - adding some Smart Commit Syntax advice." | |
cat <<EOT >>"$1" | |
# You can log time, add comments, and trigger | |
# transitions using Smart Commit syntax. | |
# | |
# Example: | |
# JRA-123 JRA-234 JRA-345 #resolve #time 2d 5h #comment Task completed ahead of schedule | |
# | |
# See: <https://confluence.atlassian.com/fisheye/using-smart-commits-960155400.html> | |
EOT | |
fi | |
else | |
debug "Either no ISSUE_ID was detected, or there appears to be an issue ID already in the commit body." | |
debug " ISSUE_REGEX=$ISSUE_REGEX" | |
debug " ISSUE_ID=$ISSUE_ID" | |
debug " Commit body:\n$(cat "$1")" | |
fi ;; | |
esac | |
debug "Done." |
git-tracker supports Pivotal Tracker-style IDs, which are just numbers, but it won't include the project key that Jira prefixes to the issue ID. That's why this exists. :)
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
You might have to make the
.git/hooks/prepare-commit-msg
executable:chmod +x .git/hooks/prepare-commit-msg
Update! Do not use Git tracker. It does not work as Jeremy mentioned below.
Git tracker: to enable Git clients to add the Jira ticket ID usegit-tracker
-brew install git-tracker
-git-tracker init
Tested the above script in Github Desktop Client and it works.