Git rev-listesini anlama
Git kanca örneklerini ararken şu gönderiye rastladım: https://github.com/Movidone/git-hooks/blob/master/pre-receive ve aşağıdaki komutu anlamak istedim:
git rev-list $new_list --not --all
new_list şuradan alınır:
NULL_SHA1="0000000000000000000000000000000000000000" # 40 0's
new_list=
any_deleted=false
while read oldsha newsha refname; do
case $oldsha,$newsha in *,$NULL_SHA1) # it's a delete
any_deleted=true;;
$NULL_SHA1,*) # it's a create new_list="$new_list $newsha";; *,*) # it's an update new_list="$new_list $newsha";;
esac
done
Rev listesinin taahhütleri ters kronolojik sırayla gösterdiğini düşündüm.
Ama, ne teneke birisi payı daha anlayış -notve -alliçindir seçenekler?
Belgelere göre:
--not
Reverses the meaning of the ^ prefix (or lack thereof) for all following revision specifiers, up to the next --not.
--all
Pretend as if all the refs in refs/ are listed on the command line as <commit>.
Bu seçenekleri tam olarak anlayamıyorum.
[Güncelle] Bazı test taahhütlerini yaptıktan sonra, kullanmazsam --notve --allseçenekleri kullanmazsam , git rev-listitme niyetinde olduğum süreyi değil, şubedeki tüm taahhütleri listeleyeceğimi anladım.
Bununla birlikte, --allseçenek geçildiğinde neden sha değerlerini terminalde yazdırmadığını anlamak istedim ?
Yanıtlar
git rev-listKomutu a çok karmaşık, çok merkezi ne yapar olduğu gibi, Git komut grafiğini yürümek . Buradaki kelime grafiği , hem commit grafiğinin kendisine hem de bazı durumlarda bir sonraki seviye aşağıya (kayıtlardan ulaşılabilen Git nesneleri ) atıfta bulunur .
Rev listesinin taahhütleri ters kronolojik sırayla gösterdiğini düşündüm.
Tam olarak değil ama yakın:
- Sıra değiştirilebilir. Varsayılan ters kronolojik olduğunu.
- Varsayılan, bazı işlemlerde yürümektir, ancak
rev-listağaç ve blob nesnelerini dahil etmek ve hatta nesneleri etiketlemek için daha derine inebilirsiniz. Bu,git fetchve gibigit push(çağırangit pack-objects) vegit pack-objects. Bu olasılığı burada tamamen görmezden gelmeyi planlıyorum ama en azından bundan bahsetmem gerektiğini hissediyorum. 😀
Bu nedenle varsayılan , bazı taahhütleri ters kronolojik sırayla listelemektir. Hem önemlidir ve biraz tam olarak belirtmek için, zor bit hangi parçaların biz sahip olacak grafiğin git rev-listyürüyüş: Bazı içinde bazı kaydedilmesini .
Ama, ne teneke birisi payı daha anlayış
--notve--alliçindir seçenekler?
As VonC notları , efekt burada alıcı deposuna yeni liste kaydedilmesini sağlamaktır. Bu, bu git rev-listkomutun bir ön alım kancasında çalışıyor olmasına bağlıdır . Genellikle bu özel kancanın dışında yararlı hiçbir şey yapmaz. Bu nedenle, görebileceğiniz gibi, bir kancanın Git'teki çalışma zamanı ortamı genellikle en azından biraz özeldir. (Bu, önceden alma kancasından daha fazlası için geçerlidir: her kancanın aktivasyon bağlamı düşünülmelidir.)
Hakkında daha ayrıntılı --not --all
--allSeçenek belgelerinden alıntı sadece gelmez Ne:
Tüm referanslar
refs/komut satırında listelenmiş gibi davranın ...
Yani bu, a'ya eşdeğerdir git for-each-ref refs: her referansın üzerinde döngü yapar. Bu şube adlarını içerir ( masterveya main, develop, feature/tallve böylece gerçekten de bunların tümü, üzerinde refs/heads/), etiket adları ( v1.2ki gerçekten refs/tags/v1.2), (isimleri uzaktan izleme origin/developgerçekten hangi refs/remotes/origin/develop), yedek hakemler (içinde refs/replace/), zulası ( refs/stash), ikiye bölme referansları, Gerrit, Gerrit kullanıyorsanız bunu belirtir, vb. Reflog girdileri üzerinden döngü yapmadığını unutmayın .
--notÖnek basit boole işlemdir. Gitrevisions sözdiziminde - gitrevisions belgelerine bakın - şöyle şeyler yazabiliriz develop, yani size baştan başlamanızı developve geriye doğru çalışmanızı ve bu taahhütleri dahil etmenizi söylüyorum , ama aynı zamanda ^develop, size başladığınız developve geriye doğru çalışmanızı ve bu taahhütleri hariç tutmanızı söylüyorum. . Yani yazarsam:
git rev-list feature1 feature2 ^main
Git'ten , isimlerle tanımlanan işlemlerden ulaşılabilen işlemeleri yürütmesinifeature1 ve feature2ancak ile tanımlanan işlemlerden ulaşılabilen taahhütleri hariç tutmasını istiyorum main. Erişilebilirlik ve grafikte gezinme genel fikri hakkında (çok) daha fazla bilgi için , bkz. Gibi Düşünün (a) Git .
--notOperatör etkili bir çevirir ^her referansıyla ilgili:
git rev-list --not feature1 feature2 ^main
kısaltması olduğu gibi:
git rev-list ^feature1 ^feature2 main
Bu, ulaşılabilen işlemlerin listesini gösterir main, ancak feature1veya veya seçeneklerinden erişilebilenleri hariç tutar feature2.
Genellikle tüm kayıtlar ile bulunabilir--all
Normal gündelik şekilde Git kullanıyorsanız, varsa ve moment müstakil BAŞ modunda bir "müstakil HEAD" yok tam olarak değil anormal ama iş için her zamanki gibi değil --allseçeneği git rev-listdahil etmek söyler tüm kaydedilmesini tüm kaydedilmesini çünkü olan tüm referansların ulaşılabilecek. 1 Yani tüm taahhütleri --not --alletkin bir şekilde hariç tutar . Bu nedenle , başka türlü listeleyen --not --allherhangi bir işleme eklemek git rev-list, listeyi engelleme etkisine sahiptir. Çıktı boş: neden zahmet ettik?
Eğer müstakil BAŞ modunda ve birkaç yeni yaptıysanız için interaktif bir veya çatışmalı rebase ortasında olduğunda örneğin-sonra kaydedilmesini-bu olabilir git rev-list HEAD --not --allbu teslimleri listelemek istiyorum vardır erişilebilir HEADama değil herhangi dal adından. Örneğin, bu yeniden hesaplamada bunlar şimdiye kadar kopyaladığınız taahhütler olabilir.
Bu nedenle, "ayrılmış HEAD" modu git rev-list --not --all, komut satırından yararlı olabilecek bir yer olacaktır . Ancak incelediğiniz durum için - bir ön alım kancası - aslında komut satırında değiliz.
Ön alma kancaları
Birisi kendi Git'inize commit git pushgöndermek için kullandığında , Git'iniz:
- herhangi bir yeni nesneyi (yeni taahhütler ve bloblar vb.) tutmak için bir karantina alanı kurar; 1
- gönderenin ne göndermesi gerektiğine karar vermek için gönderenle görüşür;
- bu nesneleri alır; ve
- referans güncelleme isteklerinin bir listesini alır . Bu güncelleme istekleri esasen bu adın bu hash kimliğini tuttuğunu söylüyor . 2
Aslında önce yapıyor istenen güncellemeleri, sizin Git herhangi:
- Tüm listeyi ön alım kancasına besler. O kanca "hayır" diyebilir; eğer öyleyse, tüm itme bir bütün olarak reddedilir.
- Bu "tamam" diyorsa, listeyi her seferinde bir istek olacak şekilde güncelleme kancasına aktarır. Bu kanca "tamam" dediğinde güncelleme yapar. Kanca "hayır" diyorsa, Git'iniz bir güncellemeyi reddeder, ancak diğerlerini incelemeye devam eder.
- 2. adımda tüm güncellemeler kabul edildikten veya reddedildikten sonra, kabul edilen listeyi alma sonrası kancasına besler.
2. adımda bazı ref'e eklenen gerekli nesneler, karantinadan Git'in nesne veritabanına taşınır. Reddedilenler değildir.
Şimdi, bir tipik düşünün git push. Bazı yeni commit (ler) ve bir istek alıyoruz : yeni bir şube adı yaratınfeature/short veya bazı yeni commit (ler) ve bir talep alıyoruz: eski olanlarla birlikte bu yeni commit'leri içerecek şekilde mevcut şube adını güncelleyindevelop .
Yukarıdaki 1. adımda, tek bir yeni hash kimliğimiz var. Hepimiz ref isimlerini okumak için bir döngü koştu ve onların mevcut ve önerilen yeni karma kimlikleri ve tek bir nedeni döngü, sadece bir kez koştu adı ediliyordu git push-ed. Bu hash ID , bu mevcut şubeye eklenecek olan veya yeni şubeye özel bahşiş ve diğer taahhütler olacak olan yeni commit veya commit'leri ifade eder .
Şimdi bu taahhütleri incelemek istiyoruz , mevcut herhangi bir şubeden ulaşılabilen mevcut taahhütlerin hiçbirini değil. Basit olması için, $new_listdiğer cevabımdan ziyade , sadece bir yeni hash ID $newve şube adı için eski hash ID olduğunu varsayalım $old: Dal tamamen yeniyse all-sıfırlar veya eğer öyleyse mevcut bazı geçerli commit mevcut bir şube adı.
Yeni taahhütler tamamen yeni bir şubedeyse, o zaman:
git rev-list $new ^master ^develop ^feature/short ^feature/tall
Örneğin, var olan tek dalların bu dördü olduğunu bilseydik (ve endişelenecek herhangi bir etiket vb. olmadığını) bilseydik onları kapsayacaktı. Ama ya ekleniyorlarsa, mesela develop? Ardından, şu anda devam eden taahhütleri hariç tutmak istiyoruz develop. Bunu $oldyapmak için hash kimliğini kullanabiliriz:
git rev-list $new ^master ^$old ^feature/short ^feature/tall
Bu yine yalnızca koşan git push origin developkişinin eklemek istediği yeni taahhütleri listeleyecektir develop.
Ama bir düşünün $old. Bu bir hash kimliğidir. Git bunu nereden aldı? Git var bu karma kimliği adı develop . Bu bir ön alım kancasıdır ; adı develop henüz güncellenmedi . Yani ad develop , eski karma kimliğin adıdır $old. Bunun anlamı:
git rev-list $new ^master ^develop ^feature/short ^feature/tall
olacaktır da iş yapmak.
git rev-list $newArdından "mevcut olanların tümü değil" ifadesi iş görürse , o zaman:
git rev-list $new --not --branches
işi yapacak. Neredeyse burada sahip olduğumuz şey bu.
Sadece kullanmanın hatası, --branchesherhangi bir etiket veya başka referans almamasıdır. Kullanabilirdik --not --branches --tagsama --not --alldaha kısadır ve diğer tüm referansları da alır.
İşte nereden --not --allgeliyor: ön alım kancasının özel durumuna bağlı. git pushGit'imizin bize ilettiği yeni hash kimliklerini, a'yı çalıştıran her kimse tarafından önerildiği gibi bir satır listesi olarak listeleriz. Biz git rev-listkarantina alanında yeni kaydedilmesini bakarak, ama bizim depoda zaten bütün hareketin hariç, önerilen--güncelleştirilmesi taahhüt grafiği yürüyün. Rev-list komutu, satır başına bir tane olmak üzere bu hash ID'lerini üretir, daha sonra bunları bir kabuk döngüsünde okuruz ve her commit'i incelemek için ne istersek onu yaparız .
1 Karantina alanı Git 2.11'de yeniydi. Bundan önce, itme reddedilse bile, yeni nesneler depoda bir süre kalabilir. Karantina alanı çoğu insan için gerçekten o kadar büyük bir sorun değil, ancak GitHub gibi büyük sunucular için onlara çok fazla disk alanı kazandırabilir.
2 Talep zorla veya zorla yapılmayabilir ve eğer zorlanırsa zorla kiralama olabilir veya olmayabilir. Bu bilgi, ön alım kancasında (ne de güncelleme kancasında) mevcut değildir, bu, um, sadece çok iyi olmadığını söyleyelim , ancak onu eklemeyle ilgili uyumluluk sorunları var. Yine de, çoğunlukla yaşanabilir. Kanca, bunun bir yeni başvuru oluşturup oluşturmadığını veya mevcut başvuru isteğini silip oluşturmadığını söyleyebilir, çünkü öyleyse, iki karma kimliğinden biri - eski ya da yeni - tümü sıfır olan "boş karma" (ayrılmış; karma kimliğine izin verilmez) tamamen sıfır olmak).
Anlamı:
- İşlemek verilen (s) kaynağındaki ana bağlantıları izleyerek ulaşılabilir Liste kaydedilmesini, burada
$new_list, yeni değiştirilmiş veya kaydedilmesini silindi - ancak
^önlerinde bir ile verilen işlemlerden erişilebilen kaydetmeleri hariç tutun , burada " tümü ", yani tüm HEADS taahhütleri veya etiketli kaydetmeler.
Bu, rev-listesini yalnızca alınan yeni kayıtlarla sınırlar ve tüm taahhütleri (alınan ve alıcı havuzda zaten mevcut olan) değil