Как добавить имя ветки Git в сообщение коммита?

Мне нужна помощь с сценарием Bash, который автоматически добавит имя ветки git в качестве хэша в сообщения о фиксации.


person Tomer Lichtash    schedule 05.05.2011    source источник
comment
Для всех, кто сюда приходит, лучший ответ - внизу страницы.   -  person Ben Taliadoros    schedule 19.07.2018
comment
Боковое примечание: все git branch | grep ... для получения текущей ветки - неправильный способ сделать это. Рассмотрим либо git symbolic-ref -q HEAD (как показано в этом ответе) или git rev-parse --abbrev-ref HEAD. Команда symbolic-ref завершится ошибкой, если вы используете отключенную HEAD, поэтому, если вы хотите обнаружить этот случай, используйте ее. В противном случае, вероятно, лучше всего использовать метод rev-parse --abbrev-ref.   -  person torek    schedule 18.04.2019


Ответы (9)


Используйте prepare-commit-msg или commit-msg githook.

В вашем каталоге PROJECT/.git/hooks/ уже есть примеры.

В качестве меры безопасности вам придется вручную включить такую ловушку для каждого репозитория, который вы хотите использовать. Тем не менее, вы можете зафиксировать сценарий и скопировать его на всех клонах в каталог .git/hooks/.

person ninjagecko    schedule 05.05.2011
comment
Спасибо большое зацепку; Спасибо. Если вы можете мне помочь дальше, с самим скриптом, буду признателен :) - person Tomer Lichtash; 05.05.2011
comment
Мне не нужно, у вас уже есть пример, который делает именно то, что вы хотите, как я уже сказал, в .git/hooks/prepare-commit-msg.sample. =) Все, что вам нужно изменить (после выполнения указаний в комментариях), - это скопировать и вставить любое решение из stackoverflow.com/questions/1593051/, которую вы хотите - person ninjagecko; 05.05.2011
comment
@ninjagecko, для меня .git/hooks/prepare-commit-msg.sample содержит три примера. Один для комментирования раздела конфликтов, добавления к нему git diff --name-status -r вывода и добавления строк Signed-off-by ... Без добавления имени ветки в сообщение фиксации. Так что я был вынужден написать свой собственный крючок. - person shytikov; 18.07.2012
comment
Означает ли это you will have to manually enable such a hook on each repository you wish to use it, что вы должны предоставить ФАЙЛУ права на выполнение? Если да, могу ли я отредактировать ответ, включив это (или вы могли бы, пожалуйста)? - person Dan Rosenstark; 26.12.2016
comment
@DanRosenstark: я думаю, что папка .git / hooks не отслеживается (по крайней мере, по умолчанию), и может потребоваться вручную скопировать файлы в папку .git / hooks (или иметь сценарий для этого) или какой-либо другой домашний пользовательский метод. О том, что я имел в виду, см. stackoverflow. .com / questions / 4457031 /. Также, чтобы ответить на ваш вопрос: образцы файлов в каталоге .git / hooks, похоже, не предлагают добавлять разрешения + exec (хотя я вижу, что некоторые сайты говорят, что вам могут понадобиться разрешения exec; поэтому я не знаю точного ответа на ваш вопрос). - person ninjagecko; 28.12.2016
comment
@ninjagecko, хорошо, мы пока оставим это как есть, но для ME на osx изменение разрешений на 755 для конкретного файла в каталоге хуков сработало. Однако в конце концов я выбрал более старое решение, которое вообще не использует хуки: stackoverflow.com/questions/4086896/ ... который охватывает только некоторую часть текущего вопроса, но в любом случае, спасибо! - person Dan Rosenstark; 28.12.2016
comment
Почему это ответ? Скорее, позволь мне погуглить это для тебя. Следует выбрать ответ @shytikov - person TheRealFakeNews; 23.04.2019

Вот мой сценарий commit-msg в качестве примера:

#!/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 

Создает следующее сообщение фиксации:

[branch_name]: [original_message]

[branch_description]

Я использую номер проблемы как branch_name, описание проблемы помещается в branch_description с помощью команды git branch --edit-description [branch_name].

Подробнее об описаниях веток вы можете найти в этом Q&A.

Пример кода хранится в следующем Gist.

person shytikov    schedule 17.07.2012
comment
Этот скрипт сжимает многострочные сообщения фиксации в одну строку. Я заменил ваше выражение echo на: echo -n $ NAME ':' | cat - $ 1 ›/ tmp / out && mv / tmp / out $ 1 - person Alex Spence; 15.01.2014
comment
Поместите этот файл в папку PROJECT / .git / hooks / - person iOS Developer; 14.01.2015
comment
Это работает хорошо. Но для Mac мне также пришлось установить разрешение, чтобы оно работало: ››› sudo chmod 755 .git / hooks / commit-msg - person Manoj Shrestha; 25.09.2017
comment
@ManojShrestha да, это должен быть исполняемый файл - person David Mann; 14.08.2018
comment
@AlexSpence проще вы могли бы использовать echo $NAME: "$(cat $1)" > $1. Это работает, потому что причина потери новых строк заключается в том, что echo обрабатывает каждую строку $(cat "$1") как новый аргумент и повторяет каждую с пробелом между ними. Заключив $(cat "$1") в двойные кавычки, echo обрабатывает вывод cat как единственный аргумент. Также я не думаю, что нужно указывать $1, так как его значение .git/COMMIT_EDITMSG - person PiersyP; 27.06.2019
comment
Я получаю Aborting commit due to empty commit message. после git commit - person Hairi; 19.12.2019
comment
Было бы полезно упомянуть, что это тоже git-крючок - person BrutalSimplicity; 12.01.2020
comment
Как добавить это в ловушку подмодуля? Так как я получаю ошибку cat: .git/COMMIT_EDITMSG: Not a directory - person Estevex; 21.02.2020

Немного более простой скрипт, который добавляет имя ветки к сообщению о фиксации перед его редактированием. Так что, если вы хотите изменить или удалить его, вы можете.

Создайте этот файл .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
person Pylinux    schedule 24.06.2013
comment
Я получаю: sed: 1: ".git/COMMIT_EDITMSG": invalid command code . при использовании этого. - person Adam Parkin; 16.07.2013
comment
Ага, разница в Mac OSX, см .: hintsforums.macworld.com/showpost.php? p = 393450 & postcount = 11 для исправления - person Adam Parkin; 16.07.2013
comment
как проверка случая исправления и исправления - person pogopaule; 27.03.2015
comment
OSX: требуется расширение файла для работы, если вы получаете вышеуказанное сообщение об ошибке. sed -i '.bak' "1s/^/$branchName : \n/" $1 - person canintex; 15.07.2015
comment
Вы можете использовать @ в качестве sed разделителя вместо /, поскольку косая черта с большей вероятностью будет отображаться в имени ветки или сообщении фиксации, что приведет к ошибке sed. - person Ory Band; 28.10.2015
comment
@OryBand имя ветки - это текст за последней косой чертой, т.е. он никогда не будет содержать косой черты. - person Pylinux; 29.10.2015
comment
@Pylinux у меня не получилось на ветке с именем ory/SERVER-111-bla-bla - person Ory Band; 29.10.2015
comment
@OryBand, тогда проблема не в том, что имя ветки содержит косую черту, запустите это в * nix cmd branchPath=ory/SERVER-111-bla-bla; echo ${branchPath##*/}, и вы увидите, что имя ветки не содержит косой черты. - person Pylinux; 29.10.2015
comment
@Pylinux, чем почему замена /s на @s решила проблему? больше ничего не включало слэши. - person Ory Band; 29.10.2015
comment
@OryBand Вы проверили, что переменная branchName содержит косые черты? Единственная задача второй строки - удалить папки из ветки. - person Pylinux; 30.10.2015
comment
@Pylinux содержит косые черты, но я хочу, чтобы ветвь сохраняла косые черты, например. ory/SERVER-111-bla-bla. Если я выполню строку 2, то часть ory/ будет удалена, а я этого не хочу. - person Ory Band; 01.11.2015
comment
@Pylinux Теперь я понимаю, о чем вы говорили. Вы удаляете части с префиксом с /s из имени ветки, избегая, таким образом, случая, который у меня был. Я пропустил замену в своей версии и не заметил этого до сих пор. Спасибо! - person Ory Band; 02.11.2015
comment
Нет проблем, рад помочь :-) - person Pylinux; 03.11.2015
comment
AFAICT предполагает, что сообщение исходит от -m: мне нужно было удалить if, чтобы заставить его работать с сообщением, сгенерированным шаблоном. - person snakecharmerb; 05.12.2020
comment
@snakecharmerb Это предназначено для использования без -m, т.е. только с git commit и настройкой редактора в git (обычно vim). Совершенно уверен, что -m переопределит то, что мы пытаемся здесь достичь. - person Pylinux; 06.12.2020

Вы можете сделать это с помощью комбинации обработчиков prepare-commit-msg и pre-commit.

.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

Установить разрешения

sudo chmod 755 .git/hooks/prepare-commit-msg
sudo chmod 755 .git/hooks/pre-commit
person Farid Movsumov    schedule 07.11.2014
comment
Обратите внимание, что это может удалить исходное сообщение фиксации, если вы, например, используете --amend. Вместо использования echo вы должны использовать sed. Вот он в одном строчке: sed -i "1s@^@$(git branch | grep '^\*' | cut -b3-) @" $1 - person Ory Band; 28.10.2015

добавьте приведенный ниже код в файл prepare-commit-msg.

#!/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

Он добавит имя ветки в сообщение фиксации, кроме фиксации слияния. По умолчанию слияние-фиксация содержит информацию о ветке, поэтому дополнительное имя ветки не требуется и делает сообщение некрасивым.

person Tim    schedule 11.09.2013
comment
Значит, это не изменит сообщение фиксации, когда он найдет слово слияние в сообщении? - person thoroc; 01.02.2016
comment
@thoroc, что технически правильно; однако при обычном использовании это не имеет большого значения. Анализируемое сообщение фиксации является сообщениями по умолчанию перед их редактированием. Итак, пока в вашем шаблоне фиксации нет слова «слияние», я считаю, что с вами все должно быть в порядке (пока другие сообщения по умолчанию не содержат, за исключением сообщения о фиксации слияния по умолчанию). Я неправильно понял это изначально и считаю, что теперь это правильно. - person Novice C; 19.09.2016

Вдохновленный ответом Тима, который основан на верхнем ответе, оказывается, что ловушка prepare-commit-msg принимает как аргумент, какой тип фиксации происходит. Как видно по умолчанию, prepare-commit-msg, если $ 2 - это 'merge', то это фиксация слияния. Таким образом, можно изменить регистр, чтобы включить функцию Тима addBranchName ().

Я включил свои собственные предпочтения относительно того, как добавить имя ветки и все раскомментированные части хука по умолчанию prepare-commit-msg.sample.

подготовить коммит-сообщение

#!/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
person Novice C    schedule 27.09.2016

Если вы хотите сделать его глобальным (для всех проектов):

Создайте git-msg файл с содержимым ответа Шитикова и поместите его в какую-нибудь папку:

mkdir -p ~/.git_hooks
# make it executable
chmod a+x ~/.git_hooks/commit-msg

Теперь включите хуки:

git config --global init.templatedir '~/.git_hooks'

и снова git init в каждом проекте, который вы хотите использовать.

person Maroun    schedule 26.06.2018
comment
Я обнаружил, что для использования этой функции мне пришлось поместить «commit-msg» в каталог «hooks» внутри каталога, настроенного для «init.templatedir», чтобы при копировании всего шаблона в «git init», «commit- msg 'попадает в каталог проекта' .git / hooks '. - person Dan; 06.02.2019

У меня возникли проблемы с работой этих решений на MacOS из-за того, что он использует BSD sed вместо GNU sed. Однако мне удалось создать простой скрипт, который выполняет свою работу. Все еще использую .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 

Это предполагает стандарт именования веток, подобный functional-desc_JIRA-NUMBER. Если имя вашего филиала - это только номер вашего билета Jira, вы можете просто избавиться от всего, от конвейера до f2. Также требуется, чтобы в вашем домашнем каталоге был файл с именем .gitmessage.

person PhPGuy    schedule 08.03.2018

Если вы хотите, чтобы билет JIRA был добавлен в сообщение фиксации, используйте сценарий ниже.

Сообщение фиксации вроде PROJECT-2313: Add awesome feature. Для этого требуется, чтобы имя вашей ветки начиналось с jira Ticket.

Это комбинация этих решений:

Он модифицирован для OS X с sed -i '.bak' и также работает с 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
person Mihai Georgescu    schedule 20.01.2020
comment
Это хорошо работает с файлом на стороне клиента: prepare-commit-msg для автоматического заполнения префикса фиксации. Но если я хочу сделать то же самое на стороне сервера, которым является сервер Bitbucket (в моем случае), и я пытаюсь добавить эту логику в ловушку предварительного приема на пути к серверу Bitbucket: BITBUCKET_HOME / shared / data / repositories / ‹Repository-id› / hooks / 21_pre_receive, он не работает как git symbolic-ref -q HEAD, дающий «master», хотя я совершаю коммит из своей ветки feature / abc на стороне клиента. Есть ли здесь другой выход? - person santhosh; 14.08.2020