Git: Làm cách nào để xóa tệp khỏi cam kết lịch sử?


113

Tôi có cam kết với id 56f06019 (ví dụ). Trong lần cam kết đó, tôi đã vô tình gán tệp lớn (50Mb). Trong một cam kết khác, tôi thêm cùng một tệp nhưng có kích thước phù hợp (nhỏ). Bây giờ repo của tôi khi tôi sao chép quá nặng :( Làm cách nào để xóa tệp lớn đó khỏi lịch sử repo để giảm kích thước repo của tôi?


trong trường hợp của tôi, nó không phải là một tệp lớn, mà là một tệp cấu hình chứa tín dụng cơ sở dữ liệu. Tôi đang học git, lúc đó tôi không biết gì về .gitignore.
Rashi


Câu trả lời:


165

Chương 9 của sách Pro Git có phần Xoá Đối tượng .

Hãy để tôi phác thảo các bước ngắn gọn ở đây:

git filter-branch --index-filter \
    'git rm --cached --ignore-unmatch path/to/mylarge_50mb_file' \
    --tag-name-filter cat -- --all

Giống như tùy chọn khôi phục được mô tả trước đây, filter-branchlà hoạt động viết lại. Nếu bạn đã xuất bản lịch sử, bạn sẽ phải --forceđẩy giới thiệu mới.

Phương filter-branchpháp này mạnh hơn đáng kể so với rebasephương pháp này, vì nó

  • cho phép bạn làm việc trên tất cả các chi nhánh / giới thiệu cùng một lúc,
  • đổi tên bất kỳ thẻ nào một cách nhanh chóng
  • hoạt động rõ ràng ngay cả khi đã có một số cam kết hợp nhất kể từ khi thêm tệp
  • hoạt động rõ ràng ngay cả khi tệp được (lại) thêm / xóa nhiều lần trong lịch sử của (a) chi nhánh
  • không tạo các cam kết mới, không liên quan, mà sao chép chúng trong khi sửa đổi các cây được liên kết với chúng. Điều này có nghĩa là những thứ như cam kết đã ký, ghi chú cam kết, v.v. được giữ nguyên

filter-branch giữ các bản sao lưu, vì vậy kích thước của repo sẽ không giảm ngay lập tức trừ khi bạn hết hạn các bản ghi lại và thu thập rác:

rm -Rf .git/refs/original       # careful
git gc --aggressive --prune=now # danger

1
Cần lưu ý rằng điều này dường như không hoạt động trong Windows cmd.exe. Có vẻ như hoạt động dưới cygwin tốt, mặc dù.
Tên giả

2
Tôi có git trên filter-branch để làm việc bằng cách sử dụng dấu nháy kép thay vì đơn dấu ngoặc kép (trên Windows Server 2012 cmd.exe)
JCii

1
Điều làm việc cho tôi là dòng lệnh nhánh bộ lọc này. git filter-branch --force --index-filter 'git rm --ignore-unmatch --cached PathTo/MyFile/ToRemove.dll' -- fbf28b005^.. Sau đó rm --recursive --force .git/refs/originalrm --recursive --force .git/logs Sau đó, tôi sử dụng git prune --expire nowgit gc --aggressive Điều này hoạt động tốt hơn cho tôi so với các bước chính xác của bạn được liệt kê ở trên. Cảm ơn bạn đã bao gồm liên kết đến cuốn sách Git Pro vì nó vô giá.
dacke.geo

Sau lệnh filter-branch, cách duy nhất tôi có thể giảm kích thước của thư mục .git là làm theo lệnh được tìm thấy tại đây: stackoverflow.com/questions/1904860/… git -c gc.reflogExpire = 0 -c gc. reflogExpireUnreachable = 0 -c gc.rerereresolved = 0 \ -c gc.rererereunresolved = 0 -c gc.pruneExpire = now gc "$ @"
Steve Ardis

Đối với thu hẹp repo, tôi đã sử dụng các lệnh được liệt kê trong git filter-branch doc: git-scm.com/docs/...
Ludovic Ronsin


0

Bạn sẽ cần git rebase trong chế độ tương tác, hãy xem ví dụ ở đây: Làm cách nào để xóa cam kết trên GitHub? cách xóa các cam kết cũ .

Nếu cam kết của bạn ở HEAD trừ đi 10 cam kết:

$ git rebase -i HEAD~10

Sau khi ấn bản lịch sử của bạn, bạn cần đẩy lịch sử "mới", bạn cần thêm +lực lượng (xem refspec trong các tùy chọn đẩy ):

$ git push origin +master

Nếu người khác đã nhân bản kho lưu trữ của bạn, bạn sẽ thông báo cho họ, vì bạn vừa thay đổi lịch sử.


3
Điều đó không xóa tệp lớn khỏi lịch sử. Ngoài ra, một cách kinh điển để lực đẩy là git push --forcehay git push -f(mà không đòi hỏi mọi người biết mục tiêu chi nhánh push)
sehe

Dựa trên câu hỏi, tệp mới hoàn toàn giống với tệp cũ, tức là có cùng đường dẫn. Đây là lý do tại sao bạn không thể sử dụng trực tiếp git rmtrên đường dẫn.
Loïc d'Anterroches

2
@sehe, nếu bạn thực hiện rebase loại bỏ cam kết với tệp lớn thì mọi việc sẽ ổn.
vonbrand

@vonbrand chỉ từ chi nhánh mà bạn đã giảm giá. Tôi không giả định rằng nhánh 'từ' bị xóa. Nhưng vâng, nếu bạn xóa một nhánh cây sửa đổi, điều đó sẽ hữu ích: _
sehe

@sehe, chắc chắn, bạn phải đuổi xuống tất cả các nhánh có chứa commit vi phạm. Nếu đó là trước một số bận rộn trong repo, bạn sẽ phải sắp xếp lại rất nhiều việc. Nhưng rebase công cụ cho việc này.
vonbrand

0

Tôi đã thử sử dụng câu trả lời sau trên windows https://stackoverflow.com/a/8741530/8461756

Dấu ngoặc kép không hoạt động trên windows, bạn cần dấu ngoặc kép.

Sau đây làm việc cho tôi.

git filter-branch --force --index-filter "git rm --cached --ignore-unatch PathRelativeRepositoryRoot / bigfile.csv" - --all

Sau khi xóa tệp lớn, tôi đã có thể đẩy các thay đổi của mình lên github master.


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.