Git tarihindeki büyük taahhütleri nasıl bulabilirim / tanımlayabilirim?


366

300 MB git repo'm var. Şu anda teslim alınan dosyalarımın toplam boyutu 2 MB ve geri kalan deponun geri kalanının toplam boyutu 298 MB. Bu temelde birkaç MB'den fazla olmamalıdır sadece kod repo.

Birisinin yanlışlıkla bazı büyük dosyaları (video, resim vb.) İşlediğinden ve sonra onları kaldırdığından şüpheleniyorum ... ama git'ten değil, bu yüzden tarih hala işe yaramaz büyük dosyalar içeriyor. Git tarihindeki büyük dosyaları nasıl bulabilirim? 400'den fazla taahhüt var, bu yüzden tek tek gitmek pratik değil.

NOT : sorum , dosyanın nasıl kaldırılacağı değil , ilk etapta nasıl bulunacağı ile ilgili .



Yanıtlar:


143

Bu komut dosyasını geçmişte bir git deposunda büyük (ve açık olmayan) nesneler bulmak için çok yararlı buldum:


#!/bin/bash
#set -x 

# Shows you the largest objects in your repo's pack file.
# Written for osx.
#
# @see https://stubbisms.wordpress.com/2009/07/10/git-script-to-show-largest-pack-objects-and-trim-your-waist-line/
# @author Antony Stubbs

# set the internal field separator to line break, so that we can iterate easily over the verify-pack output
IFS=$'\n';

# list all objects including their size, sort by size, take top 10
objects=`git verify-pack -v .git/objects/pack/pack-*.idx | grep -v chain | sort -k3nr | head`

echo "All sizes are in kB's. The pack column is the size of the object, compressed, inside the pack file."

output="size,pack,SHA,location"
allObjects=`git rev-list --all --objects`
for y in $objects
do
    # extract the size in bytes
    size=$((`echo $y | cut -f 5 -d ' '`/1024))
    # extract the compressed size in bytes
    compressedSize=$((`echo $y | cut -f 6 -d ' '`/1024))
    # extract the SHA
    sha=`echo $y | cut -f 1 -d ' '`
    # find the objects location in the repository tree
    other=`echo "${allObjects}" | grep $sha`
    #lineBreak=`echo -e "\n"`
    output="${output}\n${size},${compressedSize},${other}"
done

echo -e $output | column -t -s ', '

Bu size blob'un nesne adını (SHA1sum) verecektir ve sonra bunun gibi bir komut dosyası kullanabilirsiniz:

... bu lekelerin her birine işaret eden taahhüdü bulmak için.


31
Bu cevap gerçekten yardımcı oldu, çünkü beni yukarıdaki mesaja gönderdi. Yazının senaryosu çalışırken acı verici şekilde yavaş buldum. Bu yüzden yeniden yazdım ve şimdi büyük depolarda önemli ölçüde daha hızlı. Bir göz atın: gist.github.com/nk9/b150542ef72abc7974cb
Nick K9

7
Lütfen yalnızca site dışı bağlantılara değil, yanıtlarınıza tam talimatlar ekleyin; Stubbisms.wordpress.com kaçınılmaz olarak aşağı indiğinde ne yapacağız?
ThorSummoner

@ NickK9 ilginç senaryo ve diğer farklı çıktı olsun. sizinkilerin kaçırdığı bir sürü büyük nesne var. Kaçırdığım bir şey var mı?
UpAndAdam

Oh harika! Senaryomu daha hızlı yaptığınız için teşekkürler @nick \ k9: D @UpAndAdam, senaryomun yanlış çıktı ürettiğini mi söylüyorsun?
Antony Stubbs

1
Bu yorumlar, bayt cinsinden boyutu bildiriyormuş gibi ses çıkarıyor, ancak kilobayt alıyorum.
Kat

682

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,6 milyon nesnesiyle 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)' \
| sed -n 's/^blob //p' \
| sort --numeric-sort --key=2 \
| cut -c 1-12,41- \
| $(command -v gnumfmt || echo 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

macOS kullanıcıları : macOS'tanumfmt bulunmadığından, son satırı atlayabilir ve ham bayt boyutları ile başa çıkabilir veya brew install coreutils.

süzme

Elde etmek için daha fazla filtreleme aşağıdaki satırları herhangi eklemek önce sorthat .

İçinde bulunan dosyaları hariç tutmakHEAD için aşağıdaki satırı ekleyin:

| grep -vF --file=<(git ls-tree -r HEAD | awk '{print $3}') \

İçin , sadece belirli bir büyüklüğü aşan dosyalarını göstermek (örneğin 1 MIB = 2 20  B) aşağıdaki hattı elemanı:

| awk '$2 >= 2^20' \

Bilgisayarlar için Çıktı

Bilgisayarlar tarafından daha fazla işlenmek üzere daha uygun çıktı üretmek için , temel komut dosyasının son iki satırını atlayın. Tüm biçimlendirmeyi yaparlar. Bu size böyle bir şey bırakacaktır:

...
0d99bb93129939b72069df14af0d0dbda7eb6dba 542455 path/to/some-image.jpg
2ba44098e28f8f66bac5e21210c2774085d2319b 12446815 path/to/hires-image.png
bd1741ddce0d07b72ccf69ed281e09bf8a2d0b2f 65183843 path/to/some-video-1080p.mp4

Dosya Kaldırma

Gerçek dosya kaldırma için, konuyla ilgili bu SO sorusuna göz atın .


14
Bu benim oyumdan daha fazlasını hak ediyor! Hem bilgisayar hem de insan tarafından okunabilir çıktı sağladığınız için teşekkür ederiz.
Michel Jung

2
Bu son derece hızlı ve kullanımı kolaydır!
Çene

32
Mac'te Bunu kullanmak için yapmanız gerekenler brew install coreutilsve daha sonra değiştirmek cutile gcutve numfmtile gnumfmt.
Nick Sweeting

2
Tekrar vurgulayayım - bu gördüğüm diğer listelerden çok daha hızlı.
Sridhar Sarnobat

4
Bu harika bir git takma adı yapar :) git largekimse?
anarcat

160

ETH Zürih Fizik Bölümü wiki sayfasında tek sayfalık bir çözüm buldum (bu sayfanın sonuna yakın). Sadece git gceski önemsiz kaldırmak için bir yapın ve sonra

git rev-list --objects --all \
  | grep "$(git verify-pack -v .git/objects/pack/*.idx \
           | sort -k 3 -n \
           | tail -10 \
           | awk '{print$1}')"

depodaki en büyük 10 dosyayı verecektir.

Artık daha tembel bir çözüm var, GitExtensions şimdi bunu kullanıcı arayüzünde yapan bir eklentiye sahip (ve tarih yeniden yazmalarını da işliyor ).

GitExtensions 'Büyük dosyaları bul' iletişim kutusu


8
Bu tek astar yalnızca en büyük tek dosyayı almak istiyorsanız çalışır (yani kuyruk -1 kullanın). Yeni satırlar daha büyük her şeyin önüne geçer. Yeni satırları dönüştürmek için sed kullanabilirsiniz, böylece grep güzel oynayacak:git rev-list --objects --all | grep -E `git verify-pack -v .git/objects/pack/*.idx | sort -k 3 -n | tail -10 | awk '{print$1}' | sed ':a;N;$!ba;s/\n/|/g'`
Throctukes

10
grep: a70783fca9bfbec1ade1519a41b6cc4ee36faea0: Böyle bir dosya veya dizin yok
Jonathan Allard

1
Wiki bağlantısı şu adrese
outsmartin

11
GitExtensions'ı bulmak altın potu ve gökkuşağının sonunu bulmak gibidir - teşekkürler!
ckapilla

3
Dosyaların boyutunu yazdıran bir uzantı var mı?
Michael

27

Adım 1 Tüm SHA1 dosyalarını bir metin dosyasına yazın:

git rev-list --objects --all | sort -k 2 > allfileshas.txt

Adım 2 Lekeleri büyükten küçüğe doğru sıralayın ve sonuçları metin dosyasına yazın:

git gc && git verify-pack -v .git/objects/pack/pack-*.idx | egrep "^\w+ blob\W+[0-9]+ [0-9]+ [0-9]+$" | sort -k 3 -n -r > bigobjects.txt

Adım 3a Dosya adını / sha1 / boyut bilgilerini almak için her iki metin dosyasını da birleştirin:

for SHA in `cut -f 1 -d\  < bigobjects.txt`; do
echo $(grep $SHA bigobjects.txt) $(grep $SHA allfileshas.txt) | awk '{print $1,$3,$7}' >> bigtosmall.txt
done;

Adım 3b Boşluk içeren dosya adlarınız veya yol adlarınız varsa , Adım 3a'nın bu varyasyonunu deneyin. İstenilen sütunları dahil etmek cutyerine kullanır awk. sütun 7'den satır sonuna kadar olan boşluklar:

for SHA in `cut -f 1 -d\  < bigobjects.txt`; do
echo $(grep $SHA bigobjects.txt) $(grep $SHA allfileshas.txt) | cut -d ' ' -f'1,3,7-' >> bigtosmall.txt
done;

Artık Git geçmişinizden hangi dosyaları kaldırmak istediğinize karar vermek için bigtosmall.txt dosyasına bakabilirsiniz.

Adım 4 Kaldırma işlemini gerçekleştirmek için (tanımladığınız dosyayla ilgili veriler için geçmişinizdeki tüm işlemleri inceleyeceğinden bu bölümün yavaş olduğuna dikkat edin):

git filter-branch --tree-filter 'rm -f myLargeFile.log' HEAD

Kaynak

1-3a Adımları Git Geçmişinden Büyük Dosyaları Bulma ve Temizleme işleminden kopyalandı

DÜZENLE

Makale 2017 yılının ikinci yarısında bir süre silindi, ancak arşivlenmiş bir kopyasına Wayback Machine kullanılarak erişilebiliyor .


6
Aynı şeyi yapmak için bir astar:git gc && join -e ERROR -a 2 -j 1 -o 2.1,2.3,1.2 --check-order <( git rev-list --objects --all | sort -k 1 ) <( git verify-pack -v .git/objects/pack/pack-*.idx | gawk '( NF == 5 && $2 == "blob" ){print}' | sort -k1 ) | sort -k2gr
Iwan Aucamp

1
@Iwan, tek hat için teşekkürler! Bu onları boşluk olan dosya adlarını işlemez, bu gibi görünüyor: join -t' ' -e ERROR -a 2 -j 1 -o 2.1,2.3,1.2 --check-order <( git rev-list --objects --all | sed 's/[[:space:]]/\t/' | sort -k 1 ) <( git verify-pack -v .git/objects/pack/pack-*.idx | gawk '( NF == 5 && $2 == "blob" ){print}' | sort -k1 | sed 's/[[:space:]]\+/\t/g' ) | sort -k2gr | less. Geekbraindump.blogspot.ru/2009/04/unix-join-with-tabs.htmljoin -t'
Nickolay

2
@Nickolay ile bash $'\t'size bir sekme vermelidir. echo -n $'\t' | xxd -ps->09
Iwan Aucamp

1
@IwanAucamp: daha da iyisi, bahşiş için teşekkürler! (Önceki yorumu düzenleyemem çok kötü .. oh iyi.)
Nickolay

1
@ Sridhar-Sarnobat Makale Wayback Machine tarafından kaydedildi! :) web.archive.org/web/20170621125743/http://www.naleid.com/blog/…
friederbluemle

18

BFG Repo-Cleaner kullanmalısınız .

Web sitesine göre:

BFG, Git veri havuzu geçmişinizdeki kötü verileri temizlemek için git-filtre-dalına daha basit ve daha hızlı bir alternatiftir:

  • Crazy Big Dosyalarını Kaldırma
  • Parolaları, Kimlik Bilgilerini ve diğer Özel verileri kaldırma

Bir havuzun boyutunu küçültmek için klasik prosedür şöyle olacaktır:

git clone --mirror git://example.com/some-big-repo.git
java -jar bfg.jar --strip-biggest-blobs 500 some-big-repo.git
cd some-big-repo.git
git reflog expire --expire=now --all
git gc --prune=now --aggressive
git push

4
BFG Repo-Cleaner çok iyi. Hızlı aydınlanır ve çok güvenilir çalışır.
fschmitt

30
Bu, tüm büyük dosyaları nasıl listeleyeceğinizi söylemez.
Andi Jay

5
Buradaki sorun, büyük dosyaların ne olduğunu gerçekten kaldırmadan GÖRMEYİNİZ. Sadece büyük dosyaları listeleyen kuru bir çalışma olmadan bunu yapmakta rahat hissetmiyorum.
Sridhar Sarnobat

Ne yapar --strip-biggest-blobs 500?
2540625

git bu aracın yaptığı değişiklikleri reddedecektir.
Christopher

9

Yalnızca büyük dosyaların bir listesini almak istiyorsanız, size aşağıdaki tek astarı sunmak istiyorum:

join -o "1.1 1.2 2.3" <(git rev-list --objects --all | sort) <(git verify-pack -v objects/pack/*.idx | sort -k3 -n | tail -5 | sort) | sort -k3 -n

Kimin çıktısı olacak:

commit       file name                                  size in bytes

72e1e6d20... db/players.sql 818314
ea20b964a... app/assets/images/background_final2.png 6739212
f8344b9b5... data_test/pg_xlog/000000010000000000000001 1625545
1ecc2395c... data_development/pg_xlog/000000010000000000000001 16777216
bc83d216d... app/assets/images/background_1forfinal.psd 95533848

Listedeki son giriş git geçmişinizdeki en büyük dosyayı gösterir.

Bu çıktıyı , geçmişinizde ihtiyaç duyacağınız BFG ile bir şey silmediğinizden emin olmak için kullanabilirsiniz .


2
Korku veren !! Ancak, bu komutu çalıştırmadan önce repoyu --mirror seçenekleriyle klonlamanız gerektiğini unutmayın.
Andi Jay

Merak ediyorum, 1.1, 1.2, 2.3sayılar ne için?
ympostor

Sayılar <filenumber>.<field>, kombinasyonun sırasını belirten bir listedir . Daha fazla bilgi için man.cx/join adresine bakınız .
schmijos

6

Windows kullanıyorsanız, deponuzdaki en büyük 10 dosyayı yazdıracak bir PowerShell betiği:

$revision_objects = git rev-list --objects --all;
$files = $revision_objects.Split() | Where-Object {$_.Length -gt 0 -and $(Test-Path -Path $_ -PathType Leaf) };
$files | Get-Item -Force | select fullname, length | sort -Descending -Property Length | select -First 10

1
Bu, depomdaki en büyük dosyaların bir demetini eksik olan @raphinesse'den farklı bir yanıt üretir. Ayrıca, büyük bir dosyada çok fazla değişiklik olduğunda, yalnızca en büyük boyut bildirilir.
kristianp

Bu komut dosyası hatası ile benim için başarısız oldu: You cannot call a method on a null-valued expression. At line: 2 char: 1. Ancak, bu cevap işe yaradı: stackoverflow.com/a/57793716/2441655 (ayrıca daha kısa)
Venryx

4

Deneyin git ls-files | xargs du -hs --threshold=1M.

CI boru hattımızda aşağıdaki komutu kullanıyoruz, git deposunda büyük dosyalar bulursa durur:

test $(git ls-files | xargs du -hs --threshold=1M 2>/dev/null | tee /dev/stderr | wc -l) -gt 0 && { echo; echo "Aborting due to big files in the git repository."; exit 1; } || true

2

--batch-checkGit 1.8.3 için komut satırı anahtarı (kullanmam gereken) herhangi bir argümanı kabul etmediği için en popüler yanıtı kullanamadım. Takip eden adımlar Bash 4.1.2 ile CentOS 6.5 üzerinde denendi

Anahtar kavramlar

Git'te blob terimi bir dosyanın içeriğini ima eder. Bir taahhüdün bir dosyanın veya yol adının içeriğini değiştirebileceğini unutmayın. Böylece, aynı dosya işleme bağlı olarak farklı bir blob ifade edebilir. Belirli bir dosya, bir komut dosyasındaki dizin hiyerarşisindeki en büyük dosya olabilir, ancak başka bir dosyada değil. Bu nedenle, büyük dosyalar yerine büyük taahhütler bulma sorunu, meseleleri doğru perspektife koyar.

Sabırsızlar İçin

Lekeler listesini azalan boyutta yazdırma komutu:

git cat-file --batch-check < <(git rev-list --all --objects  | \
awk '{print $1}')  | grep blob  | sort -n -r -k 3

Örnek çıktı:

3a51a45e12d4aedcad53d3a0d4cf42079c62958e blob 305971200
7c357f2c2a7b33f939f9b7125b155adbd7890be2 blob 289163620

Bu tür lekeleri çıkarmak için , diğer yanıtlarda belirtildiği gibi BFG Repo Temizleyici'yi kullanın . blobs.txtSadece blob karmaları içeren bir dosya verildiğinde, örneğin:

3a51a45e12d4aedcad53d3a0d4cf42079c62958e
7c357f2c2a7b33f939f9b7125b155adbd7890be2

Yapmak:

java -jar bfg.jar -bi blobs.txt <repo_dir>

Soru, lekeleri bulmaktan daha fazla iş olan taahhütleri bulmakla ilgilidir. Bilmek için lütfen okumaya devam edin.

İleri Çalışmalar

Bir sağlama karması verildiğinde, lekeler de dahil olmak üzere kendisiyle ilişkili tüm nesnelerin karmalarını basan bir komut:

git ls-tree -r --full-tree <commit_hash>

Dolayısıyla, repodaki tüm taahhütler için bu tür çıktılarımız varsa, o zaman bir blob karması verilirse, taahhütlerin bir kısmı çıktılardan herhangi biriyle eşleşen olanlardır. Bu fikir aşağıdaki komut dosyasında kodlanmıştır:

#!/bin/bash
DB_DIR='trees-db'

find_commit() {
    cd ${DB_DIR}
    for f in *; do
        if grep -q $1 ${f}; then
            echo ${f}
        fi
    done
    cd - > /dev/null
}

create_db() {
    local tfile='/tmp/commits.txt'
    mkdir -p ${DB_DIR} && cd ${DB_DIR}
    git rev-list --all > ${tfile}

    while read commit_hash; do
        if [[ ! -e ${commit_hash} ]]; then
            git ls-tree -r --full-tree ${commit_hash} > ${commit_hash}
        fi
    done < ${tfile}
    cd - > /dev/null
    rm -f ${tfile}
}

create_db

while read id; do
    find_commit ${id};
done

İçindekiler adlı bir dosyaya kaydedilmişse, find-commits.shtipik bir çağrı aşağıdaki gibi olacaktır:

cat blobs.txt | find-commits.sh

Daha önce olduğu gibi, dosya blobs.txther satırda bir tane olmak üzere blob karmaları listeler. create_db()Fonksiyon tüm önbellek geçerli dizinde bir alt dizinde listeleri işlemek kaydeder.

İşletim sistemi tarafından 24 sanal çekirdek olarak sunulan iki Intel (R) Xeon (R) CPU E5-2620 2.00GHz işlemci içeren bir sistemde yaptığım deneylerden bazı istatistikler:

  • Repodaki toplam taahhüt sayısı = yaklaşık 11.000
  • Dosya oluşturma hızı = 126 dosya / sn. Komut dosyası her işlem için tek bir dosya oluşturur. Bu yalnızca önbellek ilk kez oluşturulduğunda oluşur.
  • Önbellek oluşturma yükü = 87 s.
  • Ortalama arama hızı = 522 işlem / sn. Önbellek optimizasyonu, çalışma süresinde% 80 azalma sağladı.

Komut dosyasının tek iş parçacıklı olduğunu unutmayın. Bu nedenle, aynı anda yalnızca bir çekirdek kullanılır.


2

Windows Git için Powershell çözümü, en büyük dosyaları bulun:

git ls-tree -r -t -l --full-name HEAD | Where-Object {
 $_ -match '(.+)\s+(.+)\s+(.+)\s+(\d+)\s+(.*)'
 } | ForEach-Object {
 New-Object -Type PSObject -Property @{
     'col1'        = $matches[1]
     'col2'      = $matches[2]
     'col3' = $matches[3]
     'Size'      = [int]$matches[4]
     'path'     = $matches[5]
 }
 } | sort -Property Size -Top 10 -Descending

0

Git geçmişindeki büyük dosyaları nasıl izleyebilirim?

Temel nedeni analiz ederek, doğrulayarak ve seçerek başlayın. git-repo-analysisYardım için kullanın .

BFG Repo-Cleaner tarafından oluşturulan ayrıntılı raporlarda , 10MiB / s ağ çıktılarını kullanarak Dijital Okyanus damlacıklarına klonlanarak çok hızlı bir şekilde çalıştırılabilen bazı değerler de bulabilirsiniz .


BFG önerisinde güzel bir genel cevabınız olduğunu düşünüyorum, ancak herhangi bir ayrıntı vermeden ve daha sonra farklı bir üçüncü taraf hizmeti (herhangi bir açıklama yapmadan) önererek şımartıyorsunuz. Bu BFG kullanımının komut satırı örneğini sağlamak için bazılarını temizleyebilir misiniz?
phord

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.