2015-11-25 17 views
10

Hãy ngay lập tức bắt đầu với một phế liệu của móc pre-receive mà tôi đã viết:Git móc '-nhận tiền' và 'git-vang-format' kịch bản đáng tin cậy từ chối push vi phạm công ước mã phong cách

#!/bin/sh 
## 
    format_bold='\033[1m' 
    format_red='\033[31m' 
format_yellow='\033[33m' 
format_normal='\033[0m' 
## 
    format_error="${format_bold}${format_red}%s${format_normal}" 
format_warning="${format_bold}${format_yellow}%s${format_normal}" 
## 
stdout() { 
    format="${1}" 
    shift 
    printf "${format}" "${@}" 
} 
## 
stderr() { 
    stdout "${@}" 1>&2 
} 
## 
output() { 
    format="${1}" 
    shift 
    stdout "${format}\n" "${@}" 
} 
## 
error() { 
    format="${1}" 
    shift 
    stderr "${format_error}: ${format}\n" 'error' "${@}" 
} 
## 
warning() { 
    format="${1}" 
    shift 
    stdout "${format_warning}: ${format}\n" 'warning' "${@}" 
} 
## 
die() { 
    error "${@}" 
    exit 1 
} 
## 
git() { 
    command git --no-pager "${@}" 
} 
## 
list() { 
    git rev-list "${@}" 
} 
## 
clang_format() { 
    git clang-format --style='file' "${@}" 
} 
## 
while read sha1_old sha1_new ref; do 
    case "${ref}" in 
    refs/heads/*) 
    branch="$(expr "${ref}" : 'refs/heads/\(.*\)')" 
    if [ "$(expr "${sha1_new}" : '0*$')" -ne 0 ]; then # delete 
     unset sha1_new 
     # ... 
    else # update 
     if [ "$(expr "${sha1_old}" : '0*$')" -ne 0 ]; then # create 
     unset sha1_old 
     sha1_range="${sha1_new}" 
     else 
     sha1_range="${sha1_old}..${sha1_new}" 
     # ... 
     fi 
     fi 
     # ... 
      GIT_WORK_TREE="$(mktemp --tmpdir -d 'gitXXXXXX')" 
     export GIT_WORK_TREE 
      GIT_DIR="${GIT_WORK_TREE}/.git" 
     export GIT_DIR 
     mkdir -p "${GIT_DIR}" 
     cp -a * "${GIT_DIR}/" 
     ln -s "${PWD}/../.clang-format" "${GIT_WORK_TREE}/" 
     error= 
     for sha1 in $(list "${sha1_range}"); do 
     git checkout --force "${sha1}" > '/dev/null' 2>&1 
     if [ "$(list --count "${sha1}")" -eq 1 ]; then 
      # What should I put here? 
     else 
      git reset --soft 'HEAD~1' > '/dev/null' 2>&1 
     fi 
     diff="$(clang_format --diff)" 
     if [ "${diff%% *}" = 'diff' ]; then 
      error=1 
      error '%s: %s\n%s'             \ 
       'Code style issues detected'         \ 
       "${sha1}"              \ 
       "${diff}"              \ 
       1>&2 
     fi 
     done 
     if [ -n "${error}" ]; then 
     die '%s' 'Code style issues detected' 
     fi 
    fi 
    ;; 
    refs/tags/*) 
    tag="$(expr "${ref}" : 'refs/tags/\(.*\)')" 
    # ... 
    ;; 
    *) 
    # ... 
    ;; 
    esac 
done 
exit 0 

LƯU Ý:
Các địa điểm có mã không liên quan được trang bị # ....

LƯU Ý:
Nếu bạn không quen thuộc với git-clang-format, hãy xem here.

Móc đó hoạt động như mong đợi, và cho đến nay, tôi không nhận thấy bất kỳ lỗi nào, nhưng nếu bạn phát hiện bất kỳ vấn đề nào hoặc có đề xuất cải tiến, tôi đánh giá cao bất kỳ báo cáo nào. Có lẽ, tôi nên đưa ra nhận xét về ý định đằng sau cái móc này là gì. Vâng, nó kiểm tra mọi sửa đổi để tuân thủ các quy ước kiểu mã bằng cách sử dụng git-clang-format và nếu bất kỳ quy tắc nào không tuân thủ, nó sẽ tạo ra sự khác biệt có liên quan (bản phát hành nói cho nhà phát triển những gì nên được sửa) cho mỗi người trong số họ. Về cơ bản, tôi có hai câu hỏi chuyên sâu về móc này.

Trước tiên, lưu ý rằng tôi thực hiện sao chép kho lưu trữ trống (máy chủ) của từ xa vào một số thư mục tạm thời và kiểm tra mã để phân tích ở đó. Hãy để tôi giải thích về ý định này. Lưu ý rằng tôi thực hiện một số git checkout s và git reset s (do vòng lặp for) để phân tích tất cả các bản sửa đổi được đẩy riêng lẻ với git-clang-format. Những gì tôi đang cố gắng để tránh ở đây, là (có thể) vấn đề đồng thời về đẩy truy cập vào kho lưu trữ trần (máy chủ) của từ xa. Đó là, tôi đang bị ấn tượng rằng nếu nhiều nhà phát triển sẽ cố gắng đẩy cùng một lúc với điều khiển từ xa với móc cài đặt pre-receive này, điều đó có thể gây ra sự cố nếu mỗi "phiên" này không thực hiện git checkout s và git reset s bản sao lưu trữ riêng của nó. Vì vậy, để đặt nó đơn giản, không git-daemon có tích hợp khóa quản lý cho đồng thời đẩy "phiên"? Nó sẽ thực hiện các trường hợp móc pre-receive tương ứng một cách chặt chẽ theo tuần tự hoặc có khả năng xen kẽ (có khả năng có thể gây ra hành vi không xác định)? Một cái gì đó nói với tôi rằng cần phải có một giải pháp tích hợp cho vấn đề này với sự đảm bảo cụ thể, nếu không làm thế nào điều khiển từ xa sẽ làm việc nói chung (thậm chí không có móc phức tạp) đang bị đẩy đồng thời? Nếu có một giải pháp tích hợp như vậy, thì bản sao là không cần thiết và chỉ đơn giản là sử dụng lại kho trống sẽ thực sự đẩy nhanh quá trình xử lý. Bằng cách này, bất kỳ tham chiếu đến tài liệu chính thức liên quan đến câu hỏi này là rất hoan nghênh.

Thứ hai, git-clang-format chỉ xử lý được tổ chức (nhưng không cam kết) thay đổi so với cam kết cụ thể (HEAD theo mặc định). Vì vậy, bạn có thể dễ dàng nhìn thấy nơi một trường hợp góc nằm. Có, đó là với cam kết gốc (bản sửa đổi). Thực tế, không thể áp dụng git reset --soft 'HEAD~1' cho các cam kết gốc vì chúng không có cha mẹ để đặt lại. Do đó, việc kiểm tra sau đây với câu hỏi thứ hai của tôi là ở đó:

 if [ "$(list --count "${sha1}")" -eq 1 ]; then 
      # What should I put here? 
     else 
      git reset --soft 'HEAD~1' > '/dev/null' 2>&1 
     fi 

Tôi đã thử git update-ref -d 'HEAD' nhưng điều này phá vỡ kho theo cách như vậy mà git-clang-format là không thể xử lý nó nữa. Tôi tin rằng điều này có liên quan đến thực tế là tất cả các bản sửa đổi được đẩy đang được phân tích (bao gồm cả bản gốc này) không thực sự thuộc về bất kỳ chi nhánh nào. Tức là, họ đang ở trạng thái tách raHEAD.Sẽ là hoàn hảo để tìm giải pháp cho trường hợp góc này, do đó, cam kết ban đầu cũng có thể trải qua cùng một kiểm tra bằng git-clang-format để tuân thủ các quy ước kiểu mã.

Hòa bình.

Trả lời

4

LƯU Ý:
Đối với những người tìm kiếm một ngày up-to-, giải pháp (nhiều hơn hoặc ít hơn) toàn diện, và được kiểm tra kỹ, tôi đăng cai kho công khai tương ứng [1]. Hiện tại, hai móc quan trọng dựa trên git-clang-format được triển khai: pre-commitpre-receive. Lý tưởng nhất là bạn nhận được quy trình làm việc tự động và chống trộm nhất khi sử dụng cả hai cùng một lúc. Như thường lệ, đề xuất cải tiến rất được hoan nghênh.

LƯU Ý:
Hiện nay, móc pre-commit [1] đòi hỏi sự git-clang-format.diff vá (tác giả của tôi cũng) [1] để được áp dụng cho git-clang-format. Các ví dụ về động lực và trường hợp sử dụng cho bản vá này được tóm tắt trong bản đánh giá bản vá chính thức cho LLVM/Clang [2]. Hy vọng rằng, nó sẽ sớm được chấp nhận và sáp nhập.


Tôi đã quản lý để triển khai giải pháp cho câu hỏi thứ hai. Tôi phải thừa nhận rằng nó không phải là dễ dàng để tìm thấy do tài liệu Git khan hiếm và vắng mặt của các ví dụ. Chúng ta hãy nhìn vào những thay đổi mã tương ứng đầu tiên:

# ... 
clang_format() { 
    git clang-format --commit="${commit}" --style='file' "${@}" 
} 
# ... 
     for sha1 in $(list "${sha1_range}"); do 
     git checkout --force "${sha1}" > '/dev/null' 2>&1 
     if [ "$(list --count "${sha1}")" -eq 1 ]; then 
      commit='4b825dc642cb6eb9a060e54bf8d69288fbee4904' 
     else 
      commit='HEAD~1' 
     fi 
     diff="$(clang_format --diff)" 
     # ... 
     done 
     # ... 

Như bạn thấy, thay vì liên tục làm git reset --soft 'HEAD~1', bây giờ tôi hướng dẫn một cách rõ ràng git-clang-format để hoạt động chống lại HEAD~1 với các tùy chọn --commit (trong khi mặc định của nó là HEAD đó là ngụ ý trong phiên bản ban đầu được trình bày trong câu hỏi của tôi). Tuy nhiên, điều đó vẫn không giải quyết được vấn đề bởi vì khi chúng tôi nhấn gốc, hãy cam kết điều này một lần nữa sẽ dẫn đến lỗi khi HEAD~1 sẽ không tham chiếu đến bản sửa đổi hợp lệ nữa (tương tự như cách không thể thực hiện git reset --soft 'HEAD~1') . Đó là lý do tại sao trong trường hợp cụ thể này, tôi hướng dẫn git-clang-format để hoạt động chống lại (băm) 4b825dc642cb6eb9a060e54bf8d69288fbee4904 băm (ma thuật) [3, 4, 5, 6]. Để tìm hiểu thêm về băm này, hãy tham khảo tài liệu tham khảo, nhưng tóm lại, nó đề cập đến đối tượng cây trống Git - không có gì được dàn dựng hoặc cam kết, chính xác là những gì chúng tôi cần git-clang-format để hoạt động trong trường hợp của chúng tôi.

LƯU Ý:
Bạn không cần phải nhớ 4b825dc642cb6eb9a060e54bf8d69288fbee4904 bởi trái tim và nó tốt hơn không cứng mã nó (chỉ trong trường hợp băm ma thuật này bao giờ thay đổi trong tương lai). Nó chỉ ra rằng nó luôn luôn có thể được lấy ra với git hash-object -t tree '/dev/null' [5, 6]. Do đó, trong phiên bản cuối cùng của móc câu pre-receive ở trên, tôi có commit="$(git hash-object -t tree '/dev/null')" thay thế.

P.S. Tôi vẫn đang tìm kiếm câu trả lời có chất lượng tốt về câu hỏi đầu tiên của mình. Nhân tiện, tôi đã hỏi những câu hỏi này trên danh sách gửi thư chính thức của Git và không nhận được câu trả lời nào cho đến nay, thật đáng tiếc ...

Các vấn đề liên quan