Bagaimana cara menghapus objek yang tidak digunakan dari repositori git?

90

Saya tidak sengaja menambahkan, berkomitmen, dan mendorong file biner besar dengan komit terbaru saya ke repositori Git.

Bagaimana saya bisa membuat Git menghapus objek yang telah / dibuat untuk komit itu sehingga .gitdirektori saya menyusut ke ukuran yang wajar lagi?

Edit : Terima kasih atas jawaban Anda; Saya mencoba beberapa solusi. Tidak ada yang berhasil. Misalnya yang dari GitHub menghapus file dari riwayat, tetapi .gitukuran direktori tidak berkurang:

$ BADFILES=$(find test_data -type f -exec echo -n "'{}' " \;)

$ git filter-branch --index-filter "git rm -rf --cached --ignore-unmatch $BADFILES" HEAD
Rewrite 14ed3f41474f0a2f624a440e5a106c2768edb67b (66/66)
rm 'test_data/images/001.jpg'
[...snip...]
rm 'test_data/images/281.jpg'
Ref 'refs/heads/master' was rewritten

$ git log -p # looks nice

$ rm -rf .git/refs/original/
$ git reflog expire --all
$ git gc --aggressive --prune
Counting objects: 625, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (598/598), done.
Writing objects: 100% (625/625), done.
Total 625 (delta 351), reused 0 (delta 0)

$ du -hs .git
174M    .git
$ # still 175 MB :-(
Jonas H.
sumber
13
Sekadar pengingat untuk moderator, pertanyaan ini 100% milik SO, bukan superuser.
VonC
Seperti disebutkan di sini ( stackoverflow.com/questions/685319/… ), apakah Anda mencoba mengemas ulang setelah gc Anda? git-repack -adiikuti dengan git-prune-packedmisalnya. Lihat blog.felipebalbi.com/2007/12/19/…
VonC
2
@ Jonas: dan bagaimana jika, setelah Anda melakukan semua itu, Anda mengkloning repo Anda? Apakah Anda kemudian akan mendapatkan klon dengan ukuran yang diperkecil yang diinginkan?
VonC
1
@Jonas: setelah semua yang Anda lakukan ( filter-branch, gc, repack, ...), tidak ada, Anda tidak harus melihat buruk komit sama sekali. Ini pertanda bahwa pembersihan tidak berlangsung seperti yang diharapkan.
VonC

Jawaban:

129

Saya menjawab ini di tempat lain, dan akan menyalin di sini karena saya bangga akan hal itu!

... dan tanpa basa-basi lagi, izinkan saya menyajikan kepada Anda skrip yang berguna ini, git-gc-all, yang dijamin akan menghapus semua sampah git Anda hingga muncul dengan variabel konfigurasi tambahan:

git -c gc.reflogExpire=0 -c gc.reflogExpireUnreachable=0 \
  -c gc.rerereresolved=0 -c gc.rerereunresolved=0 \
  -c gc.pruneExpire=now gc "$@"

Opsi --aggressive mungkin bisa membantu.

CATATAN: ini akan menghapus SEMUA hal yang tidak direferensikan, jadi jangan datang menangis kepada saya jika Anda memutuskan nanti bahwa Anda ingin menyimpan beberapa dari mereka!

Anda mungkin juga perlu menjalankan sesuatu seperti ini terlebih dahulu, ya ampun, git itu rumit !!

git remote rm origin
rm -rf .git/refs/original/ .git/refs/remotes/ .git/*_HEAD .git/logs/
git for-each-ref --format="%(refname)" refs/original/ |
  xargs -n1 --no-run-if-empty git update-ref -d

Saya meletakkan semua ini dalam sebuah skrip, di sini:

http://sam.nipl.net/b/git-gc-all-ferocious

Sam Watkins
sumber
Seperti di stackoverflow.com/questions/1904860/… , beri Anda +1 lagi.
VonC
18
luar biasa: D rencana jahat saya untuk mendapatkan lebih banyak poin dengan mengkloning jawaban telah berhasil !! 1;)
Sam Watkins
Iya! Ini berhasil, tetapi saya harus menjalankan skrip lengkap. Hanya menjalankan perintah gc (dengan opsi konfigurasi) tidak cukup.
Daniel
4
102m hingga 160k .. efektif dan merusak
prusswan
4
Terima kasih banyak untuk naskahnya! Info bonus: xargsPerintah menghasilkan kesalahan pada OS X karena opsi yang tidak dikenal. Solusi paling sederhana: Instal GNU xargs melalui homebrew brew install findutilsdan ganti xargsdengan gxargs.
qqilihq
26

Anda git reflog expire --allsalah. Ini menghapus entri reflog yang lebih lama dari waktu kedaluwarsa, yang defaultnya hingga 90 hari. Gunakan git reflog expire --all --expire=now.

Jawaban saya untuk pertanyaan serupa berkaitan dengan masalah benar-benar menghapus objek yang tidak digunakan dari sebuah repositori.

Josh Lee
sumber
18

1) Hapus file dari git repo (& bukan filesystem):

  • git rm --cached path/to/file

2) Kecilkan repo menggunakan:

  • git gc,

  • atau git gc --aggressive

  • atau git prune

atau kombinasi di atas seperti yang disarankan dalam pertanyaan ini: Kurangi ukuran repositori git

Jamie
sumber
10

Panduan tentang menghapus data sensitif ini dapat diterapkan, menggunakan metode yang sama. Anda akan menulis ulang riwayat untuk menghapus file itu dari setiap revisi yang ada di dalamnya. Ini merusak dan akan menyebabkan repo bentrok dengan pembayaran lain, jadi peringatkan setiap kolaborator terlebih dahulu.

Jika Anda ingin menyimpan biner di repo untuk orang lain, maka tidak ada cara nyata untuk melakukan apa yang Anda inginkan. Hampir semuanya atau tidak sama sekali.

Daenyth
sumber
8

Kuncinya bagi saya ternyata berjalan git repack -A -d -fdan kemudian git gcmengurangi ukuran paket git tunggal yang saya miliki.

Andrew Charneski
sumber
6

Hy!

Git hanya menerima objek yang sebenarnya dibutuhkan saat mengkloning repositori (jika saya memahaminya dengan benar)

Jadi Anda dapat mengubah komit terakhir menghapus file yang ditambahkan secara tidak sengaja, lalu mendorong perubahan Anda ke repositori jarak jauh (dengan opsi -f untuk menimpa komit lama di server juga)

Kemudian ketika Anda membuat klon baru dari repo itu, direktori .git itu harus sekecil sebelum file besar dikomit.

Secara opsional jika Anda ingin menghapus file yang tidak perlu dari server juga, Anda dapat menghapus repositori di server dan mendorong salinan yang baru Anda kloning (yang memiliki riwayat lengkap)

u-foka
sumber
5
git filter-branch --index-filter 'git rm --cached --ignore-unmatch Filename' --prune-empty -- --all

Ingatlah untuk mengubah Filenameyang ingin Anda hapus dari repositori.

Martin
sumber