코드 리뷰나 버전 관리 작업에서 수십 년 동안 기본값이었던 diff -u는 파일을 그저 텍스트 줄의 나열로 본다. 줄 단위로 더해지고 빠진 부분을 표시할 뿐, 함수 하나가 통째로 옮겨졌는지 변수명만 바뀌었는지는 구분하지 못한다. 최근 Hacker News에 공개된 OmniDiff는 이 지점을 겨냥한 오픈소스 도구다. Rust로 작성됐고, 파일의 종류를 인식해 그에 맞는 방식으로 차이를 보여주는 '콘텐츠 인식(content-aware)' 디프를 표방한다.
구조적 디프와 파일 타입 인식
OmniDiff의 핵심은 파일을 바이트가 아니라 내용으로 다룬다는 점이다. 텍스트 소스 코드는 확장자로 언어를 판별하고, 그중 25개 언어는 tree-sitter 문법으로 파싱해 구조적으로 비교한다. 즉 줄이 아니라 함수·클래스·구조체 같은 구문 단위로 변화를 추적한다. 변경 구간(hunk) 앞에 가장 가까운 함수나 클래스 선언 줄을 덧붙여, 큰 파일 깊숙한 곳의 수정 위치를 짚어주는 기능도 여기서 나온다. 반면 Bazel, Dart, Emacs Lisp, 마크다운, 프로토콜 버퍼, SQL은 확장자는 인식하되 문법이 내장되지 않아 일반 텍스트로 처리되고, 확장자가 없거나 알 수 없는 파일도 거부되지 않고 줄 단위 텍스트로 비교된다.
텍스트가 아닌 파일은 이름이 아니라 바이트로 종류를 판별한다. 이미지, 폰트, 압축 아카이브, PDF 등은 '무엇이 바뀌었는지'에 대한 짧은 보고로 표시된다. 글리프 두 개가 수정된 폰트라면 바뀐 두 글리프만 열어 보여주는 식이다. 흥미로운 점은 변화의 성격을 사람이 체감하는 정도로 이름 붙인다는 것인데, 바이트만 다른 invisible부터 imperceptible, 압축·리샘플링 잔재인 artifacts, edited, redrawn, replaced까지 단계가 나뉜다. 터미널이 kitty·sixel·iTerm2 그래픽 프로토콜을 지원하면 이미지를 실제 이미지로, 아니면 유니코드 반블록 문자로 그려준다. 이 모든 분류에 해당하지 않는 바이너리는 기존 도구와 똑같이 Binary file ... differs 한 줄로 끝난다.
실무 도입 시 들여다볼 지점
도입을 고려한다면 통합 경로가 현실적인 관심사다. OmniDiff는 git difftool 백엔드로 동작하며, 설정 마법사로 전역 또는 저장소 단위 등록이 가능하고 GIT_EXTERNAL_DIFF 경로도 지원한다. 다만 git diff나 git log -p는 출력을 페이저로 보내기 때문에 전체 화면 TUI가 뜨지 않고 항상 평문 모드로 떨어진다. 대화형 뷰어를 원하면 git difftool을 써야 하고, SSH 환경에서는 의사 터미널 할당을 위해 ssh -t로 재접속해야 할 수 있다. Jujutsu(jj)도 별도 설정이 필요하며 diff-invocation-mode = "file-by-file" 지정이 필수다. CI나 스크립트에서는 --headless(또는 --batch)로 평문을 뽑고, stdout이 터미널이 아니면 자동으로 이 모드가 켜진다. 종료 코드는 성공 0, 오류 2이며, 파일이 다를 때 1을 받으려면 --exit-code를 명시해야 한다. 버전 관리 시스템이 비정상 종료를 '도구 실패'로 해석하는 관행을 고려한 선택이다. 기계가 읽기 좋은 --mode json 출력도 제공되고 스키마가 함께 공개돼 있다.
설치는 Linux·macOS·Windows 프리빌드 바이너리, 서명된 apt 저장소의 .deb, Nix, Arch·Gentoo 레시피로 다양하다. 소스 빌드는 Rust 1.92 이상과 C 컴파일러가 필요하고, 모든 tree-sitter 문법을 C에서 컴파일하는 데다 lto = "fat" 릴리스 프로파일 때문에 첫 설치에 몇 분이 걸린다. VS Code 확장은 아직 없다. 내장 디프 뷰를 대체하는 API가 상류에 구현됐지만 릴리스되지 않아, 공개되면 채택할 예정이라고 한다.
성능과 아직 남은 숙제
속도는 공개된 수치가 구체적이다. i7-1370P 노트북에서 2,302개 픽스처를 측정한 결과 중앙값 4.2ms, p90 35.1ms, p99 177ms, 최대 482ms였고 100ms를 넘는 경우는 2.4%에 그쳤다. 다만 측정값은 기계마다 달라 Xeon E3-1275 v5 서버는 약 2.5배 더 걸린다고 명시한다. 견고성 목표는 '모든 커밋의 100% 처리'인데, Gentoo가 추린 약 7,500개 오픈소스 저장소의 커밋 이력에서 25개 언어 44만여 쌍을 비교해 99.95%가 완료됐다. 실패한 쪽은 대부분 생성·임베드된 파일이나 거대한 단일 헤더 라이브러리 같은 극단적 사례였다.
주목할 점은 정확도에 대해 개발자가 솔직하다는 것이다. 사람이 손으로 레이블링한 정답 매핑과 바이트 단위로 비교하는데, 1,419개 픽스처에 이 정답이 달려 있고 두 목표 모두 '아직 달성하지 못했다'고 밝힌다. 전체 코퍼스 기준 오차율이 1%에 한참 못 미치는 것은 대부분이 변경되지 않은 영역이라 쉽기 때문이며, 실제로 중요한 건 사람이 디프를 한 건씩 마주할 때의 테스트 케이스 단위 수치라고 짚는다. 격차의 원인도 매처보다 하이라이팅 규칙 쪽에 있다고 분석한다. 라이선스는 AGPL v3이며, 소스 공개 의무 없이 조직 내부에서 쓰려면 GitHub Sponsors를 통한 월 구독형 상용 라이선스를 별도로 선택해야 한다. 코드 리뷰용 웹 도구 codereview는 아직 v0.0.0으로 '사용 시 위험 감수' 단계다. 요약하면 OmniDiff는 구조적·콘텐츠 인식 디프라는 방향성과 투명한 벤치마크가 장점이지만, 정확도 지표를 스스로 미완으로 표기하고 일부 통합이 아직 막혀 있다는 점을 감안해 도입 여부를 판단할 필요가 있다.