Thursday, February 14, 2008

Git กับการ revert

ใน svn เวลาเราทำอะไรผิดผลาด แล้วเราอยากย้อนกลับเนื้อหา file
มันก็มี case อยู่แค่ 2 case คือ
  1. file ยังไม่ถูก commit
    อันนี้ง่ายเลย แค่ใช้ svn revert ก็จบ
  2. file ถูก commit เข้าไปแล้ว
    อันนี้ก็ง่าย ก็แค่ revert โดยระบุ revision ที่เราต้องการ

    svn update -r REVISION_ID



ส่วนใน git นั้น มันไม่ง่ายเหมือน svn เพราะว่า มันมี state มากกว่า svn
โดย git มันจะมี state ของ file ได้ดังนี้
  • สถานะปกติ ยังไม่ถูกแก้ไข
  • ถูกแก้ไขแล้ว แต่ยังไม่ได้ add เข้า index (index ของ git เปรียบเสมือน buffer area ที่รอการ commit)
  • add เข้า index แล้ว แต่ยังไม่ได้ commit


จะเห็นว่ามี state ที่ content ค้างอยู่ใน index แต่ยังไม่ถูก commit เพิ่มเข้ามา(เมื่อเทียบกับ svn)
ดังนั้นถ้าเราจะ revert มันก็ต้องคิดว่าจะ revert ขั้นไหน เช่น

  1. file นั้นยังไม่ได้ถูก add เข้า index กรณีนี้ใช้คำสั่ง
    git checkout -- FILENAME

  2. file นั้นถูก add เข้า index แล้ว แต่ต้องการเอาออกมาจาก index
    git reset

    (state จะกลับไปเหมือนในข้อ 1)
  3. file นั้นถูก commit ไปแล้ว แต่ต้องการย้อนกลับออกมาสู่สถานะที่ file นั้นอยู่ใน index
    git reset --soft COMMIT_ID

  4. file นั้นถูก commit ไปแล้ว แต่ต้องการย้อนออกมาสู่สถานะก่อนการ add เข้า index
    ให้ทำคำสั่งในขั้น 3 แล้วต่อด้วยคำสั่งในขั้น 2
  5. file นั้นถูก commit ไปแล้ว และต้องการย้อนกลับมาสู่ version ก่อนหน้านั้น โดยเก็บ track การ revert ไว้ใน history ด้วย
    git revert COMMIT_ID

  6. file นั้นถูก commit ไปแล้ว แต่ต้องการย้อนไปสู่ version(ใดๆ) ก่อนหน้านั้น โดยไม่ทิ้งร่อยรอย
    git reset --hard COMMIT_ID



Note: ผมใช้คำว่า file ซึ่งไม่ถูกต้อง จริงๆต้องใช้คำว่า content (อ่านได้ใน "Git อีกทีน่า")
แต่เพื่อให้สื่อสารได้ง่ายขึ้น ขออนุญาติใช้คำว่า file

Related link from Roti

Wednesday, February 13, 2008

Open class

Ruby

>> class Integer
>> def fact
>> (2..self).inject(1) {|acc,v| acc * v}
>> end
>> end
=> nil
>> 7.fact
=> 5040


Grovvy

groovy:000> Integer.metaClass.fact = {   
groovy:001> delegate == 1 ? 1 : delegate * (delegate-1).fact()
groovy:002> }
===> groovysh_evaluate$_run_closure1@89ff97
groovy:000> 7.fact()
===> 5040


Scala

scala> class IntExt(v:Int) {             
| def fact() = {
| (2 to v).foldLeft(1) (_ * _)
| }
| }
defined class IntExt

scala> implicit def FactExt(v:Int) = new IntExt(v)
FactExt: (Int)IntExt

scala> 7 fact
res33: Int = 5040


เจ้า scala นี่แปลกตรงมันใช้หลักการ Implicit conversions
อย่างประโยค
7 fact จริงๆคือ
7.fact()
แต่ method fact มันไม่มีใน class Int
ดังนั้น compiler จะดูว่ามี Implicit conversions rule อะไรอยู่บ้าง
ในกรณีนี้ ก็คือจะแอบแปลงให้เป็นแบบนี้
(new IntExt(7)).fact()

Related link from Roti