Git pre-push hooks


115

ฉันต้องการเรียกใช้การทดสอบหน่วยก่อนการพุชคอมไพล์ทุกครั้งและหากการทดสอบล้มเหลวให้ยกเลิกการพุช แต่ฉันไม่พบตะขอพรีพุชมีเฉพาะ pre-commit และ pre-rebase เท่านั้น


ที่เกี่ยวข้อง: stackoverflow.com/questions/31681746
tkruse

คำตอบ:


14

ฉันอยากจะทำการทดสอบแบบ pre-commit-hook เนื่องจากมีการบันทึกการเปลี่ยนแปลงไว้แล้วเมื่อกระทำ ผลักและดึงเฉพาะแลกเปลี่ยนข้อมูลเกี่ยวกับการเปลี่ยนแปลงที่บันทึกไว้แล้ว หากการทดสอบล้มเหลวคุณจะมีการแก้ไข "เสีย" ในที่เก็บของคุณอยู่แล้ว ไม่ว่าคุณจะผลักดันหรือไม่ก็ตาม


203
ฉันเห็นด้วยโดยทั่วไปแม้ว่าคุณจะมีนิสัยชอบทำสควอชเพิ่มขึ้นเป็นจำนวนมากในภายหลังและชุดทดสอบมีขนาดใหญ่ แต่ก็อาจทำไม่ได้
Cascabel

ฉันเห็น. ดังนั้นฉันขอแนะนำให้ทำการทดสอบก่อนที่จะรวมกับสาขาหลัก แต่ไม่มีตะขอก่อนการรวม อย่างไรก็ตามมี hook "update" ที่สามารถใช้เพื่อป้องกันการอัพเดต ref ในที่เก็บระยะไกล: "ก่อนที่จะอัพเดต ref บนที่เก็บระยะไกลจะมีการเรียก update hook สถานะการออกจะเป็นตัวกำหนดความสำเร็จหรือความล้มเหลวของการอ้างอิง ปรับปรุง hook ดำเนินการหนึ่งครั้งสำหรับแต่ละ ref ที่จะอัปเดตและรับพารามิเตอร์สามตัว: ชื่อของการอ้างอิงที่กำลังอัพเดตชื่ออ็อบเจ็กต์เก่าที่จัดเก็บใน ref และชื่ออ็อบเจ็กต์ใหม่ที่จะเก็บไว้ใน ref "
ordnungswidrig

18
โหวตลงเพราะ - ในขณะที่ให้ข้อมูล - มันไม่สนใจคำถามของ OP โดยสิ้นเชิง
The Dembinski

1
@TheDembinski ฉันจะไม่พูดว่ามันเพิกเฉยต่อคำถาม OP ในความเป็นจริงจะต้องพิจารณาและบอกว่ามีวิธีที่ดีกว่าวิธีที่ OP คิดไว้ โดยทั่วไปแล้วคำตอบที่ฉันต้องการจะได้รับ
calder.ty

9
@ calder.ty - น๊ะ. manojlds จัดการสิ่งที่สำคัญได้ดีกว่า ในความเป็นจริงแล้ว hooks ที่เรียกใช้การทดสอบโดยทั่วไปแล้วเป็นความคิดที่ไม่ดี ถือว่าทุกสิ่งที่มุ่งมั่นต้องผ่านการทดสอบ ซึ่งไม่ดีสำหรับขั้นตอนการทำงานทั่วไปที่เน้นการทำงานร่วมกัน เออ ... ฉันไม่เห็นด้วย; ไม่ใช่วิธีที่ดีกว่าในการทำ "มัน" และไม่ตอบคำถาม
The Dembinski

209

Git มี pre-pushเบ็ดในการ1.8.2เปิดตัว

ตัวอย่างpre-pushสคริปต์: https://github.com/git/git/blob/87c86dd14abe8db7d00b0df5661ef8cf147a72a3/templates/hooks--pre-push.sample

บันทึกประจำรุ่น 1.8.2 พูดถึง pre-push hook ใหม่: https://github.com/git/git/blob/master/Documentation/RelNotes/1.8.2.txt


1
@manojlds รู้ไหมว่าตะขอนี้ออกแบบมาเพื่อใช้ทำอะไร? ฉันต้องการใช้เพื่อพุชไบนารีของฉันไปยังลูกค้าของฉันเมื่อกดไปยังสาขาใดสาขาหนึ่ง (เช่นสร้างเวอร์ชันสำหรับคืนและอัปโหลดด้วย curl ก่อนที่จะพุช) ปัญหาคือต้องใช้เวลาสักพักในการสร้างและอัปโหลดและจากระยะไกลจะปิดการเชื่อมต่อ ดังนั้นฉันจึงลงเอยด้วยไบนารีของฉันที่สร้างและอัปโหลดให้กับลูกค้า แต่ไม่ถูกผลักไปที่ repo เนื่องจาก repo ระยะไกลปิดการเชื่อมต่อ มีความคิดอย่างไรในการแก้ไขปัญหานี้? หรืออาจเป็นความคิดที่ไม่ดีในรากของมัน
igrek

@igrek คุณพบวิธีแก้ปัญหาการปิดการเชื่อมต่อหรือไม่?
Mario Estrada

1
@MarioEstrada ใช่ฉันจำไม่ได้ว่าเป็นอย่างไร แต่ฉันทำให้มันดันสองครั้ง: คำสั่ง git แรกเรียกใช้การทดสอบหน่วยจากนั้นถ้ามันไม่ตัดการเชื่อมต่อมันจะดันและเริ่มการพุชอีกครั้งในเธรดอื่นหากครั้งแรกดันครั้งแรก ออกอันที่สองจากเธรดอื่นใช้ได้กับฉัน ถ้าอย่างใดอย่างหนึ่งและครั้งที่สองประสบความสำเร็จครั้งแรกจะผลักดันการเปลี่ยนแปลงและครั้งที่สองไม่ผลักดันอะไรเลย เคล็ดลับคือฉันได้เพิ่มอาร์กิวเมนต์ซึ่งข้ามการทดสอบหน่วย (ซึ่งใช้สำหรับการกดคอมไพล์ครั้งที่สองดังนั้นจึงไม่เริ่มการทดสอบหน่วยอีกครั้ง)
igrek

24

Git ได้รับ pre-push hook ในรุ่น 1.8.2

ตะขอกดล่วงหน้าคือสิ่งที่ฉันต้องการพร้อมกับตะขอเกี่ยวล่วงหน้า นอกเหนือจากการปกป้องสาขาแล้วยังสามารถให้การรักษาความปลอดภัยเพิ่มเติมร่วมกับตะขอแบบพรีคอมมิต

และสำหรับตัวอย่างวิธีการใช้งาน (นำมาใช้และปรับปรุงจากรายการที่ดีนี้ )

ตัวอย่างง่ายๆในการล็อกอินเข้าสู่คนเร่ร่อนเรียกใช้การทดสอบแล้วกด

#!/bin/bash
# Run the following command in the root of your project to install this pre-push hook:
# cp git-hooks/pre-push .git/hooks/pre-push; chmod 700 .git/hooks/pre-push

CMD="ssh vagrant@192.168.33.10 -i ~/.vagrant.d/insecure_private_key 'cd /vagrant/tests; /vagrant/vendor/bin/phpunit'"
protected_branch='master'

# Check if we actually have commits to push
commits=`git log @{u}..`
if [ -z "$commits" ]; then
    exit 0
fi

current_branch=$(git symbolic-ref HEAD | sed -e 's,.*/\(.*\),\1,')

if [[ $current_branch = $protected_branch ]]; then
    eval $CMD
    RESULT=$?
    if [ $RESULT -ne 0 ]; then
        echo "failed $CMD"
        exit 1
    fi
fi
exit 0

ดังที่คุณเห็นตัวอย่างใช้สาขาที่ได้รับการป้องกันซึ่งเป็นเรื่องของพรีพุชเบ็ด


14

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

แก้ไข

จาก git 1.8.2 คำตอบนี้ล้าสมัย ดูคำตอบของ manojlds ด้านบน


หมายความว่าไม่ใช้ตะขอเลยเหรอ? เพียงแค่แทนที่ "git pull" ด้วยเช่น "git uinttestspull"? นั่นไม่ใช่สิ่งที่ฉันต้องการ
sheepwalker

1
@sheepwalker: s / pull / push / และใช้นามแฝงเพื่อทำให้ดีและสั้น
Cascabel

@sheepwalker ใช่นั่นไม่ใช่สิ่งที่คุณขอ แต่เหมือนที่ @calmh กล่าวว่าไม่มีตะขอก่อนกด
kubi

8

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

คุณสามารถทำการตรวจสอบในฝั่งรับได้ในpost-receiveตะขอ นั่นคือจุดที่คุณมักจะปฏิเสธการผลักดันที่เข้ามา การเรียกใช้การทดสอบหน่วยอาจต้องทำแบบเบ็ดเสร็จเล็กน้อย แต่ก็ขึ้นอยู่กับคุณ


6

สำหรับบันทึกที่มีแพทช์เพื่อ Git 1.6 ที่เพิ่มเบ็ดก่อนผลักดัน ฉันไม่รู้ว่ามันใช้ได้กับ 1.7 ไหม

แทนที่จะยุ่งกับสิ่งนั้นคุณสามารถเรียกใช้ push script เช่น @kubi แนะนำ คุณยังสามารถทำให้เป็นงาน Rake แทนดังนั้นจึงอยู่ใน repo ของคุณ Ruby-gitสามารถช่วยในเรื่องนี้ได้ หากคุณตรวจสอบ repo เป้าหมายคุณจะเรียกใช้การทดสอบได้ก็ต่อเมื่อกดไปที่ repo การผลิตเท่านั้น

สุดท้ายคุณสามารถเรียกใช้การทดสอบของคุณในpre-commitเบ็ดของคุณแต่ตรวจสอบว่าสาขาใดที่มุ่งมั่น จากนั้นคุณอาจมีproductionสาขาที่ต้องผ่านการทดสอบทั้งหมดก่อนที่จะยอมรับข้อตกลง แต่คุณmasterไม่สนใจ limerick_rakeอาจมีประโยชน์ในสถานการณ์นั้น


ขอบคุณจริงๆฉันได้เลือกตัวแปรสุดท้ายแล้ว (ในที่สุดคุณสามารถเรียกใช้การทดสอบของคุณในเบ็ดก่อนคอมมิต .. )
sheepwalker

1

สคริปต์เชื่อมโยงโดยสูงได้รับการโหวตคำตอบที่แสดงให้เห็นว่าพารามิเตอร์ ฯลฯ กับpre-pushตะขอ ( $1เป็นชื่อที่ห่างไกล$2URL) และวิธีการเข้าถึงกระทำ (เส้นreadจาก stdin มีโครงสร้าง<local ref> <local sha1> <remote ref> <remote sha1>)

#!/bin/sh

# An example hook script to verify what is about to be pushed.  Called by "git
# push" after it has checked the remote status, but before anything has been
# pushed.  If this script exits with a non-zero status nothing will be pushed.
#
# This hook is called with the following parameters:
#
# $1 -- Name of the remote to which the push is being done
# $2 -- URL to which the push is being done
#
# If pushing without using a named remote those arguments will be equal.
#
# Information about the commits which are being pushed is supplied as lines to
# the standard input in the form:
#
#   <local ref> <local sha1> <remote ref> <remote sha1>
#
# This sample shows how to prevent push of commits where the log message starts
# with "WIP" (work in progress).

remote="$1"
url="$2"

z40=0000000000000000000000000000000000000000

while read local_ref local_sha remote_ref remote_sha
do
    if [ "$local_sha" = $z40 ]
    then
        # Handle delete
        :
    else
        if [ "$remote_sha" = $z40 ]
        then
            # New branch, examine all commits
            range="$local_sha"
        else
            # Update to existing branch, examine new commits
            range="$remote_sha..$local_sha"
        fi

        # Check for WIP commit
        commit=`git rev-list -n 1 --grep '^WIP' "$range"`
        if [ -n "$commit" ]
        then
            echo >&2 "Found WIP commit in $local_ref, not pushing"
            exit 1
        fi
    fi
done

exit 0
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.