2015-11-25 11 views
10

आइए तुरंत pre-receive हुक के एक स्क्रैप कि मैं पहले से ही लिखा है के साथ शुरू:Git 'पूर्व प्राप्त' हुक और 'Git-बजना प्रारूप' स्क्रिप्ट मज़बूती से धक्का का उल्लंघन कोड शैली सम्मेलनों को अस्वीकार करने के

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

नोट:
अप्रासंगिक कोड वाले स्थान # ... के साथ दबाए गए हैं।

नोट:
आप git-clang-format से परिचित नहीं हैं, तो एक नजर here ले।

वह हुक अपेक्षित काम करता है, और अब तक, मुझे कोई भी बग नहीं दिखाई देता है, लेकिन यदि आप किसी समस्या को देखते हैं या कोई सुधार सुझाव देते हैं, तो मैं किसी भी रिपोर्ट की सराहना करता हूं। शायद, मुझे इस हुक के पीछे क्या इरादा है इस पर एक टिप्पणी देनी चाहिए। खैर, यह git-clang-format का उपयोग करके कोड शैली सम्मेलनों के अनुपालन के लिए प्रत्येक धक्का संशोधन की जांच करता है, और यदि उनमें से कोई भी अनुपालन नहीं करता है, तो यह उनमें से प्रत्येक के लिए प्रासंगिक diff (एक डेवलपर्स को क्या तय किया जाना चाहिए) आउटपुट करेगा। असल में, मेरे पास इस हुक के बारे में दो गहन प्रश्न हैं।

सबसे पहले, ध्यान दें कि मैं कुछ अस्थायी निर्देशिका में रिमोट (सर्वर) नंगे भंडार की प्रतिलिपि करता हूं और वहां विश्लेषण के लिए कोड देखता हूं। मुझे इसके इरादे की व्याख्या करने दो। ध्यान दें कि git-clang-format के साथ व्यक्तिगत रूप से सभी धक्का संशोधनों का विश्लेषण करने के लिए मैं कई git checkout s और git reset s (for लूप के कारण) करता हूं। मैं यहां से बचने की कोशिश कर रहा हूं, रिमोट (सर्वर) नंगे भंडार में पुश पहुंच पर (संभव) समवर्ती मुद्दा है। यही है, मैं इस धारणा के तहत हूं कि यदि एकाधिक डेवलपर्स एक ही समय में इस pre-receive हुक के साथ रिमोट पर धक्का देने का प्रयास करेंगे, तो इन समस्याओं में से प्रत्येक "सत्र" git checkout एस और git reset एस के साथ नहीं होने पर समस्याएं पैदा हो सकती हैं भंडार की इसकी निजी प्रति। तो, इसे सरल रखने के लिए, git-daemon में समवर्ती धक्का "सत्र" के लिए अंतर्निहित लॉक प्रबंधन है? क्या यह संबंधित pre-receive हुक उदाहरणों को सख्ती से अनुक्रमिक रूप से निष्पादित करेगा या इंटरलिविंग की संभावना है (जो संभावित रूप से अपरिभाषित व्यवहार का कारण बन सकता है)? कुछ मुझे बताता है कि कंक्रीट गारंटी के साथ इस समस्या के लिए एक अंतर्निहित समाधान होना चाहिए, अन्यथा समवर्ती धक्का के अधीन सामान्य रूप से काम (जटिल हुक के बिना) को कैसे हटाया जाएगा? यदि ऐसा कोई अंतर्निहित समाधान है, तो प्रतिलिपि अनावश्यक है और केवल नंगे भंडार का पुन: उपयोग करने से वास्तव में प्रसंस्करण तेज हो जाएगा। वैसे, इस प्रश्न के बारे में आधिकारिक दस्तावेज का कोई भी संदर्भ बहुत स्वागत है।

दूसरा, git-clang-format प्रक्रियाओं केवल मंचन (लेकिन प्रतिबद्ध) बनाम विशिष्ट कुछ परिवर्तन के लिए प्रतिबद्ध (HEAD डिफ़ॉल्ट रूप से)। इस प्रकार, आप आसानी से देख सकते हैं कि एक कोने का मामला कहाँ है। हां, यह रूट के साथ है (संशोधन)। वास्तव में, git reset --soft 'HEAD~1' रूट प्रतिबद्धताओं पर लागू नहीं किया जा सकता क्योंकि उनके पास रीसेट करने के लिए कोई माता-पिता नहीं हैं। इसलिए, मेरी दूसरी सवाल के साथ निम्नलिखित की जांच होती है:

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

मैं git update-ref -d 'HEAD' की कोशिश की है, लेकिन यह इस तरह से भंडार टूट जाता है कि git-clang-format इसे अब और प्रोसेस करने में सक्षम नहीं है। मेरा मानना ​​है कि यह इस तथ्य से संबंधित है कि इन सभी ने संशोधित संशोधनों का विश्लेषण किया है (इस रूट सहित) वास्तव में अभी तक किसी भी शाखा से संबंधित नहीं हैं। यही है, वे अलगHEAD राज्य में हैं।इस कोने के मामले में भी समाधान ढूंढना सही होगा, ताकि प्रारंभिक प्रतिबद्धता कोड शैली सम्मेलनों के अनुपालन के लिए git-clang-format द्वारा एक ही चेक से गुजर सकती है।

शांति।

उत्तर

4

नोट:
एक अप-टू-डेट की तलाश में उन लोगों के लिए, (कम या ज्यादा) व्यापक, और अच्छी तरह से परीक्षण किया समाधान, मैं इसी सार्वजनिक भंडार [1] होस्ट करते हैं। वर्तमान में, git-clang-format पर निर्भर दो महत्वपूर्ण हुक लागू किए गए हैं: pre-commit और pre-receive। आदर्श रूप से, आप दोनों को एक साथ उपयोग करते समय सबसे अधिक स्वचालन और मूर्ख-प्रमाण कार्यप्रवाह प्राप्त करते हैं। हमेशा की तरह, सुधार सुझावों का बहुत स्वागत है।

नोट:
वर्तमान में, pre-commit हुक [1] git-clang-format.diff पैच (और साथ ही मुझे द्वारा लेखक) [1] git-clang-format लिए लागू किया जा करने के लिए की आवश्यकता है। इस पैच के लिए प्रेरणा और उपयोग केस उदाहरणों को आधिकारिक पैच समीक्षा सबमिशन में एलएलवीएम/क्लैंग [2] में सारांशित किया गया है। उम्मीद है कि इसे जल्द ही अपस्ट्रीम स्वीकार कर लिया जाएगा और विलय कर दिया जाएगा।


मैंने दूसरे प्रश्न के लिए समाधान लागू करने में कामयाब रहा है। मुझे यह मानना ​​है कि गिट दस्तावेज और उदाहरणों की अनुपस्थिति के कारण यह खोजना आसान नहीं था। का पहला इसी कोड में परिवर्तन पर एक नज़र लेते हैं:

# ... 
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 
     # ... 

आप देख सकते हैं बजाय बार-बार git reset --soft 'HEAD~1' करने का, अब मैं स्पष्ट रूप से git-clang-format हिदायत (--commit विकल्प के साथ HEAD~1 खिलाफ काम करने की है, जबकि उसके डिफ़ॉल्ट HEAD कि था है मेरे प्रश्न में प्रस्तुत प्रारंभिक संस्करण में निहित)। हालांकि, यह अभी भी समस्या को हल नहीं करता है क्योंकि जब हम रूट को हिट करेंगे, तो फिर से यह त्रुटि होगी क्योंकि HEAD~1 अब एक वैध संशोधन का संदर्भ नहीं देगा (इसी प्रकार git reset --soft 'HEAD~1' करना संभव नहीं होगा) । यही कारण है कि इस विशेष मामले के लिए, मैं git-clang-format को (जादू) 4b825dc642cb6eb9a060e54bf8d69288fbee4904 हैश [3, 4, 5, 6] के विरुद्ध संचालित करने के लिए निर्देश देता हूं। इस हैश के बारे में अधिक जानने के लिए, संदर्भों से परामर्श लें, लेकिन संक्षेप में, यह गिट खाली पेड़ ऑब्जेक्ट - जिसे किसी भी चरणबद्ध या प्रतिबद्ध नहीं है, को संदर्भित करता है, जो कि हमारे मामले में संचालित करने के लिए हमें git-clang-format की आवश्यकता है।

नोट:
आप 4b825dc642cb6eb9a060e54bf8d69288fbee4904 दिल से याद करने की जरूरत नहीं है और यह मुश्किल कोड यह (सिर्फ मामले में यह जादू हैश कभी भविष्य में बदल देता है) के लिए नहीं बेहतर है। यह पता चला है कि इसे हमेशा git hash-object -t tree '/dev/null' [5, 6] से पुनर्प्राप्त किया जा सकता है। इस प्रकार, उपरोक्त pre-receive हुक के मेरे अंतिम संस्करण में, मेरे पास commit="$(git hash-object -t tree '/dev/null')" है।

पीएस मैं अभी भी अपने पहले प्रश्न पर एक अच्छी गुणवत्ता का जवाब ढूंढ रहा हूं। वैसे, मैंने इन प्रश्नों को आधिकारिक गिट मेलिंग सूची पर पूछा और अब तक कोई जवाब नहीं मिला, क्या शर्म की बात है ...

संबंधित मुद्दे