สมมติว่าบางอย่างเกิดขึ้นแล้วกันครับ ทำให้ feature นึงไม่พร้อมใช้งาน แต่มันได้เข้าไปอยู่ใน develop branch เรียบร้อยแล้ว (สมมติว่าใช้ git flow) คุณในฐานะที่เป็นเป็นผู้รับผิดชอบ product การเอา feature เข้าออกอาจเป็นเรื่องปกติ แต่มาเจอแบบ last minute แบบนี้ ก็สามารถทำให้ปวดหัวได้เช่นกัน เหตุการณ์แบบนี้เกิดขึ้นได้ ไม่เป็นไรครับ ลองมาดูว่าจะแก้ปัญหานี้ได้อย่างไร โดยขอใช้เป็น git command line ในการอธิบายสิ่งที่เกิดขึ้น ทำให้เห็นภาพง่ายกว่า GUI tool
กรณี #1
แบบไม่ค่อยเต็มใจจะเอา feature ออกเท่าไหร่ แก้บางไฟล์ใน last commit ก็พอ เราใช้ git checkout เพื่อ เอาไฟล์ออกมา เพราะการ checkout คือการเอาไฟล์จาก index หรือ statging area มาไว้ที่ working tree (directory) ซึ่งจริงๆแล้วการ checkout สามารถดึงไฟล์จาก commit ไหนก็ได้ ไม่ใช่เฉพาะจาก commit ล่าสุด
//สมมติว่าเราเจอว่า last commit SHA-1 คือ c5f567
$ git checkout c5f567~1 — file1/to/restore
~1 หมายถึง commit ก่อนหน้า c5f567 1 commit ถ้า ~2 ก็หมายถึง 2 commit ก่อนหน้า
เมื่อเราได้ไฟล์มาแล้ว ซึ่งเป็น file ก่อนหน้า last commit ทีนี้ก็ขึ้นกับเราว่าจะแก้ไข หรือ commit มันกลับเข้าไป ในกรณีนี้ commit history จะมี commit เพิ่มมาใหม่ 1 อัน
$ git status
On branch develop
Your branch is up to date with ‘origin/develop’.
Changes not staged for commit:
(use “git add <file>…” to update what will be committed)
(use “git checkout — <file>…” to discard changes in working directory)
modified: file1/to/restore
กรณี #2
เอา feature (pull request) ที่เพิ่ง merge ออกไปทั้งอันเลย ง่ายมากครับ เพียงแค่ใช้ git reset เพราะ มันคือการ undo สิ่งที่เราเพิ่ง commit หรือ merge เข้าไป แต่ต้องเข้าใจว่าการ reset มีอยู่ 3 แบบ
1. SOFT
Commit C2 (latest commit ที่เป็น PR merged)
Commit C1
$ git reset --soft C1
กรณีนี้จะเป็นการเอา feature ที่เพิ่ง PR ออกไปจาก commit history และ repository แต่ไฟล์ที่เพิ่ง commit เข้าไปจะยังอยู่ใน staging และ working tree ไม่หายไปไหน และเรายังสามารถแตก branch ออกไปจากจุดนี้ได้ด้วย
2. MIXED
$ git reset --mixed C1
กรณีนี้เป็นการเอา feature ออกจาก commit history, repository และ staging แต่ไฟล์เพิ่ง commit เข้าไปจะเหลืออยู่ที่ working tree เท่านั้น
3. HARD
$ git reset --hard C1
กรณีนี้เป็นการเอา feature ออกจาก commit history, repo, staging และ working tree ด้วย กรณีนี้ค่อนข้างอันตรายเพราะจะมีการลบไฟล์ที่เป็น untrack ออกไปด้วย
สังเกตว่า git reset จะไม่เหลือ history ใน commit เลย แต่ถ้าอยาก track history ต้องดูกรณีต่อไป
กรณี #3
ใช้ git revert สำหรับเอา feature ออกทั้งหมด แต่ยังคงเก็บ history ไว้ เป็นเหมือนการ undo สิ่งที่ทำลงไป
Commit C2 (latest commit ที่เป็น merge PR)
Commit C1
$ git revert -m 1 C2
กรณีนี้ จะสร้าง new commit ขึ้นมาเพื่อ undo C2 นั่นคือ feature ที่เพิ่ง merge ไปได้ถูกเอาออกไปหมด
เมื่อแก้ไขปัญหาได้แล้ว ก็ทำการ git push origin develop ขึ้นไปใหม่
สรุป
ในการใส่ feature เข้าไปใน pipeline อย่างรวดเร็ว ต้องมี process ที่ดีมารองรับ การวางแผนที่ดีจะช่วยให้เหตุการณ์แบบนี้น้อยลง แต่ถ้ามันเกิดขึ้น อย่างน้อยเราก็เตรียมพร้อมที่จะรับมือกับมันได้ อย่าลืมว่าเราใช้ version control ก็เพื่อเป็นเครื่องมือช่วยให้เราทำงานได้มีประสิทธิภาพมากขึ้น และสำหรับ git แล้ว ให้มั่นใจได้ว่า “you are in good hands.”