Metin Farkı
İki metni yan yana karşılaştırın ve satır satır farkları vurgulayın
Metin A
Metin B
Metin Diff Nedir?
Metin diff ("fark" kelimesinin kısaltması), iki metin bloğunu karşılaştırıp hangi satırların eklendiğini, hangi satırların kaldırıldığını ve hangilerinin değişmeden kaldığını belirleyen bir işlemin sonucudur. Bu kavram, 1974'te Version 5 Unix'in bir parçası olarak ilk kez yayımlanan Unix diff yardımcı programından kaynaklanmaktadır. Günümüzde metin diff, her commit'in dosyaların tam bir kopyası yerine bir diff depoladığı Git gibi sürüm kontrol sistemlerinin temelini oluşturmaktadır.
Bir diff algoritması, iki satır dizisi arasındaki En Uzun Ortak Alt Diziyi (LCS — Longest Common Subsequence) bulur. LCS'de bulunan satırlar değişmeden kalmış olarak işaretlenir. Orijinal metinde olup LCS'de olmayan satırlar kaldırıldı olarak işaretlenir. Değiştirilmiş metinde olup LCS'de olmayan satırlar ise eklendi olarak işaretlenir. Sonuç, bir metni diğerine dönüştürmek için gereken minimum değişiklikler kümesidir.
Diff çıktısı çeşitli biçimlerde sunulur. Unified diff (git diff için varsayılan), kaldırılan satırların başına eksi işareti, eklenen satırların başına artı işareti koyar. Yan yana diff her iki metni paralel sütunlarda düzenler. Bu araç, renk kodlu çıktıyla satır satır karşılaştırma kullanır: eklemeler yeşil, kaldırmalar kırmızı ve değişmemiş satırlar nötr renkte gösterilir. Değişmemiş satırlar varsayılan olarak ön ek olmaksızın görünür; ancak yalnızca değişikliklere odaklanmak için gizlenebilir.
Çevrimiçi Metin Diff Aracı Neden Kullanılır?
Terminalde metin karşılaştırmak, diff yardımcı programlarını kurmayı ve komut satırı bayraklarıyla uğraşmayı gerektirir. Tarayıcı tabanlı bir diff aracı bu engeli tamamen ortadan kaldırır.
Metin Diff Kullanım Senaryoları
Diff Çıktı Biçimleri Karşılaştırması
Diff araçları çıktıyı çeşitli biçimlerde üretir. Aşağıdaki tablo en yaygın biçimleri, bunları neyin ürettiğini ve her birinin ne zaman yararlı olduğunu özetlemektedir.
| Biçim | Araç / Kaynak | Açıklama |
|---|---|---|
| Unified diff | diff -u / git diff | Prefixes lines with + / - / space; includes @@ hunk headers |
| Side-by-side | diff -y / sdiff | Two columns, changed lines aligned horizontally |
| Context diff | diff -c | Shows changed lines with surrounding context, marked with ! / + / - |
| HTML diff | Python difflib | Color-coded HTML table with inline change highlights |
| JSON Patch | RFC 6902 | Array of add/remove/replace operations on a JSON document |
Satır Diff Nasıl Çalışır: LCS Algoritması
Bu araç dahil çoğu satır diff aracı, En Uzun Ortak Alt Dizi (LCS) algoritmasını kullanır. LCS, her iki metinde de aynı göreli sırada görünen en büyük satır kümesini bulur; bu satırların bitişik olması gerekmez. LCS'de bulunmayan satırlar gerçek farklılıklardır.
Standart LCS algoritması dinamik programlama kullanır ve O(m x n) sürede çalışır; burada m ve n iki metnin satır sayılarıdır. Büyük dosyalar için Git tarafından kullanılan Myers diff algoritması gibi iyileştirilmiş varyantlar bunu O(n + d^2)'ye indirger; burada d fark sayısıdır; bu da satırların büyük çoğunluğu paylaşıldığında algoritmayı hızlandırır.
Kod Örnekleri
JavaScript, Python, Go ve komut satırında satır satır metin karşılaştırması uygulamaları. Her örnek unified biçiminde diff çıktısı üretir.
// Line-by-line diff using the LCS algorithm
function diffLines(a, b) {
const linesA = a.split('\n')
const linesB = b.split('\n')
// Build LCS table
const m = linesA.length, n = linesB.length
const dp = Array.from({ length: m + 1 }, () => new Array(n + 1).fill(0))
for (let i = 1; i <= m; i++)
for (let j = 1; j <= n; j++)
dp[i][j] = linesA[i-1] === linesB[j-1]
? dp[i-1][j-1] + 1
: Math.max(dp[i-1][j], dp[i][j-1])
// Backtrack to produce diff
const result = []
let i = m, j = n
while (i > 0 || j > 0) {
if (i > 0 && j > 0 && linesA[i-1] === linesB[j-1]) {
result.unshift({ type: 'equal', text: linesA[i-1] }); i--; j--
} else if (j > 0 && (i === 0 || dp[i][j-1] >= dp[i-1][j])) {
result.unshift({ type: 'add', text: linesB[j-1] }); j--
} else {
result.unshift({ type: 'remove', text: linesA[i-1] }); i--
}
}
return result
}
const diff = diffLines("alpha\nbeta\ngamma", "alpha\nbeta changed\ngamma\ndelta")
// → [
// { type: 'equal', text: 'alpha' },
// { type: 'remove', text: 'beta' },
// { type: 'add', text: 'beta changed' },
// { type: 'equal', text: 'gamma' },
// { type: 'add', text: 'delta' }
// ]import difflib
text_a = """alpha
beta
gamma""".splitlines()
text_b = """alpha
beta changed
gamma
delta""".splitlines()
# Unified diff (same format as git diff)
for line in difflib.unified_diff(text_a, text_b, fromfile='a.txt', tofile='b.txt', lineterm=''):
print(line)
# --- a.txt
# +++ b.txt
# @@ -1,3 +1,4 @@
# alpha
# -beta
# +beta changed
# gamma
# +delta
# HTML side-by-side diff
d = difflib.HtmlDiff()
html = d.make_file(text_a, text_b, fromdesc='Original', todesc='Modified')package main
import (
"fmt"
"strings"
)
// Minimal LCS-based line diff
func diffLines(a, b string) {
la := strings.Split(a, "\n")
lb := strings.Split(b, "\n")
m, n := len(la), len(lb)
dp := make([][]int, m+1)
for i := range dp {
dp[i] = make([]int, n+1)
}
for i := 1; i <= m; i++ {
for j := 1; j <= n; j++ {
if la[i-1] == lb[j-1] {
dp[i][j] = dp[i-1][j-1] + 1
} else if dp[i-1][j] >= dp[i][j-1] {
dp[i][j] = dp[i-1][j]
} else {
dp[i][j] = dp[i][j-1]
}
}
}
var result []string
i, j := m, n
for i > 0 || j > 0 {
if i > 0 && j > 0 && la[i-1] == lb[j-1] {
result = append([]string{" " + la[i-1]}, result...)
i--; j--
} else if j > 0 && (i == 0 || dp[i][j-1] >= dp[i-1][j]) {
result = append([]string{"+" + lb[j-1]}, result...)
j--
} else {
result = append([]string{"-" + la[i-1]}, result...)
i--
}
}
for _, line := range result {
fmt.Println(line)
}
}
// Output:
// alpha
// -beta
// +beta changed
// gamma
// +delta# Compare two files with unified diff (3 lines of context) diff -u original.txt modified.txt # Git diff between working tree and last commit git diff HEAD -- file.txt # Git diff between two branches git diff main..feature -- src/ # Side-by-side diff in the terminal diff -y --width=120 original.txt modified.txt # Color-coded diff (requires colordiff) diff -u original.txt modified.txt | colordiff