Git ขั้นต่ำที่ทำงานได้สำหรับการพัฒนาตามลำต้น

Nov 30 2022
Less is more เมื่อพูดถึงเครื่องมือที่ทรงพลังและซับซ้อนเกินไปอย่าง Git Eli เป็นผู้ร่วมก่อตั้งและ Co-CEO ของ trunk.io

Less is more เมื่อพูดถึงเครื่องมือที่ทรงพลังและซับซ้อนเกินไปอย่าง Git

Eli เป็นผู้ร่วมก่อตั้งและซีอีโอร่วมของtrunk.io เขาดำรงตำแหน่งผู้นำด้านวิศวกรรมที่ Microsoft, Uber และ Google (ซึ่งได้รับสตาร์ทอัพที่เขาร่วมก่อตั้ง) เป้าหมายหลักของเขาคือการช่วยให้ทีมสร้างซอฟต์แวร์ที่ดีขึ้น เร็วขึ้น

Git Inferno ของ Dante

การพัฒนาในสภาพแวดล้อมการทำงานร่วมกันเป็นการดำเนินการที่ซับซ้อนซึ่งเกี่ยวข้องกับการติดตามและประสานงานจากนักพัฒนาหลายคน พวกเราหลายคนใช้ 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 ง่าย ๆ พ่นอะไรลงในเทอร์มินัลของฉัน:

เวิร์กโฟลว์ที่ดีไม่ควรต้องการคำแนะนำในการทำงาน

มีสิ่งผิดปกติมากมายกับเทอร์มินัลนั้น ฉันได้รับบันทึกเกี่ยวกับการคอมมิตแฮช — ไม่ต้องการเห็นสิ่งเหล่านั้น ฉันได้รับคำแนะนำสีเหลืองสี่บรรทัดเพื่อเตือนฉันว่าทั้งหมดนี้ทำงานอย่างไร และตอนนี้ฉันอยู่ในเวิร์กโฟลว์เพียงเพื่อรับรหัสจาก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 กับสาขาในพื้นที่ของคุณได้ทุกเมื่อ และดูงานทั้งหมดที่คุณทำเสร็จแล้วจากmainHEAD ซึ่งคล้ายกับมุมมองแบบละเอียดที่ GitHub แสดงสิ่งที่เปลี่ยนแปลง แต่ช่วยให้คุณอยู่ในเทอร์มินัลและหลีกเลี่ยงการสลับระหว่าง UI ที่แตกต่างกันสองอันอย่างสับสน

ฉันต้องยอมรับว่าครั้งแรกที่ David แสดงเวิร์กโฟลว์นี้ให้ฉันดู ฉันรู้สึกประทับใจ เขาฆ่าrebaseมังกรเป็นส่วนใหญ่และความสามารถในการดูไฟล์ทั้งหมดที่คุณเปลี่ยนแปลงในสาขาของคุณนั้นยอดเยี่ยมมาก

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

ข้อผิดพลาดของความช่วยเหลือสาขา GitHub

ช่องทำเครื่องหมายเหล่านี้ใน GitHub ดูเหมือนจะมีประโยชน์…แต่ไม่ใช่

GitHub เสนอการตั้งค่านี้ ☝️ เพื่อแนะนำการรวมmainเข้ากับสาขาของคุณโดยอัตโนมัติหากล้าสมัย การตั้งค่านี้มักจะไม่เกิดผล ฉันต้องการให้สาขาท้องถิ่นของฉันเป็นแหล่งความจริงเพียงแหล่งเดียวสำหรับ PR ของฉัน และไม่ควรมีใครอื่น (รวมถึง GitHub) ผลักดันเรื่องนี้ การทำงานกับ GitHub ในสาขาส่วนตัวของฉันควรเป็นแบบทางเดียว ฉันเข้ารหัสในเครื่องและกด

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

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

ฉันมักจะค้นพบว่าฉันทำสิ่งนี้กับตัวเองโดยไม่ได้ตั้งใจเมื่อฉันพยายามส่งการอัปเดตกลับไปที่รีโมตและ git บอกว่าฉันไม่ซิงค์ ณ จุดนั้น ฉันมีสองทางเลือก:

  1. git push --forceและระเบิดทุกสิ่งบนรีโมทที่ไม่ได้อยู่ในสาขาในพื้นที่ของคุณ โดยทั่วไปแล้วอะไรก็ตามที่มีคำว่า แรง นั้นเป็นสิ่งที่ทำลายล้างและหมดกำลังใจ
  2. git merge origin/{my-work-branch}เพื่อรวมการเปลี่ยนแปลงระยะไกลเข้ากับมุมมองภายในของสาขา

การตั้งค่า GitHub นี้ ️☝️ กำหนดให้ PRs เป็นปัจจุบันmainก่อนที่จะรวมเข้าด้วยกัน ซึ่งโดยทั่วไปจะ "แก้ไข" โอกาสที่จะเกิดการmainแตกหัก อย่างไรก็ตาม มันใช้งานได้กับ repos ที่มีความเร็วต่ำมากเท่านั้น เมื่อนักพัฒนาไม่กี่คนพยายามรวม PR หลายรายการต่อวัน พวกเขาลงเอยด้วยการแข่งขันเพื่อรวมเข้าด้วยกันmainหรือมิฉะนั้นก็พบว่าตัวเองทำการผสาน/รีเบสอย่างต่อเนื่องmainในสาขาของตนเพื่อให้ "ทันสมัย" อีกครั้ง และโดยพื้นฐานแล้วแข่งกับเพื่อนร่วมงาน เพื่อรวมเป็นคนแรก เจ็บปวด. โดยทั่วไปแล้ว ถ้าคุณต้องการคุณลักษณะนี้ แต่คุณไม่ใช่นักพัฒนาเดี่ยว คุณอาจต้องการคิวการผสานแทน ซึ่งเป็นวิธีที่ปรับขนาดได้เพื่อให้ได้มาซึ่งส่วนหลักที่ไม่เสียหาย นี่เป็นสิ่งที่เรารู้สึกว่าสำคัญพอที่จะสร้างผลงานด้วยTrunk Merge

ย่อ Git ให้เล็กสุดเพื่อให้ได้ค่าสูงสุด

การทำให้การใช้งาน Git ของคุณเรียบง่ายที่สุดเท่าที่จะเป็นไปได้ ทำให้นักพัฒนามีเชือกผูกมัดน้อยลงและมีเวลามากขึ้นในการพัฒนางานที่สำคัญจริงๆ ให้ Git เป็นตัวประกอบ ไม่ใช่ตัวเอก เพื่อรักษาสภาพแวดล้อมการพัฒนาที่เหมาะสมและการทำงานร่วมกัน อย่าลืม:

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