Git tarafından oluşturulan büyük .pack dosyasını kaldırın


112

Bir dalda bir sürü dosyayı kontrol ettim ve birleştirdim ve sonra onları kaldırmak zorunda kaldım ve şimdi nasıl kurtulacağımı bilmediğim büyük bir .pack dosyasıyla kaldım.

Kullanarak tüm dosyaları sildim git rm -rf xxxxxxve --cachedseçeneği de çalıştırdım .

Birisi bana şu anda aşağıdaki dizinde bulunan büyük bir .pack dosyasını nasıl kaldırabileceğimi söyleyebilir mi:

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

Hala sahip olduğum ancak artık kullanmadığım dalı kaldırmam gerekiyor mu? Yoksa koşmam gereken başka bir şey mi var?

Ne kadar fark yarattığından emin değilim ama dosyaya karşı bir asma kilit gösteriyor.

Teşekkürler


DÜZENLE

İşte bash_historyumdan bu duruma nasıl girmeyi başardığıma dair bir fikir vermesi gereken bazı alıntılar (bu noktada 'dalım' adlı bir git dalı üzerinde çalıştığımı ve daha fazla klasör içeren bir klasörüm olduğunu varsayın / Dosyalar):

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)

Aşağıdakileri de çalıştırdığımı düşündüm ancak bash_history'de diğerleriyle görünmüyor:

git rm -rf --cached unwanted_folder/

Ayrıca git gc, paket dosyasını düzenlemeye çalışmak için bazı git komutları (gibi ) çalıştırdığımı da düşündüm , ancak bunlar .bash_history dosyasında da görünmüyor.


Onları nasıl çıkardığınızı açıklayabilir misiniz? Hala işleme geçmişindelerse, o zaman hala paket dosyalarınızda olurlar.
loganfsmyth

Merhaba @loganfsmyth, umarım yardımcı olacak bash geçmişi betiklerini ekledim.
user1116573

Yanıtlar:


201

Sorun şu ki, dosyaları kaldırmış olsanız bile, önceki revizyonlarda hala mevcut. Git'in tüm amacı bu, bir şeyi silseniz bile, geçmişe erişerek onu yine de geri alabilirsiniz.

Yapmak istediğiniz şeye geçmişi yeniden yazma deniyor ve bu git filter-branchkomutu içeriyor .

GitHub'ın sitesinde sorunla ilgili iyi bir açıklama var. https://help.github.com/articles/remove-sensitive-data

Sorunuzu daha doğrudan yanıtlamak için temelde çalıştırmanız gereken şey, bu komutun unwanted_filename_or_folderuygun şekilde değiştirilmesidir:

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

Bu, dosyalara yapılan tüm referansları deponun etkin geçmişinden kaldıracaktır.

Sonraki adım, dosyaya yapılan tüm referansların süresinin dolmasını ve paket dosyasından temizlenmesini sağlamak için bir GC döngüsü gerçekleştirmek. Bu komutlarda hiçbir şeyin değiştirilmesi gerekmez.

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

3
Bu, gelecekte bu soruya gelenlerin işini kolaylaştıracaksa kabul edildi olarak işaretledim, ancak o sırada sorunumu yeni bir git
deposu

3
Bunu nasıl ortaya çıkardın bilmiyorum ama ... Adam sensin. Teşekkürler.
Ezekiel Victor

5
Bu cevap beni doğru yönü gösterdi. Aslında dosyaları silmek için Ama 3 daha komutlar ihtiyaç vardır 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
Kullanmayı bfgçok daha kolay buluyorum . Resmi github belgelerinde de tavsiye edilir: help.github.com/articles/…
Timo

2
@Timo Zamanla işler değiştiyse, yeni bir cevap eklemek iyidir. Göreyim seni!
loganfsmyth

12

Senaryo A : Büyük dosyalarınız yalnızca bir dala eklendiyse, çalıştırmanıza gerek yoktur git filter-branch. Sadece dalı silmeniz ve çöp toplamayı çalıştırmanız gerekir:

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

Senaryo B : Ancak, bash geçmişinize göre değişiklikleri ana olarak birleştirmişsiniz gibi görünüyor. Değişiklikleri kimseyle paylaşmadıysanız (henüz hayır git push). En kolay şey, büyük dosyalara sahip dalla birleştirmeden önce ana kopyayı sıfırlamaktır. Bu, şubenizdeki tüm taahhütleri ve birleştirmeden sonra ustalaşmak için yapılan tüm taahhütleri ortadan kaldıracaktır. Dolayısıyla, büyük dosyalara ek olarak, gerçekten istemiş olabileceğiniz değişiklikleri de kaybedebilirsiniz:

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

Ardından A senaryosundaki adımları çalıştırın.

Senaryo C : Dalda başka değişiklikler varsa veya tutmak istediğiniz birleştirmeden sonra ana birimde değişiklikler varsa, en iyisi ana kopyayı yeniden temel almak ve istediğiniz taahhütleri seçerek dahil etmek olacaktır:

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

Düzenleyicinizde, büyük dosyaları ekleyen işlemlere karşılık gelen satırları kaldırın, ancak her şeyi olduğu gibi bırakın. Kaydet ve çık. Ana dalınız yalnızca istediğinizi içermeli ve büyük dosyalar içermemelidir. Not o git rebaseolmadan -pbirleştirme kaydedilmesini ortadan kaldıracak, böylece sonra usta doğrusal geçmişi ile sol olacağım <commit hash>. Bu muhtemelen sizin için uygundur, ancak değilse deneyebilirsiniz -p, ancak git help rebasediyor combining -p with the -i option explicitly is generally not a good idea unless you know what you are doing.

Sonra A senaryosundaki komutları çalıştırın.


Senaryo A varyantı var burada ekstra beklenmeyen bir sorun, ancak, ile.

Senaryo Büyük miktarda geçici paket dosyasını silmek için çözülmüş bir mayın sorunu. Depo bir yapı sunucusu tarafından yönetiliyordu ve .git / objects / pack klasörü içinde istenmeyen dosya oluşturulmasına neden oluyor. Diskimden değerli GB'leri boşaltabilirim.
xrissz

7

Loganfsmyth zaten onun belirtildiği gibi cevap dosyaları bile repo sildikten sonra orada var olmaya devam, çünkü tasfiye git tarihinin gerekir. Resmi GitHub dokümanları , kullanmaktan daha kolay bulduğum BFG'yi öneriyorfilter-branch :

Geçmişten dosyaları silme

BFG'yi web sitelerinden indirin . Java'yı yüklediğinizden emin olun, ardından bir ayna klonu oluşturun ve geçmişi temizleyin. YOUR_FILE_NAMESilmek istediğiniz dosyanın adıyla değiştirdiğinizden emin olun :

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

Bir klasörü silin

Yukarıdakinin aynısı ama kullan --delete-folders

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

Diğer seçenekler

BFG ayrıca aşağıdakiler gibi daha meraklı seçeneklere de izin verir ( belgelere bakın ):

Geçmişten 100 milyondan büyük tüm dosyaları kaldırın:

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

Önemli!

BFG'yi çalıştırırken, her ikisine de YOUR_FILE_NAMEve YOUR_FOLDER_NAMEaslında sadece dosya / klasör adları olduğuna dikkat edin . Yol değiller , bu yüzden böyle bir şey foo/bar.jpgişe yaramayacak! Bunun yerine, belirtilen ada sahip tüm dosyalar / klasörler, hangi yol veya dalda olduklarına bakılmaksızın depo geçmişinden kaldırılacaktır.


Bu bfgaracı yerel bir git deposuna uygulamak isteyip istemediğimi merak ediyorum , komut nasıl görünmeli?
Angel Todorov

5

Bir seçenek:

git gcbir dizi paket dosyasını bir veya birkaç paket dosyasında yoğunlaştırmak için manuel olarak çalıştırın . Bu işlem kalıcıdır (yani büyük paket dosyası sıkıştırma davranışını koruyacaktır), bu nedenle bir depoyu periyodik olarak sıkıştırmak yararlı olabilir.git gc --aggressive

Diğer bir seçenek, kodu ve .git'i bir yere kaydetmek ve ardından .git'i silmek ve bu mevcut kodu kullanarak yeni bir git deposu ( git init) oluşturmaktır.


Merhaba Michael, Çalıştırmayı denedim git gcve sadece birkaç paket dosyasına indim ama büyük olanı hala onlardan biri ve sadece ondan kurtulmak istiyorum, böylece klasörü harici olarak daha kolay yedekleyebilirim (daha önce zip 1 idi -2Mb, şimdi 55Mb). Birisi başka bir şey öneremezse, sanırım yeni bir git yaratmam gerekebilir. Bunun şu anda sahip olduğum şubelere erişimimi kaybedeceğim anlamına geldiğini varsayıyorum vb ...?
user1116573

2
Denemekten vazgeçtim ve .git klasörünü sildim ve dediğin gibi yeni bir git deposu oluşturdum. Bunu öğrenilmiş bir ders olarak kabul edeceğim. Teşekkürler Michael.
user1116573

4
Bu pek mantıklı değil. Neden git'e mevcut depoyu birleştirmesini ve işlemdeki paket dosyalarını kaldırmasını söylemiyorsunuz?
jml

4

PATH-TO-YOUR-FILE-WITH-SENSITIVE-DATAYalnızca dosya adını değil, kaldırmak istediğiniz dosyanın yolunu değiştirerek aşağıdaki komutu çalıştırın . Bu argümanlar:

  1. Git'i her dalın ve etiketin tüm geçmişini işlemeye, ancak kontrol etmeye zorla
  2. Belirtilen dosyayı ve sonuç olarak oluşturulan boş taahhütleri kaldırın
  3. Mevcut etiketlerinizin üzerine yazın
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

Bu, dosyalara yapılan tüm referansları deponun aktif geçmişinden zorla kaldıracaktır.

Sonraki adım, dosyaya yapılan tüm referansların süresinin dolmasını ve paket dosyasından temizlenmesini zorlamak için bir GC döngüsü gerçekleştirmek. Bu komutlarda hiçbir şeyin değiştirilmesi gerekmez.

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

Sonunda 2. bölümden 158M'ye kadar bir 28G repo aldım. Google'da neredeyse hiçbir şey işe yaramadı. Teşekkür ederim.
Sridhar Sarnobat

Yukarıdaki adımları izledim ve "git push origin --force --all" olarak ittim ve yine de uzak dallarım (ana, geliştirme ve özellik / ASD-1010) temizlenmedi. Uzak depodan yeni klonladığımda, .pack dosyaları hala mevcuttu. Bu temizlemeyi tüm uzak git dallarına nasıl yansıtabilirim?
Sambit Swain

1

Gösteri için biraz geç kaldım ama yukarıdaki cevabın soruyu çözmemesi durumunda başka bir yol buldum. Belirli büyük dosyayı .pack'ten kaldırmanız yeterlidir. Yanlışlıkla büyük bir 2GB dosyasını kontrol ettiğimde bu sorunu yaşadım. Bu bağlantıda açıklanan adımları izledim: http://www.ducea.com/2012/02/07/howto-completely-remove-a-file-from-git-history/


Bu yöntemi uyguladıktan sonra, projenin tüm geçmişini tamamen kaldıracak mı yoksa yalnızca belirtilen dosyayı kaldıracak mı?
Samim Aftab Ahmed

-3

bu, kodlamadan çok kullanışlı bir çözümdür. dosyayı sıkıştırın. Zip dosyasını dosya görünümü biçiminde açın (sıkıştırmadan farklı). .Pack dosyasını silin. Klasörü açın ve değiştirin. Tıkır tıkır çalışıyor!

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.