Git deposundaki büyük bir dosyayı kayıt geçmişinden nasıl kaldırırım / silebilirim?


708

Bazen bir DVD ripini bir web sitesi projesine bıraktım, sonra dikkatsizce git commit -a -m ...ve zap, repo 2.2 konser tarafından şişirildi. Bir dahaki sefere bazı düzenlemeler yaptım, video dosyasını sildim ve her şeyi yaptım, ancak sıkıştırılmış dosya hala depoda, tarihte orada.

Bu taahhütlerden şubelere başlayabileceğimi ve bir şubeyi diğerine yeniden pazarlayabileceğimi biliyorum. Ancak, büyük dosyanın tarihte gösterilmemesi ve çöp toplama prosedüründe temizlenmesi için 2 taahhüdü birleştirmek için ne yapmalıyım?




1
Büyük dosyanız bir alt dizindeyse, göreli yolun tamamını belirtmeniz gerektiğini unutmayın.
Johan


BFG'nin altındaki birçok cevap daha kolay git filter-branch, ancak tam tersini doğru buldum.
2540625

Yanıtlar:


605

Git geçmişinden istenmeyen dosyaları kaldırmak için özel olarak tasarlanmış olan daha basit ve daha hızlı bir alternatif olan BFG Repo-Cleaner'ı kullanın git-filter-branch.

Kullanım talimatlarını dikkatlice takip edin , çekirdek kısım sadece bu:

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

100 MB'tan büyük dosyalar ( en son işleminizde bulunmayan) Git deponuzun geçmişinden kaldırılır. Daha sonra git gcölü verileri temizlemek için kullanabilirsiniz :

$ git gc --prune=now --aggressive

BFG tipik olarak koşudan en az 10-50x daha hızlıdır git-filter-branchve genellikle kullanımı daha kolaydır.

Tam açıklama: BFG Repo-Cleaner'ın yazarıyım.


4
@tony Yeniden klonlamanızı isteyen mesajın tekrarlanıp tekrarlanmadığını görmek için tüm klonlama ve temizleme prosedürünü tekrarlamaya değer, ancak bunun nedeni kesinlikle uzak sunucunuzun hızlı ileri olmayan güncellemeleri reddetmek üzere yapılandırılmış olması (yani, sizi durdurmak için yapılandırılmış olması) tarihi kaybetmekten - ki tam olarak yapmak istediğiniz şey budur). Bu ayarın uzaktan kumandada değiştirilmesini veya başarısız olması durumunda, güncellenmiş repo geçmişini yepyeni bir boş repoya aktarmanız gerekir.
Roberto Tyley

1
@RobertoTyley Teşekkürler. 3 Farklı kez denedim ve hepsi aynı mesajla sonuçlandı. Bu yüzden, uzak sunucunun hızlı ileri olmayan güncellemeleri reddetmek üzere yapılandırıldığını da düşünüyorum. Güncellenen repoyu yepyeni bir repoya itmeyi düşüneceğim. Teşekkür ederim!
Tony

7
@RobertoTyley Mükemmel, zamanımı kurtarıyorsun, çok teşekkürler. Bu arada, belki git push --forceadımlarınızdan sonra yapmalısınız , aksi takdirde uzaktan repo hala değişmez.
li2

3
Eklemek için +1 git push --force. Ayrıca kayda değer: uzaktan kumanda tarafından zorla itmelere izin verilmeyebilir (gitlab.com varsayılan olarak izin vermez. Dalın "korumasını kaldırmak" zorundaydı).
MatrixManAtYrService

25
Bence aracın çıkardığı Trump jargonu biraz fazla.
Chris

564

Tarihi diğer geliştiricilere yayınladıysanız, yapmak istediğiniz şey oldukça rahatsız edicidir. Geçmişinizi onardıktan sonra gerekli adımlar için git rebasedokümantasyondaki “Yukarı Akış Rebase'den Kurtarma” başlığına bakın .

En az iki seçeneğiniz vardır: git filter-branchve ikisi de aşağıda açıklanan etkileşimli bir yeniden temel.

kullanma git filter-branch

Bir Subversion içe aktarımından hantal ikili test verileri ile benzer bir sorun yaşadım ve git deposundan veri kaldırma hakkında yazdım .

Git geçmişinizin:

$ 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

Bunun git lolastandart olmayan ancak son derece kullanışlı bir takma ad olduğunu unutmayın. İle --name-statusanahtar, her taahhüt ilişkili ağaç değişiklikleri görebilirsiniz.

"Dikkatsiz" komutunda (SHA1 nesne adı ce36c98 olan) dosya oops.iso, kazayla eklenen ve sonraki işlem olan cb14efd'de kaldırılan DVD ripidir. Yukarıda adı geçen blog gönderisinde açıklanan tekniği kullanarak, yürütme komutu şöyledir:

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

Seçenekler:

  • --prune-emptyfiltre işlemi sonucunda boş kalan ( yani ağacı değiştirmeyen) taahhütleri kaldırır . Tipik durumda, bu seçenek daha temiz bir geçmiş oluşturur.
  • -dfiltrelenmiş geçmişi oluşturmak için henüz kullanılmayan geçici bir dizini adlandırır. Modern bir Linux dağıtımında çalışıyorsanız, bir ağacın/dev/shm belirtilmesi daha hızlı yürütmeye neden olur .
  • --index-filterana olaydır ve geçmişin her adımında dizine karşı çalışır. Bulunduğu yeri kaldırmak istiyorsunuz oops.iso, ancak tüm taahhütlerde mevcut değil. Komut git rm --cached -f --ignore-unmatch oops.iso, DVD rip'i mevcut olduğunda siler ve aksi halde başarısız olmaz.
  • --tag-name-filteretiket adlarının nasıl yeniden yazılacağını açıklar. Bir filtre catkimlik işlemidir. Deponuzda, yukarıdaki örnekte olduğu gibi, herhangi bir etiket olmayabilir, ancak tam genellik için bu seçeneği ekledim.
  • -- için seçeneklerin sonunu belirtir git filter-branch
  • --allAşağıdaki --tüm referanslar için kestirme. Deponuzda, yukarıdaki örnekte olduğu gibi, yalnızca bir ref (master) olabilir, ancak tam genelleme için bu seçeneği ekledim.

Bazı çalkalamalardan sonra, tarih şimdi:

$ 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

Yeni "Dikkatsiz" komutunun yalnızca eklediğine other.htmlve "DVD-rip'i Kaldır" komutunun artık ana dalda olmadığına dikkat edin. Etiketli şube refs/original/refs/heads/master, bir hata yapmanız durumunda orijinal taahhütlerinizi içerir. Kaldırmak için, “Bir Depoyu Küçültmek İçin Denetim Listesi” bölümündeki adımları izleyin .

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

Daha basit bir alternatif için, istenmeyen bitleri atmak için havuzu klonlayın.

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

Bir file:///...klon URL'si kullanmak, nesneleri yalnızca sabit bağlantılar oluşturmak yerine kopyalar.

Şimdi geçmişiniz:

$ 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

İlk iki işlemin (“Dizin” ve “Yönetici sayfası”) SHA1 nesne adları aynı kaldı, çünkü filtre işlemi bu taahhütleri değiştirmedi. Kayıp “Dikkatsiz” oops.isoonların SHA1s böylece ve “Giriş sayfası”, yeni bir ebeveyn var yaptılar değişikliği.

Etkileşimli rebase

Geçmişi ile:

$ 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

oops.isodaha önce hiç eklememişsiniz gibi “Dikkatsiz” öğesinden kaldırmak istiyorsunuz ve daha sonra “DVD-rip'i Kaldır” işinize yaramaz. Bu nedenle, etkileşimli bir yeniden plana girme planımız “Yönetici sayfası” nı “Dikkatsiz” olarak düzenlemeyi ve “DVD-rip'i Kaldır” a atmayı amaçlıyor.

Running $ git rebase -i 5af4522, aşağıdaki içeriğe sahip bir düzenleyici başlatır.

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.
#

Planımızı uygulayarak,

edit ce36c98 Careless
pick f772d66 Login page

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

Yani, “DVD-rip'i Kaldır” ile çizgiyi sileriz ve “Dikkatsiz” üzerindeki işlemi edityerine değiştiririz pick.

Düzenleyiciyi kaydetmeyi bırak, aşağıdaki mesajla birlikte bir komut isteminde bizi bırakır.

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

Mesajın söylediği gibi, düzenlemek istediğimiz “Dikkatsiz” taahhüt üzerindeyiz, bu yüzden iki komut çalıştırıyoruz.

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

Birincisi, rahatsız edici dosyayı dizinden kaldırır. İkincisi “Dikkatsiz” i güncellenmiş endeks olarak değiştirir veya değiştirir ve git'e -C HEADeski işlem mesajını yeniden kullanma talimatı verir. Son olarak, git rebase --continuegeri kalan operasyonun geri kalanıyla devam ediyor.

Bu şu tarihçeyi verir:

$ 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

istediğin şey bu.


4
Git filtre-dalını kullanırken neden itemiyorum, 'git@bitbucket.org: product / myproject.git' e bazı referanslar gönderemedim Neden geçmişinizi kaybetmemeniz için, hızlı ileri olmayan güncellemeler reddedildi Uzaktan kumandayı birleştir tekrar basmadan önce değişir.
Agung Prasetyo

11
Ekle -f(ya --forceda hiç) seçeneğini git pushkomutu: “Genellikle, komut üzerine yazmak için kullanılan lokal ref atalarından olmayan bir uzak ref güncellemek için reddeder. Bu bayrak denetimi devre dışı bırakır. Bu, uzak deponun taahhütlerini kaybetmesine neden olabilir; dikkatli kullanın. ”
Greg Bacon

5
Bu, istenmeyen büyük dosyaları tarihten kaldırmak için git-filter-branch kullanımını açıklayan harika bir cevaptır, ancak Greg cevabını yazdığından, genellikle daha hızlı ve daha kolay olan BFG Repo-Cleaner'ın yayınlandığını belirtmek gerekir. kullanın - ayrıntılar için cevabıma bakın.
Roberto Tyley

1
Yukarıdaki yordamlardan birini gerçekleştirdikten sonra, uzak depo (GitHub'da) büyük dosyayı SİLMEZ. Sadece yerel. İtme ve nadayı zorlarım. Neyi kaçırıyorum?
azatar

1
bu dirs üzerinde de çalışır. ... "git rm --cached -rf --ignore-unmatch path/to/dir"...
rynop

198

Neden bu basit ama güçlü komutu kullanmıyorsunuz?

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

--tree-filterOpsiyon projenin her ödeme sonra belirli bir komutu çalıştırır ve sonra sonuçları recommits. Bu durumda, DVD-rip adlı bir dosyayı var olsun ya da olmasın her anlık görüntüden kaldırırsınız.

Hangi dosyanın büyük dosyayı tanıttığını biliyorsanız (35dsa2 diyelim), çok fazla geçmişin yeniden yazılmasını önlemek için HEAD'i 35dsa2..HEAD ile değiştirebilirsiniz, böylece henüz itmediyseniz sapma işlemlerinden kaçının. @ Alpha_989'ın bu yorumu sayesinde buradan ayrılmak çok önemli görünüyor.

Bu bağlantıya bakın .


3
Bu iyi bir çözüm! Temizlemek
punkdata

5
Bfg'den çok daha iyi. Bir git bfg ile dosyayı temizleyemedim, ancak bu komut yardımcı oldu
podarok

4
Bu harika. Diğerleri için, büyük dosya birden çok daldaysa bunu dal başına yapmanız gerekecek bir not.
James

2
Windows'da aldım fatal: bad revision 'rm', bunun "yerine kullanarak sabitledim '. Genel komut:git filter-branch --force --index-filter "git rm --cached -r --ignore-unmatch oops.iso" --prune-empty --tag-name-filter cat -- --all
marcotama

2
commitDosyayı nereye koyduğunuzu biliyorsanız (diyelim 35dsa2) HEADile değiştirebilirsiniz 35dsa2..HEAD. bu yoldan tree-filterçok daha yavaştır index-filterve tüm taahhütleri kontrol etmeye ve yeniden yazmaya çalışmaz. HEAD kullanırsanız, bunu yapmaya çalışacaktır.
alpha_989

86

(Bu soruna gördüğüm en iyi yanıt: https://stackoverflow.com/a/42544963/714112 , bu konu Google arama sıralamalarında yüksek göründüğü için kopyalandı, ancak diğeri değil)

Fast Çarpıcı derecede hızlı bir kabuk tek astar 🚀

Bu kabuk betiği, depodaki tüm blob nesnelerini en küçükten en büyüğe doğru sıralanmış şekilde görüntüler.

Örnek depom için, burada bulunanlardan yaklaşık 100 kat daha hızlı koştu .
Güvenilir Athlon II X4 sistemimde, Linux Çekirdeği deposunu 5,622,155 nesnesi ile bir dakikadan fazla bir sürede ele alıyor .

Temel Komut Dosyası

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

Kodun üzerinde çalıştığınızda, insan tarafından okunabilir güzel bir çıktı elde edersiniz :

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

File Hızlı Dosya Kaldırma 🚀

Daha sonra dosyaları kaldırmak istediğinizden ave bulaşılabilen her işlemden HEADbu komutu kullanabilirsiniz:

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

3
Repo'nuzda herhangi bir etiket varsa, büyük olasılıkla --tag-name-filter catyeni ilgili taahhütleri yeniden git filter-branch --index-filter 'git rm --cached --ignore-unmatch a b' --tag-name-filter cat HEAD
yazıldıklarında

3
Mac talimatları ve diğer bazı bilgiler, orijinal bağlantılı
mesajda

3
git filter-branch --index-filter 'git rm --cached --ignore-unmatch <filename>' HEADyarasa hakkı
eleijonmarck

benim favori cevabım. Mac OS'de kullanmak için hafif bir değişiklik (gnu komutlarını kullanarak)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

rev-list ile serin script ama benim için bir takma ad olarak işe yaramadı, bunu nasıl yapacağına dair herhangi bir fikir?
Robin Manoli

47

SO'daki hemen hemen her cevabı denedikten sonra, nihayet havuzumdaki büyük dosyaları hızla silip silen ve tekrar senkronize etmeme izin veren bu gemiyi buldum: http://www.zyxware.com/articles/4027/how-to-delete -dosyalar-kalıcı-den-your-yerel-ve-uzak-git-depoları

CD'yi yerel çalışma klasörünüze yerleştirin ve aşağıdaki komutu çalıştırın:

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

FOLDERNAME yerine verilen git deposundan kaldırmak istediğiniz dosya veya klasörü yazın.

Bu yapıldıktan sonra, yerel havuzu temizlemek için aşağıdaki komutları çalıştırın:

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

Şimdi tüm değişiklikleri uzak depoya aktarın:

git push --all --force

Böylece uzak depo temizlenir.


Benim için bir cazibe gibi çalıştı.
Ramon Vasconcelos

3
Bu benim için de işe yaradı. Depodaki belirli bir klasörden (benim durumumda, çok büyük dosyalar veya bir Github repo içeren bir klasör) kurtulur, ancak varsa yerel dosya sisteminde tutar.
skizzo

Benim için çalıştı! emin olun (hemen klonu birisi varsa) herhangi bir kırık linkleri, bağımlılıklar, vb güncellemek için bir planı var öyküsü potansiyel kafa karıştırıcı hangi bırakılır
ruoho Ruotsi

38

Bu komutlar benim durumumda çalıştı:

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

Yukarıdaki sürümlerden biraz farklıdır.

Bunu github / bitbucket'e itmesi gerekenler için (Bunu sadece bitbucket ile test ettim):

# 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
Yukarıdakilerden farkı ne, neden daha iyi?
Andy Hayden

1
Nedense mkljun sürümü gitmeme boşluk azalmaz benim durumumda, zaten kullanarak dizininden dosyaları kaldırmıştı git rm --cached files. Greg Bacon'un teklifi daha eksiksiz ve bu benimkiyle tamamen aynı, ancak filtre şubesini birden çok kez kullandığınızda durumlar için --force endeksini kaçırdı ve o kadar çok bilgi yazdı ki sürümüm özgeçmiş gibi onun.
Kostanos

1
Bu gerçekten yardımcı oldu ama aşağıdaki @ lfender6445 göre yerine -fsadece -rfburada git rm --cached -rf --ignore-unmatch oops.isokullanmak git rm --cached -r --ignore-unmatch oops.isozorunda
drstevok

10

Bu komutların çok yıkıcı olabileceğini unutmayın. Repo üzerinde daha fazla insan çalışıyorsa, hepsinin yeni ağacı çekmesi gerekecek. Hedefiniz boyutu küçültmek DEĞİLSE, üç orta komut gerekli değildir. Filtre dalı kaldırılan dosyanın bir yedeğini oluşturduğundan uzun süre orada kalabilir.

$ 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
Kendiniz için büyük bir acı yaratmak istemiyorsanız bu komutları ÇALIŞTIRMAYIN. Orijinal kaynak kod dosyalarımın çoğunu sildi. GIT'teki taahhüt geçmişimden bazı büyük dosyaları temizleyeceğini varsaydım (orijinal soruya göre), ancak bu komutun orijinal kaynak kod ağacınızdan (büyük fark!) Dosyaları kalıcı olarak temizlemek için tasarlandığını düşünüyorum. Sistemim: Windows, VS2012, Git Kaynak Kontrol Sağlayıcısı.
Contango

2
Bu komutu kullandım: git filter-branch --force --index-filter 'git rm --cached -r --ignore-unmatch oops.iso' --prune-empty --tag-name-filter cat -- --allkodunuzdaki ilk komut yerine
Kostanos


8

Tüm ağacın içinden geçmek yerine taahhüdünüzün yakın zamanda gerçekleştiğini biliyorsanız aşağıdakileri yapın: git filter-branch --tree-filter 'rm LARGE_FILE.zip' HEAD~10..HEAD


7

Sitemin yanlışlıkla * .jpa yedeklerini sakladığım bir bitbucket hesabıyla karşılaştım.

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-DIRECTORYsöz konusu klasöre tamamen (geçmişinizi yeniden yazmaya etiketleri dahil ).

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


1
Bu yanıt bana yardımcı oldu, ancak cevaptaki komut dosyasının küçük bir sorunu var ve beni oluşturan tüm dallarda arama yapmıyor. Ancak bağlantıdaki komut mükemmel bir şekilde yaptı.
Ali B

5

Bu, geçmişinizden kaldıracak

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

Bu benim için çalıştı teşekkürler!
Sonja

Bu benim durumumda işe yarıyor. Bunu ana dalınızda çalıştırıyorum.
S. Domeng

4

Temelde bu cevapta ne yaptım: https://stackoverflow.com/a/11032521/1286423

(tarih için buraya kopyalayıp yapıştıracağım)

$ 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

İşe yaramadı, çünkü işleri yeniden adlandırmayı ve taşımayı seviyorum. Bu yüzden bazı büyük dosya yeniden adlandırılmış klasörlerde vardı ve gc bu dosyalara treeişaret eden nesnelerde referans nedeniyle bu dosyalara referansı silemediğini düşünüyorum . Gerçekten öldürmek için nihai çözümüm şuydu:

# 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

Benim Repo ( .git32MB den 388KB olarak değiştirildi), bu daha da filtre şube olabilir temiz değil.


4

git filter-branchbüyük bir dosyayı işlem geçmişinden silmek için kullanabileceğiniz güçlü bir komuttur. Dosya bir süre kalacak ve Git sonraki çöp toplamada kaldıracaktır. Aşağıda, tamamlama geçmişinden dosyaları silmenin tam süreci verilmiştir . Güvenlik için, aşağıdaki işlem önce yeni bir dalda komutları çalıştırır. Sonuç ihtiyacınız olan şeyse, gerçekte değiştirmek istediğiniz şubeye sıfırlayın.

# 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

Git Uzantıları'nı kullanın , bu bir UI aracıdır. "Büyük dosyaları bul" adlı bir eklentiye sahiptir ve bu da lage dosyalarını depolarda bulur ve onları kalıcı olarak kaldırmaya izin verir.

Bu aracı kullanmadan önce 'git filter-branch' kullanmayın, çünkü 'filter-branch' tarafından kaldırılan dosyaları bulamaz ('filter-branch' dosyaları depo paketi dosyalarından tamamen kaldırmaz) .


Bu yöntem büyük depolar için çok yavaştır. Büyük dosyaları listelemek bir saatten fazla sürdü. Sonra dosyaları sildiğimde, bir saat sonra silmek istediğim ilk dosyayı işlemenin sadece 1 / 3'ü.
kristianp

Evet, yavaş, ama iş ... Daha hızlı bir şey biliyor musun?
Nir

1
Kullanmadım, ancak bu sayfadaki başka bir cevaba göre BFG Repo-Cleaner.
kristianp

2

Bunu şu branch filterkomutu kullanarak yapabilirsiniz :

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


2

Bu konuda çok iyi cevaplar var, ancak bu arada birçoğu modası geçmiş. Kullanımı git-filter-branchartık önerilmemektedir, çünkü kullanımı zor ve büyük depolarda son derece yavaştır.

git-filter-repo kullanımı çok daha hızlı ve kolaydır.

git-filter-repogithub'da bulunan bir Python betiğidir: https://github.com/newren/git-filter-repo .

Yalnızca bir dosyaya ihtiyacınız vardır: Python3 betiği git-filter-repo. Bunu PATH değişkeninde bulunan bir yola kopyalayın. Windows'ta komut dosyasının ilk satırını değiştirmeniz gerekebilir (bkz. INSTALL.md). Python3'ün sisteminizde kurulu olması gerekir, ancak bu önemli değildir.

Önce koşabilirsin

git filter-repo --analyze

Bu, daha sonra ne yapacağınızı belirlemenize yardımcı olur.

DVD-rip dosyanızı her yerde silebilirsiniz:

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

Filtre repo gerçekten hızlı. Bilgisayarımda filtre kolu tarafından yaklaşık 9 saat süren bir görev, filtre repo ile 4 dakika içinde tamamlandı. Filtre repo ile çok daha güzel şeyler yapabilirsiniz. Bunun için belgelere bakın.

Uyarı: Bunu deponuzun bir kopyasında yapın. Filtre repo'nun birçok eylemi geri alınamaz. filter-repo, tüm değiştirilmiş taahhütlerin (elbette) ve tüm torunlarının sağlama karmalarını son taahhütlere kadar değiştirecek!


1

git rmGit bu dosyanın tarihimizde bir kez var olduğunu hatırladığı için bu sorunla karşılaştığınızda, yeterli olmayacak ve bu nedenle bir referans tutacaktır.

İşleri daha da kötüleştirmek için, yeniden basmak da kolay değildir, çünkü bloba yapılan herhangi bir referans git çöp toplayıcının alanı temizlemesini önleyecektir. Bu, uzaktan referansları ve reflog referanslarını içerir.

Bir araya getirdim git forget-blob, tüm bu referansları kaldırmayı deneyen küçük bir komut dosyası ve sonra da daldaki her taahhüdü yeniden yazmak için git filter-branch kullanıyor.

Kabarcık tamamen referanssız olduğunda git gc, ondan kurtulur

Kullanımı oldukça basit git forget-blob file-to-forget . Buradan daha fazla bilgi alabilirsiniz

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

Stack Overflow'un cevapları ve bazı blog girişleri sayesinde bunu bir araya getirdim. Krediler!


bunu homebrew almak gerekir
Cameron E

0

Dışında git filter-branch(yavaş ama saf git çözelti) ve BFG (daha kolay ve çok ölçülebilir), iyi bir performans ile filtre başka bir araç da vardır:

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

Açıklamasından:

Git-roket filtresinin amacı git-filter-branch, aşağıdaki benzersiz özellikleri sağlarken komuta benzer :

  • Taahhütlerin ve ağaçların hızlı bir şekilde yeniden yazılması (x10 ila x100 aralığında).
  • --Keep (dosyaları veya dizinleri tutar) ile beyaz listeleme ve --remove seçenekleriyle kara listeleme için yerleşik destek.
  • Ağaç filtreleme için .gitignore benzeri desen kullanımı
  • Hem taahhüt filtreleme hem de ağaç filtreleme için hızlı ve kolay C # Komut Dosyası
  • Dosya / dizin modeli başına ağaç filtrelemede komut dosyası oluşturma desteği
  • Birleştirme taahhütleri dahil olmak üzere boş / değişmemiş taahhüdü otomatik olarak budama
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.