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


708

Thỉnh thoảng tôi bỏ một DVD-rip vào một dự án trang web, sau đó bất cẩn git commit -a -m ..., và, zap, repo đã bị phồng lên bởi 2,2 hợp đồng biểu diễn. Lần sau tôi đã thực hiện một số chỉnh sửa, xóa tệp video và cam kết mọi thứ, nhưng tệp nén vẫn còn đó trong kho lưu trữ, trong lịch sử.

Tôi biết tôi có thể bắt đầu các nhánh từ những cam kết đó và khởi động lại một nhánh này sang nhánh khác. Nhưng tôi nên làm gì để hợp nhất 2 cam kết để tập tin lớn không hiển thị trong lịch sử và được làm sạch trong quy trình thu gom rác?


9
Bài viết này sẽ giúp bạn help.github.com/removing-sensitive-data
MBO


1
Lưu ý rằng nếu tệp lớn của bạn nằm trong một thư mục con, bạn sẽ cần chỉ định đường dẫn tương đối đầy đủ.
Johan

1
Cũng liên quan đến help.github.com/en/articles/ từ
frederj

Nhiều câu trả lời dưới đây chào mời BFG dễ hơn git filter-branch, nhưng tôi thấy điều ngược lại là đúng.
2540625

Câu trả lời:


605

Sử dụng BFG Repo-Cleaner , một giải pháp thay thế đơn giản hơn, nhanh hơn để git-filter-branchđược thiết kế đặc biệt để xóa các tệp không mong muốn khỏi lịch sử Git.

Làm cẩn thận theo các hướng dẫn sử dụng , phần cốt lõi chỉ là thế này:

$ java -jar bfg.jar --strip-blobs-bigger-than 100M my-repo.git

Bất kỳ tệp nào có kích thước trên 100 MB (không có trong cam kết mới nhất của bạn ) sẽ bị xóa khỏi lịch sử kho lưu trữ Git của bạn. Sau đó, bạn có thể sử dụng git gcđể dọn sạch dữ liệu chết:

$ git gc --prune=now --aggressive

BFG thường nhanh hơn ít nhất 10-50 lần so với khi chạy git-filter-branchvà thường dễ sử dụng hơn.

Tiết lộ đầy đủ: Tôi là tác giả của BFG Repo-Cleaner.


4
@tony Thật đáng để lặp lại toàn bộ quy trình nhân bản và xóa để xem tin nhắn yêu cầu bạn kéo lại xảy ra hay không, nhưng gần như chắc chắn là do máy chủ từ xa của bạn được định cấu hình để từ chối các cập nhật không chuyển tiếp nhanh (nghĩa là nó được định cấu hình để ngăn bạn từ mất lịch sử - đó chính xác là những gì bạn muốn làm). Bạn cần thay đổi cài đặt đó trên điều khiển từ xa hoặc không thành công, đẩy lịch sử repo được cập nhật lên một repo trống hoàn toàn mới.
Roberto Tyley

1
@RobertoTyley Cảm ơn. Tôi đã thử nó 3 lần khác nhau và tất cả đều có cùng một thông điệp. Vì vậy, tôi cũng nghĩ rằng bạn đúng về việc máy chủ từ xa được cấu hình để từ chối các bản cập nhật không chuyển tiếp nhanh. Tôi sẽ xem xét chỉ đẩy repo cập nhật lên một repo hoàn toàn mới. Cảm ơn bạn!
Tony

7
@RobertoTyley Hoàn hảo, bạn tiết kiệm thời gian của tôi, cảm ơn rất nhiều. Nhân tiện, có lẽ nên làm git push --forcesau các bước của bạn, nếu không thì repo từ xa vẫn không thay đổi.
li2

3
+1 để thêm git push --force. Cũng đáng chú ý: lực đẩy từ xa có thể không được phép từ xa (gitlab.com không, theo mặc định. Phải "không bảo vệ" chi nhánh).
MatrixManAtYrService

25
Tôi nghĩ rằng thuật ngữ Trump các công cụ đầu ra là một chút.
Chris

564

Những gì bạn muốn làm là rất phá vỡ nếu bạn đã xuất bản lịch sử cho các nhà phát triển khác. Xem Phục hồi từ thượng nguồn Rebase Hồi giáo trong git rebasetài liệu cho các bước cần thiết sau khi sửa chữa lịch sử của bạn.

Bạn có ít nhất hai tùy chọn: git filter-branchvà một rebase tương tác, cả hai đều được giải thích bên dưới.

Sử dụng git filter-branch

Tôi gặp vấn đề tương tự với dữ liệu kiểm tra nhị phân cồng kềnh từ nhập Subversion và đã viết về việc xóa dữ liệu khỏi kho git .

Nói lịch sử git của bạn là:

$ git lola --name-status
* f772d66 (HEAD, master) Login page
| A     login.html
* cb14efd Remove DVD-rip
| D     oops.iso
* ce36c98 Careless
| A     oops.iso
| A     other.html
* 5af4522 Admin page
| A     admin.html
* e738b63 Index
  A     index.html

Lưu ý rằng git lola là một bí danh không chuẩn nhưng rất hữu ích. Với công --name-statustắc, chúng ta có thể thấy các sửa đổi cây liên quan đến từng cam kết.

Trong cam kết của Carless, (có tên đối tượng SHA1 là ce36c98), tệp oops.iso này là DVD-rip được thêm vào một cách tình cờ và bị xóa trong lần xác nhận tiếp theo, cb14efd. Sử dụng kỹ thuật được mô tả trong bài viết trên blog đã nói ở trên, lệnh để thực thi là:

git filter-branch --prune-empty -d /dev/shm/scratch \
  --index-filter "git rm --cached -f --ignore-unmatch oops.iso" \
  --tag-name-filter cat -- --all

Tùy chọn:

  • --prune-empty loại bỏ các xác nhận trở nên trống rỗng ( nghĩa là không thay đổi cây) do hoạt động của bộ lọc. Trong trường hợp điển hình, tùy chọn này tạo ra một lịch sử sạch hơn.
  • -dđặt tên một thư mục tạm thời chưa tồn tại để sử dụng để xây dựng lịch sử đã lọc. Nếu bạn đang chạy trên một bản phân phối Linux hiện đại, chỉ định một cây trong/dev/shm sẽ dẫn đến việc thực thi nhanh hơn .
  • --index-filterlà sự kiện chính và chạy ngược lại chỉ số ở mỗi bước trong lịch sử. Bạn muốn xóa oops.isobất cứ nơi nào nó được tìm thấy, nhưng nó không có trong tất cả các cam kết. Lệnhgit rm --cached -f --ignore-unmatch oops.iso xóa DVD-rip khi có mặt và không bị lỗi khác.
  • --tag-name-filtermô tả cách viết lại tên thẻ. Một bộ lọc củacat là hoạt động nhận dạng. Kho lưu trữ của bạn, như mẫu ở trên, có thể không có bất kỳ thẻ nào, nhưng tôi đã bao gồm tùy chọn này để có tính tổng quát.
  • -- chỉ định kết thúc các tùy chọn để git filter-branch
  • --all tiếp theo -- là tốc ký cho tất cả các ref. Kho lưu trữ của bạn, giống như mẫu ở trên, có thể chỉ có một ref (chính), nhưng tôi đã bao gồm tùy chọn này để có tính tổng quát.

Sau một vài lần khuấy động, lịch sử bây giờ là:

$ git lola --name-status
* 8e0a11c (HEAD, master) Login page
| A     login.html
* e45ac59 Careless
| A     other.html
|
| * f772d66 (refs/original/refs/heads/master) Login page
| | A   login.html
| * cb14efd Remove DVD-rip
| | D   oops.iso
| * ce36c98 Careless
|/  A   oops.iso
|   A   other.html
|
* 5af4522 Admin page
| A     admin.html
* e738b63 Index
  A     index.html

Lưu ý rằng cam kết mới của Car Carless chỉ bổ sung other.htmlvà cam kết xóa Xóa DVD DVD không còn trên nhánh chính. Chi nhánh được dán nhãn refs/original/refs/heads/masterchứa các cam kết ban đầu của bạn trong trường hợp bạn mắc lỗi. Để xóa nó, hãy làm theo các bước trong Danh sách kiểm tra để thu nhỏ kho lưu trữ.

$ git update-ref -d refs/original/refs/heads/master
$ git reflog expire --expire=now --all
$ git gc --prune=now

Để thay thế đơn giản hơn, sao chép kho lưu trữ để loại bỏ các bit không mong muốn.

$ cd ~/src
$ mv repo repo.old
$ git clone file:///home/user/src/repo.old repo

Sử dụng một file:///...bản sao URL sao chép các đối tượng thay vì chỉ tạo các liên kết cứng.

Bây giờ lịch sử của bạn là:

$ git lola --name-status
* 8e0a11c (HEAD, master) Login page
| A     login.html
* e45ac59 Careless
| A     other.html
* 5af4522 Admin page
| A     admin.html
* e738b63 Index
  A     index.html

Tên đối tượng SHA1 cho hai lần xác nhận đầu tiên (trang Index Index và trang quản trị trang trực tuyến) giữ nguyên vì hoạt động của bộ lọc không sửa đổi các cam kết đó. oops.isoTrang web không có người lái bị mất và người đăng nhập Trang đã có một phụ huynh mới, vì vậy SHA1 của họ đã thay đổi.

Rebase tương tác

Với lịch sử:

$ git lola --name-status
* f772d66 (HEAD, master) Login page
| A     login.html
* cb14efd Remove DVD-rip
| D     oops.iso
* ce36c98 Careless
| A     oops.iso
| A     other.html
* 5af4522 Admin page
| A     admin.html
* e738b63 Index
  A     index.html

bạn muốn loại bỏ oops.iso khỏi dịch vụ của Car Carless như thể bạn chưa bao giờ thêm nó, và sau đó, Xóa Xóa DVD-rip, là vô dụng đối với bạn. Do đó, kế hoạch của chúng tôi trong một cuộc nổi loạn tương tác là giữ cho trang Admin Admin, chỉnh sửa trực tuyến, không cần chỉnh sửa, xóa và xóa bỏ DVD-rip.

Chạy $ git rebase -i 5af4522bắt đầu một trình soạn thảo với các nội dung sau.

pick ce36c98 Careless
pick cb14efd Remove DVD-rip
pick f772d66 Login page

# Rebase 5af4522..f772d66 onto 5af4522
#
# Commands:
#  p, pick = use commit
#  r, reword = use commit, but edit the commit message
#  e, edit = use commit, but stop for amending
#  s, squash = use commit, but meld into previous commit
#  f, fixup = like "squash", but discard this commit's log message
#  x, exec = run command (the rest of the line) using shell
#
# If you remove a line here THAT COMMIT WILL BE LOST.
# However, if you remove everything, the rebase will be aborted.
#

Thực hiện kế hoạch của chúng tôi, chúng tôi sửa đổi nó thành

edit ce36c98 Careless
pick f772d66 Login page

# Rebase 5af4522..f772d66 onto 5af4522
# ...

Đó là, chúng tôi xóa dòng này bằng cách loại bỏ DVD-rip-Thay đổi và thay đổi hoạt động trên trang web của Car Carless editthay vì pick.

Lưu-thoát trình soạn thảo thả chúng tôi tại một dấu nhắc lệnh với thông báo sau.

Stopped at ce36c98... Careless
You can amend the commit now, with

        git commit --amend

Once you are satisfied with your changes, run

        git rebase --continue

Như thông báo cho chúng tôi biết, chúng tôi đang thực hiện cam kết của chúng tôi muốn chỉnh sửa, vì vậy chúng tôi chạy hai lệnh.

$ git rm --cached oops.iso
$ git commit --amend -C HEAD
$ git rebase --continue

Việc đầu tiên loại bỏ các tập tin vi phạm từ chỉ mục. Cái thứ hai sửa đổi hoặc sửa đổi Dịch vụ chăm sóc người khuyết tật là một chỉ mục được cập nhật và -C HEADhướng dẫn git sử dụng lại thông điệp cam kết cũ. Cuối cùng,git rebase --continue đi trước với phần còn lại của hoạt động rebase.

Điều này cho một lịch sử của:

$ git lola --name-status
* 93174be (HEAD, master) Login page
| A     login.html
* a570198 Careless
| A     other.html
* 5af4522 Admin page
| A     admin.html
* e738b63 Index
  A     index.html

đó là những gì bạn muốn


4
Tại sao tôi không thể đẩy khi sử dụng nhánh bộ lọc git, không thể đẩy một số giới thiệu đến 'git@bitbucket.org: sản phẩm / myproject.git' Để ngăn bạn khỏi mất lịch sử, các cập nhật không chuyển tiếp nhanh đã bị từ chối Hợp nhất từ ​​xa thay đổi trước khi đẩy một lần nữa.
Agung Prasetyo

11
Thêm tùy chọn -f(hoặc --force) vào git pushlệnh của bạn : Thông thường, lệnh từ chối cập nhật một ref từ xa không phải là tổ tiên của ref cục bộ được sử dụng để ghi đè lên nó. Cờ này vô hiệu hóa kiểm tra. Điều này có thể khiến kho lưu trữ từ xa bị mất các xác nhận; sử dụng nó một cách cẩn thận
Greg Bacon

5
Đây là một câu trả lời tuyệt vời kỹ lưỡng giải thích việc sử dụng nhánh git-filter để xóa các tệp lớn không mong muốn khỏi lịch sử, nhưng đáng chú ý là kể từ khi Greg viết câu trả lời của mình, BFG Repo-Cleaner đã được phát hành, thường nhanh hơn và dễ dàng hơn sử dụng - xem câu trả lời của tôi để biết chi tiết.
Roberto Tyley

1
Sau khi tôi thực hiện một trong các quy trình trên, kho lưu trữ từ xa (trên GitHub) KHÔNG xóa tệp lớn. Chỉ có địa phương nào. Tôi buộc đẩy và nada. Tôi đang thiếu gì?
azatar

1
Điều này cũng hoạt động trên dirs. ... "git rm --cached -rf --ignore-unmatch path/to/dir"...
rynop

198

Tại sao không sử dụng lệnh đơn giản nhưng mạnh mẽ này?

git filter-branch --tree-filter 'rm -f DVD-rip' HEAD

Các --tree-filtertùy chọn chạy lệnh quy định sau mỗi lần thanh toán của dự án và sau đó recommits kết quả. Trong trường hợp này, bạn xóa một tệp có tên DVD-rip khỏi mọi ảnh chụp, cho dù nó có tồn tại hay không.

Nếu bạn biết cam kết nào đã giới thiệu tệp khổng lồ (giả sử 35dsa2), bạn có thể thay thế CHÍNH bằng 35dsa2..PHẦN để tránh viết lại quá nhiều lịch sử, do đó tránh chuyển hướng cam kết nếu bạn chưa đẩy. Nhận xét lịch sự này của @ alpha_989 dường như quá quan trọng để bỏ qua đây.

Xem liên kết này .


3
Đây là một giải pháp tốt! Tôi đã tạo một ý chính có tập lệnh python để liệt kê các tệp & git cmd sẽ xóa tệp bạn muốn làm sạch gist.github.com/ariv3ra/16fd94e46345e62cfcbf
punkdata

5
Tốt hơn nhiều so với bfg. Tôi không thể xóa tập tin từ một git bằng bfg, nhưng lệnh này đã giúp
podarok

4
Điều đó thật tuyệt. Chỉ cần một lưu ý cho những người khác là bạn sẽ phải làm điều này trên mỗi nhánh nếu tệp lớn nằm trong nhiều nhánh.
James

2
Trên Windows tôi có fatal: bad revision 'rm', cái mà tôi đã sửa bằng cách sử dụng "thay vì '. Lệnh tổng thể:git filter-branch --force --index-filter "git rm --cached -r --ignore-unmatch oops.iso" --prune-empty --tag-name-filter cat -- --all
marcotama

2
Nếu bạn biết commitnơi bạn đặt tệp vào (nói 35dsa2), bạn có thể thay thế HEADbằng 35dsa2..HEAD. tree-filterchậm hơn nhiều so với index-filtercách nó không cố gắng kiểm tra tất cả các cam kết và viết lại chúng. nếu bạn sử dụng CHÍNH, nó sẽ cố gắng làm điều đó.
alpha_989

86

(Câu trả lời tốt nhất tôi từng thấy cho vấn đề này là: https://stackoverflow.com/a/42544963/714112 , được sao chép ở đây vì chủ đề này xuất hiện cao trong bảng xếp hạng tìm kiếm của Google nhưng cái khác thì không)

Một lớp vỏ nhanh chóng rực rỡ

Kịch bản shell này hiển thị tất cả các đối tượng blob trong kho lưu trữ, được sắp xếp từ nhỏ nhất đến lớn nhất.

Đối với repo mẫu của tôi, nó chạy nhanh hơn khoảng 100 lần so với những cái khác được tìm thấy ở đây.
Trên hệ thống Athlon II X4 đáng tin cậy của tôi, nó xử lý kho Linux Kernel với 5.622.155 đối tượng chỉ trong hơn một phút .

Tập lệnh cơ sở

git rev-list --objects --all \
| git cat-file --batch-check='%(objecttype) %(objectname) %(objectsize) %(rest)' \
| awk '/^blob/ {print substr($0,6)}' \
| sort --numeric-sort --key=2 \
| cut --complement --characters=13-40 \
| numfmt --field=2 --to=iec-i --suffix=B --padding=7 --round=nearest

Khi bạn chạy mã trên, bạn sẽ nhận được đầu ra đẹp như người đọc như thế này:

...
0d99bb931299  530KiB path/to/some-image.jpg
2ba44098e28f   12MiB path/to/hires-image.png
bd1741ddce0d   63MiB path/to/some-video-1080p.mp4

Xóa tệp nhanh

Giả sử sau đó bạn muốn xóa các tệp abtừ mọi cam kết có thể truy cập từ đó HEAD, bạn có thể sử dụng lệnh này:

git filter-branch --index-filter 'git rm --cached --ignore-unmatch a b' HEAD

3
Nếu repo của bạn có bất kỳ thẻ nào, bạn cũng có thể muốn thêm cờ --tag-name-filter catđể gắn thẻ lại các cam kết tương ứng mới khi chúng được viết lại, nghĩa là git filter-branch --index-filter 'git rm --cached --ignore-unmatch a b' --tag-name-filter cat HEAD(xem câu trả lời liên quan này )
naitsirhc

3
Hướng dẫn về Mac và một số thông tin khác xuất hiện trong bài đăng được liên kết ban đầu
nruth

3
git filter-branch --index-filter 'git rm --cached --ignore-unmatch <filename>' HEADquyền làm việc của dơi
eleijonmarck

câu trả lời yêu thích của tôi một tinh chỉnh nhỏ để sử dụng trên mac os (sử dụng lệnh gnu)git rev-list --objects --all \ | git cat-file --batch-check='%(objecttype) %(objectname) %(objectsize) %(rest)' \ | awk '/^blob/ {print substr($0,6)}' \ | sort --numeric-sort --key=2 \ | gnumfmt --field=2 --to=iec-i --suffix=B --padding=7 --round=nearest
Florian Oswald

kịch bản tuyệt vời với danh sách rev nhưng nó không hoạt động với tư cách là bí danh, bạn có biết làm thế nào để làm điều đó không?
Robin Manoli

47

Sau khi thử hầu như mọi câu trả lời trong SO, cuối cùng tôi đã tìm thấy viên ngọc này đã nhanh chóng xóa và xóa các tệp lớn trong kho lưu trữ của tôi và cho phép tôi đồng bộ lại: http://www.zyxware.com/articles/4027/how-to-delete -files-Permanent-from-your-local-and-remote-git-reporiesories

CD vào thư mục làm việc cục bộ của bạn và chạy lệnh sau:

git filter-branch -f --index-filter "git rm -rf --cached --ignore-unmatch FOLDERNAME" -- --all

thay thế FOLDERNAME bằng tệp hoặc thư mục bạn muốn xóa khỏi kho git đã cho.

Một khi điều này được thực hiện, chạy các lệnh sau để dọn sạch kho lưu trữ cục bộ:

rm -rf .git/refs/original/
git reflog expire --expire=now --all
git gc --prune=now
git gc --aggressive --prune=now

Bây giờ đẩy tất cả các thay đổi vào kho lưu trữ từ xa:

git push --all --force

Điều này sẽ dọn sạch kho lưu trữ từ xa.


Làm việc như một cơ duyên đối với tôi.
Ramon Vasconcelos

3
Cái này cũng có tác dụng với tôi. Loại bỏ một thư mục cụ thể (trong trường hợp của tôi, một thư mục chứa các tệp quá lớn hoặc repo Github) trên kho lưu trữ, nhưng giữ nó trên hệ thống tệp cục bộ trong trường hợp tồn tại.
skizzo

Đã làm cho tôi! không có lịch sử nào còn lại có thể gây nhầm lẫn (nếu có ai đó sao chép ngay bây giờ), hãy đảm bảo bạn có kế hoạch cập nhật bất kỳ liên kết bị hỏng, phụ thuộc, v.v.
ruoho ruotsi

38

Các lệnh này hoạt động trong trường hợp của tôi:

git filter-branch --force --index-filter 'git rm --cached -r --ignore-unmatch oops.iso' --prune-empty --tag-name-filter cat -- --all
rm -rf .git/refs/original/
git reflog expire --expire=now --all
git gc --prune=now
git gc --aggressive --prune=now

Nó có chút khác biệt so với các phiên bản trên.

Đối với những người cần đẩy nó lên github / bitbucket (tôi chỉ thử nghiệm điều này với bitbucket):

# WARNING!!!
# this will rewrite completely your bitbucket refs
# will delete all branches that you didn't have in your local

git push --all --prune --force

# Once you pushed, all your teammates need to clone repository again
# git pull will not work

4
Làm thế nào nó khác với ở trên, tại sao nó tốt hơn?
Andy Hayden

1
Vì một số lý do, phiên bản mkljun không bị giảm dung lượng git trong trường hợp của tôi, tôi đã xóa các tệp khỏi chỉ mục bằng cách sử dụng git rm --cached files. Đề xuất của Greg Bacon hoàn chỉnh hơn và hoàn toàn giống với đề xuất này, nhưng anh ta đã bỏ lỡ chỉ số - Force cho các trường hợp khi bạn sử dụng nhánh lọc nhiều lần và anh ta đã viết rất nhiều thông tin, rằng phiên bản của tôi giống như sơ yếu lý lịch của nó
Kostanos

1
Điều này thực sự hữu ích nhưng tôi cần sử dụng -ftùy chọn không chỉ -rfở đây git rm --cached -rf --ignore-unmatch oops.isothay vì git rm --cached -r --ignore-unmatch oops.isotheo @ lfender6445 bên dưới
drstevok

10

Chỉ cần lưu ý rằng các lệnh này có thể rất phá hủy. Nếu nhiều người đang làm việc trên repo, tất cả họ sẽ phải kéo cây mới. Ba lệnh giữa không cần thiết nếu mục tiêu của bạn KHÔNG làm giảm kích thước. Bởi vì nhánh bộ lọc tạo ra một bản sao lưu của tệp đã xóa và nó có thể ở đó trong một thời gian dài.

$ git filter-branch --index-filter "git rm -rf --cached --ignore-unmatch YOURFILENAME" HEAD
$ rm -rf .git/refs/original/ 
$ git reflog expire --all 
$ git gc --aggressive --prune
$ git push origin master --force

11
KHÔNG chạy các lệnh này trừ khi bạn muốn tạo ra nỗi đau to lớn cho chính mình. Nó đã xóa rất nhiều tập tin mã nguồn gốc của tôi. Tôi giả định rằng nó sẽ lọc một số tệp lớn khỏi lịch sử cam kết của tôi trong GIT (theo câu hỏi ban đầu), tuy nhiên, tôi nghĩ rằng lệnh này được thiết kế để lọc vĩnh viễn các tệp khỏi cây mã nguồn gốc của bạn (sự khác biệt lớn!). Hệ thống của tôi: Windows, VS2012, Nhà cung cấp kiểm soát nguồn Git.
Contango

2
Tôi đã sử dụng lệnh này: git filter-branch --force --index-filter 'git rm --cached -r --ignore-unmatch oops.iso' --prune-empty --tag-name-filter cat -- --allthay vì lệnh đầu tiên từ mã của bạn
Kostanos


8

Nếu bạn biết cam kết của mình là gần đây thay vì đi qua toàn bộ cây, hãy làm như sau: git filter-branch --tree-filter 'rm LARGE_FILE.zip' HEAD~10..HEAD


7

Tôi đã sử dụng tài khoản bitbucket, nơi tôi đã vô tình lưu trữ các bản sao lưu * .jpa của trang web của mình.

git filter-branch --prune-empty --index-filter 'git rm -rf --cached --ignore-unmatch MY-BIG-DIRECTORY-OR-FILE' --tag-name-filter cat -- --all

Relpace MY-BIG-DIRECTORYvới thư mục trong câu hỏi để viết lại hoàn toàn lịch sử của bạn ( bao gồm các thẻ ).

nguồn: https://web.archive.org/web/20170727144429/http://naleid.com:80/blog/2012/01/17/finding-and-purging-big-files-from-git-history/


1
Câu trả lời này đã giúp tôi, ngoại trừ kịch bản trong câu trả lời có một vấn đề nhỏ và nó không tìm kiếm trong tất cả các chi nhánh tạo thành tôi. Nhưng lệnh trong liên kết đã làm điều đó một cách hoàn hảo.
Ali B

5

Điều này sẽ xóa nó khỏi lịch sử của bạn

git filter-branch --force --index-filter 'git rm -r --cached --ignore-unmatch bigfile.txt' --prune-empty --tag-name-filter cat -- --all

Điều này làm việc cho tôi cảm ơn !!
Sonja Brits

Điều này hoạt động trong trường hợp của tôi. Tôi chạy cái này trên nhánh chủ của bạn.
S. Domeng

4

Về cơ bản tôi đã làm những gì về câu trả lời này: https://stackoverflow.com/a/11032521/1286423

(đối với lịch sử, tôi sẽ sao chép-dán nó ở đây)

$ git filter-branch --index-filter "git rm -rf --cached --ignore-unmatch YOURFILENAME" HEAD
$ rm -rf .git/refs/original/ 
$ git reflog expire --all 
$ git gc --aggressive --prune
$ git push origin master --force

Nó không hoạt động, vì tôi thích đổi tên và di chuyển mọi thứ rất nhiều. Vì vậy, một số tệp lớn nằm trong các thư mục đã được đổi tên và tôi nghĩ gc không thể xóa tham chiếu đến các tệp đó vì tham chiếu trong treecác đối tượng trỏ đến các tệp đó. Giải pháp cuối cùng của tôi để thực sự giết nó là:

# First, apply what's in the answer linked in the front
# and before doing the gc --prune --aggressive, do:

# Go back at the origin of the repository
git checkout -b newinit <sha1 of first commit>
# Create a parallel initial commit
git commit --amend
# go back on the master branch that has big file
# still referenced in history, even though 
# we thought we removed them.
git checkout master
# rebase on the newinit created earlier. By reapply patches,
# it will really forget about the references to hidden big files.
git rebase newinit

# Do the previous part (checkout + rebase) for each branch
# still connected to the original initial commit, 
# so we remove all the references.

# Remove the .git/logs folder, also containing references
# to commits that could make git gc not remove them.
rm -rf .git/logs/

# Then you can do a garbage collection,
# and the hidden files really will get gc'ed
git gc --prune --aggressive

Repo của tôi (cái .git) đã thay đổi từ 32MB thành 388KB, mà ngay cả nhánh lọc cũng không thể sạch.


4

git filter-branchlà một lệnh mạnh mẽ mà bạn có thể sử dụng nó để xóa một tệp lớn khỏi lịch sử cam kết. Tệp sẽ lưu lại trong một thời gian và Git sẽ xóa nó trong bộ sưu tập rác tiếp theo. Dưới đây là toàn bộ quá trình xóa các tập tin từ lịch sử cam kết . Để an toàn, quy trình dưới đây sẽ chạy các lệnh trên một nhánh mới trước. Nếu kết quả là những gì bạn cần, sau đó đặt lại nó về nhánh bạn thực sự muốn thay đổi.

# Do it in a new testing branch
$ git checkout -b test

# Remove file-name from every commit on the new branch
# --index-filter, rewrite index without checking out
# --cached, remove it from index but not include working tree
# --ignore-unmatch, ignore if files to be removed are absent in a commit
# HEAD, execute the specified command for each commit reached from HEAD by parent link
$ git filter-branch --index-filter 'git rm --cached --ignore-unmatch file-name' HEAD

# The output is OK, reset it to the prior branch master
$ git checkout master
$ git reset --soft test

# Remove test branch
$ git branch -d test

# Push it with force
$ git push --force origin master

2

Sử dụng Tiện ích mở rộng Git , đây là công cụ UI. Nó có một plugin có tên "Tìm tệp lớn" tìm tệp lage trong kho và cho phép loại bỏ chúng vĩnh viễn.

Không sử dụng 'git bộ lọc nhánh' trước khi sử dụng công cụ này, vì nó sẽ không thể tìm thấy các tệp bị xóa bởi 'bộ lọc nhánh' (Altough 'bộ lọc nhánh' không xóa hoàn toàn các tệp khỏi tệp gói kho lưu trữ) .


Phương pháp này là waaay quá chậm cho các kho lớn. Phải mất hơn một giờ để liệt kê các tập tin lớn. Sau đó, khi tôi đi xóa các tập tin, sau một giờ chỉ là 1/3 quá trình xử lý tập tin đầu tiên tôi muốn xóa.
kristianp

Vâng, nó chậm, nhưng công việc ... Bạn có biết gì nhanh hơn không?

1
Không sử dụng nó, nhưng BFG Repo-Cleaner, theo câu trả lời khác trên trang này.
kristianp

2

Bạn có thể làm điều này bằng cách sử dụng branch filterlệnh:

git filter-branch --tree-filter 'rm -rf path/to/your/file' HEAD


2

Có những câu trả lời rất hay trong chủ đề này, nhưng trong khi đó nhiều câu hỏi đã lỗi thời. Việc sử dụng git-filter-branchkhông còn được khuyến khích nữa, vì nó rất khó sử dụng và cực kỳ chậm trên các kho lưu trữ lớn.

git-filter-repo là nhanh hơn và đơn giản hơn để sử dụng.

git-filter-repolà tập lệnh Python, có sẵn tại github: https://github.com/newren/git-filter-repo .

Bạn chỉ cần một tệp: tập lệnh Python3 git-filter-repo. Sao chép nó vào một đường dẫn được bao gồm trong biến PATH. Trên Windows, bạn có thể phải thay đổi dòng đầu tiên của tập lệnh (tham khảo INSTALL.md). Bạn cần cài đặt Python3 trên hệ thống của mình, nhưng đây không phải là vấn đề lớn.

Đầu tiên bạn có thể chạy

git filter-repo --analyze

Điều này giúp bạn xác định những việc cần làm tiếp theo.

Bạn có thể xóa tệp DVD-rip ở mọi nơi:

 git filter-repo --invert-paths --path-match DVD-rip

Bộ lọc-repo thực sự nhanh chóng. Một tác vụ mất khoảng 9 giờ trên máy tính của tôi bằng nhánh lọc, đã được hoàn thành sau 4 phút bởi bộ lọc-repo. Bạn có thể làm nhiều điều hay hơn với bộ lọc-repo. Tham khảo tài liệu cho điều đó.

Cảnh báo: Làm điều này trên một bản sao của kho lưu trữ của bạn. Nhiều hành động của bộ lọc-repo không thể được hoàn tác. bộ lọc-repo sẽ thay đổi băm cam kết của tất cả các xác nhận đã sửa đổi (tất nhiên) và tất cả các hậu duệ của chúng xuống các cam kết cuối cùng!


1

Khi bạn gặp phải vấn đề này, git rmsẽ không đủ, vì git nhớ rằng tệp đã tồn tại một lần trong lịch sử của chúng tôi và do đó sẽ giữ một tham chiếu đến nó.

Để làm cho mọi thứ tồi tệ hơn, việc nổi loạn cũng không dễ dàng, bởi vì bất kỳ tham chiếu nào đến blob sẽ ngăn người thu gom rác git dọn sạch không gian. Điều này bao gồm các tài liệu tham khảo từ xa và reflog tham khảo.

Tôi kết hợp lại git forget-blob, một tập lệnh nhỏ cố gắng loại bỏ tất cả các tham chiếu này và sau đó sử dụng nhánh bộ lọc git để viết lại mọi cam kết trong nhánh.

Một khi blob của bạn hoàn toàn không được kiểm chứng, git gcsẽ thoát khỏi nó

Cách sử dụng khá đơn giản git forget-blob file-to-forget. Bạn có thể biết thêm thông tin ở đây

https://ownyourbits.com/2017/01/18/completely-remove-a-file-from-a-git-reposeective-with-git-forget-blob/

Tôi kết hợp điều này nhờ vào câu trả lời từ Stack Overflow và một số mục blog. Tín dụng cho họ!


bạn nên lấy cái này trong homebrew
Cameron E

0

Ngoài git filter-branch(giải pháp git chậm nhưng thuần túy) và BFG (dễ dàng hơn và rất hiệu quả), còn có một công cụ khác để lọc với hiệu suất tốt:

https://github.com/xoustx/git-rocket-filter

Từ mô tả của nó:

Mục đích của bộ lọc tên lửa git tương tự như lệnh git-filter-branchtrong khi cung cấp các tính năng độc đáo sau:

  • Viết lại nhanh chóng các cam kết và cây (theo thứ tự từ x10 đến x100).
  • Hỗ trợ tích hợp cho cả danh sách trắng với --keep (giữ tệp hoặc thư mục) và danh sách đen với các tùy chọn --remove.
  • Sử dụng mẫu .gitignore giống như để lọc cây
  • C # Scripting nhanh chóng và dễ dàng cho cả lọc cam kết và lọc cây
  • Hỗ trợ cho kịch bản trong lọc cây trên mỗi mẫu tệp / thư mục
  • Tự động cắt tỉa cam kết trống / không thay đổi, bao gồm các cam kết hợp nhất
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.