Git ขั้นต่ำที่ทำงานได้สำหรับการพัฒนาตามลำต้น
Less is more เมื่อพูดถึงเครื่องมือที่ทรงพลังและซับซ้อนเกินไปอย่าง Git
Eli เป็นผู้ร่วมก่อตั้งและซีอีโอร่วมของtrunk.io เขาดำรงตำแหน่งผู้นำด้านวิศวกรรมที่ Microsoft, Uber และ Google (ซึ่งได้รับสตาร์ทอัพที่เขาร่วมก่อตั้ง) เป้าหมายหลักของเขาคือการช่วยให้ทีมสร้างซอฟต์แวร์ที่ดีขึ้น เร็วขึ้น
![](https://post.nghiatu.com/assets/images/m/max/724/1*QmbOGm8jxBU5tC51y1zylQ.png)
การพัฒนาในสภาพแวดล้อมการทำงานร่วมกันเป็นการดำเนินการที่ซับซ้อนซึ่งเกี่ยวข้องกับการติดตามและประสานงานจากนักพัฒนาหลายคน พวกเราหลายคนใช้ Git สำหรับการควบคุมเวอร์ชันเพื่อจัดการกับการเปลี่ยนแปลงเหล่านี้ทั้งหมด แต่ใน คำพูดของ Linus Git คือ "ผู้จัดการข้อมูลจากขุมนรก" มันมีตัวเลือกและสถานะแปลก ๆ มากมาย คุณสามารถพบว่าตัวเองอยู่ในจุดที่แย่จนถึงจุดที่คุณต้องโคลนใหม่ตั้งแต่เริ่มต้น — แม้ว่าคุณจะไม่ได้ทำอะไรผิดก็ตาม
พวกเราหลายคนรู้ว่ามีนักพัฒนาคนหนึ่งที่ศึกษา Git refspec และ Merkle tree ที่อิงตามนั้น แต่การเป็น Git savant อาจไม่อยู่ในรายละเอียดงานของคุณ ฉันสามารถขับรถได้อย่างสมบูรณ์แบบโดยไม่ต้องเข้าใจว่าระบบส่งกำลังทำงานอย่างไร และท้ายที่สุดแล้ว Git เป็นเพียงหนทางสู่จุดจบ
เพื่อให้ได้ประโยชน์สูงสุดจาก Git คุณต้องใช้มันให้น้อยที่สุดเท่าที่จะเป็นไปได้ในการพัฒนาตามลำต้น จำกัดคำสั่งที่คุณใช้ อัปเดตฟีเจอร์สาขาของคุณให้เป็นปัจจุบันอย่างเหมาะสม และสร้างมาตรฐานการใช้งานเป็นทีม โดยส่วนตัวแล้ว คุณอาจมีอิสระที่จะทำอะไรก็ได้ตามที่คุณต้องการ แต่ในฐานะทีม ราคาของอิสรภาพต้องแลกมาด้วยแรงเสียดทาน
จำกัดการกระทำ Git ของคุณ
วิธีปฏิบัติที่ง่ายที่สุดในการปรับใช้เพื่อประสิทธิภาพสูงสุดของ Git คือการยึดติดกับชุดคำสั่งย่อย Git สามารถทำได้หลายอย่าง แต่พลังส่วนใหญ่ของมันมีอยู่เพียงเพื่อช่วยให้คุณออกจากสถานการณ์เลวร้ายเท่านั้น จำนวนคำสั่งที่ Git อนุญาตกับจำนวนคำสั่งที่คุณควรเรียกใช้จริงๆ นั้นแตกต่างกันมาก
ครั้งหนึ่ง CTO ขอให้ฉันสอนวิชาคอมไพล์ขั้นสูงให้กับทีมวิศวกรของเขา คำตอบของฉันง่ายมาก:
เมื่อถึงเวลาที่คุณต้องการคอมไพล์ขั้นสูง — ล้อได้หลุดออกจากรถแล้ว ให้มุ่งเน้นไปที่การใช้คอร์ git อย่างถูกต้องแทน
ต่อไปนี้คือคำสั่งคอมไพล์ 10 คำสั่งที่ฉันใช้เพื่อทำงานให้เสร็จในขณะที่ลดจำนวนครั้งที่ฉันลงจอดใน Git hell:
การจัดการสาขา
git checkout -t -b {branch-name}
สร้างสาขา ตั้งค่าอัพสตรีมเป็นสาขาปัจจุบัน และสลับไปยังสาขานั้น คุณสามารถทำได้ผ่านคำสั่ง `git branch` แต่ต้องใช้หลายคำสั่ง เนื่องจากฉันต้องการเปลี่ยนไปใช้สาขาเมื่อฉันสร้างมันขึ้นมา คำสั่งนี้จึงรวบรัดมากขึ้น สร้างและชำระเงินสาขาได้ในบัดดล ฉันมักจะตั้งชื่อทุกสาขาของeli/{work-being-done}
ฉัน
git checkout {branch-name}
สลับไปที่สาขา
git branch -vv
ดูสาขาปัจจุบันของคุณและต้นน้ำของพวกเขา
git branch -D {branch-name}
ลบสาขาในพื้นที่ โดยปกติเพื่อล้างสาขาเก่า/ที่ผสานเข้ากับสาขาหลัก
ดัน & ดึง
git fetch origin main:main
ดึงรีโมทmain
เข้าไปในเครื่องของคุณmain
แม้ว่าคุณจะไม่ได้อยู่ที่main
สาขาก็ตาม! นั่นคือ ; มีประโยชน์มากเมื่อคุณพยายามรวมข้อมูลล่าสุดmain
เข้ากับสาขาประชาสัมพันธ์
git push origin
กดรหัสของฉันไปที่รีโมท มีแนวโน้มที่จะหมุนเครื่องจำนวนมากใน CI เพื่อตรวจสอบงานของฉัน
git pull
อัปเดตสาขาในพื้นที่ของฉันด้วยรีโมตที่มีชื่อเดียวกัน
ความมุ่งมั่น
git add -A .
เพิ่มทุกสิ่งที่ฉันกำลังทำอยู่ (ไฟล์ใหม่และไฟล์ที่แก้ไขแล้ว)
git commit -am "work"
ดูที่นี่เพื่อเจาะลึกความคิดของฉันเกี่ยวกับข้อความยืนยันในเครื่อง
git merge main
อีกมากมายเกี่ยวกับสิ่งนี้ด้านล่าง ฉันเป็นนักปฏิบัติและไม่ใช่นัก rebase และยินดีที่จะทำให้สาขาในพื้นที่ของฉันยุ่งเหยิงด้วยสิ่งที่เกิดขึ้นจากmain
.
ปรับปรุงฟีเจอร์สาขาของคุณให้ทันสมัยอยู่เสมอ
ในส่วนสุดท้ายของฉัน ฉันได้พูดถึงวิธีจัดการรหัสเชื่อมโยงไปmain
ถึง แต่บ่อยครั้งในระหว่างการพัฒนา และแน่นอนว่าก่อนที่จะทำการรวม คุณจะต้องได้รับข้อมูลล่าสุดเกี่ยวกับการเปลี่ยนแปลงล่าสุดmain
เนื่องจาก:
- คุณต้องมีคุณลักษณะบางอย่างที่เข้ามา
main
เพื่อให้คุณลักษณะของคุณทำงาน - มีบางสิ่งที่
main
เปลี่ยนแปลงและหากคุณไม่หยิบมันขึ้นมา คุณจะทำลายมันเมื่อคุณพยายามลงรหัสของคุณ - คุณแค่ต้องการความสดใหม่เพราะคุณเป็นวิศวกรและรักสิ่งใหม่ๆ
ประตู 1: คอมไพล์ผสาน
นี่คือกลยุทธ์การผสานรวมของฉัน มันเรียบง่าย เชื่อถือได้ และไม่หรูหรา พื้นฐานgit merge
ใช้การเปลี่ยนแปลงทั้งหมดที่เกิดขึ้นmain
และรวมเข้าด้วยกันเป็นการกระทำควบคู่ไปกับการเปลี่ยนแปลงของคุณ คุณสามารถอ่านโฆษณาที่น่าสะอิดสะเอียนเกี่ยวกับข้อเสียของวิธีแก้ปัญหาง่ายๆ นี้ แต่บอกตามตรงว่าฉันแค่ยักไหล่และพูดว่า "ฉันไม่สนใจเรื่องนั้น" หากคุณรวมสาขางานของคุณเข้าด้วยกันmain
เรื่องไร้สาระทั้งหมดเกี่ยวกับมลพิษ git-log ก็จะกลายเป็นเรื่องนั้น
จริงๆ แล้วไม่สำคัญว่า/ทำไม/อะไรเข้ามาในสาขางานของฉัน สิ่งที่สำคัญคือ มันสร้าง ใช้งานได้ และโค้ดทำในสิ่งที่ฉันต้องการหรือไม่ ที่เหลือเป็นเรื่องวิชาการ
ในทางปฏิบัติ และฉันเป็นวิศวกรที่ใช้งานได้จริงgit merge
ช่วยให้คุณสามารถจัดการกับข้อขัดแย้งในการผสานได้อย่างหมดจดและกลับไปสร้างใหม่ คุณแก้ไขข้อขัดแย้งในการผสานเพียงครั้งเดียว — และคุณก็พร้อมดำเนินการต่อ นี่เป็นตัวเลือกที่ดีที่สุดสำหรับผู้เริ่มต้น ผู้ใช้ขั้นสูงที่มีงานยุ่ง และบรรดาผู้ที่ไม่ฝันถึงการเป็นกูรูด้าน Git
ประตู 2: git rebase
นี่เป็นตัวเลือกที่แย่ที่สุด โอเค ฉันรู้; มีคนทั้งรุ่นที่ดู rebase และผสานบางอย่างเช่น tabs vs spaces แต่ในโครงการ "จริง" ที่หนึ่งหรือหลายทีมรวมเข้ากับ repo ทุกวัน การรีเบสจำเป็นต้องแก้ไข ข้อขัดแย้งในการผสาน n ครั้งแทนที่จะใช้การผสานหรือสควอชรีเบส (รายละเอียดเพิ่มเติมด้านล่าง)
นอกจากนี้ การรีเบสใด ๆ จะเขียนประวัติ Git ใหม่ และนั่นหมายความว่าหากสาขาของคุณมีรีโมตคู่ฉบับ คุณต้องgit push --force
เหยียบประวัติด้วยประวัติการรีเบสใหม่ของสาขาของคุณ วิธีนี้ใช้ได้ในทางทฤษฎี แต่มีความเป็นไปได้ที่จะลบงานก่อนหน้าของคุณโดยไม่ตั้งใจด้วยวิธีที่ยากต่อการกู้คืน มันอันตรายกว่าการผสานและทำให้ฉันปวดหัวจริงๆ แค่คิดเกี่ยวกับมัน
สำหรับจุดประสงค์ของบทความนี้ ฉันพยายามรีเบสเพื่อเตือนตัวเองว่าฉันไม่ชอบเวิร์กโฟลว์นี้มากแค่ไหน ดูว่าคำสั่ง rebase ง่าย ๆ พ่นอะไรลงในเทอร์มินัลของฉัน:
![](https://post.nghiatu.com/assets/images/m/max/724/1*lUbjMn7LcXy_3tovVNDlDQ.png)
มีสิ่งผิดปกติมากมายกับเทอร์มินัลนั้น ฉันได้รับบันทึกเกี่ยวกับการคอมมิตแฮช — ไม่ต้องการเห็นสิ่งเหล่านั้น ฉันได้รับคำแนะนำสีเหลืองสี่บรรทัดเพื่อเตือนฉันว่าทั้งหมดนี้ทำงานอย่างไร และตอนนี้ฉันอยู่ในเวิร์กโฟลว์เพียงเพื่อรับรหัสจากmain
สาขาของฉัน ต้นไม้การตัดสินใจนั้นซับซ้อนงี่เง่า git rebase --skip
- นั่นคืออะไร?! ทำไมการข้ามการกระทำจึงเป็นเรื่องปกติ คุณรู้อะไรไหม? ไม่บอกเพราะมีงานต้องทำ
ประตู 3: git squash rebase
แน่นอนคุณไม่ต้องการสิ่งที่อยู่เบื้องหลังประตู # 2 แต่บางคนก็เป็นคนดื้อรั้น David Apirian ผู้ร่วมก่อตั้งและซีอีโอร่วมของฉันได้แสดงให้ฉันเห็นทางเข้าลับหลังเวทีเพื่อทำการรีเบส และมันก็ยอดเยี่ยมมาก เราจะเรียกสิ่งนี้ว่า รี เบสสควอช
ฉันได้ย้ำถึงความสำคัญของความเรียบง่ายของ Git แต่ด้วยวิธีนี้ คุณสามารถรีเบสและกินมันได้เช่นกัน คุณจะได้รับเลเยอร์การรีเบสที่มีมนต์ขลังโดยไม่ต้องใช้โฟลว์การรีเบสมาตรฐานที่บ้าระห่ำ ด้วยการรีเบสสควอช คุณสามารถ:
- ดูความแตกต่างของคอมมิชชันในเครื่องของคุณก่อนที่จะพุชไปที่ GitHub
- ยกเลิกการกระทำล่าสุดของคุณได้อย่างง่ายดาย
- หลีกเลี่ยงการสร้างมลพิษให้กับมุมมองของ GitHub ต่อคำขอดึงข้อมูลของคุณด้วยคอมมิชชันในท้องถิ่นเพียงเล็กน้อย
ขั้นตอนที่ 1 — สควอชคอมมิชชันในเครื่องทั้งหมดของคุณ:
git reset --soft $(git merge-base HEAD main) &&
git commit -am "" --allow-empty-message
git rebase main
คุณสามารถรวมทั้งหมดนี้เข้าด้วยกันเป็นคำสั่ง uber เดียวเพื่อดึง main ล่าสุด บีบคอมมิชชันทั้งหมดของคุณ และ rebase บน main ล่าสุด:
git reset --soft $(git merge-base HEAD main) &&
git commit -am "" --allow-empty-message &&
git fetch origin main:main &&
git rebase main
[alias]
smartcommit = !git add -A . && git commit -am "" --allow-empty-message
squash = !git reset --soft $(git merge-base HEAD main) && git commit -am "" --allow-empty-message
squashrebase = !git squash && git fetch origin main:main && git rebase main
smart = !git smartcommit && git squashrebase
แง่มุมที่ยอดเยี่ยมอย่างหนึ่งของการบีบคอมมิชชันในพื้นที่ของคุณอยู่เสมอgit log
คืองานทั้งหมดที่คุณได้ทำในสาขานั้นสำคัญที่สุด ตอนนี้งานในพื้นที่ของคุณมีความคล้ายคลึงกับสควอชที่ผสาน PR มากขึ้นเมื่อเข้าสู่main
.
คุณสามารถเปิดคอมมิชชันล่าสุดของ HEAD กับสาขาในพื้นที่ของคุณได้ทุกเมื่อ และดูงานทั้งหมดที่คุณทำเสร็จแล้วจากmain
HEAD ซึ่งคล้ายกับมุมมองแบบละเอียดที่ GitHub แสดงสิ่งที่เปลี่ยนแปลง แต่ช่วยให้คุณอยู่ในเทอร์มินัลและหลีกเลี่ยงการสลับระหว่าง UI ที่แตกต่างกันสองอันอย่างสับสน
ฉันต้องยอมรับว่าครั้งแรกที่ David แสดงเวิร์กโฟลว์นี้ให้ฉันดู ฉันรู้สึกประทับใจ เขาฆ่าrebase
มังกรเป็นส่วนใหญ่และความสามารถในการดูไฟล์ทั้งหมดที่คุณเปลี่ยนแปลงในสาขาของคุณนั้นยอดเยี่ยมมาก
แม้ว่าการรีเบสสควอชจะช่วยให้คุณรักษาสถานะโฟลว์ที่ดีขึ้นได้ แต่นักพัฒนาส่วนใหญ่ที่ล้นหลามกลับดีกว่าเพียงแค่ควบรวมกิจการ การใช้ rebase หรือ squash rebase อย่างไม่ถูกต้องส่งผลให้เกิดแรงเสียดทานที่ทำให้ผลผลิตลดลง
ข้อผิดพลาดของความช่วยเหลือสาขา GitHub
GitHub เสนอการตั้งค่านี้ ☝️ เพื่อแนะนำการรวมmain
เข้ากับสาขาของคุณโดยอัตโนมัติหากล้าสมัย การตั้งค่านี้มักจะไม่เกิดผล ฉันต้องการให้สาขาท้องถิ่นของฉันเป็นแหล่งความจริงเพียงแหล่งเดียวสำหรับ PR ของฉัน และไม่ควรมีใครอื่น (รวมถึง GitHub) ผลักดันเรื่องนี้ การทำงานกับ GitHub ในสาขาส่วนตัวของฉันควรเป็นแบบทางเดียว ฉันเข้ารหัสในเครื่องและกด
หากคุณกำหนดค่า GitHub ให้เริ่มส่งการอัปเดตไปยังสาขางานของคุณ แสดงว่าคุณกำลังขอให้ทราฟฟิกเริ่มมุ่งไปในทิศทางที่ไม่ถูกต้อง และนั่นคือสูตรสำหรับความเจ็บปวด
ปัญหานี้เกิดขึ้นเมื่อผู้ตรวจสอบโค้ดให้ข้อเสนอแนะเล็กน้อยเกี่ยวกับคำขอดึงข้อมูลของคุณและคุณนำไปใช้อย่างเต็มใจ หากคุณทำงานใด ๆ กับสาขาในพื้นที่ของคุณก่อนที่จะดึงการเปลี่ยนแปลงเหล่านั้น ... คุณได้เปิดกระเป๋าเล็ก ๆ น้อย ๆ ของความเจ็บปวด
ฉันมักจะค้นพบว่าฉันทำสิ่งนี้กับตัวเองโดยไม่ได้ตั้งใจเมื่อฉันพยายามส่งการอัปเดตกลับไปที่รีโมตและ git บอกว่าฉันไม่ซิงค์ ณ จุดนั้น ฉันมีสองทางเลือก:
git push --force
และระเบิดทุกสิ่งบนรีโมทที่ไม่ได้อยู่ในสาขาในพื้นที่ของคุณ โดยทั่วไปแล้วอะไรก็ตามที่มีคำว่า แรง นั้นเป็นสิ่งที่ทำลายล้างและหมดกำลังใจgit merge origin/{my-work-branch}
เพื่อรวมการเปลี่ยนแปลงระยะไกลเข้ากับมุมมองภายในของสาขา
การตั้งค่า GitHub นี้ ️☝️ กำหนดให้ PRs เป็นปัจจุบันmain
ก่อนที่จะรวมเข้าด้วยกัน ซึ่งโดยทั่วไปจะ "แก้ไข" โอกาสที่จะเกิดการmain
แตกหัก อย่างไรก็ตาม มันใช้งานได้กับ repos ที่มีความเร็วต่ำมากเท่านั้น เมื่อนักพัฒนาไม่กี่คนพยายามรวม PR หลายรายการต่อวัน พวกเขาลงเอยด้วยการแข่งขันเพื่อรวมเข้าด้วยกันmain
หรือมิฉะนั้นก็พบว่าตัวเองทำการผสาน/รีเบสอย่างต่อเนื่องmain
ในสาขาของตนเพื่อให้ "ทันสมัย" อีกครั้ง และโดยพื้นฐานแล้วแข่งกับเพื่อนร่วมงาน เพื่อรวมเป็นคนแรก เจ็บปวด. โดยทั่วไปแล้ว ถ้าคุณต้องการคุณลักษณะนี้ แต่คุณไม่ใช่นักพัฒนาเดี่ยว คุณอาจต้องการคิวการผสานแทน ซึ่งเป็นวิธีที่ปรับขนาดได้เพื่อให้ได้มาซึ่งส่วนหลักที่ไม่เสียหาย นี่เป็นสิ่งที่เรารู้สึกว่าสำคัญพอที่จะสร้างผลงานด้วยTrunk Merge
ย่อ Git ให้เล็กสุดเพื่อให้ได้ค่าสูงสุด
การทำให้การใช้งาน Git ของคุณเรียบง่ายที่สุดเท่าที่จะเป็นไปได้ ทำให้นักพัฒนามีเชือกผูกมัดน้อยลงและมีเวลามากขึ้นในการพัฒนางานที่สำคัญจริงๆ ให้ Git เป็นตัวประกอบ ไม่ใช่ตัวเอก เพื่อรักษาสภาพแวดล้อมการพัฒนาที่เหมาะสมและการทำงานร่วมกัน อย่าลืม:
- เลือกพื้นที่ผิวที่เล็กที่สุดของ Git เพื่อใช้และติดกับมัน
- จัดการการเปลี่ยนแปลงต้นน้ำด้วยวิธีเดียวกันเสมอ
- กำหนดแนวทางปฏิบัติในทีมของคุณให้เป็นมาตรฐาน เพื่อให้เพื่อนร่วมงานของคุณไม่ออกนอกลู่นอกทางเช่นกัน