---
title: 'Dal Oluşturma ve Geçiş'
source: 'https://academia.sh/tr/kurslar/dallanma-ve-isbirligi/dal-olusturma-ve-gecis'
course: 'Dallanma ve İşbirliği'
language: tr
updated: '2026-08-17T18:10:43+00:00'
license: 'CC BY-SA 4.0'
---

# Dal Oluşturma ve Geçiş

Dal açmak ile dala geçmek ayrı işlemlerdir: geçiş yalnız iki dal arasında farklı olan dosyayı yeniden yazar ve elde kalan on iki durumun 3'ü taşınır, 5'i geçişi engeller, 4'ü geride kalır; sessizce kaybolan hiçbiri yoktur.

Önceki ders dallanmanın maliyetini ölçtü: üç dalın açılışı **0** yeni işleme ve **123** bayt
yazıyor. Ölçüm bir şeyi kasten dışarıda bıraktı. Bir dal adı yazıldıktan sonra `refs/heads`
altında yeni bir başvuru vardır, ama çalışma dizininde tek bir dosya değişmemiştir. `HEAD`
hâlâ eski dalı gösterir, ekrandaki kod hâlâ eski dalın kodudur. Ad yazılmıştır, o ada
geçilmemiştir.

Bu dersin sorusu geçişin kendisidir. Geçiş bir başvuru yazmaktan ibaret değildir; çalışma
dizinini ve hazırlık alanını hedef dalın gördüğü hâle getirmek zorundadır. İki soru buradan
doğar: geçiş kaç dosyaya dokunur, ve o sırada elde işlenmemiş bir değişiklik varsa ona ne
olur? İkinci sorunun tek bir yanıtı yoktur — değişikliğin türüne ve dosyanın iki dal
arasında farklı olup olmadığına göre üç ayrı sonuç doğar.

## İki Ayrı Komut

Dal oluşturmak ve dala geçmek aracın iki ayrı çağrısıdır. Birincisi yalnız başvuruyu yazar;
ikincisi `HEAD`i, hazırlık alanını ve çalışma dizinini birlikte günceller.

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

$ git branch olcum
$ git status --short --branch
## ana

$ git switch olcum
Switched to branch 'olcum'
$ git status --short --branch
## olcum
```

İlk çağrıdan sonra `git status` hâlâ `ana` diyor: dal var, geçilmemiş. İkinci çağrıdan sonra
aynı satır `olcum` diyor. Arada dosya adı geçmiyor, çünkü bu iki dal arasında henüz fark
yok; ölçüm birazdan farkın olduğu durumu sayacak.

İki işi tek çağrıda yapan bir kısayol vardır: `git switch -c olcum` önce başvuruyu yazar,
sonra ona geçer; eski biçimi `git checkout -b olcum`'dur. `git checkout` aşırı yüklü bir
addır — aynı komut hem dal değiştirir hem tek bir dosyayı geri alır, ve ayrım yalnız
çağrının biçiminden okunur. `git switch` ile `git restore` bu iki işi iki ada böler. Kurs
boyunca ayrık adlar kullanılır.

## Geçişin Üç Adımı

Bir dala geçmek üç ayrı yazma işlemidir ve üçü tek bir işlem gibi davranır: biri
başarısız olursa hiçbiri uygulanmaz.

Birincisi `HEAD`in yeniden yazılmasıdır. Önceki derste `HEAD`in bir işlemeyi değil bir dal
adını gösterdiği kurulmuştu; geçiş bu simgesel başvurunun içeriğini değiştirir ve maliyeti
tek bir satırdır. İkincisi hazırlık alanının hedef dalın ağacına göre yeniden kurulmasıdır.
Üçüncüsü çalışma dizinidir: hedef dalda **farklı** olan dosyalar hedefteki sürümle
değiştirilir.

Üçüncü adımın kapsamı kritiktir. Geçiş dalın tüm dosyalarını yeniden yazmaz, yalnız iki dal
arasında **farklı** olanları yazar. Fark iki türlüdür: içerik farkı (dosya iki dalda da var
ama sürümleri ayrı) ve varlık farkı (dosya bir dalda var, ötekinde yok). İkincisinde geçiş
ya bir dosya yaratır ya siler. Bu yüzden geçişin maliyeti dalın büyüklüğüne değil, iki dal
arasındaki farka bağlıdır — ve ölçümün üst tablosu bunu sayar.

## Elde Kalan Değişiklik: Üç Kural

Geçiş anında çalışma ağacında işlenmemiş bir değişiklik varsa aracın davranışı üç kuralla
belirlenir.

**Birinci kural.** Dosya iki dal arasında **özdeşse** geçiş o dosyaya dokunmaz. Üstündeki
her işlenmemiş değişiklik — çalışma dizinindeki de, hazırlık alanına alınmış olanı da —
olduğu gibi yeni dalda belirir. Bu genellikle istenen davranıştır: bir dalda başlanan küçük
bir düzeltme, o dosya öteki dalda değişmemişse yanınızda gelir.

**İkinci kural.** Dosya iki dal arasında **farklıysa** geçiş onu yeniden yazmak zorundadır.
Üstünde işlenmemiş bir değişiklik varsa araç bu değişikliği ezmek yerine geçişi **durdurur**.
Hiçbir şey yazılmaz, `HEAD` yerinde kalır, hata iletisi hangi dosyanın engellediğini söyler.

**Üçüncü kural.** İzlenmeyen dosya tarihçenin dışındadır ve hiçbir dalın ağacında yer almaz.
Hedef dalda aynı adda bir dosya yoksa geçişle birlikte olduğu yerde durur. Aynı adda izlenen
bir dosya varsa geçiş onun üzerine yazacaktır ve yine **durdurulur**. Buradaki ince nokta
şudur: dosya tarihçenin dışında olduğu hâlde geçişi engeller, çünkü engelin nedeni dosyanın
kaydı değil, adının çakışmasıdır.

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

$ git switch rapor
error: Your local changes to the following files would be overwritten by checkout:
	rapor.py
Please commit your changes or stash them before you switch branches.
Aborting

$ git switch rapor
error: The following untracked working tree files would be overwritten by checkout:
	ayar.py
Please move or remove them before you switch branches.
Aborting
```

İki ileti iki ayrı kuraldan geliyor ve ikisi de aynı sonucu bildiriyor: geçiş yapılmadı.
İkinci iletinin önerdiği çözüm de farklıdır — izlenmeyen dosya işlenemez ya da zulaya
alınamaz, taşınması ya da silinmesi istenir.

## Üç Çıkış Yolu

Engellenen bir geçişin önünde dört seçenek vardır ve üçü değişikliği korur.

Birincisi değişikliği **işlemektir**. Değişiklik eski dalın ucuna yazılır, bir başvurudan
erişilebilir olur ve geçiş serbest kalır. Değişiklik geçişle birlikte gelmez; eski dalda
kalır ve oraya dönüldüğünde bulunur.

İkincisi **zulaya (stash)** almaktır. `git stash push` işlenmemiş değişikliği çalışma
ağacından alır ve `refs/stash` altındaki ayrı bir başvuruya yazar; ağaç temizlenir, geçiş
serbest kalır. `git stash list` yığını listeler, `git stash pop` en üsttekini geri uygular.
Zula bir dala bağlı değildir — başka bir dalda da açılabilir, ve o dalda dosya farklıysa geri
uygulama bir çakışma çıkarabilir. Bu davranış birleştirme konusunun kapsamındadır ve orada
ele alınır.

Üçüncüsü değişikliği **taşımayı zorlamaktır**: `git switch -m` seçeneği işlenmemiş
değişikliği hedef dalın sürümüyle birleştirmeyi dener. Başarılı olduğunda değişiklik yeni
dalda belirir; olmadığında çalışma ağacında çözülmesi gereken bir çakışma bırakır. Bu ders
çakışma çözmez ve seçeneği yalnız adıyla anar.

Dördüncüsü değişiklikten **vazgeçmektir**. `git switch` komutunun bunun için bir seçeneği
vardır ve işlenmemiş değişikliği geri alınamaz biçimde siler; değişiklik hiçbir zaman bir
işlemeye ya da bir başvuruya yazılmadığı için kurtarılabileceği bir yer yoktur. Bu ders o
seçeneği çalıştırılabilir biçimde yazmaz. Güvenli alışkanlık şudur: vazgeçmeden önce zulaya
alın; zula geri alınabilir, silme alınamaz.

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

- **DL7** — Kurgu ortak tanımın on iki işlemesidir ve değiştirilmez. Taban ağacında üç dosya
  vardır: `olcum.py`, `rapor.py`, `kimlik.py`. `ayar.py` tabanda **yoktur**; üçüncü adımda
  `olcum` ve `rapor` onu ekler, bu yüzden `kimlik` dalının ağacında bulunmaz.
- **DL8** — Bir dalın çalışma ağacı, o dal ucundan görülen dosya sürümleridir: dala ait son
  işlemenin bıraktığı sürüm, dokunulmamışsa taban sürümü.
- **DL9** — Geçiş yalnız iki dal arasında **farklı** olan dosyayı yeniden yazar. Fark hem
  içerik farkını hem varlık farkını kapsar.
- **DL10** — Üç kural uygulanır: özdeş dosyadaki değişiklik **taşınır**; farklı dosyadaki
  işlenmemiş değişiklik geçişi **engeller**; izlenmeyen dosya hedefte aynı adda bir dosya
  yoksa taşınır, varsa geçişi engeller.
- **DL11** — On iki durum tek bir geçişte, `kimlik` dalından `rapor` dalına, denenir. Beş
  değişiklik türü sayılır: çalışma dizininde değiştirilmiş, hazırlık alanına alınmış,
  izlenmeyen, işlenmiş, zulaya alınmış.
- **DL12** — İşlenmiş ve zulaya alınmış değişiklik geçişi ilgilendirmez: ikisi de bir
  başvuruya yazılmıştır. Geçiş bunları taşımaz, bulundukları yerde bırakır; ölçüm bu sonucu
  **geride kalır** diye sayar.
- **DL13** — **Sessiz kayıp**, bir değişikliğin kullanıcıya bildirilmeden ortadan kalkmasıdır
  ve ayrı sayılır. Durdurulan geçiş bir kayıp değildir; hiçbir şey yazılmamıştır.
- **DL14** — Ölçüm bir dosya sistemi ölçümü değildir. Sayılan iki şey vardır: geçişin yeniden
  yazmak zorunda olduğu dosya ve geçiş anında elde kalan durumun nereye gittiği.

## Ölçüm

```python
"""Dal olusturma ile dala gecis ayri islemlerdir.

Bolum 1 - iki dal arasindaki dosya farki: gecisin yeniden yazdigi dosyalar.
Bolum 2 - on iki durum: elde kalan degisiklik gecisten sonra nerede.
"""
TOHUM = 20260813
DALLAR = ("olcum", "rapor", "kimlik")
DOSYALAR = {"olcum": "olcum.py", "rapor": "rapor.py", "kimlik": "kimlik.py"}
KUSURLU = ("rapor", 2)
ORTAK_DOSYA = "ayar.py"
TABAN = ("olcum.py", "rapor.py", "kimlik.py")   # ayar.py tabanda yoktur


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 agac(kayit, dal):
    """Bir dal ucundaki calisma agaci: dosya -> surum."""
    s = {d: "taban" for d in TABAN}
    for k in kayit:
        if k["dal"] == dal:
            s[k["dosya"]] = f"{dal}{k['sira']}"
    return s


def fark(kayit, kaynak, hedef):
    """Gecisin yeniden yazmak zorunda oldugu dosyalar."""
    a, b = agac(kayit, kaynak), agac(kayit, hedef)
    return sorted(d for d in set(a) | set(b) if a.get(d) != b.get(d))


KAYNAK, HEDEF = "kimlik", "rapor"
DURUMLAR = (("olcum.py", "çalışma dizini"), ("rapor.py", "çalışma dizini"),
            ("kimlik.py", "çalışma dizini"), ("olcum.py", "hazırlık alanı"),
            ("rapor.py", "hazırlık alanı"), ("kimlik.py", "hazırlık alanı"),
            ("not.txt", "izlenmeyen"), ("ayar.py", "izlenmeyen"),
            ("rapor.py", "işlenmiş"), ("kimlik.py", "işlenmiş"),
            ("rapor.py", "zulaya alınmış"), ("kimlik.py", "zulaya alınmış"))
YER = {"taşınır": "çalışma ağacında", "engellenir": "eski dalda, geçiş olmadı",
       "işlenmiş": "eski dalın ucunda", "zulaya alınmış": "zula yığınında"}


def sonuc(dosya, tur, farkli, hedef_agac):
    if tur in ("işlenmiş", "zulaya alınmış"):
        return "geride kalır"
    if tur == "izlenmeyen":
        return "engellenir" if dosya in hedef_agac else "taşınır"
    return "engellenir" if dosya in farkli else "taşınır"


kayit = gelisim()
print(f"kurgu: {len(kayit)} işleme, {len(DALLAR)} dal, taban ağacı "
      f"{len(TABAN)} dosya, dalların dokunduğu dosya "
      f"{len({k['dosya'] for k in kayit})}")
print()
print(f"{'geçiş':<20s}{'yeniden yazılan dosya':>22s}   hangileri")
for a, b in [("taban", d) for d in DALLAR] + [("kimlik", "rapor"),
                                              ("olcum", "rapor")]:
    f = fark(kayit, a, b)
    print(f"  {a + ' -> ' + b:<18s}{len(f):22d}   {', '.join(f)}")

farkli, hedef_agac = set(fark(kayit, KAYNAK, HEDEF)), agac(kayit, HEDEF)
print()
print(f"geçiş {KAYNAK} -> {HEDEF}: elde kalan on iki durum")
print(f"{'  elde ne var':<34s}{'hedefte':<9s}{'sonuç':<14s}değişiklik nerede")
sayac = {}
for dosya, tur in DURUMLAR:
    if tur in ("işlenmiş", "zulaya alınmış"):
        hedefte = "-"
    elif dosya not in hedef_agac:
        hedefte = "yok"
    elif tur == "izlenmeyen":
        hedefte = "var"
    else:
        hedefte = "farklı" if dosya in farkli else "özdeş"
    s = sonuc(dosya, tur, farkli, hedef_agac)
    sayac[s] = sayac.get(s, 0) + 1
    print(f"  {dosya + ' (' + tur + ')':<32s}{hedefte:<9s}{s:<14s}"
          f"{YER[tur] if s == 'geride kalır' else YER[s]}")
print()
for s in ("taşınır", "engellenir", "geride kalır"):
    print(f"{s:<14s}{sayac.get(s, 0):3d} / {len(DURUMLAR)}")
print(f"{'sessiz kayıp':<14s}{0:3d} / {len(DURUMLAR)}")
```

```
kurgu: 12 işleme, 3 dal, taban ağacı 3 dosya, dalların dokunduğu dosya 4

geçiş                yeniden yazılan dosya   hangileri
  taban -> olcum                         2   ayar.py, olcum.py
  taban -> rapor                         2   ayar.py, rapor.py
  taban -> kimlik                        1   kimlik.py
  kimlik -> rapor                        3   ayar.py, kimlik.py, rapor.py
  olcum -> rapor                         3   ayar.py, olcum.py, rapor.py

geçiş kimlik -> rapor: elde kalan on iki durum
  elde ne var                     hedefte  sonuç         değişiklik nerede
  olcum.py (çalışma dizini)       özdeş    taşınır       çalışma ağacında
  rapor.py (çalışma dizini)       farklı   engellenir    eski dalda, geçiş olmadı
  kimlik.py (çalışma dizini)      farklı   engellenir    eski dalda, geçiş olmadı
  olcum.py (hazırlık alanı)       özdeş    taşınır       çalışma ağacında
  rapor.py (hazırlık alanı)       farklı   engellenir    eski dalda, geçiş olmadı
  kimlik.py (hazırlık alanı)      farklı   engellenir    eski dalda, geçiş olmadı
  not.txt (izlenmeyen)            yok      taşınır       çalışma ağacında
  ayar.py (izlenmeyen)            var      engellenir    eski dalda, geçiş olmadı
  rapor.py (işlenmiş)             -        geride kalır  eski dalın ucunda
  kimlik.py (işlenmiş)            -        geride kalır  eski dalın ucunda
  rapor.py (zulaya alınmış)       -        geride kalır  zula yığınında
  kimlik.py (zulaya alınmış)      -        geride kalır  zula yığınında

taşınır         3 / 12
engellenir      5 / 12
geride kalır    4 / 12
sessiz kayıp    0 / 12
```

## Sayıların Okunması

Üst tablo geçişin maliyetini veriyor. Tabandan `kimlik` dalına geçiş **1** dosya yazıyor,
`olcum` ve `rapor` dallarına geçiş **2** dosya. İki dal arasındaki geçişler **3** dosya
yazıyor, çünkü iki dalın da kendi dosyası ile ortak `ayar.py` dosyası farklıdır. Ağaçtaki
dördüncü dosya her satırda yerinde kalıyor.

Bu sayı önceki dersin ölçüsünü tamamlıyor. Dal açmak **41** bayt yazıyordu ve ağacın
büyüklüğünden bağımsızdı. Dala geçmek ağaca dokunur, ama tüm ağaca değil: dört bin dosyalık
bir ağaçta iki dal üç dosyada ayrılıyorsa geçiş **3** dosya yazar. Kopya modelinde aynı iş
dört bin dosyanın tamamını kopyalamayı gerektirirdi. İşaretçi modelinin geçişteki karşılığı
budur — maliyet ağacın değil, **farkın** büyüklüğüdür.

Alt tablo dersin ana ölçüsü. On iki durumun **3**'ü taşınıyor, **5**'i geçişi engelliyor,
**4**'ü geride kalıyor. Sessiz kayıp **0**.

Taşınan üçünün ortak yanı, geçişin o dosyaya hiç dokunmamasıdır. `olcum.py` iki dalda da
taban sürümündedir, bu yüzden hem çalışma dizinindeki hem hazırlık alanındaki değişikliği
yanında getirir. `not.txt` hiçbir dalın ağacında yoktur ve geçişin umurunda değildir.
İkisinde de taşıma bir yetenek değil, bir **çakışmama** sonucudur.

Engellenen beşinin de tek bir nedeni var: dosya iki dal arasında farklı ve geçiş onu yeniden
yazacak. Çalışma dizini ile hazırlık alanı arasında bu bakımdan hiçbir fark yok — dördü de
aynı iki dosyadan, `rapor.py` ile `kimlik.py`'den geliyor. Beşincisi, `ayar.py`, ayrı bir
yoldan aynı sonuca varıyor: dosya izlenmiyor, hiçbir işlemede geçmiyor, ama hedef dalda aynı
adda izlenen bir dosya var. Tarihçenin dışında olmak geçişi engellememek anlamına gelmiyor.

Sıfır sessiz kayıp bir tasarım kararıdır. Araç hiçbir durumda işlenmemiş bir değişikliği
bildirmeden silmez; engellemeyi seçer. **5/12** oranındaki durdurma bir kusur değil, o
kararın bedelidir. Bunun karşılığı şudur: iş akışında bir geçiş engellendiğinde ortada
kaybedilmiş bir şey yoktur, yalnız kayda alınmamış bir şey vardır.

Geride kalan dördü aracın değil kullanıcının kararıdır ve ikisi arasında bir fark vardır.
İşlenmiş değişiklik eski dalın ucundadır; bir dal başvurusundan erişilir ve dal adı
listelendiğinde görünür. Zulaya alınmış değişiklik `refs/stash` altındadır; erişilebilir ama
hiçbir dalda görünmez ve unutulduğunda bulunması dal aramaktan zordur. Bir işlemenin hiçbir
dal başvurusundan erişilemediği durum bu konunun dördüncü dersinin konusudur.

On iki durumluk kümede ölçülebilen en küçük fark **1/12**'dir. Taşınan ile engellenen
arasındaki **2/12**'lik fark bu bandın iki katıdır ve savunulabilir; daha ince ayrımlar bu
kurguyla savunulamaz.

## Özet

- Dal oluşturmak yalnız bir başvuru yazar; dala geçmek `HEAD`i, hazırlık alanını ve çalışma
  dizinini birlikte günceller. `git switch -c` iki işi tek çağrıda yapar.
- Geçiş dalın tüm dosyalarını değil, iki dal arasında **farklı** olanları yeniden yazar;
  kurguda bu sayı tabandan dallara **1** ile **2**, dallar arasında **3** dosyadır.
- Özdeş dosyadaki işlenmemiş değişiklik taşınır; farklı dosyadaki değişiklik geçişi
  durdurur; izlenmeyen dosya yalnız hedefte aynı adda bir dosya varsa geçişi durdurur.
- On iki durumun **3**'ü taşınır, **5**'i engellenir, **4**'ü geride kalır; sessiz kayıp
  **0**'dır — araç işlenmemiş değişikliği silmek yerine geçişi durdurur.
- Engellenen geçişin üç güvenli çıkışı vardır: işleme, zula ve taşımayı birleştirmeyle
  zorlama; vazgeçme geri alınamaz ve zula onun güvenli karşılığıdır.

## Sonraki Adım

Geçişin hangi dosyaya dokunacağı iki dalın farkından okunuyor ve bu, adına hiç bakmadan
hesaplanan bir sayı. Ad ise başka bir soruya hizmet eder. Ölçümde `kimlik` ve `rapor`
adları geçişin sonucunu hiç değiştirmedi; ama aynı depoda otuz dal varken hangisinin hangi
işe ait olduğu, hangisinin kapatılabileceği, hangisinin uzun ömürlü olduğu yalnız adlardan
okunur. Sonraki ders adlandırma düzenini ölçer: tarihçenin birinci sorusu olan özellik
gruplaması dal kaydı tutulduğunda evet der, ama adlar düzensizse grubun ne olduğu yine de
okunamaz — ve ölçüm bu iki koşulun birbirinin yerine geçmediğini gösterir.
