Tôi đã sử dụng câu trả lời của Adam trong nhiều năm nay. Điều đó nói rằng, có một số trường hợp nó không hoạt động như tôi mong đợi:
- các nhánh có chứa từ "master" đã bị bỏ qua, ví dụ "notmaster" hoặc "masterful", thay vì chỉ nhánh chính
- các nhánh có chứa từ "dev" đã bị bỏ qua, ví dụ "dev-test", thay vì chỉ nhánh dev
- xóa các nhánh có thể truy cập từ đầu của nhánh hiện tại (nghĩa là không nhất thiết phải là chủ)
- ở trạng thái CHÍNH tách rời, xóa mọi nhánh có thể truy cập khỏi cam kết hiện tại
1 & 2 rất đơn giản để giải quyết, chỉ cần thay đổi biểu thức chính quy. 3 phụ thuộc vào ngữ cảnh của những gì bạn muốn (nghĩa là chỉ xóa các nhánh chưa được sáp nhập thành chủ hoặc chống lại chi nhánh hiện tại của bạn). 4 có khả năng trở thành thảm họa (mặc dù có thể phục hồi được git reflog
), nếu bạn vô tình chạy nó trong trạng thái CHÍNH tách rời.
Cuối cùng, tôi muốn tất cả điều này nằm trong một lớp lót không yêu cầu một tập lệnh (Bash | Ruby | Python) riêng biệt.
TL; DR
Tạo một bí danh git "quét" chấp nhận một -f
cờ tùy chọn :
git config --global alias.sweep '!git branch --merged $([[ $1 != "-f" ]] \
&& git rev-parse master) | egrep -v "(^\*|^\s*(master|develop)$)" \
| xargs git branch -d'
và gọi nó bằng:
git sweep
hoặc là:
git sweep -f
Câu trả lời dài và chi tiết
Dễ dàng nhất đối với tôi để tạo một ví dụ git repo với một số nhánh và cam kết kiểm tra hành vi chính xác:
Tạo một repo git mới với một cam kết duy nhất
mkdir sweep-test && cd sweep-test && git init
echo "hello" > hello
git add . && git commit -am "initial commit"
Tạo một số chi nhánh mới
git branch foo && git branch bar && git branch develop && git branch notmaster && git branch masterful
git branch --list
bar
develop
foo
* master
masterful
notmaster
Hành vi mong muốn: chọn tất cả các nhánh được hợp nhất ngoại trừ: chính, phát triển hoặc hiện tại
Regex ban đầu bỏ lỡ các nhánh "masterful" và "notmaster":
git checkout foo
git branch --merged | egrep -v "(^\*|master|dev)"
bar
Với regex được cập nhật (hiện không bao gồm "phát triển" thay vì "dev"):
git branch --merged | egrep -v "(^\*|^\s*(master|develop)$)"
bar
masterful
notmaster
Chuyển sang nhánh foo, tạo một cam kết mới, sau đó kiểm tra một nhánh mới, foobar, dựa trên foo:
echo "foo" > foo
git add . && git commit -am "foo"
git checkout -b foobar
echo "foobar" > foobar
git add . && git commit -am "foobar"
Nhánh hiện tại của tôi là foobar và nếu tôi chạy lại lệnh trên để liệt kê các nhánh tôi muốn xóa, nhánh "foo" được bao gồm ngay cả khi nó chưa được sáp nhập vào master:
git branch --merged | egrep -v "(^\*|^\s*(master|develop)$)"
bar
foo
masterful
notmaster
Tuy nhiên, nếu tôi chạy cùng một lệnh trên master, nhánh "foo" không được bao gồm:
git checkout master && git branch --merged | egrep -v "(^\*|^\s*(master|develop)$)"
bar
masterful
notmaster
Và điều này chỉ đơn giản là vì git branch --merged
mặc định là ĐẦU của nhánh hiện tại nếu không có quy định khác. Ít nhất là đối với quy trình làm việc của tôi, tôi không muốn xóa các chi nhánh địa phương trừ khi chúng được hợp nhất thành chủ, vì vậy tôi thích biến thể sau:
git checkout foobar
git branch --merged $(git rev-parse master) | egrep -v "(^\*|^\s*(master|develop)$)"
bar
masterful
notmaster
Tách bang
Dựa vào hành vi mặc định của git branch --merged
thậm chí còn có hậu quả quan trọng hơn trong trạng thái CHÍNH bị tách ra:
git checkout foobar
git checkout HEAD~0
git branch --merged | egrep -v "(^\*|^\s*(master|develop)$)"
bar
foo
foobar
masterful
notmaster
Điều này sẽ xóa chi nhánh tôi vừa mới mở, "foobar" cùng với "foo", gần như chắc chắn không phải là kết quả mong muốn. Tuy nhiên, với lệnh sửa đổi của chúng tôi:
git branch --merged $(git rev-parse master) | egrep -v "(^\*|^\s*(master|develop)$)"
bar
masterful
notmaster
Một dòng, bao gồm xóa thực tế
git branch --merged $(git rev-parse master) | egrep -v "(^\*|^\s*(master|develop)$)" | xargs git branch -d
Tất cả được gói gọn trong một bí danh "quét":
git config --global alias.sweep '!git branch --merged $([[ $1 != "-f" ]] \
&& git rev-parse master) | egrep -v "(^\*|^\s*(master|develop)$)" \
| xargs git branch -d'
Bí danh chấp nhận một -f
cờ tùy chọn . Hành vi mặc định là chỉ xóa các nhánh đã được hợp nhất thành chủ, nhưng -f
cờ sẽ xóa các nhánh đã được sáp nhập vào nhánh hiện tại.
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
sẽ xóa bất kỳ nhánh nào cho dù nó có được hợp nhất hay không.