· kaynak dev.to (home feed)
Git 2.43, üç gün önceki kodu uyarı vermeden çekilen düzeltmelerin üzerine geri yazdı
Bir dev.to raporu, git 2.43.0 üzerinde pull.rebase ve rebase.autoStash birleşiminin bayat bir çalışma ağacı düzenini yeni çekilen kodun üzerine sessizce yazdığını, 0 ile çıkıp kanıtı da yok ettiğini gösteriyor.

Yeni kodun üzerine eski kod yazan bir pull
dev.to'daki bir yazı, birçok geliştiricinin bir kez ayarlayıp unuttuğu iki yapılandırma satırının tetiklediği bir git 2.43.0 hata modunu belgeliyor: pull.rebase true ve rebase.autoStash true. İkisi de etkinken yazar, üç gün önce yapılmış ilgisiz bir kirli düzeni taşırken düz bir git pull komutu çalıştırdı. Pull, upstream'deki bir düzeltmeyi çekti, fast-forward yaptı, bir autostash oluşturup uyguladı ve 0 durum koduyla çıktı. Çıktıda uyarı olarak okunabilecek hiçbir şey yoktu.
Ortaya çıkan dosya iki dönemi karıştırıyordu. Bir satır henüz gelmiş olan upstream düzeltmesini taşıyordu; bir diğeri ise güncellemenin üzerine yeniden uygulanmış, üç gün önceki yerel düzeni. HEAD'deki dosyaya bakmak, bayat satırın yalnızca çalışma ağacında olduğunu, hiçbir commit'te bulunmadığını doğruladı. Değişiklik zamanı içinde bulunulan saniyeye damgalanmıştı; yani dosyanın yaşı ile kökeni zıt yönleri işaret ediyordu.
Mekanizma sıradan bir birleştirme
Yazıya göre bu davranış doğrudan autostash'in çalışma biçiminden kaynaklanıyor. Git kirli ağacı stash'ler, HEAD'i upstream commit'ine taşır, ardından stash'i yeni çekilen dosyaların üzerine yeniden uygular. Stash bir diff'tir ve bir diff'in ne zaman yapıldığına dair hafızası yoktur. Bayat parçacıklar ile upstream parçacıkları dosyanın farklı bölgelerinde bulunduğunda three-way merge başarılı olur, git "Applied autostash." yazdırır ve sonuç, hangi kısımların güncel hangilerinin eski olduğunu söyleyen hiçbir işaret taşımayan bir melez dosyadır. Yazıda, etkiyi yaklaşık bir saniyede gösteren kendi başına çalışan bir shell tekrarlayıcısı da yer alıyor.
Çakışan varyant da sıfırla çıkıyor
Tekrarlayıcıyı, bayat düzen ile upstream düzeltmesi aynı satıra değecek şekilde değiştirmek autostash uygulamasını çakıştırıyor. Git çakışmayı stdout'ta duyuruyor ve değişikliklerin stash içinde güvende kaldığını söylüyor — sonra yazıya göre yine de 0 çıkış kodu döndürüyor, çalışma ağacında çakışma işaretleri ve birleştirilmemiş bir yol bırakıyor. Yazarın vurguladığı nokta şu: git pull && make çalıştıran herhangi bir deploy betiği ya da $? kontrol eden herhangi bir CI adımı doğrudan geçecek, çünkü betiklerin gerçekten okuduğu tek kanal başarı bildiren kanaldır.
Sessiz durumda stash kayboluyor
Çakışma durumunda stash hayatta kalıyor. Temiz, sessiz durumda — yazarın tehlikeli bulduğu durumda — git onu düşürüyor. Yazı, boş bir stash listesi, stash reflog'u olmadığını ve yalnızca git fsck --no-reflogs ile keşfedilebilen, çöp toplayıcının sonunda sileceği bir dangling commit gösteriyor. Bir hafta sonra eski bir satırın nasıl geri geldiğini araştıran biri neredeyse hiçbir şey bulamaz.
Yazarın kendi denetimleri neden yeşil kaldı
Yazar, yazılım ajanlarının ürettiği işleri commit'leyen küçük bir otomasyon aracı çalıştırıyor; her commit mesajında yazılı üç ölçüte bağlı olarak: bir dosya, değişiklik zamanı on dakikadan uzun süre kararlı kaldığında yerleşmiş sayılıyor, ayrıca hatasız ayrıştırılabilir olmalı ve incelenmiş olmalı. Geri oynatılmış bayat bir ağaç bu üçünü de yapısı gereği karşılar. Pull güncel bir değişiklik zamanı damgaladığı için üç gün önceki bir satır on dakika sonra yerleşmiş gibi okunur. Eski kod yazıldığında düzgün biçimliydi; bu yüzden ayrıştırma denetimleri, hatta test takımları bile geçer, çünkü geri alınan sürüm yayınlandığında yeşildi. Commit mesajı şablonu ise gerçek düzeltmelerle geri almalar için aynıdır.
Yazıya göre sonuç şu: bir retry döngüsünün geri alınması, yerleşmiş bir düzeltme ifadesi altına girdi, sonra upstream ile kalıcı olarak çakıştı ve onu indiren hattı tıkadı. Yazar üç günlük bir pencerede en az 38 ilgili gönderi saydı ve bu sayının bir alt sınır olduğunu, çünkü pencerenin kaydığını belirtti.
Geri almaları içerik kimliğiyle tespit etmek
Yazının savunusuna göre denetimlerin hiçbirinin sormadığı soru şuydu: byte'lar nereden geldi? Önerilen denetim ucuz: aday dosyayı git hash-object ile hash'leyin ve HEAD'in tüm atalarında o yolda saklanan blob ile karşılaştırın. Byte düzeyinde özdeş bir eşleşme, ağacın ileri değil geri gittiği anlamına gelir. Eski bir sürüm tutan bir çalışma ağacına karşı çalıştırıldığında betik, dosyayı adı geçen tarihsel bir commit ile özdeş olarak işaretler.
Neden önemli
pull.rebase ve rebase.autoStash, çalışma ağacı kirliyken pull'ları derli toplu tutmak için yaygın şekilde önerilir. Bu anlatım, bu birleşimin geri alınmış kodu sessizce yeniden girebileceğini gösteriyor — başarı çıkış kodu, yepyeni bir zaman damgası, kendini silen kanıt ve gerçek işten ayırt edilemeyen commit mesajlarıyla. Betikle yapılan bir pull'dan sonra çıkış kodlarına, dosya yaşlarına veya biçim denetimlerine güvenen hatlar açık veriyor. Dosya içeriğini tarihsel blob'larla karşılaştıran köken denetimleri — ya da otomatik pull'larda autostash'ten kaçınmak — alışılmış denetimlerin göremediği bir boşluğu kapatıyor.
- #git
- #version-control
- #developer-tools
- #data-loss
- #ci