ข้อจำกัดความรับผิดชอบ: ฉันใช้ Git ติดตามการพัฒนา Git ในรายชื่อผู้รับจดหมาย git และสนับสนุน bit ให้กับ Git (gitweb เป็นหลัก) ฉันรู้ Mercurial จากเอกสารและบางอย่างมาจากการอภิปรายในช่อง #revctrl IRC บน FreeNode
ขอบคุณทุกคนใน #mercurial IRC channel ที่ให้ความช่วยเหลือเกี่ยวกับ Mercurial สำหรับการเขียนนี้
สรุป
ที่นี่มันจะดีถ้ามี syntax สำหรับ table เช่นใน PHPMarkdown / MultiMarkdown / Maruku ส่วนขยายของ Markdown
- โครงสร้างที่เก็บข้อมูล: Mercurial ไม่อนุญาตให้รวมปลาหมึกยักษ์ (กับพ่อแม่มากกว่าสองคน) หรือการติดแท็กวัตถุที่ไม่ส่งมอบ
- แท็ก: Mercurial ใช้
.hgtags
ไฟล์ที่มีเวอร์ชันพร้อมกฎพิเศษสำหรับแท็กต่อพื้นที่เก็บข้อมูลและยังรองรับแท็กท้องถิ่น.hg/localtags
ด้วย ในแท็ก Git นั้นอ้างอิงอยู่ในrefs/tags/
เนมสเปซและโดยค่าเริ่มต้นจะมีการติดตามอัตโนมัติในการดึงข้อมูลและต้องการการผลักดันอย่างชัดเจน
- สาขาใน Mercurial พื้นฐานขั้นตอนการทำงานจะขึ้นอยู่กับหัวที่ไม่ระบุชื่อ ; Git ใช้กิ่งไม้ที่มีน้ำหนักเบาและมีสาขาพิเศษ ( สาขาติดตามระยะไกล ) ที่ติดตามสาขาในที่เก็บระยะไกล
- การตั้งชื่อและช่วงการแก้ไขใหม่: Mercurial ให้หมายเลขการแก้ไขท้องถิ่นไปยังที่เก็บและฐานการแก้ไขที่เกี่ยวข้อง (นับจากส่วนปลายเช่นสาขาปัจจุบัน) และช่วงการแก้ไขสำหรับหมายเลขท้องถิ่นนี้ Git นำเสนอวิธีการอ้างถึงการแก้ไขที่สัมพันธ์กับปลายกิ่งและช่วงการแก้ไขเป็นทอพอโลยี (ขึ้นอยู่กับกราฟของการแก้ไข)
- Mercurial ใช้การติดตามการเปลี่ยนชื่อในขณะที่ Git ใช้การตรวจจับการเปลี่ยนชื่อเพื่อจัดการกับการเปลี่ยนชื่อไฟล์
- เครือข่าย: Mercurial รองรับโปรโตคอล SSH และ HTTP "สมาร์ท" และโปรโตคอล HTTP แบบคงที่ modern Git รองรับโปรโตคอล SSH, HTTP และ GIT "สมาร์ท" และโปรโตคอล HTTP "S" dumb " ทั้งสองรองรับไฟล์บันเดิลสำหรับการส่งแบบออฟไลน์
- Mercurial ใช้ส่วนขยาย (ปลั๊กอิน) และ API ที่สร้างขึ้น Git มีความสามารถในการเขียนสคริปต์และรูปแบบที่กำหนดไว้
มีบางสิ่งที่แตกต่างจาก Mercurial จาก Git แต่มีสิ่งอื่นที่ทำให้พวกมันเหมือนกัน ทั้งสองโครงการยืมแนวคิดจากกันและกัน ยกตัวอย่างเช่นhg bisect
คำสั่งใน Mercurial (เดิมนามสกุลแบ่งครึ่ง ) คือแรงบันดาลใจจากgit bisect
คำสั่งใน Git ในขณะที่ความคิดของการเป็นแรงบันดาลใจgit bundle
hg bundle
โครงสร้างที่เก็บการจัดเก็บการแก้ไข
ใน Git มีวัตถุสี่ประเภทในฐานข้อมูลวัตถุ: วัตถุblobที่มีเนื้อหาของไฟล์วัตถุต้นไม้ลำดับชั้นที่จัดเก็บโครงสร้างไดเรกทอรีรวมถึงชื่อไฟล์และส่วนที่เกี่ยวข้องของการอนุญาตไฟล์ (สิทธิ์การปฏิบัติการสำหรับไฟล์เป็นลิงค์สัญลักษณ์) , กระทำวัตถุซึ่งมีข้อมูลประพันธ์ชี้ไปยังภาพรวมของสถานะของพื้นที่เก็บข้อมูลในการแก้ไขแสดงโดยกระทำ (ผ่านวัตถุต้นไม้ของไดเรกทอรีบนของโครงการ) และการอ้างอิงถึงศูนย์หรือมากกว่ากระทำของผู้ปกครองและแท็กวัตถุซึ่งอ้างอิงวัตถุอื่น ๆ และสามารถ สามารถลงนามโดยใช้ PGP / GPG
Git ใช้วิธีการเก็บวัตถุสองวิธี: รูปแบบหลวมที่แต่ละวัตถุถูกเก็บไว้ในไฟล์แยกต่างหาก (ไฟล์เหล่านั้นถูกเขียนเพียงครั้งเดียวและไม่เคยแก้ไข) และรูปแบบที่บรรจุซึ่งวัตถุจำนวนมากถูกเก็บเดลต้าบีบอัดไว้ในไฟล์เดียว ความเป็นจริงของการดำเนินการของอะตอมมิกคือการอ้างอิงถึงวัตถุใหม่นั้นถูกเขียนขึ้น (แบบอะตอมใช้การสร้าง + เปลี่ยนชื่อเคล็ดลับ) หลังจากเขียนวัตถุ
ที่เก็บ Git ต้องการการบำรุงรักษาเป็นระยะโดยใช้git gc
(เพื่อลดพื้นที่ดิสก์และปรับปรุงประสิทธิภาพ) แม้ว่าปัจจุบัน Git จะทำเช่นนั้นโดยอัตโนมัติ (วิธีนี้ให้การบีบอัดที่เก็บที่ดีกว่า)
Mercurial (เท่าที่ฉันเข้าใจ) เก็บประวัติของไฟล์ในfilelog (ด้วยกันฉันคิดว่ามีเมทาดาทาพิเศษเช่นการเปลี่ยนชื่อการติดตามและข้อมูลผู้ช่วยบางส่วน); มันใช้โครงสร้างแบนที่เรียกว่ารายการที่จะจัดเก็บโครงสร้างไดเรกทอรีและโครงสร้างที่เรียกว่าchangelogซึ่งเก็บข้อมูลเกี่ยวกับการเปลี่ยนแปลง (แก้ไข) รวมถึงการกระทำข้อความและศูนย์พ่อแม่หนึ่งหรือสอง
Mercurial ใช้เจอร์นัลธุรกรรมเพื่อจัดเตรียมอะตอมมิกของการดำเนินการและอาศัยการตัดทอนไฟล์เพื่อล้างข้อมูลหลังจากการดำเนินการล้มเหลวหรือถูกขัดจังหวะ Revlogs เป็นแบบต่อท้ายเท่านั้น
เมื่อดูที่โครงสร้างของที่เก็บใน Git กับ Mercurial เราจะเห็นได้ว่า Git นั้นเป็นเหมือนฐานข้อมูลวัตถุ (หรือระบบไฟล์ที่แก้ไขเนื้อหา) และ Mercurial ก็เหมือนกับฐานข้อมูลเชิงสัมพันธ์คงที่แบบดั้งเดิม
ความแตกต่าง:
ใน Git วัตถุต้นไม้ในรูปแบบโครงสร้างลำดับชั้น ; ในไฟล์ Mercurial manifestเป็นโครงสร้างแบบแบน ในที่เก็บวัตถุGit blob หนึ่งรุ่นของเนื้อหาของไฟล์ ใน Mercurial filelogเก็บประวัติทั้งหมดของไฟล์เดียว (หากเราไม่ได้คำนึงถึงความซับซ้อนของการเปลี่ยนชื่อ) ซึ่งหมายความว่ามีพื้นที่ต่าง ๆ ของการดำเนินการที่ Git จะเร็วกว่า Mercurial ทุกสิ่งอื่น ๆ ถือว่าเท่าเทียมกัน (เช่นการรวมหรือแสดงประวัติของโครงการ) และพื้นที่ที่ Mercurial จะเร็วกว่า Git (เช่นการใช้แพทช์หรือการแสดง ประวัติของไฟล์เดียว)ปัญหานี้อาจไม่สำคัญสำหรับผู้ใช้
เนื่องจากโครงสร้างบันทึกคงที่ของโครงสร้างการเปลี่ยนแปลงของ Mercurial การกระทำใน Mercurial จึงสามารถมีผู้ปกครองได้สูงสุดสองคนเท่านั้น คอมมิทใน Git สามารถมีพ่อแม่ได้มากกว่าสองคน (เรียกว่า "octopus merge") ในขณะที่คุณสามารถ (ในทางทฤษฎี) แทนที่ octopus merge ด้วยชุดของการรวมกันของสองพาเรนต์ แต่สิ่งนี้อาจทำให้เกิดความยุ่งยากเมื่อทำการแปลงระหว่างที่เก็บ Mercurial และ Git
เท่าที่ฉันทราบ Mercurial ไม่มีแท็กหมายเหตุประกอบ (วัตถุแท็ก) จาก Git กรณีพิเศษของแท็กที่มีคำอธิบายประกอบเป็นแท็กที่ลงนามแล้ว (ที่มีลายเซ็น PGP / GPG); สามารถเทียบเท่าใน Mercurial ได้โดยใช้GpgExtensionส่วนขยายใดที่ถูกแจกจ่ายพร้อมกับ Mercurial คุณไม่สามารถติดแท็กวัตถุที่ไม่ส่งมอบใน Mercurial อย่างที่คุณสามารถทำได้ใน Git แต่นั่นไม่ใช่สิ่งที่สำคัญมากฉันคิดว่า (ที่เก็บ git บางแห่งใช้แท็ก blob เพื่อกระจายคีย์ PGP สาธารณะเพื่อใช้ยืนยันแท็กที่ลงนามแล้ว)
การอ้างอิง: สาขาและแท็ก
ในการอ้างอิง Git (สาขาสาขาและแท็กติดตามระยะไกล) อยู่นอก DAG ของการกระทำ (เท่าที่ควร) การอ้างอิงในrefs/heads/
namespace ( สาขาในพื้นที่ ) ชี้ไปที่การกระทำและมักจะมีการปรับปรุงโดย "git กระทำ"; พวกเขาชี้ไปที่ปลาย (หัว) ของสาขานั่นคือเหตุผลที่ชื่อดังกล่าว การอ้างอิงในrefs/remotes/<remotename>/
เนมสเปซ ( สาขาการติดตามระยะไกล ) ชี้ไปที่กระทำตามสาขาในที่เก็บระยะไกล<remotename>
และได้รับการอัปเดตโดย "git fetch" หรือเทียบเท่า การอ้างอิงในrefs/tags/
เนมสเปซ ( แท็ก ) มักจะชี้ไปที่คอมมิท (แท็กน้ำหนักเบา) หรือแท็กออบเจ็กต์ (แท็กที่ใส่หมายเหตุประกอบและลงนาม) และไม่ได้หมายถึงการเปลี่ยนแปลง
แท็ก
ใน Mercurial คุณสามารถให้ชื่อถาวรมีการแก้ไขโดยใช้แท็ก ; แท็กจะถูกจัดเก็บคล้ายกับรูปแบบการเพิกเฉย หมายความว่าแท็กที่มองเห็นได้ทั่วโลกจะถูกเก็บไว้ใน.hgtags
ไฟล์ที่มีการควบคุมการแก้ไขในพื้นที่เก็บข้อมูลของคุณ สิ่งนี้มีสองผล: อันดับแรก Mercurial จะต้องใช้กฎพิเศษสำหรับไฟล์นี้เพื่อรับรายการแท็กทั้งหมดและอัปเดตไฟล์ดังกล่าว (เช่นจะอ่านการแก้ไขไฟล์ที่ได้ทำไว้ล่าสุดไม่ได้ตรวจสอบเวอร์ชั่น) สองคุณต้องยอมรับการเปลี่ยนแปลงในไฟล์นี้เพื่อให้แท็กใหม่ปรากฏต่อผู้ใช้รายอื่น / ที่เก็บอื่น ๆ (เท่าที่ฉันเข้าใจ)
Mercurial ยังสนับสนุนแท็กท้องถิ่นที่เก็บไว้hg/localtags
ซึ่งไม่สามารถมองเห็นได้โดยผู้อื่น (และแน่นอนไม่สามารถถ่ายโอนได้)
ในแท็ก Git ได้รับการแก้ไข (ค่าคงที่) ชื่อการอ้างอิงไปยังวัตถุอื่น ๆ (โดยปกติคือวัตถุแท็กซึ่งจะถูกเก็บไว้ในrefs/tags/
เนมสเปซ ตามค่าเริ่มต้นเมื่อดึงหรือผลักดันชุดการแก้ไข git จะดึงหรือดันแท็กโดยอัตโนมัติซึ่งจะชี้ไปยังการแก้ไขที่ถูกดึงหรือผลัก อย่างไรก็ตามคุณสามารถควบคุมได้บ้างว่าแท็กใดที่ดึงหรือผลักดัน
Git ปฏิบัติแท็กที่มีน้ำหนักเบา (ชี้ไปที่การคอมมิทโดยตรง) และแท็กที่มีคำอธิบายประกอบ (การชี้ไปที่วัตถุแท็กซึ่งมีข้อความแท็กซึ่งรวมถึงลายเซ็น PGP ซึ่งในทางกลับกันที่จะยอมรับ) แตกต่างกันเล็กน้อย กระทำโดยใช้ "git อธิบาย"
Git ไม่มีแท็กท้องถิ่นที่เทียบเท่าใน Mercurial อย่างไรก็ตามแนวทางปฏิบัติที่ดีที่สุดของคอมไพล์แนะนำให้ตั้งค่าพื้นที่เก็บข้อมูลสาธารณะที่แยกต่างหากซึ่งคุณผลักดันการเปลี่ยนแปลงที่พร้อมและจากที่คนอื่นโคลนและดึงข้อมูล ซึ่งหมายความว่าแท็ก (และสาขา) ที่คุณไม่ได้กดเป็นส่วนตัวกับที่เก็บของคุณ บนมืออื่น ๆ คุณยังสามารถใช้ namespace อื่น ๆ กว่าheads
, remotes
หรือtags
ตัวอย่างเช่นlocal-tags
สำหรับแท็กท้องถิ่น
ความเห็นส่วนตัว:ในแท็กความคิดเห็นของฉันควรอยู่นอกกราฟการแก้ไขเนื่องจากมันเป็นสิ่งภายนอก (เป็นตัวชี้ไปยังกราฟการแก้ไข) แท็กควรไม่มีเวอร์ชัน แต่สามารถถ่ายโอนได้ ทางเลือกของ Mercurial ในการใช้กลไกที่คล้ายคลึงกับการละเว้นไฟล์หมายความว่ามันต้องปฏิบัติต่อ.hgtags
เป็นพิเศษ (ไฟล์ในทรีสามารถถ่ายโอนได้ แต่โดยทั่วไปจะเป็นเวอร์ชัน) หรือมีแท็กที่เป็นแบบโลคัลเท่านั้น ( .hg/localtags
ไม่ใช่เวอร์ชัน) แต่ไม่สามารถโอนได้)
สาขา
ในสาขาท้องถิ่น Git (ส่วนปลายของสาขาหรือหัวหน้าสาขา) เป็นการอ้างอิงที่มีชื่อถึงการกระทำที่หนึ่งสามารถเติบโตได้ใหม่ สาขายังหมายถึงสายการพัฒนาที่ใช้งานอยู่นั่นคือทั้งหมดที่กระทำสามารถเข้าถึงได้จากปลายสาขา สาขาในพื้นที่นั้นอยู่ในrefs/heads/
เนมสเปซดังนั้นเช่นชื่อเต็มของสาขา 'ต้นแบบ' คือ 'refs / heads / master'
สาขาปัจจุบันใน Git (หมายถึงสาขาที่เช็กเอาต์และสาขาที่การส่งมอบใหม่จะดำเนินการ) เป็นสาขาที่อ้างอิงโดยการอ้างอิง HEAD หนึ่งสามารถให้ HEAD ชี้ไปที่การกระทำโดยตรงแทนที่จะเป็นสัญลักษณ์อ้างอิง; สถานการณ์ของการอยู่ในสาขาที่ไม่ระบุชื่อนี้เรียกว่าHEAD HEAD ("สาขา git" แสดงให้เห็นว่าคุณอยู่ใน '(ไม่มีสาขา)')
ใน Mercurial มีสาขาที่ไม่ระบุชื่อ (หัวสาขา) และสามารถใช้บุ๊กมาร์กได้ (ผ่านส่วนขยายบุ๊กมาร์ก ) สาขาบุ๊กมาร์กดังกล่าวล้วน แต่อยู่ในพื้นที่ล้วนๆและชื่อเหล่านั้น (จนถึงเวอร์ชัน 1.6) ไม่สามารถถ่ายโอนได้โดยใช้ Mercurial คุณสามารถใช้ rsync หรือ scp เพื่อคัดลอก.hg/bookmarks
ไฟล์ไปยังที่เก็บระยะไกล คุณยังสามารถใช้hg id -r <bookmark> <url>
เพื่อรับรหัสการแก้ไขของเคล็ดลับปัจจุบันของบุ๊คมาร์ค
ตั้งแต่ 1.6 ที่คั่นหน้าสามารถผลัก / ดึง BookmarksExtensionหน้ามีส่วนในการทำงานกับที่เก็บระยะไกล มีความแตกต่างในการที่ชื่อ Mercurial bookmark เป็นglobalในขณะที่คำจำกัดความของ 'remote' ใน Git อธิบายถึงการแมปชื่อสาขาจากชื่อใน repository ระยะไกลกับชื่อของ Branch-tracking remote ตัวอย่างเช่นrefs/heads/*:refs/remotes/origin/*
การทำแผนที่หมายความว่าเราสามารถค้นหาสถานะของ 'master' branch ('refs / heads / master') ใน repository ระยะไกลใน 'origin / master' remote-tracking branch ('refs / remotes / origin / master')
Mercurial ก็มีชื่อเรียกอีกชื่อหนึ่งว่ากิ่งซึ่งฝังอยู่ในคอมมิชชัน (ในเซ็ตการแก้ไข) ชื่อดังกล่าวเป็นสากล (ถ่ายโอนเมื่อดึงข้อมูล) ชื่อสาขาเหล่านั้นจะถูกบันทึกอย่างถาวรเป็นส่วนหนึ่งของเมตาดาต้าเซ็ตการแก้ไข \ u2019s ด้วย Mercurial ที่ทันสมัยคุณสามารถปิด "branch branch" และหยุดการบันทึกชื่อ branch ในกลไกนี้เคล็ดลับของกิ่งไม้จะถูกคำนวณทันที
ในความคิดของฉัน "Mercuryial" ควรได้รับการขนานนามว่าเป็นฉลากแทนเพราะมันคือสิ่งที่พวกเขาเป็น มีสถานการณ์ที่ "สาขาที่มีชื่อ" สามารถมีเคล็ดลับได้หลายอย่าง (หลายลูกที่ไม่มีสัญญา) และยังสามารถประกอบด้วยกราฟที่ไม่ปะติดปะต่อหลายส่วน
ไม่มีอะไรเทียบเท่า Mercurial "กิ่งก้านสาขาที่ฝังตัว" ใน Git; ยิ่งไปกว่านั้นปรัชญาของ Git คือในขณะที่บางคนสามารถพูดได้ว่าสาขานั้นมีการกระทำบางอย่าง แต่ก็ไม่ได้หมายความว่าการกระทำนั้นเป็นของสาขา
โปรดทราบว่าเอกสาร Mercurial ยังเสนอที่จะใช้โคลนแยกต่างหาก (เก็บที่แยกต่างหาก) อย่างน้อยสำหรับสาขายาวอาศัยอยู่ (สาขาเดียวต่อพื้นที่เก็บข้อมูลขั้นตอนการทำงาน) หรือที่รู้จักแตกแขนงจากโคลน
สาขาในการผลักดัน
Mercurial โดยค่าเริ่มต้นผลักดันให้ทุกหัว หากคุณต้องการดันสาขาเดียว ( หัวเดียว ) คุณต้องระบุการแก้ไขเคล็ดลับของสาขาที่คุณต้องการดัน คุณสามารถระบุเคล็ดลับสาขาด้วยหมายเลขการตรวจทานแก้ไข (ภายในเครื่องไปยังที่เก็บข้อมูล) โดยการตรวจทานแก้ไขโดยใช้ชื่อบุ๊กมาร์ก (ภายในเครื่องไปยังที่เก็บข้อมูลไม่ได้รับการโอนย้าย)
เท่าที่ฉันเข้าใจถ้าคุณผลักช่วงของการแก้ไขที่มีการทำเครื่องหมายว่าอยู่ใน "สาขาที่มีชื่อ" ใน Mercurial parlance คุณจะมี "สาขาที่มีชื่อ" นี้ในที่เก็บที่คุณกดไป ซึ่งหมายความว่าชื่อของสาขาที่ฝัง (เช่นชื่อสาขา) เป็นชื่อโกลบอล (เทียบกับโคลนของพื้นที่เก็บข้อมูล / โครงการที่กำหนด)
ตามค่าเริ่มต้น (ขึ้นอยู่กับpush.default
ตัวแปรการกำหนดค่า) "git push" หรือ "git push < remote >" Git จะผลักดันกิ่งไม้ที่ตรงกันเช่นเฉพาะสาขาในท้องถิ่นที่มีค่าเทียบเท่าที่มีอยู่แล้วในที่เก็บระยะไกลที่คุณกด คุณสามารถใช้--all
ตัวเลือกในการ git-push ("git push - all ") เพื่อกดทุกสาขาคุณสามารถใช้ "git push < remote > < branch >" เพื่อกดสาขาเดียวที่กำหนดและคุณสามารถใช้ "git push < ระยะไกล > HEAD" ที่จะผลักดันสาขาในปัจจุบัน
จากทั้งหมดที่กล่าวมาข้างต้นถือว่า Git ไม่ได้กำหนดค่าที่จะผลักดันผ่านremote.<remotename>.push
ตัวแปรการกำหนดค่า
สาขาในการดึง
หมายเหตุ:ที่นี่ฉันใช้คำศัพท์ Git โดยที่ "การดึงข้อมูล" หมายถึงการดาวน์โหลดการเปลี่ยนแปลงจากที่เก็บระยะไกลโดยไม่ต้องรวมการเปลี่ยนแปลงเหล่านั้นกับงานในท้องถิ่น นี่คือสิ่งที่ " git fetch
" และ " hg pull
" ทำ
ถ้าผมเข้าใจอย่างถูกต้องตามค่าเริ่มต้น Mercurial เรียกทุกหัวจากพื้นที่เก็บข้อมูลระยะไกล แต่คุณสามารถระบุสาขาสามารถดึงข้อมูลผ่านทาง " hg pull --rev <rev> <url>
" หรือ " hg pull <url>#<rev>
" เพื่อให้ได้สาขาเดียว คุณสามารถระบุ <rev> โดยใช้ตัวระบุการแก้ไขชื่อ "named branch" (branch ที่ฝังใน changelog) หรือชื่อบุ๊กมาร์ก ชื่อบุ๊กมาร์ก (อย่างน้อยปัจจุบัน) ไม่ได้รับการถ่ายโอน การแก้ไข "สาขาที่มีชื่อ" ทั้งหมดที่คุณได้รับจะถูกโอนไป "hg pull" เก็บเคล็ดลับของสาขาที่ดึงมาเป็นแบบไม่ระบุชื่อและไม่มีชื่อ
ใน Git โดยค่าเริ่มต้น (สำหรับรีโมต 'ต้นทาง' สร้างโดย "git clone" และสำหรับรีโมตที่สร้างโดยใช้ "git remote add") " git fetch
" (หรือ " git fetch <remote>
") รับสาขาทั้งหมดจากที่เก็บระยะไกล (จากrefs/heads/
เนมสเปซ) และเก็บไว้ในrefs/remotes/
namespace ซึ่งหมายความว่าตัวอย่างเช่นสาขาที่ชื่อ 'master' (ชื่อเต็ม: 'refs / heads / master') ใน 'แหล่งกำเนิด' ระยะไกล 'จะถูกเก็บไว้ (บันทึก) เป็น' แหล่งกำเนิด / ต้นแบบ ' สาขาติดตามระยะไกล (ชื่อเต็ม:' refs / รีโมท / กำเนิด / โท)
คุณสามารถดึงข้อมูลสาขาเดียวใน Git ได้โดยใช้git fetch <remote> <branch>
- Git จะเก็บสาขาที่ร้องขอใน FETCH_HEAD ซึ่งเป็นสิ่งที่คล้ายกับ Mercurial heads ที่ไม่มีชื่อ
สิ่งเหล่านี้เป็นเพียงตัวอย่างของกรณีเริ่มต้นของไวยากรณ์ Git refspec ที่มีประสิทธิภาพ: ด้วย refspecs คุณสามารถระบุและ / หรือกำหนดค่าว่าสาขาใดที่ต้องการดึงข้อมูลและสถานที่จัดเก็บ ตัวอย่างเช่นค่าเริ่มต้น "ดึงทุกสาขา" จะแสดงด้วย '+ refs / heads / *: refs / remotes / origin / *' wildcard refspec และ "fetch single branch" นั้นย่อมาจาก 'refs / heads / <branch>:' . Refspecs ใช้เพื่อแม็พชื่อของ branch (refs) ในที่เก็บรีโมตกับชื่อ refs ท้องถิ่น แต่คุณไม่จำเป็นต้องรู้ (มาก) เกี่ยวกับ refspec เพื่อให้สามารถทำงานได้อย่างมีประสิทธิภาพกับ Git (ขอบคุณคำสั่ง "git remote" เป็นหลัก)
ความเห็นส่วนตัว:ส่วนตัวแล้วฉันคิดว่า "การตั้งชื่อสาขา" (ด้วยชื่อสาขาที่ฝังอยู่ในเมตาดาต้าเซ็ตการแก้ไข) ใน Mercurial นั้นเป็นการออกแบบที่เข้าใจผิดกับเนมสเปซทั่วโลกโดยเฉพาะอย่างยิ่งสำหรับระบบควบคุมเวอร์ชันกระจาย ตัวอย่างเช่นลองดูว่าทั้ง Alice และ Bob มี "branch branch" ชื่อ 'for-joe' ในที่เก็บของพวกเขาสาขาที่ไม่มีอะไรเหมือนกัน ในพื้นที่เก็บข้อมูลของโจ แต่ทั้งสองสาขาจะถูกทำร้ายเป็นสาขาเดียว ดังนั้นคุณจะมีวิธีป้องกันอนุสัญญาชื่อสาขา นี่ไม่ใช่ปัญหาของ Git ซึ่งในที่เก็บของโจสาขา 'for-joe' จากอลิซจะเป็น 'alice / for-joe' และจาก Bob มันจะเป็น 'bob / for-joe'
"สาขาบุ๊กมาร์ก" ของ Mercurial ในปัจจุบันขาดกลไกการกระจายในแกน
ความแตกต่าง:
พื้นที่นี้เป็นหนึ่งในความแตกต่างที่สำคัญระหว่าง Mercurial และ Git ขณะที่James woodyattและSteve Loshกล่าวในคำตอบของพวกเขา โดยค่าเริ่มต้น Mercurial ใช้ codelines ที่ไม่ระบุชื่อเบาซึ่งในคำศัพท์เรียกว่า "หัว" Git ใช้กิ่งไม้ที่มีน้ำหนักเบาพร้อมการแมปแบบหัวฉีดเพื่อแมปชื่อสาขาในที่เก็บระยะไกลกับชื่อของสาขาการติดตามระยะไกล Git "บังคับ" ให้คุณตั้งชื่อกิ่ง (ดียกเว้นสาขาที่ไม่มีชื่อเดียวสถานการณ์ที่เรียกว่า HEAD HEAD) แต่ฉันคิดว่าวิธีนี้จะทำงานได้ดีขึ้นด้วยเวิร์กโฟลว์สาขาที่หนักเช่นเวิร์กโฟลว์สาขาหัวข้อซึ่งหมายถึงหลายสาขาในกระบวนทัศน์พื้นที่เก็บข้อมูลเดียว
การแก้ไขการตั้งชื่อ
ใน Git มีหลายวิธีในการตั้งชื่อการแก้ไข (อธิบายเช่นในgit rev-parse manpage):
- ชื่อวัตถุ SHA1 แบบเต็ม (สตริงเลขฐานสิบหก 40- ไบต์) หรือสตริงย่อยที่ไม่ซ้ำกันภายในที่เก็บ
- ชื่ออ้างอิงสัญลักษณ์เช่น 'master' (หมายถึงสาขา 'master') หรือ 'v1.5.0' (หมายถึงแท็ก) หรือ 'origin / next' (อ้างอิงสาขาติดตามระยะไกล)
- ส่วนต่อท้าย
^
เพื่อแก้ไขพารามิเตอร์หมายถึงผู้ปกครองแรกของวัตถุกระทำ^n
หมายถึงผู้ปกครองที่ n ของการผสานกระทำ ส่วนต่อท้าย~n
ไปยังพารามิเตอร์การแก้ไขหมายถึงบรรพบุรุษของ n-th ของการกระทำในสายพ่อแม่แรกตรง คำต่อท้ายเหล่านั้นสามารถนำมารวมกันเพื่อสร้างตัวระบุการแก้ไขต่อไปนี้เส้นทางจากการอ้างอิงสัญลักษณ์เช่น 'pu ~ 3 ^ 2 ~ 3'
- เอาท์พุทของ "git อธิบาย" คือแท็กที่ใกล้เคียงที่สุดเลือกตามด้วยเครื่องหมายขีดกลางและจำนวนของการกระทำตามด้วยเครื่องหมายขีดกลาง 'g' และชื่อวัตถุย่อตัวอย่างเช่น 'v1.6.5.1-75- g5bf8097'
นอกจากนี้ยังมีตัวระบุการแก้ไขที่เกี่ยวข้องกับ reflog ไม่ได้กล่าวถึงที่นี่ ใน Git แต่ละวัตถุไม่ว่าจะกระทำแท็กต้นไม้หรือหยดมีตัวระบุ SHA-1 มีไวยากรณ์พิเศษเช่น 'next: Documentation' หรือ 'next: README' เพื่ออ้างถึง tree (directory) หรือ blob (เนื้อหาไฟล์) ตามการแก้ไขที่ระบุ
Mercurial มีหลายวิธีในการตั้งชื่อเซ็ตการแก้ไข (อธิบายเช่นในhg manpage):
- จำนวนเต็มธรรมดาจะถือว่าเป็นหมายเลขการแก้ไข หนึ่งต้องจำไว้ว่าตัวเลขการแก้ไขที่มีในท้องถิ่นเพื่อให้พื้นที่เก็บข้อมูล ; ในพื้นที่เก็บข้อมูลอื่น ๆ พวกเขาอาจแตกต่างกัน
- จำนวนเต็มลบจะถือเป็นออฟเซ็ตตามลำดับจากปลายด้วย -1 แสดงถึงเคล็ดลับ -2 แสดงถึงการแก้ไขก่อนหน้าเคล็ดลับและอื่น ๆ พวกเขายังท้องถิ่นเพื่อพื้นที่เก็บข้อมูล
- ตัวระบุการแก้ไขที่ไม่ซ้ำกัน (สตริงเลขฐานสิบหก 40 หลัก) หรือคำนำหน้าเฉพาะ
- ชื่อแท็ก (ชื่อสัญลักษณ์ที่เชื่อมโยงกับการแก้ไขที่กำหนด) หรือชื่อบุ๊กมาร์ก (พร้อมส่วนขยาย: ชื่อสัญลักษณ์ที่เชื่อมโยงกับส่วนหัวที่กำหนดพื้นที่ในพื้นที่เก็บข้อมูล) หรือ "branch branch" (กระทำ label; ทิป (การกระทำที่ไม่มีลูก) ของการกระทำทั้งหมดที่มีป้ายกำกับการส่งมอบที่มีหมายเลขการแก้ไขที่ใหญ่ที่สุดหากมีมากกว่าหนึ่งเคล็ดลับดังกล่าว)
- ชื่อ "เคล็ดลับ" ที่สงวนไว้เป็นแท็กพิเศษที่ระบุการแก้ไขล่าสุดเสมอ
- ชื่อสงวน "null" หมายถึงการแก้ไขว่าง
- ชื่อที่สงวนไว้ "." บ่งบอกถึงไดเรกทอรีไดเรกทอรีการทำงาน
ความแตกต่างดัง
ที่คุณเห็นการเปรียบเทียบรายการด้านบน Mercurial เสนอหมายเลขการแก้ไขท้องถิ่นกับที่เก็บในขณะที่ Git ไม่มี ในทางกลับกัน Mercurial เสนอการชดเชยแบบสัมพัทธ์เฉพาะจาก 'เคล็ดลับ' (สาขาปัจจุบัน) ซึ่งอยู่ในพื้นที่เก็บข้อมูล (อย่างน้อยไม่มีParentrevspecExtension ) ในขณะที่ Git อนุญาตให้ระบุการกระทำใด ๆ ต่อไปนี้จากเคล็ดลับใด ๆ
การแก้ไขล่าสุดชื่อ HEAD ใน Git และ "เคล็ดลับ" ใน Mercurial ไม่มีการแก้ไขว่างเปล่าใน Git ทั้ง Mercurial และ Git สามารถมีได้หลายรูท (สามารถมีคอมมิทมากกว่าหนึ่งคอมเมิร์ซซึ่งโดยปกติจะเป็นผลมาจากโปรเจ็กต์ที่แยกจากกันก่อนหน้านี้)
ดูเพิ่มเติมที่: บทความตัวแก้ไขการแก้ไขประเภทต่าง ๆ มากมายบนบล็อกของ Elijah (ของใหม่)
ความเห็นส่วนตัว:ฉันคิดว่าตัวเลขการแก้ไขมีการประเมินค่ามากเกินไป (อย่างน้อยสำหรับการพัฒนาแบบกระจายและ / หรือประวัติที่ไม่เป็นเชิงเส้น / แตกกิ่ง) ขั้นแรกสำหรับระบบควบคุมเวอร์ชันแบบกระจายพวกเขาต้องเป็นแบบโลคัลไปยังที่เก็บหรือต้องการการจัดการที่เก็บบางส่วนในวิธีพิเศษในฐานะหน่วยงานการกำหนดหมายเลขกลาง ประการที่สองโครงการขนาดใหญ่ที่มีประวัติยาวนานขึ้นสามารถมีจำนวนการแก้ไขในช่วง 5 หลักดังนั้นจึงมีข้อได้เปรียบเล็กน้อยเพียงเล็กน้อยเมื่อเทียบกับตัวระบุการแก้ไขสั้น ๆ ถึง 6-7 ตัวอักษรและบ่งบอกถึงการสั่งซื้อที่เข้มงวดในขณะที่ การแก้ไข n และ n + 1 ไม่จำเป็นต้องเป็น parent และ child)
ช่วงการแก้ไข
ในช่วงการแก้ไข Git เป็นทอพอโลยี ปกติเห็นA..B
ไวยากรณ์ซึ่งสำหรับการเชิงเส้นประวัติศาสตร์หมายถึงช่วงการแก้ไขเริ่มต้นที่ A ( แต่ไม่รวม A) และสิ้นสุดที่ B (ช่วงคือคือเปิดจากด้านล่าง ) เป็นชวเลข ( "น้ำตาลประโยค") สำหรับ^A B
ซึ่งสำหรับประวัติคำสั่ง traversing หมายถึงทั้งหมด กระทำการที่สามารถเข้าถึงได้จาก B ยกเว้นสิ่งที่สามารถเข้าถึงได้จาก A. ซึ่งหมายความว่าพฤติกรรมของA..B
ช่วงนั้นสามารถคาดเดาได้ทั้งหมด (และค่อนข้างมีประโยชน์) แม้ว่า A จะไม่ใช่บรรพบุรุษของ B: A..B
หมายถึงช่วงของการแก้ไขจากบรรพบุรุษร่วมของ A และ B ) เพื่อแก้ไข B.
ในช่วง Mercurial แก้ไขจะขึ้นอยู่กับช่วงของตัวเลขการแก้ไข ช่วงที่มีการระบุโดยใช้A:B
ไวยากรณ์และขัดกับช่วง Git ทำหน้าที่เป็นช่วงเวลาปิด นอกจากนี้ช่วง B: A คือช่วง A: B ในลำดับย้อนกลับซึ่งไม่ได้เป็นกรณีใน Git (แต่ดูด้านล่างทราบเกี่ยวกับA...B
ไวยากรณ์) แต่ความเรียบง่ายดังกล่าวมาพร้อมกับราคา: ช่วงการแก้ไข A: B เหมาะสมถ้าหาก A เป็นบรรพบุรุษของ B หรือในทางกลับกันเช่นมีประวัติเชิงเส้น มิฉะนั้น (ฉันเดาว่า) ช่วงนั้นไม่สามารถคาดเดาได้และผลลัพธ์จะอยู่ในพื้นที่เก็บข้อมูล (เนื่องจากหมายเลขการแก้ไขนั้นอยู่ในพื้นที่เก็บข้อมูล)
สิ่งนี้ได้รับการแก้ไขด้วย Mercurial 1.6 ซึ่งมีช่วงการแก้ไขใหม่ของโทโพโลยีที่เข้าใจว่า 'A .. B' (หรือ 'A :: B') เป็นชุดการเปลี่ยนแปลงที่เป็นทั้งลูกหลานของ X และบรรพบุรุษของ Y นี่คือ ฉันเดาว่าเทียบเท่ากับ '--ancestry-path A..B' ใน Git
Git ยังมีสัญลักษณ์A...B
สำหรับความแตกต่างที่สมมาตรของการแก้ไข; มันหมายถึงA B --not $(git merge-base A B)
ซึ่งหมายความว่าทุกคนสามารถเข้าถึงได้จาก A หรือ B แต่ไม่รวมถึงการกระทำทั้งหมดที่สามารถเข้าถึงได้จากทั้งสอง (เข้าถึงได้จากบรรพบุรุษร่วมกัน)
เปลี่ยนชื่อ
Mercurial ใช้การติดตามการเปลี่ยนชื่อเพื่อจัดการกับการเปลี่ยนชื่อไฟล์ ซึ่งหมายความว่าข้อมูลเกี่ยวกับความจริงที่ว่าไฟล์ถูกเปลี่ยนชื่อจะถูกบันทึกในเวลากระทำ; ใน Mercurial ข้อมูลนี้จะถูกบันทึกในฟอร์ม "Enhanced diff" ในเมตาดาต้าfilelog (ไฟล์ revlog) ผลของสิ่งนี้คือคุณต้องใช้hg rename
/ hg mv
... หรือคุณต้องจำไว้ว่าhg addremove
ให้ทำการตรวจจับการเปลี่ยนชื่อตามความคล้ายคลึงกัน
Git นั้นไม่เหมือนใครในระบบควบคุมเวอร์ชันซึ่งใช้การตรวจจับการเปลี่ยนชื่อเพื่อจัดการกับการเปลี่ยนชื่อไฟล์ ซึ่งหมายความว่ามีการตรวจพบความจริงที่ว่าไฟล์ถูกเปลี่ยนชื่อในเวลาที่ต้องการ: เมื่อทำการผสานหรือเมื่อแสดง diff (ถ้ามีการร้องขอ / กำหนดค่า) นี่เป็นข้อดีที่อัลกอริทึมการตรวจจับการเปลี่ยนชื่อสามารถปรับปรุงได้และจะไม่หยุดชะงักในขณะที่ส่งมอบ
ทั้ง Git และ Mercurial จำเป็นต้องใช้--follow
ตัวเลือกในการติดตามการเปลี่ยนชื่อเมื่อแสดงประวัติของไฟล์เดียว ทั้งสองสามารถทำตามการเปลี่ยนชื่อเมื่อแสดงประวัติศาสตร์บรรทัดที่ชาญฉลาดของไฟล์ใน/git blame
hg annotate
ใน Git git blame
คำสั่งสามารถติดตามการเคลื่อนไหวของโค้ดย้ายรหัส (หรือคัดลอก) จากไฟล์หนึ่งไปยังอีกไฟล์แม้ว่าการเคลื่อนไหวของรหัสไม่ได้เป็นส่วนหนึ่งของการเปลี่ยนชื่อไฟล์ที่เป็นประโยชน์ เท่าที่ฉันรู้ว่าคุณสมบัตินี้เป็นเอกลักษณ์ของ Git (ในขณะที่เขียนตุลาคม 2009)
โปรโตคอลเครือข่าย
ทั้ง Mercurial และ Git มีการรองรับการดึงและผลักดันไปยังที่เก็บบนระบบไฟล์เดียวกันโดยที่ URL ที่เก็บเป็นเพียงเส้นทางของระบบไฟล์ไปยังที่เก็บ ทั้งยังรองรับการดึงข้อมูลจากไฟล์บันเดิล
การสนับสนุน Mercurial การดึงและผลักดันผ่าน SSH และผ่านโปรโตคอล HTTP สำหรับ SSH ต้องมีบัญชีเชลล์ที่สามารถเข้าถึงได้บนเครื่องปลายทางและสำเนาของ hg ที่ติดตั้ง / พร้อมใช้งาน สำหรับการเข้าถึง HTTP hg-serve
จำเป็นต้องใช้สคริปต์รันหรือ Mercurial CGI และจำเป็นต้องติดตั้ง Mercurial บนเครื่องเซิร์ฟเวอร์
Git รองรับโปรโตคอลสองชนิดที่ใช้ในการเข้าถึงที่เก็บระยะไกล:
- โปรโตคอล "สมาร์ท"ซึ่งรวมถึงการเข้าถึงผ่าน SSH และผ่าน git: // โพรโทคอลที่กำหนดเอง (โดย
git-daemon
) ต้องมีการติดตั้ง git บนเซิร์ฟเวอร์ การแลกเปลี่ยนในโปรโตคอลเหล่านั้นประกอบด้วยไคลเอนต์และเซิร์ฟเวอร์เจรจาเกี่ยวกับวัตถุใดที่พวกเขามีเหมือนกันจากนั้นสร้างและส่ง packfile Modern Git มีการรองรับโปรโตคอล HTTP "smart"
- โปรโตคอล "โง่"ซึ่งรวมถึง HTTP และ FTP (เฉพาะสำหรับการเรียก) และ HTTPS (สำหรับการผลักดันผ่าน WebDAV) ไม่จำเป็นต้องคอมไพล์ติดตั้งบนเซิร์ฟเวอร์ แต่พวกเขาจะต้องใช้พื้นที่เก็บข้อมูลที่มีข้อมูลพิเศษที่สร้างขึ้นโดย
git update-server-info
(มักจะวิ่งออกจากเบ็ด ) การแลกเปลี่ยนประกอบด้วยไคลเอนต์ที่เดินผ่านเชนส่งมอบและดาวน์โหลดวัตถุหลวมและไฟล์แพ็คตามต้องการ ข้อเสียคือมันดาวน์โหลดมากกว่าที่ต้องการอย่างเคร่งครัด (เช่นในมุมที่มีไฟล์แพ็คเพียงไฟล์เดียวมันจะดาวน์โหลดทั้งหมดแม้เมื่อดึงไฟล์เพียงไม่กี่ครั้งเท่านั้น) และต้องใช้การเชื่อมต่อหลายอย่างเพื่อให้เสร็จสิ้น
ขยาย: scriptability vs extensions (ปลั๊กอิน)
Mercurial มีการนำมาใช้ในPythonโดยมีคอร์โค้ดบางตัวที่เขียนด้วย C เพื่อประสิทธิภาพ มันมี API สำหรับการเขียนส่วนขยาย (ปลั๊กอิน) เป็นวิธีการเพิ่มคุณสมบัติพิเศษ ฟังก์ชั่นบางอย่างเช่น "สาขาบุ๊กมาร์ก" หรือการแก้ไขการเซ็นชื่อมีให้ในส่วนขยายที่กระจายด้วย Mercurial และต้องเปิดใช้งาน
Git จะดำเนินการในC , Perlและเชลล์สคริปต์ Git มีคำสั่งระดับต่ำจำนวนมาก ( ระบบประปา ) ที่เหมาะสมสำหรับใช้ในสคริปต์ ทางปกติของการแนะนำคุณสมบัติใหม่คือการเขียนเป็น Perl หรือเชลล์สคริปต์และเมื่อส่วนติดต่อผู้ใช้รักษาเขียนมันใน C สำหรับประสิทธิภาพการพกพาและในกรณีของเชลล์สคริปต์หลีกเลี่ยงกรณีมุม (ขั้นตอนนี้จะเรียกว่าbuiltinification )
Git อาศัยและสร้างขึ้นในรูปแบบ [พื้นที่เก็บข้อมูล] และ [เครือข่าย] โปรโตคอล แทนที่จะใช้การผูกภาษามีการใช้ Git (บางส่วนหรือทั้งหมด) ในภาษาอื่น (บางส่วนเป็นการนำไปใช้ใหม่บางส่วนและบางส่วนล้อมรอบคำสั่ง git): JGit (Java ใช้โดย EGit, Eclipse Git Plugin), Grit (Ruby) , Dulwich (Python), git # (C #)
TL; DR