Làm cách nào để thêm tên chi nhánh của Git vào thông báo cam kết?


103

Tôi cần một số trợ giúp với tập lệnh Bash sẽ tự động thêm tên chi nhánh của git làm băm trong các thông báo cam kết.


3
Đối với bất cứ ai đến đây là dường như câu trả lời tốt nhất là ở dưới cùng của trang
Bến Taliadoros

Lưu ý phụ: tất cả các cách git branch | grep ...để lấy nhánh hiện tại là cách làm sai. Cân nhắc một trong hai git symbolic-ref -q HEAD(như trong câu trả lời này ) hoặc git rev-parse --abbrev-ref HEAD. Lệnh Symbol-ref sẽ không thành công nếu bạn đang ở trên HEAD tách rời, vì vậy nếu bạn muốn phát hiện trường hợp đó, hãy sử dụng nó. Nếu không thì phương pháp phân tích cú pháp --abbrev-ref có lẽ là tốt nhất.
torek

Câu trả lời:


53

Sử dụng prepare-commit-msghoặc commit-msg githook .

Có những ví dụ đã có trong PROJECT/.git/hooks/thư mục của bạn .

Như một biện pháp bảo mật, bạn sẽ phải kích hoạt thủ công một hook như vậy trên mỗi kho lưu trữ mà bạn muốn sử dụng nó. Mặc dù vậy, bạn có thể cam kết tập lệnh và sao chép nó trên tất cả các bản sao vào .git/hooks/thư mục.


Cảm ơn một khách hàng tiềm năng; cảm ơn bạn. Nếu bạn có thể giúp tôi thêm, với chính kịch bản, tôi sẽ rất biết ơn :)
Tomer Lichtash

5
Tôi không cần phải làm như vậy, bạn đã có một ví dụ thực hiện chính xác những gì bạn muốn , như tôi đã nói, trong .git/hooks/prepare-commit-msg.sample. =) Tất cả những gì bạn cần sửa đổi (sau khi làm theo hướng dẫn trong phần nhận xét) là sao chép-dán bất kỳ giải pháp nào từ stackoverflow.com/questions/1593051/… mà bạn muốn
ninjagecko

4
@ninjagecko, đối với tôi .git/hooks/prepare-commit-msg.samplecó ba ví dụ. Một để nhận xét phần xung đột, thêm git diff --name-status -rđầu ra cho nó và thêm dòng đã ký tên ... Không thêm tên chi nhánh vào thông báo cam kết. Vì vậy, tôi buộc phải viết cái móc của riêng mình.
shytikov.

1
Điều này you will have to manually enable such a hook on each repository you wish to use itcó nghĩa là bạn phải cấp quyền thực thi FILE? Nếu vậy, tôi có thể chỉnh sửa câu trả lời để đưa vào (hoặc bạn có thể làm ơn) được không?
Dan Rosenstark

1
Tại sao đây là câu trả lời? Nó giống như để tôi google cái đó cho bạn. Câu trả lời của @shytikov nên được chọn
TheRealFakeNews

177

Đây là commit-msgtập lệnh của tôi làm ví dụ:

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

Tạo thông báo cam kết sau:

[branch_name]: [original_message]

[branch_description]

Tôi đang sử dụng số vấn đề như branch_name, mô tả vấn đề được đặt vào lệnh branch_descriptionusing git branch --edit-description [branch_name].

Bạn có thể tìm thấy thêm về mô tả chi nhánh trong phần Hỏi và Đáp này .

Ví dụ mã được lưu trữ trong Gist sau đây .


8
Tập lệnh này dồn các thông điệp cam kết nhiều dòng vào một dòng. Tôi đã thay thế câu lệnh echo của bạn bằng: echo -n "$ NAME" ':' | cat - "$ 1"> / tmp / out && mv / tmp / out "$ 1"
Alex Spence

4
Đặt tập tin này vào thư mục DỰ ÁN / .git / móc /
catanore

2
Nó hoạt động tốt. Nhưng đối với Mac, tôi đã phải thiết lập sự cho phép quá để làm cho nó hoạt: >>> sudo chmod 755 .git / móc / cam-msg
Manoj Shrestha

1
@ManojShrestha vâng nó đã được thực thi
David Mann

2
@AlexSpence đơn giản hơn bạn có thể sử dụng echo $NAME: "$(cat $1)" > $1. Điều này hoạt động bởi vì lý do các dòng mới bị mất là tiếng vọng đang coi mỗi dòng $(cat "$1")là một đối số mới và lặp lại mỗi dòng với một khoảng cách giữa. Bằng cách đặt xung quanh $(cat "$1")dấu ngoặc kép, echo coi đầu ra là một đối số duy nhất. Ngoài ra tôi không nghĩ rằng nó là cần thiết để trích dẫn $1vì giá trị của nó là.git/COMMIT_EDITMSG
PiersyP

30

Một tập lệnh đơn giản hơn một chút bổ sung tên nhánh vào thông báo cam kết trước khi bạn chỉnh sửa nó. Vì vậy, nếu bạn muốn thay đổi hoặc loại bỏ nó, bạn có thể.

Tạo tệp này .git / hooks / standard-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

4
Tôi nhận được: sed: 1: ".git/COMMIT_EDITMSG": invalid command code .khi sử dụng cái này.
Adam Parkin

1
Aha, Mac OSX chênh lệch, xem: hintsforums.macworld.com/showpost.php?p=393450&postcount=11 cho việc sửa chữa
Adam Parkin

2
như việc kiểm tra các trường hợp sửa đổi, bổ fixup
pogopaule

3
OSX: Cần phần mở rộng tệp để hoạt động nếu bạn nhận được thông báo lỗi ở trên. sed -i '.bak' "1s/^/$branchName : \n/" $1
canintex

Bạn có thể sử dụng @làm seddấu phân tách thay vì vì /dấu gạch chéo về phía trước có nhiều khả năng hiển thị trong tên chi nhánh hoặc thông báo cam kết, rất khó sed.
Ory Band

28

Bạn có thể làm điều đó với sự kết hợp của hook chuẩn bị-commit-msg và pre-commit.

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

Đặt quyền

sudo chmod 755 .git/hooks/prepare-commit-msg
sudo chmod 755 .git/hooks/pre-commit

Lưu ý rằng điều này có thể xóa thông báo cam kết ban đầu nếu bạn đang sử dụng --amendchẳng hạn. Thay vì sử dụng echobạn nên sử dụng sedthay thế. Dưới đây là trong một lót:sed -i "1s@^@$(git branch | grep '^\*' | cut -b3-) @" $1
ORY nhạc

10

thêm mã bên dưới vào tệp tin chuẩn bị.

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

Nó sẽ thêm tên nhánh vào thông báo cam kết ngoại trừ hợp nhất-cam kết. Hợp nhất-cam kết có thông tin nhánh theo mặc định vì vậy tên nhánh bổ sung là không cần thiết và làm cho thông báo trở nên xấu xí.


1
Vì vậy, điều này sẽ không sửa đổi thông báo cam kết khi nó tìm thấy từ hợp nhất trên thông báo?
thoroc

1
@thoroc đó là đúng về mặt kỹ thuật; tuy nhiên, trong sử dụng bình thường, đây không phải là một vấn đề lớn. Thông báo cam kết được phân tích cú pháp là "những thông báo mặc định" trước khi bạn chỉnh sửa chúng. Vì vậy, miễn là mẫu cam kết của bạn không có từ "hợp nhất" trong đó, tôi tin rằng bạn sẽ ổn (miễn là các thông báo "mặc định" khác không ngoại trừ thông báo cam kết hợp nhất mặc định). Tôi đã hiểu sai điều này ban đầu, và tin rằng tôi đã đúng.
Novice C

5

Lấy cảm hứng từ câu trả lời của Tim được xây dựng dựa trên câu trả lời hàng đầu, hóa ra hook chuẩn bị-cam kết-msg lấy làm đối số về loại cam kết nào đang xảy ra . Như đã thấy trong standard-commit-msg mặc định nếu $ 2 là 'hợp nhất' thì đó là một cam kết hợp nhất. Do đó, công tắc trường hợp có thể được thay đổi để bao gồm hàm addBranchName () của Tim.

Tôi đã bao gồm tùy chọn của riêng mình về cách thêm tên nhánh và tất cả các phần không có chú thích của prepare-commit-msg.samplehook mặc định .

chuẩn bị-cam kết-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

Nếu bạn muốn đưa nó ra toàn cầu (cho tất cả các dự án):

Tạo git-msgtệp với nội dung câu trả lời của shytikov và đặt nó vào thư mục nào đó:

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

Bây giờ hãy kích hoạt hook:

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

git initmột lần nữa trong mỗi dự án bạn muốn sử dụng nó.


2
Tôi thấy rằng để sử dụng tính năng này, tôi phải đặt 'commit-msg' vào thư mục 'hooks' bên trong thư mục được định cấu hình cho 'init.templatedir' để khi toàn bộ templatedir được sao chép trên 'git init', 'commit- msg 'kết thúc trong thư mục' .git / hooks 'của dự án.
Dan

2

Tôi gặp sự cố khi đưa các giải pháp này hoạt động trên MacOS do thực tế là nó sử dụng BSD sedthay vì GNU sed. Mặc dù vậy, tôi đã cố gắng tạo một tập lệnh đơn giản để thực hiện công việc. Vẫn đang sử dụng .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 

Điều này giả định một tiêu chuẩn đặt tên nhánh tương tự như functional-desc_JIRA-NUMBER. Nếu tên chi nhánh của bạn chỉ là số vé Jira của bạn, bạn chỉ cần loại bỏ mọi thứ từ đường ống đến f2. Nó cũng yêu cầu bạn có một tệp có tên .gitmessagetrong thư mục chính của bạn.


2

Trong trường hợp bạn muốn thêm vé JIRA vào thông báo cam kết, hãy sử dụng đoạn mã dưới đây.

Thông báo cam kết như thế PROJECT-2313: Add awesome feature này yêu cầu tên chi nhánh của bạn phải bắt đầu bằng Vé jira.

Đây là sự kết hợp của các giải pháp này:

Nó được sửa đổi cho OS X, với sed -i '.bak'và nó hoạt động tốt từ 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

Điều này đang hoạt động tốt trên tệp phía máy khách: chuẩn bị-cam kết-msg để tự động điền tiền tố cam kết. Nhưng nếu tôi muốn làm điều tương tự trên hook phía máy chủ, đó là máy chủ bitbucket (trong trường hợp của tôi) và tôi đang cố gắng thêm logic này trên hook nhận trước tại đường dẫn máy chủ Bitbucket: BITBUCKET_HOME / shared / data / repositories / <repository-id> / hooks / 21_pre_receive, nó không hoạt động như "git Symbol-ref -q HEAD" đưa ra 'master' mặc dù tôi đang cam kết từ chi nhánh feature / abc của mình từ phía máy khách. Có cách nào khác ở đây không?
santhosh
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.