Hizmetler Hosting & Sunucu Araçlar Blog Ara Kurumsal EnglishEN
Teklif Alın

İki Metni Karşılaştırma İhtiyacı Nereden Doğar?

Bir metnin iki farklı sürümünü elle karşılaştırmak, satır satır okuyup neyin değiştiğini bulmaya çalışmak zaman alır ve hataya açıktır. Bir kod dosyasının önceki commit'e göre nesi değişti, bir sözleşmenin yeni taslağında hangi cümleler eklendi, bir yapılandırma dosyasında hangi satır silindi — bu sorulara hızlı ve güvenilir cevap vermek için diff (fark) algoritmaları kullanılır. "Diff" kelimesi İngilizce "difference" kelimesinden gelir ve iki metin arasındaki farkı otomatik olarak tespit eden karşılaştırma işlemini tanımlar.

Diff işleminin çıktısı basittir: iki metin arasında hangi satırların aynı kaldığı, hangilerinin kaldırıldığı ve hangilerinin yeni eklendiği. Ancak bu basit çıktıyı üretmek için altta çalışan mantık, klasik bir bilgisayar bilimi problemidir: en az sayıda değişiklikle bir metni diğerine dönüştürmenin yolunu bulmak.

LCS: En Uzun Ortak Alt Dizi Yaklaşımı

Çoğu diff aracı — Unix'teki klasik diff komutundan git diff'e, kod inceleme araçlarından metin karşılaştırıcılara kadar — kavramsal olarak En Uzun Ortak Alt Dizi (Longest Common Subsequence, kısaca LCS) fikrine dayanır. LCS, iki dizi (bu durumda satır listeleri) arasında, sırası korunmak şartıyla ortak olan en uzun alt diziyi bulmayı amaçlar. Alt dizideki satırların birbirine bitişik olması gerekmez; önemli olan aralarındaki sıranın bozulmamasıdır.

Algoritma pratikte iki metnin satırlarını bir tabloya (dinamik programlama matrisine) yerleştirir ve her satır çiftini karşılaştırarak hangi satırların iki metinde de ortak sırayla bulunduğunu hesaplar. Bu ortak sıra bulunduktan sonra geriye kalan iş basittir: ortak alt diziye dahil olmayan satırlar ya eski metinden kaldırılmış ya da yeni metne eklenmiş demektir.

Eklenen, silinen ve değişmeyen satırlar nasıl belirlenir?

LCS bulunduktan sonra diff aracı iki metni baştan sona tarar: bir satır her iki metinde de ortak alt dizinin bir parçasıysa değişmedi olarak işaretlenir. Ortak alt diziye dahil olmayıp yalnızca orijinal metinde bulunan bir satır silindi (genellikle kırmızı gösterilir), yalnızca yeni metinde bulunan bir satır ise eklendi (genellikle yeşil gösterilir) olarak işaretlenir. Bir satırın içeriği kısmen değişmişse — örneğin tek bir kelime güncellenmişse — diff satır bazlı çalıştığı için bu durum genelde o satırın tamamen silinip güncellenmiş haliyle yeniden eklenmesi şeklinde gösterilir; çünkü algoritma satırın içindeki kelimeleri değil, satırın tamamını tek bir birim olarak karşılaştırır.

Basit Bir Örnek Üzerinden Diff

Aşağıdaki iki kısa metni ele alalım; soldaki orijinal, sağdaki değiştirilmiş sürümdür.

OrijinalDeğiştirilmiş
Merhaba dünyaMerhaba dünya
Bu bir örnek satırBu güncellenmiş bir satır
Değişmeyen satırDeğişmeyen satır
Son satırYeni satır eklendi

Bu iki metni satır satır karşılaştırdığımızda ortaya çıkan fark şöyledir: Merhaba dünya ve Değişmeyen satır her iki metinde de aynı sırada bulunduğu için LCS'nin bir parçasıdır ve değişmedi olarak işaretlenir. Bu bir örnek satır yalnızca orijinal metinde olduğu için silindi, yerine gelen Bu güncellenmiş bir satır yalnızca yeni metinde olduğu için eklendi sayılır. Aynı şekilde Son satır kaldırılmış, Yeni satır eklendi ise metne yeni katılmıştır. Sonuçta diff çıktısı 2 değişmeyen, 2 silinen ve 2 eklenen satırdan oluşur — tıpkı bir kod incelemesinde kırmızı/yeşil satırlar olarak gördüğünüz görünüm gibi.

Diff Çıktısının Gösterim Biçimleri

Diff sonucu genellikle iki farklı biçimde sunulur. Side-by-side (yan yana) görünüm, yukarıdaki tabloda olduğu gibi iki metni yan yana iki sütunda gösterir ve karşılaştırmayı görsel olarak kolaylaştırır. Unified diff ise tek bir sütunda, değişmeyen satırların başında boşluk, silinen satırların başında -, eklenen satırların başında + işareti kullanarak gösterir; git diff komutunun varsayılan çıktısı ve .patch dosyaları bu formatı kullanır.

Unified diff formatında her değişiklik bloğu, dosyadaki konumunu belirten @@ -a,b +c,d @@ şeklinde bir başlıkla işaretlenir; buradaki sayılar değişikliğin orijinal ve yeni dosyadaki satır numaralarını ve kapsadığı satır sayısını gösterir. Bu format, değişiklikleri e-posta ile paylaşmak veya otomatik olarak dosyaya uygulamak (patch etmek) için pratik bir yöntemdir ve birçok sürüm kontrol sisteminin altyapısında yer alır.

Diff Nerelerde Kullanılır?

  • Kod incelemesi (code review): Bir pull request'te hangi satırların değiştiğini görmek, incelemeyi tüm dosyayı yeniden okumak yerine sadece değişikliklere odaklanarak yapmayı sağlar.
  • Git ve sürüm kontrolü: git diff, git log -p gibi komutlar commit'ler arasındaki farkı LCS mantığıyla hesaplayıp gösterir; bu sayede bir dosyanın geçmişteki her değişikliği izlenebilir.
  • Belge ve içerik takibi: Bir sözleşmenin, makalenin veya web sayfası metninin iki taslağı arasındaki farkları bulmak için kullanılır.
  • Yapılandırma (config) dosyası denetimi: Sunucu veya uygulama ayarlarının önceki haliyle yeni hali arasında hangi satırların değiştiğini tespit etmek, hata ayıklamayı kolaylaştırır.

Yaygın Hatalar ve Yanlış Anlaşılmalar

Karakter, kelime ve satır bazlı diff farkı

Diff algoritmaları farklı seviyelerde çalışabilir: satır bazlı (en yaygın, git ve çoğu diff aracının varsayılanı), kelime bazlı ve karakter bazlı. Satır bazlı bir diff, bir satırdaki tek bir karakter bile değişse o satırın tamamını "değişti" olarak gösterir; bu da uzun bir satırda küçük bir değişiklik olduğunda çıktının okunmasını zorlaştırabilir. Kelime veya karakter bazlı diff araçları ise satır içinde tam olarak hangi kelimenin veya harfin değiştiğini vurgular, ancak hesaplama maliyeti daha yüksektir.

Boşluk (whitespace) duyarlılığı

Diff araçları varsayılan olarak boşluk duyarlıdır: bir satırın sonundaki fazladan bir boşluk, bir sekme (tab) karakterinin boşlukla değiştirilmesi veya satır sonu karakterinin (Windows'ta CRLF, Unix'te LF) farklı olması, içerik aslında aynı olsa bile o satırı "değişti" olarak gösterebilir. Bu durum, özellikle farklı işletim sistemlerinde düzenlenen veya farklı editör ayarlarıyla kaydedilen dosyalarda sahte (yanlış pozitif) değişiklikler üretebilir.

Uyarı
Büyük bir dosyada beklenmedik sayıda satırın "değişti" göründüğünü fark ederseniz önce satır sonu karakterlerini ve baştaki/sondaki boşlukları kontrol edin — çoğu zaman bu, gerçek bir içerik değişikliği değil biçimlendirme farkıdır.

Satır kayması yanıltıcı diff üretebilir

LCS satır bazlı eşleşme aradığı için, bir kod bloğu dosya içinde sadece yeri değiştirildiğinde (taşındığında) çoğu diff aracı bunu "taşındı" olarak değil, eski konumdan silinip yeni konuma eklenmiş gibi gösterir. Aynı şekilde dosyanın başına yeni bir satır eklendiğinde, algoritma bazen beklenenden farklı bir eşleştirme bulup gerekenden fazla satırı "değişti" gibi işaretleyebilir. Bu, algoritmanın bir hatası değil, satır bazlı karşılaştırmanın doğal bir sınırlamasıdır ve diff çıktısını yorumlarken akılda tutulmalıdır.

İki metin arasındaki farkı elle aramak yerine LCS tabanlı bir karşılaştırma aracı kullanmak hem daha hızlı hem daha güvenilirdir. Aşağıdaki araç, yukarıda anlatılan satır bazlı LCS mantığını doğrudan tarayıcınızda çalıştırır; girdiğiniz metinler herhangi bir sunucuya gönderilmez.

WhatsApp