Git: Các Git Hook

Các khóa học qua video:
Python SQL Server PHP C# Lập trình C Java HTML5-CSS3-JavaScript
Học trên YouTube <76K/tháng. Đăng ký Hội viên
Viết nhanh hơn - Học tốt hơn
Giải phóng thời gian, khai phóng năng lực

Git hooks là các tập lệnh chạy tự động mỗi khi có một sự kiện cụ thể xảy ra trong kho Git. Chúng cho phép bạn tùy chỉnh hành vi nội bộ của Git và kích hoạt các hành động có thể tùy chỉnh tại các điểm chính trong vòng đời phát triển.

Móc thực thi trong quá trình tạo cam kết

Các trường hợp sử dụng phổ biến cho móc Git bao gồm khuyến khích chính sách cam kết, thay đổi môi trường dự án tùy thuộc vào trạng thái của kho lưu trữ và thực hiện quy trình tích hợp liên tục. Nhưng, vì các tập lệnh có thể tùy chỉnh vô hạn, bạn có thể sử dụng các móc Git để tự động hóa hoặc tối ưu hóa hầu như mọi khía cạnh của quy trình phát triển của bạn.

Trong bài viết này, chúng ta sẽ bắt đầu với một tổng quan khái niệm về cách hoạt động của móc Git. Sau đó, chúng tôi sẽ khảo sát một số hook phổ biến nhất để sử dụng trong cả kho lưu trữ phía máy chủ và cục bộ.

Tổng quan về khái niệm

Tất cả các hook Git là các tập lệnh thông thường mà Git thực thi khi các sự kiện nhất định xảy ra trong kho lưu trữ. Điều này làm cho chúng rất dễ dàng để cài đặt và cấu hình.

Các hook có thể nằm trong kho lưu trữ cục bộ hoặc phía máy chủ và chúng chỉ được thực thi để đáp ứng với các hành động trong kho lưu trữ đó. Chúng ta sẽ xem xét cụ thể các loại móc sau trong bài viết này. Cấu hình được thảo luận trong phần còn lại của phần này áp dụng cho cả hook cục bộ và phía máy chủ.

Cài đặt móc

Móc nằm trong .git/hooksthư mục của mọi kho lưu trữ Git. Git tự động điền vào thư mục này với các tập lệnh mẫu khi bạn khởi tạo một kho lưu trữ. Nếu bạn nhìn vào bên trong .git/hooks, bạn sẽ tìm thấy các tệp sau:

applypatch-msg.sample pre-push.sample
commit-msg.sample pre-rebase.sample
post-update.sample prepare-commit-msg.sample
pre-applypatch.sample update.sample
pre-commit.sample

Chúng đại diện cho hầu hết các hook có sẵn, nhưng .samplephần mở rộng ngăn chúng thực thi theo mặc định. Để cài đặt một cái móc, một cái móc, tất cả những gì bạn phải làm là xóa .samplephần mở rộng. Hoặc, nếu bạn đang viết một tập lệnh mới từ đầu, bạn chỉ cần thêm một tệp mới khớp với một trong các tên tệp ở trên, trừ .samplephần mở rộng.

Ví dụ, hãy thử cài đặt một prepare-commit-msghook đơn giản . Xóa .samplephần mở rộng khỏi tập lệnh này và thêm phần sau vào tệp:

#!/bin/sh
echo "# Please include a useful commit message!" > $1

Móc cần phải được thực thi, vì vậy bạn có thể cần thay đổi quyền truy cập tệp của tập lệnh nếu bạn đang tạo nó từ đầu. Ví dụ: để đảm bảo có thể prepare-commit-msgthực thi được, bạn sẽ chạy lệnh sau:

chmod +x prepare-commit-msg

Bây giờ bạn sẽ thấy thông báo này thay cho thông báo cam kết mặc định mỗi khi bạn chạy git commit. Chúng ta sẽ xem xét kỹ hơn cách thức này thực sự hoạt động trong phần Chuẩn bị thông báo cam kết. Hiện tại, chúng ta hãy khám phá thực tế rằng chúng ta có thể tùy chỉnh một số chức năng nội bộ của Git.

Các tập lệnh mẫu tích hợp là các tham chiếu rất hữu ích, vì chúng ghi lại các tham số được truyền vào mỗi hook (chúng thay đổi từ hook sang hook).

Ngôn ngữ kịch bản

Các tập lệnh tích hợp chủ yếu là các tập lệnh shell và PERL, nhưng bạn có thể sử dụng bất kỳ ngôn ngữ kịch bản nào bạn muốn miễn là nó có thể được chạy dưới dạng thực thi. Dòng shebang ( #!/bin/sh) trong mỗi tập lệnh xác định cách tệp của bạn sẽ được diễn giải. Vì vậy, để sử dụng một ngôn ngữ khác, tất cả những gì bạn phải làm là thay đổi nó thành đường dẫn của trình thông dịch.

Chẳng hạn, chúng ta có thể viết một tập lệnh Python có thể thực thi được trong prepare-commit-msgtệp thay vì sử dụng các lệnh shell. Các hook sau sẽ làm điều tương tự như shell script trong phần trước.

#!/usr/bin/env python
import sys, os
commit_msg_filepath = sys.argv[1]
with open(commit_msg_filepath, 'w') as f:
f.write("# Please include a useful commit message!")

Lưu ý cách dòng đầu tiên thay đổi để trỏ đến trình thông dịch Python. Và, thay vì sử dụng $1để truy cập đối số đầu tiên được truyền vào tập lệnh, chúng tôi đã sử dụng sys.argv[1](một lần nữa, nhiều hơn về điều này trong một khoảnh khắc).

Đây là một tính năng rất mạnh mẽ cho móc Git vì nó cho phép bạn làm việc với bất kỳ ngôn ngữ nào bạn thấy thoải mái nhất.

Phạm vi của móc

Các hook là cục bộ của bất kỳ kho lưu trữ Git cụ thể nào và chúng không được sao chép sang kho lưu trữ mới khi bạn chạy git clone. Và, vì hook là cục bộ, chúng có thể được thay đổi bởi bất kỳ ai có quyền truy cập vào kho lưu trữ.

Điều này có tác động quan trọng khi cấu hình móc cho một nhóm các nhà phát triển. Trước tiên, bạn cần tìm cách đảm bảo các móc nối luôn cập nhật giữa các thành viên trong nhóm của bạn. Thứ hai, bạn không thể buộc các nhà phát triển tạo ra các cam kết theo cách nào đó mà bạn chỉ có thể khuyến khích họ làm như vậy.

Việc duy trì các hook cho một nhóm các nhà phát triển có thể hơi khó khăn vì .git/hooksthư mục không được sao chép với phần còn lại của dự án của bạn, cũng không nằm trong sự kiểm soát phiên bản. Một giải pháp đơn giản cho cả hai vấn đề này là lưu trữ các hook của bạn trong thư mục dự án thực tế (phía trên .gitthư mục). Điều này cho phép bạn chỉnh sửa chúng như bất kỳ tệp nào được kiểm soát phiên bản khác. Để cài đặt hook, bạn có thể tạo liên kết tượng trưng cho nó .git/hookshoặc bạn chỉ cần sao chép và dán nó vào .git/hooksthư mục bất cứ khi nào hook được cập nhật.

Móc thực thi trong quá trình tạo cam kết

Thay vào đó, Git cũng cung cấp cơ chế Thư mục Mẫu giúp cài đặt móc tự động dễ dàng hơn. Tất cả các tệp và thư mục chứa trong thư mục mẫu này được sao chép vào .gitthư mục mỗi khi bạn sử dụng git inithoặc git clone.

Tất cả các hook cục bộ được mô tả bên dưới có thể được thay đổi bởi các chủ sở hữu của kho lưu trữ. Điều đó hoàn toàn phụ thuộc vào từng thành viên trong nhóm cho dù họ có thực sự sử dụng móc hay không. Với suy nghĩ này, tốt nhất bạn nên nghĩ rằng Git hook là một công cụ phát triển thuận tiện hơn là một chính sách phát triển được thực thi nghiêm ngặt.

Điều đó nói rằng, có thể từ chối các cam kết không tuân thủ một số tiêu chuẩn bằng cách sử dụng các móc phía máy chủ . Chúng ta sẽ nói nhiều hơn về điều này sau trong bài viết.

Móc địa phương

Các hook cục bộ chỉ ảnh hưởng đến kho lưu trữ mà chúng cư trú. Khi bạn đọc qua phần này, hãy nhớ rằng mỗi nhà phát triển có thể thay đổi các móc cục bộ của riêng họ, vì vậy bạn không thể sử dụng chúng như một cách để thực thi chính sách cam kết. Tuy nhiên, họ có thể giúp các nhà phát triển tuân thủ các nguyên tắc nhất định dễ dàng hơn nhiều.

Trong phần này, chúng ta sẽ khám phá 6 trong số các hook địa phương hữu ích nhất:

  • pre-commit
  • prepare-commit-msg
  • commit-msg
  • post-commit
  • post-checkout
  • pre-rebase

4 móc đầu tiên cho phép bạn cắm vào toàn bộ vòng đời cam kết và 2 móc cuối cùng cho phép bạn thực hiện một số hành động bổ sung hoặc kiểm tra an toàn cho các lệnh git checkoutvà git rebaselệnh tương ứng.

Tất cả các pre-hook cho phép bạn thay đổi hành động sắp diễn ra, trong khi các post-hook chỉ được sử dụng cho các thông báo.

Chúng ta cũng sẽ thấy một số kỹ thuật hữu ích để phân tích cú pháp đối số hook và yêu cầu thông tin về kho lưu trữ bằng cách sử dụng các lệnh Git cấp thấp hơn.

Cam kết trước

Các pre-commitkịch bản được thực hiện mỗi khi bạn chạy git committrước Git hỏi các nhà phát triển cho một tin nhắn cam kết hoặc tạo ra một đối tượng cam kết. Bạn có thể sử dụng móc này để kiểm tra ảnh chụp nhanh sắp được cam kết. Ví dụ: bạn có thể muốn chạy một số thử nghiệm tự động để đảm bảo rằng cam kết không phá vỡ bất kỳ chức năng hiện có nào.

Không có đối số nào được chuyển đến pre-committập lệnh và thoát với trạng thái khác không hủy bỏ toàn bộ cam kết. Chúng ta hãy xem một phiên bản đơn giản (và dài dòng hơn) của pre-commitmóc tích hợp. Kịch bản lệnh này hủy bỏ cam kết nếu nó tìm thấy bất kỳ lỗi khoảng trắng nào, như được xác định bởi git diff-indexlệnh (khoảng trắng theo sau, các dòng chỉ có khoảng trắng và một khoảng trắng theo sau là một tab bên trong thụt lề ban đầu của một dòng được coi là lỗi theo mặc định).

#!/bin/sh
# Check if this is the initial commit
if git rev-parse --verify HEAD >/dev/null 2>&1
then
echo "pre-commit: About to create a new commit..."
against=HEAD
else
echo "pre-commit: About to create the first commit..."
against=4b825dc642cb6eb9a060e54bf8d69288fbee4904
fi
# Use git diff-index to check for whitespace errors
echo "pre-commit: Testing for whitespace errors..."
if ! git diff-index --check --cached $against
then
echo "pre-commit: Aborting commit due to whitespace errors"
exit 1
else
echo "pre-commit: No whitespace errors :)"
exit 0
fi

Để sử dụng git diff-index, chúng tôi cần tìm ra tham chiếu cam kết nào chúng tôi đang so sánh chỉ mục. Thông thường, đây là HEAD; tuy nhiên, HEADkhông tồn tại khi tạo cam kết ban đầu, vì vậy nhiệm vụ đầu tiên của chúng tôi là tính toán cho trường hợp cạnh này. Chúng tôi làm điều này với git rev-parse --verify, chỉ đơn giản là kiểm tra xem đối số ( HEAD) có phải là tham chiếu hợp lệ hay không. Các >/dev/null 2>&1phần im lặng bất kỳ sản lượng từ git rev-parse. Hoặc HEADhoặc một đối tượng cam kết trống được lưu trữ trong againstbiến để sử dụng với git diff-index. Các 4b825d...băm là một ID magic cam kết rằng đại diện cho một sản phẩm nào cam kết.

Các git diff-index --cachedlệnh so sánh một cam kết chống lại các chỉ mục. Bằng cách chuyển --checktùy chọn, chúng tôi yêu cầu nó cảnh báo chúng tôi nếu các thay đổi đưa ra lỗi khoảng trắng. Nếu đúng như vậy, chúng ta hủy bỏ cam kết bằng cách trả về trạng thái thoát 1, nếu không chúng ta thoát với 0và luồng công việc cam kết tiếp tục như bình thường.

Đây chỉ là một ví dụ về pre-commithook. Nó sử dụng các lệnh Git hiện có để chạy thử nghiệm các thay đổi được đưa ra bởi cam kết được đề xuất, nhưng bạn có thể làm bất cứ điều gì bạn muốn pre-commitbao gồm thực thi các tập lệnh khác, chạy bộ kiểm tra của bên thứ 3 hoặc kiểm tra kiểu mã với Lint.

Chuẩn bị tin nhắn cam kết

Các prepare-commit-msgmóc được gọi sau khi pre-commitmóc để cư trú trong soạn thảo văn bản với một thông điệp cam kết. Đây là một nơi tốt để thay đổi các thông báo cam kết được tạo tự động cho các cam kết bị nén hoặc sáp nhập.

Một đến ba đối số được truyền cho prepare-commit-msgtập lệnh:

  1. Tên của một tập tin tạm thời có chứa thông điệp. Bạn thay đổi thông điệp cam kết bằng cách thay đổi tệp này tại chỗ.
  2. Các loại cam kết. Điều này có thể là message-mhoặc -Ftùy chọn), template-ttùy chọn), merge(nếu cam kết là một cam kết hợp nhất) hoặc squash(nếu cam kết đang đè bẹp các cam kết khác).
  3. Hàm băm SHA1 của các cam kết có liên quan. Chỉ đưa ra nếu -c-Choặc --amendtùy chọn đã được đưa ra.

Như với pre-commit, thoát với trạng thái khác không hủy bỏ cam kết.

Chúng ta đã thấy một ví dụ đơn giản chỉnh sửa thông điệp cam kết, nhưng hãy xem một tập lệnh hữu ích hơn. Khi sử dụng trình theo dõi vấn đề, một quy ước chung là giải quyết từng vấn đề trong một nhánh riêng. Nếu bạn bao gồm số vấn đề trong tên chi nhánh, bạn có thể viết một prepare-commit-msghook để tự động đưa nó vào từng thông báo cam kết trên nhánh đó.

#!/usr/bin/env python
import sys, os, re
from subprocess import check_output
# Collect the parameters
commit_msg_filepath = sys.argv[1]
if len(sys.argv) > 2:
commit_type = sys.argv[2]
else:
commit_type = ''
if len(sys.argv) > 3:
commit_hash = sys.argv[3]
else:
commit_hash = ''
print "prepare-commit-msg: File: %s\nType: %s\nHash: %s" % (commit_msg_filepath, commit_type, commit_hash)
# Figure out which branch we're on
branch = check_output(['git', 'symbolic-ref', '--short', 'HEAD']).strip()
print "prepare-commit-msg: On branch '%s'" % branch
# Populate the commit message with the issue #, if there is one
if branch.startswith('issue-'):
print "prepare-commit-msg: Oh hey, it's an issue branch."
result = re.match('issue-(.*)', branch)
issue_number = result.group(1)
with open(commit_msg_filepath, 'r+') as f:
content = f.read()
f.seek(0, 0)
f.write("ISSUE-%s %s" % (issue_number, content))

Đầu tiên, prepare-commit-msghook ở trên chỉ cho bạn cách thu thập tất cả các tham số được truyền cho tập lệnh. Sau đó, nó gọi git symbolic-ref --short HEADđể lấy tên chi nhánh tương ứng HEAD. Nếu tên nhánh này bắt đầu bằng issue-, nó sẽ ghi lại nội dung tệp tin nhắn cam kết để bao gồm số vấn đề trong dòng đầu tiên. Vì vậy, nếu tên chi nhánh của bạn là issue-224, điều này sẽ tạo ra thông báo cam kết sau đây.

ISSUE-224
# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
# On branch issue-224
# Changes to be committed:
# modified: test.txt

Một lưu ý khi sử dụng prepare-commit-msglà nó chạy ngay cả khi người dùng chuyển một tin nhắn với -mtùy chọn git commit. Điều này có nghĩa là đoạn script trên sẽ tự động chèn ISSUE-[#]chuỗi mà không cho phép người dùng chỉnh sửa nó. Bạn có thể xử lý trường hợp này bằng cách xem tham số thứ 2 ( commit_type) có bằng không message.

Tuy nhiên, không có -mtùy chọn, prepare-commit-msghook cho phép người dùng chỉnh sửa tin nhắn sau khi được tạo, vì vậy đây thực sự là một kịch bản tiện lợi hơn là một cách để thực thi chính sách tin nhắn cam kết. Đối với điều đó, bạn cần commit-msghook thảo luận trong phần tiếp theo.

Tin nhắn cam kết

Các commit-msgmóc là giống như prepare-commit-msgmóc, nhưng nó được gọi sau khi người dùng nhập vào một thông điệp cam kết. Đây là nơi thích hợp để cảnh báo các nhà phát triển rằng thông điệp của họ không tuân thủ các tiêu chuẩn của nhóm bạn.

Đối số duy nhất được truyền cho hook này là tên của tệp chứa thông báo. Nếu nó không giống như thông báo mà người dùng đã nhập, nó có thể thay đổi tệp này tại chỗ (giống như với prepare-commit-msg) hoặc nó có thể hủy bỏ hoàn toàn cam kết bằng cách thoát với trạng thái khác không.

Ví dụ: tập lệnh sau kiểm tra để đảm bảo rằng người dùng không xóa ISSUE-[#]chuỗi được tạo tự động bởi prepare-commit-msghook trong phần trước.

#!/usr/bin/env python
import sys, os, re
from subprocess import check_output
# Collect the parameters
commit_msg_filepath = sys.argv[1]
# Figure out which branch we're on
branch = check_output(['git', 'symbolic-ref', '--short', 'HEAD']).strip()
print "commit-msg: On branch '%s'" % branch
# Check the commit message if we're on an issue branch
if branch.startswith('issue-'):
print "commit-msg: Oh hey, it's an issue branch."
result = re.match('issue-(.*)', branch)
issue_number = result.group(1)
required_message = "ISSUE-%s" % issue_number
with open(commit_msg_filepath, 'r') as f:
content = f.read()
if not content.startswith(required_message):
print "commit-msg: ERROR! The commit message must start with '%s'" % required_message
sys.exit(1)

Mặc dù tập lệnh này được gọi mỗi khi người dùng tạo một cam kết, bạn nên tránh thực hiện nhiều việc bên ngoài việc kiểm tra thông điệp cam kết. Nếu bạn cần thông báo cho các dịch vụ khác rằng ảnh chụp nhanh đã được cam kết, bạn nên sử dụng post-commithook thay thế.

Sau cam kết

Các post-commitmóc được gọi ngay sau khi commit-msgmóc. Nó không thể thay đổi kết quả của git commithoạt động, vì vậy nó được sử dụng chủ yếu cho mục đích thông báo.

Kịch bản không có tham số và trạng thái thoát của nó không ảnh hưởng đến cam kết theo bất kỳ cách nào. Đối với hầu hết post-commitcác tập lệnh, bạn sẽ muốn truy cập vào cam kết vừa được tạo. Bạn có thể sử dụng git rev-parse HEADđể lấy hàm băm SHA1 của cam kết mới hoặc bạn có thể sử dụng git log -1 HEADđể lấy tất cả thông tin của nó.

Ví dụ: nếu bạn muốn gửi email cho sếp mỗi khi bạn thực hiện một ảnh chụp nhanh (có thể không phải là ý tưởng tốt nhất cho hầu hết các quy trình công việc), bạn có thể thêm post-commitmóc sau đây .

#!/usr/bin/env python
import smtplib
from email.mime.text import MIMEText
from subprocess import check_output
# Get the git log --stat entry of the new commit
log = check_output(['git', 'log', '-1', '--stat', 'HEAD'])
# Create a plaintext email message
msg = MIMEText("Look, I'm actually doing some work:\n\n%s" % log)
msg['Subject'] = 'Git post-commit hook notification'
msg['From'] = 'mary@example.com'
msg['To'] = 'boss@example.com'
# Send the message
SMTP_SERVER = 'smtp.example.com'
SMTP_PORT = 587
session = smtplib.SMTP(SMTP_SERVER, SMTP_PORT)
session.ehlo()
session.starttls()
session.ehlo()
session.login(msg['From'], 'secretPassword')
session.sendmail(msg['From'], msg['To'], msg.as_string())
session.quit()

Có thể sử dụng post-commitđể kích hoạt hệ thống tích hợp liên tục cục bộ, nhưng hầu hết thời gian bạn sẽ muốn thực hiện việc này trong post-receivehook. Điều này chạy trên máy chủ thay vì máy cục bộ của người dùng và nó cũng chạy mỗi khi bất kỳ nhà phát triển nào đẩy mã của họ. Điều này làm cho nó trở thành một nơi thích hợp hơn nhiều để thực hiện tích hợp liên tục của bạn.

Sau thanh toán

Các post-checkoutmóc làm việc rất nhiều như post-commitmóc, nhưng nó được gọi là bất cứ khi nào bạn thành công kiểm tra một tài liệu tham khảo với git checkout. Điều này là tốt để xóa thư mục làm việc của bạn các tập tin được tạo mà nếu không sẽ gây nhầm lẫn.

Hook này chấp nhận ba tham số và trạng thái thoát của nó không ảnh hưởng đến git checkoutlệnh.

  1. Các ref của các Head trước
  2. Các ref của Head mới
  3. Một cờ cho bạn biết nếu đó là kiểm tra chi nhánh hoặc kiểm tra tập tin. Cờ sẽ 1và 0, tương ứng.

Một vấn đề phổ biến với các nhà phát triển Python xảy ra khi .pyccác tệp được tạo dính xung quanh sau khi chuyển nhánh. Trình thông dịch đôi khi sử dụng chúng .pycthay vì .pytệp nguồn. Để tránh mọi sự nhầm lẫn, bạn có thể xóa tất cả .pyccác tệp mỗi khi bạn kiểm tra một nhánh mới bằng cách sử dụng post-checkouttập lệnh sau :

#!/usr/bin/env python
import sys, os, re
from subprocess import check_output
# Collect the parameters
previous_head = sys.argv[1]
new_head = sys.argv[2]
is_branch_checkout = sys.argv[3]
if is_branch_checkout == "0":
print "post-checkout: This is a file checkout. Nothing to do."
sys.exit(0)
print "post-checkout: Deleting all '.pyc' files in working directory"
for root, dirs, files in os.walk('.'):
for filename in files:
ext = os.path.splitext(filename)[1]
if ext == '.pyc':
os.unlink(os.path.join(root, filename))

Thư mục làm việc hiện tại cho các tập lệnh hook luôn được đặt thành thư mục gốc của kho lưu trữ, vì vậy lệnh os.walk('.')gọi lặp lại qua mọi tệp trong kho lưu trữ. Sau đó, chúng tôi kiểm tra phần mở rộng của nó và xóa nó nếu đó là một .pyctập tin.

Bạn cũng có thể sử dụng post-checkouthook để thay đổi thư mục làm việc của mình dựa trên nhánh bạn đã kiểm tra. Ví dụ: bạn có thể sử dụng một pluginsnhánh để lưu trữ tất cả các plugin của mình bên ngoài cơ sở mã cơ sở. Nếu các plugin này yêu cầu rất nhiều nhị phân mà các nhánh khác không có, bạn chỉ có thể xây dựng chúng một cách có chọn lọc khi bạn ở trên pluginsnhánh.

Tiền khởi nghĩa

Các pre-rebasemóc được gọi trước khi git rebasethay đổi bất cứ điều gì, làm cho nó một nơi tốt để đảm bảo một cái gì đó khủng khiếp là không sắp xảy ra.

Móc này có 2 tham số: nhánh ngược dòng mà chuỗi được rẽ nhánh và nhánh bị đảo ngược. Tham số thứ hai trống khi khởi động lại nhánh hiện tại. Để hủy bỏ rebase, thoát với trạng thái khác không.

Ví dụ: nếu bạn muốn không cho phép hoàn toàn việc khởi động lại trong kho lưu trữ của mình, bạn có thể sử dụng pre-rebasetập lệnh sau :

#!/bin/sh
# Disallow all rebasing
echo "pre-rebase: Rebasing is dangerous. Don't do it."
exit 1

Bây giờ, mỗi khi bạn chạy git rebase, bạn sẽ thấy thông báo này:

pre-rebase: Rebasing is dangerous. Don't do it.
The pre-rebase hook refused to rebase.

Để có một ví dụ sâu hơn, hãy xem pre-rebase.samplekịch bản đi kèm . Kịch bản này thông minh hơn một chút về thời điểm không cho phép nổi loạn. Nó kiểm tra xem liệu nhánh chủ đề mà bạn đang cố gắng khởi động lại đã được hợp nhất vào nextnhánh đó chưa (được coi là nhánh chính). Nếu có, có lẽ bạn sẽ gặp rắc rối bằng cách khởi động lại nó, vì vậy kịch bản sẽ hủy bỏ cuộc nổi loạn.

Móc phía máy chủ

Các hook phía máy chủ hoạt động giống như các hook cục bộ, ngoại trừ chúng nằm trong kho lưu trữ phía máy chủ (ví dụ: kho lưu trữ trung tâm hoặc kho lưu trữ công cộng của nhà phát triển). Khi được gắn vào kho lưu trữ chính thức, một số trong số này có thể phục vụ như một cách để thực thi chính sách bằng cách từ chối một số cam kết nhất định.

Có 3 móc phía máy chủ mà chúng ta sẽ thảo luận trong phần còn lại của bài viết này:

  • pre-receive
  • update
  • post-receive

Tất cả các móc này cho phép bạn phản ứng với các giai đoạn khác nhau của git pushquy trình.

Đầu ra từ các móc phía máy chủ được dẫn đến bảng điều khiển của máy khách, do đó rất dễ dàng gửi tin nhắn lại cho nhà phát triển. Tuy nhiên, bạn cũng nên nhớ rằng các tập lệnh này không trả lại quyền kiểm soát thiết bị đầu cuối cho đến khi chúng hoàn thành việc thực thi, vì vậy bạn nên cẩn thận khi thực hiện các hoạt động dài hạn.

Nhận trước

Các pre-receivemóc được thực hiện mỗi khi ai đó sử dụng git pushđể thúc đẩy cam kết vào kho. Nó phải luôn nằm trong kho lưu trữ từ xa là đích đến của việc đẩy chứ không phải trong kho lưu trữ ban đầu.

Móc nối chạy trước khi bất kỳ tài liệu tham khảo nào được cập nhật, vì vậy đây là nơi tốt để thực thi bất kỳ loại chính sách phát triển nào bạn muốn. Nếu bạn không thích ai đang thực hiện việc đẩy, cách thông báo cam kết được định dạng hoặc các thay đổi có trong cam kết, bạn chỉ cần từ chối nó. Mặc dù bạn không thể ngăn các nhà phát triển thực hiện các cam kết không đúng định dạng, bạn có thể ngăn các cam kết này vào cơ sở mã chính thức bằng cách từ chối chúng pre-receive.

Tập lệnh không có tham số, nhưng mỗi tham chiếu đang được đẩy được chuyển đến tập lệnh trên một dòng riêng biệt trên đầu vào tiêu chuẩn theo định dạng sau:

<old-value> <new-value> <ref-name>

Bạn có thể thấy cách hook này hoạt động bằng cách sử dụng một pre-receivetập lệnh rất cơ bản chỉ đơn giản là đọc trong các ref được đẩy và in chúng ra.

#!/usr/bin/env python
import sys
import fileinput
# Read in each ref that the user is trying to update
for line in fileinput.input():
print "pre-receive: Trying to push ref: %s" % line
# Abort the push
# sys.exit(1)

Một lần nữa, điều này khác một chút so với các hook khác vì thông tin được truyền đến tập lệnh thông qua đầu vào tiêu chuẩn thay vì làm đối số dòng lệnh. Sau khi đặt tập lệnh trên vào .git/hooksthư mục của kho lưu trữ từ xa và đẩy masterchi nhánh, bạn sẽ thấy một cái gì đó giống như sau trong bảng điều khiển của bạn:

b6b36c697eb2d24302f89aa22d9170dfe609855b 85baa88c22b52ddd24d71f05db31f4e46d579095 refs/heads/master

Bạn có thể sử dụng các giá trị băm SHA1 này, cùng với một số lệnh Git cấp thấp hơn, để kiểm tra các thay đổi sẽ được giới thiệu. Một số trường hợp sử dụng phổ biến bao gồm:

  • Từ chối các thay đổi liên quan đến một cuộc nổi loạn ngược dòng
  • Ngăn chặn sáp nhập không nhanh
  • Kiểm tra xem người dùng có quyền chính xác để thực hiện các thay đổi dự định không (chủ yếu được sử dụng cho quy trình công việc Git tập trung)

Nếu nhiều ref được đẩy, trả về trạng thái khác không từ pre-receivehủy bỏ tất cả chúng. Nếu bạn muốn chấp nhận hoặc từ chối các chi nhánh trong từng trường hợp cụ thể, bạn cần sử dụng updatehook thay thế.

Cập nhật

Các updatemóc được gọi sau pre-receive, và nó hoạt động nhiều như vậy. Nó vẫn được gọi trước khi mọi thứ thực sự được cập nhật, nhưng nó được gọi riêng cho từng ref được đẩy. Điều đó có nghĩa là nếu người dùng cố gắng đẩy 4 nhánh, updateđược thực hiện 4 lần. Không giống như pre-receive, hook này không cần đọc từ đầu vào tiêu chuẩn. Thay vào đó, nó chấp nhận 3 đối số sau:

  1. Tên của ref đang được cập nhật
  2. Tên đối tượng cũ được lưu trong ref
  3. Tên đối tượng mới được lưu trong ref

Đây là cùng một thông tin được truyền đến pre-receive, nhưng vì updateđược gọi riêng cho từng ref, bạn có thể từ chối một số ref trong khi cho phép những ref khác.

#!/usr/bin/env python
import sys
branch = sys.argv[1]
old_commit = sys.argv[2]
new_commit = sys.argv[3]
print "Moving '%s' from %s to %s" % (branch, old_commit, new_commit)
# Abort pushing only this branch
# sys.exit(1)

Các updatehook ở trên chỉ đơn giản là đầu ra nhánh và băm cam kết cũ / mới. Khi đẩy nhiều hơn một nhánh vào kho lưu trữ từ xa, bạn sẽ thấy printcâu lệnh được thực thi cho mỗi nhánh.

Nhận sau

Các post-receivemóc được gọi sau khi một hoạt động thúc đẩy thành công, làm cho nó một nơi tốt để thực hiện thông báo. Đối với nhiều quy trình công việc, đây là nơi tốt hơn để kích hoạt thông báo hơn post-commitvì các thay đổi có sẵn trên máy chủ công cộng thay vì chỉ nằm trên máy cục bộ của người dùng. Gửi email cho các nhà phát triển khác và kích hoạt một hệ thống tích hợp liên tục là những trường hợp sử dụng phổ biến cho post-receive.

Kịch bản không có tham số, nhưng được gửi cùng thông tin như pre-receivethông qua đầu vào tiêu chuẩn.

Tóm lược

Trong bài viết này, chúng tôi đã tìm hiểu cách Git hook có thể được sử dụng để thay đổi hành vi nội bộ và nhận thông báo khi một số sự kiện nhất định xảy ra trong kho lưu trữ. Móc là các tập lệnh thông thường nằm trong .git/hookskho lưu trữ, giúp chúng rất dễ cài đặt và tùy chỉnh.

Chúng tôi cũng đã xem xét một số các hook cục bộ và phía máy chủ phổ biến nhất. Những điều này cho phép chúng tôi cắm vào toàn bộ vòng đời phát triển. Bây giờ chúng tôi biết cách thực hiện các hành động tùy chỉnh ở mọi giai đoạn trong quy trình tạo cam kết, cũng như git pushquy trình. Với một chút kiến ​​thức về kịch bản, điều này cho phép bạn làm hầu như mọi thứ bạn có thể tưởng tượng với kho Git.

» Tiếp: Đẩy code lên github
« Trước: Migrate
Các khóa học qua video:
Python SQL Server PHP C# Lập trình C Java HTML5-CSS3-JavaScript
Học trên YouTube <76K/tháng. Đăng ký Hội viên
Viết nhanh hơn - Học tốt hơn
Giải phóng thời gian, khai phóng năng lực
Copied !!!