จะตรวจสอบได้อย่างไรว่าไม่มีอะไรที่จะต้องทำในสาขาปัจจุบัน


172

เป้าหมายคือการได้รับสถานะที่ชัดเจนซึ่งสามารถประเมินได้ในคำสั่งเชลล์

ฉันพยายามgit statusแต่จะคืนค่า 0 เสมอแม้ว่าจะมีรายการที่ต้องส่ง

git status
echo $?  #this is always 0

ฉันมีความคิด แต่ฉันคิดว่ามันเป็นความคิดที่ไม่ดี

if [ git status | grep -i -c "[a-z]"> 2 ];
then
 code for change...
else
  code for nothing change...
fi

มีวิธีอื่นอีกไหม?


อัปเดตด้วยวิธีแก้ปัญหาต่อไปนี้ดูโพสต์ของ Mark Longair

ฉันลองสิ่งนี้ แต่มันทำให้เกิดปัญหา

if [ -z $(git status --porcelain) ];
then
    echo "IT IS CLEAN"
else
    echo "PLEASE COMMIT YOUR CHANGE FIRST!!!"
    echo git status
fi

ฉันได้รับข้อผิดพลาดดังต่อไปนี้ [: ??: binary operator expected

ตอนนี้ฉันกำลังมองหาชายคนนั้นและลองคอมไพล์ต่าง

=================== รหัสสำหรับความหวังของฉันและหวังว่าคำตอบที่ดีกว่า ======================

#if [ `git status | grep -i -c "$"` -lt 3 ];
# change to below code,although the above code is simple, but I think it is not strict logical
if [ `git diff --cached --exit-code HEAD^ > /dev/null && (git ls-files --other --exclude-standard --directory | grep -c -v '/$')` ];
then
        echo "PLEASE COMMIT YOUR CHANGE FIRST!!!"
    exit 1

else
    exit 0
fi

4
ในส่วนการปรับปรุงที่ดูเหมือนว่าคุณไม่ได้ทำในสิ่งที่จริงEckesแสดงให้เห็นในคำตอบของเขา - $(git status --porcelain)ในขณะที่เขากล่าวว่าคุณจะต้องใส่ราคาสองครั้งรอบ นอกจากนี้หากคุณต้องการใส่เครื่องหมายอัศเจรีย์ในข้อความของคุณคุณจะต้องใช้เครื่องหมายอัญประกาศเดี่ยวแทนเครื่องหมายคำพูดคู่ - เช่นควรecho 'PLEASE COMMIT YOUR CHANGE FIRST!!!'แทน
Mark Longair

4
ตามที่ Mark พูดว่า: คุณต้องใส่เครื่องหมายอัญประกาศล้อมรอบ$(git status --porcelain)อย่างที่ฉันบอกคุณ!
eckes

1
คำถามนี้จะมีประโยชน์มากกว่านี้หากไม่ได้รวมคำตอบไว้ด้วย
oberlies

@ 9nix00 ทำสิ่งที่คุณได้รับการบอกและแก้ไขและแก้ไขข้อบกพร่องในเชลล์สคริปต์ของคุณด้านบน: BUG: ถ้า [-z $ (คำสั่งบางคำสั่ง)] การแก้ไข: ถ้า [-z "$ (คำสั่งบางอย่าง)"]
MarcH

คำตอบ:


232

อีกทางเลือกหนึ่งในการทดสอบว่าเอาต์พุตของgit status --porcelainว่างเปล่าคือการทดสอบแต่ละเงื่อนไขที่คุณสนใจแยกกัน git statusบางคนอาจไม่เคยสนใจตัวอย่างเช่นถ้ามีไฟล์ที่ไม่ได้ติดตามในการส่งออกของ

ตัวอย่างเช่นหากต้องการดูว่ามีการเปลี่ยนแปลงใด ๆ ในท้องถิ่นที่ไม่มีการกำหนดระยะเวลาหรือไม่คุณสามารถดูรหัสส่งคืนของ:

git diff --exit-code

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

git diff --cached --exit-code

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

git ls-files --other --exclude-standard --directory

อัปเดต: คุณถามด้านล่างว่าคุณสามารถเปลี่ยนคำสั่งเพื่อแยกไดเรกทอรีในผลลัพธ์ได้หรือไม่ คุณสามารถยกเว้นไดเรกทอรีว่างได้โดยเพิ่ม--no-empty-directoryแต่เพื่อแยกไดเรกทอรีทั้งหมดในผลลัพธ์นั้นฉันคิดว่าคุณจะต้องกรองผลลัพธ์เช่นด้วย:

git ls-files --other --exclude-standard --directory | egrep -v '/$'

-vจะegrepหมายถึงการสายออกเท่านั้นที่ไม่ตรงกับรูปแบบและรูปแบบที่ตรงกับสายใด ๆ /ที่ลงท้ายด้วย


ฉันเรียนรู้เคล็ดลับเหล่านี้และมีปัญหา นั่นคือใช้ git ls-files - อื่น ๆ - ยกเว้นมาตรฐาน - ไดเรกทอรีรับรายการรวมถึงไดเรกทอรี จะมีบางวิธีแยกไดเรกทอรีเหล่านี้หรือไม่
9nix00

ใช่ฉันต้องการ และฉันจะปรับปรุงการโพสต์ของฉันสำหรับรหัสสคริปต์ใหม่ ฉันคิดว่าคุณแนะนำเป็นตรรกะที่เข้มงวดมากขึ้นแม้ว่ารหัส lol เพิ่มเติม ... และหวังว่าคำตอบที่ดีกว่าปรากฏขึ้น
9nix00

3
@albfan: อยู่ในหน้าคน git-diff : "ทำการออกจากโปรแกรมด้วยรหัสที่คล้ายกับ diff (1) นั่นคือมันจะออกด้วย 1 หากมีความแตกต่างและ 0 หมายถึงไม่มีความแตกต่าง"
Mark Longair

เพียงแค่ชี้ให้เห็นมันมีอย่างน้อยตั้งแต่ปี 2007 13da0fc0มีประโยชน์มากสำหรับเชลล์สคริปต์และเข้ากันได้อย่างสมบูรณ์กับ git รุ่นเก่า
albfan

10
--quiet(ซึ่งหมายถึง--exit-code) ยังเงียบเอาท์พุทสำหรับผู้ที่ต้องการเพียงรหัสทางออก
phs

113

ค่าตอบแทนของgit statusเพียงแค่บอกคุณรหัสทางออกของgit statusไม่ใช่ถ้ามีการแก้ไขใด ๆ ที่จะมุ่งมั่น

หากคุณต้องการgit statusเอาต์พุตรุ่นที่อ่านได้ด้วยคอมพิวเตอร์ให้ลอง

git status --porcelain

ดูคำอธิบายของ git statusสำหรับข้อมูลเพิ่มเติมเกี่ยวกับที่

ตัวอย่างการใช้งาน (สคริปต์ทดสอบเพียงว่าgit status --porcelainให้ผลใด ๆ โดยไม่จำเป็นต้องแยกวิเคราะห์):

if [ -n "$(git status --porcelain)" ]; then
  echo "there are changes";
else
  echo "no changes";
fi

git status --porcelainโปรดทราบว่าคุณจะต้องพูดสตริงเพื่อทดสอบเช่นการส่งออกของ สำหรับคำแนะนำเพิ่มเติมเกี่ยวกับการสร้างการทดสอบโปรดดูคู่มือการใช้สคริปต์การทุบตีขั้นสูง ( การเปรียบเทียบสตริงส่วน)


สวัสดีคุณให้คำแนะนำที่ดีฉันลองใช้ แต่ในสคริปต์มันทำให้เกิดปัญหาฉันปรับปรุงถ้าเราใช้สิ่งนี้ถ้า [-z $ (สถานะคอมไพล์ - พอร์ซเลน)]; มันจะได้รับข้อผิดพลาด [: ??: ผู้ประกอบการไบนารีคาดว่าฉันหาคู่มือและใช้สิ่งนี้ถ้า [-z $ (สถานะ git --short)]; สิ่งนี้สามารถใช้ได้ขอบคุณ!
9nix00

ขออภัยยังคงมีปัญหา เมื่อการกระทำนั้นสะอาด ใช้พอร์ซเลนและสั้นทั้งสองตกลง แต่เมื่อกระทำไม่สะอาด มันจะทำให้เกิดข้อผิดพลาด [: ??: คาดว่าผู้ประกอบการแบบไบนารี ฉันคิดว่าบางทีเราควรลองใช้ base64 เพื่อเข้ารหัสมัน ให้ฉันพยายาม! กำลังดาวน์โหลดเครื่องมือคำสั่ง base64 .... lol
9nix00

มันทำให้เกิดปัญหาเมื่อการกระทำไม่สะอาด
9nix00

1
ทางออกที่ดี เพื่อความทนทานที่เพิ่มขึ้นคุณสามารถผนวก|| echo noการทดแทนคำสั่งเพื่อไม่ให้รายงานพื้นที่ทำงานผิดพลาดหากgit statusล้มเหลวโดยพื้นฐาน นอกจากนี้รหัสของคุณ (น่าชื่นชม) POSIX- สอดคล้อง แต่เนื่องจากคุณลิงก์ไปยังคู่มือทุบตีให้ฉันเพิ่มว่าถ้าคุณใช้ทุบตี[[ ... ]]แทนเข้ากันได้กับ POSIX [ ... ]คุณไม่จำเป็นต้องพูดซ้ำแทนคำสั่ง (แม้ว่ามันจะ จะไม่มีอันตรายใด ๆ [[ -z $(git status --porcelain) ]]):
mklement0

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

33

หากคุณเป็นเหมือนฉันคุณต้องการที่จะรู้ว่ามี:

1) การเปลี่ยนแปลงไฟล์ที่มีอยู่ 2) ไฟล์ที่เพิ่มใหม่ 3) ไฟล์ที่ถูกลบ

และโดยเฉพาะไม่ต้องการที่จะรู้เกี่ยวกับ 4) ไฟล์ที่ไม่ได้ติดตาม

สิ่งนี้ควรทำ:

git status --untracked-files=no --porcelain

นี่คือรหัสทุบตีของฉันเพื่อออกจากสคริปต์ถ้า repo นั้นสะอาด มันใช้เวอร์ชั่นย่อของตัวเลือกไฟล์ที่ไม่ได้ติดตาม:

[[ -z $(git status -uno --porcelain) ]] && echo "this branch is clean, no need to push..." && kill -SIGINT $$;

4
+1 สำหรับ—untracked-files=no; ฉันคิดว่าการทดสอบของคุณสามารถทำให้ง่าย[[ -z $(git status --untracked-files=no --porcelain) ]]ขึ้น git statusไม่ควรเขียนถึง stderr เว้นแต่บางสิ่งบางอย่างผิดพลาดพื้นฐาน - และจากนั้นคุณไม่ต้องการที่จะเห็นผลลัพธ์ที่ (หากคุณต้องการพฤติกรรมที่แข็งแกร่งมากขึ้นในเหตุการณ์นั้นให้ผนวก|| echo noกับการทดแทนคำสั่งเพื่อให้การทดสอบความสะอาดยังคงล้มเหลว) การเปรียบเทียบสตริงการ / -zผู้ประกอบการสามารถจัดการกับสตริงหลายสาย - tailไม่จำเป็นต้องให้
mklement0

2
ขอบคุณ @ mklement0 แม้จะสั้นกว่านี้สักหน่อย:[[ -z $(git status -u no --porcelain) ]]
moodboom

1
การแก้ไข: รุ่นที่สั้นกว่าของฉันจริงเพียงแค่ตรวจสอบสถานะในไฟล์ชื่อ "ไม่"! Bzzt ควรเป็น: [[ -z $(git status -uno --porcelain) ]]
moodboom

2
ฉันซาบซึ้งในการติดตาม นั่นเป็นข้อบกพร่องเล็กน้อย - บทเรียนคือ ตัวเลือกสั้น ๆ ที่มีอาร์กิวเมนต์ตัวเลือกต้องมีการต่อท้ายอาร์กิวเมนต์โดยตรงโดยไม่มีช่องว่างระหว่าง วิธีการเกี่ยวกับการรวมรุ่นสั้นที่ถูกต้องโดยตรงในคำตอบของคุณ?
mklement0

9

เป็นไปได้ที่จะรวมเข้าgit status --porcelainกับgrepการทดสอบที่ทำได้ง่าย

if git status --porcelain | grep .; then
    echo Repo is dirty
else
    echo Repo is clean
fi

ฉันใช้สิ่งนี้เป็นหนึ่งซับง่าย ๆ บางครั้ง:

# pull from origin if our repo is clean
git status --porcelain | grep . || git pull origin master

เพิ่ม-qsในคำสั่ง grep เพื่อทำให้มันเงียบ


2
+1 เพื่อความสง่างาม; ข้อแม้เล็กน้อย: ควรgit statusล้มเหลวสาหัส (เช่น repo เสียหาย) การทดสอบของคุณจะผิดพลาดรายงานสะอาดพื้นที่ทำงาน เลือกหนึ่งคือการใช้git status --porcelain 2>&1แต่ที่จะ 'กิน' เกิดข้อผิดพลาดถ้าคุณใช้ grep -qกับ (การจัดการกับสิ่งนั้นจะทำให้ความสง่างามเสียไป(git status --porcelain || echo err) | grep -q .)
mklement0

อีกทางเลือกหนึ่งที่สามารถเขียน:test -z "$(git status --porcelain)" || git pull origin master
VasiliNovikov

5

จากซอร์สโค้ด git มีสคริปต์ sh ซึ่งรวมถึงต่อไปนี้

require_clean_work_tree () {
    git rev-parse --verify HEAD >/dev/null || exit 1
    git update-index -q --ignore-submodules --refresh
    err=0

    if ! git diff-files --quiet --ignore-submodules
    then
        echo >&2 "Cannot $1: You have unstaged changes."
        err=1
    fi

    if ! git diff-index --cached --quiet --ignore-submodules HEAD --
    then
        if [ $err = 0 ]
        then
            echo >&2 "Cannot $1: Your index contains uncommitted changes."
        else
            echo >&2 "Additionally, your index contains uncommitted changes."
        fi
        err=1
    fi

    if [ $err = 1 ]
    then
        test -n "$2" && echo >&2 "$2"
        exit 1
    fi
}

ตัวอย่างนี้แสดงให้เห็นว่ามีความเป็นไปได้ที่จะใช้git diff-filesและgit diff-indexดูว่ามีการเปลี่ยนแปลงใด ๆ กับไฟล์ที่รู้จักก่อนหน้านี้หรือไม่ อย่างไรก็ตามไม่อนุญาตให้คุณค้นหาว่ามีการเพิ่มไฟล์ที่ไม่รู้จักใหม่ลงในแผนผังการทำงานหรือไม่


ใช้งานได้ดียกเว้นไฟล์ใหม่ เราสามารถเพิ่มสิ่งนี้ ถ้า! git ls-files - อื่น ๆ - ยกเว้นมาตรฐาน - ไดเรกทอรี | grep -c -v '/ $' จากนั้นออก 0 อื่น echo "โปรดส่งไฟล์ใหม่ของคุณหากคุณไม่ต้องการเพิ่มโปรดเพิ่มมันในไฟล์ git-ละเว้น" ออก 1 fi
9nix00

การที่if [ -n "$(git ls-files --others --exclude-standard)" ]ไม่มี piping หรือ greping เพิ่มเติมก็เพียงพอที่จะตรวจจับไฟล์ที่ไม่ได้ติดตาม
Arrowmaster

5

ฉันจะทำแบบทดสอบนี้:

git diff --quiet --cached

หรือสิ่งนี้จะชัดเจน:

git diff --quiet --exit-code --cached

ที่อยู่:

--exit รหัส

ทำให้การออกจากโปรแกรมด้วยรหัสคล้ายกับ diff (1) นั่นคือมันจะออกด้วย 1 หากมีความแตกต่างและ 0 หมายถึงไม่มีความแตกต่าง

--เงียบ

ปิดใช้งานเอาต์พุตทั้งหมดของโปรแกรม นัย - ออกจากโค้ด


3

ฉันค่อนข้างช้าในการอภิปราย แต่ถ้าเป็นเพียงคุณเท่านั้นที่จำเป็นต้องมีรหัสการออกเป็น 0 หากgit status --porcelainไม่มีอะไรส่งคืนและ! = 0 โปรดลองสิ่งนี้:

exit $( git status --porcelain | wc -l )

สิ่งนี้จะทำให้จำนวนบรรทัดเป็นรหัสออกที่เสี่ยงต่อการเกิดปัญหาเมื่อมีมากกว่า 255 บรรทัด ดังนั้น

exit $( git status --porcelain | head -255 | wc -l )

จะบัญชีสำหรับที่;)


1
โดยทั่วไปจะไม่ได้กำหนดหากมีเอาต์พุตมากกว่า 255 บรรทัด
tripleee

เห็นดีขอบคุณ!
Skeeve

2

ฉันใช้สิ่งนี้ในสคริปต์เพื่อ:

  • 0 เมื่อทุกอย่างสะอาด
  • 1 เมื่อมีไฟล์ต่างหรือไม่ได้ติดตาม

    [-z "$ (สถานะคอมไพล์ - พอร์ซเลน)"]


การใช้if ! git diff --quiet; thenนั้นสะอาดและมีประสิทธิภาพมากกว่า (ฉันคิดว่า) กล่าวอีกนัยหนึ่งให้ใช้รหัสออกไม่ใช่ stdout
Alexander Mills

1
@AlexanderMills git diff --quietทำงานแตกต่างจากgit status --porcelainการเปลี่ยนแปลงในแคช
Martin von Wittich

0

ไม่สวย แต่ใช้งานได้:

git status | grep -qF 'working directory clean' || echo "DIRTY"

ไม่แน่ใจว่าข้อความนั้นขึ้นอยู่กับสถานที่หรือไม่ดังนั้นอาจวางไว้LANG=Cข้างหน้า

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