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
olcumdalını almış bir depodur ve ana dalı 5 işleme taşır; karşı tarafın dalıraporilekimliki 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.