ฉันใช้คำตอบของอดัมมาหลายปีแล้ว ที่กล่าวว่ามีบางกรณีที่มันไม่ทำงานตามที่ฉันคาดไว้:
- สาขาที่มีคำว่า "master" ถูกละเว้นเช่น "notmaster" หรือ "masterful" แทนที่จะเป็นเพียงสาขาหลัก
- สาขาที่มีคำว่า "dev" ถูกเพิกเฉยเช่น "dev-test" มากกว่าเฉพาะสาขา dev
- การลบสาขาที่สามารถเข้าถึงได้จาก HEAD ของปัจจุบันสาขา (นั่นคือไม่จำเป็นต้องเป็นหลัก)
- ในสถานะ HEAD เดี่ยวการลบทุกสาขาที่สามารถเข้าถึงได้จากการกระทำปัจจุบัน
1 & 2 ตรงไปยังที่อยู่เพียงแค่เปลี่ยน regex 3 ขึ้นอยู่กับบริบทของสิ่งที่คุณต้องการ (เช่นลบสาขาที่ไม่ได้รวมเข้ากับมาสเตอร์หรือกับสาขาปัจจุบันของคุณ) 4 มีความเป็นไปได้ที่จะเกิดภัยพิบัติ (แม้ว่าจะสามารถกู้คืนได้git reflog
) หากคุณดำเนินการนี้โดยไม่ตั้งใจในสถานะ HEAD เดี่ยว
ในที่สุดฉันต้องการให้สิ่งนี้อยู่ในสายการบินเดียวที่ไม่ต้องการสคริปต์แยก (Bash | Ruby | Python)
TL; DR
สร้างนามแฝง "sweep" คอมไพล์ที่ยอมรับการ-f
ตั้งค่าสถานะทางเลือก:
git config --global alias.sweep '!git branch --merged $([[ $1 != "-f" ]] \
&& git rev-parse master) | egrep -v "(^\*|^\s*(master|develop)$)" \
| xargs git branch -d'
และเรียกใช้กับ:
git sweep
หรือ:
git sweep -f
คำตอบที่ยาวและละเอียด
มันง่ายที่สุดสำหรับฉันที่จะสร้าง repo git ตัวอย่างกับกิ่งไม้บางอย่างและมุ่งมั่นที่จะทดสอบพฤติกรรมที่ถูกต้อง:
สร้าง repo คอมไพล์ใหม่ด้วยการกระทำเพียงครั้งเดียว
mkdir sweep-test && cd sweep-test && git init
echo "hello" > hello
git add . && git commit -am "initial commit"
สร้างสาขาใหม่
git branch foo && git branch bar && git branch develop && git branch notmaster && git branch masterful
git branch --list
bar
develop
foo
* master
masterful
notmaster
พฤติกรรมที่ต้องการ: เลือกสาขาที่ผสานทั้งหมดยกเว้น: master, development หรือcurrent
regex ดั้งเดิมพลาดสาขา "เก่ง" และ "notmaster":
git checkout foo
git branch --merged | egrep -v "(^\*|master|dev)"
bar
ด้วย regex ที่อัปเดต (ซึ่งตอนนี้แยก "พัฒนา" มากกว่า "dev"):
git branch --merged | egrep -v "(^\*|^\s*(master|develop)$)"
bar
masterful
notmaster
สลับไปที่สาขา foo ทำการคอมมิชชันใหม่แล้วชำระเงินที่สาขาใหม่ foobar ตาม foo:
echo "foo" > foo
git add . && git commit -am "foo"
git checkout -b foobar
echo "foobar" > foobar
git add . && git commit -am "foobar"
สาขาปัจจุบันของฉันคือ foobar และถ้าฉันเรียกใช้คำสั่งด้านบนอีกครั้งเพื่อแสดงรายการสาขาที่ฉันต้องการลบสาขา "foo" จะถูกรวมไว้แม้ว่ามันจะไม่ได้ถูกรวมเข้ากับมาสเตอร์:
git branch --merged | egrep -v "(^\*|^\s*(master|develop)$)"
bar
foo
masterful
notmaster
อย่างไรก็ตามถ้าฉันเรียกใช้คำสั่งเดียวกันบนต้นแบบจะไม่รวมสาขา "foo":
git checkout master && git branch --merged | egrep -v "(^\*|^\s*(master|develop)$)"
bar
masterful
notmaster
และนี่เป็นเพราะgit branch --merged
ค่าเริ่มต้นของ HEAD ของสาขาปัจจุบันหากไม่ได้ระบุไว้เป็นอย่างอื่น อย่างน้อยสำหรับขั้นตอนการทำงานของฉันฉันไม่ต้องการลบสาขาท้องถิ่นเว้นแต่ว่าพวกเขาจะถูกรวมเข้ากับข้อมูลหลักดังนั้นฉันจึงชอบตัวแปรต่อไปนี้:
git checkout foobar
git branch --merged $(git rev-parse master) | egrep -v "(^\*|^\s*(master|develop)$)"
bar
masterful
notmaster
สถานะ HEAD ที่แยกออก
การใช้พฤติกรรมเริ่มต้นของgit branch --merged
มีผลกระทบที่สำคัญยิ่งขึ้นในสถานะ HEAD ที่แยกออก:
git checkout foobar
git checkout HEAD~0
git branch --merged | egrep -v "(^\*|^\s*(master|develop)$)"
bar
foo
foobar
masterful
notmaster
สิ่งนี้จะลบสาขาที่ฉันเพิ่งเปิดใช้งาน "foobar" พร้อมกับ "foo" ซึ่งแทบจะไม่ได้ผลลัพธ์ที่ต้องการ อย่างไรก็ตามด้วยคำสั่งที่แก้ไขแล้วของเรา:
git branch --merged $(git rev-parse master) | egrep -v "(^\*|^\s*(master|develop)$)"
bar
masterful
notmaster
หนึ่งบรรทัดรวมถึงการลบจริง
git branch --merged $(git rev-parse master) | egrep -v "(^\*|^\s*(master|develop)$)" | xargs git branch -d
ทั้งหมดถูกรวมเข้าเป็นนามแฝง "sweep" คอมไพล์
git config --global alias.sweep '!git branch --merged $([[ $1 != "-f" ]] \
&& git rev-parse master) | egrep -v "(^\*|^\s*(master|develop)$)" \
| xargs git branch -d'
นามแฝงยอมรับการ-f
ตั้งค่าสถานะเพิ่มเติม พฤติกรรมเริ่มต้นคือการลบเฉพาะสาขาที่ถูกรวมเข้ากับมาสเตอร์ แต่-f
แฟล็กจะลบสาขาที่ถูกรวมเข้ากับสาขาปัจจุบัน
git sweep
Deleted branch bar (was 9a56952).
Deleted branch masterful (was 9a56952).
Deleted branch notmaster (was 9a56952).
git sweep -f
Deleted branch foo (was 2cea1ab).
git branch -D
จะลบสาขาใด ๆ ไม่ว่าจะเป็นการผสานหรือไม่ก็ตาม