Open source

git-prompt สลับ branch และจัดการ git ใน terminal แบบหน้าต่าง branch ของ PHPStorm

พิมพ์ g ใน repo ไหนก็ได้ แล้วค้นชื่อ branch หรือคำสั่งจากกล่องเดียว เลือก Checkout, Update, Merge, Rebase, Commit, Push หรือลบ branch เก่าทีละหลายตัว โดยเห็นทุกคำสั่ง git ที่รันจริง

เผยแพร่
เวลาอ่าน
6 นาที

ผมอยากได้หน้าต่าง branch ของ PHPStorm กลับมาใน terminal

ในโพสต์ก่อน ผมเล่าว่าย้ายงาน git จากปุ่มใน PHPStorm มาใช้คำสั่งใน terminal แทน คำสั่งพวกนั้นใช้ดีอยู่แล้ว แต่มีอย่างหนึ่งที่ยังคิดถึง คือกด Cmd+G Cmd+B แล้วมีหน้าต่าง branch ขึ้นมา พิมพ์ชื่อสองสามตัวแล้วเลือก Checkout ได้ทันที ใน terminal เราต้องจำชื่อ branch ให้ครบ หรือสั่ง git branch ดูก่อนแล้วค่อยพิมพ์ตาม

เลยทำ g ขึ้นมา หน้าตาและชื่อเมนูเลียนแบบหน้าต่าง branch ของ PHPStorm ใครเคยใช้ PHPStorm น่าจะคุ้นมือตั้งแต่ครั้งแรก

หน้าแรกของ g คือแท็บ Branches

พิมพ์ g ใน repo ไหนก็ได้ branch หลักอยู่บนสุด ตามด้วย branch อื่นเรียงจากที่มี commit ล่าสุด

ติดตั้งครั้งเดียว ใช้ได้ทุก repo

git-prompt ไม่ได้ลงในแอป Laravel แต่เป็นโปรแกรม command line ที่ติดตั้งไว้ในเครื่องผ่าน composer global จึงใช้ได้กับทุก repo ทั้งโปรเจกต์ Laravel โปรเจกต์ frontend หรืออะไรก็ได้ที่เป็น git ตอนแรกผมคิดจะทำเป็นคำสั่ง artisan แต่แบบนั้นต้อง composer require ในทุกโปรเจกต์ แต่ละโปรเจกต์ก็ล็อกเวอร์ชันไว้ไม่เท่ากัน พอแก้คำสั่งทีก็ต้องไล่อัปเดตทีละที่

composer global require phattarachai/git-prompt

แล้วเพิ่ม alias ไว้ใน ~/.zshrc หรือจะใส่ ~/.composer/vendor/bin ไว้ใน PATH เลยก็ได้

alias g="$HOME/.composer/vendor/bin/g"

ต้องมี PHP 8.3 ขึ้นไป หน้าจอทั้งหมดสร้างด้วย Laravel Prompts ซึ่งใช้นอกแอป Laravel ได้ ส่วนงาน git ทั้งหมดเรียกคำสั่ง git ในเครื่องตรง ๆ ไม่มี library ไหนมาทำแทน

พิมพ์แค่บางส่วนของชื่อ branch แล้วกด Enter

แท็บแรกคือ Branches พิมพ์อะไรลงไปก็กรองทันทีแบบเดียวกับใน IDE พิมพ์ de ก็เจอ develop หรือพิมพ์ตัวอักษรตามลำดับอย่าง vr ก็เจอ hotfix/vat-rounding ชื่อที่ขึ้นต้นด้วยคำที่พิมพ์จะขึ้นก่อน และแถวแรกที่ตรงเลือกไว้ให้แล้ว กด Enter ได้เลยไม่ต้องกดลูกศรลงมาก่อน

สัญลักษณ์หน้าแต่ละแถวมีความหมายแบบนี้

  • ● branch ที่อยู่ตอนนี้
  • ★ branch หลักที่เราตั้งไว้ (ดูหัวข้อถัดไป)
  • ↑1 มี commit ที่ยังไม่ได้ push และ ↓2 มี commit บน remote ที่ยังไม่ได้ดึงลงมา
  • worktree branch นี้เปิดอยู่ในอีกโฟลเดอร์ผ่าน git worktree
  • origin/… branch ที่มีแค่บน remote พอเลือก Checkout g จะสร้าง branch ในเครื่องที่ track ตัวบน remote ให้

ตั้ง branch หลักให้อยู่บนสุด

ค่าเริ่มต้นคือ main, master และ develop ถ้าโปรเจกต์มี branch ตาม environment อย่าง uat ก็ตั้งเองได้ ลำดับที่ใส่คือลำดับที่แสดง

git config --global gitprompt.protected "develop uat main"

repo ไหนใช้ชื่อต่างออกไป ตั้งค่าใน repo นั้นโดยไม่ต้องใส่ --global ค่าของ repo จะใช้แทนค่า global ทั้งชุด ส่วน branch ที่เหลือเรียงตาม commit ล่าสุด ถ้าอยากให้ feat/, fix/, hotfix/ อยู่เป็นกลุ่ม เลือก Sort branches by name ในแท็บ Actions แล้ว g จะจำไว้ใช้ครั้งต่อไป

เมนูของแต่ละ branch ใช้ชื่อเดียวกับใน PHPStorm

กด Enter ที่ branch ไหนจะได้เมนูของ branch นั้น เมนูนี้ก็กรองได้เหมือนกัน พิมพ์ d แล้วกด Enter ก็คือ Delete ถ้ากดผิดหน้า กด Esc ย้อนกลับไปหน้าก่อนได้

พิมพ์ d ในเมนูของ branch

เมนูย่อยทุกหน้าพิมพ์กรองได้ คำที่ขึ้นต้นด้วยตัวที่พิมพ์ขึ้นก่อน

แต่ละเมนูตรงกับคำสั่ง git แบบนี้ สมมติว่าอยู่ที่ develop แล้วเลือก feat/export-pdf

เมนู คำสั่งที่ g รัน
Checkout git switch feat/export-pdf
Checkout and Update git switch แล้วอัปเดตแบบ Update Project
Checkout and Rebase onto 'develop' git switch feat/export-pdf แล้ว git rebase --autostash develop
Compare with 'develop' git log develop..feat/export-pdf และกลับกัน
Merge into 'develop' git merge --no-edit --autostash feat/export-pdf
Rebase 'develop' onto git rebase --autostash feat/export-pdf
New Branch from git switch --no-track -c <ชื่อใหม่> feat/export-pdf
Rename git branch --move
Delete git branch --delete แล้วถามว่าจะลบบน remote ด้วยไหม

ทุกคำสั่งที่รันขึ้นให้เห็นก่อน

g ไม่ได้ซ่อน git ไว้ข้างหลัง ก่อนรันทุกคำสั่งจะพิมพ์บรรทัด → git … ออกมาก่อน ตามด้วยผลจาก git ใช้ไปเรื่อย ๆ ก็จำคำสั่งได้เอง และพอมีอะไรแปลก ๆ ก็ตามได้ว่าเกิดจากคำสั่งไหน

ทุกคำสั่งที่ g รันขึ้นให้เห็น

Checkout and Update ที่ develop สลับ branch แล้วดึงงานล่าสุดลงมา

แท็บ Actions รวมงานที่ไม่ผูกกับ branch ไหน

กด Tab เพื่อสลับแท็บ หรือกด ← → ตอนช่องค้นหายังว่าง ข้อความที่พิมพ์ไว้ตามไปด้วย พิมพ์ st แล้วกด Tab ก็เจอ Status กับ Stash เลย

แท็บ Actions

แท็บ Actions ระหว่าง merge หรือ rebase ค้าง จะมี Continue กับ Abort อยู่บนสุด

  • Update Project สั่ง git fetch --prune แล้วอัปเดต branch ที่อยู่ ถ้ามีแค่ของใหม่จาก remote จะ fast-forward ไปเลย แต่ถ้าเราเองก็มี commit ใหม่ด้วย จะถามก่อนว่าจะ rebase หรือ merge ส่วนงานที่ยังไม่ commit ใช้ --autostash เก็บไว้แล้วคืนให้หลังอัปเดต ถ้าเลือกแบบเดิมทุกครั้ง ตั้งค่าเริ่มต้นได้ด้วย git config --global gitprompt.update rebase
  • Commit… เลือกไฟล์ด้วย Space ใส่ข้อความ แล้วถามว่าจะ push ต่อเลยไหม ถ้า stage ไฟล์ไว้บางส่วนแล้ว จะติ๊กไว้ให้เฉพาะไฟล์ชุดนั้น
  • Push… branch ใหม่ใส่ --set-upstream ให้ ถ้า push ไม่ผ่านเพราะบน remote มี commit ที่เรายังไม่มี จะให้เลือกว่าจะ Update ก่อนแล้วค่อย push หรือ push ทับด้วย --force-with-lease
  • Stash… เก็บงานค้างรวมไฟล์ใหม่ หรือเลือก stash เก่ามา pop, apply, ดูไฟล์ หรือลบทิ้ง
  • Status ตารางไฟล์ที่เปลี่ยน พร้อมบอกว่าไฟล์ไหน stage แล้ว

git pull เฉย ๆ ก็ดึงงานลงมาได้เหมือนกัน แต่พอ branch แยกทางกัน git จะทำตาม config ที่ตั้งไว้ หรือหยุดถ้ายังไม่ได้ตั้ง Update Project เลือกถามเราก่อน รายละเอียดเรื่อง fetch กับ pull อยู่ในโพสต์คำสั่ง git ที่ใช้ทุกวัน

branch หลักต้องพิมพ์ชื่อยืนยันก่อนทุกครั้ง

ส่วนที่ผมใส่ใจที่สุดคือกันไม่ให้พลาดกับ branch ที่หลายคนใช้ร่วมกัน

  • merge, push, rebase หรือลบ branch ที่อยู่ใน gitprompt.protected ต้องพิมพ์ชื่อ branch ยืนยันก่อน กด Enter ผ่านไปเฉย ๆ ไม่ได้
  • ไม่มี --force เฉย ๆ เลย force push ใช้ --force-with-lease ซึ่งจะไม่ยอมทับ ถ้าบน remote มีงานของคนอื่นที่เรายังไม่ได้ดึงลงมา
  • Checkout ตอนที่งานค้างชนกับ branch ปลายทาง จะเสนอ Smart checkout ให้ เก็บงานไว้ใน stash สลับ branch แล้วเอางานกลับมาให้ เหมือนใน PHPStorm
  • branch ที่เปิดอยู่ใน worktree อื่น g จะบอกว่าอยู่โฟลเดอร์ไหน แทนที่จะปล่อยให้ git error
  • merge หรือ rebase แล้วเจอ conflict จะหยุดให้เลือกว่าจะ Abort กลับไปเหมือนเดิม หรือไปแก้ใน editor ก่อน แก้เสร็จพิมพ์ g อีกที แล้วเลือก Continue ซึ่งจะเช็คก่อนว่าไม่มีเครื่องหมาย <<<<<<< เหลืออยู่ ถึงจะ stage แล้วไปต่อ

ลบ branch เก่าทีละหลายตัว ทั้งในเครื่องและบน remote

ทำงานไปสักพัก branch ที่ merge แล้วก็ค้างอยู่เต็มไปหมด ทั้งในเครื่องและบน GitHub เลือก Delete Branches ในแท็บ Actions หรือสั่ง g d ตรง ๆ

ลบ branch ที่ merge แล้วทีละหลายตัว

พิมพ์ merged แล้วกด Ctrl+A ติ๊กทุกแถวที่ตรงในครั้งเดียว

  • g สั่ง git fetch --prune ก่อน รายการจะได้ตรงกับบน remote
  • แต่ละแถวมีป้ายบอก merged คือรวมเข้า branch หลักของ remote แล้ว gone คือตัวบน remote ลบไปแล้ว เช่นหลัง merge PR ส่วน local only กับ remote only บอกว่ามีอยู่ฝั่งเดียว เรียง branch เก่าสุดไว้บนสุด
  • กด Space ติ๊กทีละแถว หรือพิมพ์ merged หรือ gone แล้วกด Ctrl+A ติ๊กทุกแถวที่ตรง
  • เลือกว่าจะลบในเครื่องอย่างเดียว หรือลบบน remote ด้วย แล้ว g จะแสดงรายการทั้งหมดให้ยืนยันอีกที
  • branch ที่ยังมี commit ไม่ได้ merge ไปไหน จะเตือนแยกและไม่ลบให้ จนกว่าเราจะยืนยันอีกรอบ
  • branch หลัก branch ที่อยู่ตอนนี้ และ branch ที่เปิดใน worktree อื่น ไม่ขึ้นมาในรายการเลย

คำสั่งลัด

พิมพ์ g เฉย ๆ ได้หน้าค้นหาครบทุกอย่าง ถ้ารู้อยู่แล้วว่าจะทำอะไร ใส่คำสั่งย่อยต่อท้ายได้

คำสั่ง ทำอะไร
g หน้าค้นหา แท็บ Branches และ Actions
g b เฉพาะ branch
g s Status
g up Update Project
g c Commit
g p Push
g st Stash
g n New branch จาก branch ที่อยู่
g d ลบ branch ทีละหลายตัว

ทุกหน้าใช้ปุ่มชุดเดียวกัน พิมพ์เพื่อกรอง Enter เลือก Tab สลับแท็บ Esc ย้อนกลับ และ Ctrl+C ออกทันที

GitHub: phattarachai/git-prompt

อ่านต่อ

ล่าสุด

ดูทั้งหมด →