ตรวจสอบดัชนีสกปรกหรือไฟล์ที่ไม่ได้ติดตามด้วย Git


243

ฉันจะตรวจสอบได้อย่างไรว่าฉันมีการเปลี่ยนแปลงที่ไม่มีข้อผูกมัดในที่เก็บ git ของฉัน:

  1. เพิ่มการเปลี่ยนแปลงในดัชนีแล้ว แต่ไม่ได้กระทำ
  2. ไฟล์ที่ไม่ได้ติดตาม

จากสคริปต์หรือไม่?

git-status ดูเหมือนว่าจะส่งคืนค่าศูนย์ด้วย git เวอร์ชัน 1.6.4.2 เสมอ


3
สถานะ git จะส่งคืน 1 หากมีไฟล์ที่ไม่มีการแก้ไข แต่โดยทั่วไปแล้วฉันพบว่าเครื่องมือคอมไพล์ไม่ได้ละเอียดถี่ถ้วนกับสถานะการส่งคืน EG git diff ส่งคืนค่า 0 ไม่ว่าจะมีความแตกต่างหรือไม่
intuited

11
@intuited: ถ้าคุณต้องการdiffที่จะบ่งบอกถึงการมีหรือไม่มีความแตกต่างมากกว่าการทำงานที่ประสบความสำเร็จของคำสั่งแล้วคุณจำเป็นต้องใช้หรือ--exit-code --quietโดยทั่วไปคำสั่ง git นั้นสอดคล้องกันมากกับการส่งคืนรหัสทางออกที่เป็นศูนย์หรือไม่เป็นศูนย์เพื่อระบุความสำเร็จของคำสั่ง
CB Bailey

1
@ Charles Bailey: เฮ้เยี่ยมมากฉันพลาดตัวเลือกนั้นไป ขอบคุณ! ฉันเดาว่าฉันไม่เคยต้องการให้ทำเช่นนั้นจริง ๆ หรือฉันอาจจะฝืน manpage สำหรับมัน ดีใจที่คุณแก้ไขฉัน :)
intuited

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

1
@Robert - ฉันหวังว่าคุณอาจลองเปลี่ยนคำตอบที่คุณยอมรับ คนที่คุณเลือกนั้นอาศัยคำสั่ง 'เครื่องลายคราม' ของ git ที่บอบบางกว่า คำตอบที่ถูกต้องจริง (ด้วย2x upvotes) ขึ้นอยู่กับคำสั่ง git 'plumbing' ที่ถูกต้อง คำตอบที่ถูกต้องนั้นเดิมคือ Chris Johnsen ฉันนำสิ่งนี้มาใช้เพราะวันนี้เป็นครั้งที่ 3 ที่ฉันต้องแนะนำใครบางคนมาที่หน้านี้ แต่ฉันไม่สามารถชี้ไปที่คำตอบได้ฉันได้อธิบายว่าทำไมคำตอบที่ได้รับการยอมรับนั้นดีที่สุด / ผิดพลาด ขอบคุณ!
ไมค์

คำตอบ:


173

ช่วงเวลาที่ยอดเยี่ยม! ฉันเขียนโพสต์บล็อกเกี่ยวกับสิ่งนี้ไม่กี่วันที่ผ่านมาเมื่อฉันคิดวิธีการเพิ่มข้อมูลสถานะ git ให้ฉัน

นี่คือสิ่งที่ฉันทำ:

  1. สำหรับสถานะสกปรก:

    # Returns "*" if the current git branch is dirty.
    function evil_git_dirty {
      [[ $(git diff --shortstat 2> /dev/null | tail -n1) != "" ]] && echo "*"
    }
  2. สำหรับไฟล์ที่ไม่ได้ติดตาม (สังเกตการ--porcelainตั้งค่าสถานะgit statusที่ให้เอาต์พุตแจงส่วนที่ดี):

    # Returns the number of untracked files
    
    function evil_git_num_untracked_files {
      expr `git status --porcelain 2>/dev/null| grep "^??" | wc -l` 
    }

แม้ว่าgit diff --shortstatจะสะดวกกว่า แต่คุณสามารถใช้git status --porcelainสำหรับรับไฟล์ที่สกปรก:

# Get number of files added to the index (but uncommitted)
expr $(git status --porcelain 2>/dev/null| grep "^M" | wc -l)

# Get number of files that are uncommitted and not added
expr $(git status --porcelain 2>/dev/null| grep "^ M" | wc -l)

# Get number of total uncommited files
expr $(git status --porcelain 2>/dev/null| egrep "^(M| M)" | wc -l)

หมายเหตุ: 2>/dev/nullตัวกรองจะแสดงข้อความแสดงข้อผิดพลาดเพื่อให้คุณสามารถใช้คำสั่งเหล่านี้ในไดเรกทอรีที่ไม่ใช่ git (พวกเขาจะกลับมา0เพื่อนับไฟล์)

แก้ไข :

นี่คือโพสต์:

การเพิ่มข้อมูลสถานะ Git ให้กับ Terminal Prompt ของคุณ

ปรับปรุง Shell Prompt ที่เปิดใช้งาน Git


8
มันน่าสังเกตว่าเสร็จทุบตีคอมไพล์มาพร้อมกับฟังก์ชั่นเปลือกสำหรับการทำสวยมากสิ่งที่คุณทำกับรวดเร็วของคุณ __git_ps1- มันแสดงชื่อสาขารวมถึงการดูแลเป็นพิเศษหากคุณอยู่ในขั้นตอนการรีบูตการสมัครสมาชิกการผสานหรือการแบ่งครึ่ง และคุณสามารถตั้งค่าตัวแปรสภาพแวดล้อมGIT_PS1_SHOWDIRTYSTATEเพื่อรับเครื่องหมายดอกจันสำหรับการเปลี่ยนแปลงที่ไม่จัดเตรียมและบวกสำหรับการเปลี่ยนฉาก (ฉันคิดว่าคุณยังสามารถได้รับมันจะบ่งบอกถึงไฟล์ที่ไม่ได้ติดตามและให้คุณบางส่วนgit-describeเอาท์พุท)
Cascabel

8
คำเตือน: git diff --shortstatจะให้ค่าลบเท็จหากมีการเปลี่ยนแปลงอยู่ในดัชนีแล้ว
Marko Topolnik

4
git status --porcelainจะดีกว่าเพราะgit diff --shortstatจะไม่จับไฟล์เปล่าที่เพิ่งสร้างใหม่ คุณสามารถลองใช้งานได้ในต้นไม้ทำงานที่สะอาด:touch foo && git diff --shortstat
Campadrenalin

7
ไม่ - พอร์ซเลนหมายถึงผลลัพธ์สำหรับมนุษย์และแตกง่าย !! ดูคำตอบของ @ChrisJohnsen ซึ่งใช้ตัวเลือกที่เสถียรและเป็นมิตรกับสคริปต์อย่างถูกต้อง
ไมค์

7
@ ไมค์จากหน้า man git-status เกี่ยวกับตัวเลือก Porcelain: "ให้ผลลัพธ์ในรูปแบบที่ง่ายต่อการแยกวิเคราะห์สำหรับสคริปต์ซึ่งคล้ายกับเอาต์พุตสั้น ๆ แต่จะยังคงมีเสถียรภาพในเวอร์ชัน Git และไม่คำนึงถึงการกำหนดค่าของผู้ใช้ "
itsadok

399

กุญแจสำคัญในการ“ เขียนสคริปต์” Git ที่น่าเชื่อถือคือการใช้คำสั่ง 'การประปา'

นักพัฒนาใช้ความระมัดระวังเมื่อเปลี่ยนคำสั่งการวางท่อเพื่อให้แน่ใจว่ามีอินเทอร์เฟซที่เสถียรมาก (เช่นการรวมกันของสถานะพื้นที่เก็บข้อมูล, stdin, ตัวเลือกบรรทัดคำสั่ง, ข้อโต้แย้ง, ฯลฯ ) จะสร้างผลลัพธ์เดียวกันใน Git ทุกรุ่น มีตัวเลือก) รูปแบบเอาต์พุตใหม่ในคำสั่งการวางท่อสามารถนำเสนอผ่านตัวเลือกใหม่ แต่ไม่สามารถแนะนำปัญหาใด ๆ สำหรับโปรแกรมที่เขียนไปแล้วกับเวอร์ชันเก่า (พวกเขาจะไม่ใช้ตัวเลือกใหม่เนื่องจากไม่มีอยู่ (หรืออย่างน้อยก็คือ ไม่ได้ใช้) ในขณะที่เขียนสคริปต์)

น่าเสียดายที่คำสั่ง Git 'ทุกวัน' เป็นคำสั่ง 'เครื่องเคลือบ' ดังนั้นผู้ใช้ Git ส่วนใหญ่อาจไม่คุ้นเคยกับคำสั่งระบบท่อ ความแตกต่างระหว่างเครื่องลายครามและคำสั่งการประปาจะทำในหลักmanpage คอมไพล์ (ดูหัวข้อย่อยชื่อคำสั่งระดับสูง (พอร์ซเลน)และคำสั่งในระดับต่ำ (ประปา)


เพื่อหาข้อมูลเกี่ยวกับการเปลี่ยนแปลง uncomitted คุณอาจจะต้องgit diff-index(ดัชนีเปรียบเทียบ (และอาจจะบิตของต้นไม้ที่ทำงาน) กับบางส่วน treeish อื่น ๆ (เช่นการติดตามHEAD)) อาจจะgit diff-filesและอาจ (เทียบต้นไม้กับดัชนีการทำงาน) git ls-files(แฟ้มรายการ; เช่นรายการที่ไม่ได้ติดตาม , ไฟล์ที่ไม่ได้รับสิทธิ)

(โปรดทราบว่าในคำสั่งด้านล่างHEAD --จะใช้แทนHEADเพราะมิฉะนั้นคำสั่งล้มเหลวหากมีไฟล์ชื่อHEAD)

ในการตรวจสอบว่าที่เก็บมีการเปลี่ยนแปลงแบบฉาก (ยังไม่ได้ทำ) ใช้สิ่งนี้

git diff-index --quiet --cached HEAD --
  • หากออก0จากที่นั่นแสดงว่าไม่มีความแตกต่าง ( 1หมายความว่ามีความแตกต่าง)

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

git diff-files --quiet
  • รหัสทางออกเหมือนกับgit diff-index( 0== ไม่มีความแตกต่าง; 1== ความแตกต่าง)

ในการตรวจสอบว่าการรวมกันของดัชนีและไฟล์ที่ถูกติดตามในแผนผังการทำงานมีการเปลี่ยนแปลงเกี่ยวกับHEAD:

git diff-index --quiet HEAD --
  • นี่คือการรวมกันของสองคนก่อนหน้านี้ ข้อแตกต่างที่สำคัญอย่างหนึ่งก็คือมันจะยังคงรายงาน“ ไม่แตกต่าง” หากคุณมีการเปลี่ยนแปลงแบบฉากที่คุณ“ เลิกทำ” ในแผนผังการทำงาน (กลับไปที่เนื้อหาที่มีอยู่HEAD) ในสถานการณ์เดียวกันนี้ทั้งสองคำสั่งที่แยกกันจะส่งคืนรายงานของ“ ความแตกต่างที่มีอยู่”

คุณยังกล่าวถึงไฟล์ที่ไม่ได้ติดตาม คุณอาจหมายถึง“ ไม่ได้ติดตามและไม่ได้รับการรับรอง” หรือคุณอาจหมายถึงเพียงแค่“ ไม่ได้ติดตาม” (รวมถึงไฟล์ที่ถูกละเว้น) ไม่ว่าจะด้วยวิธีใดgit ls-filesเป็นเครื่องมือสำหรับงาน:

สำหรับ“ untracked” (จะรวมไฟล์ที่ถูกละเว้นถ้ามี):

git ls-files --others

สำหรับ“ untracked และ unignored”:

git ls-files --exclude-standard --others

ความคิดแรกของฉันคือตรวจสอบว่าคำสั่งเหล่านี้มีเอาต์พุตหรือไม่:

test -z "$(git ls-files --others)"
  • หากออก0จากด้วยจะไม่มีไฟล์ที่ไม่ได้ติดตาม หากออก1จากด้วยจะมีไฟล์ที่ไม่ได้ติดตาม

มีโอกาสเล็กน้อยที่สิ่งนี้จะแปลการออกที่ผิดปกติจากgit ls-filesเป็นรายงาน "ไม่มีไฟล์ที่ไม่ได้ติดตาม" (ทั้งผลลัพธ์ในการออกที่ไม่ใช่ศูนย์ของคำสั่งด้านบน) รุ่นที่ทนทานกว่านี้เล็กน้อยอาจมีลักษณะเช่นนี้:

u="$(git ls-files --others)" && test -z "$u"
  • แนวคิดนี้เหมือนกับคำสั่งก่อนหน้า แต่อนุญาตให้เกิดข้อผิดพลาดที่ไม่คาดคิดจากgit ls-filesการเผยแพร่ ในกรณีนี้ทางออกที่ไม่เป็นศูนย์อาจหมายถึง“ มีไฟล์ที่ไม่ได้ติดตาม” หรืออาจหมายถึงข้อผิดพลาดเกิดขึ้น หากคุณต้องการผลลัพธ์ "ข้อผิดพลาด" รวมกับผลลัพธ์ "ไม่มีไฟล์ที่ไม่ได้ติดตาม" แทนให้ใช้test -n "$u"(โดยที่การออก0หมายถึง "ไฟล์ที่ไม่ได้ติดตาม" บางส่วนและไม่ใช่ศูนย์หมายถึงข้อผิดพลาดหรือ "ไม่มีไฟล์ที่ไม่ได้ติดตาม")

แนวคิดอื่นคือการใช้--error-unmatchเพื่อทำให้เกิดการออกที่ไม่เป็นศูนย์เมื่อไม่มีไฟล์ที่ไม่ได้ติดตาม สิ่งนี้ยังมีความเสี่ยงของการทำให้“ ไม่มีไฟล์ที่ไม่ได้ติดตาม” (จบการทำงาน1) ด้วย“ เกิดข้อผิดพลาด” (ออกจากไม่ใช่ศูนย์ แต่อาจเป็นไปได้128) แต่การตรวจสอบรหัสออก0กับ1และไม่เป็นศูนย์น่าจะค่อนข้างแข็งแกร่ง:

git ls-files --others --error-unmatch . >/dev/null 2>&1; ec=$?
if test "$ec" = 0; then
    echo some untracked files
elif test "$ec" = 1; then
    echo no untracked files
else
    echo error from ls-files
fi

ตัวอย่างใด ๆ ข้างต้นgit ls-filesสามารถทำได้--exclude-standardหากคุณต้องการพิจารณาเฉพาะไฟล์ที่ไม่ได้ติดตามและไม่ได้รับการรับรอง


5
ผมอยากจะชี้ให้เห็นว่าgit ls-files --othersจะช่วยให้ท้องถิ่นไฟล์ที่ไม่ได้ติดตามในขณะที่git status --porcelainของคำตอบที่ได้รับการยอมรับให้ทุกไฟล์ที่ไม่ได้ติดตามที่อยู่ภายใต้พื้นที่เก็บข้อมูลคอมไพล์ ฉันไม่ได้ต้องการโปสเตอร์ต้นฉบับเหล่านี้ แต่ความแตกต่างระหว่างทั้งสองนั้นน่าสนใจ
Eric O Lebigot

1
@phunehehe: คุณจำเป็นต้องจัดหา pathspec --error-unmatchกับ ลอง (เช่น) git ls-files --other --error-unmatch --exclude-standard .(สังเกตช่วงเวลาต่อท้ายมันหมายถึง cwd; ให้เรียกใช้จากไดเรกทอรีระดับบนสุดของแผนผังการทำงาน)
Chris Johnsen

8
@phs: คุณอาจต้องทำgit update-index -q --refreshก่อนที่diff-indexจะหลีกเลี่ยงบางอย่าง "บวกเท็จ" ที่เกิดจากข้อมูลสถิติไม่ตรงกัน (2)
Chris Johnsen

1
ฉันถูกกัดโดยความgit update-indexต้องการ! สิ่งนี้สำคัญหากมีสิ่งใดสัมผัสกับไฟล์โดยไม่ทำการแก้ไขใด ๆ
Nakedible

2
@RobertSiemer โดย "local" ฉันหมายถึงไฟล์ภายใต้ไดเรกทอรีปัจจุบันของคุณซึ่งอาจอยู่ใต้ที่เก็บ git หลัก --porcelainรายการวิธีการแก้ปัญหาทุกไฟล์ที่ไม่ได้ติดตามพบในเก็บคอมไพล์ทั้งหมด (ลบไฟล์คอมไพล์ละเว้น) แม้ว่าคุณเป็นคนหนึ่งที่อยู่ภายในไดเรกทอรีย่อย
Eric O Lebigot

139

สมมติว่าคุณอยู่ในคอมไพล์ 1.7.0 หรือใหม่กว่า ...

หลังจากอ่านคำตอบทั้งหมดในหน้านี้และการทดลองบางอย่างแล้วฉันคิดว่าวิธีการที่ผสมผสานความถูกต้องและความกะทัดรัดเข้าด้วยกันคือ:

test -n "$(git status --porcelain)"

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

ในกรณีนั้นมันสมเหตุสมผลที่จะจำลองสิ่งที่โปรแกรมเมอร์จะทำ: พิมพ์git statusและดูผลลัพธ์ แต่เราไม่ต้องการพึ่งคำที่แสดงดังนั้นเราจึงใช้--porcelainโหมดที่แนะนำใน 1.7.0; เมื่อเปิดใช้งานไดเร็กทอรีแบบคลีนจะไม่มีผลลัพธ์

จากนั้นเราใช้test -nเพื่อดูว่ามีการส่งออกใด ๆ หรือไม่

คำสั่งนี้จะส่งคืน 1 หากไดเร็กทอรีการทำงานสะอาดและ 0 หากมีการเปลี่ยนแปลงที่จะถูกคอมมิต คุณสามารถเปลี่ยน-nเป็น a -zหากคุณต้องการตรงกันข้าม สิ่งนี้มีประโยชน์สำหรับการโยงสิ่งนี้กับคำสั่งในสคริปต์ ตัวอย่างเช่น:

test -z "$(git status --porcelain)" || red-alert "UNCLEAN UNCLEAN"

สิ่งนี้บอกได้อย่างมีประสิทธิภาพ "ทั้งไม่มีการเปลี่ยนแปลงที่จะทำหรือตั้งค่าการเตือน" หนึ่งซับนี้อาจจะดีกว่าคำสั่ง if- ขึ้นอยู่กับสคริปต์ที่คุณกำลังเขียน


1
สำหรับฉันคำสั่งอื่น ๆ ทั้งหมดให้ผลลัพธ์ที่แตกต่างในตัวแทนเดียวกันระหว่าง Linux และ windows คำสั่งนี้ให้ผลลัพธ์เดียวกันทั้งคู่
Adarsha

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

สำหรับสคริปต์การปรับใช้แบบแมนวลให้รวมสิ่งนี้เข้าด้วยtest -n "$(git diff origin/$branch)"กันเพื่อช่วยป้องกันไม่ให้มีการอนุญาตการกระทำในเครื่อง
Erik Aronesty


8

ลองดูคำตอบเหล่านี้สองสามข้อ ... (และมีปัญหาต่าง ๆ ใน * ระวังและหน้าต่างซึ่งเป็นข้อกำหนดที่ฉันมี) ... พบว่าทำงานได้ดี ...

git diff --no-ext-diff --quiet --exit-code

วิธีตรวจสอบรหัสออกใน * ระวัง

echo $?   
#returns 1 if the repo has changes (0 if clean)

ในการตรวจสอบรหัสออกในหน้าต่าง $

echo %errorlevel% 
#returns 1 if the repos has changes (0 if clean) 

แหล่งข่าวจากhttps://github.com/sindresorhus/pure/issues/115 ขอบคุณ @paulirish บนโพสต์นั้นเพื่อการแบ่งปัน


4

ทำไมไม่แค็ปซูล ' git statusกับสคริปต์ที่:

  • จะวิเคราะห์ผลลัพธ์ของคำสั่งนั้น
  • จะส่งคืนรหัสข้อผิดพลาดที่เหมาะสมตามสิ่งที่คุณต้องการ

ด้วยวิธีนี้คุณสามารถใช้สถานะ 'ปรับปรุง' ในสคริปต์ของคุณ


ในฐานะที่เป็น0xFEกล่าวของเขาในคำตอบที่ดีเยี่ยม , git status --porcelainเป็นเครื่องมือในการแก้ปัญหาใด ๆ ตามสคริปต์

--porcelain

ให้เอาต์พุตในรูปแบบที่เสถียรและง่ายต่อการแยกวิเคราะห์สำหรับสคริปต์
ปัจจุบันนี้เหมือนกัน--short outputแต่รับประกันได้ว่าจะไม่เปลี่ยนแปลงในอนาคตทำให้ปลอดภัยสำหรับสคริปต์


อาจเป็นเพราะฉันขี้เกียจ ฉันคิดว่ามันมีในตัวสำหรับสิ่งนี้เพราะดูเหมือนว่าเป็นกรณีการใช้งานที่ค่อนข้างพบบ่อย
Robert Munteanu

ฉันโพสต์โซลูชันตามคำแนะนำของคุณถึงแม้ว่าฉันจะไม่พอใจอย่างมาก
Robert Munteanu

4

ความเป็นไปได้แบบ DIY เดียวได้รับการปรับปรุงให้เป็นไปตามคำแนะนำของ0xfe

#!/bin/sh
exit $(git status --porcelain | wc -l) 

ตามที่บันทึกไว้โดยChris Johnsenสิ่งนี้ใช้ได้กับ Git 1.7.0 หรือใหม่กว่าเท่านั้น


6
ปัญหานี้คือคุณไม่สามารถคาดหวังได้อย่างน่าเชื่อถือสตริง 'ไดเรกทอรีการทำงานที่สะอาด' ในรุ่นอนาคต ธง --porcelain มีไว้สำหรับการแยกวิเคราะห์ดังนั้นทางออกที่ดีกว่าคือ: ออกจาก $ (สถานะคอมไพล์ --porcelain | wc -l)
0xfe

@ 0xfe - คุณรู้เมื่อมีการ--porcelainเพิ่มธง? ไม่ทำงานกับ 1.6.4.2
Robert Munteanu

@ Robert: ลองgit status --shortแล้ว
VonC

3
git status --porcelainและgit status --shortทั้งคู่ได้รับการแนะนำใน 1.7.0 --porcelainมันถูกนำมาใช้โดยเฉพาะเพื่อให้git status --shortสามารถเปลี่ยนแปลงรูปแบบในอนาคต ดังนั้นgit status --shortจะประสบปัญหาเดียวกับgit status(เอาท์พุทอาจเปลี่ยนแปลงได้ตลอดเวลาเพราะมันไม่ใช่คำสั่ง 'ประปา')
Chris Johnsen

@ Chris ขอบคุณสำหรับข้อมูลพื้นหลัง ฉันได้อัปเดตคำตอบเพื่อสะท้อนวิธีที่ดีที่สุดในการทำเช่นนี้ใน Git 1.7.0
Robert Munteanu

2

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

นี่เป็นสิ่งสำคัญมากสำหรับการหลีกเลี่ยงกรณีที่บิวด์สร้างสิ่งที่เหลืออยู่

ถึงตอนนี้คำสั่งที่ดีที่สุดที่ฉันใช้ดูเหมือนจะเป็น:

 test -z "$(git status --porcelain | tee /dev/fd/2)" || \
     {{ echo "ERROR: git unclean at the end, failing build." && return 1 }}

มันอาจดูซับซ้อนเล็กน้อยและฉันจะขอบคุณถ้ามีคนพบว่ามีตัวแปรสั้น ๆ ที่ยังคงรักษาพฤติกรรมที่ต้องการ:

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

2

@ eduard-wirch คำตอบค่อนข้างสมบูรณ์ แต่เนื่องจากฉันต้องการตรวจสอบทั้งสองในเวลาเดียวกันนี่คือตัวแปรสุดท้ายของฉัน

        set -eu

        u="$(git ls-files --others)"
        if ! git diff-index --name-only --quiet HEAD -- || [ -z "${u:-}" ]; then
            dirty="-dirty"
        fi

เมื่อไม่ดำเนินการโดยใช้ set -e หรือเทียบเท่าเราสามารถทำแทนu="$(git ls-files --others)" || exit 1(หรือคืนค่าถ้าฟังก์ชันนี้ใช้กับฟังก์ชันที่ใช้แล้ว)

ดังนั้น untracked_files จะถูกตั้งค่าก็ต่อเมื่อคำสั่งประสบความสำเร็จอย่างถูกต้อง

หลังจากนั้นเราสามารถตรวจสอบคุณสมบัติทั้งสองและตั้งค่าตัวแปร (หรืออะไรก็ได้)


1

นี่เป็นรูปแบบที่เป็นมิตรกับเชลล์สำหรับการค้นหาว่ามีไฟล์ที่ไม่ได้ติดตามอยู่ในที่เก็บหรือไม่:

# Works in bash and zsh
if [[ "$(git status --porcelain 2>/dev/null)" = *\?\?* ]]; then
  echo untracked files
fi

นี่ไม่ได้แยกกระบวนการที่สองgrepและไม่จำเป็นต้องตรวจสอบว่าคุณอยู่ในที่เก็บ git หรือไม่ ซึ่งมีประโยชน์สำหรับการแจ้งเชลล์ ฯลฯ


1

คุณยังสามารถทำ

git describe --dirty

. มันจะผนวกคำว่า "-dirty" ที่ท้ายถ้าตรวจพบต้นไม้ทำงานสกปรก ตามgit-describe(1):

   --dirty[=<mark>]
       Describe the working tree. It means describe HEAD and appends <mark> (-dirty by default) if
       the working tree is dirty.

. ข้อแม้: ไฟล์ที่ไม่ได้ติดตามจะไม่ถือว่าเป็น "สกปรก" เนื่องจากในฐานะ manpage ระบุว่ามันสนใจเฉพาะต้นไม้ทำงาน


0

อาจจะมีการรวมกันที่ดีขึ้นของคำตอบจากหัวข้อนี้ .. แต่งานนี้สำหรับฉัน ... สำหรับคุณ.gitconfig's [alias]ส่วน ...

          # git untracked && echo "There are untracked files!"
untracked = ! git status --porcelain 2>/dev/null | grep -q "^??"
          # git unclean && echo "There are uncommited changes!"
  unclean = ! ! git diff --quiet --ignore-submodules HEAD > /dev/null 2>&1
          # git dirty && echo "There are uncommitted changes OR untracked files!"
    dirty = ! git untracked || git unclean

0

การทดสอบอัตโนมัติที่ง่ายที่สุดที่ฉันใช้ในการตรวจจับสถานะสกปรก = การเปลี่ยนแปลงใด ๆ รวมถึงไฟล์ที่ไม่ได้ติดตาม :

git add --all
git diff-index --exit-code HEAD

บันทึก:

  • ไม่มี add --all diff-indexไม่ไม่สังเกตเห็นไฟล์ที่ไม่ได้ติดตาม
  • โดยปกติฉันเรียกใช้git resetหลังจากทดสอบรหัสข้อผิดพลาด

คำถามคือโดยเฉพาะ "จากสคริปต์" ... ไม่ใช่ความคิดที่ดีที่จะเปลี่ยนดัชนีเพื่อทดสอบสถานะสกปรก
ScottJ

@ScottJ เมื่อแก้ไขปัญหาไม่ได้ว่าทุกคนจะต้องเข้มงวดกับดัชนีที่สามารถแก้ไขได้หรือไม่ พิจารณากรณีของงานอัตโนมัติซึ่งเป็นเรื่องเกี่ยวกับแหล่งที่มาของโปรแกรมแก้ไขอัตโนมัติพร้อมหมายเลขรุ่นและสร้างแท็ก - สิ่งที่คุณต้องแน่ใจก็คือไม่มีการดัดแปลงใด ๆ ในตัวเครื่องเลย (ไม่ว่าจะอยู่ในดัชนีหรือไม่ก็ตาม) เพื่อให้ห่างไกลนี้คือการทดสอบที่เชื่อถือได้สำหรับการเปลี่ยนแปลงใด ๆ รวมถึงไฟล์ที่ไม่ได้ติดตาม
uvsmtid

-3

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

function git_dirty {
    text=$(git status)
    changed_text="Changes to be committed"
    untracked_files="Untracked files"

    dirty=false

    if [[ ${text} = *"$changed_text"* ]];then
        dirty=true
    fi

    if [[ ${text} = *"$untracked_files"* ]];then
        dirty=true
    fi

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