본문 바로가기
TextKit

텍스트 비교 (diff) 도구

두 글을 줄 단위로 맞대어 추가·삭제·변경을 표시

비교하는 두 글은 브라우저 밖으로 나가지 않습니다.

비교 결과

추가 0삭제 0그대로 0

두 칸에 글을 넣으면 바뀐 줄이 여기에 표시됩니다.

‘같은 줄 번호끼리 비교’는 왜 실패하는가

두 글을 비교하는 가장 단순한 방법은 첫 줄은 첫 줄끼리, 둘째 줄은 둘째 줄끼리 맞대 보는 것입니다. 이 방법은 글의 앞부분이 그대로일 때만 통합니다. 맨 위에 줄 하나만 새로 추가돼도, 그 아래 모든 줄이 한 칸씩 밀려서 전부 ‘바뀐 줄’로 보입니다.

A            B(맨 위에 한 줄 추가)
─────────────────────────────
사과         포도   ← 다름?
바나나       사과   ← 다름?
딸기         바나나 ← 다름?
             딸기   ← 다름?

사람 눈에는 “포도” 한 줄이 위에 붙었을 뿐, 사과·바나나·딸기는 그대로입니다. 그런데 줄 번호로만 비교하면 네 줄이 전부 다르다고 나옵니다. 실제로 바뀐 건 한 줄인데 결과는 온통 빨강과 초록이 되어, 정작 무엇이 달라졌는지 알아볼 수 없습니다.

LCS — ‘가장 많이 겹치게 짝짓기’

올바른 접근은 순서를 바꾸지 않으면서 양쪽에서 가장 길게 이어지는 공통 부분을 먼저 찾는 것입니다. 이걸 최장 공통 부분수열(Longest Common Subsequence, LCS)이라고 합니다. 위 예에서 LCS 는 “사과 → 바나나 → 딸기”이고, 이 세 줄을 ‘그대로’로 고정한 뒤 나머지만 설명합니다 — B 에만 있는 “포도”는 추가된 줄.

  + 포도      (B 에만 있음 → 추가)
    사과      (공통)
    바나나    (공통)
    딸기      (공통)

빨강·초록이 한 줄로 줄었습니다. 이 도구는 두 글을 이 방식으로 정렬한 뒤, 공통 줄은 회색(그대로), A 에만 있는 줄은 빨강(삭제), B 에만 있는 줄은 초록(추가)으로 표시합니다. Git 을 비롯한 거의 모든 버전 관리 도구가 내부에서 쓰는 것과 같은 원리입니다.

‘이동’은 삭제와 추가로 보인다

LCS 는 순서를 지키는 짝짓기라, 줄의 위치를 서로 맞바꾼 경우는 이동으로 인식하지 못합니다. 두 문단의 순서를 바꾸면, 한쪽에서 삭제되고 다른 위치에서 다시 추가된 것으로 나옵니다. 이건 한계라기보다 정의입니다 — 대부분의 diff 도구가 같은 방식으로 동작하고, 이동을 따로 표시하려면 훨씬 복잡한 알고리즘이 필요합니다.

줄 단위 비교의 경계 — 알고 쓰면 유용하다

이 도구는 을 최소 단위로 봅니다. 그래서 한 줄 안에서 글자 하나만 바뀌어도 그 줄은 통째로 ‘삭제된 옛 줄’과 ‘추가된 새 줄’로 나뉩니다. 어느 글자가 바뀌었는지는 두 줄을 나란히 두고 직접 봐야 합니다.

이게 단점처럼 들리지만, 줄이 의미 단위인 텍스트에서는 오히려 정확합니다. 코드는 한 줄이 한 문장이고, 로그는 한 줄이 한 이벤트이며, 목록은 한 줄이 한 항목입니다. 이런 글에서 “줄 3이 바뀌었다”는 정보는 그 자체로 충분합니다. 반대로 긴 산문처럼 한 문단이 한 줄인 글은, 문단을 문장 단위로 줄바꿈해 두고 비교하면 훨씬 세밀하게 볼 수 있습니다.

옵션을 언제 켜는가

  • 공백 무시 — 들여쓰기만 바꿨거나, 탭을 스페이스로 치환했거나, 문장 사이 공백 칸 수만 다를 때. 서식 변경을 실제 내용 변경에서 걸러 냅니다.
  • 대소문자 무시 — 제목의 대소문자 표기만 통일한 경우처럼, 의미가 같은 변경을 무시하고 싶을 때.

두 옵션 모두 비교할 때만적용되고, 화면에 보여 주는 글자는 언제나 원본입니다. 공백을 무시하고 ‘같다’고 판정한 줄도, 표시는 원래 들여쓰기 그대로 나옵니다.

정리하면

  • 줄 번호로 맞대는 비교는 줄 하나만 밀려도 무너집니다. 이 도구는 LCS 로 가장 많이 겹치게 정렬한 뒤 나머지만 추가·삭제로 표시합니다.
  • 줄 단위 비교입니다. 한 줄 안의 변경은 줄 전체의 교체로 나옵니다. 줄이 의미 단위인 코드·로그·목록에 가장 잘 맞습니다.
  • 서식만 바뀐 경우는 옵션으로 걸러 내세요. 공백·대소문자 무시는 비교에만 적용되고 표시는 원본을 지킵니다.

자주 묻는 질문

줄 하나만 지웠는데 그 아래가 전부 바뀐 걸로 나오지 않나요?
이 도구는 그렇게 나오지 않습니다. 순진한 비교(같은 줄 번호끼리 맞대기)는 줄 하나만 밀려도 그 아래가 전부 어긋나 보이지만, 이 도구는 최장 공통 부분수열(LCS)로 '가장 많이 겹치도록' 두 글을 먼저 정렬합니다. 그래서 실제로 바뀐 줄만 추가·삭제로 표시됩니다.
한 줄 안에서 단어 하나만 바꿨는데 줄 전체가 바뀐 걸로 나옵니다.
이 도구는 줄 단위로 비교하기 때문입니다. 줄의 내용이 조금이라도 다르면 그 줄은 '삭제된 옛 줄 + 추가된 새 줄'로 나뉩니다. 어느 단어가 바뀌었는지는 두 줄을 직접 눈으로 대조해야 합니다. 코드나 문서처럼 줄이 의미 단위인 텍스트에는 줄 단위 비교가 가장 잘 맞습니다.
들여쓰기만 바꿨는데 전부 바뀐 걸로 나옵니다.
'공백 무시' 옵션을 켜세요. 앞뒤 여백과 연속된 공백의 차이를 무시하고 비교합니다. 탭을 스페이스로 바꾼 것, 들여쓰기 칸 수만 조정한 것 등을 실제 변경에서 걸러 낼 수 있습니다. 대소문자만 다른 경우를 위한 '대소문자 무시' 옵션도 있습니다.
순서를 서로 바꾼 두 줄은 어떻게 표시되나요?
위치를 옮긴 것을 '이동'으로 인식하지는 못합니다. LCS 기준으로는 한쪽에서 삭제되고 다른 위치에서 추가된 것으로 나옵니다(삭제 1 + 추가 1). 줄 단위 diff 의 일반적인 동작이며, 대부분의 버전 관리 도구도 같은 방식으로 이동을 다룹니다.
비교할 수 있는 글 길이에 제한이 있나요?
한쪽당 1,500줄까지 비교합니다. LCS 계산은 두 글의 줄 수를 곱한 만큼 시간과 메모리를 쓰기 때문에, 아주 긴 로그를 붙이면 브라우저가 멈출 수 있어 상한을 뒀습니다. 넘으면 앞부분만 비교하고 화면에 '잘렸다'고 알립니다 — 조용히 일부만 비교하지 않습니다.
비교하는 두 글이 서버로 전송되나요?
아닙니다. 비교는 전부 브라우저 안에서 끝나고, 입력한 글은 어디로도 전송되거나 저장되지 않습니다. 계약서 초안이나 사내 문서의 두 버전을 붙여넣어도 안전합니다.