- Một lệnh đơn giản để giải quyết vấn đề dọn dẹp các nhánh Git cũ đã được tìm thấy trong tài liệu phát triển nội bộ của CIA
git branch --merged | grep -v "\*\|master" | xargs -n 1 git branch -d
- Lệnh này sẽ xóa hàng loạt các nhánh đã được merge, ngoại trừ nhánh hiện tại và master, từ kết quả của
git branch --merged
- Cũng có phiên bản đã được chỉnh sửa để phù hợp với các dự án hiện đại, nhằm loại trừ các nhánh
main và develop
- Có thể đăng ký làm Git alias để tự động hóa công việc lặp lại; đây là công cụ đơn giản nhưng hữu ích để cải thiện hiệu suất làm việc lâu dài và giữ repository gọn gàng
Mẹo Git được tìm thấy trong Vault7
- Các tài liệu Vault7 do WikiLeaks công bố năm 2017 có chứa các công cụ hack của CIA và tài liệu phát triển nội bộ
- Trong đó có một trang tổng hợp mẹo và thủ thuật Git, phần lớn là các cách dùng thông thường như sửa commit, stash, và bisect
- Một lệnh một dòng được tìm thấy trong tài liệu đó đã được giữ lại trong
~/.zshrc của tôi cho tới tận bây giờ
Vấn đề dọn dẹp các nhánh cũ
- Trong repository Git cục bộ, theo thời gian các nhánh đã merge sẽ tích tụ, khiến việc dọn dẹp trở nên khó khăn
- Các nhánh tính năng, hotfix, hay nhánh thử nghiệm vẫn còn lại sau khi merge, làm danh sách
git branch trở nên rối rắm
- Có thể kiểm tra các nhánh đã merge bằng lệnh
git branch --merged, nhưng xóa thủ công thì rất phiền phức
Lệnh gốc trong tài liệu CIA
Phiên bản lệnh được hiện đại hóa
- Vì đa số dự án hiện nay dùng nhánh
main, có thể chỉnh lệnh như sau
git branch --merged origin/main | grep -vE "^\s*(\*|main|develop)" | xargs -n 1 git branch -d
- Khi chạy trên nhánh
main sau khi triển khai, số lượng nhánh có thể giảm từ vài chục xuống chỉ còn vài nhánh
- Có thể đăng ký lệnh này làm Git alias để chạy tiện hơn
alias ciaclean='git branch --merged origin/main | grep -vE "^\s*(\*|main|develop)" | xargs -n 1 git branch -d'
- Sau đó, chỉ cần nhập
ciaclean trong repository là quá trình dọn dẹp sẽ chạy tự động
Hiệu quả và tính thực dụng
- Lệnh này giúp tiết kiệm vài phút mỗi tuần và giữ danh sách nhánh luôn gọn gàng
- Đây được đánh giá là một công cụ thực dụng, đơn giản nhưng mang lại cải thiện năng suất bền vững
4 bình luận
Trong phần bình luận trên HN có người nói đang dùng chương trình tôi từng làm.
Tôi cũng đang đặt alias
git goneđể dùng. Rất tiện. - alias.gone = ! git fetch -p && git for-each-ref --format '%(refname:short) %(upstream:track)' | awk '$2 == "[gone]" {print $1}' | xargs -r git branch -DTôi không dùng git thuần, mà đang dùng một công cụ tên là
gh-poiđể dọn dẹp.https://github.com/seachicken/gh-poi
Ý kiến trên Hacker News
Tôi dùng alias
git tidyđể dọn dẹp branchKhông xóa branch mặc định (main, master), cũng không đụng đến branch hiện tại hay branch của worktree khác
Các branch đã biến mất trên remote cũng được tự động xóa, và có mã trong cấu hình dotfiles của tôi
init.defaultBranchlà rủi ro. Tên branch mặc định có thể khác nhau ở từng repository, còn thiết lập này là toàn cục (global) nên phải khai báo trướcTôi tạo alias
git defaultđể tự động tìm branch mặc định thực tế từ remote(origin)Tôi dùng lệnh cleanup tích hợp với
fzfCó thể chọn trước các branch đã merge để xóa hàng loạt, và nếu muốn thì loại trừ một số branch
Nó cũng dọn cả branch remote, và có mã trong thiết lập .gitconfig của tôi
Ngoài ra còn dùng biến
user.primaryBranchđể chỉ định branch mặc định khác nhau cho từng repositoryinit.defaultBranchthay thế cũng ổn. Kể cả với repository đã được khởi tạo, chỉ cần đặtgit config --local init.defaultBranch mainlà vẫn hoạt độnggit pull origin main:mainrồi xử lý bằnggit rebase maingit branch --mergedkhông hoạt động đúng trong repository dùng squash mergeVì SHA của commit đã squash khác với HEAD của branch gốc
Tôi tò mò không biết có công cụ nào phát hiện branch đã squash một cách an toàn hay không
Không hoàn hảo nhưng đủ thực dụng, và luôn hiện prompt xác nhận trước khi xóa
Tôi tham khảo thiết lập tự động xóa branch của GitHub
Hầu hết mọi người xử lý bằng cách gắn hook vào sự kiện xóa branch remote
Tôi dùng alias
git goneđể chạygit fetch -prồi dọn các branch ở trạng thái[gone]Vì vậy tôi dùng script kết hợp ba cách:
git branch --merged,git cherry,git log grepTuy nhiên, có thể xuất hiện false positive nếu commit đã bị amend hoặc có nhiều commit
Tôi dùng alias
git lintđể dọn các branch đã mergeNó loại trừ các branch main, master, stable rồi xóa, và tôi hay dùng tổ hợp
git pull --prune && git lintBản thân lệnh Git thì bình thường, nhưng thật thú vị khi đang click linh tinh lại đọc được tài liệu từ nguồn Wikileaks
Dự án “Fine Dining” của CIA là công cụ ngụy trang malware ẩn trong USB thành ứng dụng
Vấn đề ban đầu thực ra chỉ cần giải quyết bằng cách đơn giản là in ra danh sách branch chưa được merge
Thật lạ khi một tác vụ tự nhiên như vậy lại cần đến vài dòng bash
Codebase của Git lớn như thế mà vẫn không có sẵn dưới dạng tính năng mặc định thì khá đáng tiếc
Cũng có thể tham khảo bài blog liên quan
xargshay vòng lặp for thì đây là chuyện nhỏNếu biến nó thành lệnh tích hợp sẵn thì lại phải xử lý đủ loại trường hợp ngoại lệ nên có khi còn phức tạp hơn
Rốt cuộc cũng có phản ứng kiểu “trông như người vừa mới học xong xargs”
Trước đây tôi cũng học mấy thứ này qua blog và bài viết
Dạo này tôi nghiện TUI. Hễ thấy gì bất tiện là tôi lại nhờ Claude-code tạo TUI cho mình
Tôi đã làm một TUI quản lý Git worktree bằng thư viện Textual, và Claude xử lý mã Python khá tốt
tig, một Git TUI lâu đời. Nó cũng tốt để lấy cảm hứngBài viết về tính năng rebase của Magit cũng đáng tham khảo
Tôi cũng triển khai thứ tương tự trong Fish shell
Đó là một hàm dùng
fzfđể chọn và xóa các branch đã biến mất trên remoteCó trong mã dotfiles của tôi