---
title: 'İleri Git'
source: 'https://academia.sh/tr/kurslar/ileri-git'
language: tr
updated: '2026-08-17T04:42:42+00:00'
license: 'CC BY-SA 4.0'
lessons: 12
outcomes:
    - 'Tarihçeyi yeniden yazma araçlarını risklerini bilerek kullanır'
    - 'Bir hatanın hangi işlemede girdiğini sistematik olarak bulur'
    - 'Büyük ve çok bileşenli depoları yönetir'
---

# İleri Git

Tarihçeyi yeniden yazan, tarihçeye soru soran ve büyüyen depoyu yöneten araçlar; kurs her işlemin bedelini tarihçenin uzunluğuyla değil dokunduğu nesne sayısıyla ölçer.

## Tarihçeyi Yeniden Yazma

İşleme sıkıştırma, düzenleme ve yeniden sıralama; depo genelinde geçmiş değiştirmenin maliyeti; paylaşılan dallarda zorlayıcı itme disiplini; ve kaybolan işlemeleri referans günlüğüyle kurtarma.

### Etkileşimli Yeniden Temellendirme

Source: https://academia.sh/tr/kurslar/ileri-git/etkilesimli-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.

Ö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.

```text
# öğ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 // 2` demektir; ö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ı `k` ise yeniden yazma `n - k + 1` konumundan 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

```python
"""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.

```text
# öğ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.

### Toplu Tarihçe Dönüşümü

Source: https://academia.sh/tr/kurslar/ileri-git/toplu-tarihce-donusumu

Depo genelinde bir dönüşüm ilk işlemeden başlar: bin işlemelik tarihçede 1000 kimlik değişir, 5640 nesneye dokunulur ve yeni tarihçe eskisiyle tek bir işleme bile paylaşmaz — bu yüzden her kopya yeniden klonlanmak zorundadır ve işlem geri alınamaz.

Önceki ders yeniden yazmayı tek bir dalın üstünde tuttu. Plan uca yakın kaldığında bedel
küçüktü: üç işlemelik bir plan altı nesneye dokunuyordu. Tarihçenin ortasından başlandığında
bile işlemelerin yaklaşık yarısı kimlik değiştiriyor, geri kalan yarısı olduğu gibi
kalıyordu. O yarı, ölçümün gördüğü en derin noktaydı.

Bazı işler o kadarını bile bırakmaz. Deponun ilk günlerinde işlenmiş ve orada durmaması
gereken bir varlık, bütün işlemelerde yanlış yazılmış bir yazar alanı, kökün altına
taşınması gereken bir dizin — bunların hepsi tarihçenin **ilk** işlemesinden başlamak
zorundadır. Bunlara **toplu tarihçe dönüşümü** denir ve önceki dersin aracıyla aynı aileden
olsalar da başka bir ölçekte çalışırlar. Bu dersin sorusu şudur: dönüşüm ilk işlemeden
başladığında bedel ne olur ve işlem bittikten sonra deponun öbür kopyalarının elinde ne
kalır.

#### Kural Olarak Dönüşüm

Etkileşimli kipte plan bir listeydi: satırları görüyor, tek tek eylem yazıyordunuz. Toplu
dönüşümde plan yoktur; **kural** vardır. Kural her işlemeye sırayla uygulanır, işlemenin
ağacı kuraldan geçirilir ve sonuçtan yeni bir işleme üretilir. On işlemeyle bin işleme
arasındaki fark yalnız süredir; yazılan kural aynı kuraldır.

Dört tipik gereksinim bu sınıfa girer. **Bir varlığın çıkarılması:** hiç işlenmemesi gereken
bir ikili dosya ya da bir gizli anahtar tarihçede duruyorsa, onu son işlemeden silmek
yetmez; eski işlemelerden okunabilir olmaya devam eder. **Üstveri düzeltmesi:** yazar ya da
işleyen alanı bütün tarihçede yanlışsa. **Ağaç taşıması:** bir alt dizinin deponun kökü
hâline getirilmesi ya da tersi. **Geriye dönük normalleştirme:** satır sonu ya da kodlama
düzeltmesinin yalnız yeni işlemelere değil, eskilerine de uygulanması.

Aracın bu işi yapan alt komutu vardır ve depo dışında çalışan süzme araçları da vardır.
Komut bu derste **tam biçimde verilmez.** Nedeni öğretim değil sorumluluktur: kopyalanıp
çalıştırılabilir bir toplu dönüşüm satırı, çalıştırıldığı deponun tarihçesini geri
alınamayacak biçimde değiştirir ve o deponun bütün kopyalarını geçersiz kılar. Aşağıdaki
döküm süzgeç yerine bir yer tutucu taşır ve çalıştırılamaz.

```text
# örnek döküm — çalıştırılmamıştır, komut tam biçimde verilmemiştir

$ git filter-branch <süzgeç> -- --all
Rewrite 9c4d7e1 (1/1000) (0 seconds passed, remaining 0 predicted)
Rewrite 4a5b6c7 (2/1000) (0 seconds passed, remaining 0 predicted)
...
Ref 'refs/heads/ana' was rewritten
```

Dökümün sayacı dersin ölçüsünü doğrudan gösteriyor: sayaç birden bine kadar sayıyor, çünkü
bin işlemenin bini yeniden üretiliyor.

Dökümün sonundaki satır ikinci bir şey söylüyor. Etkileşimli kip tek bir dalın ucundan
çalışır; toplu dönüşüm **başvuruların tümüne** uygulanabilir ve genellikle öyle uygulanır.
Nedeni ölçümle doğrudan ilgilidir: dönüşümün dışında bırakılan bir dal ya da bir etiket eski
zinciri göstermeye devam eder, o zincir erişilebilir kalır ve çıkarılmak istenen varlık
depodan gitmez. Bir dalı unutmak, dönüşümü yapmamakla aynı sonucu verir. Bu yüzden kapsam
kararı kuralın kendisinden önce verilir: hangi başvurular dönüşüme girecek, hangileri
dönüşümden önce silinecek.

#### Dönüşüm Nereden Başlar

Kural her işlemeye uygulanır, ama **kimlik değişimi** her işlemede başlamaz. Kuralın içeriği
gerçekten değiştirdiği ilk işlemeye kadar üretilen işlemeler eskisiyle birebir aynı çıkar ve
aynı kimliği alır. Değişim o ilk işlemede başlar ve önceki dersin kuralı gereği uca kadar
sürer.

Bu, bir dosyayı tarihçeden çıkarma işini şu soruya indirger: o dosyaya **ilk** ne zaman
dokunulmuş. Yanıt genellikle hoş değildir. Bir depoda birkaç dosya varsa ve her işleme
onlardan birine dokunuyorsa, her dosyanın ilk görünüşü tarihçenin en başındadır. Ölçüm bunu
beş dosya ve bir ikili varlık için ayrı ayrı sorar.

Ölçümün varsayımları:

- **YZ9** — Kurgu önceki dersin kurgusudur ve değiştirilmez: dört ölçek (**50, 200, 1000,
  4000**), her işleme beş dosyadan birine dokunur, on birde biri bir ikili varlık taşır.
- **YZ10** — Toplu dönüşüm her işlemeye uygulanan bir kuraldır. Ölçüm kuralın **ne**
  yaptığını değil, kaç işlemeyi yeniden ürettiğini sayar; bu yüzden yazar düzeltmesiyle
  dosya çıkarma aynı sütunda durur.
- **YZ11** — Kimlik değişimi, kuralın içeriği gerçekten değiştirdiği ilk işlemede başlar ve
  tarihçenin ucuna kadar sürer.
- **YZ12** — Bir dosyayı çıkarmak, o dosyaya ilk dokunan işlemeden başlar; ikili varlık için
  başlangıç, ikili taşıyan ilk işlemedir.
- **YZ13** — Bu dersin bedel birimi **dokunulan nesnedir**. Kimliği değişen işleme sayısı
  kümenin genişliğidir; adım birimi bu derste kullanılmaz.
- **YZ14** — Paylaşılan önek, yeni tarihçenin eskisiyle ortak kalan işlemeleridir: başlanan
  konumdan bir öncesine kadar olan aralık.
- **YZ15** — Getirilecek nesne, karşı tarafın elinde bulunmayan nesnelerin sayısıdır; ortak
  önek dışındaki her nesne yeniden aktarılır. Bu bir ağ ölçümü değil, nesne sayımıdır.
- **YZ16** — Kümenin çözünürlüğü dört ölçekte **1/50, 1/200, 1/1000, 1/4000**'dir.

#### Ölçüm

```python
"""Toplu tarihce donusumu: ilk islemeden baslayan yeniden yazmanin bedeli.

Bolum 1 - dort olcekte ilk islemeden donusum.
Bolum 2 - hangi varlik cikarilirsa donusum nereden baslamak zorunda.
Bolum 3 - eski ve yeni tarihcenin paylastigi onek.
"""
TOHUM = 20260814
DOSYALAR = ("olcum.py", "rapor.py", "kimlik.py", "ayar.py", "belge.md")
IKILI_VARLIK = "sunum.bin"
OLCEKLER = (50, 200, 1000, 4000)


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):
    sonra = [x for x in t if x["no"] >= konum]
    return len(sonra), sum(x["nesne"] for x in sonra)


def ilk_dokunus(t, ad):
    """Cikarilacak varliga ilk dokunan isleme: donusum oradan baslar."""
    for x in t:
        if x["ikili"] if ad == IKILI_VARLIK else x["dosya"] == ad:
            return x["no"]
    return 0


print(f"{'işleme':>7s} {'kimliği değişen':>16s} {'dokunulan nesne':>16s}"
      f" {'oran':>6s} {'paylaşılan önek':>16s}")
for n in OLCEKLER:
    t = tarihce(n)
    isl, nes = yeniden_yaz(t, 1)
    print(f"{n:7d} {isl:16d} {nes:16d} {isl / n:6.3f}"
          f" {len(t) - isl:16d}")

print()
T = tarihce(1000)
print(f"{'çıkarılan varlık':<17s} {'ilk dokunuş':>12s} {'kimliği değişen':>16s}"
      f" {'dokunulan nesne':>16s} {'oran':>6s}")
for ad in DOSYALAR + (IKILI_VARLIK,):
    k = ilk_dokunus(T, ad)
    isl, nes = yeniden_yaz(T, k)
    print(f"{ad:<17s} {k:12d} {isl:16d} {nes:16d} {isl / len(T):6.3f}")

print()
print(f"{'başlanan konum':>15s} {'paylaşılan önek':>16s} {'ortak nesne':>12s}"
      f" {'getirilecek nesne':>18s}")
for konum in (1, 2, 9, 501):
    ortak = sum(x["nesne"] for x in T if x["no"] < konum)
    print(f"{konum:15d} {konum - 1:16d} {ortak:12d}"
          f" {sum(x['nesne'] for x in T) - ortak:18d}")
```

```
 işleme  kimliği değişen  dokunulan nesne   oran  paylaşılan önek
     50               50              380  1.000                0
    200              200              920  1.000                0
   1000             1000             5640  1.000                0
   4000             4000            22600  1.000                0

çıkarılan varlık   ilk dokunuş  kimliği değişen  dokunulan nesne   oran
olcum.py                     1             1000             5640  1.000
rapor.py                     8              993             5586  0.993
kimlik.py                    4              997             5634  0.997
ayar.py                      3              998             5636  0.998
belge.md                     2              999             5638  0.999
sunum.bin                    6              995             5630  0.995

 başlanan konum  paylaşılan önek  ortak nesne  getirilecek nesne
              1                0            0               5640
              2                1            2               5638
              9                8           56               5584
            501              500         2640               3000
```

#### Oran Bire Sabitlenir

Üst tablo dört ölçekte aynı işlemi yapıyor ve oran sütunu tek bir değer veriyor: **1,000**.
Bin işlemelik tarihçede **1000** kimlik değişiyor ve **5640** nesneye dokunuluyor. Önceki
dersin ortadan yeniden yazması aynı tarihçede 501 kimlik ve 3002 nesne demekti; ilk
işlemeden başlamak bu sayıyı yaklaşık ikiye katlıyor. Ama asıl fark sağdaki sütunda:
paylaşılan önek **0**. Ortadan yeniden yazmada eski ve yeni tarihçe ilk 500 işlemeyi
paylaşıyordu; burada tek bir ortak işleme kalmıyor.

Oranın sabitlenmesi ölçeğin önemsiz olduğu anlamına gelmez, tersini söyler. Oran sabit
olduğu için mutlak bedel tarihçeyle birlikte doğrusal büyür: dört bin işlemelik tarihçede
dokunulan nesne **22600**'dür ve bu, elli işlemeliğin altmış katıdır. Ölçüm bir süre
ölçmüyor, ama sayının pratik karşılığı bellidir — dönüşüm bir anlık iş değil, planlanması
gereken bir iştir.

Orta tablo başlangıç noktasının seçilebilir bir şey olmadığını gösteriyor. Beş dosyanın ve
ikili varlığın ilk dokunuşları **1, 8, 4, 3, 2** ve **6** numaralı işlemelerde. En geç
görüneni sekizinci işleme ve onu çıkarmak bile **993** işlemeyi yeniden yazdırıyor —
tarihçenin **0,993**'ü. Bu bir tesadüf değil, sayının doğrudan sonucudur: bir avuç dosyanın
paylaşıldığı bir depoda her dosya ilk birkaç işlemede görünür. **Toplu dönüşümde
"tarihçenin bir kısmı" diye bir seçenek yoktur;** seçenek tarihçenin tamamı ile tarihçenin
neredeyse tamamı arasındadır.

Alt tablo bedelin nereye düştüğünü söylüyor. Başlangıç konumu **1** olduğunda karşı tarafın
elindeki hiçbir nesne işe yaramaz: ortak nesne **0**, getirilecek nesne **5640**, yani
deponun tamamı. Konum **501** olsaydı ortak nesne **2640** olur ve aktarılacak miktar
**3000**'e inerdi. Aradaki fark yalnız nicelik değil, nitelik farkıdır: ortak bir ata
varken karşı taraf **getirme** yapabilir, yokken yapabileceği tek şey **klonlamaktır.**
Getirme işlemi elde olanın üzerine ekler; eklenecek bir taban kalmadığında getirme adı
üstünde bir getirme olmaktan çıkar.

#### Dönüşümün Değiştirmediği Şey

Sayılar yalnız bedeli veriyor; dönüşümün tarihçeye ne yaptığını vermiyor. O tarafta durum
şaşırtıcı biçimde sakindir. Kural yalnız üstveriye dokunuyorsa — yazar alanı gibi — her
işlemenin getirdiği değişiklik olduğu gibi kalır, sıra korunur, dalların yapısı korunur.
Önceki kursun ölçtüğü sorular aynı yanıtları alır; değişen yalnız o yanıtların bağlı olduğu
kimliklerdir. **Toplu dönüşüm çoğu durumda tarihçenin yanıtlarını değil, adreslerini
değiştirir.**

Bir durumda bu doğru değildir: kural bir varlığı çıkarıyorsa, o varlığa dokunan işlemelerin
getirdiği değişiklik de kaybolur. O dosyanın satır tarihçesi artık sorulamaz, ona dokunan
işlemeler artık ona dokunmuş görünmez. Kaybolan bilgi budur ve dönüşümün amacı da genellikle
tam olarak budur. Ayrımı yapmak gerekir: üstveri düzeltmesi bilgi silmez, varlık çıkarma
siler. İkisi aynı bedeli öder ve aynı ölçüde geri alınamazdır, ama tarihçenin okunabilirliği
bakımından aynı işlem değildirler.

#### Geri Alınamazlık ve Güvenli Yol

Toplu dönüşüm geri alınamaz bir işlemdir ve bunun iki ayrı nedeni vardır.

**Yerelde** eski zincir erişilemez kalır. Referans günlüğü bir süre onu gösterir, sonra çöp
toplama nesneleri temizler; kurtarma penceresi bu konunun dördüncü dersinde ölçülür. Bu ara
dönemin doğrudan bir sonucu vardır ve sık gözden kaçar: **dönüşümü yapmış olan depo, dönüşüm
biter bitmez temiz değildir.** Çıkarılmış varlığın nesneleri erişilemez durumda ama yerinde
durur; kimliğini bilen biri onları hâlâ okuyabilir. Temiz olan şey, o depodan alınan yeni bir
klondur — çünkü klonlama yalnız erişilebilir nesneleri aktarır. Bu, "ayrı klon üzerinde
çalış" alışkanlığının yalnız güvenlik değil, sonuç bakımından da doğru yol olmasının
nedenidir.

**Kopyalarda** kurtarma diye bir şey yoktur, çünkü kurtarılacak bir kayıp da yoktur: her
kopyanın elinde eski zincir olduğu gibi durur. Sorun budur. Eski zinciri elinde tutan bir
kopya yeni tarihçeyle birleştirilirse, çıkarılan varlık geri gelir ve dönüşüm boşa gider.
Bu yüzden **her kopya yeniden klonlanmak zorundadır** ve bu kural bir öneri değil, işlemin
tanımının parçasıdır. Kopyalarını değiştirmediğiniz sürece toplu dönüşüm tamamlanmamıştır.

Dönüşümün etkisi depo dışına da taşar. Eski kimlikler bir sorun izleme kaydında, bir yayım
notunda ya da bir yapı kaydında yazılıysa, o kimlikler artık hiçbir şeyi göstermez. Etiketler
eski işlemelere bağlıysa ayrıca ele alınmaları gerekir.

Güvenli yol dört maddedir. **Birincisi ayrı klondur:** dönüşüm asıl depoda değil, onun taze
bir kopyasında denenir ve asıl depo doğrulama bitene kadar el sürülmeden bekler.
**İkincisi doğrulamadır:** yeni tarihçede çıkarılmak istenen varlığın gerçekten kalmadığı ve
işleme sayısının beklenen sayı olduğu ölçülür. Doğrulama üç soruya yanıt arar — dönüşüm
sonrası işleme sayısı nedir, çıkarılan varlığın adı hiçbir işlemenin ağacında geçiyor mu ve
dönüşüme girmemiş bir başvuru kalmış mı. Üçü de okuma işlemleridir ve hiçbirinin yıkıcı
tarafı yoktur; ölçüm bunları saymayı zaten yapıyor, aynı sayım gerçek bir depoda da
yapılabilir. **Üçüncüsü eşgüdümdür:** kopyaların ne zaman
değiştirileceği önceden duyurulur, çünkü değişimi kaçıran bir kopya eski zinciri geri
getirebilir. **Dördüncüsü sızıntı kuralıdır:** tarihçeden çıkarılan bir gizli anahtar
çıkarılmakla geçersiz olmaz. Bir anahtar bir kez yazıldıysa yenilenmelidir; toplu dönüşüm
onun okunmasını zorlaştırır, olmamış hâle getirmez.

Eşgüdüm maddesi uygulamada bir sıraya dönüşür. Dönüşüm bir ana bağlanır: o ana kadar herkes
elindeki işi karşı tarafa yazar, o andan sonra kimse eski zincirden yeni iş türetmez, dönüşüm
uygulanır, kopyalar yenilenir ve ancak ondan sonra çalışmaya devam edilir. Sıranın hangi
adımı atlanırsa atlansın sonuç aynıdır: eski zincirden türetilmiş tek bir işleme yeni
tarihçeye girdiğinde dönüşüm bozulur ve baştan yapılması gerekir. Bu, toplu dönüşümü teknik
bir işlem olmaktan çıkarıp bir **takvim işi** hâline getirir; bedelin ölçülmeyen ama çoğu
zaman en büyük kalemi de budur.

#### Özet

- Toplu dönüşüm bir plan değil bir **kuraldır**: her işlemeye uygulanır ve her işlemeyi
  yeniden üretir. Aracın alt komutu ve depo dışı süzme araçları bu işi yapar; komut burada
  tam biçimde verilmez.
- Kimlik değişimi, kuralın içeriği değiştirdiği ilk işlemede başlar. Bir dosyayı çıkarmak
  için o dosyanın **ilk görünüşüne** kadar geri gidilir.
- İlk işlemeden dönüşüm dört ölçekte **380 / 920 / 5640 / 22600** nesneye dokunur ve oran
  her ölçekte **1,000**'dir; bin işlemelik tarihçede **1000** kimlik değişir.
- Beş dosyanın ve ikili varlığın ilk dokunuşları **1** ile **8** arasındadır; en geç
  görünen varlığı çıkarmak bile tarihçenin **0,993**'ünü yeniden yazdırır.
- Paylaşılan önek **0**'a indiğinde ortak ata kalmaz: karşı taraf getirme yapamaz, **5640**
  nesnenin tamamını yeniden klonlamak zorundadır.
- İşlem geri alınamaz. Güvenli yol ayrı klon, doğrulama, eşgüdüm ve sızan anahtarın
  yenilenmesidir.

#### Sonraki Adım

Bu derste bedel bir kez sayıldı ve tek bir depoda kaldı: bin kimlik, beş bin altı yüz kırk
nesne, sıfır ortak ata. Sayının eksik bıraktığı taraf şudur — yeniden yazılmış tarihçeyi
karşı tarafa yazmak, karşı taraftaki zinciri **ezmek** demektir ve bunu yapan kişi bedelin
kendi payına düşen kısmını ödemez. Sonraki ders bu ayrımı ölçer: bin işlemelik bir
tarihçede son işlemeyi düzeltmekle ilk işlemeyi düzeltmek arasında kimlik bakımından bin
kat fark varken, deponun kopyaları bakımından hiç fark olup olmadığı.

### Zorlayıcı İtme Disiplini

Source: https://academia.sh/tr/kurslar/ileri-git/zorlayici-itme-disiplini

Bin işlemelik bir tarihçede son işlemeyi değiştirmek 1, ilk işlemeyi değiştirmek 1000 kimlik değiştirir; ama iki durumda da yedi kopyanın yedisi yeniden eşitlemek zorundadır ve dayanaksız kalan yerel iş aynı kalır — bedel değişikliğin büyüklüğüyle değil kopya sayısıyla ölçeklenir.

Önceki derste bedel bir kez sayıldı ve tek bir depoda kaldı: bin kimlik, beş bin altı yüz
kırk nesne, sıfır ortak ata. Sayı, işlemin yerel yarısını anlatıyordu. Yeniden yazılmış bir
tarihçenin bir işe yaraması için karşı tarafa da yazılması gerekir — ve karşı taraf onu
olağan yolla kabul etmez.

Bu ders o reddin neden konduğunu, nasıl aşıldığını ve aşıldığında kimin ne kaybettiğini ele
alır. Bir yordam dersi değildir: aşağıda hiçbir zorlayıcı itme satırı çalıştırılabilir
biçimde yazılmaz. Ölçülen şey aracın nasıl çağrıldığı değil, çağrının **kimin üstünde**
bıraktığı bedeldir.

#### Reddin Nedeni

Getirme, çekme ve itme arasındaki ayrım önceki kursta kuruldu ve burada tekrarlanmaz. Bir
tanesi burada gerekli: itme, karşı taraftaki bir başvurunun gösterdiği yeri değiştirmeyi
ister. Karşı taraf bu isteği yalnız bir koşulda kabul eder — istenen yeni uç, o anki ucu
**içeriyorsa**. İçeriyorsa hiçbir şey kaybolmaz; karşı taraftaki her işleme yeni uçtan geriye
doğru yürünerek bulunabilir.

Yeniden yazma tam olarak bu koşulu bozar. Yeni zincir eski zincirin işlemelerini içermez,
onların yerine başka kimlikli işlemeler koyar. Karşı taraf isteği reddeder ve gerekçesini
söyler.

```text
# örnek döküm — çalıştırılmamıştır

$ git push kaynak olcum
 ! [rejected]        olcum -> olcum (non-fast-forward)
error: failed to push some refs to 'kaynak'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart.
```

Ret iletisi bir kusuru değil, bir kuralın işlediğini bildiriyor. Bu ret deponun tek yerleşik
korumasıdır. Karşı taraftaki başvurunun
gösterdiği zinciri **yalnız büyüterek** değiştirmeye izin verir; küçültmeye ya da başka bir
zincirle değiştirmeye izin vermez.

#### Reddi Aşmak

Aracın bu reddi devre dışı bırakan bir seçeneği vardır ve adı **zorlayıcı itmedir**.
Yaptığı iş tek cümleyle söylenebilir: karşı taraftaki başvuruyu, eski değerini hiç
sormadan yeni zincirin ucuna taşır. Eski zincir silinmez; onu gösteren başvuru kalmadığı
için erişilemez kalır ve karşı tarafın çöp toplama düzeni onu bir süre sonra temizler.

Bu satır burada tam biçimde yazılmaz. Nedeni, satırın kopyalanabilir olmasının kendisidir:
paylaşılan bir dalda çalıştırıldığında başkalarının işini o dalın kaydından siler ve
**işlem geri alınamaz** — geri alınabilirliği yalnız başkalarının elindeki kopyalar sağlar,
ki bunun ne demek olduğu dersin sonunda ayrıca yazılır.

Aynı ailenin ikinci bir seçeneği, karşı taraftaki başvurunun **beklenen değerini** de
isteğe ekler: uç beklenen yerdeyse yazar, değilse reddeder. Bu seçenek zorlayıcı itmeyi
güvenli hâle getirmez; yalnız **görmediğiniz** bir işi ezmenizi engeller. Gördüğünüz ve
yine de ezdiğiniz iş için hiçbir koruma yoktur.

#### Bedeli Kim Öder

Yeniden yazmanın bedeli iki ayrı kalemde durur. Birincisi yazanın kalemidir: yeniden
yazılan zincirin nesneleri bir kez üretilir. İkincisi kopyaların kalemidir: aynı zinciri
her kopya yeniden almak zorundadır. Ölçüm ikisini yan yana koyar ve değiştirilen işlemenin
yerini dört kez değiştirir.

Ölçümün varsayımları:

- **YZ17** — Kurgu önceki derslerin kurgusudur ve değiştirilmez; ölçüm **1000** işlemelik
  tarihçe üzerinde yapılır.
- **YZ18** — Depo **yedi** kopyada yaşıyor. Kopya sayısı ölçümün girdisidir ve yeniden
  yazmayı yapan kişinin seçimi değildir.
- **YZ19** — Dal ucunun kimliği değiştiği anda her kopya yeniden eşitlemek zorundadır.
  Ölçüm eşitlemek **zorunda olan** kopyayı sayar; eşitleyip eşitlemedikleri ölçümün dışıdır.
- **YZ20** — Yazanın bedeli yeniden yazdığı zincirin nesne sayısıdır; kopyaların bedeli aynı
  sayının kopya adedi kadar katıdır. Birim **dokunulan nesnedir**.
- **YZ21** — Her kopyanın eski ucun üzerine yazdığı bir miktar yerel iş vardır (kurgudan
  gelir, sıfır ile üç işleme arası) ve bu iş henüz karşı tarafa yazılmamıştır.
- **YZ22** — Zorlayıcı itmeden sonra bu yerel işin dayanağı ortadan kalkar. Dayanaksız kalan
  iş, değiştirilen işlemenin **yerinden bağımsızdır**: uç değiştiği anda her yerel zincir
  dayanağını yitirir.
- **YZ23** — Kimlik ve kopya sayıları bir bedel değil, kümenin genişliğidir; bedel yalnız
  nesne sütununda okunur.
- **YZ24** — Çözünürlük işlemede **1/1000**, kopyada **1/7**'dir.

#### Ölçüm

```python
"""Zorlayici itme: yeniden yazmanin bedelini yazan odemez.

Bolum 1 - dort konum: kimligi degisen, yazanin ve kopyalarin dokundugu nesne.
Bolum 2 - kopyalarin eski ucun uzerine yazdigi yerel is.
Bolum 3 - paylasim durumu: tek guvenli kosul hangisi.
"""
TOHUM = 20260814
DOSYALAR = ("olcum.py", "rapor.py", "kimlik.py", "ayar.py", "belge.md")
KOPYA = 7


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):
    sonra = [x for x in t if x["no"] >= konum]
    return len(sonra), sum(x["nesne"] for x in sonra)


def yeniden_esitleyen(kopya_sayisi, konum, t):
    """Yeniden yazilan tarihceyi kimler yeniden esitlemek zorunda."""
    degisen, _ = yeniden_yaz(t, konum)
    return kopya_sayisi if degisen else 0


def kopyalar(sayi=KOPYA, tohum=TOHUM):
    """Her kopyanin eski ucun uzerine yazdigi yerel isleme sayisi."""
    r = uretec(tohum)
    return [{"no": i + 1, "yerel": r(4)} for i in range(sayi)]


T = tarihce(1000)
K = kopyalar()

print(f"{'değiştirilen yer':>17s} {'kimliği değişen':>16s}"
      f" {'yazanın nesnesi':>16s} {'eşitleyen kopya':>16s}"
      f" {'kopyaların nesnesi':>19s}")
for konum in (1000, 900, 500, 1):
    isl, nes = yeniden_yaz(T, konum)
    k = yeniden_esitleyen(KOPYA, konum, T)
    print(f"{konum:17d} {isl:16d} {nes:16d} {k:16d} {k * nes:19d}")

print()
print("kopyaların eski uç üzerine yazdığı yerel işleme:",
      [x["yerel"] for x in K], "toplam", sum(x["yerel"] for x in K))
print()
print(f"{'paylaşım durumu':<16s} {'kopya':>6s} {'eşitleyen':>10s}"
      f" {'dayanaksız (son işleme)':>24s} {'dayanaksız (ilk işleme)':>24s}")
for ad, sayi in (("paylaşılmamış", 0), ("üç kopya", 3), ("yedi kopya", 7)):
    dayanaksiz = sum(x["yerel"] for x in K[:sayi])
    print(f"{ad:<16s} {sayi:6d} {yeniden_esitleyen(sayi, 1000, T):10d}"
          f" {dayanaksiz:24d} {dayanaksiz:24d}")
```

```
 değiştirilen yer  kimliği değişen  yazanın nesnesi  eşitleyen kopya  kopyaların nesnesi
             1000                1                2                7                  14
              900              101              602                7                4214
              500              501             3002                7               21014
                1             1000             5640                7               39480

kopyaların eski uç üzerine yazdığı yerel işleme: [0, 0, 3, 2, 2, 2, 0] toplam 9

paylaşım durumu   kopya  eşitleyen  dayanaksız (son işleme)  dayanaksız (ilk işleme)
paylaşılmamış         0          0                        0                        0
üç kopya              3          3                        3                        3
yedi kopya            7          7                        9                        9
```

#### Bin Kat Fark, Sıfır Kat Fark

Üst tablonun sol yarısı beklenen şeyi veriyor. Son işlemeyi değiştirmek **1** kimlik
değiştiriyor ve yazana **2** nesneye mal oluyor; ilk işlemeyi değiştirmek **1000** kimlik
değiştiriyor ve **5640** nesne demek. Aradaki fark bin kat. Bir yazım hatasını düzeltmekle
deponun tamamını dönüştürmek arasında, yazanın gördüğü bedel bakımından, uçurum var.

Sağ yarı bu uçurumu görmüyor. **Eşitlemek zorunda olan kopya sayısı dört satırda da 7.**
Yedi kopyanın yedisi, ne kadar küçük bir değişiklik olursa olsun, dal ucunun yeni kimliğini
almak ve kendi durumunu ona göre düzeltmek zorunda. Fark bin kat değil, **sıfır kat**. Yazanın gördüğü uçurum, kopyaların gördüğü tabloda hiç
yoktur.

Kopyaların nesne sütunu bunun mutlak karşılığını veriyor: son işlemeyi değiştirmenin
karşılığı **14** nesne, ilk işlemeyi değiştirmenin karşılığı **39480**. İki sayı da yazanın
sütunundakinin **yedi katı** — ve yedi, yazanın belirlediği bir sayı değil. Kursun üçüncü
iddiası buradadır: **bedel değişikliğin büyüklüğüyle değil, kopya sayısıyla ölçeklenir ve o
sayı yeniden yazmayı yapanın elinde değildir.** Yeniden yazan kişi kendi kaleminde en ucuz
satırı seçebilir; kopyaların kalemi seçime bağlı değildir.

Alt tablo bunu en sert biçimde söylüyor. Kopyaların eski uç üzerine yazdığı yerel iş toplam
**9** işleme — yedi kopyanın üçünün elinde hiç yerel iş yok, dördünün elinde var. Zorlayıcı
itmeden sonra dayanaksız kalan iş **9** ve bu sayı iki sütunda da aynı: **son** işlemeyi
değiştirseniz de **ilk** işlemeyi değiştirseniz de dokuz işleme dayanağını yitiriyor. Uç
değişti mi değişmedi mi — sorunun tamamı bu; ne kadar değiştiği kimseyi ilgilendirmiyor.

Tabloda tek bir güvenli satır var: **paylaşılmamış**. Kopya sayısı sıfır olduğunda eşitleyen
sıfır, dayanaksız kalan sıfır. Ölçümün ürettiği ölçüt budur ve tek ölçüt budur.

Ara satırlar bir ayrıntıyı da gösteriyor. Dokuz yüzüncü işlemeden yeniden yazmak **101**
kimlik değiştiriyor ama **602** nesneye dokunuyor; iki yüz iki değil. Fark, o aralığa düşen
ikili varlıklardan geliyor — kimlik saymakla nesne saymak aynı sonucu vermiyor ve bu dersin
birimi nesne. Kopyaların sütunu da bu yüzden kimlik sayısını değil nesne sayısını yediyle
çarpıyor.

#### Kopya Ne Yapmak Zorunda

"Yeniden eşitlemek" tek bir işlem değil, bir karardır ve kararı kopyanın sahibi verir. İki
yol vardır ve ikisi de bedelsiz değildir.

**Birinci yol**, yerel dalı yeni uca sıfırlamaktır. Yerel iş varsa bu yol onu bırakır;
işlemeler erişilemez kalır ve ancak o kopyanın kendi referans günlüğünden bulunur. Yerel iş
yoksa yol temizdir ve ölçümdeki üç kopya için durum budur.

**İkinci yol**, yerel işi yeni zincirin üstüne yeniden temellendirmektir. Hiçbir şey
kaybolmaz, ama yerel işlemeler de yeni kimlik alır ve bu kursun ilk dersindeki bedel bu kez
kopyanın kaleminde yazılır. Dört kopya için ödenen budur: dokuz işlemenin dokuzu yeniden
yazılır.

Üçüncü bir yol, en azından bedelsiz bir üçüncü yol, yoktur. Yerel işi olduğu gibi karşı tarafa yazmayı denemek, aynı reddi bu kez
kopyanın karşısına çıkarır — ve o noktada kopyanın sahibi de zorlayıcı itme düğmesine
bakıyor olur. Bir zorlayıcı itmenin ikincisini davet etmesi, dersin başlığındaki disiplinin
neden bir kişinin değil ekibin disiplini olduğunu gösterir.

#### Kimin Haberi Olmadan

İşlemin en can sıkıcı yanı sayılarda görünmez. Zorlayıcı itme **tarihçeye yazılmaz.** Yeni
tarihçede, birinin bir şeyi ezdiğini söyleyen hiçbir işleme, hiçbir alan yoktur. Önceki
kursun altıncı sorusu çakışma kararının kayda geçmediğini gösteriyordu; burada kayda
geçmeyen şey, kaydın kendisinin değiştirilmiş olmasıdır.

Kopyalar da anında öğrenmez. Bir kopya karşı tarafa bakmadığı sürece elindeki eski zinciri
geçerli sanmaya devam eder, üstüne işleme yazar ve dayanaksız işini büyütür. Öğrenme anı bir
sonraki getirmedir. O ana kadar geçen sürede yapılan her yeni işleme, ezilmiş bir uca eklenen
bir işlemedir.

Öğrenme anının kendisi de yanıltıcı olabilir. Getirmenin ardından çekme çağrılırsa araç iki
zinciri birleştirmeyi dener ve genellikle başarır: eski zincir ile yeni zincir aynı
değişiklikleri taşıdığı için birleşme sessizce tamamlanır. Sonuç, aynı değişikliklerin iki
ayrı kimlikle iki kez bulunduğu bir tarihçedir. Bunu fark etmenin tek yolu tarihçeye
bakmaktır; hiçbir uyarı çıkmaz. Ezilen dalın yeniden ezilmesi de çoğu kez böyle başlar —
kopyalardan biri eski zinciri geri getirir, yeniden yazan kişi bunu görür ve işlemi
tekrarlar.

Bu üç gerçek birlikte, işlemi bir araç sorunu olmaktan çıkarıp bir **bildirim sorunu**
hâline getirir. Araç kimseyi uyarmaz, tarihçe kimseye söylemez; söyleyecek olan yeniden
yazmayı yapan kişidir. Duyurunun içeriği de bellidir: hangi dal, hangi an ve kopyaların
hangi yolu izlemesi bekleniyor.

#### Disiplin

Ölçütler ölçümden çıkar ve dördü de kısa yazılabilir.

**Birincisi:** zorlayıcı itme yalnız **paylaşılmamış** dallarda uygulanır. Bir dalın
paylaşılmamış olması, "kimse ondan çalışmıyor" varsayımı değil, kontrol edilebilir bir
durumdur.

**İkincisi:** ana dal, yayım dalı ve etiketlerin gösterdiği zincirler yeniden yazılmaz.
Bir değişikliği geri almak gerektiğinde yol yeniden yazmak değil, tersini yapan yeni bir
işleme yazmaktır — bu yol Sürüm Kontrolüne Giriş kursunda devirme adıyla kuruldu ve
tarihçeyi hiç değiştirmediği için hiçbir kopyayı ilgilendirmez.

**Üçüncüsü:** paylaşılan bir inceleme dalının yeniden yazılması gerekiyorsa işlem önceden
duyurulur, sonrasında da duyurulur. Beklenen değeri isteğe ekleyen seçenek kullanılır;
o seçenek görülmemiş işi korur, görülmüş işi korumaz.

**Dördüncüsü:** koruma araca değil, karşı tarafa konur. Depo sunucusunda dal koruma
yetenekleri bulunur ve ileri sarma dışındaki güncellemeleri reddedecek biçimde
ayarlanabilir. Bir kuralın araç tarafında değil sunucu tarafında durması, onu unutulabilir
olmaktan çıkarır.

Dört ölçütün pratikte hangi noktada çöktüğü de söylenmelidir. Çoğu zaman kural bilinir ve
uygulanır; kaza, bir dalın **paylaşılmamış sanılmasından** doğar. Bir dalın adı kişiseldir,
kimsenin ondan çalışmadığı varsayılır, oysa biri onu bir inceleme sırasında getirmiştir.
Varsayımı sınamanın yolu karşı tarafa bakmaktır, kendi belleğine değil; dalın karşı taraftaki
durumu getirilirse varsayım bir ölçüme dönüşür.

Her kayıp yolunun bir kurtarma yolu vardır ve burada üçü sayılabilir. Karşı taraftaki eski
zincir başvurusuz kaldığında kurtarma **kopyalardadır**: eski ucu hâlâ gösteren bir kopya
onu yeni bir dal olarak geri yazabilir; ezilen tarafın yedeği, bedeli ödeyen taraftır. Bir
kopyanın dayanaksız kalan yerel işi, o kopyanın kendi referans günlüğünden bulunup yeni
zincirin üstüne taşınabilir. Yeniden yazmayı yapan kişinin kaybettiği eski uç, yedek dal ya
da yerel referans günlüğünden okunur. Üç yolun ikisi aynı düzeneğe dayanıyor ve o düzeneğin
bir ömrü var.

#### Özet

- Olağan itme yalnız karşı taraftaki ucu **içeren** bir zinciri kabul eder; yeniden yazma bu
  koşulu bozduğu için reddedilir ve ret deponun tek yerleşik korumasıdır.
- Zorlayıcı itme reddi kaldırır: başvuruyu eski değerini sormadan taşır. Satır burada tam
  biçimde yazılmaz; paylaşılan bir dalda geri alınamaz.
- Bin işlemelik tarihçede son işlemeyi değiştirmek **1** kimlik ve **2** nesne, ilk işlemeyi
  değiştirmek **1000** kimlik ve **5640** nesne demektir — ama **yedi kopyanın yedisi** dört
  durumda da yeniden eşitlemek zorundadır.
- Kopyaların ödediği **14** ile **39480** nesne arasında değişir ve her zaman yazanın
  ödediğinin **yedi katıdır**; dayanaksız kalan **9** işleme ise değiştirilen yerden
  bağımsızdır. **Bedeli yazan ödemez.**
- Ölçümün verdiği tek güvenli satır **paylaşılmamış** dallardır: sıfır kopya, sıfır
  dayanaksız iş.
- İşlem tarihçeye yazılmaz ve kopyalar bir sonraki getirmeye kadar öğrenmez; bildirim
  aracın değil, yeniden yazan kişinin işidir.

#### Sonraki Adım

Bu dersin kurtarma yollarından ikisi aynı yere bakıyordu: dal ucunun eski değerini tutan
yerel kayda. O kayıt sınırsız değildir. Yeniden yazılmış bir tarihçede eski zincirin
işlemeleri erişilemez durumda durur, bir süre kurtarılabilir kalır, sonra temizlenir.
Sonraki ders o pencereyi ölçer: yeniden yazmadan sonra kaç işleme erişilebilir kalır, kaçı
yalnız kayıttan bulunabilir ve kurtarma penceresi hangi anda kapanır.

### Referans Günlüğü

Source: https://academia.sh/tr/kurslar/ileri-git/referans-gunlugu

Yeniden yazma tarihçeyi kısaltmaz, ikiye katlar: bin işlemelik depoda ilk işlemeden dönüşümden sonra 1000 işleme erişilebilir, 1000 işleme erişilemez durumda durur; altı kayıtlık bir günlükte saklama ufku 7, 30, 60 ve 90 gün olduğunda kurtarılabilen işleme 3, 50, 500 ve 1000'dir.

Önceki dersin kurtarma yollarından ikisi aynı yere bakıyordu: dal ucunun eski değerini tutan
yerel kayda. Ezilmiş bir dalın geri getirilmesi de, dayanaksız kalan yerel işin
kurtarılması da o kayıttan başlıyordu. Ders orada bir uyarıyla bitti — o kaydın bir ömrü
var.

Bu ders o ömrü ölçer. İki soru sorulur ve ikisi ayrıdır. Birincisi: bir yeniden yazmadan
sonra deponun içinde ne kalıyor, kaç işleme erişilebilir durumda ve kaçı değil. İkincisi:
erişilemez kalanlar ne kadar süreyle kurtarılabilir, pencere hangi anda kapanıyor ve
kapandığında ne kayboluyor.

#### Erişilemez Olmak, Yok Olmak Değildir

Bu kursun ilk dersinde yeniden yazmanın bir silme değil bir çoğaltma olduğu söylenmişti.
Ölçüm o cümleyi sayıya çevirir. Bin işlemelik bir tarihçe yeniden yazıldığında yeni zincir
de bin işlemedir; eski zincirin işlemeleri hiçbir yere gitmez. Depoda artık iki zincir
vardır: biri dal ucundan erişilebilen, öbürü hiçbir başvurunun göstermediği.

Bir nesnenin **erişilebilir** olması, bir daldan, bir etiketten ya da `HEAD`'den başlayarak
öncül bağlantıları izlenerek bulunabilmesi demektir. Erişilemez nesne bu yürüyüşle bulunamaz;
ama diskte durur, kimliği verilirse okunur ve **çöp toplama** çalışana kadar da orada kalır.
Yeniden yazma bittiğinde depo küçülmez, büyür.

#### Günlük İşleme Değil, Hareket Tutar

Erişilemez zinciri kurtarmanın yolu eski ucun kimliğini bilmektir. Araç bunu kendiliğinden
kaydeder: her başvurunun her hareketi yerel bir günlüğe yazılır. **Referans günlüğü
(reflog)** budur.

Kaydın birimi bu dersin en önemli ayrımıdır. Günlük **işlemeleri** değil, **hareketleri**
tutar. Beş yüz işlemeyi erişilemez bırakan bir yeniden yazma günlüğe beş yüz satır yazmaz;
bir satır yazar. O satır o andaki ucu gösterir, uçtan geriye yürünerek beş yüz işlemenin
hepsine ulaşılır. Kayıt sayısıyla kurtarılabilir işleme sayısı bu yüzden aynı şey değildir.

Günlüğün üç sınırı vardır. **Yereldir:** karşı tarafa gitmez, klonlanmaz, bir kopyanın
günlüğü öbür kopyayı kurtarmaz. **Başvuru başınadır:** her dalın kendi günlüğü vardır,
ayrıca `HEAD`'in genel bir günlüğü tutulur. **Süresizdir sanılır ama değildir:** kayıtlar bir
saklama ufkuna göre temizlenir ve o ufuk bir ayardır.

```text
# öğretilen komut, örnek döküm — çalıştırılmamıştır

$ git reflog olcum
5b6c7d8 olcum@{0}: rebase (finish): refs/heads/olcum onto 9c4d7e1
2f8a1c3 olcum@{1}: commit: olcum: eşik değerini yazdır
7e1b4d2 olcum@{2}: commit: olcum: ayar dosyasını böl

$ git branch kurtarma/olcum olcum@{1}
```

İkinci satır kurtarmanın tamamıdır: eski uca bir dal adı verilir ve o zincir yeniden
erişilebilir olur. İşlem hiçbir şeyi silmez, hiçbir başvuruyu taşımaz; bu yüzden burada tam
biçimde yazılabilir. Kurtarma yolları yıkıcı değildir — yıkıcı olan, onları gerektiren
işlemdir.

Günlüğün gösteremediği bir durum için ikinci bir araç vardır: deponun bütünlüğünü denetleyen
alt komut, hiçbir başvurunun göstermediği nesneleri **sarkık** olarak listeler. Kayıt
temizlenmiş ama çöp toplama henüz çalışmamışsa kurtarma oradan yapılır. O da bir okuma
işlemidir.

Üçüncü sınırın pratikte en sık ödettiği durum şudur: **dal silindiğinde onun günlüğü de
silinir.** Yanlışlıkla silinmiş bir dalın kendi kaydına bakmak artık olanaksızdır. Bu
durumda çare `HEAD`'in günlüğüdür — çalışma alanının hangi uçlarda durduğu orada ayrıca
tutulur ve silinen dalın son ucu genellikle o listede görünür. İki günlüğün ayrı tutulması
bir ayrıntı değil, kurtarmanın kalan tek yolu olabilir.

Nesnelerin ne zaman gerçekten temizlendiği de yazılmalıdır. **Çöp toplama** kendiliğinden
çalışır; bakım işlemleri sırasında tetiklenir ve elle de çağrılabilir. Ama erişilemez bir
nesnenin temizlenmesi için iki koşulun birden sağlanması gerekir: onu gösteren günlük kaydı
ufkun dışına düşmüş olmalı **ve** toplama çalışmış olmalıdır. İki koşul da sağlanana kadar
nesne yerinde durur. Ufkun kendisi de tek bir sayı değildir: erişilebilir uçların kayıtları
ile erişilemez uçların kayıtları ayrı ayrı ayarlanabilir ve ikincisi genellikle daha kısa
tutulur.

Ölçümün varsayımları:

- **YZ25** — Kurgu önceki derslerin kurgusudur ve değiştirilmez; ölçüm **1000** işlemelik
  tarihçe üzerinde yapılır.
- **YZ26** — Yeniden yazma tarihçeyi kısaltmaz: yeni zincir aynı uzunluktadır ve eski
  zincirin işlemeleri depoda erişilemez durumda kalır.
- **YZ27** — Referans günlüğü dal ucunun hareketlerini kaydeder, işlemeleri değil. Bir kayıt
  o andaki ucu tutar; o uçtan geriye erişilen bütün zinciri temsil eder.
- **YZ28** — Kayıtların gösterdiği eski uçlar iç içe geçmiş soneklerdir; kurtarılabilir
  kümeyi **en geriye giden** kayıt belirler, kayıtların toplamı değil.
- **YZ29** — Saklama ufku bir ayardır, sabit bir sayı değildir. Ölçüm dört değer dener:
  **7, 30, 60, 90** gün.
- **YZ30** — Ufkun dışında kalan kayıt silinir ve yalnız o kayıttan erişilen işlemeler
  toplanabilir hâle gelir. Ölçüm çöp toplamanın ne zaman çalıştığını değil, hangi kümenin
  **toplanabilir** olduğunu sayar.
- **YZ31** — Bu derste iki ayrı şey sayılır ve karıştırılmaz: **erişilebilirlik** işleme
  sayısıyla, **bedel** dokunulan nesneyle sayılır. Adım birimi kullanılmaz.
- **YZ32** — Çözünürlük işlemede **1/1000**, günlük kaydında **1/6**'dır.

#### Ölçüm

```python
"""Referans gunlugu: erisilebilirlik ve kurtarma penceresi.

Bolum 1 - yeniden yazmadan sonra depoda ne kaliyor.
Bolum 2 - gunluk kayitlari: kayit sayisi ile kurtarilabilir isleme ayri sey.
Bolum 3 - saklama ufku pencereyi ne zaman kapatiyor.
"""
TOHUM = 20260814
DOSYALAR = ("olcum.py", "rapor.py", "kimlik.py", "ayar.py", "belge.md")
KONUMLAR = (1, 300, 501, 800, 951, 998)
UFUKLAR = (7, 30, 60, 90)


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):
    sonra = [x for x in t if x["no"] >= konum]
    return len(sonra), sum(x["nesne"] for x in sonra)


def gunluk(tohum=TOHUM):
    """Dal ucunun her hareketi bir kayit yazar; kayit gunu ve ucu tutar."""
    r, kayit, gun = uretec(tohum), [], 0
    for i, konum in enumerate(KONUMLAR):
        gun += 1 + r(30)
        kayit.append({"no": i + 1, "gun": gun, "konum": konum})
    return kayit


def kurtarilabilir(t, kayitlar):
    """Kayitlarin gosterdigi uclarin birlesimi: en geriye giden belirler."""
    if not kayitlar:
        return 0, 0
    return yeniden_yaz(t, min(k["konum"] for k in kayitlar))


T = tarihce(1000)
G = gunluk()
BUGUN = G[-1]["gun"]

print(f"{'yeniden yazılan yer':>20s} {'erişilebilir':>13s} {'erişilemez':>11s}"
      f" {'depodaki toplam':>16s} {'erişilemez nesne':>17s}")
for konum in (998, 501, 300, 1):
    isl, nes = yeniden_yaz(T, konum)
    print(f"{konum:20d} {len(T):13d} {isl:11d} {len(T) + isl:16d} {nes:17d}")

print()
print(f"{'kayıt':>6s} {'gün':>5s} {'eski ucun konumu':>17s}"
      f" {'o kayıttan erişilen':>20s}")
for k in G:
    isl, _ = yeniden_yaz(T, k["konum"])
    print(f"{k['no']:6d} {k['gun']:5d} {k['konum']:17d} {isl:20d}")
print(f"kayıt sayısı {len(G)}, bugün {BUGUN}. gün")

print()
print(f"{'saklama ufku':>13s} {'kalan kayıt':>12s} {'kurtarılabilir işleme':>22s}"
      f" {'kurtarılabilir nesne':>21s} {'kalıcı kayıp':>13s}")
tum_isl, _ = kurtarilabilir(T, G)
for ufuk in UFUKLAR:
    kalan = [k for k in G if BUGUN - k["gun"] <= ufuk]
    isl, nes = kurtarilabilir(T, kalan)
    print(f"{ufuk:13d} {len(kalan):12d} {isl:22d} {nes:21d}"
          f" {tum_isl - isl:13d}")
```

```
 yeniden yazılan yer  erişilebilir  erişilemez  depodaki toplam  erişilemez nesne
                 998          1000           3             1003                 6
                 501          1000         500             1500              3000
                 300          1000         701             1701              4162
                   1          1000        1000             2000              5640

 kayıt   gün  eski ucun konumu  o kayıttan erişilen
     1    11                 1                 1000
     2    20               300                  701
     3    40               501                  500
     4    49               800                  201
     5    58               951                   50
     6    81               998                    3
kayıt sayısı 6, bugün 81. gün

 saklama ufku  kalan kayıt  kurtarılabilir işleme  kurtarılabilir nesne  kalıcı kayıp
            7            1                      3                     6           997
           30            2                     50                   260           950
           60            4                    500                  3000           500
           90            6                   1000                  5640             0
```

#### Depo Küçülmez

Üst tablonun ikinci sütunu dört satırda da aynı: **1000**. Yeniden yazma nereden başlarsa
başlasın, dal ucundan erişilen tarihçe bin işlemedir. Üçüncü sütun değişkendir: erişilemez
kalan **3**, **500**, **701** ve **1000**. Dördüncü sütun ikisinin toplamıdır ve dersin
başlığını taşır — ilk işlemeden dönüşümden sonra depoda **2000** işleme durur, yarısı
erişilebilir, yarısı değil.

Bu, önceki dersteki toplu dönüşümün neden hemen bir kazanç getirmediğini açıklıyor. Bir
ikili varlığı tarihçeden çıkarmak deponun boyutunu düşürmez; yalnız o varlığın nesnelerini
erişilemez kümeye taşır. Erişilemez nesne sütunu ilk işlemeden dönüşümde **5640**'tır ve bu
sayı ancak çöp toplama çalıştığında serbest kalır. Kazanç ile işlem arasında bir gecikme
vardır ve o gecikme aynı zamanda **kurtarma penceresidir.** İkisi aynı şeydir: nesneleri
tutan süre, hatayı geri alma süresidir.

#### Kayıt Sayısı ile Kurtarılabilir İşleme

Orta tablo günlüğün altı kaydını gösteriyor. Bir kayıt üç işleme kurtarıyor, bir kayıt bin
işleme. **6** kayıtlık bir günlük **1000** işlemeyi kurtarabiliyor; oran kayıt başına yüz
altmış yedi işleme. Bu, günlüğün ucuz bir düzenek olmasının nedeni: uçları saklıyor,
zincirleri değil.

Kayıtların okunmasında ikinci bir bilgi daha var. Her satır hareketin **türünü** de yazar:
bir işleme yazıldığında, bir yeniden temellendirme bittiğinde, bir dal ucu sıfırlandığında
kayıt bunu ayrı ayrı bildirir. Kurtarılacak ucu ararken bakılacak yer bu alandır — aranan
genellikle yeniden yazmayı bildiren satırın bir öncesindeki uçtur. Günlüğün kimliği ve türü
birlikte tutması, doğru kaydı bulmayı bir tahmin işi olmaktan çıkarır.

Aynı yapı bir tuzağı da doğuruyor. Kayıtların kapsadığı kümeler iç içe geçmiş sonekler
olduğu için, kurtarılabilir kümeyi kayıtların **sayısı** değil, aralarında **en geriye
gideni** belirliyor. Beş kayıt kalsa bile en derin kayıt gitmişse, kurtarılabilir küme o beş
kaydın en derinine kadar iner. Günlükte çok satır görmek, kurtarma kapsamı hakkında hiçbir
şey söylemez.

#### Pencere Kapanırken

Alt tablo pencerenin nasıl kapandığını gösteriyor. Saklama ufku **90** gün olduğunda altı
kaydın altısı duruyor, **1000** işlemenin hepsi kurtarılabilir ve kalıcı kayıp **0**.
Ufuk **60** güne indiğinde dört kayıt kalıyor ve kurtarılabilir işleme **500**'e düşüyor:
tarihçenin yarısı artık günlükten bulunamaz. **30** günde iki kayıt ve **50** işleme kalıyor.
**7** günde geriye tek bir kayıt kalıyor, kurtarılabilir işleme **3**, kalıcı kayıp **997**.

Sayıların ayrık atlaması ufkun değil, kayıtların dağılımının sonucudur: onbirinci gündeki
derin kayıt ufuk altmışın dışında kalır kalmaz beş yüz işleme bir anda erişilmez olur.
Pencere düzgün kapanmaz, **basamak basamak** kapanır. Bu yüzden "günlükte bir hafta daha
var" cümlesi bir güvence değildir; hangi kaydın hangi gün düştüğü bilinmeden ne kadarının
kurtarılabildiği bilinemez. Basamakların yeri de rastgeledir: kayıtların günleri çalışma
düzeninden gelir, kapsadıkları derinlik ise o gün hangi işin yapıldığından. İkisi arasında
bir bağ yoktur, bu yüzden en derin kaydın en eski kayıt olması sık rastlanan ama garanti
edilmeyen bir durumdur.

Ufkun kendisi bir ayardır ve depodan depoya değişir. Ölçümün söylediği şey belirli bir
sayıyı savunmak değil, **ufkun kurtarma kapsamını doğrudan belirlediğidir.** Uzun ufuk daha
çok kurtarma, daha çok tutulan nesne demektir; kısa ufuk tersini. İki yönlü bir ödünleşimdir
ve iki yönü de bu tabloda görünür: kurtarılabilir nesne sütunu **6**'dan **5640**'a çıkarken
serbest bırakılabilecek nesne de aynı ölçüde azalır.

#### Kayıp Yolları ve Kurtarma Yolları

Bu konuda sayılan her kayıp yolunun bir kurtarma yolu vardır ve dördü birlikte yazılabilir.

**Yeniden yazılmış zincirin eski hâli** kaybolduğunda kurtarma günlüktedir: eski uca bir dal
adı verilir. Pencere kapalıysa sarkık nesne listesi ikinci yoldur.

**Toplu dönüşümde çıkarılan varlık** yanlışlıkla çıkarıldıysa kurtarma yine günlüktedir —
ama yalnız dönüşümü yapan depoda. Ayrı klon alışkanlığı burada kendini öder: asıl depo el
sürülmemiş durursa kurtarma diye bir soru doğmaz.

**Ezilmiş uzak dal** için kurtarma yerel günlükte değil, **kopyalardadır**. Ezilen tarafın
yedeği bedeli ödeyen taraftır ve o yedeğin bir saklama ufku yoktur; kopya eski ucu
gösterdiği sürece kurtarma açıktır.

**Ufkun dışına düşmüş kayıt** için kurtarma yolu yoktur. Tek çare önlemdir ve önlem
yeniden yazmadan önce açılan yedek daldır: yedek dal bir başvurudur, başvurular ufka tabi
değildir ve silinene kadar erişilebilirliği ayakta tutar.

Dört yolun ortak bir özelliği var ve dersin sonucu da bu: **kurtarma her zaman nesneleri
elinde tutan tarafta yapılır.** Merkezî bir kurtarma yeri yoktur. Kendi günlüğünüz yalnız
kendi deponuzu kurtarır; bir kopyanın kaybettiği işi sizin günlüğünüz göstermez, sizin
ezdiğiniz dalı sizin günlüğünüz geri getirmez. Bu, önceki dersteki bedel dağılımının
aynadaki görüntüsüdür — bedel kopyalara dağılıyordu, kurtarma yeteneği de kopyalara
dağılmıştır.

Buradan tek satırlık bir alışkanlık çıkar: **yeniden yazmadan önce ucun nerede olduğu
kaydedilir.** Yedek dal bunu yapmanın en ucuz yoludur ve maliyeti önceki kursun ölçtüğü
kadardır — tek bir başvuru. Pencerenin ne kadar açık kalacağını sormak yerine pencereye hiç
ihtiyaç duymamak, sayılan bütün yolların en kısası.

#### Özet

- Yeniden yazma tarihçeyi kısaltmaz. Dört konumda da erişilebilir işleme **1000** kalır;
  erişilemez kalan **3 / 500 / 701 / 1000** olur ve depodaki toplam **2000**'e kadar çıkar.
- Erişilemez nesneler çöp toplama çalışana kadar diskte durur; ilk işlemeden dönüşümde
  serbest kalmayı bekleyen **5640** nesne vardır. Kazancın gecikmesi ile kurtarma penceresi
  aynı süredir.
- Referans günlüğü işlemeleri değil **dal ucu hareketlerini** kaydeder: **6** kayıt
  **1000** işlemeyi kurtarabilir. Kayıt sayısı kurtarma kapsamını göstermez.
- Kurtarılabilir kümeyi kayıtların en geriye gideni belirler; saklama ufku **7 / 30 / 60 /
  90** gün olduğunda kurtarılabilir işleme **3 / 50 / 500 / 1000**, kalıcı kayıp
  **997 / 950 / 500 / 0** olur.
- Günlük yereldir, başvuru başınadır ve ufka tabidir; yedek dal üçünün de dışındadır ve tek
  kalıcı önlemdir.
- Kurtarma işlemleri okuma işlemleridir: eski uca dal adı vermek hiçbir şeyi silmez.

#### Sonraki Adım

Buraya kadar tarihçe **değiştirildi** ve her değişikliğin bedeli dokunulan nesneyle sayıldı:
etkileşimli kipte 3002, toplu dönüşümde 5640, zorlayıcı itmede kopyalar üzerinden 39480,
kurtarmada pencerenin genişliğine göre 6 ile 5640 arası. Değiştirmenin bedeli artık
biliniyor. Bilinmeyen, tersinin bedelidir: aynı tarihçeye **soru sormak** ne kadar tutar.
Sonraki konu bunu ölçer — bin işlemelik bir tarihçede bir kusurun hangi işlemeyle girdiğini
bulmak kaç adım sürer ve tarihçe dört kat büyüdüğünde o adım sayısı kaça çıkar. Bedelin
birimi de orada değişir: nesne değil, **adım**.

## Tanı Araçları

Regresyonun girdiği işlemeyi ikili aramayla bulma, bir satırın geçmişini izleme, ve istemci ile sunucu tarafı kancaların ne zaman devreye girdiği.

### İkili Arama ile Hata Avı

Source: https://academia.sh/tr/kurslar/ileri-git/ikili-arama-ile-hata-avi

Tarihçeye soru sormanın bedeli adım sayısıdır: aynı kusuru bulmak için doğrusal tarama 37, 150, 750 ve 3000 adım harcarken ikili arama 6, 7, 9 ve 11 adımda bitirir ve aramayı ucuzlatan toplama yanıtın çözünürlüğünü kabalaştırır.

Önceki ders yeniden yazmanın ardından geriye ne kaldığını saydı: kaybolan işlemeler
referans günlüğünde bir süre daha erişilebilir kalıyor, çöp toplama çalışınca o pencere
kapanıyordu. Buraya kadar tarihçe **değiştirilen** bir nesneydi ve her değişikliğin bedeli
dokunulan nesneyle ölçüldü.

Bu ders yönü çeviriyor. Tarihçeye dokunmuyoruz, ona **soru soruyoruz**: bu kusur hangi
işlemede girdi? Bedelin birimi de değişiyor. Burada sayılan şey dokunulan nesne değil,
**adım** — yani kâhine kaç kez başvurulduğu. Sorunun yanıtı tarihçenin içinde duruyor;
mesele onu kaç denemede çıkarabildiğimiz.

#### Aramanın Dayandığı Tek Varsayım

Tarihçe boyunca her işleme için tek bir soru sorulabilir: kusur burada var mı? Yanıt bir
noktaya kadar "yok", o noktadan sonra hep "var" ise, tarihçe bu soru açısından
**tekdüzedir**. Aranan şey, yanıtın döndüğü ilk işlemedir.

Bu tekdüzelik bir armağan değil, bir varsayımdır ve bozulabilir. Kusur girmiş, sonra bir
başka işlemede yanlışlıkla örtülmüş, sonra yeniden açığa çıkmışsa yanıt iki kez döner ve
arama yanlış işlemeyi gösterir. Aramayı kurmadan önce sorulacak soru budur: bu koşul
tarihçe boyunca bir kez mi değişiyor?

Tekdüze bir yüklem üzerinde aralığı yarılayan algoritmanın kendisi Algoritmalar kursunun
Arama ve Sıralama konusunda kuruldu; orada ölçülen şey **algoritmanın karmaşıklığıydı**.
Burada ölçülen şey başka: aynı yöntem bir işleme dizisine uygulandığında **tarihçe
üzerinde kaç adım** harcandığı. Aracın alt komutu bu yöntemi tarihçeye bağlar ve her
adımda çalışma alanını o işlemeye taşır.

#### Aracın Yürüttüğü Döngü

Arama üç bildirimle kurulur: aramanın başlatılması, kusurun görüldüğü bir işleme ve
kusurun görülmediği bir işleme. Bundan sonrasını araç yürütür; her adımda aralığın
ortasındaki işlemeye geçer ve yanıtı bekler.

```text
# öğretilen komutlar ve örnek döküm — çalıştırılmamıştır

git bisect start
git bisect bad HEAD
git bisect good v-onceki-surum

# araç aralığın ortasına geçer ve kalan aday sayısını bildirir:
Bisecting: <kalan aday> revisions left to test after this
[a1b2c3d] olcum: esik degerini ayardan oku

# her adımda yanıt verilir
git bisect good        # ya da: git bisect bad

# arama bittiğinde aracın çalışma alanı geri alınır
git bisect reset
```

İki ucun seçimi aramanın tek serbest parametresidir ve iki yönde de yanlış seçilebilir.
Kusursuz uç gereğinden geriye konursa aday kümesi büyür ve her fazladan iki katı bir adım
daha ödetir. Gereğinden ileriye konursa daha kötüsü olur: kusur o ucun gerisinde kalır,
arama tekdüzelik varsayımını sağlamayan bir küme üzerinde yürür ve yine bir işleme
gösterir. Yanlış uç seçiminin belirtisi yoktur; aramanın sonunda dönen işleme her iki
durumda da aynı biçimde bildirilir.

Yanıtı elle vermek zorunlu değildir. Kusuru sınayan bir betik varsa arama tümüyle araca
bırakılabilir; betiğin çıkış kodu kâhin yerine geçer, sıfır "kusur yok", sıfırdan farklı
"kusur var" demektir. Bu ayrım pratikte belirleyicidir: kâhin otomatikleştirilemiyorsa
adım sayısı doğrudan insan emeğine dönüşür.

Aramanın bir de eksik yanıtı vardır. Aralığın ortasındaki işleme kurulmuyorsa ya da o
noktada sınama anlamlı değilse, o işleme yanıt veremez ve arama onu **atlamak** zorunda
kalır. Atlanan işleme aralığı yarılamaz; yalnızca komşusuna kayar. Kurulmayan bir pencere
tarihçenin ortasındaysa, arama o pencerenin genişliği kadar adımı yarılama olmadan harcar.

Ölçümün varsayımları:

- **TA1** — Tarihçe ortak kurgudan üretilir: dört ölçekte doğrusal bir işleme dizisi,
  her işleme beş dosyadan birine dokunuyor.
- **TA2** — Kâhin kurguyu biz ürettiğimiz için bilinir ve kusurun tarihçenin dörtte
  üçünde girdiğini söyler. Kâhin her ölçekte aynı kuraldır ve ölçüm boyunca
  değiştirilmez.
- **TA3** — Tekdüzelik varsayılır: kusur girdiği işlemeden sonra hiç kapanmaz. Ölçüm
  tekdüzeliğin bozulduğu durumu saymaz.
- **TA4** — Bir adım, kâhine yapılan bir başvurudur. Kurulum, sınama ve çalışma alanının
  taşınması bir adımın içinde sayılır; adımlar birbirinden ayırt edilmez.
- **TA5** — Doğrusal tarama tarihçeyi baştan sona yürür ve kusuru gördüğü ilk işlemede
  durur. Bu, aramanın en iyi durumda değil, **kurgunun verdiği durumda** ölçülmesidir.
- **TA6** — İkinci bölümde tek değişen şey işlemelerin toplanma oranıdır: aynı
  değişiklikler, her biri daha az sayıda işlemede kayıtlı. Kurgu ve kâhin aynı kalır.
- **TA7** — Kurgu doğrusaldır: aday kümesi iki sayı arasındaki aralıktır. Çatallanmış
  tarihçede aday kümesinin nasıl kurulduğu ölçümün dışında, ölçümün ardındaki bölümde
  tartışılır.

#### Ölçüm

```python
"""Tarihcede kusurlu islemeyi bulmanin bedeli: adim sayisi.

Bolum 1 - iki tarama bicimi dort olcekte.
Bolum 2 - aramanin ucuzlamasi ile yanitin kabalasmasi.
"""
TOHUM = 20260814
DOSYALAR = ("olcum.py", "rapor.py", "kimlik.py", "ayar.py", "belge.md")


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 kusurlu_isleme(t):
    """Kahin: kusuru getiren isleme, kurguyu biz yazdigimiz icin bilinir."""
    return len(t) * 3 // 4


def dogrusal_arama(t):
    hedef, adim = kusurlu_isleme(t), 0
    for x in t:
        adim += 1
        if x["no"] >= hedef:
            return adim
    return adim


def ikili_arama(t):
    hedef, alt, ust, adim = kusurlu_isleme(t), 1, len(t), 0
    while alt < ust:
        orta = (alt + ust) // 2
        adim += 1
        if orta >= hedef:
            ust = orta
        else:
            alt = orta + 1
    return adim


def aday_izi(t):
    """Her adimdan sonra geriye kalan aday isleme sayisi."""
    hedef, alt, ust, iz = kusurlu_isleme(t), 1, len(t), []
    while alt < ust:
        orta = (alt + ust) // 2
        if orta >= hedef:
            ust = orta
        else:
            alt = orta + 1
        iz.append(ust - alt + 1)
    return iz


def toplanmis(t, k):
    """Ayni degisiklikler, k tanesi tek islemede kayitli."""
    return [{"no": i + 1, "nesne": sum(x["nesne"] for x in t[i * k:(i + 1) * k])}
            for i in range(len(t) // k)]


OLCEKLER = (50, 200, 1000, 4000)
print(f"{'işleme':>7s} {'kusurlu':>8s} {'doğrusal adım':>14s} {'ikili adım':>11s}")
for n in OLCEKLER:
    t = tarihce(n)
    print(f"{n:7d} {kusurlu_isleme(t):8d} {dogrusal_arama(t):14d} "
          f"{ikili_arama(t):11d}")

buyuk = tarihce(4000)
print()
print("4000 işlemede adım adım kalan aday:", aday_izi(buyuk))

print()
print(f"{'işleme':>7s} {'toplama':>8s} {'ikili adım':>11s} {'yanıtın kapsamı':>16s}")
for k in (1, 2, 5, 10, 40):
    g = toplanmis(buyuk, k)
    print(f"{len(g):7d} {k:8d} {ikili_arama(g):11d} {k:16d}")
```

```
 işleme  kusurlu  doğrusal adım  ikili adım
     50       37             37           6
    200      150            150           7
   1000      750            750           9
   4000     3000           3000          11

4000 işlemede adım adım kalan aday: [2000, 1000, 500, 250, 125, 62, 31, 15, 7, 3, 1]

 işleme  toplama  ikili adım  yanıtın kapsamı
   4000        1          11                1
   2000        2          10                2
    800        5           9                5
    400       10           8               10
    100       40           6               40
```

#### İki Bedelin Ayrıştığı Yer

Üst tablo aynı tarihçeyi iki biçimde tarıyor. Tarihçe **50**'den **4000**'e, yani seksen
kat büyürken doğrusal tarama **37** adımdan **3000** adıma çıkıyor; ikili arama **6**
adımdan **11**'e. **Seksen kat büyüyen bir tarihçede ikili arama iki kat bile artmıyor.**

Doğrusal taramanın sütunu ikinci sütunla birebir aynı ve bu bir tesadüf değil: doğrusal
tarama kusuru gördüğü ilk işlemede durduğu için harcadığı adım, kusurun **tarihçedeki
yeridir**. Yani doğrusal taramanın bedeli tarihçenin uzunluğuna değil, kusurun nereye
düştüğüne bağlıdır; kusur başlarda olsaydı ucuz, sonlarda olsaydı pahalı olurdu. Ölçüm
bunu bir avantaj olarak da okumuyor, çünkü kusurun nerede olduğu aramadan **önce**
bilinmiyor. Bilinseydi arama zaten gerekmezdi; ölçüm de bu yüzden kusuru sabit bir yere koyar ve iki
biçimi aynı koşulda karşılaştırır.

İkili aramanın sütununda böyle bir bağımlılık yok. Ortadaki iz satırı nedenini gösteriyor:
aday sayısı **2000**'den başlayıp her adımda yarılanarak **1**'e iniyor. Her yanıt aralığın
yarısını eliyor ve elenen yarı bir daha hiç sınanmıyor. Dört bin işlemelik tarihçede on
bir yanıt, aday kümesini **1/4000** çözünürlüğüne indirmeye yetiyor. Dört ölçekte
ulaşılan çözünürlük sırasıyla **1/50**, **1/200**, **1/1000** ve **1/4000**'dir; ölçüm
bundan küçük bir ayrımı gösteremez, çünkü tarihçenin kendi çözünürlüğü bir işlemedir.

Bu ayrım kursun ölçü ekseninin arama tarafındaki karşılığıdır: bedel tarihçenin
uzunluğundan değil, **bir adımın hangi kümeye dokunduğundan** çıkıyor. Doğrusal tarama bir
adımda bir işlemeye dokunuyor, ikili arama bir adımda kalan adayların yarısına.

#### Çatallanmış Tarihçede Aday Kümesi

Ölçümün kurgusu doğrusaldır: işlemeler bir dizi hâlindedir ve aralık iki sayı arasındadır.
Gerçek bir tarihçe çoğu zaman doğrusal değildir; Dallanma ve İşbirliği kursunda kurulan
birleştirme işlemesi tarihçeyi bir çizgi olmaktan çıkarır.

Arama bu durumda da çalışır ama aralığın anlamı değişir. Aday kümesi artık iki sayı
arasındaki işlemeler değil, **kusurlu bildirilen işlemeden erişilebilen ve kusursuz
bildirilen işlemeden erişilemeyen** işlemelerdir. Araç her adımda bu kümeyi en dengeli
bölen işlemeye geçer. Yarılama fikri korunur; değişen tek şey neyin yarıldığıdır.

Bunun iki pratik sonucu var. Birincisi, bir yan dalda girmiş kusur o dal birleştirilene
kadar ana çizgide görünmez, ama arama kusuru birleştirme işlemesinde değil yan daldaki
gerçek işlemesinde bulur — çünkü o işleme de aday kümesinin içindedir. İkincisi, adım
sayısını belirleyen şey iki uç arasındaki mesafe değil, **erişilebilir kümenin
büyüklüğüdür**. İki uç birbirine yakın görünürken araya birleşmiş dallar geniş bir küme
getiriyorsa adım sayısı o kümeye göre çıkar.

#### Bir Adımın Gerçek Bedeli

Adım sayısı tek başına bir emek ölçüsü değil. Her adım çalışma alanının o işlemeye
taşınmasını, gerekiyorsa yeniden kurulmasını ve sınanmasını içerir. Kurulumu uzun süren
bir bileşende on bir adım, kurulumu anlık olan bir bileşendeki üç bin adımdan pahalıya
gelebilir.

Bu yüzden aramanın pratikteki ölçüsü şudur: **adım sayısı × bir adımın süresi.** İkili
arama ilk çarpanı düşürür; ikinci çarpanı düşüren şey ise aramanın kendisi değil, kusuru
sınayan betiğin hızıdır. Sınama betiği kurulmuş bir ortamda saniyeler içinde yanıt
veriyorsa arama tümüyle araca bırakılabilir ve on bir adım tek bir komutun içinde geçer.
Sınama elle yapılıyorsa on bir adım on bir kez insan dikkati demektir.

Atlanan işlemeler bu çarpımı bozan tek durumdur. Kurulmayan bir işleme yanıt üretmez;
arama komşusuna kayar ve o kaymanın maliyeti yarılama olmadan ödenir. Kurulamayan
pencereler geniş bir tarihçede aramayı doğrusala yaklaştırabilir. Bunun çaresi arama
tarafında değil: tarihçenin her noktasında kurulabilir kalması, arama aracının değil
tümleştirme disiplininin sonucudur.

#### Aramanın Kaydı ve Yanıtın Doğrulanması

Arama bir dizi karardan oluşur ve kararlar yanlış verilebilir. Bir adımda kusur gözden
kaçırılıp "kusursuz" denmişse arama o yanıtın açtığı yönde ilerler ve sonunda yanlış bir
işleme gösterir. Araç bunu fark edemez, çünkü elindeki tek bilgi verilen yanıtlardır.

Buna karşı iki alışkanlık vardır. Birincisi aramanın kaydının tutulmasıdır: verilen
yanıtların dizisi bir günlüğe yazılır ve gerektiğinde yeniden oynatılabilir. Yanlış
verildiğinden şüphelenilen adım günlükten çıkarılıp arama o noktadan yeniden yürütülebilir;
tümüyle başa dönmek gerekmez.

```text
# öğretilen komutlar ve örnek döküm — çalıştırılmamıştır

git bisect log > arama-kaydi.txt
git bisect reset
git bisect replay arama-kaydi.txt

git bisect skip                 # sınanamayan işlemede
git bisect run ./sinama.sh      # kâhin betiğin çıkış kodudur
```

İkincisi, bulunan işlemenin bir yanıt değil bir **sav** olmasıdır. Arama bittiğinde elde
tek bir işleme vardır ve o işlemenin gerçekten kusuru getirdiği ayrıca sınanmalıdır:
değişiklik geri alındığında kusur kayboluyor mu? Bu doğrulama on bir adımın üstüne on
ikinciyi ekler. Ölçümde saymadığımız bu adım pratikte atlanmaz, çünkü aramanın bütün
güvencesi kâhinin verdiği yanıtların doğruluğuna dayanır.

Kâhinin kesinliği de aynı yere bağlanır. "Yavaş çalışıyor" gibi bir ölçüt eşiği belirsiz
bırakır ve aynı işleme iki denemede iki farklı yanıt alabilir. Kâhin ikili bir karara
indirgenemiyorsa tekdüzelik varsayımı sınanamaz hâle gelir ve arama dayandığı zemini
kaybeder. Aramanın kurulmasındaki asıl iş bu yüzden komutlarda değil, kusuru bir çıkış
koduna indiren betiği yazmaktadır.

#### Yanıtın Çözünürlüğü

Alt tablo aynı değişiklikleri farklı büyüklükte işlemelere toplayarak aynı aramayı
yeniden yapıyor. Dört bin değişiklik kırklı gruplara toplandığında tarihçe **100** işlemeye
iniyor ve arama **11** yerine **6** adımda bitiyor. Beş adım kazanç.

Bedeli sağdaki sütunda: yanıtın kapsamı **1**'den **40**'a çıkıyor. Arama artık "bu işlemede
girdi" demiyor, "bu kırk değişiklikten birinde girdi" diyor. Kalan iş aramanın dışında,
işlemenin içinde, elle yapılacak. Takas eşit değildir — adım sayısı logaritmik düşerken yanıtın
kabalığı doğrusal artıyor. Kırk kat daha kaba bir yanıt için beş adım kazanılıyor.

Bu, Dallanma ve İşbirliği kursunun sıkıştırma ölçümüyle aynı biçimin başka bir birimdeki
görüntüsüdür: orada temizlenen tarihçenin **yanıtlayabildiği soru** azalıyordu, burada
aranan tarihçenin **verebildiği yanıt** kabalaşıyor. İkisinin ortak sonucu şudur: aramanın
çözünürlüğü arama anında değil, **işleme anında** belirlenir. Atomik işleme alışkanlığı
bir üslup tercihi değil, ileride sorulacak sorunun çözünürlüğünü belirleyen bir karardır.

#### Özet

- Arama tek bir varsayıma dayanır: kusurun varlığı tarihçe boyunca bir kez değişir.
  Tekdüzelik bozulursa arama yanlış işlemeyi gösterir ve bunu haber vermez.
- Tarihçe seksen kat büyürken doğrusal tarama **37** adımdan **3000** adıma çıkar, ikili
  arama **6**'dan **11**'e; bedel tarihçenin uzunluğundan değil, bir adımın dokunduğu
  kümeden gelir.
- Doğrusal taramanın adımı kusurun tarihçedeki yerine eşittir; ikili aramanınki yere değil
  yalnızca uzunluğa bağlıdır ve aday kümesini **1/4000** çözünürlüğüne indirir.
- Adım sayısı emeğin yarısıdır; diğer yarısı bir adımın süresidir ve onu belirleyen şey
  kâhinin otomatikleştirilebilmesidir.
- Çatallanmış tarihçede aday kümesi bir sayı aralığı değil, iki uçtan erişilebilirlikle
  tanımlanan kümedir; adım sayısını o kümenin büyüklüğü belirler.
- Değişiklikler kırklı gruplara toplandığında adım **11**'den **6**'ya iner ama yanıtın
  kapsamı **1**'den **40**'a çıkar; aramanın çözünürlüğü işleme anında belirlenir.

#### Sonraki Adım

İkili arama tarihçeye tek bir soru sorar ve yanıtı bir işleme olarak alır: kusur şurada
girdi. Ama çoğu zaman sorulan soru bu değildir. Elde bir işleme yoktur, elde tek bir
**satır** vardır ve sorulan şey o satırın oraya neden yazıldığıdır. Sonraki ders bu soruya
bakar: bir satırın son yazarını bulmanın bedeli aynı tarihçede kaç adımdır, neden ikili
aramanın adımıyla aynı biçimde büyümez ve son yazarın gerçekten aranan kişi olmadığı
durumda yanıt nereye kayar.

### Suçlama ve Satır Tarihçesi

Source: https://academia.sh/tr/kurslar/ileri-git/suclama-ve-satir-tarihcesi

Suçlamanın bedeli o dosyaya dokunan işleme sayısıdır ve aynı tarihçede 8, 36, 209 ve 787 adıma çıkar; ikili aramanın 11 adımının yanında bu ikinci bir büyüme biçimidir ve tarama ne kadar uzarsa uzasın yanıt dosyanın satır sayısıyla sınırlı kalır.

Önceki ders tarihçeye tek bir soru sordu ve yanıtı bir işleme olarak aldı: kusur şurada
girdi. Aramanın bedeli **adım** birimiyle sayıldı ve tarihçe seksen kat büyürken altıdan
on bire çıktı.

Bu dersin sorusu başka bir yerden geliyor. Elde bir kusur belirtisi yok; elde okunan bir
dosya ve içinde anlaşılmayan bir **satır** var. Sorulan şey o satırın oraya neden
yazıldığı. **Suçlama (blame)** bu soruya doğrudan yanıt vermez ama en yakın vekili verir:
o satırı **en son hangi işleme yazdı**. Aynı tarihçe, aynı depo — ama bedel bu kez bambaşka
bir biçimde büyüyor.

#### Suçlamanın Yanıtladığı Soru

Suçlama, bir dosyanın her satırı için tek bir işleme adı üretir. Ürettiği ad, o satırın
şimdiki hâlini yazan **son** işlemedir. Bu ayrım dersin tamamını taşır: yanıt "bu satırı
kim yazdı" değil, "bu satıra en son kim dokundu" sorusunun yanıtıdır. İkisi çoğu zaman
aynıdır, ama ayrıldıklarında suçlama ayrıldığını haber vermez.

Yanıtı üretmek için araç dosyanın tarihçesini sondan başa yürür. Her adımda o işlemenin
dosyada neyi değiştirdiğine bakar; hâlâ sahipsiz kalan satırlardan hangilerini o işleme
yazmışsa onları işaretler ve kalanlarla bir önceki işlemeye geçer. Bütün satırlar
sahiplenince tarama biter — ya da dosyaya dokunan işlemeler tükenince. İlk kurulan satırlar
tarihçenin başında sahiplenilir, en son değişenler ise daha ilk adımlarda; tarama sırası bu
yüzden dosyanın değil, tarihçenin sırasıdır.

Buradan bedelin birimi çıkıyor. Bir adım, **o dosyaya dokunan bir işlemedir**. Dosyaya
dokunmayan işlemeler taramaya girmez; tarihçenin geri kalanı suçlama açısından yok
hükmündedir. Bu yüzden suçlamanın bedeli tarihçenin uzunluğuna değil, **dosyanın
tarihçedeki payına** bağlıdır.

#### Neden Yarılanamıyor

Önceki dersin aramasında bedeli düşüren şey tekdüzelikti: tek bir yüklem tarihçe boyunca
bir kez değişiyordu ve her yanıt adayların yarısını eliyordu. Suçlamada böyle bir yüklem
yok. Sorulan şey bir eşiğin nerede aşıldığı değil, kırk ayrı satırın her birinin en son
nerede yazıldığı. Kırk ayrı sorunun kırk ayrı yanıtı var ve hiçbiri diğerinin aday
kümesini daraltmıyor.

Yarılama bir ikinci nedenle de kapalı: yanıtın **eksiksiz** olması isteniyor. Arama tek bir
işlemeyi bulup durabilirdi, çünkü aradığı tek bir noktaydı. Suçlama duramaz; sahipsiz tek
bir satır kaldığı sürece taramaya devam etmek zorunda. Bu yüzden suçlama, tarihçeye
sorulan sorular arasında **tam tarama** gerektiren sınıfa girer.

```text
# öğretilen komutlar ve örnek döküm — çalıştırılmamıştır

git blame ayar.py
git blame -L 12,18 ayar.py          # yalnız belirli satır aralığı
git blame -w ayar.py                # boşluk değişikliklerini yok say
git blame --ignore-rev a1b2c3d ayar.py

# çıktının biçimi: işleme kimliği, rol, tarih alanı, satır no, satırın kendisi
a1b2c3d (yazan     <tarih alanı> 12) esik = ayar.oku("esik")
7d4e5f6 (inceleyen <tarih alanı> 13)     if esik is None:
a1b2c3d (yazan     <tarih alanı> 14)         esik = VARSAYILAN
```

Satır aralığı seçeneği bedeli düşürmez, yalnız çıktıyı kısaltır: araç yine dosyanın
tarihçesini yürümek zorundadır. Bedeli gerçekten düşüren tek şey dosyanın tarihçedeki
payının küçük olmasıdır.

Çıktının her satırı üç şey taşır: satırı en son yazan işlemenin kimliği, o işlemenin
üstverisinden gelen rol ve zaman alanı ve satırın kendisi. Yanıtın adres gösterdiği yer
bir kişi değil bir **işlemedir**; kişi bilgisi işlemenin üstverisinden okunur ve suçlamanın
ürettiği bir bulgu değildir. Bu ayrımın ekip içindeki karşılığı — bulgunun kime ve nasıl
iletildiği — Kod İnceleme ve Ekip Süreci kursunun konusudur; burada suçlama bir ölçüm
aracıdır, bir sorumluluk aracı değil.

Ölçümün varsayımları:

- **TA17** — Tarihçe ortak kurgudan üretilir; her işleme beş dosyadan birine dokunur ve
  dosya seçimi kurgunun kendisidir. Kurgu ve kâhin bu derste de değiştirilmez.
- **TA18** — İzlenen dosya `ayar.py`; ölçüm dört ölçekte aynı dosyayı izler.
- **TA19** — Bir adım, izlenen dosyaya dokunan bir işlemedir. Dosyaya dokunmayan
  işlemeler sayılmaz.
- **TA20** — Dosya **40** satırdır ve satır sayısı ölçek boyunca sabittir; taşınma,
  bölünme ve dosya adı değişikliği ölçümün dışındadır.
- **TA21** — İçerik değiştiren her dokunuş kırk satırdan **birini** yeniden yazar. Bir
  dokunuşun birden çok satıra dokunması ölçümde sayılmaz; bu, gizlenen işleme sayısını
  **eksik** tahmin eden bir varsayımdır.
- **TA22** — İkinci bölümde tek değişen şey bir **biçim geçişinin** eklenmesidir:
  tarihçenin tam ortasındaki işleme dosyanın kırk satırının kırkını da yeniden yazar,
  içeriğini değiştirmeden.
- **TA23** — Suçlamanın yanıtı satır başına tek bir işlemedir. Aracın satırı önceki
  hâlinden izleyip izlemediği ölçüme girmez; ölçülen şey yanıtın kendisidir.

#### Ölçüm

```python
"""Suclamanin bedeli: bir adim, dosyaya dokunan bir islemedir.

Bolum 1 - ayni tarihcede iki aramanin adim sayisi.
Bolum 2 - bir bicim gecisinin satir tarihcesine etkisi.
"""
TOHUM = 20260814
DOSYALAR = ("olcum.py", "rapor.py", "kimlik.py", "ayar.py", "belge.md")
IZLENEN, SATIR, TOHUM_SATIR = "ayar.py", 40, 20260815


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 kusurlu_isleme(t):
    """Kahin: kusuru getiren isleme, kurguyu biz yazdigimiz icin bilinir."""
    return len(t) * 3 // 4


def ikili_arama(t):
    hedef, alt, ust, adim = kusurlu_isleme(t), 1, len(t), 0
    while alt < ust:
        orta = (alt + ust) // 2
        adim += 1
        if orta >= hedef:
            ust = orta
        else:
            alt = orta + 1
    return adim


def suclama(t, dosya):
    """Bir dosyanin satir tarihcesi: o dosyaya dokunan islemeler taranir."""
    return sum(1 for x in t if x["dosya"] == dosya)


def son_yazarlar(t, dosya, bicim_konumu=None):
    """Her satirin son yazari; bicim gecisi butun satirlari yeniden yazar."""
    r, yazar = uretec(TOHUM_SATIR), [0] * SATIR
    for x in t:
        if x["no"] == bicim_konumu:
            yazar = [x["no"]] * SATIR
        if x["dosya"] == dosya:
            yazar[r(SATIR)] = x["no"]
    return yazar


OLCEKLER = (50, 200, 1000, 4000)
print(f"{'işleme':>7s} {'ikili adım':>11s} {'dokunan işleme':>15s} "
      f"{'gösterilen':>11s} {'gizlenen':>9s}")
for n in OLCEKLER:
    t = tarihce(n)
    tarama = suclama(t, IZLENEN)
    ayri = len(set(son_yazarlar(t, IZLENEN)) - {0})
    print(f"{n:7d} {ikili_arama(t):11d} {tarama:15d} {ayri:11d} "
          f"{tarama - ayri:9d}")

print()
print(f"{'işleme':>7s} {'geçişten sonraki dokunuş':>25s} "
      f"{'biçimi gösteren satır':>22s} {'ayrı işleme':>12s}")
for n in OLCEKLER:
    t = tarihce(n)
    y = son_yazarlar(t, IZLENEN, bicim_konumu=n // 2)
    sonraki = sum(1 for x in t if x["dosya"] == IZLENEN and x["no"] > n // 2)
    print(f"{n:7d} {sonraki:25d} {sum(v == n // 2 for v in y):22d} "
          f"{len(set(y) - {0}):12d}")
```

```
 işleme  ikili adım  dokunan işleme  gösterilen  gizlenen
     50           6               8           8         0
    200           7              36          25        11
   1000           9             209          40       169
   4000          11             787          40       747

 işleme  geçişten sonraki dokunuş  biçimi gösteren satır  ayrı işleme
     50                         3                     37            4
    200                        16                     25           16
   1000                       120                      3           38
   4000                       375                      0           40
```

#### Aynı Depo, İki Ayrı Büyüme

İlk iki sütun aynı tarihçenin iki sorusunu yan yana koyuyor. Tarihçe **50**'den **4000**'e
çıkarken ikili aramanın adımı **6**'dan **11**'e çıkıyor; aynı tarihçede tek bir dosyanın
suçlaması **8** adımdan **787** adıma. Seksen kat büyüyen tarihçede birinci soru iki kat
bile pahalılaşmıyor, ikincisi doksan sekiz kat pahalılaşıyor.

Fark araçların hızından gelmiyor; sorulan sorunun biçiminden geliyor. İkili arama tek bir
eşiği arıyor ve her yanıt adayların yarısını eliyor. Suçlama kırk ayrı satırın sahibini
arıyor ve hiçbir yanıt diğerinin aday kümesini daraltmıyor, üstelik yanıtın eksiksiz olması
gerekiyor. Aynı depo, aynı tarihçe, iki ayrı büyüme biçimi — ve
ikisini ayıran şey aracın gerçekleştirimi değil, sorunun kendisidir.

Bu, kursun ölçü ekseninin ikinci kez ödendiği yerdir: **bedel tarihçenin uzunluğundan
değil, işlemin dokunduğu kümeden çıkar.** İkili arama tarihçenin yarısını bir adımda
eliyor; suçlama dosyanın tarihçedeki payının tamamına dokunmak zorunda. Suçlamanın payı
kurguda beşte birdir ve **787 ÷ 4000** oranı tam olarak bunu gösteriyor.

Ölçümün çözünürlüğünü de aynı yer belirliyor. Dört ölçekte ayırt edilebilen en küçük fark
bir işlemedir, yani sırasıyla **1/50**, **1/200**, **1/1000** ve **1/4000**. Suçlamanın
sekiz adımdan yedi yüz seksen yediye çıkması bu bandın çok üstünde bir farktır ve ölçüm
onu rahatça taşır; buna karşılık iki dosyanın payları arasındaki birkaç adımlık ayrım —
kurguda beş dosyanın payları birbirine yakındır — bu kümeyle savunulamaz. Ölçümün
söylediği şey hangi dosyanın daha pahalı olduğu değil, **payın büyümesiyle bedelin aynı
oranda büyüdüğüdür**.

Bunun pratikteki karşılığı şudur: suçlamayı hızlandırmanın yolu aracı değiştirmek değil,
dosyayı küçültmektir. Beş yüz kez dokunulan bir dosya ikiye bölünürse iki dosyanın
suçlaması ayrı ayrı yaklaşık iki yüz elli adımda biter. Dosyanın büyüklüğü bir okunabilirlik
sorunu olduğu kadar bir tanı bedeli sorunudur.

#### Gösterilen ve Gizlenen

Son iki sütun daha rahatsız edici bir şey söylüyor. Dört bin işlemelik tarihçede suçlama
**787** işleme tarıyor ama yanıtında yalnız **40** ayrı işleme görünüyor; **747** işleme
dosyaya dokunmuş ve yanıtta hiç görünmüyor. Bin işlemelik tarihçede gizlenen sayı **169**,
iki yüz işlemede **11**, elli işlemede **0**.

Gösterilen sütununun **40**'ta durması bir tavandır ve nereden geldiği açık: dosya kırk
satır, suçlama satır başına bir ad veriyor, dolayısıyla en çok kırk ayrı ad üretebiliyor.
Tarama uzadıkça bedel büyüyor ama **yanıtın büyüklüğü büyümüyor.** Elli işlemede tarama
sekiz, yanıt sekiz — biri birine. Dört binde tarama yedi yüz seksen yedi, yanıt kırk —
yirmi adıma bir ad.

Bunun anlamı, suçlamanın bir **özet** olmasıdır. Dosyanın satır tarihçesinin tamamı değil,
o tarihçenin son katmanıdır. Bir satırın kaç kez değiştiği, kaç ayrı işlemenin ona
dokunduğu, önceki hâllerinin ne olduğu suçlamanın yanıtında yoktur — ve olmadığı da
yazmaz. Yanıtı okuyan, gizlenen yedi yüz kırk yedi işlemenin farkında olmaz.

Tam satır tarihçesi ayrı bir sorudur ve ayrı bir alt komutla sorulur: bir satır aralığının
bütün geçmişini isteyen sorgu, o aralığa dokunan her işlemeyi sırasıyla verir. Bedeli
suçlamayla aynı taramadır, ama yanıtın büyüklüğü artık tavana takılmaz. Doğru araç
seçiminin ölçütü budur: **son katman mı isteniyor, bütün katmanlar mı?**

#### Taşınan Satır

Ölçüm dosyanın kırk satırının yerinde kaldığını varsayıyor (TA20). Gerçek bir tarihçede
satırlar
taşınır: bir işlev başka bir dosyaya alınır, bir blok aynı dosyanın başka yerine kaydırılır.
Suçlama açısından bu, satırın yeniden **yazılması** demektir. Taşıyan işleme taşınan bütün
satırların son yazarı olur ve satırın gerçek geçmişi bir dosya sınırının ötesinde kalır.

Araç bunu bir ölçüde geri alabilir. Aynı işlemenin içinde yeri değişmiş satırları izleyen
bir ayar vardır, dosyalar arasında taşınmayı izleyen bir başkası. İkisi de taramayı
genişletir, çünkü artık yalnız izlenen dosyanın tarihçesi değil, satırın gelmiş olabileceği
dosyaların tarihçesi de yürünmek zorundadır. Bedel bu yüzden ölçümde saydığımızın üstüne
çıkar: tarama tek bir dosyanın payıyla sınırlı kalmaz.

Buradan pratik bir kural çıkıyor. **Taşıma ile değişiklik aynı işlemede birleştirilirse
satırın geçmişi orada kesilir** — araç, taşınan satırın yeni yerinde ne kadarının
korunduğunu ancak ikisi ayrıldığında güvenle çıkarabilir. Taşımayı ayrı bir işlemede
kaydetmek, ileride sorulacak soruya yanıt bırakmanın en ucuz yoludur: saf taşıma işlemesi
atlama listesine yazılabilir, taşımayla değişikliği birleştiren işleme yazılamaz.

#### Biçim Geçişinin Ödettiği

Alt tablo tarihçenin ortasına tek bir biçim geçişi koyuyor: içeriği değiştirmeyen, ama
dosyanın kırk satırının kırkını da yeniden yazan bir işleme. Sonuç ölçeğe göre sert biçimde
değişiyor.

Elli işlemelik tarihçede geçişten sonra dosyaya yalnız **3** kez dokunulmuş; suçlamanın
yanıtında **37** satır biçim geçişini gösteriyor ve geriye **4** ayrı işleme kalıyor.
Dosyanın görünür yazarlığı tek bir işlemeye toplanmış durumda. Dört bin işlemede ise
geçişten sonra **375** dokunuş olmuş ve biçim geçişini gösteren satır **0**; yanıtta yine
**40** ayrı işleme var.

Örüntü şudur: **biçim geçişinin zararı ölçekle değil, geçişten sonraki dokunuş sayısıyla
belirlenir.** Geçiş, üstünden yeterince iş geçmemiş bir dosyada suçlamanın yanıtını tümüyle
kendi üstüne toplar. Ve zararın en ağır olduğu yer, dosyanın en az dokunulan yeridir —
yani suçlamaya en çok başvurulacak, en az anlaşılan satırlar.

Bunun iki karşılığı vardır ve ikisi de suçlamanın kendisinde durur. Birincisi boşluk
değişikliklerini yok saymaktır; yalnız girinti ve hizalama değişmişse satır sahipsiz
sayılır ve tarama bir önceki işlemeye geçer. İkincisi belirli işlemelerin taramada atlanmak
üzere işaretlenmesidir; toplu biçim geçişleri bir listeye yazılır ve suçlama o işlemeleri
hiç görmemiş gibi davranır. İkisi de aracın ayarıdır ve tarihçeyi değiştirmez — bu kursta
tarihçeyi değiştirmeden çözülen ilk sorundur.

#### Özet

- Suçlama satır başına tek bir ad üretir ve o ad satırı **en son yazan** işlemedir;
  "kim yazdı" ile "en son kim dokundu" ayrıldığında araç bunu haber vermez.
- Bedelin birimi adımdır ve bir adım, izlenen dosyaya dokunan bir işlemedir; tarihçe
  **50**'den **4000**'e çıkarken bedel **8**'den **787**'ye yükselir.
- Aynı tarihçede ikili arama **6** adımdan **11**'e çıkar; sorulan sorunun biçimi tek
  başına iki ayrı büyüme üretir.
- Tarama uzarken yanıt büyümez: dört bin işlemede **787** işleme taranır, yanıtta **40**
  ayrı işleme görünür, **747** işleme gizlenir. Suçlama bir özet, tam satır tarihçesi ise
  ayrı bir sorgudur.
- Taşınan satır suçlama açısından yeniden yazılmış sayılır; taşımayı ayrı bir işlemede
  kaydetmek satırın geçmişini korumanın en ucuz yoludur.
- Tarihçenin ortasındaki tek bir biçim geçişi, üstünden az iş geçmiş bir dosyada **37**
  satırın yanıtını kendi üstüne toplar; boşluk yok sayma ve işleme atlama listesi bunu
  tarihçeye dokunmadan geri alır.

#### Sonraki Adım

Bu iki ders de tarihçeye **sonradan** soru sordu. Kusur çoktan girmişti, satır çoktan
yazılmıştı; araçlar yalnızca olmuş bitmiş bir kaydı okudu ve bedeli okuma tarafında ödedi.
Oysa her işleme, tarihçeye girmeden önce birkaç ayrı andan geçer: hazırlık alanından
işlemeye, işlemeden itmeye, itmeden karşı tarafın kabulüne. Sonraki ders bu anlara bakar —
bir denetimin hangi anda araya girebildiği, o anda hangi işlemin hâlâ engellenebilir
olduğu ve engel geç konduğunda bedelin kimin üstünde kaldığı.

### Kancalar

Source: https://academia.sh/tr/kurslar/ileri-git/kancalar

Kanca bir olay noktasıdır ve engelin konduğu an bedeli belirler: işlemeden önce durdurulan değişiklik sıfır nesneye dokunur, itmeden önce on işleme ve 140 nesne, kabulden altı yüz işleme sonra 601 işleme, 3522 nesne ve yedi kopyanın yedisi.

Önceki iki ders tarihçeye sonradan soru sordu: kusur çoktan girmiş, satır çoktan
yazılmıştı. Araçlar olmuş bitmiş bir kaydı okudu ve bedeli okuma tarafında ödedi.

Bir değişiklik ise tarihçeye tek adımda girmez. Önce çalışma alanında durur, sonra hazırlık
alanına alınır, sonra bir işleme olur, sonra itilir, sonra karşı taraf onu kabul eder. Bu
anların her biri bir **kapıdır** ve her kapıya bir denetim yerleştirilebilir. **Kanca
(hook)**, aracın bu anlardan birinde çalıştırdığı programdır; çıkış kodu sıfırdan farklıysa
kimi kapılarda işlem durur. Bu dersin sorusu kancanın ne yaptığı değil: engelin **hangi
kapıya** konduğuna göre bedelin nasıl değiştiği ve o bedeli kimin ödediği.

#### Kanca Bir Olay Noktasıdır

Kanca, deponun kendi dizini içinde belirli adlarla duran çalıştırılabilir dosyalardan
ibarettir. Araç, belirli bir işlemin belirli bir anına geldiğinde o addaki dosyayı arar,
varsa çalıştırır ve çıkış kodunu okur. Ortada bir eklenti düzeneği, bir kayıt defteri ya da
bir yapılandırma dili yoktur; sözleşme yalnızca **dosyanın adı, çalıştırılabilir olması ve
çıkış kodudur.**

Kancaların sürekli tümleştirme hattını tetikleyen kullanımı Sürekli Tümleştirme ve Dağıtım
kursunda kuruldu; orada kanca bir **tetikleyiciydi** ve tartışılan şey hattın kendisiydi. O
tartışma burada tekrarlanmıyor. Bu derste kanca bir **yerel olay noktasıdır** ve ölçülen
tek şey, o noktada hangi işlemin hâlâ durdurulabildiğidir.

İki sınıf vardır ve aralarındaki fark dersin sonucunu belirler. **İstemci tarafı kancalar**
çalışanın kendi deposunda, işlemeden ve itmeden önceki anlarda çalışır. **Sunucu tarafı
kancalar** karşı tarafta, itilen değişiklikler kabul edilmeden önce çalışır. Birincisi
deponun tarihçesinde taşınmaz — klonlama kancaları getirmez — ikincisi ise deponun
tarihçesinden bağımsız olarak her zaman çalışır.

#### Kapıların Sırası

Anlar ve o anlarda çalışan kancalar aşağıdaki sırayı izler. Yalnız bir bölümü engelleme
yetkisi taşır; kalanı olup bittikten sonra haber verir.

```text
# öğretilen dosya adları ve örnek döküm — çalıştırılmamıştır

pre-commit        işleme kurulmadan önce      — engelleyebilir
commit-msg        mesaj yazıldıktan sonra     — engelleyebilir
post-commit       işleme kurulduktan sonra    — engelleyemez
pre-push          itme başlamadan önce        — engelleyebilir
pre-receive       karşı taraf kabul etmeden   — engelleyebilir
update            her başvuru için ayrı ayrı  — engelleyebilir
post-receive      kabul tamamlandıktan sonra  — engelleyemez

# .git/hooks/pre-commit
#!/bin/sh
if git diff --cached --name-only | grep -q '\.bin$'
then
    echo "ikili varlık hazırlık alanında; işleme durduruldu" >&2
    exit 1
fi
exit 0

# örnek döküm
$ git commit -m "sunum yenilendi"
ikili varlık hazırlık alanında; işleme durduruldu
```

Sıradaki iki ayrım önemlidir. `post-` önekli kancalar bir kararı değiştiremez; iş olmuştur
ve kanca yalnız haber verir. Ve istemci tarafındaki her engelleyici kanca, komuta verilen
bir seçenekle atlanabilir — bu bir kusur değil, tasarımdır: yerel kanca çalışanın kendi
kolaylığı içindir, bir yaptırım düzeneği değil.

Ölçümün varsayımları:

- **TA33** — Tarihçe ortak kurgudan üretilir ve bin işlemedir; kurgu ve kâhin
  değiştirilmez.
- **TA34** — Engellenmesi istenen değişiklik **400**. işlemededir. Tek bir değişiklik
  izlenir; kaç değişikliğin engellendiği sayılmaz.
- **TA35** — Bedelin birimi **dokunulan nesnedir**. Bir işlemeyi tarihçeden çıkarmak,
  ondan sonraki her işlemenin kimliğini değiştirir; dokunulan nesne, kimliği değişen
  işlemelerin taşıdığı nesnelerin toplamıdır.
- **TA36** — İtme **onarlı yığınlar** hâlinde yapılır. İtmeden önceki ve sunucudaki
  kancalar bu yüzden dokuz işleme sonra devreye girer.
- **TA37** — Kabul edildikten sonra fark ediliş iki noktada ölçülür: yüz işleme sonra ve
  altı yüz işleme sonra.
- **TA38** — Deponun **yedi** kopyası vardır. Yayımlanmamış bir değişiklik hiçbir kopyayı
  ilgilendirmez; yayımlanmış bir değişikliğin geri alınması kopyaların tümünü ilgilendirir.
- **TA39** — İkinci bölümde tek değişen şey ölçektir. Kancanın çalışma sayısı ile
  incelediği işleme sayısı ayrı ayrı sayılır; kancanın kendi süresi ölçülmez.

#### Ölçüm

```python
"""Kancanin ani: o anda hangi isleme hala engellenebilir.

Bolum 1 - engel bes ayri anda konursa geri almanin bedeli.
Bolum 2 - kancanin kendi bedeli: kac kez calisir, kac isleme inceler.
"""
TOHUM = 20260814
DOSYALAR = ("olcum.py", "rapor.py", "kimlik.py", "ayar.py", "belge.md")
KOPYA, KONUM, YIGIN = 7, 400, 10


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 geri_alma(t, konum, farkedis):
    """konum'daki isleme farkedis'te fark edilirse yeniden yazilacak kume."""
    if farkedis is None:
        return 0, 0
    araya = [x for x in t if konum <= x["no"] <= farkedis]
    return len(araya), sum(x["nesne"] for x in araya)


def yeniden_esitleyen(kopya_sayisi, konum, t, farkedis):
    """Yeniden yazilan tarihceyi kimler yeniden esitlemek zorunda."""
    degisen, _ = geri_alma(t, konum, farkedis)
    return kopya_sayisi if degisen else 0


OLAYLAR = (
    ("işlemeden önce", "evet", None, 0),
    ("itmeden önce", "evet", KONUM + YIGIN - 1, 0),
    ("sunucu kabulünde", "evet", KONUM + YIGIN - 1, 0),
    ("kabulden yüz işleme sonra", "hayır", KONUM + 100, KOPYA),
    ("kabulden altı yüz sonra", "hayır", KONUM + 600, KOPYA),
)

t = tarihce(1000)
print(f"{'engelin konduğu an':>26s} {'engelleyebilir':>14s} "
      f"{'yeniden yazılan':>16s} {'dokunulan nesne':>16s} {'eşitleyen kopya':>16s}")
for ad, engel, farkedis, kopya in OLAYLAR:
    isl, nes = geri_alma(t, KONUM, farkedis)
    print(f"{ad:>26s} {engel:>14s} {isl:16d} {nes:16d} "
          f"{yeniden_esitleyen(kopya, KONUM, t, farkedis):16d}")

print()
print(f"{'işleme':>7s} {'işlemeden önce: çalışma':>24s} {'itmeden önce: çalışma':>22s} "
      f"{'incelenen işleme':>17s}")
for n in (50, 200, 1000, 4000):
    print(f"{n:7d} {n:24d} {n // YIGIN:22d} {n:17d}")
```

```
        engelin konduğu an engelleyebilir  yeniden yazılan  dokunulan nesne  eşitleyen kopya
            işlemeden önce           evet                0                0                0
              itmeden önce           evet               10              140                0
          sunucu kabulünde           evet               10              140                0
 kabulden yüz işleme sonra          hayır              101              522                7
   kabulden altı yüz sonra          hayır              601             3522                7

 işleme  işlemeden önce: çalışma  itmeden önce: çalışma  incelenen işleme
     50                       50                      5                50
    200                      200                     20               200
   1000                     1000                    100              1000
   4000                     4000                    400              4000
```

#### Engelin Konduğu An

Üst tablonun birinci satırı ölçümün çıpasıdır. İşleme kurulmadan durdurulan bir değişiklik
tarihçeye **hiç girmez**: yeniden yazılacak işleme **0**, dokunulan nesne **0**, eşitlemek
zorunda kalan kopya **0**. Değişiklik hâlâ çalışma alanındadır ve düzeltilmesi bir dosya
düzenlemesinden ibarettir.

İkinci ve üçüncü satırlarda işleme kurulmuş, üstüne dokuz işleme daha binmiştir. Geri
almanın bedeli **10** işleme ve **140** dokunulan nesnedir. Yayımlanmadığı için eşitleyen
kopya yine **0**; bedel tümüyle yazanın üstündedir ve tarihçe kendi makinesinde yeniden
yazılabilir.

Dördüncü ve beşinci satırlarda kapı kapanmamıştır. Yüz işleme sonra fark edildiğinde geri
alma **101** işlemenin kimliğini değiştirir ve **522** nesneye dokunur; altı yüz işleme
sonra **601** işleme ve **3522** nesne. Ve eşitleyen kopya artık **0** değil, **7**.
Buradaki sıçrama nesne sütununda değil, en sağdaki sütundadır: **dokunulan nesne yirmi beş
kat büyürken, işi kimin yaptığı bir kişiden yedi kopyanın hepsine geçer.**

Ölçümün çözünürlüğü bin işlemelik kümede **1/1000**'dir; ayırt edilebilen en küçük fark
tek bir işlemedir. Birinci satır ile ikinci satır arasındaki **10** işlemelik fark bu
bandın on katıdır ve rahatça taşınır. Dördüncü satırla beşinci satır arasındaki **500**
işlemelik fark ise ölçeğin yarısıdır; bu kümeyle savunulamayacak tek şey, kapılar arasında
birkaç işlemelik ince ayrımlar yapmaktır.

Örüntü şudur: **engelin bedeli engelin konduğu ana göre değil, konmadığı süreye göre
büyür.** Kapılar arasındaki fark birkaç saniye ya da birkaç saattir; bedel arasındaki fark
sıfırdan üç bin beş yüz yirmi ikiye. Ve bu bedel, bir noktadan sonra artık yazanın
ödeyebileceği bir bedel değildir.

#### Kabulden Sonrası Neden Ayrı Bir Sınıf

Kabul edilmiş bir işlemeyi tarihçeden çıkarmak, tarihçeyi yeniden yazmaktır ve o işlem bu
kursun ilk konusunda kendi bedeliyle kuruldu: geri alınamaz, her kopyanın yeniden
eşitlenmesini gerektirir ve komutu tam biçimde yazılmaz. Burada eklenen tek şey, o bedelin
neden doğduğudur: **engel bir kapı geç kondu.**

Yayımlanmış bir hatanın tarihçeyi yeniden yazmadan da bir karşılığı vardır: değişikliği
**deviren** yeni bir işleme eklemek. Devirme tarihçeyi bozmaz, kimlik değiştirmez, kopyaları
yeniden eşitlemeye zorlamaz — bu yüzden güvenli yoldur ve önce o denenir. Ama devirme
kaydı düzeltir, **nesneyi silmez**. Bir gizli anahtar ya da yanlışlıkla eklenmiş büyük bir
varlık, devirmeden sonra da tarihçedeki nesneler arasında durmaya devam eder ve klonlayan
herkese gitmeyi sürdürür.

Buradan sunucu tarafı kancanın asıl gerekçesi çıkıyor. Sızmış bir gizli değer, depo
düzeltilerek değil, **değerin kendisi geçersiz kılınarak** kurtarılır; tarihçe temizliği
ancak ondan sonra gelen ikinci bir iştir. Kabul kapısı, bu iki işten hiçbirinin gerekmediği son andır.

#### Kancanın Kendi Bedeli

Alt tablo engelin erken konmasının bedava olmadığını gösteriyor. İşlemeden önceki kanca dört
bin işlemelik bir tarihçede **4000** kez çalışır; itmeden önceki kanca onarlı yığınlar
yüzünden **400** kez. İncelenen işleme sayısı ikisinde de **4000**'dir — aynı iş, on kat
farklı sayıda çalışmaya bölünmüş.

Bu bölünmenin bedeli her çalışmanın **sabit maliyetidir**: sürecin başlaması, denetim
aracının yüklenmesi, dizinin taranması. Sabit maliyet incelenen işleme sayısıyla değil,
çalışma sayısıyla çarpılır; erken kapı bu yüzden on katı sabit maliyet öder. Karşılığında
kazandığı şey **geri bildirim mesafesidir**: işlemeden önceki kanca değişikliği üretildiği
anda durdurur, itmeden önceki kanca en kötü durumda dokuz işleme sonra.

İki kapının ölçüde nerede durduğu böylece netleşiyor. Erken kapı ucuz düzeltme ve pahalı
işletme demektir; geç kapı tersi. Yaygın düzen ikisini bölmektir: saniyeler süren ucuz
denetimler işlemeden önceki kapıya, uzun süren pahalı denetimler itmeden önceki kapıya
konur ve yaptırım gerektiren denetimler her iki durumda da kabul kapısında yinelenir.

#### Kancanın Neye Baktığı

Bir kancanın hangi anda çalıştığı, aynı zamanda **neyi görebildiğini** belirler. İşlemeden
önceki kanca hazırlık alanının içeriğini görür; çalışma alanındaki kaydedilmemiş
değişiklikleri değil. Bu ayrım gözden kaçtığında kanca yanlış şeyi denetler: çalışma
alanındaki dosyaları okuyan bir denetim, yalnız bir bölümü hazırlığa alınmış bir
değişiklikte hazırlığa girmemiş satırlara da bakar ve işlemeyi geçerken hazırlıktaki içerik
denetimden hiç geçmemiş olur. Doğru kanca hazırlık alanını okur, dosya sistemini değil.

Kabul kapısındaki iki kanca da çözünürlükleriyle ayrılır. Biri itilen yığının tamamı için
bir kez çalışır ve kararı tüm yığına verir: ya hepsi girer ya hiçbiri. Diğeri her başvuru
için ayrı ayrı çalışır ve bir dalı reddedip diğerini kabul edebilir. Ölçümün onarlı yığın
varsayımı burada karşılık buluyor — yığının tamamını reddeden bir kapı, kusurlu tek bir
işleme yüzünden dokuz kusursuz işlemeyi de geri çevirir. Reddedilen dokuz işleme kaybolmaz,
yazanın tarihçesinde durmayı sürdürür; ama yığının yeniden düzenlenmesi gerekir ve bu,
kabul kapısının erken kapılara göre ödettiği ikinci bedeldir.

Kancanın kendisi için iki kural bundan çıkar. Kanca **hızlı** olmalıdır: her çalışmada
saniyeler süren bir denetim, dört bin çalışmada saatlere dönüşür ve sonunda atlanmaya
başlar. Ve kanca **kararlı** olmalıdır: aynı içeriğe iki kez farklı yanıt veren bir denetim,
engellediği kadar geçirir ve hiçbir güvence taşımaz.

#### Kimin Kancası Çalışır

Son ayrım dersin sonucudur. İstemci tarafı kancalar deponun tarihçesinde taşınmaz; klonlama
onları getirmez, bir işleme onları yayamaz. Ekibin her üyesi kendi deposuna ayrı ayrı
kurmak zorundadır ve kuran da bir seçenekle atlayabilir. Yani istemci kancası, **yedi
kopyanın kaçında kurulu olduğu bilinmeyen** bir denetimdir.

Bu taşınmazlığın kısmi bir karşılığı vardır. Kancalar deponun içinde izlenen sıradan bir
dizine yazılabilir ve aracın kanca dizini bir ayarla oraya çevrilebilir; böylece kancaların
kendisi tarihçeyle taşınır ve ekip aynı denetimi paylaşır. Ama ayarın kurulması yine her
kopyada ayrı bir adımdır ve atlanabilirlik değişmez. Taşınan şey kancanın **içeriğidir**,
yaptırımı değil — yedi kopyanın kaçında etkin olduğu hâlâ bilinmez.

Sunucu tarafı kancası tersidir: tek bir yerde durur, herkes için aynı biçimde çalışır ve
atlanamaz. Yaptırım gerektiren her kural sonunda oraya yazılmak zorundadır. Ama kabul kapısı
aynı zamanda **engelleyebilen son kapıdır** ve o ana gelindiğinde işleme çoktan kurulmuş,
yazanın tarihçesine girmiş, belki üstüne dokuz işleme daha binmiştir. Ölçümün üçüncü satırı
tam olarak burayı gösteriyor: kabul kapısı engelleyebiliyor, ama engellediğinde bile geri
alma bedeli **10** işleme ve **140** nesnedir.

Sonuç şu ikisinin aynı anda doğru olmasıdır: **yaptırımı olan tek kapı, bedeli sıfırlayan
kapı değildir**; bedeli sıfırlayan kapının ise yaptırımı yoktur. İstemci kancası bu yüzden
bir güvence değil, bir kolaylıktır — kabul kapısında zaten reddedilecek bir şeyi yazana beş
yüz yirmi iki nesne önce söyleyen bir kolaylık.

#### Özet

- Kanca bir olay noktasıdır: aracın belirli bir anda çalıştırdığı program ve okuduğu çıkış
  kodu. `post-` önekli kancalar haber verir, karar değiştirmez.
- Engel işlemeden önce konursa değişiklik tarihçeye hiç girmez: **0** işleme, **0**
  dokunulan nesne. İtmeden önce konarsa **10** işleme ve **140** nesne, yayımlanmadığı için
  **0** kopya.
- Kabulden altı yüz işleme sonra fark edilirse geri alma **601** işlemeye ve **3522**
  nesneye dokunur ve **yedi kopyanın yedisi** yeniden eşitlemek zorunda kalır; bedel
  yazanın üstünden çıkıp herkese dağılır.
- Devirme yayımlanmış bir hatayı tarihçeyi bozmadan karşılar ama nesneyi silmez; gizli bir
  değerin karşılığı önce o değerin geçersiz kılınmasıdır.
- Erken kapı dört bin işlemede **4000** kez, itme kapısı **400** kez çalışır; incelenen
  işleme ikisinde de **4000**'dir. Erken kapı on kat sabit maliyet öder, karşılığında geri
  bildirim mesafesini dokuz işlemeden sıfıra indirir.
- İstemci kancası taşınmaz ve atlanabilir, sunucu kancası atlanamaz ama en geç kapıdır;
  yaptırımı olan kapı bedeli sıfırlayan kapı değildir.

#### Sonraki Adım

Bu konu boyunca nesne sayısı hep ölçümün arka planında durdu: aramanın adımını sayarken de,
suçlamanın taramasını sayarken de, kancanın geç kalmasının bedelini sayarken de tarihçe
**tek bir deponun** içindeydi ve nesneler o deponun kendi nesneleriydi. Sonraki konu bu
arka planı öne alıyor: ya nesne sayısı ölçümün zemini değil, **işin kendisi** olursa? Bir
depo başka bir deponun tarihçesini içine aldığında, ya da tek bir dosyanın her sürümü ayrı
bir nesne olarak biriktiğinde, buraya kadar sabit saydığımız arka plan ölçülmesi gereken
şeye dönüşür.

## Büyük Depolar

Bağımlı depoların gömülmesi ve sürüm sabitleme, ikili varlıkların tarihçeye getirdiği ağırlık, aynı depoda paralel çalışma, satır sonu ile birleştirme sürücüsü ayarları, ve tek depo ile çok depo arasındaki ölçek ödünleşimi.

### Alt Modüller

Source: https://academia.sh/tr/kurslar/ileri-git/alt-moduller

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.

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.

```text
# öğ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.

```text
# öğ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

```python
"""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 `.gitmodules` dosyası
  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.

### Büyük Dosya Depolama

Source: https://academia.sh/tr/kurslar/ileri-git/buyuk-dosya-depolama

Tarihçeyi ağırlaştıran işleme sayısı değil nesne türüdür: bin işlemenin onda birinden azı olan 91 ikili işleme toplam nesnenin 0,6777'sini üretir, klon 5640 nesnedir ve ikilisiz 1818'e iner.

Önceki derste nesne sayısı işleme sayısını izliyordu: üç yüz işlemelik alt modül, seksen
işlemelik olandan yaklaşık beş kat fazla nesne getirdi. Oran neredeyse birebirdi çünkü her
işleme aynı ağırlıkta bir kayıt bırakıyordu.

Bu ders sezginin bozulduğu duruma bakar. Aynı tarihçede işlemelerin küçük bir azınlığı
nesnelerin çoğunluğunu üretebilir ve o zaman "tarihçe ne kadar büyük?" sorusunun işleme
sayısıyla verilen yanıtı yanlış olur. Sorumuz şudur: bir tarihçeyi ağırlaştıran şey kaç
işleme yazıldığı mıdır, yoksa o işlemelerin **ne tür nesne** ürettiği midir? Depolama
maliyetinin kendisi burada tartışılmıyor — o eksen İlişkisel Veritabanı Yönetimi ve Bulutta
Depolama ve Veri kurslarında kuruldu. Burada ölçülen tek şey **tarihçedeki nesne payıdır**.

#### İkili Varlık Neden Ayrı Bir Sınıf

Sürüm kontrolü metin dosyalarını **fark** olarak saklayabilir: iki sürüm arasındaki değişen
satırlar, dosyanın tamamından çok daha küçüktür. Bu, bir dosyanın yüz sürümünün yüz kopya
etmemesini sağlar.

İkili varlıklarda bu düzenek çalışmaz. Bir görsel, bir ses kaydı ya da derlenmiş bir çıktı
sıkıştırılmış bir bayt dizisidir; içeriğinde tek bir alan değiştiğinde bayt dizisinin tamamı
değişir. Satır diye bir yapı yoktur, dolayısıyla satır farkı da yoktur. Sonuç şudur: **ikili
varlığın her sürümü tarihçede yeni ve tam bir nesnedir.** Ortak kurgu bunu doğrudan
modelliyor — ikili varlık taşıyan bir işleme, metin işlemesinin **2** nesnesine karşılık
**42** nesne yazıyor.

Bu birikimin geri alınamaz bir yanı var. Bir ikili varlık bir kez işlendiğinde tarihçeye
girer ve sonraki bir işlemede silinmesi onu tarihçeden çıkarmaz; yalnız çalışma ağacından
çıkarır. Klonlayan herkes o nesneyi almaya devam eder, çünkü klon çalışma ağacını değil
**tarihçeyi** getirir.

#### İşaretçi Düzeni

**Büyük dosya depolama (large file storage)**, ikili gövdeyi tarihçenin dışına taşıyan bir
süzgeç düzenidir. Depo özniteliklerinde bir dosya deseni bir süzgeç adına bağlanır; süzgeç
iki yönlü çalışır. **Temizleme süzgeci (clean filter)** dosya işlenirken devreye girer,
gövdeyi ayrı bir depoya yazar ve tarihçeye gövdenin yerine küçük bir **işaretçi dosyası**
koyar. **Açma süzgeci (smudge filter)** dosya çalışma ağacına yazılırken devreye girer,
işaretçiyi okur ve gövdeyi ayrı depodan getirir.

```text
# öznitelik dosyası ve işaretçi içeriği — örnek döküm, çalıştırılmamıştır

# .gitattributes
*.bin  filter=buyuk-dosya -text
*.png  filter=buyuk-dosya -text

# tarihçeye giren işaretçi dosyası (gövde değil)
surum https://<süzgeç-belirtimi>/v1
ozet  sha256:<gövdenin özeti>
boyut 41943040
```

Tarihçede duran şey bu üç satırlık metindir. `-text` niteliği dosyayı ikili olarak
işaretler ve satır sonu dönüşümünün ona uygulanmasını engeller — o ayrım bu konunun dördüncü
dersinde ölçülüyor. Süzgecin adı bir ürün adı değil, yapılandırmada tanımlanan bir addır;
aynı desen başka bir süzgece de bağlanabilir.

Düzenin tek gerçek kazancı şudur: **klon artık her sürümü değil, yalnız işaretçileri
getirir.** Gövde, çalışma ağacına gerçekten yazılacak sürüm için ve yalnız o sürüm için
istenir.

#### Ölçümün Varsayımları

- **BD7** — Ölçüm ortak kurgunun dört ölçeğini olduğu gibi kullanır: **50, 200, 1000, 4000**
  işleme. İkili varlık taşıyan işlemeler kurgunun kendi dağılımından gelir; seçilmez.
- **BD8** — Metin işlemesi **2** nesne yazar (ağaç ve damla). İkili varlık taşıyan işleme
  bunlara **40** nesne ekler; bu, gövdenin o sürümünün tarihçedeki karşılığıdır.
- **BD9** — İşaretçi düzeninde ikili gövde tarihçenin dışına çıkar ve yerine **1** nesnelik
  işaretçi damlası kalır; ikili işleme **3** nesne yazar.
- **BD10** — "Ayrı depo" ölçümün dışındadır. Sayılan tek şey **tarihçedeki nesne**;
  gövdelerin dışarıda ne kadar yer kapladığı bu ölçünün konusu değildir.
- **BD11** — Klondan sonra çalışabilmek için tek bir ikili sürümün gövdesi gerekir; ölçüm bunu
  **40** nesne olarak klonun üstüne ekler.
- **BD12** — "İkilisiz" sütunu, ikili varlık taşıyan işlemelerin **hiç yazılmamış** olduğu
  durumu verir; bu bir temizlik sonucu değil, karşılaştırma tabanıdır.
- **BD13** — Bedel **dokunulan nesne** birimiyle sayılır. Bayt, disk ve ağ süresi ölçümün
  dışındadır.

#### Ölçüm

```python
"""Buyuk dosya depolama: agirligi uretenin isleme sayisi mi nesne turu mu.

Bolum 1 - dort olcekte ikili isleme payi ve nesne payi.
Bolum 2 - ayni tarihce isaretci duzeniyle: klon nesnesi nereye iniyor.
"""
TOHUM = 20260814
DOSYALAR = ("olcum.py", "rapor.py", "kimlik.py", "ayar.py", "belge.md")
OLCEKLER = (50, 200, 1000, 4000)
ISARETCI = 1        # isaretci damlasi: ikili govdenin yerine gecen tek nesne
IKILI_GOVDE = 40    # ortak kurguda bir ikili surumun nesnesi


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 isaretci_bedeli(t):
    """Ikili govde disariya tasinir; tarihcede tek isaretci damlasi kalir."""
    return sum(2 + (ISARETCI if x["ikili"] else 0) for x in t)


def calisan_kopya(t):
    """Klondan sonra calismak icin gereken tek ikili surum."""
    return IKILI_GOVDE if any(x["ikili"] for x in t) else 0


print("isleme  ikili isleme  ikili payi  klon nesnesi  ikilisiz  ikili nesne  nesne payi")
for n in OLCEKLER:
    t = tarihce(n)
    ikili = sum(1 for x in t if x["ikili"])
    tam, dus = klon_bedeli(t), klon_bedeli(t, False)
    print(f"{n:6d} {ikili:13d} {ikili / n:11.4f} {tam:13d} {dus:9d} "
          f"{tam - dus:12d} {(tam - dus) / tam:11.4f}")
print()
print("isleme  tarihcede klon  isaretci duzeni  + tek surum  kazanilan nesne   kat")
for n in OLCEKLER:
    t = tarihce(n)
    tam, isaretci = klon_bedeli(t), isaretci_bedeli(t)
    calisir = isaretci + calisan_kopya(t)
    print(f"{n:6d} {tam:15d} {isaretci:16d} {calisir:12d} {tam - calisir:16d} "
          f"{tam / calisir:5.2f}")
print()
n = 1000
t = tarihce(n)
ikili = sum(1 for x in t if x["ikili"])
tam, dus = klon_bedeli(t), klon_bedeli(t, False)
print(f"tarihce {n} isleme, ikili varlik tasiyan {ikili}, toplam nesne {tam}, "
      f"ikili payi {(tam - dus) / tam:.4f}")
print(f"metin islemesi {n - ikili} silinse kazanilan nesne {dus}; "
      f"ikili isleme {ikili} silinse kazanilan nesne {tam - dus}")
```

```
isleme  ikili isleme  ikili payi  klon nesnesi  ikilisiz  ikili nesne  nesne payi
    50             7      0.1400           380        86          294      0.7737
   200            13      0.0650           920       374          546      0.5935
  1000            91      0.0910          5640      1818         3822      0.6777
  4000           365      0.0912         22600      7270        15330      0.6783

isleme  tarihcede klon  isaretci duzeni  + tek surum  kazanilan nesne   kat
    50             380              107          147              233  2.59
   200             920              413          453              467  2.03
  1000            5640             2091         2131             3509  2.65
  4000           22600             8365         8405            14195  2.69

tarihce 1000 isleme, ikili varlik tasiyan 91, toplam nesne 5640, ikili payi 0.6777
metin islemesi 909 silinse kazanilan nesne 1818; ikili isleme 91 silinse kazanilan nesne 3822
```

#### Nesne Sayısı İşleme Sayısını İzlemez

Üçüncü satır kursun dördüncü okumasını ödüyor. Bin işlemelik tarihçede ikili varlık taşıyan
işleme sayısı **91**'dir — işlemelerin **0,0910**'u, yani onda birinden azı. Aynı 91 işleme
toplam nesnenin **0,6777**'sini üretiyor. Kalan **909** işleme, yani tarihçenin onda dokuzuna
yakını, nesnelerin yalnız üçte birini yazıyor.

Son satır bunu bir düşünce deneyiyle keskinleştiriyor. Dokuz yüz dokuz metin işlemesinin
tümü silinseydi tarihçeden **1818** nesne düşerdi. Doksan bir ikili işleme silinseydi **3822**
nesne düşerdi — iki katından fazlası, onda birinden az işlemeyle. **Tarihçeyi ağırlaştıran
şey işleme sayısı değil, nesne türüdür.** Bu, konunun ilk dersindeki durumun tam tersidir:
orada bedeli belirleyen tarihçenin boyuydu, burada bileşimi.

Üst tablo bir uyarı da taşıyor. Nesne payı dört ölçekte **0,7737**, **0,5935**, **0,6777** ve
**0,6783** çıkıyor; sıralı bir eğilim yok. Nedeni sağdaki değil soldaki sütunda: elli
işlemelik tarihçede ikili işleme sayısı **7**'dir ve bu ölçekte ölçülebilen en küçük fark
**1/50 = 0,0200**'dür. Tek bir işlemenin yer değiştirmesi payı iki puan oynatır. Bin ve dört
bin işlemede pay **0,6777** ile **0,6783** arasında oturuyor; asıl değer budur ve küçük
ölçekteki dağılım ondan bir sonuç çıkarmaya elverişli değildir.

#### İşaretçi Düzeninin Ödediği

Alt tablonun birimi yine **dokunulan nesnedir**. Bin işlemelik tarihçede klon **5640**
nesneden **2091** nesneye iniyor; çalışmak için gereken tek ikili sürüm eklenince **2131**.
Kazanılan nesne **3509**, kat **2,65**. Dört bin işlemede kazanç **14195** nesneye çıkıyor ve
kat **2,69**'da kalıyor — düzenin kazancı ölçekle birlikte büyüyor ama **oranı** sabitleniyor,
çünkü kazanç doğrudan ikili işleme payına bağlı.

İki yüz işlemelik satır kattan düşük çıkıyor: **2,03**. Nedeni üst tabloda yazılı — o ölçekte
ikili işleme payı **0,0650** ile en düşük değerinde. Kat, doğrudan bu payın işlevidir ve
bağımsız bir ölçüt değildir. Aynı düzen, ikili varlık hiç taşımayan bir depoda **hiçbir şey**
kazandırmaz; kazandığını sandıran her sayı, aslında o deponun ikili payını ölçmektedir.

Kazancın nereden gelmediğine dikkat etmek gerekir. İşaretçi düzeni hiçbir işlemeyi
kaldırmıyor; tarihçe hâlâ bin işleme. Kaldırdığı şey **her ikili sürümün gövdesidir** ve bu
gövdeler yok olmuyor, yalnız tarihçenin dışına, ayrı bir depoya taşınıyor. Düzenin bedeli de
oradadır: klonlayan taraf artık iki kaynağa birden erişmek zorundadır ve ikinci kaynağa
erişemezse tarihçesi eksiksiz olduğu hâlde çalışma ağacını kuramaz. Alt modülde ölçülen
bağımlılığın bir başka biçimidir bu — orada eksik olan bir tarihçeydi, burada bir gövde
deposu.

Ölçünün görmediği bir eksen de var ve adının konması gerekir. Nesne birimi bir gövdenin **kaç
bayt** olduğunu sormaz; kurguda bir ikili sürüm **40** nesnedir ve bu sayı gövdenin
büyüklüğünden bağımsızdır. Gerçek bir depoda büyük bir gövde ile küçük bir gövde aynı nesne
sayısını üretir ama aynı bedeli ödetmez. Bu ders nesne payını ölçüyor; bayt ekseni ölçünün
dışındadır ve tablodan bir disk sonucu çıkarılamaz.

İkinci bir sınır: düzen ancak **baştan** kurulduğunda tam kazanç verir. Süzgeç bugün
tanımlanırsa bugünden sonraki işlemelerin gövdeleri dışarı çıkar; tarihçede zaten duran
**3822** nesne yerinde kalır ve her klon onları getirmeye devam eder.

#### İkilinin Birleştirilememesi

Nesne sayısının yanında ikinci bir sonuç daha var ve o tarihçede değil, çalışmada ödeniyor.
İki dal aynı ikili varlığın ayrı sürümlerini yazdığında birleştirme çakışması doğar ve
çakışma **çözülemez**: birleştirme, iki metnin satırlarını harmanlayarak çalışır, ikili
gövdede harmanlanacak satır yoktur. Elde kalan tek karar, iki sürümden birini seçmektir.

Bu yüzden ikili desenlere `-merge` niteliği de verilir; öznitelik, aracın harmanlamayı
denemesini engeller ve doğrudan seçim ister. `-diff` niteliği aynı gerekçenin görüntüleme
tarafıdır: iki ikili gövdeyi satır satır karşılaştırmanın anlamı yoktur, çıktı okunmaz olur.
Bu iki niteliğin ayarlanmadığı durumda ne kadar gereksiz iş doğduğu konunun dördüncü
dersinde ölçülüyor.

#### Klonun Kendisini Daraltmak

İşaretçi düzeni nesneyi tarihçenin dışına taşır. Aynı bedele başka bir açıdan giren iki
düzenek daha vardır ve ikisi de nesneyi yerinde bırakıp **ne zaman getirileceğini**
değiştirir.

```text
# öğretilen komutlar — örnek döküm, çalıştırılmamıştır

git clone --filter=blob:none <depo-adresi>
git clone --depth 1 <depo-adresi>
git sparse-checkout set bilesenler/olcum-cekirdegi
```

**Kısmi klon** damlaları klon anında getirmez; işleme ve ağaç nesneleri gelir, damlalar ancak
bir dosya gerçekten okunduğunda istenir. **Sığ klon** tarihçeyi belirli bir derinlikte keser
ve daha eski işlemeleri hiç getirmez. **Seyrek çıkarma** ise nesne deposuna değil çalışma
ağacına bakar: tarihçe eksiksiz gelir, çalışma ağacına yalnız seçilen yollar yazılır.

Üçünün de ortak yanı bir erteleme olmalarıdır: nesne hâlâ tarihçededir ve gerektiğinde
istenir. İşaretçi düzeni bundan farklıdır, gövdeyi tarihçeden **çıkarır**. Bu ders ikincisini
ölçüyor; ilk üçü aynı birimle ölçülebilir ama başka bir kurgu ister, çünkü kazançları depoya
değil erişim örüntüsüne bağlıdır. Sığ klonun ayrı bir sınırı da vardır: kesilen tarihçe
üzerinde ikili arama ve suçlama, kesilen aralığı hiç göremez.

#### Geriye Dönük Temizlik ve Kurtarma

Var olan bir tarihçeden ikili gövdeleri çıkarmak yalnız bir yolla olur: **tarihçeyi yeniden
yazarak.** Bu, konunun birinci dersinde ölçülen işlemdir ve kuralları burada da geçerlidir.

İşlem her ikili işlemenin ve ondan sonraki her işlemenin kimliğini değiştirir; bin işlemelik
tarihçede ilk ikili işleme erken bir noktadaysa **neredeyse bütün kimlikler** değişir.
**Geri alınamaz:** eski kimlikler artık hiçbir şeyi göstermez, o kimliklere dayanan her
etiket, her sabitlenmiş sürüm ve her dış atıf kopar. Depoyu klonlamış her kopya **yeniden
klonlamak** zorundadır; eski kopyadan itilen tek bir dal, silinen gövdeleri geri getirir ve
işlem baştan yapılır. Komutun tam biçimi burada verilmiyor, çünkü yanlış aralıkla
çalıştırıldığında kaybı bildiren bir uyarı yoktur.

Kurtarma yolları önceden kurulur, sonradan değil. **Birincisi:** işlem çalıştırılmadan önce
deponun eksiksiz bir kopyası ayrı bir yerde tutulur; bu kopya yeni tarihçeyle
eşitlenmediği sürece eski kimliklerin tek kaynağıdır. **İkincisi:** dönüşüm önce bu ayrı
kopyada denenir ve sonuç sayılır — kaç işlemenin kimliği değişti, kaç nesne düştü.
**Üçüncüsü:** yerelde yanlış giden bir dönüşümden sonra referans günlüğü, çöp toplama
penceresi kapanmadan eski uçları geri verir. Pencere kapandığında bu yol da kapanır.
**Dördüncüsü ve en ucuzu:** deseni öznitelik dosyasına deponun ilk gününde yazmak. Kazanç
tabloda okunuyor; bedeli, yalnızca baştan kurulduğunda ödenmemiş olması.

#### Özet

- İkili varlık satır farkına elverişli değildir; her sürümü tarihçede yeni ve tam bir nesne
  olarak birikir ve bir kez işlendikten sonra silinmesi onu tarihçeden çıkarmaz.
- Bin işlemelik tarihçede ikili varlık taşıyan **91** işleme vardır — işlemelerin **0,0910**'u
  — ve toplam nesnenin **0,6777**'sini üretir; klon **5640** nesne, ikilisiz **1818**'dir.
- **909** metin işlemesi silinse **1818** nesne düşer, **91** ikili işleme silinse **3822**:
  tarihçeyi ağırlaştıran işleme sayısı değil, nesne türüdür.
- İşaretçi düzeni bin işlemede klonu **5640**'tan **2131** nesneye indirir (**2,65** kat) ama
  hiçbir işlemeyi kaldırmaz; gövdeler ayrı bir depoya taşınır ve ikinci bir erişim koşulu
  doğar.
- Geriye dönük temizlik tarihçeyi yeniden yazar, **geri alınamaz** ve her kopyanın yeniden
  klonlanmasını gerektirir; güvenli yol, ayrı bir kopyada denemek ve deseni deponun ilk
  gününde yazmaktır.

#### Sonraki Adım

İşaretçi düzeni klon bedelini üçte bire indirdi ama tabloda hâlâ **klon** yazıyor: bedel her
seferinde yeniden ödeniyor. Aynı depoda iki dal üzerinde birlikte çalışmak gerektiğinde
alışılmış çözüm ikinci bir klondur ve o klon nesnelerin tamamını yeniden kopyalar. Sonraki
ders bu varsayımı sorgular: aynı deponun nesne deposunu paylaşan ikinci bir çalışma alanı
kurulabilir mi ve kurulursa dal başına klonla karşılaştırıldığında kaç nesne kopyalanmamış
olur?

### Çoklu Çalışma Ağacı

Source: https://academia.sh/tr/kurslar/ileri-git/coklu-calisma-agaci

Ek çalışma ağacı nesne deposunu paylaşır ve 0 nesne kopyalar: bin işlemelik tarihçede dört dal için klon düzeni 22560 nesne yazarken ağaç düzeni 5640'ta kalır, kazanılan 16920 nesnenin 11466'sı ikilidir.

Önceki ders klon bedelini üçte bire indirdi ama bedeli ortadan kaldırmadı: tabloda hâlâ
**klon** yazıyordu ve klon her yapıldığında yeniden ödeniyordu. Bu, bir varsayımı da
beraberinde taşır — aynı depoda iki dal üzerinde birlikte çalışmak için ikinci bir kopya
gerektiği varsayımını.

Varsayım doğru değildir. Deponun iki bileşeni vardır ve ayrı ayrı çoğaltılabilirler: bir
**nesne deposu** ve bir **çalışma ağacı**. Klon ikisini birden kopyalar. Bu dersin sorusu
şudur: nesne deposu tek bırakılıp çalışma ağacı çoğaltılırsa, dal başına klonla
karşılaştırıldığında kaç nesne kopyalanmamış olur?

#### Bir Nesne Deposu, Birden Çok Ağaç

**Çalışma ağacı (worktree)**, deponun bir işlemesinin dosya sistemine yazılmış hâlidir.
**Çoklu çalışma ağacı**, aynı nesne deposuna bağlı birden çok çalışma ağacı kurmayı
sağlayan düzendir. Ek ağaç bir dizin olarak açılır, içine deponun dizini değil ana depoyu
gösteren küçük bir dosya konur ve ağaç o andan itibaren nesnelerini ana depodan okur.

```text
# öğretilen komutlar — örnek döküm, çalıştırılmamıştır

git worktree add ../agac-rapor rapor
git worktree add --detach ../agac-inceleme <işleme-kimliği>
git worktree list
git worktree remove ../agac-rapor
git worktree prune
```

`add` yeni dizini açar ve verilen dalı orada çıkarır. `--detach` bir dalı değil doğrudan bir
işlemeyi çıkarır; ağaç ayrık HEAD durumunda durur ve bu, geçici bir inceleme için istenen
durumdur. `list` bütün ağaçları ve her birinin hangi dalda olduğunu bildirir. `remove` ağacı
kaldırır, `prune` ise dizini elle silinmiş ağaçların yönetim kaydını temizler.

Bir kısıt baştan bilinmelidir: **bir dal aynı anda yalnız bir ağaçta çıkarılabilir.** Aynı
dalı ikinci bir ağaçta çıkarmaya çalışmak reddedilir. Kısıt keyfî değildir — iki ağaç aynı
dala işleme yazsaydı, dalın hangi ucu gösterdiği ağaca göre değişirdi ve başvuru tekliğini
kaybederdi.

#### Neyin Paylaşıldığı

Ayrım tek cümleyle kurulur: **tarihçeye ait olan paylaşılır, çalışmaya ait olan ağaca
özeldir.**

Paylaşılan taraf nesne deposu ve başvurulardır. Bir ağaçta yazılan işleme nesne olarak
deponun içine düşer ve o andan itibaren öbür ağaçlardan **erişilebilir** — hiçbir aktarım
gerekmez. Dallar, etiketler ve referans günlüğü de ortaktır.

Ağaca özel taraf çalışma durumudur: `HEAD` başvurusu, hazırlık alanı ve çalışma alanındaki
dosyalar. Her ağaç kendi `HEAD`'ini tutar, dolayısıyla ayrı bir dalda durabilir; her ağaç
kendi hazırlık alanını tutar, dolayısıyla birinde hazırlanmış bir değişiklik öbüründe
görünmez. Kaydedilmemiş bir değişiklik ağacın içinde kalır ve paylaşılmaz.

Yapılandırma ikisinin arasında durur. Deponun yapılandırma dosyası ortaktır ve bir ağaçta
yapılan değişiklik hepsini etkiler; bir ayarı yalnız bir ağaca özel kılmak ayrıca
açılması gereken bir seçenektir. Depo öznitelikleri de ortaktır — sonraki dersin konusu olan
o dosya işlenen bir dosyadır ve tarihçeye aittir, dolayısıyla bütün ağaçlarda aynı kuralı
uygular.

Bu ayrım ölçümün kurgusunu doğrudan verir: ek bir ağaç **nesne kopyalamaz**, yalnız
yönetim kaydı yazar ve çalışma alanına dosyaları çıkarır. Klon ise nesne deposunun tamamını
kopyalar.

#### Ölçümün Varsayımları

- **BD14** — Ölçüm ortak kurgunun dört ölçeğini kullanır. Aynı iş, aynı sayıda dal üzerinde,
  iki ayrı düzende yapılır; üretilen işleme ve nesne kümesi ikisinde de aynıdır.
- **BD15** — Klon düzeninde her dal için ayrı bir klon açılır ve her klon nesne deposunun
  **tamamını** kopyalar; kısmi klon ve sığ klon bu ölçümde kullanılmaz.
- **BD16** — Ağaç düzeninde nesne deposu tektir; ek ağaç **0 nesne** kopyalar. Yazdığı tek
  şey ağaç başına **3** yönetim kaydıdır ve bu kayıtlar nesne değildir, ayrı sayılır.
- **BD17** — Çalışma alanına çıkarılan dosyalar iki düzende de aynıdır; dört dal her iki
  düzende de dört dosya kümesi materyalize eder. Bu yüzden ölçüm dışıdır.
- **BD18** — "Kopyalanmayan ikili", kazanılan nesnenin ikili gövdelerden gelen payıdır;
  önceki dersin nesne türü ayrımıyla aynı sayımdır.
- **BD19** — Birinci ve ikinci bölümün birimi **dokunulan nesnedir**. Üçüncü bölümün birimi
  **adımdır** ve bir adım, bir dalın ucunu bir kopyadan öbürüne taşıyan tek bir getirmedir.

#### Ölçüm

```python
"""Coklu calisma agaci: nesne paylasiminin dal basina klona gore kazandirdigi.

Bolum 1 - dort agac, dort olcekte: klon duzeni ve agac duzeni nesnesi.
Bolum 2 - agac sayisi buyurken kazanc (1000 islemelik tarihce).
Bolum 3 - bir agacta yazilan islemeye obur agactan erisim: birim adim.
"""
TOHUM = 20260814
DOSYALAR = ("olcum.py", "rapor.py", "kimlik.py", "ayar.py", "belge.md")
OLCEKLER = (50, 200, 1000, 4000)
AGACLAR = (1, 2, 4, 8)
YONETIM_KAYDI = 3   # ek agac basina yazilan yonetim kaydi; nesne kopyalamaz


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 klon_duzeni(t, agac):
    """Dal basina klon: her dal kendi nesne deposunu kopyalar."""
    return agac * klon_bedeli(t)


def agac_duzeni(t, agac):
    """Coklu calisma agaci: tek nesne deposu, ek agaclar nesne kopyalamaz."""
    return klon_bedeli(t)


def erisim_adimi(agac, duzen):
    """Bir agacta yazilan islemeye obur agaclardan erisim: getirme adimi."""
    return 0 if duzen == "agac" else agac - 1


print("isleme  klon nesnesi  4 klon nesnesi  4 agac nesnesi  kazanilan nesne"
      "  kopyalanmayan ikili")
for n in OLCEKLER:
    t = tarihce(n)
    k, a = klon_duzeni(t, 4), agac_duzeni(t, 4)
    ikili = 3 * (klon_bedeli(t) - klon_bedeli(t, False))
    print(f"{n:6d} {klon_bedeli(t):13d} {k:15d} {a:15d} {k - a:16d} {ikili:20d}")
print()
t = tarihce(1000)
print("agac  klon duzeni nesne  agac duzeni nesne  kazanilan nesne  ek agac basina nesne"
      "  yonetim kaydi")
for agac in AGACLAR:
    k, a = klon_duzeni(t, agac), agac_duzeni(t, agac)
    ek = (k - klon_bedeli(t)) // (agac - 1) if agac > 1 else 0
    print(f"{agac:4d} {k:18d} {a:18d} {k - a:16d} {ek:21d} "
          f"{(agac - 1) * YONETIM_KAYDI:14d}")
print()
print("agac  klon duzeninde getirme adimi  agac duzeninde getirme adimi")
for agac in AGACLAR:
    print(f"{agac:4d} {erisim_adimi(agac, 'klon'):29d} "
          f"{erisim_adimi(agac, 'agac'):29d}")
print()
print(f"tek nesne deposu {klon_bedeli(t)} nesne; dort agac ayni depoyu paylasiyor, "
      f"ek agaclarin kopyaladigi nesne {agac_duzeni(t, 4) - klon_bedeli(t)}")
print(f"ayni is dort klonla yapilsaydi kopyalanan nesne "
      f"{klon_duzeni(t, 4) - klon_bedeli(t)}")
```

```
isleme  klon nesnesi  4 klon nesnesi  4 agac nesnesi  kazanilan nesne  kopyalanmayan ikili
    50           380            1520             380             1140                  882
   200           920            3680             920             2760                 1638
  1000          5640           22560            5640            16920                11466
  4000         22600           90400           22600            67800                45990

agac  klon duzeni nesne  agac duzeni nesne  kazanilan nesne  ek agac basina nesne  yonetim kaydi
   1               5640               5640                0                     0              0
   2              11280               5640             5640                  5640              3
   4              22560               5640            16920                  5640              9
   8              45120               5640            39480                  5640             21

agac  klon duzeninde getirme adimi  agac duzeninde getirme adimi
   1                             0                             0
   2                             1                             0
   4                             3                             0
   8                             7                             0

tek nesne deposu 5640 nesne; dort agac ayni depoyu paylasiyor, ek agaclarin kopyaladigi nesne 0
ayni is dort klonla yapilsaydi kopyalanan nesne 16920
```

#### Paylaşımın Kazandırdığı

Birinci tablonun birimi **dokunulan nesnedir**. Bin işlemelik tarihçede dört dal üzerinde
çalışmak, klon düzeninde **22560** nesne yazdırıyor; ağaç düzeninde toplam **5640**'ta
kalıyor. Kazanılan nesne **16920** — üç klonun tamamı. Dört bin işlemede aynı hesap **67800**
nesne veriyor.

Kazancın nereden geldiği son sütunda yazılı. Bin işlemede kazanılan **16920** nesnenin
**11466**'sı ikili gövdelerden geliyor; önceki dersin **0,6777**'lik payı buraya da aynen
düşüyor. Bir depoda ikili varlık ne kadar çoksa, ikinci bir klon açmanın bedeli o kadar
büyüktür — ve o bedelin tamamı, paylaşılan bir nesne deposuyla **hiç ödenmez**.

Küçük ölçeklerde de örüntü aynı ama büyüklükler yanıltıcı olabilir. Elli işlemelik tarihçede
kazanç **1140** nesnedir; bu, dört bin işlemedeki **67800**'ün yanında küçük görünür ama iki
düzen arasındaki oran her satırda birebir aynıdır. Kazanç doğrudan `(ağaç − 1) × klon`
çarpımıdır; ölçek yalnız çarpanı büyütür, ilişkiyi değiştirmez. Bu ölçekte ölçülebilen en
küçük fark **1/50**'dir ve tablodaki hiçbir sayı o çözünürlüğün altında bir iddiaya
dayanmıyor.

İkinci tablo aynı şeyi ağaç sayısıyla veriyor ve orta sütun sabit kalıyor: iki ağaç, dört
ağaç, sekiz ağaç — hepsinde **5640**. Ek ağaç başına kopyalanan nesne her satırda **0**'dır;
sağdaki **5640**, klon düzeninin ek kopya başına ödediğidir. Ağaç düzeninde ödenen tek şey
sağ sondaki yönetim kaydıdır: sekiz ağaç için **21** kayıt. Bunlar nesne değildir ve
tarihçeye girmezler.

Buradan çıkan ölçüt tek cümledir: **çalışma ağacı sayısı nesne deposunu büyütmez.** Klon
düzeninde bedel ağaç sayısıyla doğrusal büyür, ağaç düzeninde sabittir. Bu, kursta ölçülen
bedeller arasında ölçekten **tamamen** bağımsız olan tek örüntüdür: ikili arama ölçekle yavaş
büyüyordu, yeniden yazma oranı sabitti ama toplamı büyüyordu; burada ek kopyanın nesne bedeli
her ölçekte ve her ağaç sayısında **sıfırdır**.

#### Görünürlük ve Getirme Adımı

Üçüncü tablonun birimi **adımdır** ve ölçtüğü şey nesne değil, erişimdir.

Klon düzeninde bir dala yazılan işleme, o klonun nesne deposunda durur. Öbür kopyaların ona
erişmesi için bir getirme gerekir; dört kopyalı bir düzende bir işlemenin hepsine ulaşması
**3** adımdır, sekiz kopyalıda **7**. Ağaç düzeninde bu sayı her satırda **0**'dır — işleme
zaten ortak nesne deposundadır ve öbür ağaç onu yazıldığı anda görür.

Bu, düzenin nesne sayısından bağımsız ikinci kazancıdır ve pratikte daha çok fark eder. Bir
ağaçta bir düzeltme yazılıp öbür ağaçta hemen sınanabilir; kiraz toplama, karşılaştırma ve
birleştirme işlemleri ağaçlar arasında **ağa çıkmadan** yapılır. Klon düzeninde aynı işler bir
uzak depo turu ister.

Sınır da aynı yerden gelir. Ortak nesne deposu, ortak bir hata yüzeyi demektir: bir ağaçta
yapılan çöp toplama bütün ağaçları ilgilendirir ve bir ağaçta bozulan depo hepsini birden
etkiler. Klon düzeninde kopyalar birbirinden yalıtılmıştır ve bu yalıtım, ödenen **16920**
nesnenin karşılığında alınan tek şeydir.

#### Üçüncü Düzen: Tek Ağaçta Geçiş

Ölçüm iki düzeni karşılaştırdı ama pratikte en yaygın olanı üçüncüsüdür: tek çalışma ağacı ve
dallar arasında geçiş. Bu düzen **0** ek nesne kopyalar — ağaç düzeniyle aynı — ve **0**
getirme adımı ister. Nesne birimiyle bakıldığında en ucuz düzendir.

Ödediği bedel başka bir yerdedir. Her geçiş çalışma alanındaki dosyaları yeniden yazar;
kaydedilmemiş bir değişiklik varsa geçiş ya engellenir ya da değişiklik taşınır. Dallanma ve
İşbirliği kursunda bu durum tek tek sayılmıştı: hangi değişikliğin taşındığı, hangisinin
engellendiği ve hangisinin geride kaldığı orada ölçüldü, burada tekrarlanmıyor. Zula, bu
engeli aşmanın standart yoludur — kaydedilmemiş değişikliği bir kenara alır ve geçişten sonra
geri açar.

Çoklu çalışma ağacının çözdüğü şey tam olarak budur: **geçiş yoktur.** İki dal aynı anda,
iki ayrı dizinde açıktır; birinde bir sınama sürerken öbüründe düzenleme yapılabilir. Zula
gerekmez, çünkü kaydedilmemiş değişikliğin yerini bırakması gerekmez.

Buna karşılık her ağaç kendi çalışma durumunu materyalize eder ve bu yalnız dosyalarla
sınırlı değildir. Bağımlılık dizinleri, derleme çıktıları ve önbellekler ağaç başına yeniden
oluşur; bunlar tarihçeye ait olmadıkları için ölçümün dışındadır ama diskte gerçekten yer
kaplarlar ve dört ağaçlı bir düzende dört kez üretilirler. Nesne birimiyle kazanılan
**16920**, bu maliyeti kapsamaz. İki düzen arasındaki seçim bu yüzden tek sayıdan çıkmaz:
ölçülen nesne kazancı gerçek ve büyüktür, ölçülmeyen çalışma durumu ise ağaç sayısıyla
büyür.

#### Ağacın Kaldırılması ve Kurtarma

Bir çalışma ağacı silindiğinde nesneler silinmez — nesneler ağaca ait değildi. Kaybolabilecek
tek şey **o ağaçta kaydedilmemiş** olandır: çalışma alanındaki değişiklikler ve hazırlık
alanının içeriği. `remove` komutu ağaçta kaydedilmemiş değişiklik varsa reddeder; dizinin
elle silinmesi hiçbir şey sormaz. Bu iki yol arasındaki fark, uyarının olup olmamasıdır.

İkinci kayıp yolu daha sessizdir. Ayrık HEAD durumundaki bir ağaçta yazılan işleme hiçbir dala
bağlı değildir; ağaç kaldırıldığında o işleme erişilemez hâle gelir ve çöp toplama penceresi
kapandığında düşer. **Kurtarma yolu:** referans günlüğü ortaktır, dolayısıyla işlemenin ucu
pencere kapanmadan başka bir ağaçtan okunabilir ve bir dala bağlanabilir. Daha ucuz yolu, o
ağacı `--detach` ile değil bir dal adıyla açmaktır — dal bir başvurudur ve başvuru, ağacın
ömründen bağımsızdır.

Çıkarılabilir bir ortamda ya da geçici olarak bağlanan bir dizinde duran ağaç için ayrı bir
önlem vardır: ağaç **kilitlenir**. Kilitli bir ağacın yönetim kaydı, dizin erişilemez olduğunda
bile temizlenmez; aksi hâlde temizleme işlemi ağacı yok sayar ve o ağaçtaki dal başka bir yerde
çıkarılabilir hâle gelir. Kilit, kaybı değil **yanlış tanıyı** önler.

Üçüncüsü yönetim kaydının kendisidir: dizini elle silinmiş bir ağacın kaydı depoda kalır ve o
dalı başka bir ağaçta çıkarmayı engellemeye devam eder. `prune` bu kayıtları temizler ve
hiçbir nesneye dokunmaz.

#### Özet

- Depo iki bileşendir: **nesne deposu** ve **çalışma ağacı**. Klon ikisini birden kopyalar;
  çoklu çalışma ağacı yalnız ikincisini çoğaltır.
- Nesne deposu, dallar, etiketler ve referans günlüğü paylaşılır; `HEAD`, hazırlık alanı ve
  çalışma alanı ağaca özeldir. Bir dal aynı anda yalnız bir ağaçta çıkarılabilir.
- Bin işlemelik tarihçede dört dal için klon düzeni **22560** nesne yazar, ağaç düzeni
  **5640**'ta kalır; kazanılan **16920** nesnenin **11466**'sı ikili gövdelerden gelir.
- Ek ağaç başına kopyalanan nesne her ölçekte **0**'dır; ağaç düzeninde ödenen tek şey ağaç
  başına **3** yönetim kaydıdır ve nesne deposu ağaç sayısıyla büyümez.
- Adım biriminde: bir işlemenin bütün kopyalara ulaşması klon düzeninde **3** ve **7** getirme
  ister, ağaç düzeninde **0**; karşılığında kaybedilen şey kopyalar arasındaki yalıtımdır.

#### Sonraki Adım

Ölçüm bir varsayımı ölçüm dışı bıraktı: çalışma alanına çıkarılan dosyaların iki düzende de
aynı olduğu varsayımını. Bu, dosyaların **nasıl** yazıldığının bir tercih olmadığını
söylüyordu — oysa çıkarma sırasında dosyaya uygulanan bir dönüşüm katmanı vardır ve nesne
deposundaki damla ile çalışma alanındaki dosya birbirinin aynısı olmak zorunda değildir.
Sonraki ders bu katmanı ölçer: satır sonu dönüşümü ayarlanmadığında hangi işleme, hangi
dosyada, gerçekten hiçbir şey değiştirmediği hâlde yeni bir nesne yazar?

### Depo Öznitelikleri

Source: https://academia.sh/tr/kurslar/ileri-git/depo-oznitelikleri

Öznitelik dosyası hangi işlemin hangi dosyada nasıl davranacağını belirler: ayarsız bin işlemelik tarihçe 5888 nesne yazar, satır sonu 162 gereksiz nesne üretir ve elli birleştirmenin 43'ü üretilen dosyada çakışarak 86 nesne daha ekler.

Önceki dersin ölçümü bir varsayımı dışarıda bıraktı: çalışma alanına çıkarılan dosyaların iki
düzende de aynı olduğu varsayımını. Bu, dosyanın **nasıl** yazıldığının bir tercih olmadığını
söylüyordu.

Öyle değildir. Nesne deposundaki damla ile çalışma alanındaki dosya birbirinin aynısı olmak
zorunda değildir; arada bir dönüşüm katmanı vardır ve o katman yapılandırılabilir. Katman
ayarsız bırakıldığında sessizce çalışır ve yaptığı iş tarihçeye yazılır. Bu dersin sorusu
şudur: hangi öznitelik hangi işlemi hangi dosyada değiştirir ve ayarsız durumda **içeriği
değişmediği hâlde** kaç nesne yazılır?

#### Öznitelik Dosyası Neyi Belirler

**Depo öznitelikleri (repository attributes)**, dosya desenlerine davranış bağlayan
kurallardır ve `.gitattributes` dosyasında dururlar. Dosya işlenen bir dosyadır: tarihçeye
girer, dallar arasında farklılaşabilir ve klonlayan herkese aynı kuralı taşır. Yapılandırma
dosyasından ayıran yer burasıdır — yapılandırma kişiseldir ve kopyaya özeldir, öznitelik
depoya aittir.

```text
# öznitelik dosyası — örnek döküm, çalıştırılmamıştır

# .gitattributes
*            text=auto
*.py         text eol=lf
*.md         text eol=lf
ayar.py      text merge=ours
sunum.bin    -text -diff
belge.md     diff=metin
```

Her satır bir desen ve ona bağlı niteliklerdir. `text` dosyanın metin sayılacağını ve satır
sonu dönüşümüne girebileceğini bildirir; `text=auto` kararı içeriğe bakarak aracın vermesini
ister. `eol=lf` çalışma alanına yazılırken hangi **satır sonu (line ending)** düzeninin
kullanılacağını sabitler. Başındaki eksi işareti niteliği kaldırır: `-text` dosyanın hiçbir
dönüşüme girmeyeceğini, `-diff` ise karşılaştırmanın metin olarak denenmeyeceğini bildirir.
`merge=ours` ve `diff=metin` ise bir **birleştirme sürücüsüne (merge driver)** ya da bir
karşılaştırma tanımına ad verir.

#### Dört İşlem, Dört Ayrı An

Öznitelikler dört ayrı anda devreye girer ve hangisinin ne zaman çalıştığı karışırsa
ölçüm de karışır.

**Çıkarma anı:** damla çalışma alanına yazılırken satır sonu dönüşümü uygulanır. **İşleme
anı:** çalışma alanındaki dosya damlaya çevrilirken ters dönüşüm uygulanır — depoya yazılan
biçim tektir. **Birleştirme anı:** iki yanın değişikliği harmanlanırken hangi sürücünün
kullanılacağı belirlenir. **Karşılaştırma anı:** iki damla arasındaki fark üretilirken metin
sayılıp sayılmayacağı belirlenir.

Beşinci bir an daha vardır ve tarihçeyi hiç ilgilendirmez: deponun bir sürümü arşiv olarak
paketlenirken hangi yolların dışarıda bırakılacağı da bir öznitelikle bildirilir. Kural
paketlemeye bakar, işlemeye değil; dosya tarihçede kalır, yalnız arşive girmez. Bu ders onu
ölçmüyor çünkü nesne birimiyle karşılığı yoktur.

İlk ikisi tarihçeye nesne yazar; son ikisinden yalnız birleştirme yazar. Karşılaştırma
okunabilirliği etkiler, tarihçeyi etkilemez — bu yüzden ölçümde `-diff` satırı sıfır verir ve
bu bir eksiklik değil, doğru sonuçtur.

Satır sonu dönüşümü ayarsızken ne olur? Depoya, yazanın ortamında ne varsa o girer. İki ayrı
satır sonu düzeni kullanan iki ortam aynı dosyaya sırayla dokunduğunda, **içerik hiç
değişmese bile** damla baştan yazılır: bayt dizisi farklıdır, dolayısıyla nesne farklıdır.

#### Ölçümün Varsayımları

- **BD20** — Ölçüm ortak kurgunun dört ölçeğini kullanır. Her işlemeye ayrı bir üreteçten iki
  alan eklenir: yazanın satır sonu düzeni ve içeriğin gerçekten değişip değişmediği.
- **BD21** — İşlemelerin **üçte biri** ayrı bir satır sonu düzeni kullanan bir ortamdan gelir;
  **beşte biri** içeriği gerçekten değiştirmez, yalnız dosyaya dokunur.
- **BD22** — Satır sonu ayarı yokken, içeriği değişmemiş bir işleme ancak dosyanın **son
  kaydedilen düzeni** farklıysa yeni damla yazar; her böyle yazım **2 nesnedir**. Ayar
  varsayıldığında bu işlemeler **0 nesne** yazar.
- **BD23** — Her **20** işlemede bir birleştirme yapılır; pencerenin iki yarısı da üretilen
  dosyaya dokunduysa birleştirme çakışması doğar. Elle çözüm bir işleme yazar, **2 nesne**.
- **BD24** — `merge=ours` tanımlandığında çakışma doğmaz ve çözüm işlemesi yazılmaz; sürücü
  üretilen dosyada karşı yanın sürümünü almaz.
- **BD25** — `-text` ve `-diff` ikili varlığa hiçbir nesne eklemez ve hiçbirini çıkarmaz;
  etkileri çıkarma ve karşılaştırma anındadır, tarihçede değil.
- **BD26** — Bedel **dokunulan nesne** birimiyle sayılır. "Ayarsız" sütunu taban, "tam ayarlı"
  sütunu ortak kurgunun klon bedelidir; aradaki fark özniteliğin **yazılmasını engellediği**
  nesnedir.

#### Ölçüm

```python
"""Depo oznitelikleri: ayarsiz durumda dogan gereksiz nesne.

Bolum 1 - hangi oznitelik hangi dosyada hangi islemi degistiriyor (1000 isleme).
Bolum 2 - dort olcekte ayarsiz, satir sonu ayarli ve tam ayarli nesne.
"""
TOHUM = 20260814
DOSYALAR = ("olcum.py", "rapor.py", "kimlik.py", "ayar.py", "belge.md")
IKILI_VARLIK = "sunum.bin"
URETILEN = "ayar.py"      # uretilen dosya: birlestirme surucusu buna baglanir
OLCEKLER = (50, 200, 1000, 4000)
BIRLESME_ARALIGI = 20     # her 20 islemede bir birlestirme


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 ortamli(t, tohum):
    """Her islemeye yazanin satir sonu duzeni ve icerigin gercekten degisip
    degismedigi eklenir."""
    r, k = uretec(tohum), []
    for x in t:
        k.append({**x, "crlf": r(3) == 0, "gercek": r(5) != 0})
    return k


def satir_sonu_nesnesi(k, dosya=None):
    """Ayarsizken: icerik ayni oldugu halde satir sonu duzeni degistigi icin
    yeniden yazilan damla. Dosya basina son duzen izlenir."""
    son, gereksiz = {}, 0
    for x in k:
        if x["dosya"] == dosya or dosya is None:
            if not x["gercek"] and son.get(x["dosya"]) not in (None, x["crlf"]):
                gereksiz += 2
        son[x["dosya"]] = x["crlf"]
    return gereksiz


def cakisan_birlesmeler(k):
    """Her aralikta bir birlestirme; iki yan da uretilen dosyaya dokunduysa
    cakisma dogar ve elle cozum bir isleme yazar."""
    sayi = 0
    for bas in range(0, len(k) - BIRLESME_ARALIGI + 1, BIRLESME_ARALIGI):
        pencere = k[bas:bas + BIRLESME_ARALIGI]
        yarim = BIRLESME_ARALIGI // 2
        sol = any(x["dosya"] == URETILEN for x in pencere[:yarim])
        sag = any(x["dosya"] == URETILEN for x in pencere[yarim:])
        sayi += sol and sag
    return sayi


def surucu_nesnesi(k):
    return 2 * cakisan_birlesmeler(k)


K = ortamli(tarihce(1000), TOHUM + 7)
print("dosya       oznitelik        degistirdigi islem        satir sonu nesnesi"
      "  surucu nesnesi")
OZNITELIK = (("olcum.py", "text eol=lf", "cikarma ve isleme"),
             ("rapor.py", "text eol=lf", "cikarma ve isleme"),
             ("kimlik.py", "text eol=lf", "cikarma ve isleme"),
             ("ayar.py", "text merge=ours", "cikarma, isleme, birlestirme"),
             ("belge.md", "text eol=lf", "cikarma ve isleme"),
             (IKILI_VARLIK, "-text -diff", "cikarma ve karsilastirma"))
for dosya, oz, islem in OZNITELIK:
    s = 0 if dosya == IKILI_VARLIK else satir_sonu_nesnesi(K, dosya)
    d = surucu_nesnesi(K) if dosya == URETILEN else 0
    print(f"  {dosya:10s} {oz:16s} {islem:26s} {s:16d} {d:15d}")
print()
print("isleme  ayarsiz nesne  satir sonu ayarli  tam ayarli  gereksiz nesne   oran")
for n in OLCEKLER:
    k = ortamli(tarihce(n), TOHUM + 7)
    tam, s, d = klon_bedeli(k), satir_sonu_nesnesi(k), surucu_nesnesi(k)
    print(f"{n:6d} {tam + s + d:14d} {tam + d:18d} {tam:11d} {s + d:15d} "
          f"{(s + d) / (tam + s + d):6.4f}")
print()
n = 1000
k = ortamli(tarihce(n), TOHUM + 7)
print(f"tarihce {n} isleme; satir sonu yuzunden yeniden yazilan damla "
      f"{satir_sonu_nesnesi(k) // 2}, yazdigi nesne {satir_sonu_nesnesi(k)}")
print(f"birlestirme {n // BIRLESME_ARALIGI}, uretilen dosyada cakisan "
      f"{cakisan_birlesmeler(k)}, elle cozumun yazdigi nesne {surucu_nesnesi(k)}")
```

```
dosya       oznitelik        degistirdigi islem        satir sonu nesnesi  surucu nesnesi
  olcum.py   text eol=lf      cikarma ve isleme                        38               0
  rapor.py   text eol=lf      cikarma ve isleme                        34               0
  kimlik.py  text eol=lf      cikarma ve isleme                        22               0
  ayar.py    text merge=ours  cikarma, isleme, birlestirme               36              86
  belge.md   text eol=lf      cikarma ve isleme                        32               0
  sunum.bin  -text -diff      cikarma ve karsilastirma                  0               0

isleme  ayarsiz nesne  satir sonu ayarli  tam ayarli  gereksiz nesne   oran
    50            390                384         380              10 0.0256
   200            972                938         920              52 0.0535
  1000           5888               5726        5640             248 0.0421
  4000          23578              22912       22600             978 0.0415

tarihce 1000 isleme; satir sonu yuzunden yeniden yazilan damla 81, yazdigi nesne 162
birlestirme 50, uretilen dosyada cakisan 43, elle cozumun yazdigi nesne 86
```

#### Hangi Öznitelik Hangi Dosyada

Üst tablo dersin birinci sorusunu yanıtlıyor ve dikkat çeken şey sütunların **birbirinden
bağımsız** olmasıdır.

Satır sonu sütunu beş metin dosyasına dağılıyor: **38**, **34**, **22**, **36** ve **32** —
toplam **162** nesne. Dağılım eşit değil ama nedeni özniteliğin kendisi değil, kurgunun dosya
dağılımı. Öznitelik açısından beş satır aynı kuralı taşıyor; ödenen bedel dosyanın ne sıklıkta
dokunulduğuna göre değişiyor.

Sürücü sütunu tek bir satırda toplanıyor: **86** nesne, yalnız `ayar.py` satırında. Bu, kurgu
gereği üretilen dosyadır — elle yazılmayan, bir araç tarafından üretilip depoya konan bir
dosya. Öbür dört dosyada sürücü sütunu **0**'dır çünkü onlarda çakışma elle çözülmelidir ve
çözüm bir karardır, ayarla değiştirilecek bir şey değildir.

İkili varlık satırı iki sütunda da **0** veriyor. `-text` ve `-diff` nitelikleri gerçek işler
yapar — dönüşümü engeller, okunmaz karşılaştırmayı önler — ama **tarihçeye tek nesne
eklemez ve çıkarmaz**. Ölçünün birimi nesne olduğu için o etkiler burada görünmez. Bu satır,
ölçünün kapsam sınırının bildirimidir.

#### Ayarsızlığın Ödettiği

Alt tablonun birimi **dokunulan nesnedir** ve üç sütun aynı tarihçenin üç ayarlama düzeyini
veriyor. Bin işlemelik tarihçe ayarsız **5888** nesne yazıyor; satır sonu ayarlandığında
**5726**'ya, birleştirme sürücüsü de tanımlandığında **5640**'a — yani ortak kurgunun klon
bedeline — iniyor. Gereksiz nesne **248**, oran **0,0421**.

Oran küçüktür ve bu, ölçümün dürüst sonucudur: satır sonu düzensizliği bir depoyu şişirmez.
İki gözlem yine de kayda değer. **Birincisi**, gereksiz nesne oranı dört ölçekte **0,0256**,
**0,0535**, **0,0421** ve **0,0415** çıkıyor; büyük iki ölçekte **0,042** dolayında oturuyor
ve ölçek büyüdükçe azalmıyor. Bu, tarihçenin ömrü boyunca ödenmeye devam eden bir bedeldir.
**İkincisi**, elli işlemelik satırdaki **10** nesne, o ölçekteki **1/50** çözünürlüğün
yanında beş işlemeye karşılık gelir; küçük depoda bu bedelden bir sonuç çıkarılamaz.

Asıl sayı üçüncü satırda duruyor: **50** birleştirmenin **43**'ü üretilen dosyada çakışıyor.
Bu, birleştirmelerin **beşte dördünden** fazlasıdır ve her biri bir kişinin oturup çakışma
işaretlerini elle temizlemesi demektir. Tarihçeye yazdığı **86** nesne bu işin en küçük
parçasıdır; ölçülmeyen kısmı, kırk üç kez verilen ve hiçbirinin bir bilgi taşımadığı karardır.
Dallanma ve İşbirliği kursu çakışma çözümünün tarihçeye yazılmadığını göstermişti — burada
görülen şey, o yazılmayan kararların **kırk üç tanesinin baştan gereksiz** olduğudur.

#### Hangi Satır Kazanır

Ölçüm her dosyaya tek bir kural düştüğünü varsaydı. Gerçek bir öznitelik dosyasında bir yola
birden çok desen uyar ve hangisinin kazandığı bilinmeden hiçbir ayarın etkisi öngörülemez.

Kural sırası üç katmanlıdır. **Aynı dosya içinde son eşleşen satır kazanır** — yukarıdan
aşağı okunur ve alttaki üsttekini ezer; bu yüzden genel desenler başa, özel desenler sona
yazılır. **Alt dizindeki öznitelik dosyası üsttekini ezer**, çünkü daha yakındır. Ve deponun
içinde, tarihçeye girmeyen yerel bir öznitelik dosyası daha vardır; o **hepsini ezer** ve
yalnız o kopyada geçerlidir.

Üçüncü katman iki yönlü keskindir. Bir kopyanın davranışını depoyu değiştirmeden ayarlamayı
sağlar; aynı nedenle, bir kopyada beklenmedik bir dönüşüm görüldüğünde bakılacak ilk yer
orasıdır. Öznitelikler depoya aittir demiştik — bu, o yerel katman dışında doğrudur ve
farkın nerede olduğu bilinmezse bir dosyanın neden başka türlü çıktığı hiç anlaşılmaz.

Bir nitelik üç değer alabilir: verilmiş (`text`), kaldırılmış (`-text`) ve **belirtilmemiş**.
Üçüncüsü ikinciyle aynı şey değildir: kaldırılmış bir nitelik kararı kesinleştirir,
belirtilmemiş bir nitelik kararı bir alt katmana ya da aracın kendi öntanımına bırakır.
`text=auto` tam olarak bu üçüncü durumu yönetir — kararı içeriğe bakarak verir ve ikili
sandığı dosyaya dönüşüm uygulamaz.

#### Ayarın Sınırı ve Kurtarma

Öznitelik dosyası ileriye dönük çalışır. Bugün yazılan bir `text=auto` satırı, dün yazılmış
damlaları düzeltmez; tarihçedeki **162** nesne yerinde kalır. Ayarın etkisi ilk çıkarmadan
sonra başlar ve depo çalışanların ellerinde zaten çıkarılmış durumdaysa, dosyaların bir kez
yeniden normalize edilmesi gerekir — bu, tarihçede yeni bir işleme olarak görünür ve
tarihçeyi yeniden yazmaz.

Yeniden yazan yol da vardır ve konunun ikinci dersindeki kuralla aynı sınıra girer: geçmişteki
bütün damlaları normalize etmek **tarihçeyi yeniden yazmaktır**, kimlikleri değiştirir,
**geri alınamaz** ve her kopyanın yeniden klonlanmasını gerektirir. Kazancı ölçümde okunuyor —
**162** nesne. Bin işlemelik bir depoda bu, klon bedelinin otuz beşte biri kadardır ve o
kazanç için tarihçeyi yeniden yazmak neredeyse hiçbir durumda haklı çıkmaz.

Ucuz ve geri alınabilir yol şudur: öznitelik dosyası deponun ilk gününde yazılır; sonradan
yazıldıysa tek bir normalizasyon işlemesiyle ileriye dönük düzeltilir; geçmiş olduğu gibi
bırakılır. Yanlış bir öznitelik satırının kendisi ise zararsızdır — dosya işlenen bir dosya
olduğu için satır geri alınabilir ve dönüşüm bir sonraki çıkarmada eski hâline döner.

#### Özet

- Depo öznitelikleri işlenen bir dosyada durur ve depoya aittir; yapılandırmadan farkı budur.
  Dört ayrı anda devreye girerler: çıkarma, işleme, birleştirme ve karşılaştırma.
- Karşılaştırma anı tarihçeye nesne yazmaz; ikili varlık satırı ölçümde iki sütunda da
  **0** verir ve bu, ölçünün kapsam sınırının bildirimidir.
- Satır sonu ayarsızken içeriği değişmemiş **81** işleme yeni damla yazar ve **162** nesne
  üretir; beş metin dosyasına **38 / 34 / 22 / 36 / 32** olarak dağılır.
- Üretilen dosyada birleştirme sürücüsü tanımsızken **50** birleştirmenin **43**'ü çakışır ve
  elle çözüm **86** nesne yazar; `merge=ours` bu çakışmaların tümünü ortadan kaldırır.
- Bin işlemede ayarsız tarihçe **5888**, tam ayarlı tarihçe **5640** nesnedir; gereksiz
  **248** nesnenin oranı **0,0421**'dir ve ölçek büyüdükçe azalmaz.

#### Sonraki Adım

Bu konunun dört dersi aynı depoya dört ayrı müdahale yaptı: bağımlı depoyu gömdü, ikili
gövdeyi dışarı taşıdı, çalışma ağacını çoğalttı ve dönüşüm katmanını ayarladı. Dördü de tek
bir soruyu varsaydı — deponun **sınırının** nerede olduğunu. Sonraki ders o varsayımı ölçer:
aynı iş tek bir depoda ve dört ayrı depoda yapılırsa, klon bedeli ile arama adımı nasıl
değişir ve bileşenler arasında sorulan sorulardan kaçı ikinci düzende yanıtsız kalır?

### Tek Depo ve Çok Depo

Source: https://academia.sh/tr/kurslar/ileri-git/tek-depo-ve-cok-depo

Aynı iş iki düzende: toplam nesne iki düzende de 22600'dür ama depo başına bedel 22600 ile 5650, ikili arama 11 ile 36 adım ve bileşenler arası dört sorudan tek depo 4'ünü yanıtlarken çok depo 1'ini yanıtlar.

Bu konunun dört dersi aynı depoya dört ayrı müdahale yaptı: bağımlı depoyu gömdü, ikili
gövdeyi dışarı taşıdı, çalışma ağacını çoğalttı ve dönüşüm katmanını ayarladı. Dördü de bir
şeyi sabit tuttu — deponun **sınırını**.

Bu ders o sınırı değişken yapar. Aynı iş, aynı işlemeler ve aynı nesneler; tek fark, hepsinin
bir deponun içinde mi yoksa dört ayrı deponun içinde mi durduğu. Ölçek ve sahiplik
ödünleşimlerinin kurumsal tartışması Yazılım Mimarlığı kursundaki Kurumsal Bağlam ve
Tümleştirme ile DevOps ve Platform Mühendisliği kurslarında kuruldu ve burada
tekrarlanmıyor. Burada ölçülen tek şey şudur: **nesne, adım ve yanıtlanan soru.**

#### İki Düzen, Aynı İş

**Tek depo (monorepo)**, birden çok bileşenin tek bir depoda ve tek bir tarihçede durduğu
düzendir. **Çok depo (polyrepo)**, her bileşenin kendi deposunda ve kendi tarihçesinde
durduğu düzendir.

Ayrımın ölçüme giren yanı tek cümleyle kurulur: **tek depoda bileşenler ortak bir sıra
paylaşır, çok depoda paylaşmaz.** Tek depoda iki bileşene aynı işlemede dokunulabilir ve
tarihçe bunu kaydeder; çok depoda her deponun kendi sırası vardır ve iki sıra arasında
karşılaştırılabilir bir ortak nokta yoktur.

Ölçüm bu yüzden bölmeyi bir yeniden yazma olarak değil, aynı işleme dizisinin ayrı
tarihçelere dağıtılması olarak modelliyor. Nesneler aynı, işlemeler aynı; değişen tek şey
sınır.

#### Ölçümün Varsayımları

- **BD27** — Aynı iş ortak kurgunun **4000** işlemelik ölçeğidir. Çok depo düzeni bu diziyi
  **4** eşit parçaya böler ve her parçayı kendi içinde yeniden numaralandırır; hiçbir işleme
  eklenmez, çıkarılmaz ve değiştirilmez.
- **BD28** — Her parçadaki nesne sayısı bölünmeden etkilenmez; iki düzenin **toplam** nesnesi
  tanım gereği eşittir. Ölçülen şey toplam değil, **depo başına** ödenen bedeldir.
- **BD29** — Kâhin her tarihçede kendi kuralıyla çalışır: kusuru getiren işleme, o tarihçenin
  dörtte üçüncü noktasındadır. Bölünen düzende dört ayrı kâhin vardır.
- **BD30** — "Deposu bilinmiyor" satırı, kusurun hangi bileşende olduğunun önceden
  bilinmediği durumdur; arama her depoda ayrı ayrı yürütülür ve adımlar toplanır.
- **BD31** — Bir soru, gerektirdiği bileşenlerin **tümü tek bir tarihçede** duruyorsa
  yanıtlanır. Tek depoda bir tarihçede dört bileşen vardır, çok depoda bir.
- **BD32** — Birinci bölümün birimi **dokunulan nesne**, ikinci bölümün birimi **adımdır**.
  Üçüncü bölüm bedel ölçmez, yanıtlanabilirlik sayar.
- **BD33** — Ölçüm ekip büyüklüğü, sahiplik, izin ve yayımlama düzeni gibi eksenleri
  içermez; bunlar başka kursların konusudur ve bu tablodan bir örgütlenme sonucu çıkarılamaz.

#### Ölçüm

```python
"""Tek depo ve cok depo: ayni is iki duzende.

Bolum 1 - klon bedeli, birim dokunulan nesne.
Bolum 2 - arama ve suclama, birim adim.
Bolum 3 - bilesenler arasi sorulardan kaci yanitlaniyor.
"""
TOHUM = 20260814
DOSYALAR = ("olcum.py", "rapor.py", "kimlik.py", "ayar.py", "belge.md")
TOPLAM = 4000
BILESEN = 4


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 kusurlu_isleme(t):
    """Kahin: kusuru getiren isleme, kurguyu biz yazdigimiz icin bilinir."""
    return len(t) * 3 // 4


def dogrusal_arama(t):
    hedef, adim = kusurlu_isleme(t), 0
    for x in t:
        adim += 1
        if x["no"] >= hedef:
            return adim
    return adim


def ikili_arama(t):
    hedef, alt, ust, adim = kusurlu_isleme(t), 1, len(t), 0
    while alt < ust:
        orta = (alt + ust) // 2
        adim += 1
        if orta >= hedef:
            ust = orta
        else:
            alt = orta + 1
    return adim


def suclama(t, dosya):
    return sum(1 for x in t if x["dosya"] == dosya)


def klon_bedeli(t, ikili_dahil=True):
    return sum(x["nesne"] for x in t if ikili_dahil or not x["ikili"])


def parcala(t, adet):
    """Ayni is, adet ayri depoya bolunmus: nesneler ayni, tarihceler ayri."""
    boy = len(t) // adet
    return [[{**x, "no": i + 1} for i, x in enumerate(t[p * boy:(p + 1) * boy])]
            for p in range(adet)]


SORULAR = (("tek bilesende kusurun yalitimi", 1),
           ("iki bilesenin birlikte degismesi", 2),
           ("bir degisikligin uc bilesene yayilimi", 3),
           ("butun bilesenlerin ortak durumu", 4))


def yanitlanir(gereken, depodaki_bilesen):
    """Soru, gerektirdigi bilesenlerin tumu tek tarihcede duruyorsa yanitlanir."""
    return gereken <= depodaki_bilesen


tek = tarihce(TOPLAM)
cok = parcala(tek, BILESEN)

print("duzen      depo  depo basina nesne  1 bilesen  2 bilesen  tum bilesenler")
print(f"  tek depo    1 {klon_bedeli(tek):18d} {klon_bedeli(tek):10d} "
      f"{klon_bedeli(tek):10d} {klon_bedeli(tek):15d}")
bir = klon_bedeli(cok[0])
iki = sum(klon_bedeli(p) for p in cok[:2])
tum = sum(klon_bedeli(p) for p in cok)
print(f"  cok depo  {BILESEN:3d} {tum // BILESEN:18d} {bir:10d} {iki:10d} {tum:15d}")
print()
print("duzen                             ikili arama  dogrusal arama"
      "  suclama (ayar.py)")
ARAMA = (("tek depo, 4000 isleme", ikili_arama(tek), dogrusal_arama(tek),
          suclama(tek, "ayar.py")),
         ("cok depo, kusurun deposu belli", ikili_arama(cok[0]),
          dogrusal_arama(cok[0]), suclama(cok[0], "ayar.py")),
         ("cok depo, deposu bilinmiyor", sum(ikili_arama(p) for p in cok),
          sum(dogrusal_arama(p) for p in cok),
          sum(suclama(p, "ayar.py") for p in cok)))
for ad, ia, da, su in ARAMA:
    print(f"  {ad:31s} {ia:11d} {da:15d} {su:18d}")
print()
print("soru                                   gereken bilesen  tek depo  cok depo")
for ad, gereken in SORULAR:
    t = "evet" if yanitlanir(gereken, BILESEN) else "hayir"
    c = "evet" if yanitlanir(gereken, 1) else "hayir"
    print(f"  {ad:38s} {gereken:14d} {t:>9s} {c:>9s}")
print()
print(f"tek depo yanitlanan {sum(yanitlanir(g, BILESEN) for _, g in SORULAR)}/"
      f"{len(SORULAR)}, cok depo yanitlanan "
      f"{sum(yanitlanir(g, 1) for _, g in SORULAR)}/{len(SORULAR)}")
print(f"toplam nesne iki duzende de {tum}; degisen sey depo basina bedel: "
      f"{klon_bedeli(tek)} ve {tum // BILESEN}")
```

```
duzen      depo  depo basina nesne  1 bilesen  2 bilesen  tum bilesenler
  tek depo    1              22600      22600      22600           22600
  cok depo    4               5650       5640      11280           22600

duzen                             ikili arama  dogrusal arama  suclama (ayar.py)
  tek depo, 4000 isleme                    11            3000                787
  cok depo, kusurun deposu belli            9             750                209
  cok depo, deposu bilinmiyor              36            3000                787

soru                                   gereken bilesen  tek depo  cok depo
  tek bilesende kusurun yalitimi                      1      evet      evet
  iki bilesenin birlikte degismesi                    2      evet     hayir
  bir degisikligin uc bilesene yayilimi               3      evet     hayir
  butun bilesenlerin ortak durumu                     4      evet     hayir

tek depo yanitlanan 4/4, cok depo yanitlanan 1/4
toplam nesne iki duzende de 22600; degisen sey depo basina bedel: 22600 ve 5650
```

#### Toplam Aynı, Depo Başına Farklı

Birinci tablonun birimi **dokunulan nesnedir** ve sağ sütun iki düzende de **22600** veriyor.
Bu bir tesadüf değil, kurgunun kuralıdır: bölmek nesne üretmez ve nesne yok etmez.

Fark soldaki sütunlardadır. Tek depoda tek bir bileşende çalışan biri de **22600** nesne
klonlar, çünkü klonun daha küçük bir birimi yoktur. Çok depoda aynı kişi **5640** nesne
klonlar — dörtte biri. İki bileşen gerekiyorsa **11280**, dördü birden gerekiyorsa yine
**22600**.

Kesişme noktası tablodan doğrudan okunur: **çok depo, ancak çalışanların çoğu tek bileşene
dokunuyorsa ucuzdur.** Dördüne birden dokunan biri için iki düzen aynı bedeli öder, üstelik
çok depoda bu bedel dört ayrı işlemle ödenir. Kısmi ve seyrek klon seçenekleri tek depoda
aynı daralmayı depoyu bölmeden sağlar; bu ölçüm onları kullanmıyor.

#### Bölünme Aramayı Bozar

İkinci tablonun birimi **adımdır** ve satırlar arasındaki fark dersin en keskin sonucudur.

Kusurun hangi bileşende olduğu **biliniyorsa** çok depo kazanır: ikili arama **11** adımdan
**9**'a, doğrusal arama **3000**'den **750**'ye, suçlama **787**'den **209**'a iner. Arama
küçük bir tarihçede yürüyor ve bedel küçülüyor.

Bilinmiyorsa tablo tersine dönüyor. İkili arama **36** adıma çıkıyor — tek depodakinin üç
katından fazlası. Neden açıktır: ikili arama tek bir sıralı küme üzerinde çalışır, dört ayrı
tarihçe ise dört ayrı kümedir ve her biri **9** adımlık dört arama yapılır. Bölünme, ikili
aramanın tek gücünü — büyüyen kümede yavaş büyümesini — parçalayarak yok eder.

Aynı satırın öbür iki sütunu **3000** ve **787** veriyor; tek depodaki değerlerin aynısı.
Doğrusal tarama ve suçlama bölünmeden etkilenmez, çünkü ikisi de zaten her işlemeye
dokunuyordu ve toplam işleme sayısı değişmedi. **Bölünmenin zarar verdiği tek arama biçimi,
kümeyi ikiye bölerek çalışandır.**

#### Yanıtsız Kalan Soru

Üçüncü tablo bedel değil, **yanıtlanabilirlik** sayıyor. Tek depo dört sorunun **4**'ünü
yanıtlıyor, çok depo **1**'ini.

Yanıtlanan tek soru, tek bir bileşenin içinde kalanıdır. Kalan üçü iki, üç ve dört bileşene
birden bakıyor ve çok depoda bunu yapacak bir tarihçe yoktur. Bu bir araç eksikliği değil,
sınırın tanımıdır: iki bileşenin birlikte değiştiğini kaydeden bir işleme yoksa, o soruyu
sonradan soracak hiçbir sorgu yoktur.

Boşluğu kapatmanın bir yolu vardır ve bedeli bu konunun ilk dersinde ölçüldü: dört bileşeni
birlikte sabitleyen bir kayıt deposu kurmak. Bu, dört bileşeni alt modül olarak bağlar ve
"bütün bileşenlerin ortak durumu" sorusunu yeniden yanıtlanabilir yapar. Karşılığında bir
işlemenin ağacını kurmak için gereken kimlik **1**'den **5**'e çıkar ve özyinelemeli klon
yine **22600** nesneye döner. Çok depo düzeni, kaybettiği soruyu geri almak istediğinde tek
deponun bedelini geri ödemeye başlar.

#### Özet

- Bölmek nesne üretmez: toplam nesne iki düzende de **22600**'dür. Değişen tek şey **depo
  başına** ödenen bedeldir — **22600** ve **5650**.
- Tek bileşene dokunan biri çok depoda **5640** nesne klonlar, dördüne dokunan **22600**;
  çok depo ancak çalışanların çoğu tek bileşende kalıyorsa ucuzdur.
- Kusurun deposu biliniyorsa ikili arama **11**'den **9** adıma iner; bilinmiyorsa **36**
  adıma çıkar. Bölünme, kümeyi ikiye bölerek çalışan aramayı bozar.
- Doğrusal tarama **3000** ve suçlama **787** adımda kalır: bölünme bu iki biçimi etkilemez,
  çünkü ikisi de zaten her işlemeye dokunuyordu.
- Bileşenler arası dört sorudan tek depo **4**'ünü, çok depo **1**'ini yanıtlar; kayıp bir
  araç eksikliği değil, sınırın tanımıdır ve geri alınması alt modülün bedelini geri getirir.

#### Kurs Kapanışı

Kurs tek bir ölçüyle yürüdü: bir işlemin bedeli **tarihçenin uzunluğu değil, dokunduğu nesne
sayısıdır** — ve bedel iki birimle sayılır, **adım** ya da **dokunulan nesne**. On iki ders
bu ölçüyü ayrı yerlere uyguladı.

| ders | ölçülen işlem | bedelin büyüme biçimi |
|---|---|---|
| Etkileşimli Yeniden Temellendirme | ortadan yeniden yazmanın dokunduğu nesne | 252 / 362 / 3002 / 11322 nesne; oran 0,520'den 0,500'e — ölçek seksen kat büyürken oran sabit kalır |
| Toplu Tarihçe Dönüşümü | ilk işlemeden dönüşümün dokunduğu nesne | 380 / 920 / 5640 / 22600 nesne, oran her ölçekte 1,000; paylaşılan önek 0'a iner ve bedel tarihçenin tamamıdır |
| Zorlayıcı İtme Disiplini | yeniden yazmanın kopyalara ödettiği | yazan 2 ile 5640 nesne arasında öder, kopyalar 14 ile 39480 arasında — her zaman yedi katı; kopya sayısıyla ölçeklenir |
| Referans Günlüğü | yeniden yazmadan sonra erişilebilir kalan | erişilebilir 1000 sabit, erişilemez 3 / 500 / 701 / 1000; kurtarma ufka bağlı ve 3 / 50 / 500 / 1000'de kapanır |
| İkili Arama ile Hata Avı | kusuru bulmanın adımı | doğrusal 37 / 150 / 750 / 3000 adım, ikili 6 / 7 / 9 / 11; seksen kat tarihçede ikili arama iki kat bile artmaz |
| Suçlama ve Satır Tarihçesi | bir dosyanın satır geçmişinin adımı | 8 / 36 / 209 / 787 adım; dosyaya dokunan işleme sayısıyla büyür ve yanıt 40 işlemede sabitlenir |
| Kancalar | engelin konduğu andaki bedel | işlemeden önce 0 nesne, itmeden önce 140, kabulden altı yüz işleme sonra 3522 nesne ve yedi kopya; geç kapı bedeli dağıtır |
| Alt Modüller | sabitlenmiş sürümün bağladığı tarihçe | 76 nesne 378 işleme bağlar; klon 920'den 4540'a (4,93 kat) çıkar ve alt modül sayısıyla toplanır |
| Büyük Dosya Depolama | nesne türünün toplam içindeki payı | 91 işleme (0,0910) nesnenin 0,6777'sini üretir; klon 5640'tan 2131'e iner — bedel işleme sayısını izlemez |
| Çoklu Çalışma Ağacı | ek çalışma alanının kopyaladığı nesne | ek ağaç her ölçekte 0 nesne; dört dal için 22560 yerine 5640 — bedel ağaç sayısıyla hiç büyümez |
| Depo Öznitelikleri | ayarsızlığın yazdırdığı gereksiz nesne | satır sonu 162, birleştirme sürücüsü 86, toplam 248 nesne ve oran 0,0421; ölçek büyüdükçe azalmaz |
| Tek Depo ve Çok Depo | aynı işin iki düzendeki bedeli | toplam 22600 nesne değişmez, depo başına 22600 ve 5650; ikili arama 11 ve 36 adım, yanıtlanan soru 4/4 ve 1/4 |

Tablodan üç okuma çıkar. **Birincisi: aynı tarihçede bedeller ayrışır.** Ölçek seksen kat
büyürken doğrusal arama seksen kat, suçlama yüz kat, klon altmış kat büyür; ikili arama iki
kat bile artmaz ve ek çalışma ağacı hiç artmaz. Bir deponun "büyük" olması tek başına bir şey
söylemez — hangi işlemin hangi kümeye dokunduğu söyler.

**İkincisi: bedeli belirleyen sayı çoğu zaman işleme sayısı değildir.** Nesne türü onda
birinden az işlemeyle nesnelerin üçte ikisini üretir; kopya sayısı, değişikliğin büyüklüğünden
bağımsız olarak yeniden eşitlemeyi zorunlu kılar; sınırın nerede çizildiği aramanın adımını
üç katına çıkarır. Üç durumda da yanlış değişkene bakmak yanlış sonuç verir.

**Üçüncüsü: bu kursun araçlarının çoğu geri alınamaz ve bedeli yazan ödemez.** Toplu dönüşüm
paylaşılan öneki sıfırlar, zorlayıcı itme kimsenin haberi olmadan siler, geriye dönük temizlik
her kopyayı yeniden klonlatır. Her birinin yanında bir kurtarma yolu sayıldı — yedek dal,
referans günlüğü, ayrı klon, kuru çalışma — ve hepsinin ortak yanı **işlemden önce**
kurulmaları gerektiğidir.

Buradan sonraki kurs — Kod İnceleme ve Ekip Süreci — aynı araçları başka bir soruyla ele alır.
Bu kurs boyunca ölçülen her şey aracın yaptığı işti: kaç nesneye dokunduğu, kaç adım harcadığı,
hangi soruyu yanıtsız bıraktığı. Hiçbir ölçüm, işlemin **yapılması gerekip gerekmediğini**
söylemedi. Tarihçeyi yeniden yazmanın 5640 nesneye dokunduğunu bilmek, o tarihçenin yeniden
yazılıp yazılmayacağına karar vermez; kancanın hangi anda engel koyduğunu bilmek, hangi
değişikliğin engellenmesi gerektiğini söylemez. Ayrım baştan konmalıdır: **araç tarihçeyi
değiştirir, kararı insan verir.** Sonraki kursun konusu o kararın nasıl verildiğidir — kimin
baktığı, neye baktığı ve kararın nerede kaydedildiği. Bu kursun bıraktığı sayılar, orada
verilecek kararların maliyetini hesaplamakta kullanılacak birimdir.

