Ders 01 / 12
Etkileşimli Yeniden Temellendirme
Bir işlemeyi değiştirmek ondan sonraki her işlemenin kimliğini değiştirir; ortadan yeniden yazmak 50, 200, 1000 ve 4000 işlemelik tarihçelerde sırasıyla 252, 362, 3002 ve 11322 nesneye dokunur ve oran her ölçekte yaklaşık yarıda kalır.
İçindekiler
Önceki kurs tarihçeyi tek bir ölçüyle okudu: bir tümleştirme biçiminin değeri, ürettiği kod değil, bıraktığı tarihçenin yanıtlayabildiği soru sayısıydı. Dört biçim aynı kodu üretiyor ve altı sorunun sırasıyla beşini, üçünü, ikisini ve üçünü yanıtlıyordu. O kursta tarihçe verilmiş bir kayıttı: sorular ona sorulur, yanıtlar sayılırdı. Kayıt yazıldıktan sonra onu değiştirmek gündeme gelmiyordu.
Bu kurs aynı kaydı bir nesne olarak ele alır. Tarihçe yeniden yazılabilir: işleme mesajı düzeltilebilir, iki işleme tek işlemeye indirilebilir, sıra değiştirilebilir, bir işleme tümüyle atılabilir. Ölçü de bununla birlikte değişir. Orada ölçülen yanıtlanan soruydu; burada ölçülen dokunulan nesnedir. Bu dersin sorusu şudur: bir işlemeyi geriye dönüp değiştirmek tarihçenin ne kadarına dokunur, ve tarihçe büyüdükçe bu oran düşer mi.
Kimlik Zincir Boyunca Yayılır
Bir işlemenin kimliği içeriğinden türetilir. Kimliğe giren alanlar bellidir: o anki dosya ağacı, yazar, işleyen, zaman damgası, mesaj ve öncülün kimliği. Son alan bu kursun tamamını belirler. Öncülün kimliği değiştiğinde ardılın kimliği de zorunlu olarak değişir, çünkü ardılın içeriği öncülün kimliğini taşır. Kimlik içerikten üretildiği için bu kaçınılmazdır: aynı kimliği koruyup içeriği değiştirmenin yolu yoktur, olsaydı kimlik bir kimlik olmazdı.
Bunun sonucu tek cümlede yazılabilir: bir işlemeyi değiştirmek, ondan sonraki her işlemenin kimliğini değiştirir. Tek bir yazım hatasını düzeltmekle bütün bir dosyayı tarihçeden çıkarmak arasında bu bakımdan fark yoktur; ikisi de aynı noktadan sonrasını yeniden üretir. Değişikliğin büyüklüğü bedeli belirlemez, yeri belirler.
Eski işlemeler bu sırada silinmez. Depoda dururlar; onları gösteren hiçbir dal ya da etiket kalmadığı için erişilemez hâle gelirler. Erişilemez olmak yok olmak değildir ve bu ayrım bu konunun dördüncü dersinin tamamıdır. Şimdilik şu kadarı yeter: yeniden yazma bir silme değil, bir çoğaltmadır — eski zincir yerinde durur, yanına yeni bir zincir yazılır ve dal ucu yeni olanı gösterir.
Etkileşimli Kip
Yeniden temellendirme önceki kursta bir tümleştirme biçimi olarak kuruldu: dalın işlemeleri yamaya çevrilir ve yeni bir taban üzerine sırayla uygulanır. O karşılaştırma burada tekrarlanmaz. Ayrılan şey, aynı ailenin orada hiç geçmemiş olan etkileşimli (interactive) kipidir.
Etkileşimli kipte araç yamaları doğrudan uygulamaz. Önce plana alınacak işlemeleri bir liste hâlinde önünüze koyar; listedeki her satır bir işlemeyi ve o işlemeye uygulanacak eylemi taşır. Liste kaydedilip kapatıldığında araç satırları yukarıdan aşağıya yürütür.
# öğretilen komut, örnek döküm — çalıştırılmamıştır $ git rebase -i HEAD~3 pick 9c4d7e1 olcum: eşik değerini yazdır pick 4a5b6c7 rapor: alan genişliğini düzelt pick 5b6c7d8 rapor: özet satırını ekle # r, reword = işlemeyi al, mesajını düzelt # s, squash = işlemeyi öncülüyle birleştir # d, drop = işlemeyi at
Dört eylem bu dersin ölçüm eksenidir. Yeniden adlandırma işlemeyi tutar, yalnız mesajını değiştirir. Sıra değiştirme satırların yerini değiştirir; tarihçedeki sıra plandaki sıra olur. Sıkıştırma bir işlemeyi öncülüyle birleştirir ve sonuçtaki işleme sayısını bir azaltır. Atma işlemeyi tümüyle çıkarır ve o da sayıyı bir azaltır.
Dördü de çok farklı işler yapar: biri yalnız bir metni düzeltir, öbürü bir değişikliği tarihçeden çıkarır. Ölçümün sorduğu şey bu farkın bedele yansıyıp yansımadığıdır.
Bu eylemlerden biri Sürüm Kontrolüne Giriş kursunda tek başına kurulmuştu: son işlemeyi yerinde değiştiren yetenek, hazırlık alanının o anki durumundan yeni bir işleme üretiyor ve eskisini erişilemez bırakıyordu. Orada da bir yeniden yazma vardı, yalnız en sığ olanıydı — tarihçenin ucunda duruyordu ve ardılı yoktu. Etkileşimli kip aynı işi tarihçenin herhangi bir yerinde yapar; ardılı olan bir işlemede yapıldığında bedel de birlikte gelir.
Plan yürütülürken bir yama uygulanamayabilir. Bu durumun mekaniği önceki kursta yeniden temellendirme biçimiyle birlikte kuruldu ve burada tekrarlanmaz. Etkileşimli kipe özgü olan iki nokta şudur: sıkıştırma satırında araç birleşen işlemelerin mesajlarını tek bir metinde önünüze getirir ve düzeltmenizi bekler; ve işlem yarıda iptal edildiğinde dal ucu plana girmeden önceki yerine döner. İptal, plan yürürken elde kalan tek bütünlüklü çıkıştır.
Bedel Nereden Başlar
Etkileşimli kip listeye kaç işleme alacağınızı sorar. Son üç işlemeyi planlarsanız araç üç satır gösterir ve yeniden yazma üçüncü işlemeden başlar. Tarihçenin ortasındaki bir işlemeyi düzeltmek istiyorsanız listeye o işlemeden bu yana yazılmış her şeyi almak zorundasınız — düzeltilecek satır bir tane olsa bile.
Bedel bu yüzden plandaki eylem sayısıyla değil, planın nereden başladığıyla ölçülür. Ölçüm bunu iki ayrı biçimde sorar: aynı konumda dört ayrı eylem, ve aynı eylem dört ayrı derinlikte.
Planın iki sınırı burada söylenmelidir. Birincisi, listedeki satırların altında kalan işlemelere dokunulamaz; başlangıç noktası bir kez seçildikten sonra ondan öncesi plan dışıdır ve daha geriye gitmek yeni bir plan demektir. İkincisi, tarihçede bir çatal kenarı varsa doğrusal plan onu olduğu gibi taşımaz: birleştirme işlemeleri ayrıca istenmedikçe düzleştirilir ve iki öncüllü yapı tek öncüle iner. Ölçümün kurgusu doğrusaldır, bu yüzden ikinci sınır ölçüme girmez; ama tarihçesinde çatal bulunan bir depoda planı kurmadan önce bilinmesi gerekir.
Ölçümün varsayımları:
- YZ1 — Kurgu tek bir tarihçedir ve dört ölçekte kurulur: 50, 200, 1000, 4000 işleme. Her işleme beş dosyadan birine dokunur; on birde biri ayrıca bir ikili varlık taşır ve o varlığın her sürümü tarihçede ayrı bir nesne olarak durur.
- YZ2 — Bir işlemenin nesne bedeli ağaç ve damla için 2’dir; ikili varlık taşıyorsa buna 40 eklenir. Sayım deponun nesne sayımıdır, dosya sayımı değil.
- YZ3 — Bir işlemeyi değiştirmek ondan sonraki her işlemenin kimliğini değiştirir. Dokunulan küme, değiştirilen konumdan tarihçenin ucuna kadar olan kapalı aralıktır.
- YZ4 — “Ortadan yeniden yazmak” konum olarak
n // 2demektir; ölçek değişse de kural değişmez. - YZ5 — Etkileşimli kipin dört eylemi yalnız sonucun uzunluğunu ayırır: sıkıştırma ve atma bir işleme eksiltir, yeniden adlandırma ve sıra değiştirme eksiltmez. Dokunulan küme dördünde de aynıdır.
- YZ6 — Bu dersin bedel birimi dokunulan nesnedir. Kimliği değişen işleme sayısı bir bedel değil, dokunulan kümenin genişliğidir; adım birimi bu derste kullanılmaz.
- YZ7 — Plana alınan işleme sayısı
kise yeniden yazman - k + 1konumundan başlar. - YZ8 — Kümenin çözünürlüğü dört ölçekte sırasıyla 1/50, 1/200, 1/1000, 1/4000’dir.
Ölçüm
"""Etkilesimli yeniden temellendirme: ortadan yeniden yazmanin bedeli. Bolum 1 - dort olcekte ortadan yeniden yazma: isleme, nesne, oran. Bolum 2 - etkilesimli kipin dort eylemi ayni konumda. Bolum 3 - plana alinan isleme sayisi bedeli belirler. """ TOHUM = 20260814 DOSYALAR = ("olcum.py", "rapor.py", "kimlik.py", "ayar.py", "belge.md") OLCEKLER = (50, 200, 1000, 4000) EYLEMLER = ("yeniden adlandırma", "sıra değiştirme", "sıkıştırma", "atma") 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 yeniden_yaz(t, konum): """Bir islemeyi degistirmek, ondan sonrakilerin kimligini degistirir.""" sonra = [x for x in t if x["no"] >= konum] return len(sonra), sum(x["nesne"] for x in sonra) def klon_bedeli(t): return sum(x["nesne"] for x in t) def etkilesimli(t, konum, eylem): """Dort eylem: sonucun uzunlugu degisir, dokunulan kume degismez.""" isl, nes = yeniden_yaz(t, konum) return len(t) - (1 if eylem in ("sıkıştırma", "atma") else 0), isl, nes print(f"{'işleme':>7s} {'yeniden yazılan':>16s} {'dokunulan nesne':>16s}" f" {'oran':>6s} {'nesne oranı':>12s}") for n in OLCEKLER: t = tarihce(n) isl, nes = yeniden_yaz(t, n // 2) print(f"{n:7d} {isl:16d} {nes:16d} {isl / n:6.3f}" f" {nes / klon_bedeli(t):12.3f}") print() T = tarihce(1000) print(f"{'eylem':<18s} {'sonuç işleme':>13s} {'kimliği değişen':>16s}" f" {'dokunulan nesne':>16s}") for e in EYLEMLER: kalan, isl, nes = etkilesimli(T, 500, e) print(f"{e:<18s} {kalan:13d} {isl:16d} {nes:16d}") print() print(f"{'plana alınan':>13s} {'başlanan konum':>15s} {'kimliği değişen':>16s}" f" {'dokunulan nesne':>16s} {'oran':>6s}") for k in (3, 10, 50, 500): isl, nes = yeniden_yaz(T, len(T) - k + 1) print(f"{k:13d} {len(T) - k + 1:15d} {isl:16d} {nes:16d}" f" {isl / len(T):6.3f}")
işleme yeniden yazılan dokunulan nesne oran nesne oranı
50 26 252 0.520 0.663
200 101 362 0.505 0.393
1000 501 3002 0.501 0.532
4000 2001 11322 0.500 0.501
eylem sonuç işleme kimliği değişen dokunulan nesne
yeniden adlandırma 1000 501 3002
sıra değiştirme 1000 501 3002
sıkıştırma 999 501 3002
atma 999 501 3002
plana alınan başlanan konum kimliği değişen dokunulan nesne oran
3 998 3 6 0.003
10 991 10 20 0.010
50 951 50 260 0.050
500 501 500 3000 0.500
Yeniden Yazma Oransal Olarak Ucuzlamaz
Üst tablo dört ölçekte aynı işlemi yapıyor: tarihçenin ortasındaki işlemeyi değiştirmek. Dokunulan nesne 252’den 11322’ye çıkıyor — kırk beş kat. Sağdaki oran sütunu ise kıpırdamıyor: 0,520 / 0,505 / 0,501 / 0,500. Tarihçe seksen kat büyüdüğünde ortadan yeniden yazma hâlâ işlemelerin yaklaşık yarısına dokunuyor.
Bu, sezgiye ters düşen bir sonuçtur. Büyüyen bir tarihçede tek bir işlemeyi düzeltmenin oransal olarak daha küçük bir iş hâline geleceği düşünülebilir; olan bunun tersidir. Oran sabit kaldığı için mutlak bedel tarihçeyle birlikte doğrusal büyür. Yeniden yazma oransal olarak ucuzlamaz; ucuzlayan tek şey, uca yakın durmaktır.
Nesne oranı sütunu ayrı bir uyarı taşıyor. İşleme oranı 0,500’e yaklaşırken nesne oranı
0,663 / 0,393 / 0,532 / 0,501 diye zıplıyor. Küçük ölçeklerde ikili varlık taşıyan
işlemelerin nereye düştüğü sonucu belirliyor: elli işlemelik tarihçede o işlemelerin çoğu
ikinci yarıda, iki yüzlükte çoğu birinci yarıda kalmış. İşleme saymakla nesne saymak aynı
şey değildir ve bu ayrımın kendisi buyuk-depolar konusunun ölçüsüdür. Burada yalnız şu
kaydedilir: oran hangi birimle sayıldığına bağlıdır ve bu dersin birimi nesnedir.
Orta tablo ikinci soruya yanıt veriyor. Dört eylem aynı konumda uygulandığında kimliği değişen 501, dokunulan nesne 3002 — dördünde de aynı. Ayrışan tek sütun sonuçtaki işleme sayısı: sıkıştırma ve atma 999, öbür ikisi 1000. Yani bir mesajdaki yazım hatasını düzeltmek ile bir işlemeyi tarihçeden tümüyle çıkarmak aynı bedele sahiptir. Araç hangi eylemi seçtiğinizi umursamaz; nereden başladığınızı umursar.
Alt tablo bunu tersinden ölçüyor. Plana 3 işleme alındığında dokunulan nesne 6; 10 alındığında 20; 50 alındığında 260; 500 alındığında 3000. Elli işlemelik planın nesne bedeli on işlemeliğin on üç katıdır, oysa işleme sayısı yalnız beş katıdır — aradaki fark plana giren aralığa düşen ikili varlıklardan gelir. Uçtaki işlemeler bu yüzden ucuzdur ve etkileşimli kipin günlük kullanımı da oradadır: henüz paylaşılmamış son birkaç işlemeyi düzenlemek.
Üç tablo birlikte okunduğunda tek bir kural veriyor: planı uca yakın tut. Kuralın hem bedel hem de risk tarafı vardır. Bedel tarafı ölçüldü — üç işlemelik plan altı nesneye, beş yüz işlemelik plan üç bin nesneye dokunuyor. Risk tarafı henüz ölçülmedi: plana giren aralık ne kadar geriye uzanırsa, o aralıktaki işlemelerin başkaları tarafından çoktan alınmış olma olasılığı da o kadar yükselir. İki taraf da aynı yöne bakar ve ikisi de aynı şeyi söyler; ölçülen ikincisi bu konunun üçüncü dersinde gelir.
Yeniden Yazmadan Önce
Yeniden yazma geri alınabilir bir işlem değildir; eski zincirin erişilemez kalması, onu geri getirmenin bir yolu bulunmadığı anlamına gelmez ama bir yolu arayacağınız anlamına gelir. Üç alışkanlık bu aramayı gereksiz kılar.
Yedek dal. İşlemden önce dalın o anki ucunu gösteren bir dal açmak tek satırdır ve kurtarmayı bir işaretçi geri almaya indirger. Yedek dal yerel bir kayıt değildir; olağan bir daldır, silinene kadar durur.
Kuru çalışma. Planı uygulamadan önce iki zincirin ne kadar ayrıştığını gösteren karşılaştırma yetenekleri vardır. Yeniden yazılmış zincir ile yedeği yan yana konduğunda hangi işlemenin gerçekten değiştiği, hangisinin yalnız kimlik değiştirdiği okunur.
Ayrı klon. Toplu bir dönüşüm denenecekse deponun ayrı bir kopyası üzerinde denenir. Bu, sonraki dersin konusudur ve orada zorunlu bir adım hâline gelir.
# öğretilen komut, örnek döküm — çalıştırılmamıştır $ git branch yedek/olcum olcum $ git rebase -i --onto ana 9c4d7e1 olcum $ git range-diff ana...yedek/olcum ana...olcum
Dördüncü güvence referans günlüğüdür (reflog): araç dal ucunun her hareketini yerel bir günlüğe yazar ve eski uç oradan okunabilir. Günlüğün iki sınırı vardır — yereldir ve süresizce saklanmaz. Bu konunun dördüncü dersi tam olarak o sınırı ölçer: yeniden yazmadan sonra kaç işlemenin erişilebilir kaldığını ve kurtarma penceresinin ne zaman kapandığını.
Özet
- Bir işlemenin kimliği öncülünün kimliğini içerir; bu yüzden bir işlemeyi değiştirmek ondan sonraki her işlemenin kimliğini değiştirir. Bedeli belirleyen, değişikliğin büyüklüğü değil yeridir.
- Etkileşimli kip işlemeleri bir plan listesine alır; dört eylem yeniden adlandırma, sıra değiştirme, sıkıştırma ve atmadır.
- Aynı konumda dört eylem de 501 işlemenin kimliğini değiştirir ve 3002 nesneye dokunur; ayrışan tek şey sonuçtaki işleme sayısıdır (999 ya da 1000).
- Ortadan yeniden yazmak dört ölçekte 252 / 362 / 3002 / 11322 nesneye dokunur ve oran 0,520 / 0,505 / 0,501 / 0,500’de kalır: yeniden yazma oransal olarak ucuzlamaz.
- Plana alınan işleme sayısı bedeli doğrudan belirler: 3 / 10 / 50 / 500 işlemelik planlar sırasıyla 6 / 20 / 260 / 3000 nesneye dokunur.
- Yeniden yazma geri alınamaz; yedek dal, kuru çalışma ve ayrı klon üç güvencedir.
Sonraki Adım
Bu derste yeniden yazma tek bir dalın son birkaç işlemesinde kaldı ve en derin denemesi bile tarihçenin ortasından başladı. Bazen gereken bundan geniştir: bir dosyanın tarihçedeki her sürümünün çıkarılması, bir yazar alanının bütün işlemelerde düzeltilmesi, bir dizinin köke taşınması. Bu işlerin ortak yanı, tarihçenin ilk işlemesinden başlamak zorunda olmalarıdır. Sonraki ders bu genişlemenin bedelini ölçer: bin işlemelik bir tarihçede ilk işlemeden başlayan bir dönüşüm kaç kimliği değiştirir, kaç nesneye dokunur, ve işlem tamamlandıktan sonra deponun kopyalarına ne olur.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.