İçeriğe geç
academia.sh

Ders 12 / 15

Getirme, Çekme ve İtme

Üç senkronizasyon işleminin yerel tarihçeye dokunduğu yer ayrıdır: getirme yerel dalı 5 işlemede bırakır ve yereldeki nesneyi 15'e çıkarır, çekme dalı 16 işlemeye ve 5 soruya taşır, itme karşı tarafın dalını 10'dan 16'ya değiştirir.

İçindekiler

Önceki ders uzak depo tanımının bir addan ibaret olduğunu ölçtü: iki tanım yerel kopyayı beş işleme ve dört soruda bıraktı, çünkü tanımlama ağa çıkmaz ve tek bir nesne getirmez. Aradaki fark kapanmadan durmaya devam ediyor — yerel kopya beş işleme taşıyor, karşı taraf on.

Bu farkı kapatan üç işlem var ve üçü sık sık aynı şeyin adları sanılır. Değildirler. Bu dersin ölçüsü tek bir eksende yürür: her işlem yerel tarihçeyi ne kadar değiştirir? Yanıt üç ayrı sayıdır ve üçüncüsünde değişen tarihçe yerel bile değildir.

Üç İşlem, Üç Ayrı Etki

Üçünü bir cümleyle ayırmak mümkündür.

Getirme (fetch) karşı tarafın başvurularını ve eksik nesneleri yerele alır. Yerel dalların hiçbirine dokunmaz, çalışma alanını değiştirmez, birleştirme yapmaz. Tek yazdığı şey uzak izleme başvurularıdır.

Çekme (pull) bileşik bir işlemdir: önce getirir, sonra getirdiğini yerel dalla birleştirir. Birinci adımı getirmenin aynısıdır; farkı ikinci adımdır ve o adım yerel tarihçeye işleme ekler.

İtme (push) yönü tersine çevirir. Yerel dalın işlemelerini karşı tarafa yollar ve karşı tarafın başvurusunu yerelinkine eşitler. Yerel tarihçeye dokunmaz; karşı tarafın tarihçesini değiştirir. Üç işlem içinde etkisi kendi deposunun dışına çıkan tek işlem budur.

Getirme

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

git fetch koken

From ornek.test/koken
 * [new branch]      rapor      -> koken/rapor
 * [new branch]      kimlik     -> koken/kimlik
   a1b2c3d..d4e5f6a  olcum      -> koken/olcum

Çıktının her satırı bir başvuru güncellemesidir, bir dal değişikliği değil. Sağdaki adlar koken/ önekiyle yazılıdır: güncellenen şey uzak izleme başvurularıdır. Yerel olcum dalı bu komuttan sonra tam olarak eskisi kadar işleme taşır.

Getirme, tek başına hiçbir şeyi bozamayan işlemdir. Karşı tarafta ne olduğunu görmek için çalışma alanını riske atmaya gerek yoktur: git fetch ardından git log koken/olcum ile gelen işlemeler okunur, git diff olcum koken/olcum ile fark alınır ve ancak sonrası kararlaştırılır.

Getirme Kuralı ve Budama

Getirmenin neyi alıp nereye yazacağı bir eşleme kuralından okunur. Kuralın varsayılan biçimi +refs/heads/*:refs/remotes/koken/* gibi bir çifttir: sol taraf karşı taraftaki başvuruları, sağ taraf onların yerelde yazılacağı adları verir. Baştaki artı işareti, ileri sarılabilir olmayan güncellemelerin de yazılmasına izin verir — uzak izleme başvurusu için bu güvenlidir, çünkü orada senin hiçbir işlemen durmuyor.

Kural daraltılabilir. Tek bir dalın getirilmesi büyük depolarda ölçülebilir zaman kazandırır; tanımlı uzak depoların hepsinin birden getirilmesi ise git fetch --all ile yapılır ve her ad kendi başvuru kümesine yazar.

Kuralın en sık gözden kaçan sonucu silinme yönündedir. Karşı tarafta bir dal silindiğinde ona karşılık gelen uzak izleme başvurusu kendiliğinden düşmez; eşleme yalnız var olan başvuruları yazar, olmayanları silmez. git fetch --prune bu temizliği yapar. Budama yapılmayan bir depoda git branch -a çıktısı, karşı tarafta artık bulunmayan dalları göstermeye devam eder ve bu, uzak izleme başvurusunun bir dal değil son görülmüş hâlin kaydı olduğunun en somut kanıtıdır.

Çekme

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

git pull koken ana
git fetch koken && git merge koken/ana

İki satır aynı işi yapar; ikincisi birincinin açılmış hâlidir. Bu açılım, çekmenin neden “zararsız bir güncelleme” olmadığını gösterir: ikinci adım bir birleştirmedir ve Birleştirme konusunda ölçülen bütün sonuçlar burada geçerlidir. Birleştirme çakışması çekme sırasında da doğar, birleştirme işlemesi çekme sırasında da yazılır.

Çekmenin ikinci adımı yapılandırmayla değiştirilebilir ve birleştirme yerine yeniden temellendirme yapılabilir. Bu, ikinci adımın hangi tümleştirme biçimini uygulayacağını seçmek demektir; biçimlerin tarihçeye ne bıraktığı Birleştirme konusunda ölçüldü ve burada tekrarlanmaz. Bu dersin ölçümü çekmenin birleştirmeli biçimini kurar.

İtme

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

git push koken ana

To ornek.test/koken
   d4e5f6a..b7c8d9e  ana -> ana

Komuta uzak depo adı ve dal adı her seferinde yazılmak zorunda değildir. -u seçeneğiyle yapılan bir itme, yerel dal ile karşı taraftaki dal arasında bir izlenen dal ilişkisi kurar; sonraki getirme, çekme ve itme çağrıları bu ilişkiyi okur ve adlar yazılmadan çalışır. İlişki yapılandırmada durur ve git status çıktısındaki “şu kadar işleme ileride, şu kadar geride” satırı da buradan hesaplanır — o satır yerel dalı uzak izleme başvurusuyla karşılaştırır, karşı tarafla değil.

İtme yalnız ileri sarılabilir olduğunda kabul edilir: karşı tarafın dalındaki her işleme yerel dalda da bulunmalıdır. Koşul sağlanmıyorsa işlem reddedilir ve bu ret bir kusur değil, kaydın korunmasıdır. Ret, karşı tarafta senin görmediğin işlemeler bulunduğunu söyler.

İtmenin bu koşulu aşan bir biçimi vardır ve bu ders onu tam biçimiyle yazmaz. Zorlayıcı itme, karşı tarafın dalını yerel dalla değiştirir ve karşı tarafta olup yerelde olmayan işlemeleri başvurulardan düşürür. Düşen işlemeler başka bir kopyada bulunmuyorsa geri alınamaz; senin deponun referans günlüğü karşı tarafın kaybını kurtarmaz, çünkü o günlük yereldir. Güvenli yol üç adımdır: getir, gelen işlemeleri oku, uzlaştır ve sıradan itme yap. Zorlamanın kiralı biçimi — karşı taraf son getirmeden bu yana kımıldadıysa işlemi reddeden biçimi — riski azaltır ama ortadan kaldırmaz; disiplini İleri Git kursunun “Zorlayıcı İtme Disiplini” dersi kurar.

Ölçümün Varsayımları

  • UD7 — Yerel kopya olcum dalını almış bir depodur ve ana dalı 5 işleme taşır; karşı tarafın dalı rapor ile kimliki almıştır ve 10 işleme taşır. İki taraf da birleştirme işlemesi biçimini kullanır.
  • UD8 — Getirme yerel dal listesine dokunmaz; yaptığı tek şey uzak izleme başvurusunu karşı tarafın dalına eşitlemek ve eksik işlemeleri yerele almaktır.
  • UD9 — Çekme, getirmenin ardından yerel dala bir birleştirme işlemesi ekler. Ölçüm çekmenin yeniden temellendirmeli biçimini kurmaz.
  • UD10 — İtme yerel dala dokunmaz; karşı tarafın dalını yerel dalın kopyasıyla değiştirir. Ölçüm yalnız ileri sarılabilir itmeyi uygular.
  • UD11 — “Yereldeki nesne” sayımı, yerel dalda olsun ya da olmasın yerelde bulunan işlemeleri sayar; uzak izleme başvurusunun gösterdiği işlemeler de buraya girer.
  • UD12 — Ayrışma, ortak tabanın dışında her iki tarafta da işleme bulunması demektir; ölçüm ayrışmayı iki kopyanın taşıdığı dal kümesini ayırarak kurar.

Ölçüm

"""Getirme, çekme ve itme: üç işlemin değiştirdiği tarihçe.

Bölüm 1 - her işlemden sonra yerel dal, yereldeki nesne ve karşı tarafın dalı.
Bölüm 2 - ayrışmış iki kopyada itmenin ileri sarılabilirliği.
"""
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 dalı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))


def yanit(t):
    return sum(f(t) for _, f in SORULAR)


def getir(y, u):
    """Getirme: uzak izleme başvurusu ve işlemeler gelir, yerel dal kımıldamaz."""
    return {"dal": list(y["dal"]),
            "nesne": y["nesne"] + [x for x in u["dal"] if x not in y["nesne"]],
            "izleme": list(u["dal"])}


def cek(y, u):
    """Çekme: getirme, ardından yerel dala bir birleştirme işlemesi."""
    y = getir(y, u)
    gelen = [x for x in y["izleme"] if x not in y["dal"]]
    if not gelen:
        return y
    birlesme = {"dal": "ana", "sira": 0, "dosya": None, "kusurlu": False,
                "zaman": max(x["zaman"] for x in y["izleme"]),
                "dal_kaydi": "ana", "birlesme": True, "zaman_korundu": True}
    y["dal"] = y["dal"] + gelen + [birlesme]
    y["nesne"] = y["nesne"] + [birlesme]
    return y


def it(y, u):
    """İtme: yerel dal kımıldamaz, karşı tarafın dalı yerelinkiyle değiştirilir."""
    return y, {"dal": list(y["dal"])}


kayit = gelisim()
yerel = {"dal": tarihce(kayit, ("olcum",)), "nesne": tarihce(kayit, ("olcum",)),
         "izleme": []}
uzak = {"dal": tarihce(kayit, ("rapor", "kimlik"))}

print(f"gerçek gelişim {len(kayit)} işleme; yerel dal {len(yerel['dal'])}, "
      f"karşı tarafın dalı {len(uzak['dal'])}")
print()
print("adım      yerel dal  yerel soru  yereldeki nesne  uzak dal  uzak soru")


def yaz(ad, y, u):
    print(f"  {ad:9s} {len(y['dal']):8d} {yanit(y['dal']):11d} {len(y['nesne']):16d}"
          f" {len(u['dal']):9d} {yanit(u['dal']):10d}")


yaz("başlangıç", yerel, uzak)
yaz("getirme", getir(yerel, uzak), uzak)
cekilmis = cek(yerel, uzak)
yaz("çekme", cekilmis, uzak)
itilmis, uzak_son = it(cekilmis, uzak)
yaz("itme", itilmis, uzak_son)

print()
print("kopya çifti    yerel  uzak  ortak taban  yalnız yerelde  yalnız uzakta  "
      "ileri sarma")
CIFTLER = {"ayrışmamış": (cekilmis["dal"], uzak["dal"]),
           "ayrışmış": (tarihce(kayit, ("olcum", "rapor")),
                        tarihce(kayit, ("olcum", "kimlik")))}
for ad, (yd, ud) in CIFTLER.items():
    ortak = [x for x in yd if x in ud]
    print(f"  {ad:12s} {len(yd):6d} {len(ud):5d} {len(ortak):12d}"
          f" {len(yd) - len(ortak):15d} {len(ud) - len(ortak):14d}"
          f"  {'evet' if all(x in yd for x in ud) else 'hayır':>10s}")

print()
for ad, (yd, ud) in CIFTLER.items():
    dusecek = [x for x in ud if x not in yd]
    print(f"  {ad} çiftte zorlayıcı itme karşı taraftan {len(dusecek)} işleme düşürür")
gerçek gelişim 12 işleme; yerel dal 5, karşı tarafın dalı 10

adım      yerel dal  yerel soru  yereldeki nesne  uzak dal  uzak soru
  başlangıç        5           4                5        10          5
  getirme          5           4               15        10          5
  çekme           16           5               16        10          5
  itme            16           5               16        16          5

kopya çifti    yerel  uzak  ortak taban  yalnız yerelde  yalnız uzakta  ileri sarma
  ayrışmamış       16    10           10               6              0        evet
  ayrışmış         10    10            5               5              5       hayır

  ayrışmamış çiftte zorlayıcı itme karşı taraftan 0 işleme düşürür
  ayrışmış çiftte zorlayıcı itme karşı taraftan 5 işleme düşürür

Üç İşlemin Ödettiği

Üst tablo dört satırda üç işlemi ayırıyor ve satırlar arasındaki fark her seferinde tek bir sütunda beliriyor.

Getirme satırı yerel dalı 5’te bırakıyor ve yanıtlanan soru 4’te kalıyor. Değişen tek sütun “yereldeki nesne”: 5’ten 15’e çıkıyor. Bu on beş işleme yerelde duruyor, diskte bulunuyor, okunabiliyor — ama hiçbiri yerel dalın tarihçesinde değil. Getirmenin tanımı budur: erişilebilirliği artırır, tarihçeyi değiştirmez. Yanıtsız kalan “kusurun yalıtımı” sorusu getirmeden sonra da yanıtsız, çünkü soru yerel dala soruluyor ve yerel dal kımıldamadı. Kusurlu işleme artık yerelde bulunuyor; yalnız koken/rapor başvurusundan sorulduğunda görünüyor.

Çekme satırı yerel dalı 5’ten 16’ya taşıyor ve yanıtlanan soruyu 4’ten 5’e çıkarıyor. On altı sayısı bileşiktir: yerel dalın kendi 5 işlemesi, karşı taraftan gelen 10 işleme ve çekmenin kendi yazdığı 1 birleştirme işlemesi. On ikilik gerçek gelişimin üstünde dört birleştirme işlemesi birikmiş oluyor — üçü dalları ana dala alan birleşmeler, dördüncüsü iki kopyayı uzlaştıran birleşme.

Kazanılan soru “kusurun yalıtımı”. Bir önceki ders bu eksikliğin kapsam kaybından geldiğini ölçmüştü; çekme kapsamı kapatıyor ve soru yanıtlanır hâle geliyor. Bu, kapsam kaybının geri alınabilir olduğunun doğrudan kanıtıdır.

İtme satırında yerel sütunların üçü de kımıldamıyor: 16, 5, 16. Değişen sütun karşı tarafın dalı — 10’dan 16’ya çıkıyor. İtmenin ölçüsü kendi deposunda değil, ötekinde okunur ve bu üç işlem içinde yalnız itme için doğrudur.

Karşı tarafın yanıtladığı soru 5’ten 5’e gidiyor; sayı değişmiyor ama taşınan işleme altı artıyor. Bu, önceki dersin bulgusunun tersten okunuşudur: işleme sayısının artması yanıtlanan soruyu tek başına artırmaz. Karşı taraf zaten kusurlu işlemeyi taşıyordu.

Ayrışma ve İtmenin Sınırı

Alt tablo iki kopya çiftini yan yana koyuyor. Ayrışmamış çiftte karşı tarafın on işlemesinin tamamı yerelde de var: ortak taban 10, yalnız uzakta kalan 0. İtme ileri sarmadır ve hiçbir şey düşmez.

Ayrışmış çiftte ortak taban 5’e iniyor. Yerelde beş işleme var karşı tarafta olmayan, karşı tarafta beş işleme var yerelde olmayan. İleri sarma koşulu sağlanmıyor ve sıradan itme reddediliyor. Son satır reddin neyi koruduğunu söylüyor: zorlayıcı itme uygulansaydı karşı taraftan 5 işleme düşecekti — gerçek gelişimin yaklaşık 5/12’si, ve o beşi yazan kişi bunu yalnız kendi kopyası kımıldadığında fark ederdi.

İki sayı arasındaki fark, itmenin ret davranışının neden bir güvenlik özelliği olduğunu gösteriyor. Ret bir hata iletisi değil, ayrışmanın bildirimidir. Doğru yanıt itmeyi zorlamak değil, ayrışmayı kapatmaktır: getirme ayrışmayı görünür kılar, çekme ya da yeniden temellendirme onu tümleştirir, sonraki itme ileri sarma olur ve düşen işleme sıfıra iner.

Özet

  • Getirme yerel dalı 5 işlemede bırakır ve yereldeki işlemeyi 15’e çıkarır; yanıtlanan soru 4’te kalır çünkü soru yerel dala sorulur ve yerel dal kımıldamaz.
  • Çekme getirmenin üstüne bir birleştirme işlemesi ekler: yerel dal 16’ya, yanıtlanan soru 5’e çıkar; on altının biri çekmenin kendi yazdığı işlemedir.
  • Kapsam kaybı geri alınabilir bir kayıptır: eksik dal geldiğinde “kusurun yalıtımı” sorusu yeniden yanıtlanır hâle gelir.
  • İtme yerel tarihçeye dokunmaz ve karşı tarafın dalını 10’dan 16’ya taşır; ölçüsü kendi deposunda değil, ötekinde okunur.
  • İtme yalnız ileri sarılabilir olduğunda kabul edilir; ayrışmış çiftte ortak taban 5’e iner ve zorlayıcı itme karşı taraftan 5 işleme düşürür, geri alınamaz biçimde.

Sonraki Adım

Bu dersin üç işlemi tek bir varsayımla çalıştı: itme yetkisi vardı. Yerel kopya karşı tarafın dalını değiştirebiliyordu ve tek engel ileri sarılabilirlik koşuluydu. Katkı akışlarının büyük bölümünde bu varsayım geçersizdir — katkıyı alan depoya yazma yetkisi yoktur. Sonraki ders bu durumda açılan iki modeli karşılaştırır: kopyayı doğrudan klonlayıp dal itmek ile ayrı bir kopya açıp oradan öneri götürmek. Ölçü, iki modelde yukarı deponun hangi soruları yanıtlayabildiğidir.

İ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