Diff 체커는 모든 개발자, 작가, 시스템 관리자에게 필수적인 도구입니다. 두 파일을 비교하거나, 코드 변경을 검토하거나, 두 텍스트 간의 차이를 찾아야 할 때, diff 알고리즘의 작동 방식을 이해하면 생산성이 크게 향상됩니다. 이 종합 가이드는 텍스트 diff 알고리즘의 기초부터 Git, JavaScript, Python, Bash의 실용적인 코드 예제까지 모두 다룹니다.
무료 온라인 텍스트 Diff 체커 도구를 사용해 보세요.
Diff 체커란?
Diff 체커(텍스트 비교 도구라고도 함)는 두 텍스트 또는 파일을 입력으로 받아 차이점을 식별하는 소프트웨어입니다. 출력은 추가, 삭제 또는 수정된 줄을 보여줍니다. 이 개념은 1974년 Douglas McIlroy가 만든 Unix diff 명령에서 시작되었습니다.
Diff 체커는 "버전 A와 버전 B 사이에 무엇이 변경되었는가?"라는 질문에 효율적으로 답합니다. diff 알고리즘은 텍스트 A를 텍스트 B로 변환하는 최소 편집 세트를 찾아야 하며, LCS(최장 공통 부분 수열) 알고리즘을 기반으로 합니다.
최신 온라인 diff 도구는 구문 강조, 문자 수준 차이 감지, 나란히 보기 및 인라인 보기, 공백 무시 옵션, 시맨틱 diff 기능을 제공합니다.
Diff 알고리즘 작동 방식
모든 diff 체커의 기반은 LCS(최장 공통 부분 수열) 알고리즘입니다. 두 입력에서 같은 순서로 나타나는 가장 긴 요소 시퀀스를 찾습니다.
클래식 LCS 알고리즘의 시간 복잡도는 O(n*m)입니다. Myers 알고리즘(1986)은 차이 수 d에 대해 O(n*d)로 최단 편집 스크립트를 찾습니다. Git이 사용하는 알고리즘입니다.
Myers 알고리즘은 편집 연산 그래프를 탐색하여 두 텍스트의 시작부터 끝까지 최단 경로를 최적으로 찾습니다.
줄 단위 vs 문자 단위 diff: 대부분의 도구는 먼저 줄 수준에서 비교한 후, 변경된 줄 내에서 문자 수준 diff를 수행하여 읽기 쉬운 출력을 생성합니다.
Diff 출력 유형
diff 결과를 표시하는 여러 표준 형식이 있습니다:
Unified Diff: git diff에서 사용하는 가장 일반적인 형식. +와 - 접두사와 @@ 마커로 변경을 표시합니다.
나란히 보기 Diff: 원본과 수정된 텍스트를 두 열에 나란히 표시하고 변경을 강조합니다.
인라인 Diff: 이전 버전과 새 버전을 한 열에 번갈아 표시하며 색상 코드(빨강/초록)를 사용합니다.
컨텍스트 Diff: !로 변경된 줄을 표시하고 ***와 --- 섹션을 가진 이전 형식.
워드 Diff: 전체 줄이 아닌 개별 단어를 비교합니다. Git은 git diff --word-diff으로 지원합니다.
일반적인 사용 사례
Diff 체크와 텍스트 비교는 많은 전문적인 워크플로에 필수적입니다:
코드 리뷰: 모든 풀 리퀘스트는 기본적으로 diff입니다. 개발자는 변경 사항을 이해하고 코드 품질을 확인하기 위해 diff 출력을 검토합니다.
문서 버전 관리: 작가와 법률 전문가는 리비전 간 변경 사항을 추적하기 위해 파일을 자주 비교합니다.
설정 파일 변경: 관리자는 변경 전후 설정 파일을 비교하여 의도한 수정만 이루어졌는지 확인합니다.
API 응답 비교: 개발자는 환경 간 JSON/XML 응답을 비교하여 예상치 못한 변경을 식별합니다.
머지 충돌 해결: diff 출력 이해는 Git 충돌을 올바르게 해결하는 데 필수적입니다.
Diff 코드 예제
Git Diff 명령어
Git에는 가장 강력한 내장 diff 체커가 있습니다. 필수 git diff 명령어를 소개합니다:
# ===== Basic git diff commands =====
# Compare working directory with staging area (unstaged changes)
git diff
# Compare staging area with last commit (staged changes)
git diff --staged
# or equivalently:
git diff --cached
# Compare working directory with last commit (all changes)
git diff HEAD
# Compare two specific commits
git diff abc1234 def5678
# Compare current branch with another branch
git diff main..feature-branch
# Compare a specific file between commits
git diff HEAD~3 HEAD -- src/app.js
# ===== Advanced git diff options =====
# Word-level diff (great for prose and documentation)
git diff --word-diff
# Output: [-old word-]{+new word+}
# Word diff with color only (no markers)
git diff --word-diff=color
# Show only file names that changed
git diff --name-only HEAD~5
# Show file names with change status (Added/Modified/Deleted)
git diff --name-status main..feature
# Show diff statistics (insertions/deletions per file)
git diff --stat
# Output:
# src/app.js | 15 +++++++++------
# src/utils.js | 8 +++++---
# 2 files changed, 14 insertions(+), 9 deletions(-)
# One-line summary of changes
git diff --shortstat
# Output: 2 files changed, 14 insertions(+), 9 deletions(-)
# Ignore whitespace changes
git diff -w
# or: git diff --ignore-all-space
# Ignore blank line changes
git diff --ignore-blank-lines
# Show diff with 10 lines of context (default is 3)
git diff -U10
# Generate a patch file
git diff > my-changes.patch
# Apply a patch file
git apply my-changes.patch
# Check if a patch applies cleanly (dry run)
git apply --check my-changes.patchJavaScript 텍스트 Diff (diff npm 패키지)
diff npm 패키지는 텍스트 diff 계산을 위한 가장 인기 있는 JavaScript 라이브러리입니다:
// npm install diff
const Diff = require('diff');
const oldText = `function greet(name) {
console.log("Hello, " + name);
return true;
}`;
const newText = `function greet(name, greeting) {
console.log(greeting + ", " + name + "!");
return true;
}`;
// ===== Line-by-line diff =====
const lineDiff = Diff.diffLines(oldText, newText);
lineDiff.forEach(part => {
const prefix = part.added ? '+' : part.removed ? '-' : ' ';
const lines = part.value.split('\n').filter(l => l);
lines.forEach(line => console.log(prefix + ' ' + line));
});
// Output:
// - function greet(name) {
// + function greet(name, greeting) {
// - console.log("Hello, " + name);
// + console.log(greeting + ", " + name + "!");
// return true;
// }
// ===== Character-level diff =====
const charDiff = Diff.diffChars('hello world', 'hello there');
charDiff.forEach(part => {
const color = part.added ? '\x1b[32m' : part.removed ? '\x1b[31m' : '';
process.stdout.write(color + part.value + '\x1b[0m');
});
// Highlights exact character changes
// ===== Word-level diff =====
const wordDiff = Diff.diffWords(
'The quick brown fox jumps over the lazy dog',
'The slow brown fox leaps over the tired dog'
);
wordDiff.forEach(part => {
if (part.added) console.log('[+] ' + part.value);
else if (part.removed) console.log('[-] ' + part.value);
});
// ===== Generate unified patch =====
const patch = Diff.createPatch(
'greeting.js', // filename
oldText, // old content
newText, // new content
'original', // old header
'modified' // new header
);
console.log(patch);
// Output: standard unified diff format
// ===== Apply a patch =====
const applied = Diff.applyPatch(oldText, patch);
console.log(applied === newText); // true
// ===== Structured patch for multiple files =====
const structuredPatch = Diff.structuredPatch(
'old/file.js', 'new/file.js',
oldText, newText, '', ''
);
console.log(JSON.stringify(structuredPatch.hunks, null, 2));Python Diff (difflib 모듈)
Python은 표준 라이브러리에 강력한 difflib 모듈을 포함하고 있습니다:
import difflib
old_text = """function greet(name) {
console.log("Hello, " + name);
return true;
}""".splitlines(keepends=True)
new_text = """function greet(name, greeting) {
console.log(greeting + ", " + name + "!");
return true;
}""".splitlines(keepends=True)
# ===== Unified diff (most common format) =====
diff = difflib.unified_diff(
old_text, new_text,
fromfile='greeting.js.orig',
tofile='greeting.js',
lineterm=''
)
print('\n'.join(diff))
# Output:
# --- greeting.js.orig
# +++ greeting.js
# @@ -1,4 +1,4 @@
# -function greet(name) {
# - console.log("Hello, " + name);
# +function greet(name, greeting) {
# + console.log(greeting + ", " + name + "!");
# return true;
# }
# ===== Context diff (older format) =====
ctx_diff = difflib.context_diff(
old_text, new_text,
fromfile='original', tofile='modified'
)
print('\n'.join(ctx_diff))
# ===== HTML visual diff report =====
d = difflib.HtmlDiff()
html = d.make_file(
old_text, new_text,
fromdesc='Original',
todesc='Modified',
context=True, # show only changed sections
numlines=3 # lines of context
)
with open('diff_report.html', 'w') as f:
f.write(html)
# ===== SequenceMatcher for similarity ratio =====
seq = difflib.SequenceMatcher(None,
''.join(old_text), ''.join(new_text))
print(f"Similarity ratio: {seq.ratio():.2%}")
# Output: Similarity ratio: 72.41%
# ===== Get matching blocks =====
for block in seq.get_matching_blocks():
print(f" a[{block.a}:{block.a+block.size}] == "
f"b[{block.b}:{block.b+block.size}] "
f"(size={block.size})")
# ===== Get opcodes (edit operations) =====
for op, i1, i2, j1, j2 in seq.get_opcodes():
print(f" {op:8s} a[{i1}:{i2}] b[{j1}:{j2}]")
# Output:
# equal a[0:0] b[0:0]
# replace a[0:28] b[0:38]
# equal a[28:50] b[38:60]
# ===== Compare two files =====
with open('file1.txt') as f1, open('file2.txt') as f2:
diff = difflib.unified_diff(
f1.readlines(), f2.readlines(),
fromfile='file1.txt', tofile='file2.txt'
)
print('\n'.join(diff))Bash / Linux Diff 명령어
Linux와 macOS는 텍스트 비교를 위한 여러 명령줄 도구를 제공합니다:
# ===== Basic diff command =====
# Compare two files (default output format)
diff file1.txt file2.txt
# Unified diff format (most readable)
diff -u file1.txt file2.txt
# Output:
# --- file1.txt 2024-01-15 10:30:00
# +++ file2.txt 2024-01-15 11:45:00
# @@ -1,4 +1,4 @@
# -old line 1
# +new line 1
# unchanged line
# Side-by-side comparison
diff -y file1.txt file2.txt
# or with specific width:
diff -y -W 120 file1.txt file2.txt
# Show only lines that differ (with side-by-side)
diff -y --suppress-common-lines file1.txt file2.txt
# Ignore case differences
diff -i file1.txt file2.txt
# Ignore all whitespace
diff -w file1.txt file2.txt
# Ignore blank lines
diff -B file1.txt file2.txt
# Recursive directory comparison
diff -r dir1/ dir2/
# Brief output (just report if files differ)
diff -q file1.txt file2.txt
# Output: Files file1.txt and file2.txt differ
# ===== Enhanced diff tools =====
# colordiff: colorized diff output
# Install: apt install colordiff / brew install colordiff
colordiff -u file1.txt file2.txt
# vimdiff: side-by-side in Vim editor
vimdiff file1.txt file2.txt
# sdiff: interactive side-by-side merge
sdiff file1.txt file2.txt
# ===== Practical examples =====
# Compare command output
diff <(ls dir1/) <(ls dir2/)
# Compare sorted files
diff <(sort file1.txt) <(sort file2.txt)
# Compare remote file with local file
diff <(curl -s https://example.com/config.yml) local-config.yml
# Generate a patch file
diff -u original.txt modified.txt > changes.patch
# Apply a patch
patch original.txt < changes.patch
# Dry run (check if patch applies cleanly)
patch --dry-run original.txt < changes.patch
# Reverse a patch
patch -R original.txt < changes.patch
# Compare two strings directly
diff <(echo "hello world") <(echo "hello there")Diff 출력 읽는 방법
diff 출력 이해는 기본적인 개발자 스킬입니다. Unified Diff 형식을 설명합니다:
파일 헤더: diff는 --- a/file.txt(원본)와 +++ b/file.txt(수정본)로 시작합니다.
헝크 헤더: @@ 줄은 @@ -시작,개수 +시작,개수 @@ 형식으로 변경 위치를 표시합니다.
변경된 줄: - 줄(빨강)은 삭제, + 줄(초록)은 추가. 접두사 없는 줄은 컨텍스트입니다.
# Example: reading a unified diff
diff --git a/src/config.js b/src/config.js
index 8a3b5c1..f29d4e2 100644
--- a/src/config.js ← original file
+++ b/src/config.js ← modified file
@@ -12,8 +12,9 @@ const defaults = { ← hunk header: line 12, 8→9 lines
timeout: 3000, ← context (unchanged)
retries: 3, ← context (unchanged)
- baseUrl: 'http://localhost:3000', ← REMOVED (red)
- debug: false, ← REMOVED (red)
+ baseUrl: 'https://api.example.com', ← ADDED (green)
+ debug: true, ← ADDED (green)
+ verbose: true, ← ADDED (green, new line)
headers: { ← context (unchanged)
'Content-Type': 'application/json' ← context (unchanged)
} ← context (unchanged)패치 파일: diff를 .patch 파일로 저장하고 git apply나 patch -p1로 적용할 수 있습니다.
통계: git diff --stat으로 파일별 변경 요약을 확인할 수 있습니다.
# git diff --stat output example:
src/config.js | 5 +++--
src/app.js | 12 ++++++------
tests/config.test | 28 ++++++++++++++++++++++++++++
3 files changed, 37 insertions(+), 8 deletions(-)
# The bar shows the ratio of additions (+) to deletions (-)
# Longer bars = more changes in that file최고의 Diff 도구 비교
사용 가능한 최고의 diff 체커 도구 비교입니다:
| Tool | Type | Price | Platform | Best For |
|---|---|---|---|---|
| DevToolBox | Web | Free | Any browser | Quick online comparisons |
| VS Code | Editor | Free | Win/Mac/Linux | Code review + editing |
| Beyond Compare | Desktop | $35-60 | Win/Mac/Linux | 3-way merge, folder sync |
| Meld | Desktop | Free | Linux/Mac/Win | Visual diff + VCS integration |
| WinMerge | Desktop | Free | Windows | File + folder comparison |
| diff (CLI) | CLI | Free | Unix/Linux/Mac | Scripting + CI/CD pipelines |
| git diff | CLI | Free | Any | Version control diffs |
DevToolBox 텍스트 Diff(온라인): 무료 온라인 diff 도구로, 구문 강조와 문자 수준 diff가 포함된 즉시 나란히 비교를 제공합니다.
VS Code 내장 Diff: VS Code에는 인라인과 나란히 보기를 갖춘 우수한 diff 편집기가 포함되어 있습니다.
Beyond Compare: 3방향 머지와 폴더 동기화를 지원하는 상용 diff 도구.
Meld: Linux, macOS, Windows용 무료 오픈소스 비주얼 diff 도구.
WinMerge: 셸 통합을 갖춘 Windows용 무료 오픈소스 diff 도구.
diff 명령어(Unix): 빠르고 스크립팅 가능한 오리지널 명령줄 diff 도구.
자주 묻는 질문
온라인에서 두 텍스트 파일을 비교하려면?
무료 Text Diff Checker와 같은 온라인 diff 도구에 각 파일의 내용을 붙여넣으세요. 도구가 추가된 줄(초록), 삭제된 줄(빨강), 변경되지 않은 컨텍스트 줄을 즉시 강조합니다. 대부분의 온라인 도구는 나란히 보기와 인라인 보기를 지원합니다.
diff 출력에서 +와 -는 무엇을 의미하나요?
Unified Diff 형식에서 +로 시작하는 줄은 추가된 콘텐츠, -로 시작하는 줄은 삭제된 콘텐츠를 나타냅니다. 접두사 없는 줄은 변경되지 않은 컨텍스트입니다. @@ 마커는 변경이 발생하는 줄 번호를 보여줍니다.
git diff는 어떻게 작동하나요?
Git diff는 Myers 알고리즘을 사용하여 두 버전 간의 최소 변경 세트를 찾습니다. 인수 없이 실행하면 작업 디렉토리와 인덱스를 비교합니다. git diff --staged는 인덱스와 HEAD를 비교합니다. 출력은 Unified Diff 형식입니다.
Diff 도구의 효과적인 사용은 개발자와 관리자에게 기본적인 스킬입니다. 무료 온라인 도구로 즉시 텍스트 비교를 수행하세요.