จัดการแพตช์ด้วย quilt

เวลาแก้ไขซอร์สโค้ดแล้วจะส่งส่วนที่แก้ให้คนอื่น เราจะส่งในรูปของแพตช์กัน ซึ่งแพตช์ก็ได้มาจากการ diff ระหว่างของเก่ากับของใหม่ หลายคนที่เคยแก้โปรแกรมจะค่อนข้างปวดหัวกับการ diff โดยเฉพาะถ้าซอร์สโค้ดมีขนาดใหญ่

บางคนใช้วิธี copy ทั้งไดเรกทอรีเป็นอีกชื่อหนึ่งก่อนแก้ แล้วสั่ง diff แบบ recursive แบบนี้จะต้องใช้เนื้อที่ในฮาร์ดดิสก์ไม่ต่ำกว่าสองเท่าของขนาดซอร์สโค้ด คนที่เคยทำแพตช์สำหรับซอร์สอย่าง Mozilla หรืออะไรประมาณนั้น จะรู้ดี ว่าไม่ใช่เนื้อที่น้อย ๆ เลย

บางคนหัวใส ก็ใช้วิธีสร้างไดเรกทอรีปลอม ที่มีแต่แฟ้มที่เกี่ยวข้อง แล้วก็ diff ซึ่งทำให้ประหยัดเนื้อที่ได้มาก แต่ปัญหาคือต้องไล่สั่งทุกอย่างเอง เป็นการเพิ่มงานจนอาจทำให้ละความคิดออกจากตัวโปรแกรมที่กำลังแก้ได้

อย่ากระนั้นเลย วันนี้จะขอแนะนำเครื่องมือจัดการแพตช์ที่สะดวกสบาย ทั้งไม่กินเนื้อที่ จนเริ่มเข้ามาแทนที่ระบบ dpatch ของ Debian มากขึ้นเรื่อย ๆ คือ quilt

quilt มองสายลำดับของแพตช์ต่าง ๆ ที่แก้ซอร์สถัด ๆ กันมาว่าเป็นสแต็ก (last in first out) ตามตรรกะของการแพตช์เป๊ะ คือถ้าจะแก้แพตช์ที่อยู่กลาง ๆ ก็ต้องเลาะแพตช์หลัง ๆ ออกก่อน หลังจากแก้เสร็จจึง push กลับเข้าไปโดยแก้ conflict ที่อาจจะเกิดขึ้นเป็นขั้น ๆ ไป

ส่วนกลไกภายในของการสร้างแพตช์ ก็ใช้วิธีสร้างไดเรกทอรีปลอมเพื่อประหยัดเนื้อที่นั่นแล เพียงแต่สามารถสั่งแบบอัตโนมัติได้ง่าย ๆ

อย่าเพิ่งไปสนใจกลไกภายใน เริ่มดูคำสั่งก่อนดีกว่า

สมมุติว่ามีซอร์สแบบนี้:

myproject/ -+-- Makefile
            |
            |-- src/ -+-- Makefile
            |         |-- main.c
            |         +-- display.c
            |
            +-- lib/ -+-- Makefile
                      |-- command1.c
                      +-- command2.c

เริ่มสร้างแพตช์ใหม่

สมมุติว่าจะสร้างแพตช์ชื่อ set_background.patch

$ cd myproject
$ quilt new set_background.patch
Patch set_background.patch is now on top

ลองสำรวจดูเสียหน่อย จะพบไดเรกทอรีเพิ่มขึ้นมาในซอร์ส คือ:

myproject/ -+-- ...
            |
            |-- patches/ -+-- series
            |             +-- set_background.patch
            |
            +-- .pc/ -+-- applied-patches
                      +-- set_background.patch/ -+-- ...

ในไดเรกทอรี patches/ จะเก็บตัวแพตช์ต่าง ๆ ที่สร้างขึ้น โดยมีแฟ้มชื่อ series จดรายชื่อแพตช์ที่จะใช้ เรียงตามลำดับ

ส่วนไดเรกทอรี .pc/ นั้น เป็นไดเรกทอรีสำหรับทำงานของ quilt ซึ่งไม่เกี่ยวกับเรา แต่ถ้าซอกแซกเข้าไปดู ก็จะเห็นแฟ้ม applied-patches เก็บสถานะปัจจุบันของสแต็กของแพตช์ และไดเรกทอรีย่อยสำหรับ diff เพื่อสร้างแพตช์ต่าง ๆ

เริ่มแก้ไข

สมมุติว่า แฟ้มที่ต้องแก้คือ src/display.c และต้องเพิ่มแฟ้ม lib/command3.c โดยปรับ lib/Makefile ด้วย

$ cd src
$ quilt edit display.c
$ cd ../lib
$ quilt edit Makefile
$ quilt edit command3.c

คำสั่ง quilt edit ... แต่ละคำสั่ง จะเตรียมแฟ้มสำหรับ diff ไว้ (ถ้ายังไม่เคยเตรียมมาก่อน) แล้วเปิด editor (ตามที่ตั้งไว้ในระบบ) เพื่อแก้ไขแฟ้มที่สั่ง

ถ้าแอบไปซอกแซกดูใน myproject/.pc/set_background.patch/ ก็จะเห็นการเตรียมการที่ว่า

ดูสิ่งที่แก้ไขไป

แก้มาสักพักแล้ว อยากดูแพตช์ว่าโอเคไหม

$ quilt diff

commit

ขอใช้ภาษา VCS หน่อยละกัน เพราะมันเทียบเท่ากับการ commit แต่ความจริงคือการ update แพตช์ตามที่ได้แก้ไขไป (คำสั่ง quilt diff แค่แสดงการเปลี่ยนแปลงเท่านั้น ยังไม่ได้เขียนแพตช์)

$ quilt refresh
Refreshed patch set_background.patch

ลองดูผลงานหน่อยซิ:

$ cd ~/myproject
$ cat patches/set_background.patch
...เนื้อหาแพตช์...

เพิ่มแพตช์ที่ 2, 3, 4, ...

$ quilt new fix_typos.patch
Patch fix_typos.patch is now on top
$ quilt edit ...
$ ...
$ quilt refresh
Refreshed patch fix_typos.patch

สอบถาม

แพตช์บนสุดที่ apply อยู่:

$ quilt top
fix_typos.patch

แพตช์ที่ apply ไปแล้ว:

$ quilt applied
set_background.patch
fix_typos.patch

แพตช์ที่ยังไม่ apply:

$ quilt unapplied
File series fully applied, ends at patch fix_typos.patch

แพตช์ทั้งหมดที่มี:

$ quilt series
set_background.patch
fix_typos.patch

แพตช์ลำดับก่อนหน้า:

$ quilt previous
set_background.patch

แพตช์ลำดับถัดไป:

$ quilt next
File series fully applied, ends at patch fix_typos.patch

เดินหน้า/ถอยหลัง

quilt ขณะใด ๆ จะทำงานกับแพตช์ที่อยู่ในระดับบนสุด (ที่ตอบเมื่อถามด้วย quilt top) โดยเมื่อสั่ง quilt edit หรือ quilt refresh ก็จะมีผลกับแพตช์นี้ แต่ถ้าเราจะถอยกลับไปทำงานกับแพตช์ก่อนหน้า ก็แค่ pop แพตช์บนสุดออก:

$ quilt top
fix_typos.patch
$ quilt pop
Restoring src/main.c
Restoring src/display.c

Now at patch set_background.patch

หรือถ้าจะเดินหน้า คือ apply แพตช์ถัดไป ก็ push เข้าไป:

$ quilt top
set_background.patch
$ quilt push
patching file src/display.c
patching file src/main.c

Now at patch fix_typos.patch

นักพัฒนาลองใช้ดูครับ แล้วจะพบว่าสะดวกสบายจริง ๆ ครับ รายละเอียดต่าง ๆ อ่านเพิ่มเติมจาก man page หรือ doc ของ quilt ที่ /usr/share/doc/quilt/quilt.html ได้

Creative Commons License ลิขสิทธิ์ของบทความเป็นของเจ้าของบทความแต่ละชิ้น
ผลงานนี้ ใช้สัญญาอนุญาตของครีเอทีฟคอมมอนส์แบบ แสดงที่มา-อนุญาตแบบเดียวกัน 3.0 ที่ยังไม่ได้ปรับแก้