
Git 2.56 새 기능 분석 — git add --resolved와 머지 베이스 29배 단축
Git 2.56이 머지 충돌 해결 전용 스테이징 명령 git add --resolved를 추가했다. 머지 베이스 탐색은 리눅스 커널 기준 0.29초에서 0.01초로 줄었고, 경로 기반 리팩은 저장소 용량을 71% 덜어낸다. 실무에서 당장 체감되는 항목만 골라 짚었다.
머지 충돌을 겨우 다 풀었다. 이제 스테이징만 하면 되는데, 손이 먼저 git add . 를 친다. 그리고 git status 를 보는 순간 알게 된다 — 아직 정리 안 된 디버그 로그와 임시 주석까지 전부 딸려 들어갔다는 걸.
Git 2.56 은 정확히 그 순간을 위한 명령을 하나 만들었다. 104명이 넘는 기여자가 참여했고 그중 39명이 첫 기여자인 이번 릴리스에서, 실무자가 당장 체감할 변화는 생각보다 뚜렷하다.

git add --resolved — 충돌만 골라 담고, 마커가 남았으면 거부한다
새로 들어온 git add --resolved 는 이름 그대로 충돌을 해결한 파일만 스테이징한다. recipe.txt 의 충돌을 푸는 동안 notes.txt 에 무관한 로컬 수정이 남아 있어도 그건 건드리지 않는다.
진짜 쓸모는 다른 데 있다. 이 명령은 스테이징에 앞서 병합되지 않은 일반 파일을 훑어 충돌 마커가 남아 있는지 먼저 검사한다.
$ git add --resolved
fatal: the following paths still have conflict markers:
recipe.txt
마커가 발견되면 해당 경로를 일러주고 인덱스는 손대지 않은 채 멈춘다. <<<<<<< HEAD 가 박힌 파일이 그대로 커밋돼 CI가 터지는 그 사고를, 명령 단계에서 끊어준다는 뜻이다.
git add -u 나 git add -A 보다 훨씬 좁게 동작한다. 넓게 쓸어 담는 명령이 이미 있는데 굳이 좁은 걸 하나 더 만든 이유가 여기 있다. 편의 기능이 아니라 안전장치다.
머지 베이스 탐색, 0.29초에서 0.01초로
병합, diff, PR 비교. 전부 두 커밋의 공통 조상(머지 베이스)을 찾는 데서 시작한다. 평소엔 의식조차 하지 않지만 히스토리가 길어지면 이 탐색이 조용히 비용을 먹는다.
기존 Git 은 머지 베이스를 다 찾고도 히스토리를 계속 걸어 내려갔다. 더 나올 게 없다는 걸 확신할 방법이 없었기 때문이다.
2.56 은 각 진영이 독점적으로 칠한 커밋을 따로 세어 둔다. 한쪽의 독점 큐가 비는 순간 새로운 만남 지점은 더 이상 생길 수 없고, 그러면 거기서 순회를 멈춘다. 물론 머지 베이스는 빠짐없이 반환하면서.
| 사례 | 이전 | 2.56 |
|---|---|---|
| 어느 모노레포 순회 | 0.68초 | 0.01초 |
리눅스 커널 merge-base --all v4.8 v4.9 | 167,441 스텝 / 0.29초 | 3,887 스텝 / 0.01초 |
순회 스텝이 43분의 1로 줄었다. 병합이 촘촘하게 얽힌 히스토리일수록 이득이 커진다.
서버를 위한 경로 기반 리팩 — 용량 71% 감소

경로 기반(path-walk) 리팩은 객체를 트리 안의 위치를 따라 방문한다. 기존의 이름 해시 그룹핑보다 나은 델타 관계를 찾아낸다는 게 핵심이다.
Fluent UI 저장소 벤치마크가 이걸 잘 보여준다. 비트맵 리팩이 558.5MB 를 만드는 동안 경로 기반 리팩은 164.4MB 로 끝냈다. 약 71% 작다.
문제는 그동안 이 방식을 서버가 쓸 수 없었다는 점이었다.
2.56 이 두 가지 제약을 걷어냈다. 경로 기반 리팩이 새 비트맵을 위한 커밋을 선택할 수 있게 됐고, 델타 아일랜드가 요구하는 부기 작업도 수행한다. 대형 저장소 호스트가 빠른 비트맵 서빙과 델타 아일랜드 제약을 포기하지 않고도 용량 절감을 저울질할 수 있게 된 셈이다.
나머지 변화들
git history drop— 선택한 커밋을 들어내고 후손 커밋을 그 부모 위에 다시 얹는다. 무관한 로컬 변경은 보존된다. 아직 실험적이며 머지 커밋이 섞인 히스토리에서는 동작하지 않는다.git refs— 저수준 레퍼런스 관리를 한데 모았다. 생성·갱신·삭제·이름변경을 지원하고 compare-and-swap 보호를 걸 수 있다.git branch --delete-merged— 업스트림에 반영된 로컬 토픽 브랜치를 한꺼번에 정리한다. 패턴 매칭과 dry-run 지원.git bisect run --reset-when-found— 범인 커밋을 찾은 뒤 원래 커밋으로 돌아갈지 찾은 자리에 머물지 고를 수 있다.git replay --linearize— 머지 토폴로지를 평탄화한다. 워킹 트리를 쓰지 않으면서 rebase 와 같은 결과를 만든다.- 부분 클론 —
git repack -a --filter=blob:limit=1m --drop-filtered로 회수 가능한 큰 블롭을 덜어낼 수 있다. git log --follow— 부모마다 경로를 따로 기록해 비선형 히스토리에서도 추적이 덜 끊긴다.
오타 교정도 들어왔다. git push origin/main 처럼 슬래시를 잘못 넣으면 Git 이 git push origin main 을 제안한다. 사소해 보이지만 하루에 몇 번씩 당하는 실수다.
내부 성능 개선도 여럿이다. reftable 쓰기가 불필요한 재로드를 피하고, 팩파일 로딩의 O(N²) 회귀가 제거됐으며, 추적되지 않은 파일 수집이 안정적으로 O(n log n) 이 됐다. 크로미움 체크아웃에서는 영향받던 git diff 하나가 8분에서 0.07초로 떨어졌다.
그래서 어디부터 체감될까
여기서부터는 릴리스 노트에 없는 이야기다.
국내 팀 기준으로 가장 먼저 효과가 나는 건 새 명령이 아니라 머지 베이스 최적화라고 본다. git add --resolved 나 git refs 는 사람이 새 명령을 익혀야 하지만, 머지 베이스는 업그레이드만 하면 자동으로 적용된다. PR 화면을 열 때마다 서버가 공통 조상을 계산한다는 걸 떠올려 보면, 이 개선은 CI 큐와 리뷰 대기 시간에 조용히 반영된다. 모노레포를 쓰거나 릴리스 브랜치를 오래 유지하는 팀일수록 이득이 크다.
반대로 git history drop 은 당분간 실무에 들이지 않는 편이 맞다. 머지 커밋이 있는 히스토리에서 못 돈다는 제약이 생각보다 치명적이다. 국내 다수 팀이 PR 을 머지 커밋으로 남기는 방식을 쓰기 때문에, 정작 "이 커밋만 들어내고 싶다"는 상황의 대부분이 적용 대상에서 빠진다. squash merge 를 표준으로 쓰는 팀이라면 얘기가 달라진다.
경로 기반 리팩의 71% 는 숫자만 보면 파격적이지만, 이건 저장소를 호스팅하는 쪽의 이야기다. GitHub·GitLab 을 쓰는 대부분의 팀에게는 당장 손에 잡히는 변화가 아니다. 사내에 Git 서버를 직접 굴리거나(Gitea, GitLab self-hosted) 게임·미디어처럼 바이너리 에셋이 큰 저장소를 다루는 팀이라면 스토리지 청구서가 실제로 달라질 수 있는 항목이다. 다만 Fluent UI 라는 특정 저장소의 벤치마크라는 점은 감안해야 한다. 저장소 구조에 따라 절감폭은 크게 흔들린다.
git branch --delete-merged 는 화려하진 않아도 체감이 빠른 쪽이다. 그동안 많은 팀이 셸 별칭이나 자체 스크립트로 각자 해결하던 일을 Git 이 표준으로 흡수했다. dry-run 이 함께 붙어 있다는 점이 중요하다. 브랜치 일괄 삭제는 한 번 잘못 돌리면 복구가 성가시다.
마무리
Git 2.56 의 성격은 분명하다. 새 워크플로를 강요하는 릴리스가 아니라 이미 하던 일을 덜 위험하고 덜 느리게 만드는 릴리스다. 충돌 해결에는 안전장치가 붙었고, 공통 조상 탐색은 수십 배 빨라졌고, 저장소를 굴리는 쪽에는 용량 카드가 한 장 생겼다.
업그레이드는 명령 한 줄이다. 익숙한 실수 하나를 줄여주는 것만으로도 값은 한다.
여러분은 어느 쪽인가요? 충돌을 풀고 나서 git add . 를 습관적으로 치는 쪽인지, 파일을 하나씩 확인하고 넣는 쪽인지 궁금합니다. git history drop 처럼 히스토리를 직접 고치는 기능은 팀 정책으로 아예 막아둔 곳도 많던데, 여러분 팀은 어떻게 하고 계신가요?
📎 출처: 원문 보기
- github.bloghttps://github.blog/open-source/git/highlights-from-git-2-56/
댓글 0
댓글을 불러오는 중…






