Xóa tệp .pack lớn được tạo bởi git


112

Tôi đã kiểm tra một lượng tệp trong một nhánh và hợp nhất, sau đó phải xóa chúng và bây giờ tôi còn lại một tệp .pack lớn mà tôi không biết làm cách nào để loại bỏ.

Tôi đã xóa tất cả các tệp bằng cách sử dụng git rm -rf xxxxxxvà tôi cũng chạy --cachedtùy chọn.

Ai đó có thể cho tôi biết cách xóa tệp .pack lớn hiện nằm trong thư mục sau không:

.git/objects/pack/pack-xxxxxxxxxxxxxxxxx.pack

Tôi chỉ cần gỡ bỏ nhánh mà tôi vẫn còn nhưng không còn sử dụng nữa? Hay là có thứ gì khác mà tôi cần chạy?

Tôi không chắc nó tạo ra sự khác biệt bao nhiêu nhưng nó hiển thị một ổ khóa chống lại tệp.

Cảm ơn


BIÊN TẬP

Dưới đây là một số đoạn trích từ bash_history của tôi sẽ cung cấp ý tưởng về cách tôi quản lý để vào trạng thái này (giả sử tại thời điểm này tôi đang làm việc trên một nhánh git có tên là 'my-branch' và tôi có một thư mục chứa nhiều thư mục hơn / các tập tin):

git add .
git commit -m "Adding my branch changes to master"
git checkout master
git merge my-branch
git rm -rf unwanted_folder/
rm -rf unwanted_folder/     (not sure why I ran this as well but I did)

Tôi nghĩ rằng tôi cũng đã chạy phần sau nhưng nó không xuất hiện trong bash_history với những người khác:

git rm -rf --cached unwanted_folder/

Tôi cũng nghĩ rằng tôi đã chạy một số lệnh git (như git gc) để cố gắng dọn dẹp tệp gói nhưng chúng cũng không xuất hiện trong tệp .bash_history.


Bạn có thể làm rõ cách bạn loại bỏ chúng không? Nếu chúng vẫn còn trong lịch sử cam kết, thì chúng vẫn ở trong các tệp gói của bạn.
loganfsmyth

Xin chào @loganfsmyth, tôi đã thêm các tập lệnh lịch sử bash hy vọng sẽ hữu ích.
dùng1116573

Câu trả lời:


201

Vấn đề là, ngay cả khi bạn đã xóa các tệp, chúng vẫn hiện diện trong các bản sửa đổi trước đó. Đó là toàn bộ điểm của git, là ngay cả khi bạn xóa một cái gì đó, bạn vẫn có thể lấy lại nó bằng cách truy cập lịch sử.

Những gì bạn đang làm được gọi là viết lại lịch sử và nó liên quan đến git filter-branchlệnh.

GitHub có một giải thích tốt về vấn đề trên trang web của họ. https://help.github.com/articles/remove-sensitive-data

Để trả lời câu hỏi của bạn trực tiếp hơn, về cơ bản những gì bạn cần chạy là lệnh này với unwanted_filename_or_folderthay thế tương ứng:

git filter-branch --index-filter 'git rm -r --cached --ignore-unmatch unwanted_filename_or_folder' --prune-empty

Điều này sẽ xóa tất cả các tham chiếu đến tệp khỏi lịch sử hoạt động của repo.

Bước tiếp theo, thực hiện chu trình GC để buộc tất cả các tham chiếu đến tệp phải hết hạn và bị xóa khỏi packfile. Không có gì cần được thay thế trong các lệnh này.

git for-each-ref --format='delete %(refname)' refs/original | git update-ref --stdin
# or, for older git versions (e.g. 1.8.3.1) which don't support --stdin
# git update-ref $(git for-each-ref --format='delete %(refname)' refs/original)
git reflog expire --expire=now --all
git gc --aggressive --prune=now

3
Tôi đã đánh dấu nó là được chấp nhận nếu điều đó giúp bất kỳ ai đến câu hỏi này trong tương lai dễ dàng hơn, mặc dù tôi thực sự đã giải quyết vấn đề của mình vào thời điểm đó bằng cách tạo một repo git mới
user1116573

3
Tôi không biết làm thế nào bạn nghĩ ra điều này nhưng ... Bạn là người đàn ông. Cảm ơn.
Ezekiel Victor

5
Câu trả lời này đã chỉ cho tôi đi đúng hướng. Nhưng để thực sự xóa các tệp, cần 3 lệnh nữa 1) git for-each-ref --format='delete %(refname)' refs/original | git update-ref --stdin2) git reflog expire --expire=now --all3)git gc --prune=now
arod

3
Tôi thấy việc sử dụng bfgdễ dàng hơn nhiều. Nó cũng được đề xuất trong tài liệu github chính thức: help.github.com/articles/…
Timo

2
@Timo Sẽ rất tốt nếu bạn thêm câu trả lời mới, nếu mọi thứ đã thay đổi theo thời gian. Cứ liều thử đi!
loganfsmyth

12

Tình huống A : Nếu các tệp lớn của bạn chỉ được thêm vào một nhánh, bạn không cần phải chạy git filter-branch. Bạn chỉ cần xóa nhánh và chạy bộ thu gom rác:

git branch -D mybranch
git reflog expire --expire-unreachable=all --all
git gc --prune=all

Tình huống B : Tuy nhiên, có vẻ như dựa trên lịch sử cơ sở của bạn, bạn đã hợp nhất các thay đổi thành chính. Nếu bạn chưa chia sẻ các thay đổi với bất kỳ ai ( git pushchưa). Điều dễ dàng nhất là đặt lại tổng thể về trước khi hợp nhất với nhánh có tệp lớn. Điều này sẽ loại bỏ tất cả các cam kết khỏi chi nhánh của bạn và tất cả các cam kết được thực hiện thành chính sau khi hợp nhất. Vì vậy, bạn có thể mất các thay đổi - ngoài các tệp lớn - mà bạn có thể thực sự muốn:

git checkout master
git log # Find the commit hash just before the merge
git reset --hard <commit hash>

Sau đó chạy các bước từ kịch bản A.

Tình huống C : Nếu có những thay đổi khác từ chi nhánh hoặc những thay đổi trên cái chính sau khi hợp nhất mà bạn muốn giữ lại, tốt nhất là bạn nên rebase cái chính và đưa vào một cách chọn lọc các cam kết mà bạn muốn:

git checkout master
git log # Find the commit hash just before the merge
git rebase -i <commit hash>

Trong trình chỉnh sửa của bạn, hãy xóa các dòng tương ứng với các cam kết đã thêm các tệp lớn, nhưng giữ nguyên mọi thứ khác. Lưu và thoát. Chi nhánh chính của bạn chỉ nên chứa những gì bạn muốn và không có tệp lớn. Lưu ý rằng git rebasenếu không có -psẽ loại bỏ các cam kết hợp nhất, vì vậy bạn sẽ được để lại lịch sử tuyến tính cho chính sau này <commit hash>. Điều này có thể ổn đối với bạn, nhưng nếu không, bạn có thể thử với-p nhưng git help rebasenói combining -p with the -i option explicitly is generally not a good idea unless you know what you are doing.

Sau đó chạy các lệnh từ kịch bản A.


Tuy nhiên, có một biến thể của Kịch bản A ở đây với một vấn đề bất ngờ bổ sung.

Tình huống Một vấn đề của tôi đã được giải quyết, để xóa một lượng lớn tệp gói tạm thời. Kho lưu trữ được quản lý bởi một máy chủ xây dựng và nó gây ra việc tạo tệp không mong muốn bên trong thư mục .git / objects / pack. Tôi có thể giải phóng các GB có giá trị khỏi đĩa của mình.
xrissz

7

Như loganfsmyth đã nêu trong câu trả lời của mình , bạn cần phải xóa lịch sử git vì các tệp vẫn tiếp tục tồn tại ở đó ngay cả sau khi xóa chúng khỏi repo. Các tài liệu chính thức của GitHub đề xuất BFG mà tôi thấy dễ sử dụng hơn filter-branch:

Xóa tệp khỏi lịch sử

Tải xuống BFG từ trang web của họ. Đảm bảo rằng bạn đã cài đặt java, sau đó tạo bản sao nhân bản và xóa lịch sử. Đảm bảo thay thế YOUR_FILE_NAMEbằng tên của tệp bạn muốn xóa:

git clone --mirror git://example.com/some-big-repo.git
java -jar bfg.jar --delete-files YOUR_FILE_NAME some-big-repo.git
cd some-big-repo.git
git reflog expire --expire=now --all && git gc --prune=now --aggressive
git push

Xóa một thư mục

Tương tự như trên nhưng sử dụng --delete-folders

java -jar bfg.jar --delete-folders YOUR_FOLDER_NAME some-big-repo.git

Sự lựa chọn khác

BFG cũng cho phép các tùy chọn thậm chí còn lạ hơn (xem tài liệu ) như sau:

Xóa tất cả các tệp lớn hơn 100M khỏi lịch sử:

java -jar bfg.jar --strip-blobs-bigger-than 100M some-big-repo.git

Quan trọng!

Khi chạy BFG, hãy cẩn thận rằng cả hai YOUR_FILE_NAMEYOUR_FOLDER_NAMEthực sự chỉ là tên tệp / thư mục. Chúng không phải là đường dẫn , vì vậy một cái gì đó như foo/bar.jpgsẽ không hoạt động! Thay vào đó, tất cả các tệp / thư mục có tên đã chỉ định sẽ bị xóa khỏi lịch sử repo, bất kể chúng tồn tại ở đường dẫn nào hoặc nhánh nào.


Tôi tự hỏi nếu tôi muốn áp dụng bfgcông cụ này cho một repo git cục bộ thì câu lệnh phải như thế nào?
Angel Todorov

5

Một lựa chọn:

chạy git gctheo cách thủ công để cô đọng một số tệp gói thành một hoặc một vài tệp gói. Thao tác này diễn ra liên tục (tức là tệp gói lớn sẽ giữ nguyên hành vi nén của nó) vì vậy việc nén kho lưu trữ định kỳ có thể có lợi vớigit gc --aggressive

Một tùy chọn khác là lưu mã và .git vào một nơi nào đó, sau đó xóa .git và bắt đầu lại bằng cách sử dụng mã hiện có này, tạo một kho lưu trữ git mới ( git init).


Xin chào Michael, tôi đã thử chạy git gcvà tải xuống chỉ một vài tệp gói nhưng tệp lớn vẫn là một trong số chúng và tôi chỉ muốn loại bỏ nó để có thể sao lưu thư mục bên ngoài dễ dàng hơn (zip trước đây là 1 -2Mb, bây giờ là 55Mb). Trừ khi ai đó có thể đề xuất bất cứ điều gì khác, tôi nghĩ tôi có thể phải tạo một git mới. Tôi cho rằng điều này có nghĩa là tôi sẽ mất quyền truy cập vào các chi nhánh mà tôi hiện có, v.v.?
dùng1116573

2
Tôi đã từ bỏ việc thử và chỉ xóa thư mục .git và tạo một kho lưu trữ git mới như bạn đã nói. Tôi sẽ coi đó là một bài học kinh nghiệm. Cảm ơn Michael.
dùng1116573

4
Điều này không có nhiều ý nghĩa. Tại sao bạn không thể yêu cầu git hợp nhất kho lưu trữ hiện tại và xóa các tệp gói trong quá trình này?
jml

4

Chạy lệnh sau, thay thế PATH-TO-YOUR-FILE-WITH-SENSITIVE-DATAbằng đường dẫn đến tệp bạn muốn xóa, không chỉ tên tệp của nó. Các đối số này sẽ:

  1. Buộc Git xử lý, nhưng không kiểm tra, toàn bộ lịch sử của mọi nhánh và thẻ
  2. Xóa tệp đã chỉ định, cũng như mọi cam kết trống được tạo ra do
  3. Ghi đè các thẻ hiện có của bạn
git filter-branch --force --index-filter "git rm --cached --ignore-unmatch PATH-TO-YOUR-FILE-WITH-SENSITIVE-DATA" --prune-empty --tag-name-filter cat -- --all

Thao tác này sẽ xóa tất cả các tham chiếu đến tệp khỏi lịch sử hoạt động của kho lưu trữ.

Bước tiếp theo, thực hiện chu trình GC để buộc tất cả các tham chiếu đến tệp hết hạn và bị xóa khỏi tệp gói. Không có gì cần được thay thế trong các lệnh này.

git update-ref -d refs/original/refs/remotes/origin/master
git for-each-ref --format='delete %(refname)' refs/original | git update-ref --stdin
git reflog expire --expire=now --all
git gc --aggressive --prune=now

Cuối cùng từ phần thứ 2, tôi nhận được 28G repo xuống còn 158M. Hầu như không có gì khác trên Google hoạt động. Cảm ơn bạn.
Sridhar Sarnobat

Tôi đã làm theo các bước trên và đẩy là "git push origin --force --all" và các nhánh từ xa của tôi (master, development và feature / ASD-1010) vẫn không được dọn dẹp. Khi tôi mới nhân bản từ repo từ xa, các tệp .pack vẫn còn. Làm thế nào tôi có thể phản ánh điều này sạch sẽ cho tất cả các chi nhánh git từ xa ??
Sambit Swain

1

Tôi hơi trễ chương trình nhưng trong trường hợp câu trả lời trên không giải quyết được câu hỏi thì tôi đã tìm ra cách khác. Đơn giản chỉ cần xóa tệp lớn cụ thể khỏi .pack. Tôi gặp sự cố này khi tôi vô tình kiểm tra một tệp lớn 2GB. Tôi đã làm theo các bước được giải thích trong liên kết này: http://www.ducea.com/2012/02/07/howto-compleedly-remove-a-file-from-git-history/


Sau khi thực hiện phương pháp này, nó sẽ xóa hoàn toàn toàn bộ lịch sử của dự án hay chỉ xóa tệp được chỉ định.
Samim Aftab Ahmed

-3

đây là một giải pháp tiện dụng hơn là một giải pháp mã hóa. nén tệp. Mở zip ở định dạng xem tệp (khác với giải nén). Xóa tệp .pack. Giải nén và thay thế thư mục. Hoạt động như một sự quyến rũ!

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.