ตรวจสอบว่าต้องการแรงดึงใน Git หรือไม่


622

ฉันจะตรวจสอบว่าที่เก็บระยะไกลมีการเปลี่ยนแปลงและฉันต้องดึงได้อย่างไร

ตอนนี้ฉันใช้สคริปต์ง่ายๆนี้:

git pull --dry-run | grep -q -v 'Already up-to-date.' && changed=1

แต่มันค่อนข้างหนัก

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


14
โปรดทราบ: "git pull --dry-run" ไม่ทำงานอย่างที่คาดไว้ ดูเหมือนว่าการดึง git นั้นผ่านตัวเลือกที่ไม่รู้จักโดยตรงไปยังการเรียก git ผลที่ได้คือการดึง git ปกติ

27
"pull" เป็นเพียงวิธีสั้น ๆ ในการ "ดึงข้อมูล" และ "ผสาน" ในครั้งเดียวหากคุณต้องการตรวจสอบสถานะ repo ระยะไกลคุณกำลังจำลอง "ดึงข้อมูล" จริง ๆ ดังนั้นgit fetch -v --dry-runสิ่งที่คุณต้องการ
Claudio Floreani

คำตอบ:


858

ใช้งานครั้งแรกgit remote updateเพื่อนำการอ้างอิงระยะไกลของคุณให้ทันสมัย จากนั้นคุณสามารถทำสิ่งหนึ่งในหลาย ๆ อย่างเช่น:

  1. git status -unoจะบอกคุณว่าสาขาที่คุณกำลังติดตามอยู่ข้างหน้าข้างหลังหรือแยกจากกัน ถ้ามันไม่พูดอะไรเลยโลคอลและรีโมตก็เหมือนกัน

  2. git show-branch *masterจะแสดงการกระทำในสาขาทั้งหมดที่มีชื่อลงท้ายด้วย 'master' (เช่นmasterและorigin / master )

หากคุณใช้-vกับgit remote update( git remote -v update) คุณจะเห็นว่าสาขาใดได้รับการอัปเดตดังนั้นคุณไม่จำเป็นต้องมีคำสั่งเพิ่มเติมอีก

อย่างไรก็ตามดูเหมือนว่าคุณต้องการทำสิ่งนี้ในสคริปต์หรือโปรแกรมและจบลงด้วยค่าจริง / เท็จ ถ้าเป็นเช่นนั้นมีหลายวิธีในการตรวจสอบความสัมพันธ์ระหว่างHEADปัจจุบันที่คุณมอบหมายกับหัวหน้าสาขาที่คุณกำลังติดตามแม้ว่าจะมีผลลัพธ์ที่เป็นไปได้สี่ประการคุณจึงไม่สามารถลดความมันลงไปเป็นคำตอบใช่ / ไม่ใช่ อย่างไรก็ตามหากคุณพร้อมที่จะทำpull --rebaseคุณสามารถรักษา "local is behind" และ "local is diverged" เป็น "need to pull" และอีกสองคนเป็น "ไม่จำเป็นต้องดึง"

คุณสามารถรับรหัสการกระทำของการอ้างอิงใด ๆ ที่ใช้git rev-parse <ref>ดังนั้นคุณสามารถทำเช่นนี้กับต้นแบบและที่มา / ต้นแบบและเปรียบเทียบได้ ถ้าพวกมันเท่ากันกิ่งก็เหมือนกัน หากพวกเขาไม่เท่ากันคุณต้องการรู้ว่าใครอยู่ข้างหน้า การใช้git merge-base master origin/masterจะบอกบรรพบุรุษของทั้งสองสาขาและหากพวกเขาไม่ได้แยกสิ่งนี้จะเป็นสิ่งเดียวกับที่อื่น หากคุณได้รับรหัสที่แตกต่างกันสามรหัสสาขาจะแตกต่างกันไป

ในการดำเนินการอย่างถูกต้องเช่นในสคริปต์คุณต้องสามารถอ้างถึงสาขาปัจจุบันและสาขาระยะไกลที่ติดตามอยู่ ฟังก์ชันการตั้งค่าพรอมต์ bash /etc/bash_completion.dมีรหัสที่เป็นประโยชน์บางอย่างสำหรับรับชื่อสาขา อย่างไรก็ตามคุณอาจไม่จำเป็นต้องได้รับชื่อจริง Git มีการจดชวเลขอย่างเป็นระเบียบเพื่ออ้างถึงกิ่งก้านและความมุ่งมั่น (ดังที่บันทึกไว้ในgit rev-parse --help) โดยเฉพาะอย่างยิ่งคุณสามารถใช้@สำหรับสาขาปัจจุบัน (สมมติว่าคุณไม่ได้อยู่ในสถานะแยกหัว) และ@{u}สำหรับสาขาต้นน้ำ (เช่นorigin/master) ดังนั้นgit merge-base @ @{u}จะส่งคืน (แฮชของ) กระทำที่สาขาปัจจุบันและความแตกต่างของต้นน้ำgit rev-parse @และgit rev-parse @{u}จะให้แฮชของทั้งสองเคล็ดลับ สามารถสรุปได้ในสคริปต์ต่อไปนี้:

#!/bin/sh

UPSTREAM=${1:-'@{u}'}
LOCAL=$(git rev-parse @)
REMOTE=$(git rev-parse "$UPSTREAM")
BASE=$(git merge-base @ "$UPSTREAM")

if [ $LOCAL = $REMOTE ]; then
    echo "Up-to-date"
elif [ $LOCAL = $BASE ]; then
    echo "Need to pull"
elif [ $REMOTE = $BASE ]; then
    echo "Need to push"
else
    echo "Diverged"
fi

หมายเหตุ:คอมไพล์รุ่นเก่ากว่าไม่อนุญาต@ด้วยตัวเองดังนั้นคุณอาจต้องใช้@{0}แทน

บรรทัดUPSTREAM=${1:-'@{u}'}ช่วยให้คุณเลือกที่จะส่งผ่านสาขาต้นน้ำอย่างชัดเจนในกรณีที่คุณต้องการตรวจสอบกับสาขาระยะไกลที่แตกต่างจากสาขาระยะไกลที่กำหนดไว้สำหรับสาขาปัจจุบัน นี้มักจะเป็นในรูปแบบremotename / BRANCHNAME หากไม่ได้ระบุพารามิเตอร์ไว้ค่าดีฟอลต์จะ@{u}เป็น

สคริปต์จะถือว่าคุณได้ทำgit fetchหรือgit remote updateก่อนเพื่อทำให้สาขาการติดตามเป็นปัจจุบัน ฉันไม่ได้สร้างสิ่งนี้ลงในสคริปต์เพราะมีความยืดหยุ่นมากกว่าที่จะสามารถทำการดึงข้อมูลและการเปรียบเทียบเป็นการดำเนินการแยกตัวอย่างเช่นถ้าคุณต้องการเปรียบเทียบโดยไม่ดึงข้อมูลเพราะคุณดึงข้อมูลมาแล้วเมื่อเร็ว ๆ นี้


4
@ ทาเคชินฉันเดาว่าคุณสามารถรวมคอมไพล์ ls-remote ต้นทาง -h refs / heads / master ตามที่แนะนำโดย @brool กับ git rev-list --max-count = 1 origin / master หากพวกเขากลับมาแฮชเดียวกันสาขาระยะไกลจะไม่เปลี่ยนแปลงเนื่องจากคุณอัปเดตการอ้างอิงระยะไกลของคุณครั้งล่าสุด (ด้วยการดึงดึงการอัปเดตระยะไกล ฯลฯ ) สิ่งนี้จะมีประโยชน์ที่คุณจะไม่ต้องดึงเนื้อหาของ ความมุ่งมั่นทั้งหมดทันที แต่อาจปล่อยให้มันเป็นเวลาที่สะดวกมากขึ้น อย่างไรก็ตามเนื่องจากการอัปเดตระยะไกลนั้นไม่เป็นอันตรายคุณอาจทำได้เช่นกัน
Neil Mayhew

2
นอกจากนี้คุณยังสามารถลองซึ่งจะช่วยให้การส่งออกที่สั้นกว่าgit status -s -u no git status -u no
Phillip Cloud

2
git remote -v update@mhulse, ดูผลลัพธ์ของgit remote --helpคำอธิบายที่สมบูรณ์กว่า
Neil Mayhew

1
@ChrisMaes เป็นจุดที่ดี จำเป็นต้องใช้ไวยากรณ์ที่ชัดเจนยิ่งขึ้นกับ git เวอร์ชันเก่ากว่า ฉันทดลองกับระบบต่าง ๆ ที่ฉันมีและพบว่าใช้@{u}งานได้กับ git 1.8.3.2 แต่@ไม่ได้ แต่ทำงานร่วมกับ@ 1.8.5.4คุณธรรมของเรื่องราว: คอมไพล์ยังคงปรับปรุงและมันก็คุ้มค่าที่จะมีรุ่นล่าสุดที่คุณสามารถ
Neil Mayhew

1
ต้องระบุตัวระบุสำหรับ @ ในขณะนี้ คุณสามารถใช้ @ {0} แทน @
Ben Davis

132

หากคุณมีสาขาต้นน้ำ

git fetch <remote>
git status

หากคุณไม่มีสาขาต้นน้ำ

เปรียบเทียบสองสาขา:

git fetch <remote>
git log <local_branch_name>..<remote_branch_name> --oneline

ตัวอย่างเช่น:

git fetch origin

# See if there are any incoming changes
git log HEAD..origin/master --oneline

(ฉันสมมติว่าorigin/masterเป็นสาขาการติดตามระยะไกลของคุณ)

หากคอมมิชชันใด ๆ มีการระบุไว้ในผลลัพธ์ด้านบนแสดงว่าคุณมีการเปลี่ยนแปลงขาเข้า - คุณต้องรวม หากไม่มีการคอมมิชชันถูกระบุโดยgit logก็ไม่มีอะไรที่จะรวม

โปรดทราบว่าสิ่งนี้จะใช้งานได้แม้ว่าคุณจะอยู่ในสาขาฟีเจอร์ - ซึ่งไม่มีการติดตามระยะไกลเนื่องจากหากอ้างอย่างชัดเจนorigin/masterแทนที่จะใช้ปริยายโดยใช้สาขาอัปสตรีมที่ Git จำได้


2
แม้แต่สัญกรณ์สั้นgit fetch; git log HEAD.. --onelineสามารถใช้ถ้ามีสาขาระยะไกลเริ่มต้นสำหรับหนึ่งในท้องถิ่น
phil pirozhkov

@philpirozhkov หากคุณมีสาขาระยะไกลที่เป็นค่าเริ่มต้นคุณควรคิดว่า "สถานะคอมไพล์" อย่างง่าย คำตอบของฉันเป็นสาขาทั่วไปสำหรับสองสาขาใดสาขาหนึ่งซึ่งอาจจะมีหรือไม่มีก็ได้
PlagueHammer

55
git rev-list HEAD...origin/master --countจะให้จำนวนการกระทำที่ "แตกต่าง" ระหว่างคุณทั้งสอง
Jake Berger

1
สั้นและเรียบง่าย วิธีแก้ปัญหาที่ฉันโปรดปรานที่เพิ่งแสดงคอมมิทใหม่ (ยกนิ้วขึ้นสองครั้ง)
spankmaster79

ฉันจะใช้สิ่งนี้ในไฟล์แบตช์ (Ubuntu) ได้อย่างไรเพื่อที่ฉันจะสามารถเรียกใช้คำสั่งอื่น ๆ ได้ในกรณีที่คำสั่งนี้แสดงให้เห็นว่าจำเป็นต้องมีการดึง
Ulysses Alves

69

หากนี่เป็นสคริปต์คุณสามารถใช้:

git fetch
$(git rev-parse HEAD) == $(git rev-parse @{u})

(หมายเหตุ: ประโยชน์ของคำตอบนี้เทียบกับคำตอบก่อนหน้าคือคุณไม่จำเป็นต้องใช้คำสั่งแยกต่างหากเพื่อรับชื่อสาขาปัจจุบัน "HEAD" และ "@ {u}" (ต้นน้ำสาขาปัจจุบัน) ดูแลดู "git rev-parse --help" สำหรับรายละเอียดเพิ่มเติม)


ฉันค้นพบ @ {u} เป็นอิสระและได้อัปเดตคำตอบก่อนที่จะเห็นคุณ
Neil Mayhew

1
จะgit rev-parse @{u}แสดงการกระทำล่าสุดโดยgit fetchไม่
Kyle Strand

3
นี่คือตั๋ว! แม้ว่าตรรกะของคุณกำลังใช้==ซึ่งหมายถึง "ถ้าไม่มีการเปลี่ยนแปลงจากต้นน้ำ" ฉันเคย!=ตรวจสอบ "ถ้ามีการเปลี่ยนแปลงจากอัปสตรีม" สำหรับแอปพลิเคชันของฉัน อย่าลืมgit fetchก่อน!
ChrisPrime

1
ฉันเพิ่มการเรียก git เพราะจำเป็นจริงๆที่จะตอบคำถามเดิม @สั้นสำหรับHEADbtw
user1338062

ผู้ใช้ Windows จะต้องมีเครื่องหมายคำพูดเดี่ยว ๆ รอบตัว@{u}เช่นgit rev-parse '@{u}'
spuder

36

คำสั่ง

git ls-remote origin -h refs/heads/master

จะแสดงรายการหัวปัจจุบันบนรีโมท - คุณสามารถเปรียบเทียบกับค่าก่อนหน้าหรือดูว่าคุณมี SHA ใน repo ท้องถิ่นของคุณหรือไม่


1
มีสคริปต์ตัวอย่างใดบ้างเพื่อเปรียบเทียบค่าเหล่านี้
takeshin

18
git rev-list HEAD...origin/master --countจะให้จำนวนการกระทำที่ "แตกต่าง" ระหว่างคุณทั้งสอง
Jake Berger

3
@ jberger เพื่อชี้แจงว่าจะแสดงจำนวนการคอมมิชชันที่คุณอยู่ข้างหลัง (ไม่ใช่ข้างหน้าและข้างหลัง) และจะใช้งานได้ก็ต่อเมื่อคุณgit fetchหรือgit remote updateคนแรก git statusยังแสดงการนับ btw
เดนนิส

1
@ เดนนิสฉันคิดว่า.."ทำคอมมิชชันในต้นกำเนิด / หลักหักหัว" (เช่นจำนวนคอมมิชชันที่อยู่ด้านหลัง) ในขณะที่...ความแตกต่างสมมาตร (เช่นข้างหน้าและข้างหลัง)
Jake Berger

3
ยอดเยี่ยม เท่าที่ผมสามารถบอกได้ว่านี้เป็นเพียงการแก้ปัญหาที่จริงการตรวจสอบแหล่งที่มาสำหรับการปรับปรุง fetchแต่ไม่ได้ทำโดยปริยาย
Kyle Strand

35

นี่คือ Bash one-liner ที่เปรียบเทียบ HEAD ของสาขาปัจจุบันที่กระทำการแฮชกับสาขาต้นน้ำระยะไกลโดยไม่ต้องใช้งานหนักgit fetchหรือgit pull --dry-runต้องดำเนินการ:

[ $(git rev-parse HEAD) = $(git ls-remote $(git rev-parse --abbrev-ref @{u} | \
sed 's/\// /g') | cut -f1) ] && echo up to date || echo not up to date

นี่คือวิธีการที่เส้นแบ่งค่อนข้างหนาแน่นนี้:

  • คำสั่งถูกจัดกลุ่มและซ้อนกันโดยใช้ไวยากรณ์แทนคำสั่ง$(x) Bash
  • git rev-parse --abbrev-ref @{u}ส่งกลับย่อเตะต้นน้ำ (เช่นorigin/master) ซึ่งจะถูกแปลงแล้วลงในเขตพื้นที่แยกจากกันโดยประปาคำสั่งเช่นsedorigin master
  • สายนี้จะถูกป้อนเข้าgit ls-remoteซึ่งจะส่งคืนการกระทำส่วนหัวของสาขาระยะไกล คำสั่งนี้จะสื่อสารกับที่เก็บระยะไกล cutคำสั่งpiped แยกเฉพาะเขตข้อมูลแรก (การกระทำแฮช) โดยลบสตริงอ้างอิงที่คั่นด้วยแท็บ
  • git rev-parse HEAD ส่งคืนแฮชการคอมมิต
  • ไวยากรณ์ทุบตี[ a = b ] && x || yเสร็จสมบูรณ์หนึ่งซับ: นี่คือทุบตีสตริงเปรียบเทียบ =ภายในสร้างการทดสอบตามด้วยและรายการและหรือสร้างรายการ[ test ]&& true || false

2
ฉันจะไม่ใช้ / g บน sed ถ้าคุณใช้เครื่องหมายทับในชื่อสาขา นั่นคือ "sed 's / \ // /" เท่านั้น
Martyn Davis

@wjordan โซลูชันของคุณล้มเหลวเมื่อที่เก็บข้อมูลระยะไกลไม่สามารถเข้าถึงได้ (หรืออยู่ระหว่างการบำรุงรักษา) และจะทริกเกอร์ "ทันสมัย"
เฟรม

20

ผมแนะนำให้คุณไปดูสคริปต์https://github.com/badele/gitcheck ฉันได้เขียนสคริปต์นี้เพื่อตรวจสอบหนึ่งผ่านที่เก็บ Git ทั้งหมดของคุณและมันแสดงให้เห็นว่าใครยังไม่ได้ทำและใครที่ไม่ได้ผลัก / ดึง

นี่คือตัวอย่างผลลัพธ์:

ป้อนคำอธิบายภาพที่นี่


6
เรียบร้อยคิดเกี่ยวกับการเขียนใหม่ในเปลือกบริสุทธิ์
Olivier Refalo

1
ตอนนี้คุณสามารถใช้ gitcheck ได้โดยตรงจาก container docker (พร้อมไฟล์ของคุณในโฮสต์ของคุณ) สำหรับข้อมูลเพิ่มเติมดูโครงการ gitcheck github
Bruno Adelé

เครื่องมือที่คล้ายกันในทุบตีGit-หลาย repo-เครื่องมือ git mrepo -cสิ่งนี้จะแสดงการกระทำที่ค้างอยู่ทั้งหมด
เกร็ก

11

ฉันใช้วิธีนี้กับความคิดเห็นของ @jberger

if git checkout master &&
    git fetch origin master &&
    [ `git rev-list HEAD...origin/master --count` != 0 ] &&
    git merge origin/master
then
    echo 'Updated!'
else
    echo 'Not updated.'
fi

หมายถึงความคิดเห็นก่อนหน้าของคุณณ เวลานี้ฉันไม่สามารถให้คำตอบที่ชัดเจน ในขณะที่ฉันแสดงความคิดเห็นเหล่านั้นฉันได้ดำดิ่งสู่ส่วนลึกของคอมไพล์โดยเฉพาะรีโมทและดิฟ ไม่กี่เดือนหลังจากนั้นและความรู้มากมายถูกฝังอยู่ในสมองของฉัน ;) หากคุณกำลังมองหาจำนวนการ 'กระทำ' ที่แตกต่างกันระหว่างทั้งสอง...ดูเหมือนว่าเป็นส่วนที่ถูกต้องของโซลูชันของคุณ
Jake Berger

1
ขอบคุณ นี่สะอาด
Shobhit Puri

10

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

# Check return value to see if there are incoming updates.
if ! git diff --quiet remotes/origin/HEAD; then
 # pull or whatever you want to do
fi

2
คำตอบเดิมขาด '!' ในถ้า ค่าส่งคืนจาก git diff คือศูนย์เมื่อไม่มีการเปลี่ยนแปลง
thuovila

IMO ทางออกที่ดีที่สุดออกไปที่นั่นฉันต้องแทนที่ "รีโมท / แหล่งกำเนิด / หัว" ด้วย "แหล่งกำเนิด / ต้นแบบ" หรือการแก้ไขอื่น ๆ
Matthias Michael Engh

9

ฉันคิดว่าวิธีที่ดีที่สุดในการทำเช่นนี้คือ:

git diff remotes/origin/HEAD

สมมติว่าคุณมีผู้ลงทะเบียนผู้นี้ คุณควรถ้าคุณได้โคลนที่เก็บมิฉะนั้น (เช่นถ้า repo ถูกสร้างขึ้นใน novo ในประเทศและผลักไปที่ระยะไกล) คุณจะต้องเพิ่ม refspec อย่างชัดเจน


9

สคริปต์ด้านล่างทำงานได้อย่างสมบูรณ์

changed=0
git remote update && git status -uno | grep -q 'Your branch is behind' && changed=1
if [ $changed = 1 ]; then
    git pull
    echo "Updated successfully";
else
    echo "Up-to-date"
fi

6

ฉันจะทำตามวิธีที่แนะนำโดย brool สคริปต์หนึ่งบรรทัดต่อไปนี้จะใช้ SHA1 ของเวอร์ชันที่ได้รับการยอมรับล่าสุดของคุณและเปรียบเทียบกับหนึ่งในแหล่งกำเนิดระยะไกลและดึงการเปลี่ยนแปลงเฉพาะในกรณีที่แตกต่างกัน และมันก็ยิ่งมีน้ำหนักเบาขึ้นของโซลูชันที่ใช้git pullหรือgit fetchหรือ

[ `git log --pretty=%H ...refs/heads/master^` != `git ls-remote origin
-h refs/heads/master |cut -f1` ] && git pull

คำสั่งนี้ล้มเหลวหากที่เก็บ git ถูกโคลนด้วย "--depth 1" (เพื่อ จำกัด ขนาดการดาวน์โหลด) คุณรู้ไหมว่าหากมีวิธีการแก้ไขหรือไม่
Adam Ryczkowski

บันทึกคอมไพล์นี้ส่งคืนหลายบรรทัดและให้ข้อผิดพลาด "ทุบตี: [: มีการโต้แย้งมากเกินไป" ฉันเปลี่ยนไปเป็นgit rev-parse --verify HEAD
Drew Pierce

1
นี่คือการเปรียบเทียบสตริงอย่างง่ายโดยการทุบตี หากสิ่งที่ล้มเหลวฉันขอแนะนำให้คุณตรวจสอบไวยากรณ์ของคุณ (เช่นคุณพิมพ์ผิด) ขั้นแรกgit log --pretty=%H ...refs/heads/master^ ให้เรียกใช้ SHA1 ของรุ่นที่คุณได้รับการยอมรับล่าสุดจากนั้นเรียกใช้ git ls-remote origin -h refs/heads/master |cut -f1 เพื่อรับ SHA1 ของแหล่งกำเนิดระยะไกล ทั้งสองนี้เป็นคำสั่ง git และไม่เกี่ยวข้องกับ bash git pullสิ่งที่ไม่ทุบตีภายในวงเล็บคือการเปรียบเทียบผลลัพธ์จากคำสั่งครั้งแรกกับคนที่สองและถ้าพวกเขามีค่าเท่ากันก็จะส่งกลับจริงและวิ่ง
Claudio Floreani

"และถ้ามันเท่ากันมันจะคืนค่าจริงและทำงานgit pull" ฉันรู้ว่าฉันเป็นคนพูดจาไร้สาระ แต่เพียงเพื่อช่วยให้คนสับสนสับสนนั่นควรจะเป็น "และถ้าพวกเขาไม่เท่ากัน" นอกจากนี้ไม่ว่าด้วยเหตุผลใดก็ตามคำสั่ง git แรกก็ใช้ไม่ได้สำหรับฉัน (ฉันอยู่ในคอมไพล์2.4.1) ดังนั้นฉันแค่ใช้git log --pretty=%H master | head -n1แทน แต่ฉันไม่แน่ใจว่ามันจะเหมือนกันหรือเปล่า
xd1le

6

หากคุณเรียกใช้สคริปต์นี้มันจะทดสอบว่าสาขาปัจจุบันต้องการgit pull:

#!/bin/bash

git fetch -v --dry-run 2>&1 |
    grep -qE "\[up\s+to\s+date\]\s+$(
        git branch 2>/dev/null |
           sed -n '/^\*/s/^\* //p' |
                sed -r 's:(\+|\*|\$):\\\1:g'
    )\s+" || {
        echo >&2 "Current branch need a 'git pull' before commit"
        exit 1
}

มันสะดวกมากที่จะใช้เป็น Git hook ล่วงหน้าเพื่อหลีกเลี่ยง

Merge branch 'foobar' of url:/path/to/git/foobar into foobar

เมื่อคุณก่อนcommitpulling

หากต้องการใช้รหัสนี้เป็นตะขอเพียงคัดลอก / วางสคริปต์

.git/hooks/pre-commit

และ

chmod +x .git/hooks/pre-commit

6

ฉันแค่ต้องการโพสต์นี้เป็นโพสต์จริงเพราะมันง่ายที่จะพลาดในความคิดเห็น

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

@stackoverflow ให้คนนี้เป็นระฆัง ขอบคุณ @ Jake Berger

git rev-list HEAD...origin/master --count will give you the total number of "different" commits between the two.  Jake Berger Feb 5 '13 at 19:23

4

เรียกใช้git fetch (remote)เพื่ออัปเดตการอ้างอิงระยะไกลของคุณมันจะแสดงให้คุณเห็นว่ามีอะไรใหม่ จากนั้นเมื่อคุณชำระเงินที่สาขาของคุณมันจะแสดงให้คุณเห็นว่ามันอยู่ด้านหลังต้นน้ำหรือไม่


ฉันคิดว่าเขามีสาขาในท้องถิ่นที่เช็คเอาท์แล้วดังนั้นเขาต้องการสิ่งอื่นเพื่อแสดงว่ามันอยู่ด้านหลัง ฯลฯ เขาสามารถทำสิ่งนี้ด้วยสถานะคอมไพล์
Neil Mayhew

จริงหลังจากที่คุณดึงรีโมทแล้วgit statusจะแสดงว่าเช่นกัน
che

1
นั่นเป็นสิ่งที่อยู่ในอารมณ์git pull --dry-runแต่ฉันคิดว่ามันเป็นเรื่องที่หนักสำหรับสคริปต์ cron ที่ทำงานทุกนาที
takeshin

@takeshin: คุณไม่สามารถตรวจสอบที่เก็บข้อมูลระยะไกลโดยไม่ต้องไปที่เครือข่าย หากไม่มีอะไรใหม่fetchจะไม่ทำอะไรมากไปกว่าการตรวจสอบสถานะ หากคุณต้องการการตอบสนองที่รวดเร็วและมีน้ำหนักเบามากในการอัปเดตระยะไกลคุณอาจต้องการตรวจสอบการแจ้งเตือนบางอย่างกับที่เก็บระยะไกล
che

@ Takeshin: หากคุณต้องการตรวจสอบ repo ระยะไกลทุกนาทีฉันคิดว่าคุณพลาดจุด DVCS แล้ว ความคิดทั้งหมดคือการสามารถพัฒนาได้อย่างอิสระชั่วขณะหนึ่งจากนั้นนำมารวมกันอย่างราบรื่นในภายหลัง มันไม่เหมือน cvs, svn, p4 และอื่น ๆ ที่คุณจะต้องทำงานบนสิ่งที่เป็นล่าสุดในพื้นที่เก็บข้อมูล หากคุณต้องการบางสิ่งบางอย่างที่คนอื่นกำลังทำงานอยู่คุณควรใช้กลไกการสื่อสารที่แตกต่างกันเช่นอีเมลเพื่อบอกคุณเมื่อพร้อมที่จะดึง
Neil Mayhew

4

ทั้งหมดที่ซับซ้อนเช่นในขณะที่การแก้ปัญหาสั้นและง่าย:

#!/bin/bash

BRANCH="<your branch name>"
LAST_UPDATE=`git show --no-notes --format=format:"%H" $BRANCH | head -n 1`
LAST_COMMIT=`git show --no-notes --format=format:"%H" origin/$BRANCH | head -n 1`

git remote update
if [ $LAST_COMMIT != $LAST_UPDATE ]; then
        echo "Updating your branch $BRANCH"
        git pull --no-edit
else
        echo "No updates available"
fi

LAST_COMMIT และ LAST_UPDATE จะเท่ากันเสมอแม้ว่าจะมีการเปลี่ยนแปลง
canbax

วิธีนี้เป็นวิธีที่ดีและเรียบง่ายทำให้ต้องมีgit remote updateการเรียกใช้ก่อนรหัสของคุณเพื่อรับแหล่งกำเนิดล่าสุดข้อมูล
ak93

git remote updateไม่ควรผนวกก่อนgit showคำสั่ง?
Setop

2

นี่คือสคริปต์ Bash เวอร์ชันของฉันที่ตรวจสอบที่เก็บทั้งหมดในโฟลเดอร์ที่กำหนดไว้ล่วงหน้า:

https://gist.github.com/henryiii/5841984

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

วาง symlink (หรือสคริปต์) ลงในโฟลเดอร์ในพา ธ ของคุณจากนั้นทำงานเป็นgit all status(, ฯลฯ ) รองรับเฉพาะต้นฉบับ / ต้นแบบ แต่สามารถแก้ไขหรือรวมกับวิธีอื่นได้


1
git ls-remote | cut -f1 | git cat-file --batch-check >&-

จะแสดงรายการทุกอย่างที่อ้างอิงในรีโมตที่ไม่ได้อยู่ใน repo ของคุณ ในการตรวจจับการเปลี่ยนแปลงการอ้างอิงระยะไกลกับสิ่งที่คุณมีอยู่แล้ว (เช่นรีเซ็ตการกระทำก่อนหน้า) จะใช้เวลาเพิ่มขึ้นเล็กน้อย

git pack-refs --all
mine=`mktemp`
sed '/^#/d;/^^/{G;s/.\(.*\)\n.* \(.*\)/\1 \2^{}/;};h' .git/packed-refs | sort -k2 >$mine
for r in `git remote`; do 
    echo Checking $r ...
    git ls-remote $r | sort -k2 | diff -b - $mine | grep ^\<
done

1

อาจเป็นเช่นนี้หากคุณต้องการเพิ่มงานเป็น crontab:

#!/bin/bash
dir="/path/to/root"
lock=/tmp/update.lock
msglog="/var/log/update.log"

log()
{
        echo "$(date) ${1:-missing}" >> $msglog
}

if [ -f $lock ]; then
        log "Already run, exiting..."
else
        > $lock
        git -C ~/$dir remote update &> /dev/null
        checkgit=`git -C ~/$dir status`
        if [[ ! "$checkgit" =~ "Your branch is up-to-date" ]]; then
                log "-------------- Update ---------------"
                git -C ~/$dir pull &>> $msglog
                log "-------------------------------------"
        fi
        rm $lock

fi
exit 0

1

ใช้ regexp ง่าย ๆ :

str=$(git status) 
if [[ $str =~ .*Your\ branch\ is\ behind.*by.*commits,\ and\ can\ be\ fast-forwarded ]]; then
    echo `date "+%Y-%m-%d %H:%M:%S"` "Needs pull"
else
    echo "Code is up to date"
fi

สิ่งนี้จะไม่ทำงาน สถานะ git เป็นเพียงการตรวจสอบในท้องถิ่นและดังนั้นมันจะบอกคุณว่าสาขาของคุณอยู่ข้างหลังหรือไม่ถ้าคุณได้อัปเดต defs ระยะไกลแล้ว
minhaz1

0

ฉันใช้เวอร์ชันของสคริปต์ตามคำตอบของ Stephen Haberman:

if [ -n "$1" ]; then
    gitbin="git -C $1"
else
    gitbin="git"
fi

# Fetches from all the remotes, although --all can be replaced with origin
$gitbin fetch --all
if [ $($gitbin rev-parse HEAD) != $($gitbin rev-parse @{u}) ]; then
    $gitbin rebase @{u} --preserve-merges
fi

สมมติว่าสคริปต์นี้ถูกเรียกgit-fetch-and-rebaseมันสามารถถูกเรียกด้วยอาร์กิวเมนต์ที่เป็นทางเลือกdirectory nameของที่เก็บ Git ท้องถิ่นเพื่อดำเนินการ ถ้าสคริปต์ถูกเรียกโดยไม่มีอาร์กิวเมนต์มันจะถือว่าไดเรกทอรีปัจจุบันเป็นส่วนหนึ่งของที่เก็บ Git

ตัวอย่าง:

# Operates on /abc/def/my-git-repo-dir
git-fetch-and-rebase /abc/def/my-git-repo-dir

# Operates on the Git repository which the current working directory is part of
git-fetch-and-rebase

มันมีให้ที่นี่เช่นกัน


0

หลังจากอ่านคำตอบมากมายและโพสต์หลายครั้งและใช้เวลาครึ่งวันในการลองเปลี่ยนรูปแบบต่าง ๆ นี่คือสิ่งที่ฉันคิดขึ้นมา

หากคุณใช้ Windows คุณอาจเรียกใช้สคริปต์นี้ใน Windows โดยใช้ Git Bash ที่ Git สำหรับ Windows จัดทำขึ้น (ติดตั้งหรือพกพา)

สคริปต์นี้ต้องการอาร์กิวเมนต์

- เส้นทางท้องถิ่นเช่น / d / source / project1
- URL Git เช่น https: //username@bitbucket.org/username/project1.git
- รหัสผ่าน

หากไม่ควรป้อนรหัสผ่านในบรรทัดคำสั่งด้วยข้อความล้วน
จากนั้นแก้ไขสคริปต์เพื่อตรวจสอบว่า GITPASS ว่างเปล่าหรือไม่ อย่า
แทนที่และปล่อยให้ Git ถามรหัสผ่าน

สคริปต์จะ

- Find the current branch
- Get the SHA1 of the remote on that branch
- Get the SHA1 of the local on that branch
- Compare them.

หากมีการเปลี่ยนแปลงตามที่พิมพ์โดยสคริปต์คุณสามารถดึงหรือดึงต่อไปได้ สคริปต์อาจไม่มีประสิทธิภาพ แต่มันทำให้ฉันทำงานเสร็จ

Update - 2015-10-30: stderr ถึง dev null เพื่อป้องกันการพิมพ์ URL ด้วยรหัสผ่านไปยังคอนโซล

#!/bin/bash

# Shell script to check if a Git pull is required.

LOCALPATH=$1
GITURL=$2
GITPASS=$3

cd $LOCALPATH
BRANCH="$(git rev-parse --abbrev-ref HEAD)"

echo
echo git url = $GITURL
echo branch = $BRANCH

# Bash replace - replace @ with :password@ in the GIT URL
GITURL2="${GITURL/@/:$GITPASS@}"
FOO="$(git ls-remote $GITURL2 -h $BRANCH 2> /dev/null)"
if [ "$?" != "0" ]; then
  echo cannot get remote status
  exit 2
fi
FOO_ARRAY=($FOO)
BAR=${FOO_ARRAY[0]}
echo [$BAR]

LOCALBAR="$(git rev-parse HEAD)"
echo [$LOCALBAR]
echo

if [ "$BAR" == "$LOCALBAR" ]; then
  #read -t10 -n1 -r -p 'Press any key in the next ten seconds...' key
  echo No changes
  exit 0
else
  #read -t10 -n1 -r -p 'Press any key in the next ten seconds...' key
  #echo pressed $key
  echo There are changes between local and remote repositories.
  exit 1
fi

0

สำหรับผู้ใช้ windows ที่จบลงด้วยคำถามที่มองหาสิ่งนี้ฉันได้แก้ไขคำตอบบางส่วนเป็นสคริปต์ PowerShell ปรับแต่งตามความจำเป็นบันทึกเป็น.ps1ไฟล์และเรียกใช้ตามความต้องการหรือกำหนดเวลาหากคุณต้องการ

cd C:\<path to repo>
git remote update                           #update remote
$msg = git remote show origin               #capture status
$update = $msg -like '*local out of date*'
if($update.length -gt 0){                   #if local needs update
    Write-Host ('needs update')
    git pull
    git reset --hard origin/master
    Write-Host ('local updated')
} else {
    Write-Host ('no update needed')
}

0

เพราะคำตอบของ Neils ช่วยฉันได้มากที่นี่คือการแปลภาษาไพ ธ อนโดยไม่มีการอ้างอิง:

import os
import logging
import subprocess

def check_for_updates(directory:str) -> None:
    """Check git repo state in respect to remote"""
    git_cmd = lambda cmd: subprocess.run(
        ["git"] + cmd,
        cwd=directory,
        stdout=subprocess.PIPE,
        check=True,
        universal_newlines=True).stdout.rstrip("\n")

    origin = git_cmd(["config", "--get", "remote.origin.url"])
    logging.debug("Git repo origin: %r", origin)
    for line in git_cmd(["fetch"]):
        logging.debug(line)
    local_sha = git_cmd(["rev-parse", "@"])
    remote_sha = git_cmd(["rev-parse", "@{u}"])
    base_sha = git_cmd(["merge-base", "@", "@{u}"])
    if local_sha == remote_sha:
        logging.info("Repo is up to date")
    elif local_sha == base_sha:
        logging.info("You need to pull")
    elif remote_sha == base_sha:
        logging.info("You need to push")
    else:
        logging.info("Diverged")

check_for_updates(os.path.dirname(__file__))

HTH


-5

คุณสามารถค้นหาสคริปต์ Phingที่ทำในตอนนี้

ฉันต้องการโซลูชันเพื่ออัปเดตสภาพแวดล้อมการผลิตของฉันโดยอัตโนมัติและเรามีความสุขมากขอบคุณสคริปต์นี้ที่ฉันแชร์

สคริปต์ที่เขียนในรูปแบบ XML และความต้องการพิงค์


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