Một cách làm điều này là ngược lại - xóa mọi thứ trừ tệp bạn muốn giữ lại.
Về cơ bản, hãy tạo một bản sao của kho lưu trữ, sau đó sử dụnggit filter-branch
để xóa mọi thứ trừ tệp / thư mục bạn muốn giữ lại.
Ví dụ: tôi có một dự án mà từ đó tôi muốn giải nén tệp tvnamer.py
vào một kho lưu trữ mới:
git filter-branch --tree-filter 'for f in *; do if [ $f != "tvnamer.py" ]; then rm -rf $f; fi; done' HEAD
Điều đó sử dụng git filter-branch --tree-filter
để đi qua từng cam kết, chạy lệnh và gửi lại nội dung thư mục kết quả. Điều này cực kỳ nguy hiểm (vì vậy bạn chỉ nên thực hiện việc này trên một bản sao của kho lưu trữ của mình!) Và có thể mất một lúc (khoảng 1 phút trên kho lưu trữ có 300 cam kết và khoảng 20 tệp)
Lệnh trên chỉ chạy shell-script sau trên mỗi bản sửa đổi, tất nhiên bạn sẽ phải sửa đổi (để làm cho nó loại trừ thư mục con của bạn thay vì tvnamer.py
):
for f in *; do
if [ $f != "tvnamer.py" ]; then
rm -rf $f;
fi;
done
Vấn đề rõ ràng nhất là nó để lại tất cả các thông báo cam kết, ngay cả khi chúng không liên quan đến tệp còn lại. Tập lệnh git-remove-blank-commit , sửa lỗi này ..
git filter-branch --commit-filter 'if [ z$1 = z`git rev-parse $3^{tree}` ]; then skip_commit "$@"; else git commit-tree "$@"; fi'
Bạn cần sử dụng -f
đối số force chạy filter-branch
lại với bất kỳ thứ gì trongrefs/original/
đó (về cơ bản là bản sao lưu)
Tất nhiên điều này sẽ không bao giờ là hoàn hảo, chẳng hạn như nếu tin nhắn cam kết của bạn đề cập đến các tệp khác, nhưng nó gần như cho phép git hiện tại (theo như tôi biết).
Một lần nữa, chỉ chạy điều này trên một bản sao của kho lưu trữ của bạn! - nhưng tóm lại, để xóa tất cả các tệp trừ "thisismyfilename.txt":
git filter-branch --tree-filter 'for f in *; do if [ $f != "thisismyfilename.txt" ]; then rm -rf $f; fi; done' HEAD
git filter-branch -f --commit-filter 'if [ z$1 = z`git rev-parse $3^{tree}` ]; then skip_commit "$@"; else git commit-tree "$@"; fi'