Comment ajouter le nom de la branche de Git au message de validation?

103

J'ai besoin d'aide avec un script Bash qui ajoutera automatiquement le nom de la branche de git en tant que hachage dans les messages de validation.

Tomer Lichtash
la source
4
Pour tous ceux qui viennent ici, il semble que la meilleure réponse se trouve au bas de la page
Ben Taliadoros
Remarque: tout ce qui git branch | grep ...concerne l'obtention de la branche actuelle n'est pas la bonne façon de le faire. Considérez soit git symbolic-ref -q HEAD(comme indiqué dans cette réponse ) ou git rev-parse --abbrev-ref HEAD. La commande symbolic-ref échouera si vous êtes sur un HEAD détaché, donc si vous souhaitez détecter ce cas, utilisez-le. Sinon, la méthode rev-parse --abbrev-ref est probablement la meilleure.
torek

Réponses:

53

Utilisez le prepare-commit-msgou commit-msg githook .

Il existe déjà des exemples dans votre PROJECT/.git/hooks/répertoire.

Par mesure de sécurité, vous devrez activer manuellement un tel hook sur chaque référentiel que vous souhaitez utiliser. Cependant, vous pouvez valider le script et le copier sur tous les clones dans le .git/hooks/répertoire.

ninjagecko
la source
Merci une bonne avance; Merci. Si vous pouvez m'aider davantage, avec le script lui-même, je vous serai reconnaissant :)
Tomer Lichtash
5
Je n'ai pas besoin de le faire, vous avez déjà un exemple qui fait exactement ce que vous voulez , comme je l'ai déjà dit .git/hooks/prepare-commit-msg.sample. =) Tout ce que vous devez modifier (après avoir suivi les instructions dans les commentaires) est de copier-coller la solution de stackoverflow.com/questions/1593051/… que vous souhaitez
ninjagecko
4
@ninjagecko, pour moi .git/hooks/prepare-commit-msg.samplecontient trois exemples. Une pour commenter la section des conflits, y ajouter une git diff --name-status -rsortie et ajouter des lignes Signed-off-by ... Pas d'ajout de nom de branche au message de validation. J'ai donc été obligé d'écrire mon propre crochet.
shytikov
1
Cela you will have to manually enable such a hook on each repository you wish to use itsignifie- t-il que vous devez accorder des autorisations d'exécution au FILE? Si oui, puis-je modifier la réponse pour inclure cela (ou pourriez-vous, s'il vous plaît)?
Dan Rosenstark
2
Pourquoi est-ce la réponse? C'est plus comme laissez-moi google pour vous. Réponse de @shytikov doit être sélectionné
TheRealFakeNews
177

Voici mon commit-msgscript à titre d'exemple:

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

Crée le message de validation suivant:

[branch_name]: [original_message]

[branch_description]

J'utilise le numéro de branch_nameproblème, la description du problème est placée dans la commande branch_descriptionusing git branch --edit-description [branch_name].

Pour en savoir plus sur les descriptions des succursales, consultez ce Q&R .

L'exemple de code est stocké dans Gist suivant .

Shytikov
la source
8
Ce script écrase les messages de validation sur plusieurs lignes en une seule ligne. J'ai remplacé votre instruction echo par: echo -n "$ NAME" ':' | cat - "$ 1"> / tmp / out && mv / tmp / out "$ 1"
Alex Spence
4
Mettez ce fichier dans le dossier PROJECT / .git / hooks /
catanore
2
Ça marche bien. Mais pour Mac, j'ai dû définir la permission aussi pour que cela fonctionne: >>> sudo chmod 755 .git / hooks / commit-msg
Manoj Shrestha
1
@ManojShrestha oui, il doit être exécutable
David Mann
2
@AlexSpence plus simplement que vous pourriez utiliser echo $NAME: "$(cat $1)" > $1. Cela fonctionne parce que la raison pour laquelle les nouvelles lignes étaient perdues est que l'écho traitait chaque ligne de $(cat "$1")comme un nouvel argument et faisait écho à chacune avec un espace entre les deux. En l'entourant $(cat "$1")de guillemets doubles, echo traite la sortie cat comme un argument unique. Aussi, je ne pense pas qu'il soit nécessaire de citer $1car sa valeur est.git/COMMIT_EDITMSG
PiersyP
30

Un script un peu plus simple qui ajoute le nom de la branche au message de validation avant de le modifier. Donc, si vous souhaitez le modifier ou le supprimer, vous pouvez.

Créez ce fichier .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
la source
4
Je reçois: sed: 1: ".git/COMMIT_EDITMSG": invalid command code .en utilisant ceci.
Adam Parkin
1
Aha, différence Mac OSX, voir: hintsforums.macworld.com/showpost.php?p=393450&postcount=11 pour le correctif
Adam Parkin
2
comme la vérification du cas de modification et de
réparation
3
OSX: nécessite une extension de fichier pour fonctionner si vous obtenez le message d'erreur ci-dessus. sed -i '.bak' "1s/^/$branchName : \n/" $1
canintex
Vous pouvez utiliser @comme sedséparateur au lieu de /puisque les barres obliques sont plus susceptibles d'apparaître dans le nom de la branche ou le message de validation, ce qui est foutu sed.
Ory Band
28

Vous pouvez le faire avec une combinaison des hooks prepare-commit-msg et 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

Définir les autorisations

sudo chmod 755 .git/hooks/prepare-commit-msg
sudo chmod 755 .git/hooks/pre-commit
Farid Movsumov
la source
Notez que cela peut supprimer le message de validation d'origine si vous utilisez --amendpar exemple. Au lieu d'utiliser, echovous devriez utiliser à la sedplace. Le voici dans un one liner:sed -i "1s@^@$(git branch | grep '^\*' | cut -b3-) @" $1
Ory Band
10

ajoutez le code ci-dessous dans le fichier 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

Il ajoutera le nom de la branche au message de validation sauf fusion-validation. Le merge-commit a des informations de branche par défaut, donc un nom de branche supplémentaire n'est pas nécessaire et rend le message laid.

Tim
la source
1
Donc, cela ne modifiera pas le message de validation lorsqu'il trouvera le mot fusionner sur le message?
thoroc
1
@thoroc qui est techniquement correct; cependant, en utilisation normale, ce n'est pas un gros problème. Le message de validation en cours d'analyse est celui "par défaut" avant que vous ne les éditiez. Donc, tant que votre modèle de commit ne contient pas le mot "merge", je pense que vous devriez être d'accord (tant que les autres messages "default" ne le font pas à l'exception d'un message de validation de fusion par défaut). J'ai mal compris cela à l'origine, et je crois que c'est correct maintenant.
Novice C
5

Inspiré par la réponse de Tim qui s'appuie sur la première réponse, il s'avère que le hook prepare-commit-msg prend comme argument le type de commit qui se produit . Comme on le voit dans le fichier prepare-commit-msg par défaut, si $ 2 est «merge», alors c'est un commit de fusion. Ainsi, le commutateur de casse peut être modifié pour inclure la fonction addBranchName () de Tim.

J'ai inclus ma propre préférence pour la manière d'ajouter le nom de la branche et toutes les parties non commentées du prepare-commit-msg.samplehook par défaut .

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
Novice C
la source
4

Si vous souhaitez le rendre global (pour tous les projets):

Créez un git-msgfichier avec le contenu de la réponse de shytikov et placez-le dans un dossier:

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

Maintenant, activez les hooks:

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

et git initencore une fois dans chaque projet que vous souhaitez utiliser.

Maroun
la source
2
J'ai trouvé que pour utiliser cette fonctionnalité, je devais mettre 'commit-msg' dans un répertoire 'hooks' à l'intérieur du répertoire configuré pour 'init.templatedir' afin que lorsque tout le templatedir soit copié sur 'git init', 'commit- msg 'se termine dans le répertoire' .git / hooks 'du projet.
Dan
2

J'avais des problèmes pour que ces solutions fonctionnent sur MacOS en raison du fait qu'il utilise BSD sedau lieu de GNU sed. J'ai réussi à créer un script simple qui fait le travail. Toujours en utilisant .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 

Cela suppose une norme de dénomination de branche similaire à functional-desc_JIRA-NUMBER. Si le nom de votre succursale n'est que votre numéro de ticket Jira, vous pouvez simplement vous débarrasser de tout, du tuyau au f2. Cela nécessite également que vous ayez un fichier nommé .gitmessagedans votre répertoire personnel.

PhPGuy
la source
2

Si vous souhaitez que le ticket JIRA soit ajouté au message de validation, utilisez le script ci-dessous.

Message de validation quelque chose comme PROJECT-2313: Add awesome feature Cela nécessite que le nom de votre succursale commence par le ticket jira.

C'est une combinaison de ces solutions:

Il est modifié pour OS X, avec le sed -i '.bak'et fonctionne également à partir de 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
la source
Cela fonctionne bien sur le fichier côté client: prepare-commit-msg pour remplir automatiquement le préfixe de commit. Mais si je veux faire la même chose sur le hook côté serveur, qui est le serveur bitbucket (dans mon cas) et que j'essaie d'ajouter cette logique sur le hook de pré-réception au chemin du serveur Bitbucket: BITBUCKET_HOME / shared / data / repositories / <repository-id> / hooks / 21_pre_receive, cela ne fonctionne pas comme "git symbolic-ref -q HEAD" donnant 'master' bien que je commette depuis ma branche feature / abc du côté client. Y a-t-il un autre moyen ici?
santhosh