Mengingat hash gumpalan, adakah cara untuk mendapatkan daftar commit yang memiliki gumpalan ini di pohon mereka?
git
version-control
Hanya baca
sumber
sumber
git hash-object
atausha1("blob " + filesize + "\0" + data)
, dan bukan hanya sha1sum dari isi blob.git log --follow filepath
(dan menggunakan ini untuk mempercepat solusi Aristoteles, jika Anda mau).~/.bin
dan nama itugit-find-object
. Anda kemudian dapat menggunakannya dengangit find-object
.git describe <hash>
: Lihat jawaban saya di bawah ini .Jawaban:
Kedua skrip berikut mengambil SHA1 gumpalan sebagai argumen pertama, dan setelahnya, opsional, argumen apa pun yang
git log
akan mengerti. Misalnya--all
untuk mencari di semua cabang, bukan hanya yang saat ini, atau-g
untuk mencari di reflog, atau apa pun yang Anda suka.Ini dia sebagai skrip shell - pendek dan manis, tapi lambat:
Dan versi yang dioptimalkan dalam Perl, masih cukup singkat tetapi jauh lebih cepat:
sumber
git rev-parse --verify $theprefix
my $blob_arg = shift; open my $rev_parse, '-|', git => 'rev-parse' => '--verify', $blob_arg or die "Couldn't open pipe to git-rev-parse: $!\n"; my $obj_name = <$rev_parse>; chomp $obj_name; close $rev_parse or die "Couldn't expand passed blob.\n"; $obj_name eq $blob_arg or print "(full blob is $obj_name)\n";
obj_name="$1" shift git log --all --pretty=format:'%T %h %s %n' -- "$@" | while read tree commit cdate subject ; do if [ -z $tree ] ; then continue fi if git ls-tree -r $tree | grep -q "$obj_name" ; then echo "$cdate $commit $@ $subject" fi done
--all
sebagai argumen tambahan. (Menemukan semua komit lebar adalah penting dalam kasus-kasus seperti menghapus file besar dari sejarah repo ).Sayangnya skrip agak lambat bagi saya, jadi saya harus mengoptimalkan sedikit. Untungnya saya tidak hanya memiliki hash tetapi juga path file.
sumber
<hash>
pada yang diberikan<path>
, maka menghapus<path>
argumen darigit log
akan bekerja. Hasil yang dikembalikan pertama adalah komit yang diinginkan.Dengan Git 2.16 (Q1 2018),
git describe
akan menjadi solusi yang baik, karena diajarkan untuk menggali lebih dalam pohon untuk menemukan<commit-ish>:<path>
yang merujuk pada objek gumpalan yang diberikan.Lihat komit 644eb60 , komit 4dbc59a , komit cdaed0c , komit c87b653 , komit ce5b6f9 (16 Nov 2017), dan komit 91904f5 , komit 2deda00 (02 Nov 2017) oleh Stefan Beller (
stefanbeller
) .(Digabung oleh Junio C Hamano -
gitster
- dalam komit 556de1a , 28 Des 2017)Itu berarti
git describe
halaman manual menambahkan ke tujuan perintah ini:Tapi:
sumber
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 -r | head -n 20
, yang menghasilkan 20 gumpalan terbesar. Kemudian Anda dapat mengirimkan blob ID dari output di atas kegit describe
. Bekerja sebagai pesona! Terima kasih!Saya pikir ini akan menjadi hal yang bermanfaat secara umum, jadi saya menulis sedikit skrip perl untuk melakukannya:
Saya akan meletakkan ini di github ketika saya pulang malam ini.
Pembaruan: Sepertinya seseorang sudah melakukan ini . Yang satu menggunakan ide umum yang sama tetapi detailnya berbeda dan implementasinya jauh lebih pendek. Saya tidak tahu mana yang lebih cepat tetapi kinerja mungkin bukan masalah di sini!
Pembaruan 2: Untuk apa nilainya, implementasi saya adalah urutan besarnya lebih cepat, terutama untuk repositori besar. Itu
git ls-tree -r
sangat menyakitkan.Pembaruan 3: Saya harus mencatat bahwa komentar kinerja saya di atas berlaku untuk implementasi yang saya tautkan di atas dalam Pembaruan pertama. Implementasi Aristoteles berkinerja sebanding dengan saya. Lebih detail dalam komentar untuk mereka yang penasaran.
sumber
git rev-parse $commit^{}
Meskipun pertanyaan awal tidak menanyakannya, saya pikir akan bermanfaat juga untuk memeriksa area pementasan untuk melihat apakah gumpalan direferensikan. Saya memodifikasi skrip bash asli untuk melakukan ini dan menemukan apa yang mereferensikan gumpalan rusak di repositori saya:
sumber
Jadi ... Saya perlu menemukan semua file melebihi batas yang diberikan dalam repo lebih dari 8GB dalam ukuran, dengan lebih dari 108.000 revisi. Saya mengadaptasi skrip perl Aristoteles bersama dengan skrip ruby yang saya tulis untuk mencapai solusi lengkap ini.
Pertama,
git gc
- lakukan ini untuk memastikan semua objek ada dalam paket - kami tidak memindai objek tidak dalam file paket.Selanjutnya Jalankan skrip ini untuk mencari semua gumpalan di atas byte CUTOFF_SIZE. Capture output ke file seperti "large-blobs.log"
Selanjutnya, edit file untuk menghapus gumpalan yang tidak Anda tunggu dan INPUT_THREAD bit di atas. setelah Anda hanya memiliki baris untuk sha1s yang ingin Anda temukan, jalankan skrip berikut seperti ini:
Di mana
git-find-blob
skrip di bawah ini.Outputnya akan terlihat seperti ini:
Dan seterusnya. Setiap komit yang berisi file besar di pohonnya akan terdaftar. jika Anda
grep
keluar dari garis yang dimulai dengan tab, danuniq
itu, Anda akan memiliki daftar semua jalur yang bisa Anda filter-cabang untuk dihapus, atau Anda bisa melakukan sesuatu yang lebih rumit.Biarkan saya ulangi: proses ini berjalan dengan sukses, pada repo 10GB dengan 108.000 komit. Butuh waktu lebih lama daripada yang saya perkirakan saat menjalankan sejumlah besar gumpalan, lebih dari 10 jam, saya harus melihat apakah bit menghafal bekerja ...
sumber
-- --all
. (Menemukan semua komit repo-lebar adalah penting dalam kasus-kasus seperti benar - benar menghapus file besar dari sejarah repo ).Selain itu
git describe
, yang saya sebutkan dalam jawaban saya sebelumnya ,git log
dangit diff
sekarang mendapat manfaat juga dari opsi "--find-object=<object-id>
" untuk membatasi temuan hanya pada perubahan yang melibatkan objek bernama.Itu ada di Git 2.16.x / 2.17 (Q1 2018)
Lihat komit 4d8c51a , komit 5e50525 , komit 15af58c , komit cf63051 , komit c1ddc46 , komit 929ed70 (04 Jan 2018) oleh Stefan Beller (
stefanbeller
) .(Digabung oleh Junio C Hamano -
gitster
- di commit c0d75f0 , 23 Jan 2018)sumber