Ders 08 / 12
Alt Modüller
Alt modül ana depoya bir tarihçe değil bir kimlik yazar: üç alt modül bir işlemeyi dört ayrı tarihçeye bağlar, 76 nesnelik 38 işleme 378 alt modül işlemesini içeri alır ve özyinelemeli klon 920 nesneden 4540'a çıkar.
İçindekiler
Buraya kadar tarihçe tek bir deponun içindeydi. İkili arama, suçlama ve yeniden yazma ölçüldü; nesne sayısı bu ölçümlerin arka planında durdu — bedeli belirleyen değişkendi ama ölçülen şeyin kendisi değildi.
Bu konuda arka plan öne geçiyor. Depo büyüdüğünde ve tek bir tarihçeye sığmayan parçalar taşımaya başladığında sorulan soru değişir: nesne sayısının kendisi iş olursa ne olur? İlk durum, bir deponun başka bir deponun tarihçesini içine alması. Bu dersin sorusu alt modülün nasıl kurulduğu değil — kurulumu iki komuttan ibarettir. Soru şudur: ana depoya yazılan tek bir kimlik, o depodaki bir işlemeyi kaç ayrı tarihçeye bağlar ve klon bedeli buna nasıl tepki verir?
Ana Depo Neyi Kaydeder
Alt modül (submodule), bir deponun çalışma ağacında duran ve kendi tarihçesi olan başka bir depodur. Ana depo onun dosyalarını kendi nesne deposuna kopyalamaz; kaydettiği tek şey alt modülün hangi işlemede durduğudur. Bu kayda sabitlenmiş sürüm (pinned version) denir ve ana depo ağacında bir dizin girdisi olarak durur.
İki dosya işin tamamıdır. .gitmodules alt modülün adını ve nereden getirileceğini bildirir;
ağaç girdisi ise sabitlenmiş sürümün kimliğini tutar. Birincisi işlenen bir metin dosyasıdır,
ikincisi her işlemede yeniden yazılabilen bir alandır.
# öğretilen komutlar ve dosya içeriği — örnek döküm, çalıştırılmamıştır git submodule add <alt-modül-adresi> bilesenler/olcum-cekirdegi git submodule update --init --recursive git clone --recurse-submodules <ana-depo-adresi> # .gitmodules [submodule "bilesenler/olcum-cekirdegi"] path = bilesenler/olcum-cekirdegi url = <alt-modül-adresi>
--recurse-submodules seçeneği klonlamayı ana depoyla bitirmez: her alt modülü ayrı ayrı
klonlar. Seçeneksiz klon alt modül dizinlerini boş bırakır; ana depo tarihçesi eksiksiz
gelir ama çalışma ağacı çalışmaz. update --init sonradan aynı işi yapar.
Sabitlenmiş Sürümün İki Yüzü
Sabitlenmiş sürüm ana depoda ucuz, ana depo dışında pahalıdır ve dersin bütün gerilimi buradadır.
Ucuz yüzü: alt modülü ilerletmek ana depoda tek bir işlemedir. Ağaç girdisindeki kimlik değişir, yeni bir ağaç ve mesajı taşıyan bir damla yazılır — iki nesne. Alt modülde o aralıkta kaç işleme birikmiş olursa olsun, ana depoya yazılan nesne sayısı bundan bağımsızdır.
Pahalı yüzü: o iki nesne, alt modül tarihçesindeki bir işlemeyi ana depo tarihçesine bağlar. Ana depodaki bir işlemeyi yeniden üretmek artık tek bir tarihçeye erişmeyi değil, ana depo ile her alt modülün tarihçesine birden erişmeyi gerektirir. Üç alt modülü olan bir depoda, tek bir işlemenin ağacını kurmak için dört ayrı tarihçeden dört kimlik okunmalıdır.
Bu ikinci yüz ölçülebilir bir şeydir ve ölçüm iki soruyu ayırır: ana depoda yazılan nesne kaçtır, ve o yazımın bağladığı tarihçe ne kadardır.
Dalı Değil İşlemeyi İzler
Sabitlenmiş sürüm bir işleme kimliğidir, bir dal adı değil. Bunun doğrudan bir sonucu var: alt modül dizini klonlandıktan sonra hiçbir dalın üstünde durmaz — ayrık HEAD durumundadır. Ayrık HEAD, Dallanma ve İşbirliği kursunda tarihçenin dışına düşen işleme bağlamında kurulmuştu; burada bir kaza değil, alt modülün normal durumudur. Ana depo bir dalı sabitleyemez, çünkü dal hareket eder ve hareket eden bir başvuru sabitlenmiş sürüm olamaz.
# öğretilen komutlar — örnek döküm, çalıştırılmamıştır git -C bilesenler/olcum-cekirdegi checkout ana git -C bilesenler/olcum-cekirdegi pull git add bilesenler/olcum-cekirdegi git commit -m "Ölçüm çekirdeği sabitlenmiş sürümü ilerletildi" git submodule update --remote bilesenler/olcum-cekirdegi git submodule status
İlerletme dört adımdır ve dördü de elle yapılır: alt modülde bir dala geçilir, yeni işlemeler
getirilir, ana depoda alt modül dizini hazırlık alanına alınır ve işlenir. Üçüncü adım
atlanırsa alt modül dizini yeni bir işlemeyi gösterir ama ana depo hâlâ eskisini kaydeder;
status çıktısı bunu bildirir, tarihçe bildirmez. --remote seçeneği ilk iki adımı
.gitmodules dosyasında yazılı dala göre otomatikleştirir, ama üçüncü adımı yine yazan
atar: ana depoya yazılmayan bir ilerletme yoktur.
Bu, alt modülü bir bağımlılık yöneticisinden ayıran yerdir. Bağımlılık yöneticisi bir aralık bildirir ve çözümü kendisi yapar; alt modül tek bir kimlik bildirir ve çözüm diye bir şey yoktur. Karşılığında alt modül tam tarihçeyi getirir: sabitlenmiş sürüme kadar olan her işleme oradadır, okunabilir ve üstünde arama yapılabilir.
Ölçümün Varsayımları
- BD1 — Ana depo ortak kurgunun 200 işlemelik ölçeğidir; üç alt modülün her biri aynı kurgudan ayrı bir tohumla üretilmiş bağımsız bir tarihçedir. Alt modül tarihçeleri ana depoyla hiçbir nesne paylaşmaz.
- BD2 — Sabitlenmiş sürümü ilerleten ana depo işlemeleri ayrı bir üreteçten seçilir; her ilerletme alt modülde 1 ile 20 arası işleme tüketir ve alt modülün sonunu aşamaz.
- BD3 — Sabitlenmiş sürümü ilerleten işleme ana depoda 2 nesne yazar: yeni ağaç ve mesajı taşıyan damla. Bu sayı, alt modülde kaç işleme geçildiğinden bağımsızdır.
- BD4 — “Kapsanan işleme”, alt modül tarihçesinde ana deponun ucuna kadar tüketilmiş işleme sayısıdır; ana depo tarihçesinde görünmez ama ana deponun ucundaki durumu yeniden üretmek için gereklidir.
- BD5 — “Gereken kimlik”, ana depodaki tek bir işlemenin ağacını kurmak için okunması gereken kimlik sayısıdır: ana deponun kendi kimliği artı her alt modülün sabitlenmiş sürümü.
- BD6 — Özyinelemeli klon her alt modülün tam tarihçesini getirir. Bedel dokunulan nesne birimiyle sayılır; ağ, saat ve disk ölçümün dışındadır.
Ölçüm
"""Alt moduller: sabitlenmis surumun bagladigi tarihce ve klon bedeli. Bolum 1 - her alt modulun ilerletme sayisi ve klon nesnesi. Bolum 2 - alt modul sayisi arttikca bagli tarihce ve ozyinelemeli klon. """ TOHUM = 20260814 DOSYALAR = ("olcum.py", "rapor.py", "kimlik.py", "ayar.py", "belge.md") ANA_OLCEK = 200 ALT_MODULLER = (("olcum-cekirdegi", 300, TOHUM + 1), ("rapor-bicimi", 150, TOHUM + 2), ("kimlik-kitapligi", 80, TOHUM + 3)) def uretec(tohum): d = tohum % 2147483646 + 1 def r(n): nonlocal d d = (d * 48271) % 2147483647 return d % n return r def tarihce(n, tohum=TOHUM): """n islemelik dogrusal tarihce; her isleme bir dosyaya dokunuyor.""" r, liste = uretec(tohum), [] for i in range(n): dosya = DOSYALAR[r(5)] ikili = r(11) == 0 liste.append({"no": i + 1, "dosya": dosya, "ikili": ikili, "nesne": 2 + (40 if ikili else 0)}) return liste def klon_bedeli(t, ikili_dahil=True): return sum(x["nesne"] for x in t if ikili_dahil or not x["ikili"]) def sabitlemeler(ana, alt, tohum): """Ana depodaki hangi islemeler sabitlenmis surumu ilerletiyor.""" r, kayit, yer = uretec(tohum), [], 0 for x in ana: ilerlet = r(12) == 0 adim = 1 + r(20) if ilerlet and yer < len(alt): yer = min(yer + adim, len(alt)) kayit.append({"ana_no": x["no"], "sabit": yer}) return kayit ana = tarihce(ANA_OLCEK) print(f"ana depo {len(ana)} isleme, klon nesnesi {klon_bedeli(ana)}, " f"ikilisiz {klon_bedeli(ana, False)}") print() print("alt modul isleme ilerletme kapsanan isleme ana depoda nesne" " klon nesnesi") kayitlar = [] for ad, n, tohum in ALT_MODULLER: alt = tarihce(n, tohum) s = sabitlemeler(ana, alt, tohum + 100) kayitlar.append((ad, alt, s)) print(f" {ad:18s} {n:6d} {len(s):10d} {s[-1]['sabit']:16d} " f"{len(s) * 2:17d} {klon_bedeli(alt):13d}") print() print("alt modul sayisi bagli tarihce gereken kimlik ana klon nesnesi" " ozyinelemeli klon nesnesi kat") for k in range(len(ALT_MODULLER) + 1): ozyinelemeli = klon_bedeli(ana) + sum(klon_bedeli(a) for _, a, _ in kayitlar[:k]) print(f"{k:16d} {k + 1:14d} {k + 1:15d} {klon_bedeli(ana):17d} " f"{ozyinelemeli:25d} {ozyinelemeli / klon_bedeli(ana):5.2f}") print() toplam_ilerletme = sum(len(s) for _, _, s in kayitlar) toplam_kapsanan = sum(s[-1]["sabit"] for _, _, s in kayitlar) print(f"sabitlemeyi ilerleten ana depo islemesi {toplam_ilerletme}, " f"ana depoya yazdigi nesne {toplam_ilerletme * 2}, " f"bagladigi alt modul islemesi {toplam_kapsanan}") print(f"ana depo tarihcesi {len(ana)} isleme gorunuyor; " f"kapsadigi isleme {len(ana) + toplam_kapsanan}")
ana depo 200 isleme, klon nesnesi 920, ikilisiz 374
alt modul isleme ilerletme kapsanan isleme ana depoda nesne klon nesnesi
olcum-cekirdegi 300 18 161 36 2200
rapor-bicimi 150 14 137 28 980
kimlik-kitapligi 80 6 80 12 440
alt modul sayisi bagli tarihce gereken kimlik ana klon nesnesi ozyinelemeli klon nesnesi kat
0 1 1 920 920 1.00
1 2 2 920 3120 3.39
2 3 3 920 4100 4.46
3 4 4 920 4540 4.93
sabitlemeyi ilerleten ana depo islemesi 38, ana depoya yazdigi nesne 76, bagladigi alt modul islemesi 378
ana depo tarihcesi 200 isleme gorunuyor; kapsadigi isleme 578
Bağlanan Tarihçe
Son iki satır dersin çekirdeğini veriyor. Ana depoda sabitlemeyi ilerleten 38 işleme var ve bu işlemeler ana depoya toplam 76 nesne yazıyor — iki yüz işlemelik tarihçenin 920 nesnesinin içinde küçük bir paydır. Aynı 38 işleme, alt modül tarihçelerinden 378 işlemeyi ana depoya bağlıyor.
Oran doğrudan okunur: ana depoya yazılan her 2 nesne, ortalama on alt modül işlemesini içeri alıyor. Bu, dersin ölçtüğü asimetridir. Ana depo tarihçesine bakan biri 200 işleme görür; ana deponun ucundaki durumu yeniden üretmek için gereken işleme sayısı 578’dir. Görünen tarihçe ile kapsanan tarihçe aynı şey değildir ve aradaki fark ana depoda hiçbir yerde yazılı değildir.
Bu asimetrinin bir tanı sonucu var. Ana depoda yürütülen bir arama yalnız ana deponun 200 işlemesini tarar; alt modüllerin 378 kapsanan işlemesi o taramanın dışındadır. Bir kusur alt modülde girmişse ana depodaki arama onu bulamaz — bulabileceği en dar aralık, kusuru içeri alan sabitleme işlemesidir. Aramanın ikinci turu alt modülün kendi tarihçesinde yeniden kurulmak zorundadır. Ana depoda daralan aralık iki işleme olsa bile, o iki işlemenin arasına sıkışmış alt modül işlemesi sayısı yirmiye kadar çıkabilir.
İkinci tablonun ilk iki sütunu aynı şeyi kimlik cinsinden söylüyor. Alt modül yokken bir işlemenin ağacını kurmak 1 kimlik ister ve 1 tarihçeye bakar. Üç alt modülle bu sayı 4’e çıkar. Dördü de bulunmak zorundadır: alt modüllerden biri erişilemezse ana depodaki işleme eksiksiz olarak durur ama yeniden üretilemez. Ana deponun tarihçesi bozulmamıştır; eksik olan başka bir tarihçedir.
Klon Bedelinin Toplanması
Alt tablonun sağ üç sütunu klon bedelini veriyor ve birim dokunulan nesnedir.
Ana depo tek başına 920 nesne. Alt modüller sırasıyla 2200, 980 ve 440 nesne getiriyor. Üçü de eklenince özyinelemeli klon 4540 nesneye çıkıyor — ana depo klonunun 4,93 katı. Ana depo tarihçesi bu sırada bir işleme bile büyümedi.
En büyük katkı ilk alt modülden geliyor ve nedeni tabloda yazılı: 300 işlemelik tarihçesi ana depodan büyük. Alt modülün boyu ana deponun boyuyla ilgisizdir; ana depo onu sabitleyen kimliği yazarken alt modülün büyüklüğüne bakmaz. Ana deposu küçük, klon bedeli büyük bir düzenlemenin önünde hiçbir engel yoktur.
Tablonun sağ sütunundaki kat sayısı doğrusal artmıyor: 3,39, sonra 4,46, sonra 4,93. Artış her adımda küçülüyor çünkü eklenen alt modüller giderek daha kısa. Sıra ters olsaydı sayılar başka görünürdü ama son satır aynı kalırdı — toplam, sıradan bağımsızdır. Kat sayısının kendisi de bir şey söylemiyor; söyleyen, alt modül tarihçelerinin toplamının ana depo tarihçesinden üç kattan fazla olmasıdır. Bu oran, ana depoya bakan hiçbir ölçümde görünmez.
Özyineleme bir katmanla da sınırlı değildir. Bir alt modülün kendi alt modülü varsa
--recursive seçeneği onu da getirir ve bağlı tarihçe sayısı beşe, gereken kimlik
sayısı beşe çıkar. Ölçüm bunu kurmuyor, ama düzenin kuralı değişmiyor: her katman ana
depoya iki nesne yazar ve arkasına kendi tarihçesinin tamamını bağlar.
Buradan iki pratik sonuç çıkar. Birincisi: özyinelemeli olmayan klon ana depo tarihçesini eksiksiz getirir ve alt modüllerin hiçbir nesnesini getirmez; bu, tarihçeyi okumak isteyen biri için doğru seçimdir. İkincisi: çalışma ağacına ihtiyacı olan biri özyinelemeli klon yapmak zorundadır ve tabloda okunan katı öder. Aynı depoda iki ayrı bedel vardır ve hangisinin ödendiğini kullanılan seçenek belirler.
Kırılan Bağ ve Kurtarma
Sabitlenmiş sürüm bir kimliktir ve kimlik, işaret ettiği işleme erişilebilir olduğu sürece geçerlidir. Alt modülün yukarı deposunda tarihçe yeniden yazılırsa — konunun ilk dersinde ölçülen işlem — eski kimlikler artık hiçbir işlemeyi göstermez. Ana depodaki 38 ilerletme işlemesinden kaçının kırılacağı, yeniden yazmanın hangi noktadan başladığına bağlıdır.
Bu bir veri kaybı değildir ama ana depo tarihçesinin geçmiş noktalarını yeniden üretilemez hâle getirir ve kaybın kaydı ana depoda tutulmaz. Kurtarma yolu üç adımlıdır. Alt modülün eski işlemeleri hâlâ bir yerde duruyorsa — bir kopyada, bir yedek dalda ya da referans günlüğü penceresi kapanmamışsa — o işlemeler ayrı bir başvurudan geri getirilebilir ve kimlikler yeniden çözülür. Duruyorsa. İkinci yol, ana depoda sabitlenmiş sürümleri yeni kimliklere taşıyan bir düzeltme işlemesi yazmaktır; bu geçmişi kurtarmaz, yalnız ucu onarır. Üçüncüsü ve en ucuzu, kaybı hiç doğurmamaktır: alt modül olarak bağlanan bir depoda tarihçe yeniden yazılmadan önce, o depoyu sabitleyen ana depoların bilinmesi gerekir. Bağın yönü tek taraflıdır — alt modül kendisini kimin sabitlediğini bilmez.
Özet
- Alt modül, ana depoya bir tarihçe değil bir kimlik yazar; kayıt
.gitmodulesdosyası ile ağaç girdisindeki sabitlenmiş sürümden ibarettir. - Sabitlenmiş sürümü ilerletmek ana depoda 2 nesne yazar ve bu sayı alt modülde kaç işleme geçildiğinden bağımsızdır; ölçümde 76 nesne, 378 alt modül işlemesini bağlar.
- Ana depo tarihçesi 200 işleme görünür; ucundaki durumu yeniden üretmek için gereken işleme sayısı 578’dir ve bu fark ana depoda yazılı değildir.
- Üç alt modülle bir işlemenin ağacını kurmak 4 ayrı tarihçeden 4 kimlik ister; biri erişilemezse işleme bozulmaz ama yeniden üretilemez.
- Özyinelemeli klon 920 nesneden 4540 nesneye çıkar — 4,93 kat; özyinelemesiz klon ana depo tarihçesini eksiksiz getirir ve alt modülden 0 nesne alır.
Sonraki Adım
Alt modülde bedeli büyüten şey işleme sayısıydı: üç yüz işlemelik bir tarihçe, seksen işlemelik olandan beş kat fazla nesne getirdi. Bu, nesne sayısının işleme sayısını izlediği bir durumdur ve sezgiye uyar. Sonraki ders sezginin bozulduğu duruma bakar: aynı tarihçede işlemelerin onda birinden azı toplam nesnenin üçte ikisinden fazlasını üretirse, tarihçeyi ağırlaştıran şeyin ne olduğu sorusu yeniden sorulmak zorundadır — ve yanıt işleme sayısı değildir. O durumda depoyu bölmek çare olmaz, çünkü ağırlık işlemelerin dağılımından değil taşıdıkları nesnenin türünden gelir; tarihçeden çıkarılması gereken şey bir depo değil, bir dosya sınıfıdır.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.