İçeriğe geç
academia.sh

Ders 11 / 15

Uzak Depo Tanımlama

Uzak depo tanımı bir adı bir adrese bağlar ve tarihçeye dokunmaz; üç kopya sırasıyla 5, 10 ve 15 işleme taşır ve 4, 5, 5 soru yanıtlar, iki tanım sonrası yerel kopya 5 işleme ve 4 soruda kalır.

İçindekiler

Önceki ders dal stratejilerini kurdu: uzun ömürlü dal, kısa ömürlü dal ve seçilen stratejinin tarihçeye ne bıraktığı. O tartışmanın tamamı tek bir kopyanın içinde geçti. Dallar aynı depoda açıldı, aynı depoda birleşti; ölçtüğümüz tarihçe tek bir yerde duruyordu ve o yerde duran şey işin tamamıydı.

Dağıtık bir sürüm kontrolünde bu varsayım ayakta durmaz. Tarihçe tek bir yerde değil, birden çok kopyada yaşar; kopyalar birbirinden habersiz ilerler ve hiçbiri kendiliğinden ötekinin işlemelerini bilmez. Bu dersin sorusu, kopyaların nasıl senkronlandığı değil — o sonraki dersin konusu. Bu dersin sorusu daha önce gelir: bir kopya öbürünü nasıl adlandırır, ve adlandırma tarihçeye ne ekler?

Kopya ve Uzak Depo

Sürüm Kontrolüne Giriş kursundaki “Merkezî ve Dağıtık Modeller” dersi ayrımı kurmuştu: dağıtık bir modelde her kopya tam bir depodur. Kopyanın kendi çalışma alanı, kendi hazırlık alanı, kendi dalları ve kendi tarihçesi vardır. Hiçbir kopya yapısı gereği ötekinden üstün değildir; “merkez” bir uzlaşımdır, bir araç özelliği değil.

Uzak depo (remote), bir depoda tanımlı olan ve başka bir kopyanın adresine bağlanmış addır. Bu ayrımı baştan koymak gerekir: karşı taraftaki kopya uzak depo değildir; uzak depo, o kopyaya bu depoda verilen yerel addır. Aynı kopya iki ayrı depoda iki ayrı adla tanımlanabilir ve bu bir tutarsızlık değildir, çünkü ad yereldir.

Tanımın nerede durduğu bu yüzden önemlidir. Uzak depo tanımı deponun yapılandırma dosyasına yazılır, tarihçeye değil. Doğrudan sonucu şudur: bir kopyayı alan başkası senin uzak depo adlarını almaz — kendi tanımlarını kendi yapar. Tanım paylaşılan bir veri değil, kişisel bir yönlendirme tablosudur.

Tanımlama Ne Yapar

Tanım, alt komutlarla yönetilir. Aşağıdaki blok örnek dökümtür; çalıştırılmamıştır ve adresler kurgudur.

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

git remote add koken ornek.test:takim/olcum-aglari.git
git remote add yukari https://ornek.test/kaynak/olcum-aglari.git
git remote -v

koken   ornek.test:takim/olcum-aglari.git (fetch)
koken   ornek.test:takim/olcum-aglari.git (push)
yukari  https://ornek.test/kaynak/olcum-aglari.git (fetch)
yukari  https://ornek.test/kaynak/olcum-aglari.git (push)

-v seçeneği her ad için iki satır verir, çünkü getirme ve itme adresleri ayrı ayarlanabilir. Yalnız okunacak bir kopyanın itme adresi bilerek geçersiz bırakılabilir; o zaman ada yapılan bir itme denemesi ağa çıkmadan durur.

Kalan alt komutlar aynı tabloyu düzenler: git remote rename adı değiştirir, git remote set-url adrese bağlı adresi değiştirir, git remote remove tanımı ve ona bağlı uzak izleme başvurularını siler, git remote show bir adın altındaki dalları listeler. git remote remove yerel dalları ve işlemeleri silmez; sildiği şey adlar ve o adların altına yazılmış başvurulardır.

Bir kopyayı ilk kez alırken uzak depo adı elle yazılmaz: klonlama, kaynağa bir varsayılan ad yazar (origin). Bu dersin ölçümü kopyaların rollerini okunur tutmak için kendi adlarını kullanıyor: yazma yetkisinin bulunduğu kopyaya koken, yalnız okunan yukarı depoya yukari.

Uzak İzleme Başvuruları

Tanım tek başına bir addır; adın altında ne olduğu ayrı bir başvuru kümesinde tutulur. Yerel dallar refs/heads altında durur, bir uzak deponun dalları ise refs/remotes/<ad> altında. İkinci kümedeki başvurulara uzak izleme başvurusu denir.

Uzak izleme başvurusunun kuralı tek cümledir: yerelden yazılmaz. Üzerine işleme yapılmaz, elle ileri alınmaz; yalnız karşı taraftan veri getirildiğinde güncellenir. Bu yüzden uzak izleme başvurusu bir dal değil, karşı tarafın dalının en son görülmüş hâlinin kaydıdır.

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

git branch -a

* olcum
  remotes/koken/olcum
  remotes/koken/rapor
  remotes/yukari/kimlik
  remotes/yukari/olcum
  remotes/yukari/rapor

Yıldız yerel dalı işaretler; kalan beş satır iki uzak deponun altındaki başvurulardır. Aynı kısa ad birden çok kez görünüyor ve bu bir kusur değil, ad alanının çalıştığının kanıtıdır.

Ölçümün Varsayımları

  • UD1 — Üç kopya aynı kurgudan üretilir: yerel yalnız olcum dalını, koken olcum ile raporu, yukari üçünü de taşır. Üçü de aynı tümleştirme biçimini — birleştirme işlemesini — kullanır; ölçülen fark biçim değil, taşınan dal kümesidir.
  • UD2 — Kopyaların ortak dalları ayrışmaz: bir dal iki kopyada da varsa aynı işlemeleri taşır. Ayrışmış kopya sonraki dersin konusudur.
  • UD3 — Tanımlama işlemi uzaklar sözlüğüne bir ad–adres çifti yazar ve tarihce listesine dokunmaz; ölçüm bu iki alanı ayrı ayrı sayar.
  • UD4 — Adresler kurgudur ve ölçüme girmez; ölçüm adresin biçimine değil, tanımın sayısına bakar.
  • UD5 — Altı soru kursun sabitidir ve burada değişmez. Değişen tek şey soruların sorulduğu kopyadır.
  • UD6 — Başvuru sayımı yerel dalları ve uzak izleme başvurularını birlikte sayar; kısa ad, başvurunun uzak depo öneki atılmış hâlidir.

Ölçüm

"""Uzak depo tanımlama: ad bir adrese bağlanır, tarihçe taşınmaz.

Bölüm 1 - üç kopyanın taşıdığı tarihçe ve yanıtlayabildiği soru.
Bölüm 2 - tanımlama işleminin yerel tarihçeye dokunduğu yer.
Bölüm 3 - uzak depo adının açtığı ad alanı.
"""
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():
    """Gerçek gelişim: üç dal, dörder işleme, biri kusuru getiriyor."""
    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 tarihce(kayit, dallar):
    """Verilen dalları birleştirme işlemesiyle almış bir kopyanın tarihçesi."""
    t = []
    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 s1(t):
    return all(x.get("dal_kaydi") for x in t if not x.get("birlesme"))


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


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


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


def s5(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(t):
    return any("secilen" in x for x in t)


SORULAR = (("özellik gruplaması", s1), ("kusurun yalıtımı", s2), ("gerçek sıra", s3),
           ("dosya izi", s4), ("dalın bütünlüğü", s5), ("çakışma kararı", s6))

KOPYALAR = {"yerel": ("olcum",), "koken": ("olcum", "rapor"),
            "yukari": ("olcum", "rapor", "kimlik")}


def tanimla(depo, ad, adres):
    """Uzak depo tanımlama: ada bir adres bağlanır, tarihçeye dokunulmaz."""
    depo["uzaklar"][ad] = adres
    return depo


def olc(d):
    return len(d["tarihce"]), sum(f(d["tarihce"]) for _, f in SORULAR)


kayit = gelisim()
print(f"gerçek gelişim {len(kayit)} işleme, {len(DALLAR)} dal; "
      f"kopya {len(KOPYALAR)}")
print()
print("kopya   dal  işleme  yanıtlanan  yanıtlanamayan")
for ad, dallar in KOPYALAR.items():
    t = tarihce(kayit, dallar)
    yok = [soru for soru, f in SORULAR if not f(t)]
    print(f"  {ad:6s} {len(dallar):3d} {len(t):7d} {len(SORULAR) - len(yok):11d}"
          f"  {', '.join(yok)}")

print()
depo = {"tarihce": tarihce(kayit, KOPYALAR["yerel"]), "uzaklar": {}}
once = olc(depo)
tanimla(depo, "koken", "ornek.test/koken")
tanimla(depo, "yukari", "ornek.test/yukari")
sonra = olc(depo)
print(f"tanımlamadan önce yerel: {once[0]} işleme / {once[1]} soru")
print(f"{len(depo['uzaklar'])} tanımdan sonra yerel: {sonra[0]} işleme / {sonra[1]} soru")

print()
basvuru = [("yerel", dal) for dal in KOPYALAR["yerel"]]
basvuru += [(uzak, dal) for uzak in depo["uzaklar"] for dal in KOPYALAR[uzak]]
kisa = [dal for _, dal in basvuru]
paylasilan = sorted(a for a in set(kisa) if kisa.count(a) > 1)
print(f"başvuru {len(basvuru)} | ayrı kısa ad {len(set(kisa))} | "
      f"birden çok başvurunun paylaştığı kısa ad {len(paylasilan)}")
for a in paylasilan:
    print(f"  {a}: " + ", ".join(f"{u}/{d}" for u, d in basvuru if d == a))
gerçek gelişim 12 işleme, 3 dal; kopya 3

kopya   dal  işleme  yanıtlanan  yanıtlanamayan
  yerel    1       5           4  kusurun yalıtımı, çakışma kararı
  koken    2      10           5  çakışma kararı
  yukari   3      15           5  çakışma kararı

tanımlamadan önce yerel: 5 işleme / 4 soru
2 tanımdan sonra yerel: 5 işleme / 4 soru

başvuru 6 | ayrı kısa ad 3 | birden çok başvurunun paylaştığı kısa ad 2
  olcum: yerel/olcum, koken/olcum, yukari/olcum
  rapor: koken/rapor, yukari/rapor

Kopyanın Yanıtlayabildiği

Üst tablo aynı soruyu üç ayrı kopyaya soruyor. yukari on beş işleme taşıyor ve beş soru yanıtlıyor; koken on işlemeyle aynı beşi yanıtlıyor; yerel beş işlemeyle dört.

Eksik olan soru kusurun yalıtımı ve eksikliğin nedeni burada yeni bir şeydir. Önceki derslerde bir sorunun yanıtsız kalması, seçilen tümleştirme biçiminin bilgiyi silmesinden geliyordu: sıkıştırma on iki işlemeyi üçe indiriyor ve kusurlu işlemeyi ayrı okunamaz hâle getiriyordu. Burada hiçbir şey silinmedi. yerel kopya kusuru yalıtamıyor çünkü kusurlu işleme onda hiç yok — kusuru rapor dalının ikinci işlemesi getiriyor ve rapor dalı bu kopyada bulunmuyor.

Bu, kursun ölçüsüne ikinci bir kayıp kaynağı ekler. Tarihçe, biçim yüzünden bilgi kaybedebilir; kopya, kapsam yüzünden bilgi kaybedebilir. İkincisi geri alınabilir bir kayıptır: eksik dallar getirildiğinde soru yeniden yanıtlanır hâle gelir. Biçim kaybı için aynı şey söylenemez.

koken ile yukari arasındaki karşılaştırma ikinci bir şey söylüyor. Beş işleme fark var ve yanıtlanan soru sayısı aynı. Taşınan işlemenin artması yanıtlanan soruyu artırmaz; artıran şey, yanıtsız kalan sorunun ihtiyaç duyduğu işlemenin gelmesidir. kimlik dalının dört işlemesi hiçbir sorunun eksik yanıtını tamamlamıyor, çünkü kusur o dalda değil.

Altıncı soru üç kopyada da yanıtsız. Çakışmanın nerede ve nasıl çözüldüğü hiçbir kopyada yazılı değildir; kopya sayısını artırmak bunu değiştirmez.

Tanımın Ödediği

Orta iki satır dersin adını taşıyan işlemi ölçüyor. Tanımlamadan önce yerel kopya 5 işleme ve 4 soru; iki uzak depo tanımlandıktan sonra yine 5 işleme ve 4 soru.

Bu bir yuvarlama değil, tanımın kendisidir. tanimla işlevi yalnız uzaklar sözlüğüne dokunuyor; tarihce listesine hiç bakmıyor. Aracın davranışı da budur: uzak depo eklemek yapılandırmaya iki satır yazar, ağa çıkmaz, tek bir nesne getirmez, tek bir başvuru oluşturmaz. Adres yanlış yazılmışsa bunu tanımlama anında öğrenmezsin — ilk getirme denemesinde öğrenirsin.

Buradan pratik bir alışkanlık çıkar: bir uzak depo tanımının doğruluğu ancak karşı tarafla konuşan bir işlemle sınanır. git remote -v yalnız ne yazdığını gösterir, git remote show ise karşı tarafa gerçekten bağlanır ve adın altındaki dalları listeler. İkisi ayrı sorulardır.

Ad Alanının Ödettiği

Alt tablo altı başvuru sayıyor ve bunların yalnız üç ayrı kısa adı var. olcum kısa adını üç başvuru paylaşıyor, rapor kısa adını iki başvuru.

Ad alanı olmasaydı bu altı başvuru üç yuvaya sığmak zorunda kalırdı ve kopyalar birbirinin kaydını ezerdi. Uzak depo adı tam olarak bu yüzden vardır: koken/olcum ile yukari/olcum ayrı başvurulardır, ayrı işlemeleri gösterebilirler ve ikisi de yerel olcum dalından bağımsızdır.

Bedeli belirsizliktir. Bir komuta yalın olcum verildiğinde araç önce yerel dallara bakar; başvuru orada bulunduğu için karşı tarafın olcumu hiç aranmaz. İki kopyanın olcum dalı ayrışmışsa ve sen yalın adı yazdıysan, gördüğün şey senin dalındır — karşı tarafınki değil. Bu, ayrışmayı fark etmeyi geciktiren en sık nedendir. Nitelikli ad yazmak (koken/olcum) bu belirsizliği ortadan kaldırır ve iki başvurunun ayrı ayrı sorulmasını sağlar.

Ad alanının bir kez daha kanıtlandığı yer yeniden adlandırmadır. git remote rename yalnız yapılandırmadaki satırı değiştirmez; o adın altındaki bütün uzak izleme başvurularını da yeni önekle yeniden yazar. Beş başvuru taşıyan bir tanımda beş başvurunun adı değişir ve işlemelerin hiçbiri kopyalanmaz — çünkü başvuru bir addır, taşıdığı işleme değil.

Birden Çok Uzak Depo Ne Zaman Gerekir

Ölçüm iki uzak depoyla çalıştı ve bu sayı keyfî değil. Birden çok tanım, kopyaların ayrı roller taşıdığı her durumda ortaya çıkar.

Birinci rol ayrımı yetkidir. Yazma yetkisinin bulunduğu kopya ile yalnız okunan kopya farklıysa iki tanım gerekir: değişiklikler birine itilir, güncellemeler ötekinden getirilir. Ölçümdeki koken ve yukari tam olarak bu ayrımı taşıyor ve sonraki iki dersin konusu bu ayrımın açtığı katkı modelidir.

İkinci rol ayrımı eşliktir. Dağıtık modelde bir kopyanın uzak deposu bir sunucu olmak zorunda değildir; takımdaki başka birinin kopyası da tanımlanabilir. Yarım kalmış bir dalı ortak bir kopyaya itmeden incelemek gerektiğinde bu doğrudan yol açılır ve ortadaki kopyaya hiç uğranmaz.

Üçüncü rol ayrımı yedektir. Bir aynanın ayrı adla tanımlanması, aynı dalların iki ayrı başvuru kümesinde tutulmasını sağlar; iki kümenin ayrışması ancak ikisi de tanımlıyken görülebilir.

Üç durumda da tanım sayısının artması yerel tarihçeyi büyütmez. Büyüyen tek şey başvuru ad alanıdır ve alt tablonun gösterdiği paylaşılan kısa ad sorunu her yeni tanımla bir kez daha tekrarlanır. Bu yüzden ad seçimi, tanım sayısı arttıkça daha çok önem kazanır: adlar rolü söylediğinde bir komutun hangi kopyaya gittiği komutun kendisinden okunur.

Özet

  • Uzak depo, karşı taraftaki kopya değil, o kopyaya bu depoda verilen addır; tanım yapılandırmada durur, tarihçede durmaz ve kopyayı alan başkasına geçmez.
  • Uzak izleme başvuruları refs/remotes/<ad> altında durur, yerelden yazılmaz ve karşı tarafın dalının en son görülmüş hâlini kaydeder.
  • Üç kopya 5, 10 ve 15 işleme taşır ve 4, 5, 5 soru yanıtlar; yerel kopyanın eksik yanıtı biçim kaybından değil kapsam kaybından gelir, çünkü kusurlu işleme o kopyada hiç yoktur.
  • Taşınan işlemenin artması yanıtlanan soruyu tek başına artırmaz: koken ile yukari arasında beş işleme fark vardır ve ikisi de aynı beş soruyu yanıtlar.
  • İki uzak depo tanımı yerel kopyayı 5 işleme ve 4 soruda bırakır; tanımlama sıfır işleme getirir ve adresin doğruluğunu sınamaz.
  • Altı başvuru üç ayrı kısa ad taşır; ad alanı bu çakışmayı çözer, karşılığında yalın ad her zaman yerel dala düşer.

Sonraki Adım

Tanım bir addır ve ad tek başına hiçbir işleme getirmiyor. Yerel kopya hâlâ beş işleme taşıyor, karşı taraf on beş taşıyor ve aradaki fark kapanmış değil. Sonraki ders bu farkı kapatan üç işlemi ayırır: hangisi yerel tarihçeye hiç dokunmaz, hangisi ona bir birleştirme işlemesi ekler, hangisi karşı tarafın tarihçesini değiştirir. Üçü aynı ağ bağlantısını kullanır ve üçünün tarihçeye ödettiği bedel aynı değildir.

İlerlemeni kaydetmek ve not almak için Giriş yap

Notlarım

Not almak için giriş yapmalısın.

Aramak için yazmaya başlayın.

↑↓ Esc gezin · aç · kapat