---
title: 'Suçlama ve Satır Tarihçesi'
source: 'https://academia.sh/tr/kurslar/ileri-git/suclama-ve-satir-tarihcesi'
course: 'İleri Git'
language: tr
updated: '2026-08-17T18:10:42+00:00'
license: 'CC BY-SA 4.0'
---

# Suçlama ve Satır Tarihçesi

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ığı.
