Jak dodać nazwę gałęzi Gita do komunikatu zmiany?

103

Potrzebuję pomocy ze skryptem Bash, który automatycznie doda nazwę gałęzi gita jako hash w komunikatach o zmianach.

Tomer Lichtash
źródło
4
Dla każdego, kto tu przyjeżdża, wydaje się, że najlepsza odpowiedź znajduje się na dole strony
Ben Taliadoros
Uwaga dodatkowa: wszystkie czynności potrzebne git branch | grep ...do uzyskania bieżącej gałęzi są złym sposobem na zrobienie tego. Rozważ albo git symbolic-ref -q HEAD(jak pokazano w tej odpowiedzi ) albo git rev-parse --abbrev-ref HEAD. Polecenie symbolic-ref nie powiedzie się, jeśli jesteś na odłączonym HEAD, więc jeśli chcesz wykryć ten przypadek, użyj go. W przeciwnym razie metoda rev-parse --abbrev-ref jest prawdopodobnie najlepsza.
torek

Odpowiedzi:

53

Użyj prepare-commit-msglub commit-msg githook .

W twoim PROJECT/.git/hooks/katalogu są już przykłady .

Ze względów bezpieczeństwa będziesz musiał ręcznie włączyć taki punkt zaczepienia w każdym repozytorium, którego chcesz używać. Chociaż możesz zatwierdzić skrypt i skopiować go na wszystkie klony do .git/hooks/katalogu.

ninjagecko
źródło
Dzięki za świetny trop; Dziękuję Ci. Jeśli możesz mi pomóc dalej, z samym scenariuszem, będę wdzięczny :)
Tomer Lichtash
5
Nie muszę, masz już przykład, który robi dokładnie to, co chcesz , jak już powiedziałem, w .git/hooks/prepare-commit-msg.sample. =) Wszystko, co musisz zmodyfikować (po wykonaniu wskazówek w komentarzach), to skopiować i wkleić dowolne rozwiązanie ze stackoverflow.com/questions/1593051/ ... które chcesz
ninjagecko
4
@ninjagecko, dla mnie .git/hooks/prepare-commit-msg.samplezawiera trzy przykłady. Jeden do komentowania sekcji konfliktów, dodawania git diff --name-status -rdo niej danych wyjściowych i dodawania linii podpisanych przez ... Bez dodawania nazwy gałęzi do komunikatu zatwierdzenia. Więc zostałem zmuszony do napisania własnego haka.
shytikov
1
Czy to you will have to manually enable such a hook on each repository you wish to use itoznacza, że ​​musisz nadać plikowi uprawnienia do wykonywania? Jeśli tak, czy mogę zmienić odpowiedź, aby to załączyć (czy możesz, proszę)?
Dan Rosenstark
2
Dlaczego to jest odpowiedź? Raczej pozwól mi to wygooglować dla Ciebie. Należy wybrać odpowiedź od @shytikov
TheRealFakeNews
177

Oto mój commit-msgskrypt jako przykład:

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

Tworzy następujący komunikat o zatwierdzeniu:

[branch_name]: [original_message]

[branch_description]

Używam numeru wydania, ponieważ branch_nameopis problemu jest umieszczony w poleceniu branch_descriptionusing git branch --edit-description [branch_name].

Więcej o opisach branż można znaleźć w tym pytaniu i odpowiedzi .

Przykładowy kod jest przechowywany w następującym Gist .

shytikov
źródło
9
Ten skrypt ogranicza wielowierszowe komunikaty o zatwierdzeniach do jednej linii. Zastąpiłem instrukcję echo: echo -n "$ NAZWA" ':' | cat - "$ 1"> / tmp / out && mv / tmp / out "$ 1"
Alex Spence
4
Umieść ten plik w folderze PROJECT / .git / hooks /
catanore
2
To dobrze działa. Ale w przypadku Maca musiałem również ustawić uprawnienia, aby działało: >>> sudo chmod 755 .git / hooks / commit-msg
Manoj Shrestha
1
@ManojShrestha tak, to musi być wykonywalne
David Mann
2
@AlexSpence prościej możesz użyć echo $NAME: "$(cat $1)" > $1. To działa, ponieważ powodem utraty nowych linii jest to, że echo traktowało każdy wiersz $(cat "$1")jako nowy argument i powtarzał każdy z odstępami między nimi. Otaczając $(cat "$1")podwójnymi cudzysłowami, echo traktuje wyjście cat jako pojedynczy argument. Nie sądzę też, aby było konieczne cytowanie, $1ponieważ jego wartość to.git/COMMIT_EDITMSG
PiersyP
30

Nieco prostszy skrypt, który dodaje nazwę gałęzi do komunikatu o zmianach przed jego edycją. Więc jeśli chcesz go zmienić lub usunąć, możesz.

Utwórz ten plik .git / hooks / Preparat-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
źródło
4
Otrzymuję: sed: 1: ".git/COMMIT_EDITMSG": invalid command code .podczas używania tego.
Adam Parkin,
1
Aha, różnica w Mac OSX, zobacz: hintsforums.macworld.com/showpost.php?p=393450&postcount=11, aby uzyskać poprawkę
Adam Parkin
2
jak sprawdzanie sprawy poprawek i poprawek
pogopaule
3
OSX: Wymaga rozszerzenia pliku do działania, jeśli pojawia się powyższy komunikat o błędzie. sed -i '.bak' "1s/^/$branchName : \n/" $1
canintex
Możesz użyć @jako sedseparatora zamiast, /ponieważ ukośniki są bardziej prawdopodobne, że pojawią się w nazwie gałęzi lub komunikacie o zatwierdzeniu sed.
Ory Band
28

Możesz to zrobić za pomocą kombinacji punktów zaczepienia przygotowanie-commit-msg i pre-commit.

.git / hooks / Preparat-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

Ustaw uprawnienia

sudo chmod 755 .git/hooks/prepare-commit-msg
sudo chmod 755 .git/hooks/pre-commit
Farid Movsumov
źródło
Zwróć uwagę, że może to usunąć oryginalny komunikat o zatwierdzeniu, jeśli używasz --amendna przykład. Zamiast używać echo, powinieneś użyć sedzamiast tego. Tutaj jest w jednej linijce:sed -i "1s@^@$(git branch | grep '^\*' | cut -b3-) @" $1
Ory Band
10

dodaj poniższy kod w pliku Preparat-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

Doda nazwę gałęzi do zatwierdzenia komunikatu, z wyjątkiem merge-commit. Merge-commit domyślnie zawiera informacje o gałęzi, więc dodatkowa nazwa gałęzi jest niepotrzebna i sprawia, że ​​komunikat jest brzydki.

Tim
źródło
1
Więc to nie zmieni komunikatu o zatwierdzeniu, gdy znajdzie słowo scalone w komunikacie?
thoroc
1
@thoroc, który jest technicznie poprawny; jednak w normalnym użytkowaniu nie jest to wielka sprawa. Komunikat o zatwierdzeniu, który jest analizowany, jest „domyślnym” przed ich edycją. Tak długo, jak twój szablon zatwierdzenia nie zawiera słowa „scalanie”, uważam, że powinno być w porządku (o ile inne „domyślne” komunikaty nie zawierają domyślnego komunikatu o zatwierdzeniu przez scalanie). Początkowo źle to zrozumiałem i sądzę, że teraz mam rację.
Nowicjusz C
5

Zainspirowany odpowiedzią Tima, która opiera się na pierwszej odpowiedzi, okazuje się, że hook przygotowawczy-commit-msg przyjmuje jako argument, jaki rodzaj zatwierdzenia występuje . Jak widać w domyślnej wiadomości, przygotuj-zatwierdzenie, jeśli $ 2 to 'merge', to jest to zatwierdzenie scalające. W ten sposób przełącznik wielkości liter można zmienić tak, aby zawierał funkcję addBranchName () Tima.

Zawarłem własne preferencje dotyczące dodawania nazwy gałęzi i wszystkich niekomentowanych części domyślnego prepare-commit-msg.samplezaczepu.

przygotować-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
Nowicjusz C
źródło
4

Jeśli chcesz, aby był globalny (dla wszystkich projektów):

Utwórz git-msgplik z treścią odpowiedzi shytikova i umieść go w jakimś folderze:

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

Teraz włącz haki:

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

i git initponownie w każdym projekcie, którego chcesz użyć.

Maroun
źródło
2
Zauważyłem, że aby skorzystać z tej funkcji, musiałem umieścić „commit-msg” w katalogu „hooks” wewnątrz katalogu skonfigurowanego dla „init.templatedir”, aby po skopiowaniu całego templatedir na „git init”, msg 'kończy się w katalogu' .git / hooks 'projektu.
Dan
2

Miałem problemy z uruchomieniem tych rozwiązań w systemie MacOS, ponieważ używa on BSD sedzamiast GNU sed. Udało mi się jednak stworzyć prosty skrypt, który spełnia swoje zadanie. Nadal używam .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 

Zakłada to standard nazewnictwa gałęzi podobny do functional-desc_JIRA-NUMBER. Jeśli nazwa twojego oddziału to tylko numer biletu Jira, możesz po prostu pozbyć się wszystkiego, od potoku po f2. Wymaga również posiadania pliku o nazwie .gitmessagew katalogu domowym.

PhPGuy
źródło
2

Jeśli chcesz, aby bilet JIRA został dodany do komunikatu o zmianach, użyj poniższego skryptu.

Komunikat PROJECT-2313: Add awesome feature o zatwierdzeniu czegoś w rodzaju To wymaga, aby nazwa twojego oddziału zaczynała się od biletu jira.

To połączenie tych rozwiązań:

Jest zmodyfikowany dla OS X, z sed -i '.bak'i działa również z 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
źródło
Działa to dobrze na pliku po stronie klienta: przygotuj-commit-msg do automatycznego wypełniania prefiksu zatwierdzenia. Ale jeśli chcę zrobić to samo na haku po stronie serwera, którym jest serwer bitbucket (w moim przypadku) i próbuję dodać tę logikę na haku przed odbiorem na ścieżce serwera Bitbucket: BITBUCKET_HOME / shared / data / repositories / <repository-id> / hooks / 21_pre_receive, to nie działa jako "git symbolic-ref -q HEAD" dając 'master', chociaż zatwierdzam z mojej gałęzi feature / abc po stronie klienta. Czy jest inny sposób?
Santhosh