Hapus file .pack besar yang dibuat oleh git

112

Saya memeriksa banyak file ke dalam cabang dan menggabungkannya dan kemudian harus menghapusnya dan sekarang saya pergi dengan file .pack besar yang saya tidak tahu bagaimana cara membuangnya.

Saya menghapus semua file menggunakan git rm -rf xxxxxxdan saya juga menjalankan --cachedopsi juga.

Adakah yang bisa memberi tahu saya bagaimana saya bisa menghapus file .pack besar yang saat ini ada di direktori berikut:

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

Apakah saya hanya perlu menghapus cabang yang masih saya miliki tetapi tidak lagi digunakan? Atau ada hal lain yang perlu saya jalankan?

Saya tidak yakin seberapa besar perbedaannya tetapi ini menunjukkan gembok pada file.

Terima kasih


EDIT

Berikut adalah beberapa kutipan dari bash_history saya yang seharusnya memberi gambaran bagaimana saya bisa masuk ke status ini (asumsikan pada titik ini saya sedang mengerjakan cabang git yang disebut 'cabang-saya' dan saya punya folder yang berisi lebih banyak folder / file):

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)

Saya pikir saya juga menjalankan perintah berikut tetapi tidak muncul di bash_history dengan yang lain:

git rm -rf --cached unwanted_folder/

Saya juga berpikir saya menjalankan beberapa perintah git (seperti git gc) untuk mencoba merapikan file paket tetapi mereka juga tidak muncul di file .bash_history.

pengguna1116573
sumber
Dapatkah Anda menjelaskan bagaimana Anda menghapusnya? Jika mereka masih dalam riwayat komit, maka mereka masih ada dalam file paket Anda.
loganfsmyth
Hai @loganfsmyth, saya telah menambahkan skrip riwayat bash yang semoga dapat membantu.
pengguna1116573

Jawaban:

201

Masalahnya adalah, meskipun Anda menghapus file, file tersebut masih ada di revisi sebelumnya. Itulah inti dari git, adalah bahwa meskipun Anda menghapus sesuatu, Anda masih bisa mendapatkannya kembali dengan mengakses riwayat.

Apa yang ingin Anda lakukan disebut menulis ulang riwayat, dan ini melibatkan git filter-branchperintah.

GitHub memiliki penjelasan yang bagus tentang masalah tersebut di situs mereka. https://help.github.com/articles/remove-sensitive-data

Untuk menjawab pertanyaan Anda lebih langsung, yang pada dasarnya perlu Anda jalankan adalah perintah ini dengan unwanted_filename_or_folderdiganti sesuai:

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

Ini akan menghapus semua referensi ke file dari riwayat aktif repo.

Langkah selanjutnya, untuk melakukan siklus GC untuk memaksa semua referensi ke file akan kedaluwarsa dan dihapus dari file paket. Tidak ada yang perlu diganti dalam perintah ini.

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
loganfsmyth
sumber
3
Saya telah menandainya sebagai diterima jika itu memudahkan siapa pun yang datang ke pertanyaan ini di masa mendatang, meskipun saya sebenarnya memecahkan masalah saya saat itu dengan membuat repo git baru
pengguna1116573
3
Saya tidak tahu bagaimana Anda datang dengan ini tapi ... Anda orangnya. Terima kasih.
Ezekiel Victor
5
Jawaban ini mengarahkan saya ke arah yang benar. Tetapi untuk benar-benar menghapus file, diperlukan 3 perintah lagi 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
Saya merasa menggunakan bfgjauh lebih mudah. Ini juga direkomendasikan di dokumen resmi github: help.github.com/articles/…
Timo
2
@Timo Adalah baik untuk menambahkan jawaban baru, jika banyak hal berubah seiring waktu. Lakukan!
loganfsmyth
12

Skenario A : Jika file besar Anda hanya ditambahkan ke cabang, Anda tidak perlu menjalankannya git filter-branch. Anda hanya perlu menghapus cabang dan menjalankan pengumpulan sampah:

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

Skenario B : Namun, sepertinya berdasarkan riwayat bash Anda, Anda telah menggabungkan perubahan ke master. Jika Anda belum membagikan perubahan dengan siapa pun ( git pushbelum). Hal termudah adalah mengatur ulang master kembali ke sebelum bergabung dengan cabang yang memiliki file besar. Ini akan menghilangkan semua komitmen dari cabang Anda dan semua komitmen yang dibuat untuk master setelah penggabungan. Jadi, Anda mungkin kehilangan perubahan - selain file besar - yang mungkin sebenarnya Anda inginkan:

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

Kemudian jalankan langkah-langkah dari skenario A.

Skenario C : Jika ada perubahan lain dari cabang atau perubahan pada master setelah penggabungan yang ingin Anda pertahankan, sebaiknya rebase master dan secara selektif menyertakan komit yang Anda inginkan:

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

Di editor Anda, hapus baris yang sesuai dengan komit yang menambahkan file besar, tetapi biarkan yang lainnya apa adanya. Simpan dan keluar. Cabang master Anda seharusnya hanya berisi apa yang Anda inginkan, dan tidak ada file besar. Perhatikan bahwa git rebasetanpa -pakan menghilangkan komit gabungan, jadi Anda akan memiliki riwayat linier untuk master setelahnya <commit hash>. Ini mungkin baik-baik saja untuk Anda, tetapi jika tidak, Anda dapat mencobanya -p, tetapi git help rebaseberkata combining -p with the -i option explicitly is generally not a good idea unless you know what you are doing.

Kemudian jalankan perintah dari skenario A.

onlynone
sumber
Ada varian Skenario A di sini dengan, bagaimanapun, masalah ekstra tak terduga.
Skenario A memecahkan masalah tambang, untuk menghapus file paket sementara dalam jumlah besar. Repositori dikelola oleh server build dan menyebabkan pembuatan file yang tidak diinginkan di dalam folder .git / objek / paket. Saya dapat membebaskan GB yang berharga dari disk saya.
xrissz
7

Seperti yang telah dinyatakan loganfsmyth dalam jawabannya , Anda perlu membersihkan riwayat git karena file tetap ada di sana bahkan setelah menghapusnya dari repo. Dokumen resmi GitHub merekomendasikan BFG yang menurut saya lebih mudah digunakan daripada filter-branch:

Menghapus file dari sejarah

Unduh BFG dari situs web mereka. Pastikan Anda telah menginstal java, lalu buat klon cermin dan riwayat pembersihan. Pastikan untuk mengganti YOUR_FILE_NAMEdengan nama file yang ingin Anda hapus:

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

Hapus folder

Sama seperti di atas tapi pakai --delete-folders

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

Pilihan lain

BFG juga memungkinkan opsi yang lebih mewah (lihat dokumen ) seperti ini:

Hapus semua file yang lebih besar dari 100 juta dari riwayat:

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

Penting!

Saat menjalankan BFG, berhati-hatilah karena keduanya YOUR_FILE_NAMEdan YOUR_FOLDER_NAMEmemang hanya nama file / folder. Itu bukan jalan , jadi sesuatu seperti foo/bar.jpgitu tidak akan berhasil! Sebaliknya semua file / folder dengan nama yang ditentukan akan dihapus dari riwayat repo, tidak peduli jalur atau cabang mana mereka ada.

Timo
sumber
Saya ingin tahu apakah saya ingin menerapkan bfgalat ini ke repo git lokal, seperti apa tampilan perintahnya?
Angel Todorov
5

Satu pilihan:

dijalankan git gcsecara manual untuk memadatkan sejumlah file paket menjadi satu atau beberapa file paket. Operasi ini bersifat persisten (yaitu file paket besar akan mempertahankan perilaku kompresinya) sehingga mungkin bermanfaat untuk mengompresi repositori secara berkala dengangit gc --aggressive

Pilihan lainnya adalah menyimpan kode dan .git di suatu tempat lalu menghapus .git dan mulai lagi menggunakan kode yang ada ini, membuat repositori git baru ( git init).

Michael Durrant
sumber
Hai Michael, saya mencoba menjalankan git gcdan turun ke hanya beberapa file paket tetapi yang besar masih salah satunya dan saya hanya ingin menyingkirkannya sehingga saya dapat membuat cadangan folder secara eksternal lebih mudah (zip sebelumnya adalah 1 -2Mb, sekarang 55Mb). Kecuali seseorang dapat menyarankan hal lain, saya pikir saya mungkin harus membuat git baru. Saya berasumsi ini berarti saya akan kehilangan akses ke cabang yang saat ini saya miliki dll ...?
pengguna1116573
2
Saya berhenti mencoba dan baru saja menghapus folder .git dan membuat repositori git baru seperti yang Anda katakan. Saya akan menganggapnya sebagai pelajaran yang didapat. Terima kasih Michael.
pengguna1116573
4
Ini tidak masuk akal. Mengapa Anda tidak bisa memberi tahu git untuk mengonsolidasi repositori saat ini dan menghapus file paket dalam prosesnya?
jml
4

Jalankan perintah berikut, ganti PATH-TO-YOUR-FILE-WITH-SENSITIVE-DATAdengan jalur ke file yang ingin Anda hapus, bukan hanya nama filenya. Argumen ini akan:

  1. Paksa Git untuk memproses, tetapi tidak memeriksa, seluruh riwayat setiap cabang dan tag
  2. Hapus file yang ditentukan, serta komit kosong yang dihasilkan sebagai hasilnya
  3. Timpa tag Anda yang sudah ada
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

Ini akan secara paksa menghapus semua referensi ke file dari riwayat aktif repo.

Langkah berikutnya, untuk melakukan siklus GC untuk memaksa semua referensi ke file tersebut kedaluwarsa dan dihapus dari file paket. Tidak ada yang perlu diganti dalam perintah ini.

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
Benjamin Wasula
sumber
Akhirnya dari bagian ke-2 saya mendapat repo 28G hingga 158M. Hampir tidak ada hal lain di Google yang berhasil. Terima kasih.
Sridhar Sarnobat
Saya mengikuti langkah-langkah di atas, dan mendorong sebagai "git push origin --force --all" dan masih cabang jarak jauh saya (master, develop dan feature / ASD-1010) tidak dibersihkan. Ketika saya baru kloning dari repo jarak jauh, file .pack itu masih ada. Bagaimana cara mencerminkan pembersihan ini ke semua cabang git yang jauh ??
Sambit Swain
1

Saya agak terlambat untuk pertunjukan tetapi jika jawaban di atas tidak menyelesaikan pertanyaan, maka saya menemukan cara lain. Cukup hapus file besar tertentu dari .pack. Saya mengalami masalah ini di mana saya memeriksa file 2GB besar secara tidak sengaja. Saya mengikuti langkah-langkah yang dijelaskan di tautan ini: http://www.ducea.com/2012/02/07/howto-completely-remove-a-file-from-git-history/

Rishabh Kumar
sumber
Setelah melakukan metode ini akan menghapus seluruh riwayat proyek, atau hanya akan menghapus file yang ditentukan.
Samim Aftab Ahmed
-3

ini lebih merupakan solusi praktis daripada solusi pengkodean. zip file tersebut. Buka zip dalam format tampilan file (berbeda dengan unzip). Hapus file .pack. Buka zip dan ganti foldernya. Bekerja seperti pesona!

shreya10
sumber