---
title: 'Sürüm Yönetimi'
source: 'https://academia.sh/tr/kurslar/python-projeleri/surum-yonetimi'
course: 'Python Projeleri: Paketleme ve Test'
language: tr
updated: '2026-08-17T18:10:31+00:00'
license: 'CC BY-SA 4.0'
---

# Sürüm Yönetimi

Aynı bildirim üç kurgu yorumlayıcı sürümünde 2 ayrı sürüm kümesi verir; bir yorumlayıcıda üretilmiş kilit dosyalarının dokuz kurulumundan 6'sı kabul edilip 3'ü reddedilir ve aynı kilit sabit yorumlayıcıda 1 ayrı sonuç verirken üç yorumlayıcıda bir ret üretir.

Önceki üç ders aynı bildirimin kaç ayrı sürüm kümesi verdiğini üç ayrı eksende ölçtü:
yalıtım sınırı, çözümleme stratejisi ve çözümleyicinin kendisi. Üçünde de yazılmamış bir
varsayım vardı — tek bir yorumlayıcı. Paket sürümleri karşılaştırılırken hepsinin aynı
yorumlayıcıda kurulabildiği kabul edildi.

Bu ders o varsayımı ölçüme sokar. Sorusu iki parçalıdır: **aynı proje, ayrı yorumlayıcı
sürümlerinde kaç ayrı sonuç veriyor**, ve bir yorumlayıcıda üretilmiş kilit dosyası bir
başkasında ne yapıyor? İkinci parçanın yanıtı, kilidin ne tür bir güvence olduğunu
kesinleştirecek.

## Yorumlayıcı da Bir Bağımlılıktır

Bir proje kendi bildirimini yazarken paketlerini sayar; yorumlayıcıyı saymayı çoğu zaman
atlar. Oysa yorumlayıcı da kurulan bir şeydir, sürümü vardır ve o sürüm değiştiğinde
projenin karşılaştığı davranış değişebilir.

Bu ders **gerçek sürüm numarası yazmaz.** Yorumlayıcılar kurgu etiketlerle anılır: `Y1`,
`Y2`, `Y3`. Etiketlerin sırası bir zaman sırasıdır — `Y1` en eski, `Y3` en yeni — ve bunun
dışında hiçbir şey ima etmez. Paketlerin sürümleri de önceki üç dersteki gibi kurgudur.

Ölçümün kurduğu ilişki basit bir tablodur: her paket sürümü, hangi yorumlayıcı sürümlerinde
kurulabildiğini bildirir. Bu bir kurgu değil, gerçek bir kısıttır; bir paket sürümü belli
bir dil düzeyine göre yazılmıştır ve o düzeyi karşılamayan bir yorumlayıcıda ya kurulamaz
ya çalışmaz. Kurguda bu ilişki bir küme olarak yazılmıştır ve **modellenmiştir**; hiçbir
ürün adı geçmez.

Bunun doğrudan sonucu şudur: yorumlayıcı, aday havuzunu **daraltır**. Bildirim
değişmemiştir, depo değişmemiştir, strateji değişmemiştir; ama aynı aralıktan seçilebilecek
sürümlerin listesi yorumlayıcıya göre kısalır. Çözümleme aynı kuralı ayrı bir havuza
uygular ve ayrı bir küme döndürür.

## Ortamın Yorumlayıcıya Bağlılığı

İlk derste sanal ortamın yorumlayıcıyı çoğaltmadığı, ona bağlandığı söylenmişti. Buradaki
ölçüm o cümlenin bedelini gösterir.

Bir ortam hangi yorumlayıcı üzerinde kurulduysa onunla anlamlıdır. Yorumlayıcı sürümü
değiştiğinde ortam taşınmaz: sitedeki paketlerin bir bölümü yeni yorumlayıcı için
üretilmemiş olabilir, ve içe aktarma yolu da yorumlayıcı sürümüne göre adlandırılır. Geçiş
işlemi bu yüzden bir yükseltme değil, **yeni bir ortam kurmaktır** — ve yeni ortamda ne
kurulacağı yeniden çözümlenir.

Aynı şey kilit dosyası için de geçerli midir? Kilit tam sürümler yazar ve çözümleme
yapmaz; öyleyse yeni yorumlayıcıda da aynı kümeyi kurmalıdır. Ölçümün sınadığı sav budur ve
yanıt tek kelimeyle verilemez.

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

- **OB37** — Depo, bildirim ve aralık kuralı ortak tanımdan birebir alınır; ders ikisinin de
  davranışını değiştirmez. Eklenen tek şey uyum tablosudur.
- **OB38** — Üç yorumlayıcı sürümü kurgudur ve `Y1`, `Y2`, `Y3` etiketleriyle anılır.
  **Gerçek sürüm numarası yazılmaz.**
- **OB39** — Uyum tablosu kurgudur ve kâhinin parçasıdır: her paket sürümünün hangi
  yorumlayıcılarda kurulabildiğini biz yazdık, bu yüzden her satırın doğru sonucu ölçmeden
  bilinir.
- **OB40** — Uyum bir ikili karardır: bir sürüm bir yorumlayıcıda ya kurulabilir ya
  kurulamaz. Kısmi çalışma ya da uyarıyla kurulum modellenmez.
- **OB41** — Çözümleme aday havuzunu önce bildirimle, sonra uyum tablosuyla daraltır. Sıra
  sonucu değiştirmez; iki süzgeç de kesişimi alır.
- **OB42** — Strateji bu derste sabittir: **en yeni uygun sürüm**. Strateji ekseni önceki iki
  derste ölçüldü ve burada tekrarlanmaz.
- **OB43** — Paketler bu derste birbirini gerektirmez; gerek ekseni önceki derste ölçüldü.
  Ölçülen tek yeni eksen yorumlayıcıdır.
- **OB44** — Kilit dosyası tam sürümler yazar ve çözümleme yapmaz. Kilitle kurulum, yazılan
  her sürümün hedef yorumlayıcıda kurulabilmesini gerektirir.
- **OB45** — Kurulum reddi bir hata değil, **ölçümün bir sonucudur** ve tabloda `ret` olarak
  sayılır. Reddedilen kurulum hiçbir ayrı sonuç üretmez.
- **OB46** — Her yorumlayıcının kilidi kendi çözümlemesinden üretilir; dokuz kurulum, üç
  kilidin üç yorumlayıcıya uygulanmasıdır.
- **OB47** — Yorumlayıcı sürümleri arasında geçiş, ortamın yeniden kurulmasıdır; eski site
  taşınmaz ve modelde de taşınmaz.
- **OB48** — **Gerçek kurulum yapılmaz, gerçek paket indirilmez, gerçek yorumlayıcı
  çağrılmaz.** Yorumlayıcı bir etiket, kurulum bir sözlüktür.
- **OB49** — Süre ölçülmez. Sayılan şey **ayrı sürüm kümesi**, **kabul** ve **ret** sayısıdır.
- **OB50** — Ölçüm tek koşumdur, belirlenimcidir ve kurguda rastgelelik yoktur.

## Ölçüm

```python
"""Yorumlayici surumleri: ayni proje, ayni bildirim, kac ayri sonuc."""

DEPO = {
    "olcum": [(1, 0), (1, 1), (1, 2), (2, 0)],
    "rapor": [(0, 9), (1, 0), (1, 1)],
    "ortak": [(3, 0), (3, 1), (3, 2), (4, 0)],
}
BILDIRIM = {"olcum": ((1, 0), (2, 0)), "rapor": ((1, 0), (2, 0)),
            "ortak": ((3, 0), (4, 0))}
PAKETLER = ("olcum", "ortak", "rapor")

# Kurgu yorumlayici surumleri; gercek surum numarasi degildir.
YORUMLAYICILAR = ("Y1", "Y2", "Y3")

# Paket surumu -> destekledigi yorumlayicilar
UYUM = {
    ("olcum", (1, 0)): {"Y1", "Y2"}, ("olcum", (1, 1)): {"Y1", "Y2"},
    ("olcum", (1, 2)): {"Y2", "Y3"}, ("olcum", (2, 0)): {"Y3"},
    ("ortak", (3, 0)): {"Y1", "Y2"}, ("ortak", (3, 1)): {"Y1", "Y2", "Y3"},
    ("ortak", (3, 2)): {"Y2", "Y3"}, ("ortak", (4, 0)): {"Y3"},
    ("rapor", (0, 9)): {"Y1"}, ("rapor", (1, 0)): {"Y1", "Y2"},
    ("rapor", (1, 1)): {"Y2", "Y3"},
}


def uygun(paket, yorumlayici):
    alt, ust = BILDIRIM[paket]
    return [s for s in DEPO[paket]
            if alt <= s < ust and yorumlayici in UYUM[(paket, s)]]


def coz(yorumlayici, strateji="en yeni"):
    secim = {}
    for paket in sorted(BILDIRIM):
        adaylar = uygun(paket, yorumlayici)
        if not adaylar:
            return None
        secim[paket] = adaylar[-1] if strateji == "en yeni" else adaylar[0]
    return secim


def kilit(secim):
    return dict(secim)


def kur(kilit_dosyasi, yorumlayici):
    """Kilit her surumu tam yazar; yorumlayici desteklemiyorsa kurulum reddedilir."""
    if all(yorumlayici in UYUM[(p, s)] for p, s in kilit_dosyasi.items()):
        return dict(kilit_dosyasi)
    return None


def yazim(secim):
    if secim is None:
        return f"{'reddedildi':>23s}"
    return " ".join(f"{'.'.join(map(str, secim[p])):>7s}" for p in PAKETLER)


def kisa(secim):
    if secim is None:
        return f"{'ret':>12s}"
    return f"{'/'.join('.'.join(map(str, secim[p])) for p in PAKETLER):>12s}"


def anahtar(secim):
    return tuple(sorted(secim.items()))


print(f"{'bildirimle çözümleme':<26s} {'olcum':>7s} {'ortak':>7s} {'rapor':>7s}")
cozumler = {}
for y in YORUMLAYICILAR:
    cozumler[y] = coz(y)
    print(f"{'yorumlayıcı ' + y:<26s} " + yazim(cozumler[y]))
print(f"aynı bildirim, üç yorumlayıcı: {len({anahtar(s) for s in cozumler.values()})} "
      f"ayrı sürüm kümesi")

print()
print(f"{'kilit üretildiği yorumlayıcı':<30s} " +
      " ".join(f"{'kurulum ' + y:>12s}" for y in YORUMLAYICILAR))
kabul, kumeler = 0, []
for uretim in YORUMLAYICILAR:
    k = kilit(cozumler[uretim])
    hucre = []
    for hedef in YORUMLAYICILAR:
        s = kur(k, hedef)
        kabul += s is not None
        if s is not None:
            kumeler.append(anahtar(s))
        hucre.append(kisa(s))
    print(f"{'kilit ' + uretim + ' üzerinde üretildi':<30s} " + " ".join(hucre))
print(f"dokuz kurulum: {kabul} kabul, {9 - kabul} ret; kabul edilenlerde "
      f"{len(set(kumeler))} ayrı sürüm kümesi")

print()
k2 = kilit(cozumler["Y2"])
sabit = [kur(k2, "Y2") for _ in range(3)]
gezen = [kur(k2, y) for y in YORUMLAYICILAR]
for ad, kurulumlar in (("aynı kilit, Y2'de üç kurulum", sabit),
                       ("aynı kilit, üç yorumlayıcıda", gezen)):
    olan = [s for s in kurulumlar if s is not None]
    print(f"{ad:<30s} {len({anahtar(s) for s in olan})} ayrı sonuç, "
          f"{len(kurulumlar) - len(olan)} ret")
```

```
bildirimle çözümleme         olcum   ortak   rapor
yorumlayıcı Y1                 1.1     3.1     1.0
yorumlayıcı Y2                 1.2     3.2     1.1
yorumlayıcı Y3                 1.2     3.2     1.1
aynı bildirim, üç yorumlayıcı: 2 ayrı sürüm kümesi

kilit üretildiği yorumlayıcı     kurulum Y1   kurulum Y2   kurulum Y3
kilit Y1 üzerinde üretildi      1.1/3.1/1.0  1.1/3.1/1.0          ret
kilit Y2 üzerinde üretildi              ret  1.2/3.2/1.1  1.2/3.2/1.1
kilit Y3 üzerinde üretildi              ret  1.2/3.2/1.1  1.2/3.2/1.1
dokuz kurulum: 6 kabul, 3 ret; kabul edilenlerde 2 ayrı sürüm kümesi

aynı kilit, Y2'de üç kurulum   1 ayrı sonuç, 0 ret
aynı kilit, üç yorumlayıcıda   1 ayrı sonuç, 1 ret
```

## İki Küme, Üç Yorumlayıcı

Üst tablo aynı bildirimi üç yorumlayıcıda çözüyor ve **2 ayrı sürüm kümesi** veriyor.

`Y1` satırı `1.1 / 3.1 / 1.0` veriyor. Üçünün de en yenisi değil bunlar; `olcum 1.2`,
`ortak 3.2` ve `rapor 1.1` bu yorumlayıcıda kurulamıyor ve havuzdan düşüyor. Strateji hâlâ
"en yeni uygun sürüm"; değişen, neyin uygun sayıldığı. `Y2` ve `Y3` ise aynı kümeyi veriyor:
`1.2 / 3.2 / 1.1`.

İki gözlem buradan çıkar. Birincisi, yorumlayıcı ekseni **kendi başına** bir ayrı sonuç
üretir: bildirime, stratejiye ve depoya dokunmadan iki kurulum elde edildi. İkincisi, sayı
yorumlayıcı sayısıyla aynı değil. Üç yorumlayıcı iki küme verdi çünkü `Y2` ile `Y3` aynı
adaylara izin veriyor. Ayrı sonuç sayısı, ortam sayısının değil **uyum tablosunun**
işlevidir.

`Y1` satırının bir yan sonucu daha var. O yorumlayıcıda çalışan bir proje, sonraki
sürümlerde düzeltilmiş kusurları taşıyan paketleri hiç görmez; bildirimi onları kabul etse
bile. Yorumlayıcıyı yerinde tutmak, paket sürümlerini de yerinde tutmaktır.

## Kilit Bir Yorumlayıcı İçin Üretilir

Orta tablo dokuz kurulum veriyor: üç kilit, üç hedef yorumlayıcı. **6 kabul, 3 ret.**

Her satırın kendi deseni var. `Y1` üzerinde üretilen kilit `Y1` ve `Y2`'de kuruluyor,
`Y3`'te **reddediliyor** — `olcum 1.1` ile `rapor 1.0` o yorumlayıcıda kurulamıyor. `Y2` ve
`Y3` üzerinde üretilen kilitler aynı kümeyi yazıyor ve ikisi de `Y1`'de reddediliyor.

Reddin ne olduğunu doğru okumak gerekir. Bu bir yükseltme hatası değildir; kilidin doğru
davranışıdır. Kilit tam sürümler yazar ve pazarlık yapmaz; yazdığı sürüm hedef ortamda
kurulamıyorsa yapabileceği tek şey durmaktır. Alternatifi, kilidi sessizce esnetip başka
bir sürüm kurmak olurdu — ve o durumda kilit, kilit olmaktan çıkardı.

Kabul edilen altı kurulum **2 ayrı sürüm kümesi** veriyor. Bu sayı üstteki tablonunkiyle
aynı, ve tesadüf değil: kilitler de o çözümlemelerden üretildi. Kilit yeni bir küme
yaratmaz, var olan bir kümeyi taşır.

## Kilidin Güvence Verdiği Eksen

Alt iki satır dersin sonucudur ve kilidin ne tür bir güvence olduğunu tam olarak yazar.

Aynı kilit, **sabit** bir yorumlayıcıda üç kez kurulduğunda **1 ayrı sonuç**, **0 ret**
veriyor. Aynı kilit üç ayrı yorumlayıcıda kurulduğunda yine **1 ayrı sonuç** ama **1 ret**
veriyor. Kilit hiçbir yerde ikinci bir küme üretmedi — sözünü tuttu. Tutamadığı şey başkaydı:
sözünü **her ortamda** tutamadı.

Buradan kilidin sınırı çıkıyor: **kilit yeniden üretilebilirliği bir yorumlayıcı içinde
sağlar; yorumlayıcı ekseninde sağlamaz.** O eksende kilit bir güvence değil, bir
**kısıttır** — ve kısıt olması kusur değil, işlevidir. Bir kilidin taşınamaması, taşınmaması
gerektiğinin bildirimidir.

Pratik karşılığı doğrudan bir kuraldır: kilit dosyası, üretildiği yorumlayıcı sürümünü de
yazmalıdır. Yazmadığında elde iki belge kalır — biri hangi sürümlerin kurulacağını söyler,
öbürü hangi ortamda geçerli olduğunu söylemez — ve ret, ancak kurulum anında görünür.
Bildirimin yorumlayıcı için de bir aralık taşıması aynı gerekçeyledir: proje hangi
yorumlayıcılarda çalıştığını söylemezse, uyum tablosu ancak kurulum denenerek keşfedilir.

Bir üçüncü sonuç da sayıların dışında durur. Yorumlayıcı geçişi bir bakım işi gibi
görünür, ama ölçüm onun bir **çözümleme** işi olduğunu gösteriyor: geçişte kilit yeniden
üretilir, yeni küme eskisinden ayrı çıkabilir ve proje o yeni kümede sınanmamıştır. Geçişin
maliyeti yorumlayıcıyı kurmak değil, **yeni kümeyi doğrulamaktır**.

## Yan Yana Duran Yorumlayıcılar

Ölçümün üç satırı bir makinede üç yorumlayıcının aynı anda bulunabileceğini varsayar, ve bu
varsayım gerçeğe uyar. Birden çok yorumlayıcı sürümünü yan yana tutan araçlar bir sınıf
oluşturur — **sürüm yöneticisi** — ve yaptıkları iş bir seçimdir: hangi dizinde hangi
yorumlayıcının çağrılacağı. Ürün adları burada da yazılmaz.

Seçimin nerede yapıldığı önemlidir. Sanal ortam kurulduğu anda bir yorumlayıcıya bağlanır;
o noktadan sonra projenin hangi yorumlayıcıyı kullandığı bir yapılandırma ayarı değil,
**ortamın kimliğidir**. Sürüm yöneticisinin seçtiği şey, yeni bir ortam kurulurken hangi
yorumlayıcının kullanılacağıdır — var olan bir ortamı başka bir yorumlayıcıya
devretmez.

Geçişin akışı bu yüzden beş adımdır ve hiçbiri atlanamaz: yeni yorumlayıcı kurulur, onun
üzerinde yeni bir ortam kurulur, bildirim yeniden çözümlenir, yeni kilit üretilir, proje
yeni kümede sınanır. Eski ortam ancak bundan sonra atılır. Ölçümün orta tablosu üçüncü ve
dördüncü adımın neden atlanamayacağını gösteriyor: yeni yorumlayıcıda eski kilidi kurmayı
denemek, üç durumdan birinde ret üretiyor.

Bir projenin aynı anda birden çok yorumlayıcıyı desteklemesi de aynı tablodan okunur.
Ölçümde her yorumlayıcının kendi kilidi var: **üç kilit, 2 ayrı küme.** İki yorumlayıcıyı
birden desteklemek, tek bir kilidi ikisine birden uydurmak değil, **iki kilit tutmak**
demektir. Tek kilitle desteklenebilen yorumlayıcılar yalnız o kilitteki bütün sürümlerin
ortak uyum kümesidir — tabloda `Y2` ile `Y3` böyle bir çifttir, `Y1` ile `Y3` değildir.

Yan yana durmanın bedeli de aynı tabloda duruyor: desteklenen her yorumlayıcı için ayrı bir
site, ayrı bir kurulum ve ayrı bir kilit. Üçü de projenin verdiği her söz için ayrı ayrı
ödenir; desteklenen sürüm sayısı arttıkça sabitlenmesi gereken küme sayısı da artar, ve her
küme kendi başına doğrulanmayı bekler.

## Özet

- Yorumlayıcı da bir bağımlılıktır ve aday havuzunu daraltır; bildirim, depo ve strateji
  değişmeden **2 ayrı sürüm kümesi** doğar.
- Ayrı sonuç sayısı ortam sayısına değil **uyum tablosuna** bağlıdır: üç yorumlayıcı iki
  küme verir, çünkü ikisi aynı adaylara izin verir.
- Bir yorumlayıcıda üretilen kilit başka birinde reddedilebilir: dokuz kurulumun **6'sı
  kabul, 3'ü rettir**. Ret bir hata değil, kilidin doğru davranışıdır.
- **Kilit yeniden üretilebilirliği bir yorumlayıcı içinde sağlar, yorumlayıcı ekseninde
  sağlamaz;** o eksende bir güvence değil bir kısıttır.
- İki yorumlayıcıyı birden desteklemek tek kilidi ikisine uydurmak değil, **iki kilit
  tutmaktır**; tek kilit ancak sürümlerinin ortak uyum kümesindeki yorumlayıcıları kapsar.
- Yorumlayıcı geçişi ortamın yeniden kurulmasıdır ve kilit yeniden üretilir; maliyeti
  kurulum değil, yeni kümenin doğrulanmasıdır.

## Sonraki Adım

Bu konu boyunca dört eksen ölçüldü — yalıtım sınırı, çözümleme stratejisi, çözümleyicinin
kendisi ve yorumlayıcı sürümü — ve dördü de aynı yöntemle tekleştirildi: kararı bir kez
verdir, yazıya geçir, sonraki koşumlara okut. Kurulumun kaç ayrı sonuç verdiği artık
sayılabiliyor.

Geriye kurulumun içindeki asıl şey kalıyor: **kod**. Ortam tek bir kümeye indirildiğinde,
o kümede koşan kodun kendisi her koşumda aynı kararı veriyor mu? Sonraki konu bu soruyu
sorar ve yanıtı ölçmek için testin ne olduğunu, bir takımın ne bildirdiğini ve aynı
takımın kaç ayrı karar verebildiğini ele alır.
