26 điểm bởi GN⁺ 2026-02-21 | 4 bình luận | Chia sẻ qua WhatsApp
  • 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 maindevelop
  • 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

  • Lệnh gốc được đưa ra như sau
    git branch --merged | grep -v "\*\|master" | xargs -n 1 git branch -d  
    
  • Giải thích các thành phần
    • git branch --merged: in ra danh sách tất cả các nhánh cục bộ đã được merge vào nhánh hiện tại
    • grep -v "\*\|master": loại trừ nhánh hiện tại (*) và master
    • xargs -n 1 git branch -d: xóa an toàn từng nhánh còn lại (-d sẽ không xóa các nhánh chưa được merge)

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

 
foriequal0 2026-02-21

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 dùng git-trim cho việc đó:
https://github.com/foriequal0/git-trim
Readme cũng giải thích vì sao trong một số trường hợp nó tốt hơn một câu lệnh bash one-liner.
https://news.ycombinator.com/item?id=47089533

 
youngminz 2026-02-21

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 -D

 
a1eng0 2026-02-21

Tô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

 
GN⁺ 2026-02-21
Ý kiến trên Hacker News
  • Tôi dùng alias git tidy để dọn dẹp branch
    Khô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

    • Dùng init.defaultBranch là 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ước
      Tôi tạo alias git default để tự động tìm branch mặc định thực tế từ remote(origin)
    • Script này thực sự hữu ích nên sẽ rất tốt nếu đóng góp vào git extras
  • Tôi dùng lệnh cleanup tích hợp với fzf
    Có 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 repository

    • Tôi nghĩ dùng init.defaultBranch thay thế cũng ổn. Kể cả với repository đã được khởi tạo, chỉ cần đặt git config --local init.defaultBranch main là vẫn hoạt động
    • Có thể pull từ branch khác mà không cần chuyển branch. Ví dụ git pull origin main:main rồi xử lý bằng git rebase main
  • git branch --merged không hoạt động đúng trong repository dùng squash merge
    Vì 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

    • Gần đây tôi sửa script để xóa theo điều kiện “không có commit trong 30 ngày gần đây” + “không còn branch trên remote”
      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
    • Không chỉ squash mergerebase merge cũng không bị phát hiện
      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 chỉ đơn giản xóa branch local khi branch remote biến mất
      Tôi dùng alias git gone để chạy git fetch -p rồi dọn các branch ở trạng thái [gone]
    • Tôi làm việc trong môi trường dùng Gerrit nên việc rebase xảy ra trên server
      Vì vậy tôi dùng script kết hợp ba cách: git branch --merged, git cherry, git log grep
      Tuy nhiên, có thể xuất hiện false positive nếu commit đã bị amend hoặc có nhiều commit
    • Có vẻ có thể phát hiện branch rỗng bằng cách thử rebase branch đó trước
  • Tôi dùng alias git lint để dọn các branch đã merge
    Nó 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 lint

  • Bả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

    • Cái đó lại giống kỹ thuật tình báo thông thường hơn. Thứ thực sự ‘điên rồ’ là các thí nghiệm kiểu MKULTRA, như bí mật cho người khác dùng LSD
  • 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

    • Nhưng nếu học qua một chút về xargs hay 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
    • Đánh giá kiểu này bằng “số dòng code” thì có vẻ là một tiêu chí kỳ lạ
  • 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”

    • Thái độ như vậy tạo cảm giác gatekeeping. Chia sẻ thứ mình vừa học được là điều tốt
      Trước đây tôi cũng học mấy thứ này qua blog và bài viết
    • Nhưng chuyện học điều này từ tài liệu CIA lại giống như một lát cắt của thế hệ. Giờ là thời đại học qua Internet nhiều hơn là ở trường
    • Cũng có ý kiến tiêu cực, nhưng chính kiểu kết hợp các utility này mới là cái hay của CLI
    • Dù là từ nguồn CIA hay gì đi nữa, nếu ai đó vừa mới học được xargs thì bản thân điều đó đã rất hay rồi
    • Từ góc nhìn của thế hệ Bell Labs thì nội dung này có thể bị xem là quá cơ bản
  • 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

    • Cũng có người gợi ý tig, một Git TUI lâu đời. Nó cũng tốt để lấy cảm hứng
    • Có ý kiến lo rằng code do Claude viết có thể làm hỏng Git repository
    • Cũng có người không biết TUI là gì
    • Nếu là TUI cho Git thì rất khuyến nghị Magit. Nó cũng hữu ích cho việc học
      Bài viết về tính năng rebase của Magit cũng đáng tham khảo
    • Tôi cũng có nhiều công cụ nhỏ làm bằng Claude. Không biết bạn có public chúng dưới dạng mã nguồn mở không
  • 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 remote
    Có trong mã dotfiles của tôi