---
title: 'Kiraz Toplama'
source: 'https://academia.sh/tr/kurslar/dallanma-ve-isbirligi/kiraz-toplama'
course: 'Dallanma ve İşbirliği'
language: tr
updated: '2026-08-17T18:10:44+00:00'
license: 'CC BY-SA 4.0'
---

# Kiraz Toplama

Tek bir işlemeyi başka dala kopyalamak aynı değişikliği tarihçede iki ayrı kimlikle iki yerde bırakır; dosya izi sorusu yine evet der ama saydığı işleme sayısı ayrı değişiklik sayısından fazladır ve kusurlu bir işleme kopyalandığında yalıtım sorusu düşer.

Yeniden temellendirme bir dalın **bütün** işlemelerini yeni bir tabana taşıdı. Bazen
gereken bundan çok daha azdır: yayımlanmış bir sürümde duran tek bir düzeltmenin
geliştirme dalına da girmesi, ya da bir dalda yazılmış tek bir işlemenin öbür dalda erken
kullanılması. Dalın tamamını almak bu durumda yanlış olur; alınmak istenen tek bir
değişikliktir.

**Kiraz toplama (cherry-pick)** tam olarak bunu yapar. Bu dersin sorusu işlemin nasıl
çalıştığı kadar sonucudur: aynı değişiklik artık tarihçede iki yerde durur, ve bir dosyaya
dokunan işlemeleri sayan **dosya izi** sorusu bundan etkilenir.

## Tek İşlemeyi Kopyalamak

Kiraz toplama, seçilen işlemenin **öncülüne göre yaptığı değişikliği** alır ve bulunduğunuz
dalın ucuna uygular. Uygulama başarılıysa yeni bir işleme yazılır. Yeni işlemenin öncülü
hedef dalın eski ucudur, ağacı yenidir, kimliği yenidir. Kaynak işleme yerinde durur ve
hiçbir şey kaybetmez.

Bu, yeniden temellendirmenin tek işlemelik hâlidir. Aradaki fark kapsamdır: yeniden
temellendirme dalın ucundan ortak ataya kadarki bütün işlemeleri taşır ve eskilerini
erişilemez bırakır; kiraz toplama tek bir işlemeyi kopyalar ve eskisini yerinde bırakır.
Tersine çalışan bir üçüncüsü de vardır: **devirme (revert)** bir işlemenin değişikliğini
ters çevirip yeni bir işleme olarak yazar. Üçü de aynı düzeneğin — yamayı çıkar, yeniden
uygula — ayrı kullanımlarıdır.

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

$ git switch kimlik
$ git cherry-pick 4d5e6f1
[kimlik 8c9d0e1] rapor: alan genisligini duzelt
 1 file changed, 6 insertions(+), 2 deletions(-)
```

Soldaki köşeli parantez hedef dalı ve **yeni kimliği** gösteriyor; komuta verilen kimlik
`4d5e6f1`, üretilen kimlik `8c9d0e1`. İki işlemenin içeriği aynı, kimliği ayrı. Bu, dersin
ölçtüğü şeyin tamamıdır.

Uygulama her zaman başarılı olmaz. Kaynak işlemenin dayandığı bağlam hedef dalda yoksa
yama tutmaz ve önceki derslerdeki çakışma durumu doğar: çalışma alanı işaretlerle
bırakılır, çözüm elle verilir, sonra devam ya da iptal çağrılır. Bir aralık verildiğinde
işlemeler sırayla kopyalanır ve çakışma her biri için ayrı ayrı sorulabilir.

Bir de tersi vardır: kopyalanan değişiklik hedef dalda **zaten uygulanmışsa** yama boş
kalır. Araç bu durumda kendiliğinden bir karar vermez, durur ve seçimi kullanıcıya
bırakır — boş bir işleme yazmak da, o adımı atlamak da tarihçeye ayrı şeyler yazar.

## Aralık, İşlemesiz Kopya ve İki Öncüllü Kaynak

Kopyalanacak şey tek bir işleme olmak zorunda değildir. Komuta bir işleme aralığı
verildiğinde araç aralıktaki işlemeleri **sırayla** kopyalar ve her biri için ayrı bir
işleme yazar. Aralık gösterimi burada da öncül temellidir: verilen alt sınır **dışarıda
kalır**, üst sınır içeridedir. Bu, aralığın bir işleme eksik kopyalanmasının en sık
nedenidir.

İkinci bir seçenek kopyayı işlemeden bırakır: değişiklik çalışma alanına ve hazırlık
alanına uygulanır, işleme yazılmaz. Bu, birkaç işlemeyi kopyalayıp hedef dalda tek bir
işleme olarak kaydetmek istendiğinde kullanılır — ve o durumda tarihçede kaynak
işlemelerin ayrı ayrı karşılığı hiç oluşmaz.

Kaynak bir birleştirme işlemesiyse durum ayrıdır. Birleştirme işlemesinin **iki öncülü**
vardır ve "öncülüne göre yaptığı değişiklik" ifadesi tek bir yanıt vermez: hangi öncüle
göre bakıldığına bağlı olarak iki ayrı yama çıkar. Araç bu yüzden hangi öncülün taban
sayılacağının açıkça belirtilmesini ister ve belirtilmediğinde işi reddeder.

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

$ git cherry-pick a1b2c3d
error: commit a1b2c3d is a merge but no -m option was given.
fatal: cherry-pick failed
```

Bu red, birinci dersteki iki öncüllü yapının doğrudan sonucudur. Birleştirme işlemesinin
taşıdığı bilgi bir değişiklik değil, iki çizginin buluşmasıdır; tek bir yamaya
indirgenmesi ancak bir taraf seçilerek yapılabilir.

## Kopyanın Kökeni Kaydedilir mi

İkinci dersin sonucu burada bire bir tekrar eder. Kopyanın kaynağı, araç kendiliğinden
yazmadıkça tarihçede durmaz: yeni işleme, hangi işlemeden kopyalandığını söyleyen bir alan
taşımaz. Bu bilgiyi kaydeden bir seçenek vardır ve isteğe bağlıdır — verildiğinde araç
işleme mesajının sonuna kaynağın kimliğini yazan bir satır ekler.

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

$ git cherry-pick -x 4d5e6f1
$ git log -1 --format=%B
rapor: alan genisligini duzelt

(cherry picked from commit 4d5e6f1)
```

Satırın nereye yazıldığına dikkat: **işleme mesajının içine**. Araç bunun için ayrı bir
alan tanımlamaz; kökeni de gerekçe gibi mesaja yazar. Önceki derste çakışma çözümü için
söylenen şey burada da geçerlidir — mesaja yazılmayan bilgi hiçbir yerde durmaz.

Kaynağı yazılmamış bir kopya sonradan bulunabilir mi? Kısmen. Aracın yamaları içeriğine
göre karşılaştıran bir yeteneği vardır: iki işlemenin ürettiği değişiklik aynıysa,
kimlikleri ayrı olsa bile aynı **yama kimliğini** taşırlar. İki dal arasında hangi
işlemelerin karşı tarafta zaten bulunduğunu bu karşılaştırma söyler.

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

$ git cherry -v ana rapor
+ 7e8f9a0 rapor: ozet satirini ekle
- 4d5e6f1 rapor: alan genisligini duzelt
```

Eksi işaretli satır, o değişikliğin karşı tarafta eşdeğer bir yama olarak zaten bulunduğunu
bildirir. Bu, kopyanın **var olduğunu** bulur; kopyanın **neden** alındığını bulmaz. İki
soru ayrıdır ve ikincisinin yanıtı yine yalnız mesajdadır.

Yama karşılaştırmasının bir sınırı da vardır: eşdeğerlik değişikliğin metnine bakar.
Kopya sırasında bir çakışma çözülmüşse ya da bağlam farklıysa yamalar birbirinin aynı
olmaz ve eşleşme kurulamaz. Kopya o zaman ayrı bir değişiklik gibi görünür.

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

- **BR22** — Kiraz toplama, kaynak işlemenin öncülüne göre yaptığı değişikliği hedef dalın
  ucuna **yeni kimlikli** bir işleme olarak yazar; kaynak işleme yerinde kalır.
- **BR23** — Yama kimliği değişikliğin kendisidir. Kopya aynı yama kimliğini taşır, işleme
  kimliği ayrıdır; ölçüm ikisini **ayrı işleme** olarak sayar.
- **BR24** — Kopya, hedef dalın kendi işlemelerinden sonra ve birleştirme işlemesinden önce
  yazılır; kendi zamanını taşır ve dalın bütünlüğünü bozmaz.
- **BR25** — Taban tarihçe birleştirme işlemesi biçimidir. Kopyanın eklenmesi dışında
  hiçbir şey değiştirilmez.
- **BR26** — İzlenen dosya `rapor.py`. Dosya izi sorusu, ona dokunan işlemelerin **ayrı
  ayrı bulunabilmesine** bakar; kaç ayrı değişiklik olduğuna bakmaz.
- **BR27** — Kusurlu bir işlemenin kopyası da kusurludur; kopyalanan değişiklik kusuru da
  taşır.
- **BR28** — Kümenin çözünürlüğü on iki işlemede **1/12**, altı soruda **1/6**.

## Ölçüm

```python
"""Kiraz toplama: ayni degisiklik tarihcede iki yerde durur.

Bolum 1 - kopya oncesi ve sonrasi: rapor.py dosyasina dokunan isleme sayisi.
Bolum 2 - dosya izi ve kusurun yalitimi sorulari kopyadan nasil etkilenir.
"""
TOHUM = 20260813
DALLAR = ("olcum", "rapor", "kimlik")
DOSYALAR = {"olcum": "olcum.py", "rapor": "rapor.py", "kimlik": "kimlik.py"}
KUSURLU = ("rapor", 2)
ORTAK_DOSYA = "ayar.py"
IZLENEN = "rapor.py"


def uretec(tohum):
    d = tohum % 2147483646 + 1

    def r(n):
        nonlocal d
        d = (d * 48271) % 2147483647
        return d % n
    return r


def gelisim():
    r, kayit, zaman = uretec(TOHUM), [], 0
    for adim in range(1, 5):
        for dal in DALLAR:
            zaman += 1 + r(3)
            dosya = (ORTAK_DOSYA if adim == 3 and dal in ("olcum", "rapor")
                     else DOSYALAR[dal])
            kayit.append({"dal": dal, "sira": adim, "dosya": dosya,
                          "kusurlu": (dal, adim) == KUSURLU, "zaman": zaman})
    return kayit


def tumlestir(kayit, bicim):
    t = []
    if bicim == "birlestirme islemesi":
        for dal in DALLAR:
            for k in [x for x in kayit if x["dal"] == dal]:
                t.append({**k, "dal_kaydi": dal, "zaman_korundu": True})
            t.append({"dal": dal, "sira": 0, "dosya": None, "kusurlu": False,
                      "zaman": max(x["zaman"] for x in kayit if x["dal"] == dal),
                      "dal_kaydi": dal, "birlesme": True, "zaman_korundu": True})
    return t


def s2_kusur(t):
    kusurlu = [x for x in t if x["kusurlu"]]
    return len(kusurlu) == 1 and not kusurlu[0].get("sikisik")


def s4_dosya(t):
    return all(isinstance(x["dosya"], str) or x.get("birlesme") for x in t)


def yama(x):
    """Yama kimligi: degisikligin kendisi. Kopya ayni yamayi tasir."""
    return x.get("yama", (x["dal"], x["sira"]))


def kiraz_topla(t, kaynak, hedef):
    """kaynak islemesi hedef dala kopyalanir: yeni kimlik, ayni yama."""
    y, k = [], next(x for x in t if (x["dal"], x["sira"]) == kaynak)
    son = max(x["zaman"] for x in t if x["dal"] == hedef
              and not x.get("birlesme"))
    for x in t:
        if x.get("birlesme") and x["dal"] == hedef:
            y.append({**k, "dal": hedef, "dal_kaydi": hedef, "zaman": son,
                      "yama": kaynak, "kopya": True})
        y.append(dict(x))
    return y


def dokunan(t, ad):
    return [x for x in t if x["dosya"] == ad]


kayit = gelisim()
TABAN = tumlestir(kayit, "birlestirme islemesi")
TARIHCELER = (("kopya yok", TABAN),
              ("kusursuz işleme kopyalandı", kiraz_topla(TABAN, ("rapor", 1),
                                                         "kimlik")),
              ("kusurlu işleme kopyalandı", kiraz_topla(TABAN, ("rapor", 2),
                                                        "kimlik")))

print(f"gerçek gelişim: {len(kayit)} işleme | izlenen dosya: {IZLENEN} | "
      f"gelişimde ona dokunan {sum(1 for k in kayit if k['dosya'] == IZLENEN)}")
print()
print(f"{'tarihçe':<26s} {'işleme':>6s} {'dokunan':>7s} {'ayrı yama':>9s}"
      f" {'yinelenen':>9s} {'dosya izi':>9s}")
for ad, t in TARIHCELER:
    d = dokunan(t, IZLENEN)
    ayri = len({yama(x) for x in d})
    print(f"{ad:<26s} {len(t):6d} {len(d):7d} {ayri:9d} {len(d) - ayri:9d}"
          f" {('evet' if s4_dosya(t) else 'hayır'):>9s}")
print()
print(f"{'tarihçe':<26s} {'kusurlu işleme':>14s} {'kusurun yalıtımı':>16s}")
for ad, t in TARIHCELER:
    print(f"{ad:<26s} {sum(1 for x in t if x['kusurlu']):14d}"
          f" {('evet' if s2_kusur(t) else 'hayır'):>16s}")
print()
for ad, t in TARIHCELER[1:]:
    k = [x for x in t if x.get("kopya")][0]
    print(f"{ad}: kopya {k['dal']} dalında, yaması {k['yama']}, "
          f"dosyası {k['dosya']}")
```

```
gerçek gelişim: 12 işleme | izlenen dosya: rapor.py | gelişimde ona dokunan 3

tarihçe                    işleme dokunan ayrı yama yinelenen dosya izi
kopya yok                      15       3         3         0      evet
kusursuz işleme kopyalandı     16       4         3         1      evet
kusurlu işleme kopyalandı      16       4         3         1      evet

tarihçe                    kusurlu işleme kusurun yalıtımı
kopya yok                               1             evet
kusursuz işleme kopyalandı              1             evet
kusurlu işleme kopyalandı               2            hayır

kusursuz işleme kopyalandı: kopya kimlik dalında, yaması ('rapor', 1), dosyası rapor.py
kusurlu işleme kopyalandı: kopya kimlik dalında, yaması ('rapor', 2), dosyası rapor.py
```

## Dosya İzinin Söylediği ve Söylemediği

Üst tablo dosya izi sorusuna üç tarihçede de **evet** verdiriyor. Sorunun tanımı
değişmedi: `rapor.py` dosyasına dokunan her işleme ayrı ayrı bulunabiliyor. Kopyalama bu
yanıtı bozmuyor, çünkü kopya da tek bir dosyaya dokunan tek bir işlemedir.

Bozulan şey yanıtın **anlamıdır**. Kopya yokken `rapor.py` dosyasına dokunan **3** işleme
var ve bunlar **3** ayrı yamayı taşıyor; sayılar örtüşüyor. Kopyadan sonra dokunan işleme
**4**, ayrı yama yine **3**, yinelenen **1**. Dosya izi hâlâ tam ama artık iki ayrı soruya
iki ayrı sayı veriyor: "bu dosyaya kaç işleme dokundu" sorusunun yanıtı 4, "bu dosyada
kaç ayrı değişiklik yapıldı" sorusunun yanıtı 3.

Bu ayrım ölçümden önce görünmezdi, çünkü kopya olmayan bir tarihçede iki sayı hep aynıdır.
Kiraz toplama onları ayırır ve tarihçeye bakan kişi hangisini okuduğunu bilmek zorunda
kalır. Bir dosyanın kaç kez değiştirildiğine bakarak istikrarsızlık ölçen bir okuma,
kopyaları saydığı için o dosyayı olduğundan hareketli gösterir. İz eksik değildir; iz
**yinelenmiştir** ve yinelenmenin işareti tarihçenin kendisinde durmaz. Onu bulmak için
yamaları içerik olarak karşılaştıran ayrı bir araç gerekir.

Aynı yinelenme satır düzeyinde de görünür. Bir satırın hangi işlemeden geldiğini soran
araç, kopyalanmış bir satır için **kopyayı** gösterir, kaynağı değil. Sorulan soru
genellikle "bu satır neden böyle" olduğuna göre, okunacak mesaj da kopyanın mesajıdır.
Kaynağın mesajı ne kadar ayrıntılı olursa olsun, köken satırı yazılmadıysa oraya giden
bir bağ yoktur. Kökeni kaydeden seçeneğin değeri tam olarak burada ortaya çıkar: iki
satırlık bir ek, kopyadan kaynağa giden tek bağdır.

## Kusurun İki Yeri

Alt tablo daha sert bir sonuç veriyor. Kusursuz bir işleme kopyalandığında kusurlu işleme
sayısı **1**'de kalıyor ve yalıtım sorusu **evet** veriyor: tarihçe değişti ama ölçüm
değişmedi. Kusurlu işleme kopyalandığında sayı **2** oluyor ve yalıtım sorusu **hayır**
veriyor.

Neden düştüğü tanımdan okunur: yalıtım sorusu kusuru getiren işlemenin **tek başına**
bulunmasını arar. Kusur iki ayrı işlemede duruyorsa "kusuru getiren işleme" tek bir yanıt
değildir. Bir dalda düzeltilen kusur öbür dalda ayakta kalır ve düzeltmenin oraya da
taşınması gerekir; taşındığında da tarihçede iki düzeltme, iki kimlik ve iki ayrı yer
oluşur.

Bu ikilik zamanla derinleşir. Kopya ile kaynak ayrı işlemelerdir ve bundan sonrası ayrı
yürür: kaynak dalda o değişikliğin üzerine yapılan bir düzeltme kopyaya kendiliğinden
gitmez, kopyanın bulunduğu dalda yapılan bir değişiklik de kaynağa dönmez. İki yer aynı
metinle başlar ve her düzenlemede biraz daha ayrışır. Yama karşılaştırması ilk günlerde
eşleşme bulur, ayrışma başladıktan sonra bulmaz — yani ikilik tam da onu bulmanın
zorlaştığı anda kalıcılaşır.

Sayısal etki **1/6**'dır: altı sorudan biri düşer ve birleştirme işlemesinin yanıtladığı
soru sayısı **5**'ten **4**'e iner. Bu, kümenin çözünürlüğüne eşit ve savunulabilir en
küçük farktır.

Buradan bir ölçüt çıkar. Kiraz toplama **tek yönlü ve kısa ömürlü** olduğunda ucuzdur:
yayımlanmış bir daldaki düzeltme geliştirme dalına alınır, sonra iki dal zaten
birleşeceği için kopya kalıcı bir yinelenme yaratmaz. Kiraz toplama iki dal arasında
**düzenli bir tümleştirme yolu** olarak kullanıldığında pahalıdır: her kopya bir yinelenen
yama, her yinelenen yama bir yanlış sayım ve bir kusur için iki ayrı yer demektir. İkinci
kullanımda gereken şey kopyalama değil, birleştirmedir.

## Özet

- Kiraz toplama, bir işlemenin öncülüne göre yaptığı değişikliği başka dalın ucuna yeni
  kimlikli bir işleme olarak yazar; kaynak işleme yerinde kalır ve aynı değişiklik iki
  yerde durur.
- Kopyanın kökeni araç tarafından kendiliğinden kaydedilmez; kaydeden seçenek kimliği
  **işleme mesajının içine** yazar, ayrı bir alan yoktur.
- Yamaları içeriğine göre karşılaştıran araç kopyanın **var olduğunu** bulur; **neden**
  alındığını bulmaz, ve çakışma çözülerek alınmış bir kopyayı hiç eşleştiremeyebilir.
- Dosya izi sorusu kopyadan sonra da **evet** verir, ama dokunan işleme **3**'ten **4**'e
  çıkarken ayrı yama **3**'te kalır; iz eksilmez, yinelenir.
- Kusurlu bir işleme kopyalandığında kusurlu işleme **2** olur ve yalıtım sorusu **hayır**
  verir; yanıtlanan soru sayısı **5**'ten **4**'e iner.

## Sonraki Adım

Kursun ölçtüğü tümleştirme biçimlerinden üçü artık kuruldu: birleştirme işlemesi, ileri
sarma ve yeniden temellendirme. Kiraz toplama bunlardan biri değildir — bir dalı ana dala
alma yolu değil, tek bir değişikliği taşıma yoludur. Geriye dördüncü biçim ve biçimleri
**yan yana** koymak kalıyor. Sonraki ders her dalın işlemelerini tek bir işlemede toplayan
sıkıştırmayı ekler ve dördünü tek tabloda karşılaştırır — en okunaklı tarihçeyi üreten
biçimin en az soru yanıtlayan biçim olduğu, ve tarihçeyi temizlemenin neden bilgi sildiği
orada sayıyla gösterilir.
