---
title: 'İleri Sarma ve Birleştirme İşlemesi'
source: 'https://academia.sh/tr/kurslar/dallanma-ve-isbirligi/ileri-sarma-ve-birlestirme-islemesi'
course: 'Dallanma ve İşbirliği'
language: tr
updated: '2026-08-17T18:10:44+00:00'
license: 'CC BY-SA 4.0'
---

# İleri Sarma ve Birleştirme İşlemesi

İki dalın birleşmesi tarihçeye ya hiçbir şey yazar ya da iki öncüllü bir işleme; on iki işlemelik gelişim birleştirme işlemesiyle on beşe çıkıp altı sorunun beşini, ileri sarmayla on ikide kalıp üçünü yanıtlar.

Dal açmak ucuzdu: bir başvuru dosyasına yazılan tek bir işleme kimliği. Ad koymak düzen
getirdi: dal adları okunduğunda kimin neyi geliştirdiği anlaşılır oldu. İki işlem de
tarihçeyi **büyütmedi** — yalnız ona işaretçiler ekledi.

Bu dersin sorusu bundan sonrasıdır. İki dal ayrıldıktan sonra bir noktada **birleşir
(merge)**; peki birleşme tarihçeye ne yazar? Yanıt tek değildir. Aracın iki ayrı davranışı
vardır ve hangisinin uygulandığı, aylar sonra tarihçeye sorulacak soruların kaçının
yanıtlanabileceğini belirler.

## Birleşmenin İki Durumu

Bir dalı ana dala almak, iki işleme kimliğinin ortak atasını bulmak ve aradaki farkı
uygulamaktır. Aracın önünde iki ayrı durum vardır.

**Birinci durum:** dal ayrıldıktan sonra ana dala hiç işleme eklenmemiştir. O zaman dalın
işlemeleri zaten ana dalın son işlemesinin üzerine kuruludur ve birleştirilecek bir şey
yoktur. Aracın yapacağı tek iş, ana dalın işaretçisini dalın ucuna **kaydırmaktır**. Buna
**ileri sarma (fast-forward)** denir.

**İkinci durum:** iki taraf da ayrıldıktan sonra işleme almıştır. Tarihçe gerçekten
çatallanmıştır ve tek bir işaretçi kaydırmasıyla kapatılamaz. Araç iki tarafın içeriğini
birleştirir ve sonucu **iki öncüllü** yeni bir işlemeye yazar: **birleştirme işlemesi
(merge commit)**.

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

$ git merge olcum
Updating 3f1a2b0..9c4d7e1
Fast-forward
 olcum.py | 24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)

$ git merge rapor
Merge made by the 'ort' strategy.
 rapor.py | 31 +++++++++++++++++++++++++++++++
 1 file changed, 31 insertions(+)
```

İlk çağrı `Fast-forward` diyor: yeni bir işleme üretilmedi. İkincisi bir strateji adıyla
birleştirme yaptığını bildiriyor: yeni bir işleme üretildi. Aynı komut, iki ayrı sonuç.

## Ortak Ata ve Üçlü Birleştirme

Aracın hangi durumda olduğunu anlaması için önce **ortak atayı** bulması gerekir: iki dalın
uçlarından geriye gidildiğinde ulaşılan ilk ortak işleme. Ortak ata, iki dalın ayrıldığı
noktadır. Birinci durumun tanımı ortak ata cinsinden yazılabilir: ortak ata ana dalın
**ucuna eşitse** ana dal ayrılmadan beri hiç ilerlememiştir ve ileri sarma uygulanabilir.

Ortak ata ana dalın ucuna eşit değilse birleştirme üç dosya sürümü üzerinden yapılır: ortak
atadaki sürüm, ana daldaki sürüm ve dallardaki sürüm. Buna **üçlü birleştirme (three-way
merge)** denir ve üçüncü sürüm, yani atadaki hâl, ölçüyü veren şeydir. İki sürümü yan yana
koymak yeterli olsaydı araç her farkı bir çatışma sayardı; ata sürümü sayesinde araç bir
satırın **kim tarafından** değiştirildiğini bilir. Yalnız bir taraf değiştirmişse o tarafın
sürümü alınır; iki taraf da aynı satırı ayrı biçimde değiştirmişse karar verilemez ve
birleştirme çakışması doğar.

Ortak ata bir arama sonucudur, tarihçede yazılı bir alan değil. Bu, birleştirmenin
maliyetinin dal ömrüyle birlikte arttığı anlamına gelir: ata ne kadar geride kalırsa iki
taraf o kadar çok satırda ayrışmıştır.

## İleri Sarmanın Yazdığı

İleri sarma tarihçeye **hiçbir şey yazmaz**. Ana dalın başvurusu yeni bir kimliği
gösterir, o kadar. Dalın işlemeleri olduğu gibi ana dalın tarihçesinde belirir; ama
tarihçede onların bir dalda geliştirildiğini söyleyen hiçbir kayıt kalmaz. Dal işaretçisi
silindiğinde, o işlemelerin ayrı bir işe ait olduğu bilgisi de silinir.

Seçim aracın eline bırakılmak zorunda değildir. Varsayılan davranış uygulanabilir olduğunda
ileri sarar; `--no-ff` seçeneği ileri sarma mümkün olsa bile iki öncüllü bir işleme
üretmeye zorlar; `--ff-only` seçeneği bunun tersini yapar ve ileri sarma uygulanamıyorsa
birleştirmeyi **yapmadan durur**. Üçüncüsü ilk bakışta işe yaramaz görünür ama bir güvenlik
kilididir: tarihçesinin doğrusal kalmasını isteyen bir ekipte, farkında olmadan üretilmiş
bir birleştirme işlemesinin girmesini engeller. Üç ayarın hiçbiri öbüründen doğru değildir;
üçü de aynı sorunun üç ayrı yanıtıdır ve o soruyu bu dersin ölçümü sorar.

## Birleştirme İşlemesinin Yazdığı

Birleştirme işlemesinin tek özel yanı **iki öncülünün** olmasıdır. Birinci öncül ana dalın
o anki ucu, ikinci öncül birleştirilen dalın ucudur. Bu ikinci kenar, tarihçenin dal
yapısını taşıyan tek şeydir.

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

$ git log --oneline --graph
*   a1b2c3d rapor dalını birleştir
|\
| * 7e8f9a0 rapor: özet satırını ekle
| * 4d5e6f1 rapor: alan genişliğini düzelt
|/
* 9c4d7e1 olcum: eşik değerini yazdır
```

Sol kenardaki çizim ikinci öncülden üretilir. Girintili iki satır `rapor` dalının
işlemeleridir; `|/` işaretinin bulunduğu satır ayrılma noktasını gösterir. Bu çizim ileri
sarmayla alınmış bir dal için **çizilemez**, çünkü çizilecek kenar yoktur.

Buradaki kimlikler ve dosya adları kurgudur. Aynı komutu kendi deponuzda çalıştırdığınızda
kimlikler farklı olur; sabit olan çıktının yapısıdır.

## Ölçünün Kurulması

Kurs boyunca sürecek kurgu şudur: üç kişi aynı depoda üç ayrı işe başlıyor — `olcum`,
`rapor` ve `kimlik`. Her biri dört işleme yapıyor. Üçüncü adımda `olcum` ile `rapor` aynı
dosyaya, `ayar.py` dosyasına dokunuyor. `rapor` dalının ikinci işlemesi bir kusur
getiriyor. Gerçek gelişim **12 işlemedir** ve gerçek sırası bilinir, çünkü kurguyu biz
yazdık.

Bu on iki işleme ayrı **tümleştirme biçimleriyle (integration format)** ana dala alınır.
Biçimlerin hepsi aynı **kodu** üretir; ürettikleri **tarihçe** ayrıdır. Kurs bu farkı tek
bir ölçütle ölçer: tarihçeye altı soru sorulur ve kaçını yanıtlayabildiği sayılır.

1. **Özellik gruplaması** — hangi işlemeler hangi işe ait?
2. **Kusurun yalıtımı** — kusuru getiren işleme tek başına bulunabiliyor mu?
3. **Gerçek sıra** — işler hangi sırayla geliştirildi?
4. **Dosya izi** — bir dosyaya dokunan her işleme ayrı ayrı bulunabiliyor mu?
5. **Dalın bütünlüğü** — bir dalın işlemeleri bir arada mı duruyor?
6. **Çakışma kararı** — çakışma nerede çözüldü ve hangi taraf seçildi?

Bu altı soru kursun sabitidir; sonraki derslerde tanımları değişmez, yalnız yanıtları
değişir.

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

- **BR1** — Gerçek gelişim kurgudan üretilir; sırası ve kusurlu işlemesi **bilinir**,
  çünkü kurguyu biz yazdık. Tarihçenin bunu bilmesi gerekmez.
- **BR2** — İleri sarma, dal ayrıldıktan sonra ana dala işleme eklenmemiş durumu temsil
  eder: işlemeler gerçek zaman sırasına dizilir ve **dal kaydı tutulmaz**.
- **BR3** — Birleştirme işlemesi her dal için bir kapanış işlemesi ekler; bu işleme dosyaya
  dokunmaz ve kusur taşımaz, yalnız **dal kaydını** taşır.
- **BR4** — Bir sorunun yanıtlanabilmesi, tarihçede o yanıtı veren kaydın **bulunması**
  demektir; kaydı okuyanın ne kadar uğraştığı ölçüme girmez.
- **BR5** — Altıncı soru, tarihçede çakışmanın seçilen tarafını taşıyan bir alan aranarak
  ölçülür. Bu ders çakışmayı çözmez; alan yoktur ve soru bu derste iki biçimde de
  yanıtsızdır.
- **BR6** — Ölçüm kodu üretir varsaymaz; iki biçimin ürettiği **kod aynıdır**, ölçülen
  yalnız tarihçedir.
- **BR7** — Kümenin çözünürlüğü on iki işlemede **1/12**, altı soruda **1/6**; bundan
  küçük bir fark bu kurguyla savunulamaz.

## Ölçüm

```python
"""Iki tumlestirme bicimi: birlestirme islemesi ve ileri sarma.

Bolum 1 - gercek gelisim: uc dal, her dalda dort isleme.
Bolum 2 - iki bicimin biraktigi tarihceye alti soru sorulur.
"""
TOHUM = 20260813
DALLAR = ("olcum", "rapor", "kimlik")
DOSYALAR = {"olcum": "olcum.py", "rapor": "rapor.py", "kimlik": "kimlik.py"}
KUSURLU = ("rapor", 2)
ORTAK_DOSYA = "ayar.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})
    elif bicim == "ileri sarma":
        for k in sorted(kayit, key=lambda x: x["zaman"]):
            t.append({**k, "dal_kaydi": None, "zaman_korundu": True})
    return t


def s1_gruplama(t):
    return all(x.get("dal_kaydi") for x in t if not x.get("birlesme"))


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


def s3_sira(t):
    return all(x.get("zaman_korundu") for x in t)


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


def s5_kapsam(t):
    yerler = {}
    for i, x in enumerate(t):
        if x.get("birlesme"):
            continue
        yerler.setdefault(x["dal"], []).append(i)
    return all(y[-1] - y[0] == len(y) - 1 for y in yerler.values())


def s6_cakisma(t):
    return any("secilen" in x for x in t)


SORULAR = (("özellik gruplaması", s1_gruplama), ("kusurun yalıtımı", s2_kusur),
           ("gerçek sıra", s3_sira), ("dosya izi", s4_dosya),
           ("dalın bütünlüğü", s5_kapsam), ("çakışma kararı", s6_cakisma))
BICIMLER = ("birlestirme islemesi", "ileri sarma")
kayit = gelisim()
T = {b: tumlestir(kayit, b) for b in BICIMLER}

print(f"gerçek gelişim: {len(kayit)} işleme, {len(DALLAR)} dal, ortak dosyaya "
      f"dokunan {sum(1 for k in kayit if k['dosya'] == ORTAK_DOSYA)}, "
      f"kusurlu işleme {sum(1 for k in kayit if k['kusurlu'])}")
print()
print(f"{'biçim':<22s} {'işleme':>6s} {'gelişimden':>10s} {'eklenen':>7s}")
for b in BICIMLER:
    ek = sum(1 for x in T[b] if x.get("birlesme"))
    print(f"{b:<22s} {len(T[b]):6d} {len(T[b]) - ek:10d} {ek:7d}")
print()
print(f"{'soru':<20s} {'birlestirme islemesi':>20s} {'ileri sarma':>12s}")
for ad, soru in SORULAR:
    print(f"{ad:<20s} {('evet' if soru(T[BICIMLER[0]]) else 'hayır'):>20s}"
          f" {('evet' if soru(T[BICIMLER[1]]) else 'hayır'):>12s}")
print(f"{'yanıtlanan':<20s} {sum(s(T[BICIMLER[0]]) for _, s in SORULAR):20d}"
      f" {sum(s(T[BICIMLER[1]]) for _, s in SORULAR):12d}")
```

```
gerçek gelişim: 12 işleme, 3 dal, ortak dosyaya dokunan 2, kusurlu işleme 1

biçim                  işleme gelişimden eklenen
birlestirme islemesi       15         12       3
ileri sarma                12         12       0

soru                 birlestirme islemesi  ileri sarma
özellik gruplaması                   evet        hayır
kusurun yalıtımı                     evet         evet
gerçek sıra                          evet         evet
dosya izi                            evet         evet
dalın bütünlüğü                      evet        hayır
çakışma kararı                      hayır        hayır
yanıtlanan                              5            3
```

## Üç İşlemenin Satın Aldığı

Üst tablo iki biçimi işleme sayısıyla karşılaştırıyor. Birleştirme işlemesi tarihçeyi
**15** işlemeye çıkarıyor: on ikisi gerçek gelişimden, **3**'ü aracın eklediği kapanış
işlemeleri. İleri sarma **12**'de kalıyor ve hiçbir şey eklemiyor.

Sezgi burada ileri sarmadan yana çalışır: aynı iş, daha az kayıt. Alt tablo bunun tersini
söylüyor. Birleştirme işlemesi altı sorunun **5**'ini, ileri sarma **3**'ünü yanıtlıyor.
Üç fazladan işleme, iki fazladan yanıt satın alıyor.

Satın alınan iki yanıt hangileri? **Özellik gruplaması** ve **dalın bütünlüğü**. İkisi de
aynı kayıptan doğuyor: ileri sarmada dal kaydı tutulmuyor. İşlemeler gerçek zaman sırasına
diziliyor, yani üç işin işlemeleri iç içe geçiyor — `olcum` dalının dört işlemesi ana
dalda ardışık durmuyor, aralarına öbür iki dalın işlemeleri giriyor. Tarihçe "bu işleme
hangi işe aitti" sorusuna yanıt veremiyor, çünkü işi adlandıran kayıt hiç yazılmamış.

Dördü ortak: **kusurun yalıtımı**, **gerçek sıra** ve **dosya izi** iki biçimde de evet.
Kusurlu işleme iki tarihçede de tek başına duruyor; hiçbir biçim onu bir başkasıyla
birleştirmedi. Zaman damgaları da korundu. Bu üç yanıt için fazladan bir kayda gerek yok.

**Çakışma kararı** iki biçimde de hayır. `olcum` ile `rapor` üçüncü adımda aynı dosyaya
dokunuyor ve bu bir **birleştirme çakışması (merge conflict)** doğuruyor; ama iki tarihçede
de çakışmanın nasıl çözüldüğünü söyleyen bir kayıt yok. Dikkat edilmesi gereken şudur:
birleştirme işlemesi çakışmanın **olduğu yeri** taşır — çözüm o işlemede yazılıdır — ama
hangi tarafın seçildiğini ayrı bir alan olarak tutmaz. Ölçüm bu ayrımı bir alan arayarak
yapıyor ve alan iki biçimde de yok. Bu sonuç dört biçimin dördü için de geçerlidir ve
sonraki ders bunu ödeyecektir.

## Seçim Neye Bağlı

İki biçim arasındaki fark bir doğru–yanlış değil, bir takastır. Ölçülen kümede fark
**2/6**'dır: altı sorudan ikisi. Kümenin çözünürlüğü **1/6** olduğuna göre bu fark ölçüm
bandının iki katıdır ve savunulabilir.

Ödenen bedel **3/12**'dir: on iki işlemelik bir gelişime üç işleme eklenmiştir. Dal sayısı
arttıkça bu bedel doğrusal büyür, çünkü her dal bir kapanış işlemesi ekler. On iki dallı
bir tümleştirmede tarihçenin dörtte biri kapanış işlemesinden oluşur ve günlük çıktısı
gerçek işi göstermek yerine kapanışları sayar.

Ölçüt şudur: **dal kaydı sonradan sorulacak mı?** Tek işlemelik bir düzeltmede sorulmaz ve
ileri sarma kaybı sıfırdır. Dört işlemelik bir özellik dalında sorulur; oradaki üç
işlemelik bedel, iki sorunun yanıtı için ödenmiş olur.

Eklenen üç işlemenin ikinci bir getirisi de vardır. Birleştirme işlemesinin **birinci
öncülü** ana dalın kendi çizgisidir; günlük yalnız birinci öncülleri izleyecek biçimde
çağrıldığında tarihçe, ölçümdeki on iki işleme yerine üç kapanış işlemesine iner. Aynı
tarihçe iki ayrı çözünürlükte okunabilir hâle gelir: **ne yapıldı** sorusuna üç satır,
**nasıl yapıldı** sorusuna on iki satır. İleri sarmada bu ikinci çözünürlük yoktur, çünkü
ayıracak kenar yoktur — her okuma on iki satır verir.

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

$ git log --oneline --first-parent
a1b2c3d rapor dalını birleştir
b2c3d4e olcum dalını birleştir
9c4d7e1 ilk kurulum
```

Bu iki çözünürlüğün ikisi de dal kaydına dayanır; kayıt yoksa ikisi çakışır ve ayrım
kurulamaz.

## Özet

- İleri sarma, ana dal ayrılma noktasından beri hiç ilerlememişse uygulanır ve tarihçeye
  hiçbir işleme yazmaz; yalnız dal işaretçisini kaydırır.
- Birleştirme işlemesi iki öncüllü bir işlemedir; ikinci öncül, tarihçenin dal yapısını
  taşıyan tek kayıttır ve günlük çizimi ondan üretilir.
- On iki işlemelik gelişim birleştirme işlemesiyle **15** işlemeye çıkar, ileri sarmayla
  **12**'de kalır; eklenen **3** işleme dal başına bir kapanıştır.
- Birleştirme işlemesi altı sorunun **5**'ini, ileri sarma **3**'ünü yanıtlar; farkı
  yaratan iki soru **özellik gruplaması** ve **dalın bütünlüğüdür**.
- Kusurun yalıtımı, gerçek sıra ve dosya izi iki biçimde de yanıtlanır; çakışma kararı
  ikisinde de yanıtsızdır.

## Sonraki Adım

Ölçümde `olcum` ile `rapor` aynı dosyaya dokundu ve iki tarihçe de bunun nasıl çözüldüğünü
kaydetmedi. Sonraki ders o çözümün kendisine bakacak: araç iki tarafı birleştiremediğinde
dosyaya ne yazar, çakışma işaretleri nasıl okunur, çözümün doğru olduğu nasıl doğrulanır —
ve çözüm bittiğinde tarihçeye tam olarak neyin yazıldığı, neyin yazılmadığı.
