텍스트 비교 도구 활용법과 diff가 계산되는 방식
두 텍스트를 나란히 놓고 눈으로 다른 곳을 찾는 일은 사람이 가장 못하는 작업 중 하나입니다. diff 알고리즘은 이를 '한쪽을 다른 쪽으로 바꾸는 최소 편집'을 찾는 문제로 바꿔 기계적으로 해결합니다. 이 도구는 그 결과를 추가·삭제·변경으로 표시해 줍니다. 결과를 정확히 읽으려면 알고리즘이 무엇을 최소화하는지 알아 두는 편이 좋습니다.
사용 방법
- 왼쪽에 원본, 오른쪽에 비교할 텍스트를 붙여넣습니다.
- 변경된 부분이 강조 표시됩니다. 추가된 줄과 삭제된 줄이 색으로 구분됩니다.
- 차이가 예상보다 많다면 줄바꿈 방식이나 공백 차이일 수 있으니 아래 항목을 확인하세요.
- JSON이나 코드처럼 구조가 있는 텍스트라면 양쪽을 같은 규칙으로 포맷한 뒤 비교하면 결과가 훨씬 읽기 쉬워집니다.
diff는 무엇을 최소화하는가
대부분의 diff 구현은 최장 공통 부분수열(LCS)을 찾는 문제로 접근합니다. 두 텍스트에서 순서를 유지하며 공통으로 등장하는 가장 긴 부분을 찾아내면, 남는 부분이 곧 삭제와 추가가 됩니다. Myers 알고리즘이 이 계산을 실용적인 속도로 수행하는 표준적인 방법이고, Git도 기본적으로 이 계열을 씁니다.
여기서 중요한 함의가 나옵니다. 알고리즘은 '편집 횟수가 가장 적은 답'을 찾을 뿐, '사람이 보기에 가장 자연스러운 답'을 찾지는 않습니다. 그래서 함수 하나를 위로 옮기기만 한 변경이 '아래에서 삭제, 위에서 추가'로 표시되고, 비슷한 줄이 반복되는 코드에서는 블록 경계가 어긋나 엉뚱한 줄끼리 짝지어지기도 합니다. Git이 --patience 나 --histogram 같은 대안 알고리즘을 제공하는 이유가 이 가독성 문제입니다.
차이가 안 보이는데 다르다고 나올 때
웹에서 복사한 텍스트를 비교할 때 특히 자주 겪습니다. HTML에서 온 문자열에는 일반 공백처럼 보이는 non-breaking space(U+00A0)나 제로 폭 문자가 섞여 있는 경우가 많고, 화면에서는 완전히 동일하게 보입니다.
| 원인 | 확인 방법 | 해결 |
|---|---|---|
| 줄바꿈 방식 (CRLF vs LF) | 파일을 헥스 뷰어나 :set list 로 확인 | 한쪽으로 통일 (dos2unix, .gitattributes) |
| 줄 끝 공백 | 정규식 /[ \t]+$/ 로 검색 | 에디터의 trim trailing whitespace 설정 |
| 탭과 공백 혼용 | 에디터의 공백 표시 기능 | 포매터로 양쪽을 통일 |
| 파일 끝 개행 유무 | wc -l 결과 비교 | 개행 추가 |
| 비ASCII 공백 (U+00A0 등) | 유니코드 변환 도구로 이스케이프 | 일반 공백으로 치환 |
| 보이지 않는 제로 폭 문자 | 같은 방법으로 이스케이프 | 제거 |
| 유니코드 정규화 (NFC vs NFD) | normalize 후 비교 | 한 형태로 통일 |
줄 단위 비교와 문자 단위 비교
diff의 기본 단위는 줄입니다. 한 줄 안에서 한 글자만 바뀌어도 그 줄 전체가 '삭제 후 추가'로 표시됩니다. 코드에서는 이 방식이 적절하지만, 긴 문장 하나를 다듬은 문서에서는 어디가 바뀐 것인지 알 수 없게 됩니다.
그래서 실무에서는 대상에 따라 단위를 바꿉니다. 산문을 비교할 때는 단어 단위 diff가 훨씬 읽기 좋고(git diff --word-diff), 한 줄에 모든 내용이 들어 있는 미니파이된 파일은 줄 단위 비교가 사실상 무의미합니다. 후자의 경우 먼저 포맷을 풀어 여러 줄로 만든 뒤 비교하는 것이 정석입니다.
이런 작업에 씁니다
- 설정 파일의 운영 환경과 스테이징 환경 차이 확인
- API 응답이 배포 전후로 달라졌는지 검증 (양쪽을 같은 방식으로 포맷한 뒤 비교)
- 번역 파일에서 새로 추가되거나 빠진 키 찾기
- package-lock.json 변경 검토 시 실제로 어떤 의존성이 바뀌었는지 파악
- 로그 두 개를 비교해 실패한 실행에서만 나타나는 줄 찾기
- 문서 초안의 수정 전후 대조
- 계약서나 약관 개정 전후 비교
구조가 있는 데이터를 비교할 때
JSON을 텍스트로 비교하면 의미 없는 차이가 잔뜩 나옵니다. 키 순서가 다르거나 들여쓰기 폭이 달라도 텍스트로는 전부 변경으로 잡히기 때문입니다. 실제로 값이 달라졌는지 알고 싶다면 양쪽을 같은 규칙으로 정규화하는 것이 먼저입니다. 키를 정렬하고 같은 들여쓰기로 포맷한 뒤 비교하면 남는 차이가 진짜 차이입니다.
# 키를 정렬하고 동일한 형식으로 출력한 뒤 비교 jq -S . a.json > a.norm.json jq -S . b.json > b.norm.json diff a.norm.json b.norm.json
자주 묻는 질문
- 입력한 텍스트가 서버로 전송되나요?
- 전송되지 않습니다. 비교는 브라우저에서 계산됩니다. 다만 계약서나 개인정보가 포함된 문서를 외부 사이트에 붙여넣는 것은 조직 정책에 저촉될 수 있으니 확인 후 사용하세요.
- 공백 차이를 무시하고 비교할 수 있나요?
- 이 도구는 있는 그대로 비교합니다. 공백을 무시하고 싶다면 비교 전에 양쪽 텍스트를 정리하거나, 명령줄에서 diff -w 또는 git diff -w 를 쓰세요. 다만 Python이나 YAML처럼 들여쓰기가 문법인 언어에서는 공백 무시가 실제 차이를 숨길 수 있으니 주의해야 합니다.
- 매우 큰 파일도 비교할 수 있나요?
- 브라우저 메모리에서 처리하므로 수천 줄 규모는 문제없지만, 수십만 줄이 되면 느려지거나 탭이 멈출 수 있습니다. diff 계산은 입력 크기에 대해 선형보다 나쁜 경우가 있어 특히 차이가 많을 때 부담이 큽니다. 큰 파일은 명령줄 diff나 git diff를 쓰는 편이 낫습니다.
- 왜 옮긴 코드가 삭제와 추가로 표시되나요?
- 표준 diff는 '이동'이라는 개념이 없고 삭제와 추가만 표현합니다. 이동을 인식하려면 그것을 지원하는 도구가 필요합니다. Git은 --color-moved 옵션으로 이동한 블록을 다른 색으로 표시해 주고, 일부 코드 리뷰 도구도 유사한 기능을 제공합니다.
- diff 결과를 패치로 적용할 수 있나요?
- 패치를 적용하려면 통합 diff(unified diff) 형식이 필요합니다. 명령줄에서 diff -u a.txt b.txt > change.patch 로 만들고 patch -p1 < change.patch 로 적용합니다. Git 저장소 안에서는 git diff 와 git apply 를 쓰는 편이 안전합니다.
- 세 개 이상의 텍스트를 한 번에 비교할 수 있나요?
- 이 도구는 두 개를 비교합니다. 세 방향 비교가 필요하다면(공통 조상과 두 변경본) diff3 이나 git merge-file, 또는 에디터의 3-way merge 화면을 쓰세요. 병합 충돌을 해결할 때 필요한 것이 바로 이 형태입니다.
💡 참고: 차이가 유난히 많이 나오면 내용이 아니라 형식을 먼저 의심하세요. 줄바꿈 방식 하나만 달라도 모든 줄이 변경으로 표시됩니다.