Reputation: 9262
I need some help with a Bash script that will automatically add the git's branch name as a hash in commit messages.
Upvotes: 139
Views: 92021
Reputation: 638
my bash add branch name and version from VERSION file around commit text
#!/bin/bash
#вторая версия, умеет вытаскивать текст коммита сообщений вида:
# "$BRANCH текст ($VERSION)"
# "текст ($VERSION)"
# "$BRANCH текст"
# "текст"
#долбанный баш, перед и после = нельзя ставить пробелы
COMMIT_MSG_FILE=$(echo $1 | head -n1 | cut -d " " -f1)
VERSION_FROM_FILE=$(head -n 1 version)
COMMIT_MSG_TEXT=$(cat "$COMMIT_MSG_FILE" | sed -r 's/.*PPP-[0-9]{0,6} (.*) ?/\1/') #убираем имя ветки если оно есть
COMMIT_MSG_TEXT=$(echo "$COMMIT_MSG_TEXT" | sed -r 's/(.* )\(.*\)/\1/') #убираем версию если она есть
COMMIT_MSG_TEXT=$(echo "$COMMIT_MSG_TEXT" | xargs) #это обычный trim
echo "текст коммита $COMMIT_MSG_TEXT"
if [ -z "$BRANCHES_TO_SKIP" ]; then #в этих ветках ничего не подставляем
BRANCHES_TO_SKIP=(master develop test)
fi
BRANCH_NAME=$(git symbolic-ref --short HEAD)
BRANCH_NAME="${BRANCH_NAME##*/}" #что тут происходит хз, какое то комбо на фаталити
echo -n "$BRANCH_NAME $COMMIT_MSG_TEXT ($VERSION_FROM_FILE)" > $COMMIT_MSG_FILE
create new task in gradle(kotlin) with automatic install pre-commit-msg hook
task<Copy>("installGitHook") {
group = "verification"
description = "Install Pre-commit linting hook"
from("gradle/prepare-commit-msg")
into(".git/hooks")
// Kotlin does not support octal litterals
fileMode = 7 * 64 + 7 * 8 + 7
}
tasks.named("assemble") { dependsOn("installGitHook") }
Upvotes: 0
Reputation: 21
You can use git prepare-commit-msg hook for this.
Hook can look like this:
# Get the currently checked-out branch name
BRANCH_NAME=$(git branch | grep '*' | sed 's/* //')
# Get the commit message, removing lines that start with a #
MESSAGE=$(cat "$1" | sed '/^#.*/d')
# Check if the commit message is non-empty
if [ -n "$MESSAGE" ]
then
# Add the branch name and the commit message
echo "$BRANCH_NAME: $MESSAGE" > "$1"
else
echo "Aborting commit due to empty commit message."
exit 1
fi
You probably don't want to include the branch name when committing merges, as default merge comment already includes branch names. When git does merge - it adds MERGE_HEAD file into the .git folder. So we can use that to exit hook before prepending branch name.
# Check if the MERGE_HEAD file is present
if [ -f ".git/MERGE_HEAD" ]
then
exit 0
fi
Full hook can be fetched from the gist.
Git hooks work per repository, so you will need to copy the hook file into the .git/hooks directory of each repository you want to use it in. To automate the process of adding the git hook to multiple repositories, you can run next script in the root folder of your repositories.
You can fetch the script from gist to the root folder like this:
curl -s "https://gist.githubusercontent.com/wolf6101/a90126e4b47a943e0235861516236eb3/raw/2f505db26d8adbabab9b93a8bb990ab42b2fb55c/apply-git-hooks.sh" -o "apply-git-hooks.sh"
To add hook:
sh apply-git-hooks.sh
To remove hook:
sh apply-git-hooks.sh remove
So now when you commit to the branch with the name ABC-123, like this:
git commit -m "I wrote something incredible, check this out"
You will get "ABC-123: I wrote something incredible, check this out"
This will work for commits via GUI as well.
Upvotes: 2
Reputation: 6614
Piecing together the excellent answers here, and adding a few tweaks, my .git/hooks/prepare-commit-msg
script takes a branch name such as feature/ABC-#123-feature-title
and outputs ABC #123:
COMMIT_MSG=$1
REPLACE_DELIMETER=true
FIRST_LINE=$(head -n1 $COMMIT_MSG)
addBranchName() {
BRANCH_NAME=$(git branch | grep '*' | sed 's/* //') # get the branch name (e.g. `feature/ABC-#123-feature-title`)
NAME=${BRANCH_NAME##*/} # get everything after the last slash (e.g. `ABC-#123-feature-title`)
DELIMITER=$(echo $NAME | grep -o '[-_]' | head -n1) # get the character that separates the parts (e.g. `-`)
FEATURE_ID=$(echo $NAME | cut -d $DELIMITER -f 1,2) # get the first two parts of the name, split by the delimeter found in the branch name (e.g. `ABC-#123`)
if [ "$REPLACE_DELIMETER" = true ]; then
FEATURE_ID=$(echo $FEATURE_ID | sed "s/$DELIMITER/ /g") # replace the delimiter if `REPLACE_DELIMETER` is set to true (e.g. `ABC #123`)
fi
echo "$FEATURE_ID: $(cat $COMMIT_MSG)" > $COMMIT_MSG # prepend the name and parse the existing commit message (for instance commented out commit details)
}
if [ -z "$FIRST_LINE" ]; then # check that this is not an amend by checking that the first line is empty
addBranchName
fi
Upvotes: 1
Reputation: 845
I adapted this for my needs:
#!/bin/bash
# hook arguments
COMMIT_MSG_FILE=$1
COMMIT_SOURCE=$2
SHA1=$3
BRANCH_NAME=$(git branch --show-current)
# check branch name isn’t empty (typical e.g. during rebase)
if [ -n "$BRANCH_NAME" ]
then
# check that this is a regular commit
if [ "$COMMIT_SOURCE" = "message" ] || [ -z "$COMMIT_SOURCE" ]
then
sed -r -i "1!b;/^(fixup|squash)/! s@^@$BRANCH_NAME @" $COMMIT_MSG_FILE # insert branch name at the start of the commit message file
fi
fi
Copy this snipped in a file called prepare-commit-msg
inside your repos .git/hooks
folder.
This should add the branch name in the case of git commit
, git commit -m …
and do nothing in case of merge, rebase etc.
Upvotes: 5
Reputation: 1454
I edited this answer (https://stackoverflow.com/a/17270862/9266796) so it also works for branches that contain slashes in their name, using @
instead of /
as a sed
separator. Getting the branch name is also simpler now with git branch --show-current
. I also moved the branch name to the bottom of the commit message since it makes more sense that the actual title of the message is what you see first.
The file should still be called .git/hooks/prepare-commit-msg
.
#!/bin/bash
branchName=$(git branch --show-current)
firstLine=$(head -n1 $1)
if [ -z "$firstLine" ] ;then #Check that this is not an amend by checking that the first line is empty
sed -i "1s@^@\n\n$branchName@" $1 #Insert branch name at the end of the commit message file
fi
Upvotes: 5
Reputation: 786
In case you want the JIRA ticket added to the commit message use the script bellow.
Commit message something like PROJECT-2313: Add awesome feature
This requires your branch name to start with the jira Ticket.
This is a combination of this solutions:
It is modified for OS X, with the sed -i '.bak'
and it works as well from SourceTree.
https://gist.github.com/georgescumihai/c368e199a9455807b9fbd66f44160095
#!/bin/sh
#
# A hook script to prepare the commit log message.
# If the branch name it's a jira Ticket.
# It adds the branch name to the commit message, if it is not already part of it.
branchPath=$(git symbolic-ref -q HEAD) #Somthing like refs/heads/myBranchName
branchName=${branchPath##*/} #Get text behind the last / of the branch path
regex="(PROJECTNAME-[0-9]*)"
if [[ $branchName =~ $regex ]]
then
# Get the captured portion of the branch name.
jiraTicketName="${BASH_REMATCH[1]}"
originalMessage=`cat $1`
# If the message already begins with PROJECTNAME-#, do not edit the commit message.
if [[ $originalMessage == $jiraTicketName* ]]
then
exit
fi
sed -i '.bak' "1s/^/$jiraTicketName: /" $1 #Insert branch name at the start of the commit message file
fi
Upvotes: 8
Reputation: 96016
If you want to make it global (for all projects):
Create git-msg
file with the content of shytikov's answer, and put it in some folder:
mkdir -p ~/.git_hooks
# make it executable
chmod a+x ~/.git_hooks/commit-msg
Now enable hooks:
git config --global init.templatedir '~/.git_hooks'
and git init
again in each project you want to use it.
Upvotes: 5
Reputation: 41
I was having issues getting these solutions to work on MacOS due to the fact that it uses BSD sed
instead of GNU sed
. I managed to create a simple script that does the job though. Still using .git/hooks/pre-commit
:
#!/bin/sh
BRANCH=$(cat .git/HEAD | cut -d '_' -f2)
if [ ! -z "$BRANCH" ]
then
echo "$BRANCH" > "/Users/username/.gitmessage"
else
echo "[JIRA NUMBER]" > "/Users/username/.gitmessage"
fi
This assumes a branch naming standard similar to functional-desc_JIRA-NUMBER
. If your branch name is only your Jira ticket number you can simply get rid of everything from the pipe to the f2. It also requires that you have a file named .gitmessage
in your home directory.
Upvotes: 2
Reputation: 12735
You can do it with a combination of the prepare-commit-msg and pre-commit hooks.
.git/hooks/prepare-commit-msg
#!/bin/sh
BRANCH=`git branch | grep '^\*' | cut -b3-`
FILE=`cat "$1"`
echo "$BRANCH $FILE" > "$1"
.git/hooks/pre-commit
#!/bin/bash
find vendor -name ".git*" -type d | while read i
do
if [ -d "$i" ]; then
DIR=`dirname $i`
rm -fR $i
git rm -r --cached $DIR > /dev/null 2>&1
git add $DIR > /dev/null 2>&1
fi
done
Set permissions
sudo chmod 755 .git/hooks/prepare-commit-msg
sudo chmod 755 .git/hooks/pre-commit
Upvotes: 32
Reputation: 1374
Inspired by Tim's answer which builds upon the top answer, it turns out the prepare-commit-msg hook takes as an argument what kind of commit is occurring. As seen in the default prepare-commit-msg if $2 is 'merge' then it is a merge commit. Thus the case switch can be altered to include Tim's addBranchName() function.
I've included my own preference for how to add the branch name, and all the uncommented parts of the default prepare-commit-msg.sample
hook.
prepare-commit-msg
#!/bin/sh
addMyBranchName() {
# Get name of current branch
NAME=$(git branch | grep '*' | sed 's/* //')
# First blank line is title, second is break for body, third is start of body
BODY=`cut -d \| -f 6 $1 | grep -v -E .\+ -n | cut -d ':' -f1 | sed '3q;d'`
# Put in string "(branch_name/): " at start of commit message body.
# For templates with commit bodies
if test ! -z $BODY; then
awk 'NR=='$BODY'{$0="\('$NAME'/\): "}1;' $1 > tmp_msg && mv tmp_msg "$1"
else
echo "title\n\n($NAME/):\n`cat $1`\n" > "$1"
fi
}
# You might need to consider squashes
case "$2,$3" in
# Commits that already have a message
commit,?*)
;;
# Messages are one line messages you decide how to handle
message,)
;;
# Merge commits
merge,)
# Comments out the "Conflicts:" part of a merge commit.
perl -i.bak -ne 's/^/# /, s/^# #/#/ if /^Conflicts/ .. /#/; print' "$1"
;;
# Non-merges with no prior messages
*)
addMyBranchName $1
;;
esac
Upvotes: 6
Reputation: 161
add the below code in prepare-commit-msg file.
#!/bin/sh
#
# Automatically add branch name and branch description to every commit message except merge commit.
#
COMMIT_EDITMSG=$1
addBranchName() {
NAME=$(git branch | grep '*' | sed 's/* //')
DESCRIPTION=$(git config branch."$NAME".description)
echo "[$NAME]: $(cat $COMMIT_EDITMSG)" > $COMMIT_EDITMSG
if [ -n "$DESCRIPTION" ]
then
echo "" >> $COMMIT_EDITMSG
echo $DESCRIPTION >> $COMMIT_EDITMSG
fi
}
MERGE=$(cat $COMMIT_EDITMSG|grep -i 'merge'|wc -l)
if [ $MERGE -eq 0 ] ; then
addBranchName
fi
It will add branch name to commit message except merge-commit. The merge-commit has branch information by default so extra branch name is unnecessary and make the message ugly.
Upvotes: 16
Reputation: 91149
Use the prepare-commit-msg
or commit-msg
githook.
There are examples already in your PROJECT/.git/hooks/
directory.
As a security measure, you will have to manually enable such a hook on each repository you wish to use it. Though, you can commit the script and copy it on all clones into the .git/hooks/
directory.
Upvotes: 69
Reputation: 11836
A bit simpler script that adds the branch name to the commit message before you edit it. So if you want want to change or remove it you can.
Create this file .git/hooks/prepare-commit-msg:
#!/bin/bash
branchPath=$(git symbolic-ref -q HEAD) #Somthing like refs/heads/myBranchName
branchName=${branchPath##*/} #Get text behind the last / of the branch path
firstLine=$(head -n1 $1)
if [ -z "$firstLine" ] ;then #Check that this is not an amend by checking that the first line is empty
sed -i "1s/^/$branchName: \n/" $1 #Insert branch name at the start of the commit message file
fi
Upvotes: 44
Reputation: 9558
Here is my commit-msg
script as an example:
#!/bin/sh
#
# Automatically adds branch name and branch description to every commit message.
#
NAME=$(git branch | grep '*' | sed 's/* //')
DESCRIPTION=$(git config branch."$NAME".description)
echo "$NAME"': '$(cat "$1") > "$1"
if [ -n "$DESCRIPTION" ]
then
echo "" >> "$1"
echo $DESCRIPTION >> "$1"
fi
Creates following commit message:
[branch_name]: [original_message]
[branch_description]
I'm using issue number as branch_name
, issue description is placed to the branch_description
using git branch --edit-description [branch_name]
command.
More about branch descriptions you can find on this Q&A.
The code example is stored in following Gist.
Upvotes: 206