วันอังคารที่ 3 กรกฎาคม พ.ศ. 2555

วิธีการใช้ Subversion (SVN) – ตัวอย่างโปรเจค SimpleCalculator

จะเขียนอย่างย่อมากๆแต่เต็มไปด้วย Screen Shot เหมาะสำหรับคนใช้ TortoiseSVN เป็นมาบ้างแล้วเท่านั้นนะขอรับ (.  .’)
ขั้นที่ 1 เราจะสร้างเครื่องคิดเลขโง่ๆกันครับ สามารถทำการ
  • ยกกำลังสอง (Square)
  • ถอดราก (Sqrt) และ
  • กลับเครื่องหมาย (Inverse) ได้
หน้าตาออกมาประมาณนี้ และเราก็จะทำการ Implement ฟังก์ชันอันหนึ่งไปก่อน ส่วนอีกสองอันที่เหลือจะแจกให้ Dev คนอื่นทำ
Design UI

using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using System.Drawing;using System.Linq;using System.Text;using System.Windows.Forms;namespace SimpleCalculator{public partial class FormMain : Form{public FormMain(){InitializeComponent();}private void uxSignInverse_Click(object sender, EventArgs e){try{int val = Convert.ToInt32(uxInput.Text);uxInput.Text = (-1*val).ToString();}catch (Exception ex){MessageBox.Show("Something Wrong!");}}}}

ขั้นที่ 2 เอาเข้า Repository ครับผมใช้วิธีสร้างโฟลเดอร์ว่างๆใน Repo Browser แล้ว check out ออกมาก่อนแล้วเอา project ใส่เข้าไป เลือก commitเฉพาะไฟล์ที่จำเป็นตามที่เขียนไว้ในเรื่องก่อน (การใช้งาน SVN กับ Visual Studio)
ขั้นที่ 3 แตก Branch ออกไปสองอัน เป็น Feature Branch โดยจะให้ Dev อีกสองคนมาเขียนส่วน Square Root และ Square
Create Sqr Branch
ขั้นที่ 4 Dev ทั้งสองทำงานบน Branch ของตัวเอง โดยcheck out SimpleCalculator/brances/square (หรือ squareroot)แล้วเพิ่มโค้ดส่วนที่เป็นการหา Square และ Square Root แล้ว commitกลับเข้าไป
ถ้ามาดูหน้าตาของ Revision Graph จะได้ประมาณนี้
Revision Graph
ขั้นที่ 5 ถึงเวลา Merge อันนี้แอบยากและวุ่นวายนิดนึง เริ่มจากการ Merge โค้ดของ Square Branch กลับเข้าไปใน trunk ก่อน ดูให้แน่ใจว่าตอนนี้เราทำงานอยู่ที่โฟลเดอร์ trunk (Working Directory เป็น trunk)
อันนี้เป็นการ Merge ในกรณีที่ trunk ไม่มีการเปลี่ยนแปลงใดๆตั้งแต่แยก Branch ออกมาถ้ามีการเปลี่ยน (ซึ่งก็มักจะเปลี่ยน) จะต้องทำการ Sync ตัว Branchของเราเข้ากับ Trunk ก่อน Merge เสมอ ซึ่งเดี๋ยวจะต้องทำตอน Merge SquareRoot เข้ามา
การ Merge จะเอาการเปลี่ยนแปลง (Delta) ทั้งแต่ trunk จนไปถึง branchเข้ามาบวกให้กับ trunk ปัจจุบันอาจจะดูงงๆนิดหน่อยเหมือนที่เขียนไว้ในโพสต์ก่อน (Branch และ Merge ใน SVN) ให้ FROM เป็น trunk และ TO เป็น branches/square และสั่งให้ Merge เข้าไปที่ trunk ตามรูป
Merge with Square


พวกปุ่มทั้งหลาย ตั้งแต่ Dry run, Diff, Unified diff ลองเล่นๆดูได้ มีประโยชน์มากมาย
หลังจาก Merge เสร็จแล้ว ก็ตรวจดูให้เรียบร้อยว่ามันทำงานได้ในที่นี้ก็คือ เราจะใช้ได้ทั้งสองฟังก์ชันทั้ง Inverse และ Square นั่นเอง^ ^
มั่นใจว่าใช้ได้ก็ commit
ขั้นที่ 6 อันนี้ยาก เป็นการ Merge Square Rootเข้าไปใน trunk เนื่องจากตอนนี้ trunkมีการเปลี่ยนไปแล้วตั้งแต่เวลาที่แตก branch ออกมา (จากการ commitในขั้นตอนก่อน) ดังนั้นต้องปรับ base ของเราให้ทันสมัยก่อน ก่อนทำดูให้แน่ใจก่อนว่าตอนนี้ Working Directory อยู่ที่ branch
การปรับให้ทันสมัย (หรือที่ผมชอบเขียนว่า sync branch เข้ากับ trunk)ทำโดยการหาความเปลี่ยนแปลง (Delta) ของ trunk ตั้งแต่ตอนเริ่มแตกออกมาจนมาถึง trunk ปัจจุบัน (HEAD revision) มาบวกกับ branch ของเราดังนั้นจะใช้ FROM เป็น trunk ใช้ revision ตอนแตก branchหรือตอน sync ครั้งล่าสุด และ TO เป็น trunk ปัจจุบัน (HEAD) และสั่งให้Merge ไปที่ตัว branch
  • FROM trunk REVISION 10 (เช่นพบว่าแตกออกมาตอน rev 10)
  • TO trunk REVISION HEAD
  • MERGE TO branches/squareroot
ปัญหาสำคัญในขั้นตอนนี้อยู่ที่ การหา revision number ของ trunk ตอนแตก branch หรือตอน sync ครั้งล่าสุด ออกมาจะทำยังไงถ้าเป็นการแตก branch ครั้งแรก เราสามารถดูจาก log message ได้ว่ามีการcopy จาก trunk เกิดขึ้นที่ revision ไหน แต่หลังจากการ syncไปแล้วครั้งนึงแล้ว เราจะเห็นการ sync เป็นแค่การ commit ธรรมดาดังนั้นมันจึงสำคัญมากที่จะต้องระบุเลข revision ของ trunk ที่เรา sync ล่าสุดใน log message ของการ commit ด้วยตอน merge ครั้งหน้าจะได้ดูได้ง่ายๆ อันนี้เป็นข้อเสียของ SVN(ซึ่งเหมือนว่าจะไม่มีใน Git - -‘a) -- แต่ถ้าคิดว่าจะ mergeครั้งเดียวแล้วลบ branch นี้ทิ้งไปเลยก็ได้เช่นกัน
ในกรณีนี้อาจมีการ Conflict เกิดขึ้นได้ด้วยโดยเราจะต้องใช้วิจารณญาณแก้ไข conflict เอง ในตัวอย่างจะเกิดที่FormMain.cs ไอคอนมันจะไม่ใช่สีแดง (Modified) หรือสีเขียว แต่จะเป็นสีเหลืองพร้อมเครื่องหมายตกใจ (อัศเจรีย์ – !) ให้คลิกขวาที่ไฟล์แล้วเลือกTortoiseSVN -> Edit Conflicts จะมีหน้าต่างสีแดงฉานขึ้นมาให้ใช้ก็ให้ใช้ common sense แก้ไขนะครับ :)
Resolve Conflict
หลังจาก Resolved (แปลว่าแก้ conflict ได้แล้ว) ได้แล้ว ก็ทำการทดสอบ (ควรจะใช้ได้ทั้ง 3 functions แล้ว) ก็ทำการ commit
หลังจากนั้นกลับไปทำงานที่ trunk (Working Directory เป็น trunk) แล้วMerge ด้วยวิธีเดิมได้แล้ว (เพราะ sync กันแล้ว)ซึ่งก็ไม่น่าจะมีปัญหาอะไรใดๆ แต่พึงสังวรณ์ไว้ว่าการ mergeในขั้นตอนนี้ถึงจะมีปัญหา Subversion ก็จะบอกไม่ได้อยู่ดี ..เป็นข้อเสียอย่างหนึ่ง
การแก้แบบหนึ่งนั้นทำได้โดยใช้ 3-way merge tool ซึ่งจะเป็นการ merge แบบใช้ 3 ไฟล์ ได้ผลลัพธ์ออกมา 1 ไฟล์ โดยมี พ่อ, ลูก 1 และ ลูก 2 (น่าจะเข้าใจได้นะ)
using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using System.Drawing;using System.Linq;using System.Text;using System.Windows.Forms;namespace SimpleCalculator{public partial class FormMain : Form{public FormMain(){InitializeComponent();}private void uxSignInverse_Click(object sender, EventArgs e){try{int val = Convert.ToInt32(uxInput.Text);uxInput.Text = (-1*val).ToString();}catch (Exception ex){MessageBox.Show("Something Wrong!");}}private void uxSquareRoot_Click(object sender, EventArgs e){try{int val = Convert.ToInt32(uxInput.Text);// Find integer rootuxInput.Text = ((int)Math.Round(Math.Sqrt(val))).ToString();}catch (Exception ex){MessageBox.Show("Something Wrong!");}}private void uxSquare_Click(object sender, EventArgs e){try{int val = Convert.ToInt32(uxInput.Text);uxInput.Text = (val * val).ToString();}catch (Exception ex){MessageBox.Show("Something Wrong!");} }}}
   
และอันนี้เป็น Revision Graph สุดท้าย จะเห็นได้อย่างนึงว่ามันบอกไม่ได้ว่ามีการ merge เข้าไปตรงไหน เพราะการ merge ก็เป็นแค่การcommit ธรรมดา (แต่เหมือนว่า Git จะไม่มีปัญหานี้เช่นกัน โอ้วว)
Final Revision Graph
จบแล้วครับ series เผาเวลาว่างของผม :) ครั้งหน้าอาจจะเขียน Git(เมื่อถึงเวลาที่ Windows ใช้งาน Git ง่ายกว่านี้ และผมอยากใช้มันจริงๆ –เท่าที่รู้มันยังต้องรันผ่าน cygwin อยู่เลย)
แถมอีกนิด ทำไมต้อง Git ?
  • ไม่ใช่ระบบรวมศูนย์แบบ SVN ดังนั้นไม่ต้องยุ่งกับ Network มาก เร็วปรื้ดดดด ลองเทียบความเร็วตอนใช้ SVN แล้วมี Repo เป็น Local กับตอนมีที่ Google Code ดู
  • พอมันไม่มีการรวมศูนย์ มันก็จะกลายเป็นว่าต้องมีคนคอยไล่ Merge จากชาวบ้านชาวเมืองที่แตกหน่อไปแก้โค้ดกัน ดังนั้นไม่ต้องควบคุม Permission ว่าใครจะมายุ่งกับ repo กลางได้บ้าง แต่กลายเป็นว่าจะมีผู้ถูกแต่งตั้งเป็น “ผู้กุม version ล่าสุด” เป็นผู้ไล่ merge จากคนที่น่าสนใจแทน
  • มี การ keep track ให้ว่าตอนแตก branch มันเป็น revision เท่าไหร่ ดังนั้นการ merge ทำได้ง่ายกว่า (ยังไม่ลองกับตัว และคงยังไม่ได้ลองเร็วๆนี้ -- ก็เค้าว่ากันว่าแบบนั้นนี่ >,<’)
  • ขนาดรวมของ Repository เล็กกว่ามาก ได้ยินว่า repo ของ mozilla ใช้ SVN แล้วจะใหญ่ 14 GB แต่ถ้าใช้ Git จะใหญ่ 420 MB (ขอโทษที่ไม่ได้ cite ครับ แอบขี้เกียด)
ฟังดูแล้ว promising ไม่ใช่น้อย แต่ก็นั่นแหละ ติดปัญหาเรื่อง platform กับ GUI ซึ่งก็ไม่ได้น่าจะเป็นเรื่องที่แก้ยาก ดูกันต่อไป :)

Credit: DevStock

ไม่มีความคิดเห็น:

แสดงความคิดเห็น