Linus Torvalds หมายถึงอะไรเมื่อเขาบอกว่า Git“ ไม่เคยมี” ติดตามไฟล์?


283

การอ้างถึง Linus Torvalds เมื่อถูกถามว่ามีกี่ไฟล์ Git ที่สามารถจัดการได้ระหว่างTech Talkของเขาที่ Google ในปี 2007 (43:09 น.):

… Git ติดตามเนื้อหาของคุณ มันไม่เคยติดตามไฟล์เดียว คุณไม่สามารถติดตามไฟล์ใน Git สิ่งที่คุณทำได้คือคุณสามารถติดตามโครงการที่มีไฟล์เดียว แต่ถ้าโครงการของคุณมีไฟล์เดียวให้ทำและคุณสามารถทำได้ แต่ถ้าคุณติดตาม 10,000 ไฟล์ Git ไม่เคยเห็นไฟล์เหล่านั้นเป็นไฟล์เดี่ยวเลย Git คิดว่าทุกสิ่งเป็นเนื้อหาที่สมบูรณ์ ประวัติทั้งหมดใน Git ขึ้นอยู่กับประวัติของโครงการทั้งหมด ...

(การถอดเสียงที่นี่ )

แต่เมื่อคุณดำดิ่งลงในหนังสือ Gitสิ่งแรกที่คุณได้รับการบอกกล่าวก็คือไฟล์ใน Git นั้นสามารถติดตามหรือไม่ได้ติดตามได้ ยิ่งไปกว่านั้นฉันรู้สึกว่าประสบการณ์ Git ทั้งหมดนั้นมุ่งไปที่การกำหนดเวอร์ชันไฟล์ เมื่อใช้git diffหรือแสดงgit statusผลจะแสดงตามแต่ละไฟล์ เมื่อใช้งานgit addคุณจะได้รับการเลือกแบบต่อไฟล์ คุณสามารถตรวจสอบประวัติบนพื้นฐานของไฟล์และรวดเร็ว

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


20
reddit.com/r/git/comments/5xmrkv/what_is_a_snapshot_in_git - "สำหรับคุณจะอยู่ที่ไหนในขณะที่ฉันสงสัยว่าสิ่งที่สำคัญมากขึ้นในการตระหนักคือว่ามีความแตกต่างระหว่างวิธี Git ไฟล์นำเสนอให้กับผู้ใช้และวิธีการที่มันเกี่ยวข้องกับพวกเขาภายในสแน็ปช็อตมีไฟล์สมบูรณ์ไม่เพียง แต่แตกต่าง แต่ภายในใช่แล้ว Git ใช้ diffs เพื่อสร้างไฟล์แพ็คที่เก็บการแก้ไขอย่างมีประสิทธิภาพ " (นี่คือความคมชัดที่คมชัดเช่นการโค่นล้ม)
2864740

5
Git ไม่ได้ติดตามไฟล์ แต่ติดตามการเปลี่ยนแปลง ระบบควบคุมเวอร์ชันส่วนใหญ่จะติดตามไฟล์ต่างๆ เป็นตัวอย่างของสิ่งที่อาจเกิดขึ้นได้อย่างไรลองตรวจสอบในไดเรกทอรีว่างเปล่าเพื่อ git (spolier: คุณทำไม่ได้เพราะเป็นเซ็ตการแก้ไขที่ "ว่างเปล่า")
Elliott Frisch

12
@ElliottFrisch นั่นฟังดูไม่ถูก คำอธิบายของคุณใกล้เคียงกับสิ่งที่ตัวอย่างเช่นDarcsทำ Git เก็บภาพรวมไม่ใช่เซ็ตการแก้ไข
melpomene

4
ฉันคิดว่าเขาหมายถึง Git ไม่ได้ติดตามไฟล์โดยตรง ไฟล์มีชื่อและเนื้อหา Git ติดตามเนื้อหาเป็น blobs เมื่อกำหนดเป็นหยดเดียวคุณจะไม่สามารถบอกได้ว่าชื่อไฟล์นั้นตรงกันคืออะไร อาจเป็นเนื้อหาของไฟล์หลายไฟล์ที่มีชื่อแตกต่างกันภายใต้เส้นทางที่แตกต่างกัน การเชื่อมโยงระหว่างชื่อพา ธ และ blob ถูกอธิบายในวัตถุต้นไม้
ElpieKay

3
ที่เกี่ยวข้อง: การติดตามของ Randal Schwartz ในการพูดคุยของ Linus (เช่นการพูดคุยของ Google Tech) - "... สิ่งที่ Git เกี่ยวข้องกับ ... Linus กล่าวว่า Git ไม่ใช่สิ่ง"
Peter Mortensen

คำตอบ:


316

ใน CVS ประวัติถูกติดตามแบบต่อไฟล์ สาขาอาจประกอบด้วยไฟล์ต่าง ๆ ที่มีการแก้ไขที่แตกต่างกันของพวกเขาแต่ละคนมีหมายเลขรุ่นของตัวเอง CVS ใช้ RCS ( Revision Control System ) ซึ่งติดตามแต่ละไฟล์ด้วยวิธีเดียวกัน

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

เมื่อ Git อ้างถึงการติดตามไฟล์มันหมายถึงว่ามันจะรวมอยู่ในประวัติของโครงการ การพูดคุยของ Linus ไม่ได้อ้างถึงการติดตามไฟล์ในบริบท Git แต่เป็นการเปรียบเทียบโมเดล CVS และ RCS กับแบบจำลอง snapshot-based ที่ใช้ใน Git


4
คุณสามารถเพิ่มได้ว่านี่เป็นสาเหตุใน CVS และการโค่นล้มคุณสามารถใช้แท็กเหมือน$Id$ในไฟล์ เช่นเดียวกันไม่สามารถใช้งานในคอมไพล์ได้เนื่องจากการออกแบบนั้นแตกต่างกัน
gerrit

58
และเนื้อหาไม่ถูกผูกไว้กับไฟล์อย่างที่คุณคาดหวัง ลองย้ายรหัส 80% ของไฟล์หนึ่งไปยังอีกไฟล์ Git จะตรวจจับการย้ายไฟล์โดยอัตโนมัติ + 20% การเปลี่ยนแปลงแม้เมื่อคุณเพิ่งย้ายรหัสไปรอบ ๆ ในไฟล์ที่มีอยู่
อัลโล

13
@allo ในฐานะที่เป็นผลข้างเคียงของสิ่งนั้น git สามารถทำสิ่งหนึ่งที่คนอื่นไม่สามารถทำได้: เมื่อมีการรวมสองไฟล์และคุณใช้ "git blame -C" git สามารถดูประวัติทั้งคู่ได้ ในการติดตามแบบไฟล์คุณต้องเลือกไฟล์ต้นฉบับที่เป็นต้นฉบับจริงและบรรทัดอื่น ๆ ทั้งหมดจะปรากฏขึ้นใหม่
Izkata

1
@allo, Izkata - และมันเป็นเอนทิตีการสืบค้นที่ทำงานทั้งหมดนี้โดยการวิเคราะห์เนื้อหา repo ณ เวลาที่สืบค้น (คอมมิชชันประวัติและความแตกต่างระหว่างต้นไม้อ้างอิงและ blobs) แทนที่จะกำหนดเอนทิตีและผู้ใช้มนุษย์เพื่อระบุหรือสังเคราะห์อย่างถูกต้อง ข้อมูลนี้ในเวลาที่กำหนด - หรือผู้พัฒนาเครื่องมือซื้อคืนเพื่อออกแบบและใช้ความสามารถนี้และสคีมาเมทาดาทาที่สอดคล้องกันก่อนที่เครื่องมือจะถูกนำไปใช้งาน Torvalds ถกเถียงกันอยู่ว่าการวิเคราะห์ดังกล่าวจะได้ดีขึ้นในช่วงเวลาและทุกประวัติศาสตร์ของทุก repo คอมไพล์ตั้งแต่วันหนึ่งจะได้รับประโยชน์
Jeremy

1
@allo Yep และเพื่อตอกย้ำความจริงที่ว่าคอมไพล์ไม่ทำงานในระดับไฟล์คุณไม่จำเป็นต้องยอมรับการเปลี่ยนแปลงทั้งหมดในไฟล์ในครั้งเดียว คุณสามารถกระทำช่วงของเส้นโดยพลการในขณะที่ออกจากการเปลี่ยนแปลงอื่น ๆ ในไฟล์นอกกระทำ แน่นอนว่า UI สำหรับสิ่งนั้นไม่ได้เรียบง่ายนักดังนั้นส่วนใหญ่ไม่ได้ทำ แต่มันไม่ค่อยมีการใช้งาน
อัลวิน ธ อมป์สัน

103

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

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

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

โปรดทราบว่า VCS สามารถมุ่งเน้นที่มุ่งมั่น แต่ยังคงจัดเก็บข้อมูลไฟล์โดยไฟล์ นั่นเป็นรายละเอียดการปฏิบัติแม้ว่าบางครั้งก็เป็นสิ่งสำคัญและ Git ก็ไม่ได้ทำเช่นนั้น แต่แต่ละกระทำระเบียนต้นไม้กับไฟล์ต้นไม้เข้ารหัสวัตถุชื่อ , โหมด (กล่าวคือเป็นปฏิบัติการไฟล์นี้หรือไม่?) และชี้ไปยังเนื้อหาของแฟ้มที่เกิดขึ้นจริง เนื้อหาของตัวเองจะถูกเก็บไว้เป็นอิสระในวัตถุหยด เช่นเดียวกับออบเจกต์กระทำบล็อบได้รับรหัสแฮชที่ไม่ซ้ำกับเนื้อหาของมัน - แต่ต่างจากการคอมมิทซึ่งสามารถปรากฏได้เพียงครั้งเดียว ดังนั้นเนื้อหาไฟล์พื้นฐานใน Git จะถูกจัดเก็บโดยตรงเป็นหยดแล้วทางอ้อม ในวัตถุต้นไม้ที่มีการบันทึกรหัสแฮช (โดยตรงหรือโดยอ้อม) ในวัตถุที่กระทำ

เมื่อคุณขอให้ Git แสดงประวัติของแฟ้มโดยใช้:

git log [--follow] [starting-point] [--] path/to/file

สิ่ง Git เป็นจริงทำคือเดินกระทำประวัติศาสตร์ซึ่งเป็นประวัติศาสตร์เพียง Git มี แต่ไม่แสดงให้คุณกระทำใด ๆ ของเหล่านี้เว้นแต่

  • การกระทำไม่ใช่การรวมการกระทำและ
  • พาเรนต์ของการส่งนั้นมีไฟล์อยู่ด้วย แต่เนื้อหาในพาเรนต์นั้นแตกต่างกันหรือพาเรนต์ของการส่งไม่มีไฟล์เลย

(แต่เงื่อนไขเหล่านี้บางอย่างสามารถแก้ไขได้ผ่านทางgit logตัวเลือกเพิ่มเติมและมีผลข้างเคียงที่ยากมากที่เรียกว่าการทำให้เข้าใจง่ายของประวัติศาสตร์ซึ่งทำให้ Git ละเว้นการกระทำบางอย่างจากการเดินประวัติโดยสิ้นเชิง) ประวัติไฟล์ที่คุณเห็นที่นี่ไม่ได้มีอยู่จริงในที่เก็บในบางแง่: แทนมันเป็นเพียงส่วนย่อยสังเคราะห์ของประวัติศาสตร์จริง คุณจะได้รับ "ประวัติไฟล์" ที่แตกต่างกันหากคุณใช้git logตัวเลือกที่ต่างกัน


สิ่งที่ต้องเพิ่มอีกอย่างหนึ่งคือการทำเช่นนี้ Git สามารถทำสิ่งต่าง ๆ เช่นโคลนตื้น ๆ มันแค่ต้องดึงหัวคอมมิชชันและ blobs ที่มันอ้างถึง ไม่จำเป็นต้องสร้างไฟล์ใหม่โดยใช้ชุดการเปลี่ยนแปลง
Wes Toleman

@WesToleman: แน่นอนทำให้ง่ายขึ้น Mercurial stores deltas โดยมีการรีเซ็ตเป็นครั้งคราวและในขณะที่ Mercurial folks ตั้งใจที่จะเพิ่มโคลนตื้น ๆ ที่นั่น (ซึ่งเป็นไปได้เนื่องจากแนวคิด "รีเซ็ต") พวกเขายังไม่ได้ทำจริง ๆ
torek

@torek ฉันมีข้อสงสัยเกี่ยวกับคำอธิบายของคุณเกี่ยวกับ Git ในการตอบคำขอประวัติไฟล์ แต่ฉันคิดว่ามันสมควรได้รับคำถามที่เหมาะสมของตัวเอง: stackoverflow.com/questions/55616349/…
Amaya

@torek ขอบคุณสำหรับลิงก์ไปยังหนังสือของคุณฉันไม่เคยเห็นอะไรแบบนี้มาก่อน
gnarledRoot

17

บิตที่สับสนอยู่ที่นี่:

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

Git มักจะใช้แฮช 160 บิตแทนวัตถุใน repo ของตัวเอง แผนผังไฟล์เป็นรายการชื่อและแฮชที่สัมพันธ์กับเนื้อหาของแต่ละรายการ (รวมถึงข้อมูลเมตาบางส่วน)

แต่แฮชขนาด 160 บิตจะระบุเนื้อหาโดยเฉพาะ (ภายในจักรวาลของฐานข้อมูล git) ดังนั้นต้นไม้ที่มีแฮชในขณะที่เนื้อหาจะมีเนื้อหาอยู่ในสถานะ

หากคุณเปลี่ยนสถานะของเนื้อหาของไฟล์แฮชจะเปลี่ยนไป แต่ถ้าแฮชของมันเปลี่ยนไปแฮชที่เชื่อมโยงกับเนื้อหาของชื่อไฟล์ก็จะเปลี่ยนไปเช่นกัน ซึ่งจะเปลี่ยนการแฮชของ "ไดเรกทอรีต้นไม้"

เมื่อร้านค้าฐานข้อมูลคอมไพล์ต้นไม้ไดเรกทอรีที่ต้นไม้ไดเรกทอรีนัยและรวมทั้งหมดของเนื้อหาทั้งหมดของไดเรกทอรีและไฟล์ทั้งหมดที่อยู่ในนั้น

มันถูกจัดระเบียบในโครงสร้างต้นไม้ที่มีตัวชี้ (ไม่เปลี่ยนรูปได้, นำกลับมาใช้ใหม่ได้) ไปที่ blobs หรือต้นไม้อื่น ๆ แต่เหตุผลมันเป็นภาพรวมเดียวของเนื้อหาทั้งหมดของต้นไม้ทั้งหมด การแสดงในฐานข้อมูล git ไม่ใช่เนื้อหาข้อมูลแบบเรียบ แต่มีเหตุผลคือเป็นข้อมูลทั้งหมดและไม่มีอะไรอื่น

หากคุณทำให้ต้นไม้เป็นอนุกรมกับระบบไฟล์ลบโฟลเดอร์. git ทั้งหมดและบอกให้ git เพิ่ม tree กลับเข้าไปในฐานข้อมูลของมันคุณจะไม่ต้องเพิ่มอะไรลงในฐานข้อมูล - องค์ประกอบจะมีอยู่แล้ว

มันอาจช่วยให้คิดถึงแฮชของคอมไพล์เป็นตัวชี้นับที่อ้างอิงกับข้อมูลที่ไม่เปลี่ยน

หากคุณสร้างแอปพลิเคชันรอบ ๆ เอกสารจะเป็นกลุ่มของเพจซึ่งมีเลเยอร์ซึ่งมีกลุ่มที่มีวัตถุ

เมื่อคุณต้องการเปลี่ยนวัตถุคุณต้องสร้างกลุ่มใหม่ทั้งหมดสำหรับมัน หากคุณต้องการเปลี่ยนกลุ่มคุณต้องสร้างเลเยอร์ใหม่ซึ่งต้องการหน้าใหม่ซึ่งต้องการเอกสารใหม่

ทุกครั้งที่คุณเปลี่ยนวัตถุเดียวมันจะวางไข่เอกสารใหม่ เอกสารเก่ายังคงมีอยู่ เอกสารใหม่และเก่าแบ่งปันเนื้อหาส่วนใหญ่ของพวกเขา - พวกเขามีหน้าเดียวกัน (ยกเว้น 1) หน้านั้นมีเลเยอร์เดียวกัน (ยกเว้น 1) เลเยอร์นั้นมีกลุ่มเดียวกัน (ยกเว้น 1) กลุ่มนั้นมีวัตถุเดียวกัน (ยกเว้น 1)

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

repo คอมไพล์เป็นจำนวนมากเช่นนั้น

ซึ่งหมายความว่าเซ็ตการแก้ไข git ที่กำหนดนั้นมีข้อความการคอมมิท (เป็นรหัสแฮช) มันมีแผนผังการทำงานและมีการเปลี่ยนแปลงพาเรนต์

การเปลี่ยนแปลงพาเรนต์เหล่านั้นจะมีการเปลี่ยนแปลงพาเรนต์ไปตลอดทาง

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

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

บางครั้งไฟล์ก็หายไป; แต่ทรี "ไดเรกทอรี" อาจมีไฟล์อื่นที่มีเนื้อหาเหมือนกัน (รหัสแฮชเดียวกัน) ดังนั้นเราจึงสามารถติดตามได้ในลักษณะนั้น (หมายเหตุนี่คือสาเหตุที่คุณต้องการให้คอมมิทบังคับย้ายไฟล์แยกจากคอมมิท -Edit) หรือชื่อไฟล์เดียวกันและหลังจากตรวจสอบไฟล์แล้วก็มีความคล้ายคลึงกันพอสมควร

ดังนั้นคอมไพล์สามารถปะติดปะต่อ "ประวัติไฟล์" เข้าด้วยกันได้

แต่ประวัติไฟล์นี้มาจากการแยกวิเคราะห์ "ชุดการเปลี่ยนแปลงทั้งหมด" ที่มีประสิทธิภาพไม่ใช่จากลิงก์จากไฟล์หนึ่งไปยังอีกเวอร์ชั่นหนึ่ง


12

"คอมไพล์ไม่ได้ติดตามไฟล์" โดยทั่วไปหมายถึงว่ากระทำคอมไพล์ประกอบด้วยภาพต้นไม้แฟ้มการเชื่อมต่อเส้นทางในต้นไม้ให้เป็น "หยด" และกระทำกราฟติดตามประวัติศาสตร์ของกระทำ ทุกอย่างถูกสร้างขึ้นใหม่ในทันทีโดยคำสั่งเช่น "บันทึก git" และ "git blame" การสร้างใหม่นี้สามารถบอกได้ผ่านตัวเลือกต่าง ๆ ว่ามันยากที่จะมองหาการเปลี่ยนแปลงตามไฟล์ ฮิวริสติกเริ่มต้นสามารถกำหนดได้ว่าเมื่อใดที่การเปลี่ยนแปลงของ Blob ในทรีของไฟล์โดยไม่มีการเปลี่ยนแปลงหรือเมื่อไฟล์นั้นสัมพันธ์กับ Blob ที่แตกต่างจากเดิม กลไกการบีบอัดที่ Git ใช้นั้นไม่ได้สนใจอะไรมากมายเกี่ยวกับขอบเขตของไฟล์ / ไฟล์ หากเนื้อหาอยู่ที่ใดที่หนึ่งแล้วสิ่งนี้จะทำให้พื้นที่เก็บข้อมูลเติบโตน้อยโดยไม่ต้องเชื่อมโยง blobs ต่างๆ

ตอนนี้ที่เก็บคือ Git ยังมีแผนผังการทำงานและในแผนผังการทำงานนี้จะมีการติดตามและไม่ได้ติดตามไฟล์ ไฟล์ที่ถูกติดตามเท่านั้นที่จะถูกบันทึกในดัชนี (พื้นที่การจัดเตรียมแคช?) และเฉพาะไฟล์ที่ถูกติดตามเท่านั้นที่ทำให้อยู่ในที่เก็บ

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

เนื่องจาก Git ไม่ได้ติดตามประวัติและการเปลี่ยนชื่อไฟล์และประสิทธิภาพของมันไม่ได้ขึ้นอยู่กับพวกเขาบางครั้งคุณต้องลองสองสามครั้งด้วยตัวเลือกที่แตกต่างกันจนกว่า Git จะสร้างประวัติ / diffs / blames ที่คุณสนใจสำหรับประวัติศาสตร์ที่ไม่สำคัญ

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

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


7

Git ไม่ได้ติดตามไฟล์โดยตรง แต่ติดตามสแนปชอตของที่เก็บและสแน็ปช็อตเหล่านี้จะประกอบด้วยไฟล์

นี่คือวิธีดูมัน

ในระบบการควบคุมรุ่นอื่น ๆ (SVN, เหตุผล ClearCase) คุณสามารถคลิกขวาที่ไฟล์และได้รับประวัติการเปลี่ยนแปลงของมัน

ใน Git ไม่มีคำสั่งโดยตรงที่ทำเช่นนี้ ดูคำถามนี้ คุณจะประหลาดใจกับจำนวนคำตอบที่ต่างกัน ไม่มีคำตอบง่ายๆเพราะGit ไม่เพียงแค่ติดตามไฟล์ไม่ใช่ในแบบที่ SVN หรือ ClearCase ทำ


5
ฉันคิดว่าฉันได้สิ่งที่คุณพยายามจะพูด แต่ "ใน Git ไม่มีคำสั่งโดยตรงที่ทำสิ่งนี้" ขัดแย้งโดยตรงกับคำตอบของคำถามที่คุณเชื่อมโยง แม้ว่าการกำหนดเวอร์ชันจะเกิดขึ้นที่ระดับของพื้นที่เก็บข้อมูลทั้งหมด แต่โดยทั่วไปมีวิธีมากมายในการทำสิ่งต่างๆใน Git ดังนั้นการมีคำสั่งหลายคำสั่งเพื่อแสดงประวัติของไฟล์จึงไม่ใช่หลักฐานมากนัก
Joe Lee-Moyet

ฉันอ่านคำตอบแรก ๆ ของคำถามที่คุณเชื่อมโยงและพวกเขาทั้งหมดใช้git logหรือโปรแกรมบางส่วนที่สร้างขึ้นจากนั้น (หรือนามแฝงบางอย่างที่ทำสิ่งเดียวกัน) แต่แม้ว่าจะมีหลายวิธีที่แตกต่างกันตามที่โจบอกว่ามันเป็นความจริงสำหรับการแสดงประวัติสาขา (ก็git log -p <file>ถูกสร้างขึ้นในและทำสิ่งนั้นอย่างแน่นอน)
Voo

คุณแน่ใจหรือว่า SVN เก็บการเปลี่ยนแปลงต่อไฟล์ไว้ภายใน ฉันไม่ได้ใช้งานมาก่อนแล้ว แต่ฉันจำได้ว่ามีไฟล์ชื่อเช่นรหัสเวอร์ชันแทนที่จะสะท้อนโครงสร้างของไฟล์โครงการ
Artur Biesiadowski

3

การติดตาม "เนื้อหา" โดยบังเอิญคือสิ่งที่นำไปสู่การไม่ติดตามไดเรกทอรีว่างเปล่า
นั่นคือเหตุผลที่ถ้าคุณ GIT rm ไฟล์ล่าสุดของโฟลเดอร์โฟลเดอร์ที่ตัวเองได้รับการลบ

ไม่ได้เป็นเช่นนั้นเสมอไปและมีเพียง Git 1.4 (พฤษภาคม 2549) ที่บังคับใช้นโยบาย "ติดตามเนื้อหา" ด้วยความมุ่งมั่น 443f833 :

สถานะ git: ข้ามไดเรกทอรีที่ว่างเปล่าและเพิ่ม -u เพื่อแสดงไฟล์ที่ไม่ได้ติดตามทั้งหมด

ตามค่าเริ่มต้นเราใช้--others --directoryเพื่อแสดงไดเรกทอรีที่ไม่น่าสนใจ (เพื่อรับความสนใจของผู้ใช้) โดยไม่มีเนื้อหา (เพื่อคลายเอาต์พุต)
แสดงไดเรกทอรีว่างเปล่าไม่สมเหตุสมผลดังนั้นผ่าน--no-empty-directoryเมื่อเราทำเช่นนั้น

การให้-u(หรือ--untracked) ปิดใช้งานการกระจายนี้เพื่อให้ผู้ใช้ได้รับไฟล์ที่ไม่ได้ติดตามทั้งหมด

นั่นเป็นเสียงสะท้อนหลายปีต่อมาในเดือนมกราคม 2011 ด้วยความมุ่งมั่น 8fe533 , Git v1.7.4:

สิ่งนี้สอดคล้องกับปรัชญา UI ทั่วไป: git ติดตามเนื้อหาไม่ใช่ไดเรกทอรีว่างเปล่า

ในระหว่างนี้ด้วย Git 1.4.3 (ก.ย. 2006) Git เริ่ม จำกัด เนื้อหาที่ไม่ได้ติดตามไปยังโฟลเดอร์ที่ไม่ว่างโดยมีคอมมิต 2074cb0 :

ไม่ควรแสดงรายการเนื้อหาของไดเรกทอรีที่ไม่ได้ติดตามอย่างสมบูรณ์ แต่มีเพียงชื่อของไดเรกทอรีนั้น (รวมถึงส่วนท้าย ' /')

เนื้อหาการติดตามคือสิ่งที่อนุญาตให้คอมไพล์ตำหนิได้ตั้งแต่วันที่ (Git 1.4.4, ต.ค. 2549, ยอมรับ cee7f24 ) มีประสิทธิภาพมากกว่า:

ที่สำคัญกว่านั้นโครงสร้างภายในของมันถูกออกแบบมาเพื่อรองรับการเคลื่อนไหวของเนื้อหา (aka cut-and-paste) ได้ง่ายขึ้นโดยอนุญาตให้ใช้มากกว่าหนึ่งพา ธ จากการคอมมิทเดียวกัน

(เนื้อหาการติดตาม) ก็เป็นสิ่งที่เพิ่ม git ใน Git API ด้วย Git 1.5.0 (Dec. 2006, กระทำ 366bfcb )

ทำให้ 'git add' เป็นอินเทอร์เฟซผู้ใช้ที่เป็นมิตรกับดัชนี

สิ่งนี้จะนำพลังของดัชนีไปข้างหน้าโดยใช้แบบจำลองทางจิตที่เหมาะสมโดยไม่ต้องพูดถึงดัชนีเลย
ดูตัวอย่างว่าการอภิปรายทางเทคนิคทั้งหมดได้รับการอพยพจากหน้าคน git-add

เนื้อหาใด ๆ ที่จะมุ่งมั่นจะต้องเพิ่มเข้าด้วยกัน
เนื้อหานั้นมาจากไฟล์ใหม่หรือไฟล์ที่แก้ไขแล้วไม่สำคัญ
คุณเพียงแค่ต้อง "เพิ่ม" ไม่ว่าจะด้วย git-add หรือโดยการให้ git-commit กับ-a(สำหรับไฟล์ที่รู้จักแล้วเท่านั้น)

นั่นคือสิ่งที่ทำgit add --interactiveไปได้ด้วย Git เดียวกัน 1.5.0 ( กระทำ 5cde71d )

หลังจากทำการเลือกแล้วให้ตอบด้วยบรรทัดว่างเพื่อจัดวางเนื้อหาของไฟล์แผนผังการทำงานสำหรับพา ธ ที่เลือกในดัชนี

นั่นคือเหตุผลว่าทำไมในการลบเนื้อหาทั้งหมดออกจากไดเรกทอรีซ้ำคุณต้องผ่าน-rตัวเลือกไม่ใช่เฉพาะชื่อไดเรกทอรี<path>(ยังคง Git 1.5.0 ยอมรับ 9f95069 )

การดูเนื้อหาไฟล์แทนที่จะเป็นไฟล์นั้นเป็นสิ่งที่อนุญาตให้ผสานสถานการณ์เช่นเดียวกับที่อธิบายไว้ในคอมมิต 1de70db (Git v2.18.0-rc0, เม.ย. 2018)

พิจารณาการผสานต่อไปนี้ด้วยการเปลี่ยนชื่อ / เพิ่มความขัดแย้ง:

  • ด้าน A: แก้ไขfooเพิ่มที่ไม่เกี่ยวข้องbar
  • ด้าน B: เปลี่ยนชื่อfoo->bar(แต่อย่าแก้ไขโหมดหรือเนื้อหา)

ในกรณีนี้การผสานสามทางของ foo ดั้งเดิม, A's foo และ B's barจะทำให้ชื่อพา ธ ที่ต้องการของbarด้วยโหมด / เนื้อหาเดียวกันกับที่ A มีfooไว้
ดังนั้น A จึงมีโหมดและเนื้อหาที่ถูกต้องสำหรับไฟล์และมีชื่อพา ธ ที่ถูกต้อง (เช่น, bar)

กระทำ 37b65ce , Git v2.21.0-rc0, ธ.ค. 2018, เพิ่งปรับปรุงการแก้ไขข้อขัดแย้งที่ขัดแย้งกัน
และยอมรับ bbafc9c firther แสดงให้เห็นถึงความสำคัญของการพิจารณาเนื้อหาไฟล์โดยการปรับปรุงการจัดการสำหรับการเปลี่ยนชื่อ / เปลี่ยนชื่อ (2to1) ความขัดแย้ง:

  • แทนการจัดเก็บไฟล์ที่collide_path~HEADและไฟล์ที่มีสองทางรวมและบันทึกไว้ในcollide_path~MERGEcollide_path
  • แทนการบันทึกเวอร์ชันของไฟล์ที่ถูกเปลี่ยนชื่อที่มีอยู่ในด้านที่เปลี่ยนชื่อในดัชนี (ดังนั้นการเพิกเฉยต่อการเปลี่ยนแปลงใด ๆ ที่เกิดขึ้นกับไฟล์ที่ด้านข้างของประวัติโดยไม่มีการเปลี่ยนชื่อ) เราทำการผสานเนื้อหาสามทางบนการเปลี่ยนชื่อ เส้นทางจากนั้นเก็บสิ่งนั้นไว้ที่สเตจ 2 หรือสเตจ 3
  • โปรดทราบว่าเนื่องจากการรวมเนื้อหาสำหรับการเปลี่ยนชื่อแต่ละครั้งอาจมีข้อขัดแย้งและจากนั้นเราต้องรวมสองไฟล์ที่ถูกเปลี่ยนชื่อเราจึงสามารถจบด้วยตัวทำเครื่องหมายข้อขัดแย้งที่ซ้อนกัน
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.