ทำไมฉันถึงต้องการเวทีก่อนที่จะดำเนินการใน Git


105

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

สิ่งที่ฉันไม่เข้าใจคือการจัดฉากนั้นมาจากมุมมองที่ใช้งานได้จริง การจัดเตรียมสิ่งที่มีอยู่ในชื่อเท่านั้นหรือมีจุดประสงค์หรือไม่? เมื่อคุณกระทำมันก็จะกระทำทุกอย่างใช่ไหม?

แก้ไข: ฉันคิดว่าฉันอาจสับสนกับคำศัพท์ ไฟล์ 'staged' เหมือนกับไฟล์ 'tracked' หรือไม่?


6
ไม่ไฟล์ที่ติดตามเป็นไฟล์ที่รู้จักกันในที่เก็บ (โดยทั่วไปจะมาจากการกระทำก่อนหน้านี้) ไฟล์ที่จัดขั้นเป็นไฟล์ที่ถูกเพิ่มลงในดัชนีซึ่งจะถูกใช้ในการคอมมิต
Mark Peters

คำตอบ:


83

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

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


25
ใช้บ่อยจริงๆอื่น ๆ คือเมื่อบางส่วนของการเปลี่ยนแปลงของคุณควรจะไม่เคยเป็นความมุ่งมั่น; git reset --hardตัวอย่างเช่นคุณสามารถเวทีสิ่งที่ดีกระทำมันแล้วพัดไปสิ่งที่ไม่ดีด้วย
Cascabel

4
@BenJackson ในตัวอย่างของคุณอะไรคือความแตกต่างระหว่างสเตจ + คอมมิตและคอมมิตแบบเลือก? ฉันไม่เห็นความแตกต่างใด ๆ
Eugenio

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

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

1
@ kiwicomb123 โดยปกติแล้วเป็นเพราะคุณพบข้อผิดพลาดนั้นในขณะที่ทำงานอย่างอื่นและคุณต้องการแก้ไขข้อผิดพลาดนั้นด้วยข้อความบันทึกของตัวเองและความยืดหยุ่นในการผสาน / cherry-pick / rebase ที่แก้ไขที่อื่น
Ben Jackson

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

13

วัตถุประสงค์ในทางปฏิบัติประการหนึ่งของการจัดเตรียมคือการแยกไฟล์คอมมิตแบบลอจิคัล

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

สมมติว่าคุณมี 4 ไฟล์fileA.html, fileB.html, และfileC.html fileD.htmlคุณทำการเปลี่ยนแปลงกับไฟล์ทั้ง 4 ไฟล์และพร้อมที่จะคอมมิต แต่มีการเปลี่ยนแปลงfileA.htmlและfileB.htmlเกี่ยวข้องกันในเชิงตรรกะ (ตัวอย่างเช่นการนำฟีเจอร์ใหม่ที่เหมือนกันไปใช้ในทั้งสองไฟล์) ในขณะที่การเปลี่ยนแปลงในfileC.htmlและfileD.htmlแยกกันและไม่เกี่ยวข้องกับไฟล์ก่อนหน้าอย่างมีเหตุผล คุณสามารถไฟล์ขั้นตอนแรกfileA.htmlและfileB.htmlและการกระทำเหล่านั้น

git add fileA.html
git add fileB.html
git commit -m "Implemented new feature XYZ"

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

git add fileC.html
git add fileD.html
git commit -m "Implemented another feature EFG"

7
ในตัวอย่างนี้ฉันไม่แน่ใจว่าจำเป็นต้องมีการจัดเตรียมหรือไม่ หลังจากแก้ไขไฟล์ทั้ง 4 ไฟล์แล้วถ้าฉันแค่ต้องการคอมมิต fileA.html และ fileB.html ฉันยังสามารถคอมมิตได้โดยไม่ต้องจัดเตรียม คำสั่ง: git commit -m "Implemented new feature XYZ" fileA.html fileB.html จะทำงานได้ดีโดยไม่ต้องใช้คำสั่งเพิ่มคอมไพล์ ฉันมาจากโลกที่ถูกโค่นล้มโดยที่การแสดงละครไม่ใช่แนวคิดดังนั้นฉันไม่มั่นใจเกี่ยวกับความมีประโยชน์ของการจัดเตรียมคอมไพล์
Pavan

6

หากต้องการขยายคำตอบของ Ben Jacksonซึ่งเป็นเรื่องปกติเรามาดูคำถามเดิมอย่างใกล้ชิด (ดูคำตอบของเขาสำหรับคำถามประเภทที่น่ารำคาญนี่คือข้อมูลเพิ่มเติมเกี่ยวกับสิ่งที่เกิดขึ้น)

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

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

สิ่งที่ฉันไม่เข้าใจคือการจัดฉากนั้นมาจากมุมมองที่ใช้งานได้จริง การจัดเตรียมสิ่งที่มีอยู่ในชื่อเท่านั้นหรือมีจุดประสงค์หรือไม่? เมื่อคุณกระทำมันก็จะกระทำทุกอย่างใช่ไหม?

ใช่และไม่. การออกแบบของ Git ที่นี่ค่อนข้างแปลก มีระบบควบคุมเวอร์ชันที่ไม่ต้องการขั้นตอนการจัดเตรียมแยกต่างหาก ตัวอย่างเช่น Mercurial ซึ่งเหมือนกับ Git ในแง่ของการใช้งานไม่จำเป็นต้องมีhg addขั้นตอนแยกต่างหากนอกเหนือจากขั้นตอนแรกที่แนะนำไฟล์ใหม่ทั้งหมด ด้วย Mercurial คุณใช้hgคำสั่งที่เลือกการกระทำบางอย่างจากนั้นคุณก็ทำงานของคุณจากนั้นคุณก็รันhg commitและเสร็จสิ้น ด้วย Git คุณใช้git checkout, 1แล้วคุณจะทำผลงานของคุณแล้วคุณทำงานแล้วgit add git commitทำไมต้องเพิ่มgit addขั้นตอน?

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

แก้ไข: ฉันคิดว่าฉันอาจสับสนกับคำศัพท์ ไฟล์ 'staged' เหมือนกับไฟล์ 'tracked' หรือไม่?

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


ตั้งแต่ Git เวอร์ชัน 2.23 คุณสามารถใช้git switchแทนgit checkoutไฟล์. สำหรับกรณีนี้คำสั่งสองคำสั่งนี้ทำสิ่งเดียวกันทุกประการ คำสั่งใหม่มีอยู่เนื่องจากgit checkoutมีสิ่งต่างๆมากเกินไป พวกเขาแยกออกเป็นสองคำสั่งแยกกันgit switchและgit restoreเพื่อให้ง่ายและปลอดภัยยิ่งขึ้นในการใช้ Git


กระทำ

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

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

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

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

  • Git มีแช่แข็งสำหรับทุกเวลาสำเนา Git-ified ในปัจจุบันกระทำ คุณไม่สามารถเปลี่ยนสำเนานี้ได้ (แม้ว่าคุณจะสามารถเลือกคอมมิตอื่นหรือสร้างคอมมิตใหม่ได้)

  • คุณมีสำเนารูปแบบปกติในแผนผังงานของคุณ คุณสามารถทำอะไรก็ได้ที่ต้องการโดยใช้คำสั่งใดก็ได้บนคอมพิวเตอร์ของคุณ

ระบบควบคุมเวอร์ชันอื่น ๆ (รวมถึง Mercurial ตามที่กล่าวไว้ข้างต้น) จะหยุดที่นี่พร้อมกับสำเนาสองชุดนี้ คุณเพียงแค่แก้ไขสำเนาแผนผังงานของคุณแล้วคอมมิต Git ... ไม่

ดัชนี

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

git addคำสั่งวิธีการทำสำเนาดัชนีของแฟ้มที่ตรงกับสำเนาการทำงานต้นไม้ นั่นคือคุณกำลังบอก Git: แทนที่ Frozen-format, de-du-duplicated copy ที่อยู่ในดัชนีในตอนนี้โดยการบีบอัดสำเนาแผนผังงานที่อัปเดตของฉัน, ยกเลิกการทำซ้ำและเตรียมให้พร้อมที่จะถูกตรึงเป็นคอมมิตใหม่ หากคุณไม่ใช้git addดัชนีจะยังคงเก็บสำเนารูปแบบที่ตรึงไว้จากการคอมมิตปัจจุบัน

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

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

โปรดทราบว่าgit checkoutในตอนแรกจะเติมดัชนีของ Git จากคอมมิตที่คุณเช็คเอาต์ ดังนั้นดัชนีจะเริ่มจากการจับคู่คอมมิต Git ยังเติมใน work-tree ของคุณจากแหล่งเดียวกันนี้ ดังนั้นในตอนแรกทั้งสามการแข่งขัน เมื่อคุณเปลี่ยนไฟล์ในแผนผังงานของคุณและgit addตอนนี้ดัชนีและแผนผังงานของคุณตรงกัน จากนั้นคุณเรียกใช้git commitและ Git ทำการคอมมิตใหม่จากดัชนีและตอนนี้ทั้งสามจะจับคู่อีกครั้ง

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

นั่นคือทั้งหมดที่มี - แต่ก็ยังค่อนข้างซับซ้อน! เป็นเรื่องยุ่งยากเป็นพิเศษเพราะไม่มีวิธีง่ายๆในการดูว่าอะไรอยู่ในดัชนีของ Git 3 แต่มีเป็นคำสั่ง Git git statusที่จะบอกคุณสิ่งที่เกิดขึ้นในทางที่เป็นประโยชน์สวยและคำสั่งที่


2 ในทางเทคนิคนี่ไม่ใช่สำเนาเลย แต่เป็นการอ้างอิงถึงไฟล์ Git-ified, pre-de-duplicated และทุกอย่าง ที่นี่ยังมีอีกหลายอย่างเช่นโหมดชื่อไฟล์หมายเลขการจัดเตรียมและข้อมูลแคชบางอย่างเพื่อให้ Git ทำงานได้อย่างรวดเร็ว แต่ถ้าคุณไม่ได้ทำงานกับคำสั่งระดับต่ำของ Git - git ls-files --stageและgit update-indexโดยเฉพาะอย่างยิ่งคุณสามารถคิดว่ามันเป็นสำเนา

3git ls-files --stageคำสั่งจะแสดงชื่อและหมายเลขการแสดงละครของไฟล์ทุกไฟล์ในดัชนี Git แต่มักจะไม่ได้อยู่แล้วที่มีประโยชน์มาก


git status

git statusคำสั่งใช้งานได้จริงโดยการทำงานสองแยกgit diffคำสั่งสำหรับคุณ (และทำบางสิ่งที่มีประโยชน์อื่น ๆ เช่นบอกคุณซึ่งสาขาที่คุณกำลัง)

ข้อแรกgit diffเปรียบเทียบการกระทำปัจจุบันซึ่งจำไว้ว่าถูกแช่แข็งตลอดเวลากับสิ่งที่อยู่ในดัชนีของ Git สำหรับไฟล์ที่เหมือนกัน Git จะไม่พูดอะไรเลย สำหรับไฟล์ที่มีความแตกต่างกัน , Git จะบอกคุณว่าไฟล์นี้เป็นฉากสำหรับการกระทำ ซึ่งรวมถึงการใหม่ทั้งหมดไฟล์ถ้ากระทำไม่ได้มีsub.pyอยู่ในนั้น แต่ดัชนีไม่ได้sub.pyอยู่ในนั้นแล้วไฟล์นี้จะมีการเพิ่มและไฟล์ที่ถูกลบใด ๆ ที่มี (และ) ในการกระทำ แต่ไม่ได้อยู่ใน ดัชนีอีกต่อไป ( git rmบางที)

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

ในตอนท้ายเมื่อสะสมไฟล์ที่ไม่ได้ติดตามเหล่านี้ไว้ในรายการgit statusจะประกาศชื่อไฟล์เหล่านั้นด้วย แต่มีข้อยกเว้นพิเศษคือหากชื่อไฟล์อยู่ใน.gitignoreไฟล์จะเป็นการระงับรายการสุดท้ายนี้ โปรดทราบว่าการแสดงรายการไฟล์ที่ติดตามซึ่งเป็นไฟล์ที่อยู่ในดัชนีของ Git .gitignoreจะไม่มีผลใด ๆ ที่นี่ไฟล์อยู่ในดัชนีดังนั้นจึงได้รับการเปรียบเทียบและได้รับความมุ่งมั่นแม้ว่าจะอยู่ในรายการ.gitignore. ไฟล์ละเว้นจะระงับการร้องเรียน "ไฟล์ที่ไม่ได้ติดตาม" เท่านั้น 5


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

5 การแสดงรายการไฟล์ยังทำให้ en-masse เพิ่มการทำงานของไฟล์จำนวนมากเช่นgit add .หรือgit add *ข้ามไฟล์ที่ไม่ได้ติดตาม ส่วนนี้จะซับซ้อนขึ้นเล็กน้อยเนื่องจากคุณสามารถใช้git add --forceเพื่อเพิ่มไฟล์ที่ปกติจะถูกข้ามไป มีกรณีพิเศษอื่น ๆ ตามปกติซึ่งทั้งหมดนี้รวมเข้าด้วยกัน: ไฟล์.gitignoreอาจถูกเรียกอย่างถูกต้องมากกว่า.git-do-not-complain-about-these-untracked-files-and-do-not-auto-add-themหรือมีบางอย่างที่เทอะทะพอ ๆ กัน แต่ที่ไร้สาระเกินไปดังนั้น.gitignoreมันเป็น


git add -u, git commit -aฯลฯ

มีทางลัดที่สะดวกมากมายที่ควรทราบเกี่ยวกับที่นี่:

  • git add .จะเพิ่มทุกไฟล์ที่อัปเดตในไดเรกทอรีปัจจุบันและใด ๆ ไดเรกทอรีย่อย ในกรณีนี้.gitignoreดังนั้นหากไฟล์ที่ไม่ได้ติดตามอยู่ในขณะนี้ไม่ได้รับการร้องเรียนgit statusไฟล์นั้นจะไม่ถูกเพิ่มอัตโนมัติ

  • git add -uอัตโนมัติจะเพิ่มทุกไฟล์ที่อัปเดตได้ทุกที่ในการทำงานต้นไม้ของคุณ 6 สิ่งนี้มีผลกับไฟล์ที่ติดตามเท่านั้น โปรดทราบว่าหากคุณลบสำเนาแผนผังงานออกจะเป็นการลบสำเนาดัชนีด้วย ( git addซึ่งเป็นส่วนหนึ่งของการทำให้ดัชนีตรงกับสิ่งที่ต้นไม้งาน )

  • git add -Aก็เหมือนกับการเรียกใช้git add .จากระดับบนสุดของโครงสร้างงานของคุณ (แต่ดูเชิงอรรถ 6)

นอกจากนี้คุณสามารถเรียกใช้git commit -aซึ่งเทียบเท่าประมาณ7กับการทำงานแล้วgit add -u git commitนั่นคือทำให้คุณมีพฤติกรรมแบบเดียวกับที่สะดวกใน Mercurial

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


6หากเวอร์ชัน Git ของคุณมาก่อน Git 2.0 โปรดระวังที่นี่: git add -uใช้ได้เฉพาะกับไดเรกทอรีปัจจุบันและไดเรกทอรีย่อยดังนั้นคุณต้องปีนขึ้นไปที่ระดับบนสุดของแผนผังงานก่อน git add -Aตัวเลือกที่มีปัญหาที่คล้ายกัน

7ฉันบอกว่าเทียบเท่าโดยประมาณเพราะgit commit -aใช้งานได้จริงโดยการสร้างดัชนีพิเศษและใช้ดัชนีอื่นเพื่อทำการคอมมิต หากกระทำการงานgit add -u && git commitคุณจะได้รับผลเช่นเดียวกับการทำ หากคอมมิตไม่ได้ผล - ถ้าคุณทำให้ Git ข้ามคอมมิตในหลาย ๆ วิธีที่คุณสามารถทำได้หลังจากนั้นจะไม่มีการแก้ไขไฟล์ใดgit addๆ เนื่องจาก Git จะพ่นดัชนีพิเศษชั่วคราวออกมาและกลับไปใช้ดัชนีหลัก .

มีภาวะแทรกซ้อนเพิ่มเติมที่เข้ามาหากคุณใช้git commit --onlyที่นี่ ในกรณีนี้ Git จะสร้างดัชนีที่สามและสิ่งต่าง ๆ จะยุ่งยากมากโดยเฉพาะอย่างยิ่งถ้าคุณใช้ pre -mit hooks นี่เป็นอีกเหตุผลหนึ่งที่ต้องใช้git addการดำเนินการแยกกัน


5

มันง่ายกว่าที่จะเข้าใจการใช้คำสั่ง git addและcommitหากคุณนึกภาพไฟล์บันทึกที่เก็บรักษาไว้ในที่เก็บของคุณบน Github ไฟล์บันทึกของโครงการโดยทั่วไปสำหรับฉันอาจมีลักษณะดังนี้:

---------------- Day 1 --------------------
Message: Complete Task A
Index of files changed: File1, File2

Message: Complete Task B
Index of files changed: File2, File3
-------------------------------------------

---------------- Day 2 --------------------
Message: Correct typos
Index of files changed: File3, File1
-------------------------------------------
...
...
...and so on

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

แต่ละงานย่อยเหล่านี้ (งาน A และงาน B ที่นี่) เป็นการกระทำของแต่ละคน git addคำสั่งเพิ่มไฟล์ไป 'ดัชนีของไฟล์ที่มีการเปลี่ยนแปลงรายชื่อ กระบวนการนี้เรียกอีกอย่างว่าการจัดเตรียม git commitบันทึกคำสั่ง / สรุปการเปลี่ยนแปลงและรายการดัชนีที่สอดคล้องกันพร้อมกับข้อความที่กำหนดเอง

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

ตัวอย่างเช่นในการรับรายการที่สองในล็อกไฟล์จินตภาพนั้นฉันจะต้องทำ:

git pull
# Make changes to these files
git add File3 File4
# Verify changes, run tests etc..
git commit -m 'Correct typos'
git push

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


2

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

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

คุณสามารถดูตัวอย่างเพิ่มเติมได้ที่นี่: การ ใช้ดัชนี

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


1

ฉันเห็นประเด็นในการใช้เวทีเพื่อทำให้การแสดงเล็กลงตามที่ @Ben Jackson และ @Tapashee Tabassum Urmi กล่าวไว้และบางครั้งฉันก็ใช้มันเพื่อจุดประสงค์นั้น แต่ส่วนใหญ่จะใช้มันเพื่อทำให้งานของฉันใหญ่ขึ้น! นี่คือประเด็นของฉัน:

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

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

ฉันเห็นวิธีอื่น ๆ ในการทำสิ่งนี้ (ทำให้ประวัติคอมไพล์ง่ายขึ้น) ซึ่งคุณอาจใช้ขึ้นอยู่กับความต้องการของคุณ:

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

0

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

ตัวอย่างเช่นหากฉันได้แก้ไขfileA.txtและfileB.txtแต่ฉันต้องการเปลี่ยนแปลงfileA.txtเฉพาะ fileB.txtเพราะผมยังไม่เสร็จด้วย

ฉันสามารถใช้git add fileA.txtและกระทำโดยใช้git commit -m "changed fileA.txt"และทำงานต่อไปได้fileB.txtและหลังจากเสร็จสิ้นฉันสามารถกระทำfileB.txtได้อย่างง่ายดาย

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