텍스트 비교

두 텍스트를 나란히 비교하고 줄별로 차이를 강조 표시

예시 시도

텍스트 A

텍스트 B

로컬에서 실행 · 시크릿 붙여넣기 안전
로컬에서 실행 · 시크릿 붙여넣기 안전

텍스트 비교(Diff)란?

텍스트 diff(difference의 줄임말)는 두 텍스트 블록을 비교하여 어떤 줄이 추가, 삭제, 또는 변경 없이 유지되었는지 식별한 결과물입니다. 이 개념은 1974년 Version 5 Unix의 일부로 처음 출시된 Unix diff 유틸리티에서 비롯되었습니다. 오늘날 텍스트 diff는 Git과 같은 버전 관리 시스템의 근간으로, 모든 커밋은 각 파일의 전체 복사본이 아닌 diff를 저장합니다.

diff 알고리즘은 두 줄 시퀀스 간의 LCS(Longest Common Subsequence, 최장 공통 부분 수열)를 찾습니다. LCS에 포함된 줄은 변경되지 않음으로 표시됩니다. 원본 텍스트에 있지만 LCS에 없는 줄은 삭제됨으로 표시됩니다. 수정된 텍스트에 있지만 LCS에 없는 줄은 추가됨으로 표시됩니다. 결과는 한 텍스트를 다른 텍스트로 변환하는 데 필요한 최소한의 변경 집합입니다.

diff 출력 형식은 여러 가지입니다. 통합 diff(git diff의 기본값)는 삭제된 줄에 마이너스 기호를, 추가된 줄에 플러스 기호를 붙입니다. 나란히 보기 diff는 두 텍스트를 병렬 열로 배치합니다. 이 도구는 색상 코드 출력을 사용한 줄 단위 비교를 사용합니다: 추가는 초록색, 삭제는 빨간색, 변경 없음은 중립색. 변경되지 않은 줄은 기본적으로 접두사 없이 표시되지만, 변경 사항에만 집중하기 위해 숨길 수 있습니다.

온라인 텍스트 비교 도구를 사용하는 이유

터미널에서 텍스트를 비교하려면 diff 유틸리티를 설치하고 커맨드라인 플래그를 다뤄야 합니다. 브라우저 기반 diff 도구는 이런 번거로움을 완전히 제거합니다.

즉각적인 비교
두 텍스트 블록을 붙여넣으면 차이점이 즉시 강조 표시됩니다. 파일 생성, 기억해야 할 명령어, 파싱할 출력이 없습니다.
🔒
개인정보 보호 우선 처리
모든 비교는 JavaScript를 사용하여 브라우저에서 실행됩니다. 텍스트는 기기를 떠나지 않으며, 이는 구성 파일, 인증 정보, 또는 독점 코드를 비교할 때 중요합니다.
📋
복사 가능한 출력
diff 출력은 통합 diff 형식과 일치하는 표준 + / - 접두사를 사용합니다. 결과를 커밋 메시지, 코드 리뷰 댓글, 또는 버그 보고서에 직접 복사할 수 있습니다.
🌐
로그인 또는 설치 불필요
브라우저가 있는 모든 기기에서 작동합니다. 계정 생성, 확장 프로그램, 데스크톱 앱이 필요 없습니다. 페이지를 열고 바로 비교를 시작하세요.

텍스트 비교 활용 사례

프론트엔드 개발
빌드 단계 전후의 최소화된 CSS 또는 HTML 출력을 비교하여 생성된 마크업이나 스타일의 의도치 않은 변경 사항을 발견합니다.
백엔드 엔지니어링
환경 간(스테이징 vs 프로덕션) API 응답을 비교하여 배포가 예상치 못한 데이터 변경 사항을 도입하지 않았는지 확인합니다.
DevOps 및 인프라
라이브 클러스터나 서버에 변경 사항을 적용하기 전에 Kubernetes 매니페스트, Terraform 계획, 또는 Nginx 설정을 비교합니다.
QA 및 테스트
실제 결과와 저장된 스냅샷 파일을 비교하여 테스트 출력이 예상 기준선과 일치하는지 확인합니다.
데이터 엔지니어링
데이터베이스 마이그레이션에서 CSV 헤더나 SQL 스키마 정의를 비교하여 컬럼이 올바르게 추가되거나 이름이 변경되었는지 확인합니다.
학습 및 과제
풀이를 참고 구현과 줄 단위로 비교하여 로직이 예상 접근 방식에서 어디서 벗어나는지 찾습니다.

diff 출력 형식 비교

diff 도구는 여러 형식으로 출력을 생성합니다. 아래 표는 가장 일반적인 형식, 생성하는 도구, 각각이 유용한 상황을 정리합니다.

형식도구 / 출처설명
Unified diffdiff -u / git diffPrefixes lines with + / - / space; includes @@ hunk headers
Side-by-sidediff -y / sdiffTwo columns, changed lines aligned horizontally
Context diffdiff -cShows changed lines with surrounding context, marked with ! / + / -
HTML diffPython difflibColor-coded HTML table with inline change highlights
JSON PatchRFC 6902Array of add/remove/replace operations on a JSON document

줄 비교 작동 방식: LCS 알고리즘

이 도구를 포함한 대부분의 줄 비교 도구는 LCS(Longest Common Subsequence, 최장 공통 부분 수열) 알고리즘을 사용합니다. LCS는 연속적일 필요 없이 같은 상대적 순서로 두 텍스트에 모두 나타나는 가장 큰 줄 집합을 찾습니다. LCS에 없는 줄이 실제 차이점입니다.

표준 LCS 알고리즘은 동적 프로그래밍을 사용하며 O(m × n) 시간으로 실행됩니다. 여기서 m과 n은 두 텍스트의 줄 수입니다. 대용량 파일의 경우 Git에서 사용하는 Myers' diff 알고리즘과 같은 최적화 변형이 이를 O(n + d²)로 줄입니다. 여기서 d는 차이의 수로, 대부분의 줄이 공유될 때 빠르게 동작합니다.

1. DP 테이블 구성
(m+1) × (n+1) 행렬을 만듭니다. 각 줄 쌍에 대해 지금까지 발견된 최장 공통 부분 수열의 길이를 저장합니다. 동일한 줄은 대각선 값을 1씩 늘립니다.
2. 역추적
행렬의 오른쪽 하단 모서리에서 (0,0)까지 거슬러 올라갑니다. 동일한 줄에서의 대각선 이동은 '변경 없음' 항목을 만듭니다. 수평 또는 수직 이동은 '추가됨' 또는 '삭제됨' 항목을 만듭니다.
3. 출력 렌더링
각 항목을 표시 줄로 매핑합니다: 변경되지 않은 줄은 접두사 없음, 추가된 줄은 +, 삭제된 줄은 -. 시각적 명확성을 위해 색상 코드를 적용합니다.

코드 예제

JavaScript, Python, Go 및 커맨드라인에서 줄 단위 텍스트 비교 구현. 각 예제는 통합 형식 diff 출력을 생성합니다.

JavaScript
// 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' }
// ]
Python
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')
Go
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
CLI (diff / git)
# 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

자주 묻는 질문

줄 diff와 문자 diff의 차이는 무엇인가요?
줄 diff는 텍스트를 줄 단위로 비교합니다: 한 줄에서 어떤 문자라도 변경되면 전체 줄이 삭제됨으로 표시되고, 새 버전은 추가됨으로 표시됩니다. 문자 diff(또는 단어 diff)는 더 세밀한 단위로 작동하여 줄 내에서 변경된 특정 문자나 단어를 표시합니다. 줄 diff는 코드 리뷰에 표준이며, 문자 diff는 산문 편집에 더 유용합니다.
git diff는 내부적으로 어떻게 작동하나요?
Git은 기본적으로 Myers' diff 알고리즘을 사용합니다. 이 알고리즘은 두 파일 간의 최단 편집 스크립트(삽입과 삭제의 최소 수)를 찾습니다. Git은 줄 번호를 나타내는 @@ 헝크 헤더와 함께 통합 diff 형식으로 결과를 저장합니다. git diff를 실행하면, HEAD를 명시적으로 전달하지 않는 한 Git은 마지막 커밋이 아닌 작업 트리를 인덱스(스테이징 영역)와 비교합니다.
텍스트 diff 도구로 바이너리 파일을 비교할 수 있나요?
아니요. 텍스트 diff 도구는 입력을 줄바꿈 문자로 분리하고 문자열을 비교합니다. 바이너리 파일은 무의미한 줄 분리를 만들어내는 임의의 바이트 시퀀스를 포함합니다. 바이너리 비교에는 hex diff 도구나 파일 수준 체크섬 비교(두 파일에 sha256sum)를 사용하세요.
이 도구를 사용할 때 데이터가 서버로 전송되나요?
아니요. 이 도구는 완전히 브라우저에서 실행됩니다. diff 계산은 클라이언트 사이드에서 실행되는 JavaScript LCS 구현을 사용합니다. 텍스트 내용으로 네트워크 요청이 이루어지지 않습니다. 도구를 사용하는 동안 브라우저의 네트워크 탭을 열어 직접 확인할 수 있습니다.
통합 diff 형식이란 무엇인가요?
통합 diff는 diff -u와 git diff에서 사용하는 출력 형식입니다. 변경된 줄을 -(삭제됨)과 +(추가됨) 접두사로 표시하고, 두 파일의 줄 번호 범위를 지정하는 @@ 헤더가 앞에 붙습니다. 컨텍스트 줄(변경 없음)은 공백 접두사를 가집니다. 통합 diff는 패치, 풀 리퀘스트, 코드 리뷰 도구에서 가장 일반적인 형식입니다.
차이가 많은 대용량 파일은 어떻게 비교하나요?
수천 줄의 파일은 브라우저 기반 도구에서도 작동하지만 LCS 알고리즘이 이차적으로 확장되기 때문에 느려질 수 있습니다. 매우 큰 diff의 경우 diff나 git diff 같은 커맨드라인 도구가 최적화된 C 구현을 사용하고 출력을 스트리밍할 수 있어 더 빠릅니다. 또한 이 도구에서 '변경되지 않은 줄 표시'를 끄면 변경 사항에만 집중할 수 있습니다.
3방향 병합 diff란 무엇인가요?
3방향 병합은 파일의 두 수정된 버전을 공통 조상(기준)과 비교합니다. Git은 git merge와 git rebase 중에 이를 사용합니다. 기준 대비 각 브랜치에서 변경된 사항을 식별하고 이를 결합합니다. 두 브랜치가 동일한 줄을 수정하면 Git은 병합 충돌을 보고합니다. 3방향 병합은 세 개의 입력이 필요하지만, 표준 diff는 두 개만 필요합니다.