จะเพิ่มชื่อสาขาของ Git ในข้อความคอมมิตได้อย่างไร?


103

ฉันต้องการความช่วยเหลือเกี่ยวกับสคริปต์ Bash ที่จะเพิ่มชื่อสาขาของ git โดยอัตโนมัติเป็นแฮชในข้อความคอมมิต


4
สำหรับใครก็ตามที่มาที่นี่ดูเหมือนว่าคำตอบที่ดีที่สุดจะอยู่ที่ด้านล่างของหน้า
Ben Taliadoros

หมายเหตุด้านข้าง: การgit branch | grep ...รับสาขาปัจจุบันเป็นวิธีที่ผิดในการทำเช่นนี้ พิจารณาอย่างใดอย่างหนึ่งgit symbolic-ref -q HEAD(ดังแสดงในคำตอบนี้ ) git rev-parse --abbrev-ref HEADหรือ คำสั่ง symbolic-ref จะล้มเหลวหากคุณอยู่ใน HEAD ที่แยกออกมาดังนั้นหากคุณต้องการตรวจจับกรณีดังกล่าวให้ใช้ มิฉะนั้นวิธีการ rev-parse --ab สั้น-ref น่าจะดีที่สุด
torek

คำตอบ:


53

ใช้prepare-commit-msgหรือgithookcommit-msg

มีตัวอย่างอยู่แล้วในPROJECT/.git/hooks/ไดเรกทอรีของคุณ

ตามมาตรการรักษาความปลอดภัยคุณจะต้องเปิดใช้งาน hook ด้วยตนเองในแต่ละที่เก็บที่คุณต้องการใช้ แม้ว่าคุณสามารถคอมมิตสคริปต์และคัดลอกบนโคลนทั้งหมดลงใน.git/hooks/ไดเร็กทอรี


ขอบคุณผู้นำที่ดี; ขอบคุณ. หากคุณสามารถช่วยฉันเพิ่มเติมด้วยตัวบทฉันจะขอบคุณ :)
Tomer Lichtash

5
ฉันไม่ต้องการคุณมีตัวอย่างที่ทำในสิ่งที่คุณต้องการอย่างที่ฉันพูดไปแล้วใน.git/hooks/prepare-commit-msg.sample. =) สิ่งที่คุณต้องแก้ไข (หลังจากทำตามคำแนะนำในความคิดเห็น) คือคัดลอกและวางโซลูชันใดก็ได้จากstackoverflow.com/questions/1593051/…ที่คุณต้องการ
ninjagecko

4
@ninjagecko สำหรับฉัน.git/hooks/prepare-commit-msg.sampleมีสามตัวอย่าง หนึ่งสำหรับการแสดงความคิดเห็นในส่วนความขัดแย้งเพิ่มgit diff --name-status -rเอาต์พุตและเพิ่มบรรทัด Signed-off-by ... ไม่มีการเพิ่มชื่อสาขาในข้อความคอมมิต เลยจำใจต้องเขียนเบ็ดเอง
shytikov

1
นี้ไม่you will have to manually enable such a hook on each repository you wish to use itได้หมายความว่าคุณจะต้องให้ FILE รันสิทธิ์? ถ้าเป็นเช่นนั้นฉันขอแก้ไขคำตอบเพื่อรวมสิ่งนั้น (หรือขอคุณได้ไหม)
Dan Rosenstark

2
ทำไมถึงเป็นคำตอบ? มันเหมือนกับให้ฉันใช้ Google สำหรับคุณ คำตอบโดย @shytikov ควรจะเลือก
TheRealFakeNews

177

นี่คือ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]คำสั่ง

เพิ่มเติมเกี่ยวกับคำอธิบายสาขาที่คุณสามารถพบได้ในถาม & ตอบนี้นี้

ตัวอย่างรหัสถูกเก็บไว้ในต่อไปนี้สรุปสาระสำคัญ


8
สคริปต์นี้บีบข้อความคอมมิตหลายบรรทัดเป็นบรรทัดเดียว ฉันแทนที่คำสั่ง echo ของคุณด้วย: echo -n "$ NAME" ':' | cat - "$ 1"> / tmp / out && mv / tmp / out "$ 1"
Alex Spence

4
ใส่ไฟล์นี้ลงในโฟลเดอร์ PROJECT / .git / hooks /
catanore

2
มันทำงานได้ดี แต่สำหรับ Mac ฉันต้องตั้งค่าการอนุญาตด้วยเพื่อให้มันใช้งานได้: >>> sudo chmod 755 .git / hooks / commit-msg
Manoj Shrestha

1
@ManojShrestha ใช่มันจะต้องมีการดำเนินการ
David Mann

2
@AlexSpence ง่ายกว่าที่คุณสามารถecho $NAME: "$(cat $1)" > $1ใช้ได้ สิ่งนี้ได้ผลเนื่องจากเหตุผลที่การขึ้นบรรทัดใหม่หายไปคือเสียงสะท้อนกำลังปฏิบัติต่อแต่ละบรรทัด$(cat "$1")เป็นอาร์กิวเมนต์ใหม่และสะท้อนแต่ละบรรทัดด้วยช่องว่างระหว่าง โดยล้อมรอบ$(cat "$1")ด้วยเครื่องหมายคำพูดคู่ echo ถือว่าเอาต์พุต cat เป็นอาร์กิวเมนต์เดียว นอกจากนี้ฉันไม่คิดว่าจำเป็นต้องอ้างอิง$1เนื่องจากมูลค่าของมันคือ.git/COMMIT_EDITMSG
PiersyP

30

สคริปต์ที่ง่ายกว่าเล็กน้อยที่เพิ่มชื่อสาขาลงในข้อความคอมมิตก่อนหน้านี้คุณแก้ไข ดังนั้นหากคุณต้องการเปลี่ยนหรือลบออกคุณสามารถทำได้

สร้างไฟล์นี้. git / hooks / เตรียมคอมมิต-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

4
ฉันได้รับ: sed: 1: ".git/COMMIT_EDITMSG": invalid command code .เมื่อใช้สิ่งนี้
Adam Parkin

1
Aha ความแตกต่างของ Mac OSX โปรดดู: hintsforums.macworld.com/showpost.php?p=393450&postcount=11สำหรับการแก้ไข
Adam Parkin

2
เช่นเดียวกับการตรวจสอบกรณีแก้ไขและแก้ไข
pogopaule

3
OSX: ต้องการนามสกุลไฟล์เพื่อใช้งานได้หากคุณได้รับข้อความแสดงข้อผิดพลาดข้างต้น sed -i '.bak' "1s/^/$branchName : \n/" $1
canintex

คุณสามารถใช้@เป็นsedตัวคั่นแทนตั้งแต่ทับมีแนวโน้มที่จะแสดงขึ้นมาในชื่อสาขาหรือกระทำข้อความกวดขันขึ้น/ sed
Ory Band

28

คุณสามารถทำได้โดยใช้ hooks เตรียมการคอมมิตและพรีคอมมิตร่วมกัน

.git / hooks / เตรียมคอมมิต -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

โปรดทราบว่าสิ่งนี้สามารถลบข้อความคอมมิตเดิมได้หากคุณใช้--amendตัวอย่างเช่น แทนที่จะใช้echoคุณควรใช้sedแทน นี่คือซับในหนึ่งเดียว:sed -i "1s@^@$(git branch | grep '^\*' | cut -b3-) @" $1
Ory Band

10

เพิ่มโค้ดด้านล่างในไฟล์เตรียมคอมมิต - 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

จะเพิ่มชื่อสาขาเพื่อส่งข้อความยกเว้นการรวมคอมมิต การผสานรวมมีข้อมูลสาขาโดยค่าเริ่มต้นดังนั้นชื่อสาขาพิเศษจึงไม่จำเป็นและทำให้ข้อความน่าเกลียด


1
ดังนั้นสิ่งนี้จะไม่แก้ไขข้อความกระทำเมื่อพบคำว่าผสานในข้อความ?
thoroc

1
@thoroc ที่ถูกต้องทางเทคนิค; อย่างไรก็ตามในการใช้งานปกตินี่ไม่ใช่เรื่องใหญ่ ข้อความคอมมิตที่ถูกแยกวิเคราะห์คือ "ค่าเริ่มต้น" ก่อนที่คุณจะแก้ไข ตราบใดที่เทมเพลตการคอมมิตของคุณไม่มีคำว่า "ผสาน" ฉันเชื่อว่าคุณน่าจะโอเค (ตราบใดที่ข้อความ "ค่าเริ่มต้น" อื่น ๆ ไม่ยกเว้นข้อความคอมมิตการผสานเริ่มต้น) แต่เดิมฉันเข้าใจผิดและเชื่อว่าฉันแก้ไขแล้ว
Novice C

5

ได้รับแรงบันดาลใจจากคำตอบของ Tim ซึ่งสร้างขึ้นจากคำตอบด้านบนปรากฎว่าตะขอเตรียมคอมมิต - msg ใช้เป็นอาร์กิวเมนต์ว่าการกระทำประเภทใดที่เกิดขึ้นอาร์กิวเมนต์ชนิดของการกระทำที่เกิดขึ้นดังที่เห็นในค่าเริ่มต้นเตรียมคอมมิต - msg หาก $ 2 เป็น 'ผสาน' แสดงว่าเป็นการรวมคอมมิต ดังนั้นสวิตช์เคสจึงสามารถเปลี่ยนแปลงได้เพื่อรวมฟังก์ชัน addBranchName () ของ Tim

ฉันได้รวมการตั้งค่าของตัวเองสำหรับวิธีการเพิ่มชื่อสาขาและส่วนที่ไม่ใส่ส่วนประกอบทั้งหมดของprepare-commit-msg.sampleเบ็ดเริ่มต้น

เตรียมการกระทำ 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

4

หากคุณต้องการทำให้เป็นสากล (สำหรับทุกโครงการ):

สร้างgit-msgไฟล์ที่มีเนื้อหาของคำตอบของ shytikovและวางไว้ในบางโฟลเดอร์:

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

ตอนนี้เปิดใช้งาน hooks:

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

และgit initอีกครั้งในแต่ละโครงการที่คุณต้องการใช้


2
ฉันพบว่าในการใช้คุณสมบัตินี้ฉันต้องใส่ 'comm-msg' ลงในไดเร็กทอรี 'hooks' ภายในไดเร็กทอรีที่กำหนดค่าสำหรับ 'init.templatedir' ดังนั้นเมื่อ templatedir ทั้งหมดถูกคัดลอกบน 'git init', 'กระทำ - msg 'สิ้นสุดในไดเร็กทอรี' .git / hooks 'ของโปรเจ็กต์
แดน

2

ผมมีปัญหาได้รับการแก้ไขปัญหาเหล่านี้จะทำงานใน MacOS เนื่องจากความจริงที่ว่ามันใช้ BSD sedแทน sedGNU ฉันจัดการสร้างสคริปต์ง่ายๆที่ใช้งานได้ดี ยังคงใช้.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ในโฮมไดเร็กทอรีของคุณ


2

ในกรณีที่คุณต้องการให้ตั๋ว 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

สิ่งนี้ทำงานได้ดีกับไฟล์ฝั่งไคลเอ็นต์: เตรียมคอมมิท - msg เพื่อเติมคำนำหน้าคอมมิตอัตโนมัติ แต่ถ้าฉันต้องการทำเช่นเดียวกันบน hook ฝั่งเซิร์ฟเวอร์ซึ่งเป็นเซิร์ฟเวอร์ bitbucket (ในกรณีของฉัน) และฉันกำลังพยายามเพิ่มตรรกะนี้ในการรับเบ็ดล่วงหน้าที่เส้นทางเซิร์ฟเวอร์ Bitbucket: BITBUCKET_HOME / shared / data / repositories / <repository-id> / hooks / 21_pre_receive มันไม่ทำงานเป็น "git symbolic-ref -q HEAD" ที่ให้ 'master' แม้ว่าฉันจะยอมรับจาก feature / abc branch จากฝั่งไคลเอ็นต์ มีวิธีอื่นอีกไหม
santhosh
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.