การจัดการเวอร์ชันด้วย Mercurial ปฏิบัติการเกี่ยวกับวิศวกรรมคอมพิวเตอร์ (01204223) ผศ.ดร.ชัยพร ใจแก้ว ภาควิชาวิศวกรรมคอมพิวเตอร์ คณะวิศวกรรมศาสตร์ มหาวิทยาลัยเกษตรศาสตร์
ตัวอย่าง Development Timeline revision 1: แก้บั๊ก X revision 2: แก้บั๊ก Y revision 5: แก้บั๊ก Z Development Timeline revision 0: เวอร์ชันแรกสุด revision 3: เพิ่มฟีเจอร์ A revision 4: เพิ่มฟีเจอร์ B ปัจจุบัน: (ยังไม่เก็บเป็น revision)
ตัวอย่างซอฟต์แวร์จัดการเวอร์ชัน แบบรวมศูนย์ (มี repo* กลางที่เดียว) CVS – Concurrent Versions System SVN – Apache Subversion แบบกระจาย (repo ติดอยู่กับผู้พัฒนา) Git Mercurial Repo ผู้พัฒนา ผู้พัฒนา ผู้พัฒนา Repo ผู้พัฒนา Repo ผู้พัฒนา Repo ผู้พัฒนา Repo ผู้พัฒนา *Repo = Repository - คลังเก็บเวอร์ชัน
Workflow ระบบจัดการเวอร์ชันแบบรวมศูนย์ (centralized version control system) ระบบจัดการเวอร์ชันแบบกระจาย (distributed version control system) Repo update commit update commit ผู้พัฒนา src code ผู้พัฒนา src code commit/update commit/update push / pull / clone src code Repo ผู้พัฒนา src code Repo ผู้พัฒนา
Mercurial ซอฟต์แวร์จัดการเวอร์ชันแบบกระจาย สั่งงานด้วย Command-Line มี GUI frontend มากมาย TortoiseHg (Windows/Linux/Mac OS) MacHg (Mac OS X 10.6+) ดูเพิ่มเติมที่ http://mercurial.selenic.com/wiki/OtherTools
ส่วนประกอบหลักของการจัดการเวอร์ชัน ข้อความสรุปการแก้ไข (commit message) ชื่อผู้ที่แก้ไข เวลาที่แก้ รายการรีวิชัน รายละเอียดรีวิชัน ไฟล์ที่มีการเปลี่ยนแปลง revision = changeset
เตรียมตัวใช้ Mercurial สร้างไฟล์ .hgrc ในโฮมไดเรคเตอรีของตนเพื่อระบุชื่อและอีเมล์ กรอกข้อมูลต่อไปนี้ลงในไฟล์ โดยใส่ชื่อและอีเมล์ตามความเป็นจริง ชื่อนี้จะถูกบันทึกเป็นผู้จัดเก็บรีวิชัน [ui] username = Firstname Lastname <email@some.where>
จัดการเวอร์ชันให้ myweb สร้าง mercurial repository ในไดเรคตอรี myweb บอก mercurial ให้ไม่ต้องสนใจไฟล์ *.pyc สร้างไฟล์ .hgignore ไว้ใน myweb โดยมีข้อความ $ cd myweb $ hg init syntax: glob *.pyc
ตรวจสอบสถานะการจัดการเวอร์ชัน ใช้คำสั่ง hg status เพื่อดูสถานะการจัดการเวอร์ชันของไฟล์ในโปรเจ็ค $ hg status ? .hgignore ? __init__.py ? manage.py ? settings.py ? shape/__init__.py ? shape/models.py ? shape/tests.py ? shape/views.py ? templates/index.html ? templates/rectangle.html ? templates/result.html ? urls.py เครื่องหมาย ? แสดงถึงการที่ไฟล์นั้นยังไม่ถูกจัดการเวอร์ชัน
ระบุไฟล์ที่ต้องการจัดการเวอร์ชัน คำสั่ง hg add ใช้บอกให้ mercurial เริ่มจัดการเวอร์ชันให้ไฟล์ เพิ่มไฟล์ทั้งหมดที่ยังไม่ถูกจัดการเวอร์ชัน เพิ่มโดยระบุชื่อไฟล์ เพิ่มไฟล์ *.py ทุกไฟล์ในไดเรคตอรีปัจจุบัน เพิ่มไฟล์ *.py ทุกไฟล์ในไดเรคตอรีปัจจุบันและซับไดเรคตอรีทั้งหมด เพิ่มไฟล์ทุกไฟล์ที่ยังไม่ถูกจัดการ ยกเว้นไฟล์ที่ลงท้ายด้วย .html $ hg add $ hg add manage.py settings.py $ hg add -I '*.py' $ hg add -I '**.py' $ hg add -X '**.html'
Commit - บันทึกรีวิชัน ควรตรวจสอบสถานะไฟล์ก่อนโดยใช้คำสั่ง status $ hg status A .hgignore A __init__.py A manage.py A settings.py A shape/__init__.py A shape/models.py A shape/tests.py A shape/views.py A templates/index.html A templates/rectangle.html A templates/result.html A urls.py $ hg commit –m "First revision" $ Commit Message หรือข้อความแสดงการแก้ไข ควรให้กระชับและได้ใจความ เช่น "Fix bug …" "Add feature …" ผลลัพธ์จาก hg status แสดงให้เห็นว่าไม่เหลือไฟล์ที่ถูกแก้ไขแต่ยังไม่ได้เก็บลงเป็นรีวิชัน
Commit แบบเลือกไฟล์ เราไม่จำเป็นต้อง commit ทุกไฟล์ที่มีการเปลี่ยนแปลงลงในรีวิชันเดียว ตามธรรมเนียมปฏิบัติที่ดี แต่ละรีวิชันของซอฟต์แวร์ควรทำงานได้สมบูรณ์ในตัวเอง เช่นแก้บั๊กเสร็จ 1 แห่งหรือเพิ่มฟีเจอร์ 1 อย่าง ไม่ควรใช้เป็นที่เก็บไฟล์ที่เซฟครึ่ง ๆ กลาง ๆ $ hg status M shape/views.py M templates/rectangle.html A templates/triangle.html M urls.py $ hg commit –m "Fix incorrect URL" shape/views.py urls.py $ เลือก commit เพียงสองไฟล์ เปลี่ยนแปลง 4 ไฟล์ (แก้ 3 เพิ่ม 1) เหลือ 2 การแก้ไข ที่ยังไม่ถูกบันทึก เป็นรีวิชัน
ลำดับ/หมายเลขรีวิชัน ชื่อผู้บันทึกรีวิชัน ตรวจดูรายการรีวิชัน ใช้คำสั่ง log ใช้ทางเลือก -v เพื่อแสดงไฟล์ที่แก้ไขและถูกบันทึกลงในแต่ละรีวิชัน ลำดับ/หมายเลขรีวิชัน $ hg log changeset: 0:87ad7f0fe866 tag: tip user: Chaiporn Jaikaeo <chaiporn.j@ku.ac.th> date: Wed Jul 06 22:07:35 2011 +0700 summary: First revision ชื่อผู้บันทึกรีวิชัน เวลาที่บันทึก Commit message $ hg -v log
TortoiseHg ให้ผู้ใช้สั่งงาน Mercurial ผ่าน GUI ใช้คำสั่ง hgtk แทนที่ hg ได้กับคำสั่งส่วนใหญ่ $ hgtk add $ hgtk status $ hgtk commit $ hgtk log
เตรียม repository บนเซิร์ฟเวอร์ ใช้ ssh เข้าไปยังเครื่อง cloud28 เพื่อสร้าง hg repository ไว้เก็บโปรเจ็คของตน ใช้คำสั่ง push ที่เครื่องตนเองเพื่อส่งข้อมูลรีวิชันทั้งหมดไปไว้บนเครื่อง cloud28 $ ssh username@cloud28.cpe.ku.ac.th Password: : (ตอนนี้อยู่ที่เครื่อง cloud28) $ mkdir hg $ cd hg $ hg init myweb $ logout $ hg push ssh://username@cloud28.cpe.ku.ac.th/hg/myweb
การโคลนและดึง repository ใช้คำสั่ง clone เพื่อดึง repository ทั้งก้อนมาพัฒนาต่อบนเครื่องที่ไม่มีโปรเจ็คอยู่ก่อน ใช้คำสั่ง pull เพื่อให้ repository ในเครื่องมีข้อมูลรีวิชันล่าสุดตามที่อยู่บนเซิร์ฟเวอร์ $ hg clone ssh://username@cloud28.cpe.ku.ac.th/hg/myweb $ hg pull ssh://username@cloud28.cpe.ku.ac.th/hg/myweb
การสลับรีวิชัน ใช้คำสั่ง update เพื่อเปลี่ยนโค้ดปัจจุบันไปเป็นโค้ด ณ เวลาที่รีวิชันถูกสร้างขึ้น ปรับโค้ดไปเป็นโค้ดของรีวิชันที่ 3 ปรับโค้ดไปเป็นโค้ดของรีวิชันล่าสุด $ hg update 3 $ hg update
ซอฟต์แวร์ที่พัฒนาหลายคน สั่ง merge เพื่อรวบประวัติรีวิชันต่างกันเข้าด้วยกัน commit Repo เครื่องของ Jittat commit push push pull clone Timeline Repo เซิร์ฟเวอร์กลาง pull push pull push clone Repo เครื่องของ Chaiporn commit merge commit
คำสั่ง merge $ hg push คลังเก็บเวอร์ชันกลาง pushing to ... searching for changes abort: push creates new remote heads on branch 'default'! (you should pull and merge or use push -f to force) $ hg pull คลังเก็บเวอร์ชันกลาง : $ hg merge $ hg commit -m commit message
ตัวอย่างกระบวนการ merge Repository สองแห่ง (r1 และ r2) โคลนมาจากที่เดียวกันแต่เริ่มมีประวัติรีวิชันต่างกัน
ตัวอย่างกระบวนการ merge r2 สั่ง pull มาจาก r1 r2 สั่ง merge และ commit