กฎการยกเว้น. gitignore ทำงานอย่างไร


146

ฉันพยายามที่จะแก้ปัญหา gitignore ในโครงสร้างไดเรกทอรีขนาดใหญ่ แต่เพื่อลดความซับซ้อนของคำถามของฉันฉันได้ลดลงดังต่อไปนี้

ฉันมีโครงสร้างไดเรกทอรีต่อไปนี้ของสองไฟล์ (foo, bar) ในแหล่งเก็บข้อมูล git ใหม่ล่าสุด (ยังไม่ได้ทำคอมมิชชัน):

a/b/c/foo
a/b/c/bar

เห็นได้ชัดว่า 'สถานะ git -u' แสดง:

# Untracked files:
...
#       a/b/c/bar
#       a/b/c/foo

สิ่งที่ฉันต้องการจะทำคือสร้างไฟล์. gignignore ที่ไม่สนใจทุกสิ่งภายใน a / b / c แต่ไม่สนใจไฟล์ 'foo'

ถ้าฉันสร้าง. gitignore ดังนั้น:

c/

จากนั้น 'สถานะ git -u' แสดงทั้ง foo และ bar ว่าถูกละเว้น:

# Untracked files:
...
#       .gitignore

ซึ่งเป็นสิ่งที่ฉันคาดหวัง

ตอนนี้ถ้าฉันเพิ่มกฎการยกเว้นสำหรับ foo ดังนั้น:

c/
!foo

ตาม manpage ของ gitignore ฉันคาดหวังว่าสิ่งนี้จะได้ผล แต่มันไม่ใช่ - มันยังไม่สนใจ foo:

# Untracked files:
...
#       .gitignore

สิ่งนี้ไม่ทำงาน:

c/
!a/b/c/foo

ไม่ทำสิ่งนี้:

c/*
!foo

ให้:

# Untracked files:
...
#       .gitignore
#       a/b/c/bar
#       a/b/c/foo

ในกรณีนี้ถึงแม้ว่า foo จะไม่ถูกเพิกเฉยอีกต่อไป แต่ bar ก็ไม่ได้ถูกละเว้น

ลำดับของกฎใน. gitignore ดูเหมือนจะไม่สำคัญเช่นกัน

สิ่งนี้ไม่ได้ทำตามที่ฉันคาดไว้:

a/b/c/
!a/b/c/foo

คนนั้นไม่สนใจทั้ง foo และ bar

สถานการณ์หนึ่งที่ทำงานได้คือถ้าฉันสร้างไฟล์ a / b / c / .gitignore และใส่เข้าไปในนั้น:

*
!foo

แต่ปัญหาของเรื่องนี้คือในที่สุดจะมีไดเรกทอรีย่อยอื่น ๆ ภายใต้ a / b / c และฉันไม่ต้องการที่จะใส่. gitignore แยกต่างหากลงในทุก ๆ อัน - ฉันหวังว่าจะสร้าง 'project-based' .itignore ไฟล์ที่สามารถนั่งในไดเรกทอรีบนสุดของแต่ละโครงการและครอบคลุมโครงสร้างย่อยทั้งหมดของ 'มาตรฐาน'

สิ่งนี้ดูเหมือนจะเทียบเท่า:

a/b/c/*
!a/b/c/foo

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

อย่างไรก็ตามฉันอาจไม่เข้าใจว่ากฎการยกเว้นทำงานอย่างไรหรือพวกเขาไม่ทำงานเลยเมื่อไดเรกทอรี (แทนที่จะใช้สัญลักษณ์แทน) จะถูกเพิกเฉยโดยกฎที่ลงท้ายด้วย a /

ใครช่วยได้โปรดส่องแสงนี้หน่อยได้ไหม?

มีวิธีที่จะทำให้ gitignore ใช้สิ่งที่มีเหตุผลเช่นนิพจน์ปกติแทนที่จะใช้ไวยากรณ์เชลล์ที่เงอะงะนี้หรือไม่?

ฉันใช้และสังเกตด้วย git-1.6.6.1 บน Cygwin / bash3 และ git-1.7.1 บน Ubuntu / bash3


คำถามที่เกี่ยวข้อง: stackoverflow.com/questions/2820255/…
Cascabel

4
คำถามที่เขียนอย่างดีเลิศ! จำนวนคดีที่คุณพยายามช่วยจริงๆให้ฉันเข้าใจในสิ่งที่ฉันทำผิดในกรณีที่คล้ายกันของฉัน ขอบคุณพระเจ้าที่ฉันมองหามาเป็นเวลานานในวันนี้
Alex G

คำตอบ:


153
/ a / B / C / *
! foo

ดูเหมือนว่าจะทำงานให้ฉัน (git 1.7.0.4 บน Linux) *เป็นสิ่งที่สำคัญเป็นอย่างอื่นคุณไม่สนใจไดเรกทอรีของตัวเอง (เพื่อให้คอมไพล์จะไม่ได้ดูภายใน) แทนไฟล์ภายในไดเรกทอรี (ซึ่งจะช่วยให้การยกเว้น)

คิดว่าการแยกออกเป็นการพูดว่า "แต่ไม่ใช่อันนี้" แทนที่จะเป็น "แต่รวมถึงสิ่งนี้" - "ไม่สนใจไดเรกทอรีนี้ ( /a/b/c/) แต่ไม่ใช่อันนี้ ( foo)" ไม่สมเหตุสมผลนัก "ละเว้นไฟล์ทั้งหมดในไดเรกทอรีนี้ ( /a/b/c/*) แต่ไม่ใช่ไฟล์นี้ ( foo)" ในการอ้างถึงหน้าคน:

คำนำหน้าเป็นตัวเลือก! ซึ่งขัดแย้งกับรูปแบบ; ไฟล์ที่ตรงกันใด ๆ ที่ยกเว้นโดยรูปแบบก่อนหน้านี้จะถูกรวมอีกครั้ง

กล่าวคือไฟล์ที่ได้จะได้รับการยกเว้นแล้วจะรวมอีกครั้ง หวังว่าแสงจะหายไป


ใช่ตัวอย่างที่คุณให้ก็ใช้ได้ดีสำหรับฉันเช่นกัน ปัญหาคือ / a / b / * ไม่ทำงานหาก foo อยู่ใน c ซึ่งหมายความว่าถ้าฉันมีไฟล์ foo หลายไฟล์ในไดเรกทอรีย่อยต่างๆภายใต้ c (เช่น d /, e /, f / g / h /, / i / j / ฯลฯ ) จากนั้นกฎปฏิเสธ '! foo' จะไม่จับสิ่งเหล่านั้น
davidA

1
@ meowsqueak แน่นอนมันจะไม่ หากคุณเพิกเฉย / a / b / * แล้วไม่มีไดเรกทอรีสำหรับ foo ที่จะอยู่ใน! หากคุณพยายามที่จะเพิกเฉยไดเรกทอรีไดเรกทอรีทั้งหมดภายใต้ / a / b แต่รวมไฟล์ใด ๆ ที่ชื่อว่า "foo" ซึ่งสามารถอยู่ที่ใดก็ได้ในต้นไม้ฉันไม่คิดว่ามันจะใช้รูปแบบ. gitignore: \
Chris

จริงๆแล้วนี่อาจอธิบายได้ว่าทำไมมันถึงไม่เหมาะกับฉัน - กฎต่อไปนี้ใช้ไม่ได้: "/ a / b / *", "! c / foo" หากใช้งานได้แสดงว่าอาจไม่มีปัญหา
davidA

5
"ฉันไม่คิดว่ามันจะเป็นไปได้ด้วยรูปแบบ. gignignore" - ฉันคิดว่าคุณพูดถูก
davidA

@meowsqueak คุณอาจจะไม่สนใจ/a/b/cแล้วเขียนเบ็ดไปยังgit add --forceไฟล์ใด ๆ ที่ตรงกันก่อนกระทำการหรือสิ่งที่
คริส

24

ฉันมีสถานการณ์ที่คล้ายกันทางออกของฉันคือการใช้:

/a/**/*
!/a/**/foo

สิ่งนี้ควรใช้ได้กับไดเรกทอรีระดับกลางโดยพลการหากฉันอ่าน**อย่างถูกต้อง


6

นี่ไม่ชัดเจนจากหน้า man. gitignore งานนี้:

*
!/a
!/a/b
!/a/b/c
!/a/b/c/foo

# don't forget this one
!.gitignore

ดังที่ Chris บอกไว้ไดเรกทอรีจะไม่ถูกเปิดแม้จะถูกแยกออก ดังนั้นหากคุณต้องการที่จะเพิกเฉย * แต่ไฟล์บางไฟล์คุณต้องสร้างเส้นทางไปยังไฟล์เหล่านั้นดังกล่าวข้างต้น สำหรับฉันสิ่งนี้สะดวกเพราะฉันต้องการทำการตรวจสอบโค้ดบนไฟล์ 1 ไฟล์ของไลบรารีและถ้าฉันต้องการที่จะทำอย่างอื่นในภายหลังฉันเพิ่งเพิ่มและจะไม่สนใจสิ่งใด


6

นี่คือตัวเลือกอื่น:

*
!/a*
!/a/*
!/a/*/*
!/a/*/*/*

ที่จะละเว้นทุกไฟล์และไดเรกทอรียกเว้นไฟล์ / ไดเรกทอรีสามระดับลึกภายใน


5

ในบันทึกทั่วไปที่มากขึ้นgit1.8.2จะรวมโปรแกรมปะแก้ (เช่นเดียวกับใน v4ซึ่งได้รับการแจ้งเตือนจากคำถาม Stack Overflow ) จากAdam Spiresเกี่ยวกับการพิจารณาว่าgitignoreกฎใดละเว้นไฟล์ของคุณ

ดูบันทึกประจำรุ่น git1.8.2และคำถามที่ว่า " กฎ gitignore ละเลยไฟล์ของฉัน " ที่จะเป็นคำสั่ง
git check-ignore


1
ขอบคุณสำหรับการเผยแพร่ข้อมูลนี้ check-ignoreนอกจากนี้ยังจะบอกคุณที่กฎการป้องกันไฟล์ของคุณจากการถูกละเว้นถ้าเป็นกรณีที่
Adam Spires

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