Como adicionar o nome do branch do Git à mensagem de confirmação?

103

Preciso de ajuda com um script Bash que adicionará automaticamente o nome do branch do git como um hash nas mensagens de confirmação.

Tomer Lichtash
fonte
3
Para quem vem aqui, parece que a melhor resposta está no final da página
Ben Taliadoros
Nota lateral: todos os git branch | grep ...métodos para obter o branch atual são a maneira errada de fazer isso. Considere git symbolic-ref -q HEAD(como mostrado nesta resposta ) ou git rev-parse --abbrev-ref HEAD. O comando symbolic-ref falhará se você estiver em um HEAD separado, então se você deseja detectar esse caso, use-o. Caso contrário, o método rev-parse --abbrev-ref é provavelmente o melhor.
torek de

Respostas:

53

Use o prepare-commit-msgou commit-msg githook .

Já existem exemplos em seu PROJECT/.git/hooks/diretório.

Como medida de segurança, você terá que habilitar manualmente esse gancho em cada repositório que deseja usá-lo. Porém, você pode confirmar o script e copiá-lo em todos os clones para o .git/hooks/diretório.

ninjagecko
fonte
Obrigado, uma ótima pista; obrigado. Se puderem me ajudar mais, com o script em si, ficarei grato :)
Tomer Lichtash
5
Não preciso, você já tem um exemplo que faz exatamente o que você quer , como já falei, no .git/hooks/prepare-commit-msg.sample. =) Tudo que você precisa modificar (depois de seguir as instruções nos comentários) é copiar e colar qualquer solução de stackoverflow.com/questions/1593051/… que desejar
ninjagecko
4
@ninjagecko, para mim .git/hooks/prepare-commit-msg.samplecontém três exemplos. Um para comentar a seção de conflitos, adicionando git diff --name-status -rsaída a ela e adicionando linhas Signed-off-by ... Sem adicionar nome de ramificação à mensagem de confirmação. Então fui forçado a escrever meu próprio livro.
shytikov
1
Isso you will have to manually enable such a hook on each repository you wish to use itsignifica que você precisa dar permissões de execução ao FILE? Em caso afirmativo, posso editar a resposta para incluir isso (ou você poderia, por favor)?
Dan Rosenstark
1
Por que essa é a resposta? É mais como deixe-me pesquisar isso no Google para você. A resposta de @shytikov deve ser selecionada
TheRealFakeNews
177

Aqui está meu commit-msgscript como exemplo:

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

Cria a seguinte mensagem de confirmação:

[branch_name]: [original_message]

[branch_description]

Estou usando o número do problema porque a branch_namedescrição do problema é colocada no comando branch_descriptionusing git branch --edit-description [branch_name].

Mais sobre as descrições dos ramos você pode encontrar neste Q&A .

O exemplo de código é armazenado no seguinte Gist .

Shytikov
fonte
8
Este script comprime mensagens de commit de várias linhas em uma única linha. Substituí sua instrução echo por: echo -n "$ NAME" ':' | cat - "$ 1"> / tmp / out && mv / tmp / out "$ 1"
Alex Spence
4
Coloque este arquivo na pasta PROJECT / .git / hooks /
catanore
2
Isso funciona bem. Mas para Mac, eu tive que definir a permissão também para fazê-lo funcionar: >>> sudo chmod 755 .git / hooks / commit-msg
Manoj Shrestha
1
@ManojShrestha sim, tem que ser executável
David Mann
2
@AlexSpence de forma mais simples que você poderia usar echo $NAME: "$(cat $1)" > $1. Isso funciona porque a razão pela qual as novas linhas estavam sendo perdidas é que a echo estava tratando cada linha de $(cat "$1")como um novo argumento e ecoando cada uma com um espaço entre eles. Rodando $(cat "$1")com aspas duplas, echo trata a saída cat como um único argumento. Também não acho que seja necessário citar, $1pois seu valor é.git/COMMIT_EDITMSG
PiersyP
30

Um script um pouco mais simples que adiciona o nome do branch à mensagem de confirmação antes de editá-la. Então, se você quiser mudar ou remover, você pode.

Crie este arquivo .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
Pylinux
fonte
4
Eu entendo: sed: 1: ".git/COMMIT_EDITMSG": invalid command code .ao usar isso.
Adam Parkin
1
Aha, diferença do Mac OSX, consulte: hintsforums.macworld.com/showpost.php?p=393450&postcount=11 para a correção
Adam
2
como a verificação do caso de correção e
conserto
3
OSX: Requer extensão de arquivo para funcionar se você estiver recebendo a mensagem de erro acima. sed -i '.bak' "1s/^/$branchName : \n/" $1
canintex
Você pode usar @como um sedseparador em vez de, /já que as barras normais são mais prováveis ​​de aparecer no nome do branch ou na mensagem de confirmação, bagunçando tudo sed.
Ory Band
28

Você pode fazer isso com uma combinação dos ganchos prepare-commit-msg e 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

Definir permissões

sudo chmod 755 .git/hooks/prepare-commit-msg
sudo chmod 755 .git/hooks/pre-commit
Farid Movsumov
fonte
Observe que isso pode remover a mensagem de confirmação original se você estiver usando, --amendpor exemplo. Em vez de usar, echovocê deve usar sed. Aqui está em uma linha:sed -i "1s@^@$(git branch | grep '^\*' | cut -b3-) @" $1
Ory Band
10

adicione o código abaixo no arquivo 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

Ele adicionará o nome do branch para enviar mensagem, exceto mesclar-commit. O merge-commit tem informações de branch por padrão, então o nome de branch extra é desnecessário e torna a mensagem feia.

Tim
fonte
1
Portanto, isso não alterará a mensagem de confirmação quando encontrar a palavra mesclar na mensagem?
Thoroc 01 de
1
@thoroc que é tecnicamente correto; entretanto, em uso normal, isso não é grande coisa. A mensagem de confirmação que está sendo analisada é a "padrão" antes de você editá-la. Então, contanto que seu modelo de commit não tenha a palavra "merge" nele, eu acredito que você deva ficar bem (contanto que as outras mensagens "default" não tenham, exceto para uma mensagem default de merge commit). Eu entendi mal isso originalmente, e acredito que estou correto agora.
Iniciante C
5

Inspirado pela resposta de Tim que se baseia na resposta principal, acontece que o gancho prepare-commit-msg toma como argumento o tipo de confirmação que está ocorrendo . Como visto na mensagem padrão prepare-commit-se $ 2 for 'merge' então é um commit de mesclagem. Portanto, a opção de maiúsculas e minúsculas pode ser alterada para incluir a função addBranchName () de Tim.

Incluí minha própria preferência sobre como adicionar o nome do branch e todas as partes não comentadas do prepare-commit-msg.samplegancho padrão .

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
Novato C
fonte
4

Se você quiser torná-lo global (para todos os projetos):

Crie um git-msgarquivo com o conteúdo da resposta de shytikov e coloque-o em alguma pasta:

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

Agora habilite os ganchos:

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

e git initnovamente em cada projeto que você deseja usar.

Maroun
fonte
2
Eu descobri que para usar este recurso, eu tive que colocar 'commit-msg' em um diretório 'hooks' dentro do diretório configurado para 'init.templatedir' para que quando todo o templatedir fosse copiado em 'git init', 'commit- msg 'termina no diretório' .git / hooks 'do projeto.
Dan
2

Eu estava tendo problemas para fazer essas soluções funcionarem no MacOS devido ao fato de que ele usa BSD em sedvez de GNU sed. Eu consegui criar um script simples que faz o trabalho. Ainda usando .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 

Isso pressupõe um padrão de nomenclatura de ramificação semelhante a functional-desc_JIRA-NUMBER. Se o nome da sua agência for apenas o número do seu tíquete Jira, você pode simplesmente se livrar de tudo, do pipe ao f2. Também requer que você tenha um arquivo nomeado .gitmessageem seu diretório inicial.

PhPGuy
fonte
2

Caso queira adicionar o ticket do JIRA na mensagem de commit, use o script abaixo.

Envie uma mensagem como PROJECT-2313: Add awesome feature Isso requer que o nome do seu ramo comece com o tíquete jira.

Esta é uma combinação das seguintes soluções:

Ele foi modificado para OS X, com o sed -i '.bak'e funciona bem no 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
Mihai Georgescu
fonte
Isso está funcionando bem no arquivo do lado do cliente: prepare-commit-msg para preencher automaticamente o prefixo de confirmação. Mas se eu quiser fazer o mesmo no gancho do lado do servidor, que é o servidor bitbucket (no meu caso) e estou tentando adicionar essa lógica no gancho de pré-recebimento no caminho do servidor Bitbucket: BITBUCKET_HOME / shared / data / repositories / <repository-id> / hooks / 21_pre_receive, não está funcionando como "git symbolic-ref -q HEAD" dando 'master' embora eu esteja fazendo commit do meu branch feature / abc do lado do cliente. Existe outra maneira aqui?
santhosh