Git 3.0이 SHA-256을 기본값으로 삼는다는 소식을 보면, 기존 저장소의 커밋 해시도 전부 바뀌는지부터 걱정할 수 있습니다. 우선 구분할 것은 새 저장소를 초기화할 때의 기본값과 이미 있는 저장소의 객체 형식입니다. Git 버전을 올리는 일과 과거 이력을 다른 형식으로 변환하는 일은 같지 않습니다.
Git 공식 BreakingChanges 문서는 새 저장소의 기본 해시를 sha1에서 sha256으로 바꾸는 계획을 설명합니다. 같은 문서는 생태계의 지원 준비를 중요한 조건으로 두며, 현재 SHA-1 객체 형식을 폐기할 계획은 없다고 밝힙니다. 따라서 ‘모든 기존 저장소를 곧바로 바꿔야 한다’는 안내로 읽으면 범위가 달라집니다.
이 문서는 Git 3.0의 출시일이 아직 정해지지 않았다고도 명시합니다. 따라서 여기서 다루는 것은 이미 모든 개발 환경에 적용된 변경이 아니라 다음 주요 버전의 전환 계획과 준비할 항목입니다. 새 기본값을 이야기할 때는 이 상태를 먼저 고정해야 합니다.
해시는 파일 이름보다 더 깊이 연결돼 있음
Git에서 객체 ID는 내용을 식별하는 주소 역할을 합니다. 파일 내용에 해당하는 blob뿐 아니라 파일 목록을 나타내는 tree, 부모 커밋과 tree 등을 가리키는 commit도 객체입니다. 커밋은 다른 객체를 참조하므로 한 지점의 변경이 연결된 식별자에 영향을 줄 수 있습니다. 공식 해시 전환 문서는 이 객체 구조와 형식 간 대응을 설명합니다.
그러므로 SHA-256 전환은 화면에서 해시 문자열을 조금 길게 보여 주는 수정만은 아닙니다. 객체를 저장하고 전송하는 도구가 형식을 이해해야 하며, 커밋 ID를 받아 처리하는 주변 자동화도 점검 대상이 됩니다. 해시를 데이터베이스의 고정 길이 필드에 넣거나 정확히 40자리라고 가정하는 코드가 있다면, 그런 가정이 어디에 퍼져 있는지 확인할 이유가 있습니다.
전체 객체 ID를 16진수로 표시하면 SHA-1은 40자리, SHA-256은 64자리입니다. 하지만 기존 40자리 문자열 뒤에 문자를 더 붙이는 변환은 아닙니다. 같은 파일 내용도 다른 해시 함수로 계산하면 다른 주소를 얻고, 그 주소를 담은 tree와 commit의 내용도 함께 달라집니다. 예를 들어 login.ts의 내용이 같아도, 새 형식에서 파일을 가리키는 ID가 바뀌면 그 ID를 포함하는 상위 객체도 새로 식별됩니다. 파일 내용과 커밋 식별자가 별개라는 뜻입니다.
단축 해시가 같은 길이로 표시된다고 저장소의 객체 형식도 같다고 판단해서는 안 됩니다. 사용자 화면에 보이는 일부 문자열과 내부 객체 식별자는 다른 층위입니다. 형식은 Git 명령으로 확인하는 편이 명확합니다.
기존 저장소와 새 저장소를 나누어 보기
서비스 팀이 오래 운영한 앱 저장소를 유지하면서 새 SDK 저장소를 만든다고 가정해 보겠습니다. 기존 앱 저장소는 그 저장소의 현재 객체 형식으로 계속 관리합니다. 새 SDK 저장소는 초기화할 때 선택한 형식과 기본값의 영향을 받습니다. 하나의 개발자 컴퓨터에서 두 경우가 동시에 생길 수 있습니다.
기존 저장소를 계속 쓰는 개발자와 새 저장소 템플릿을 관리하는 플랫폼 팀이 해야 할 일이 다른 이유입니다. 전자는 당장 이력을 재작성할 이유를 찾기보다 현재 형식과 사용 도구를 파악하면 됩니다. 후자는 새 저장소 생성 자동화와 첫 push·clone 경로까지 살펴봐야 합니다.
공식 계획에 생태계 준비라는 조건이 있다는 점도 중요합니다. Git 명령줄이 형식을 처리하더라도 IDE, GUI 클라이언트, 호스팅, 내부 서비스가 사용하는 Git 라이브러리까지 모두 같은 시점에 대응한다고 추정할 수 없습니다. 특정 서비스가 지원하는지는 해당 서비스의 실제 문서와 테스트로 확인해야 합니다.
보안 강화와 호환성 비용이 충돌하는 지점
Git 프로젝트는 알려진 SHA-1 공격에 대한 보호 장치가 있더라도 미래 공격과 하드웨어 발전을 고려해 더 강한 해시로 준비할 필요가 있다고 설명합니다. 이는 SHA-1 객체 형식의 즉각 폐기를 선언하는 것과 다른 판단입니다. 전환 계획의 근거
반면 Scott Chacon은 기본값 변경으로 생길 생태계 비용에 비해 실용적인 보안 이익이 충분한지 비판합니다. 그의 글은 의견 글이며, 기본값 전환을 비판한다는 이유로 ‘SHA-1에 문제가 없다’는 검증 결과가 되지는 않습니다. Hacker News 토론에서도 공격 가능성과 전환 비용을 놓고 반론이 이어집니다.
두 종류의 판단을 분리하면 논쟁을 읽기 쉽습니다. 하나는 어떤 공격을 막고 장기적으로 어떤 식별 체계를 유지할지입니다. 다른 하나는 호환성 비용을 언제, 누가, 어떤 순서로 부담할지입니다. 전환에 비용이 있다는 사실만으로 보안 가치가 없어지지 않고, 더 강한 해시라는 사실만으로 전환 절차가 저절로 준비되지도 않습니다.
일반 개발팀이 당장 결정해야 할 것은 이 논쟁의 승자를 고르는 일이 아닙니다. 자신의 전달 경로에서 어떤 구성 요소가 객체 형식을 해석하는지 파악하고, 지원하지 않는 구간이 있는지 확인하는 일입니다.
논쟁에서 혼동하기 쉬운 것이 ‘우연히 같은 해시가 나오는 일’과 ‘공격자가 같은 해시를 갖는 서로 다른 내용을 만들려는 일’입니다. SHA-1에 대한 공개 공격을 단순한 우연의 확률로 반박할 수는 없습니다. 반대로 충돌 공격이 존재한다는 말이 임의의 과거 커밋을 지금 원하는 내용으로 곧바로 바꿀 수 있다는 뜻도 아닙니다. 이미 정해진 내용과 같은 해시를 갖는 다른 내용을 찾는 것은 두 번째 역상 공격이라는 별도 문제입니다. Git의 공식 전환 문서는 두 공격에 대한 저항성 모두를 요구하며, 알려진 공격에 대한 보호와 장기 전환 필요성을 함께 설명합니다.
해시와 서명도 역할이 다릅니다. 해시는 내용을 식별하고 변경을 검출하는 데 쓰이고, 서명은 서명한 주체의 키와 데이터를 연결합니다. 누가 승인했는지 검증한다고 해서 그 서명이 참조하는 객체의 식별 문제까지 사라지는 것은 아닙니다. 그렇다고 더 강한 해시만 쓰면 코드 리뷰나 서명 확인이 필요 없어지는 것도 아닙니다. 보안 판단과 배포 절차를 함께 유지해야 하는 이유입니다.
현재 형식을 확인하는 읽기 전용 명령
저장소 안에서 다음 명령으로 Git 버전과 저장 객체 형식을 확인할 수 있습니다. Windows PowerShell·macOS·Linux 공통 Git 명령이며, 저장소를 변경하지 않습니다. 명령의 옵션은 git-rev-parse 공식 문서의 --show-object-format 설명을 기준으로 합니다.
git --version
git rev-parse --show-object-format=storage
두 번째 명령이 sha1을 출력하면 그 저장소의 저장 객체 형식이 SHA-1이라는 뜻입니다. sha256이면 SHA-256 형식입니다. 이는 해당 저장소를 사용하는 원격 서비스나 모든 보조 도구가 지원된다는 확인까지 대신하지는 않습니다.
저장소 밖에서 실행하면 저장소를 찾지 못했다는 오류가 날 수 있습니다. 옵션을 인식하지 못하는 Git 버전이라면 설치된 버전의 문서를 확인해야 합니다. 이때 결과를 얻으려고 설정 파일의 형식 값을 수동으로 바꾸면 안 됩니다. 확인 명령의 실패와 저장소 변환은 전혀 다른 작업입니다.
새 저장소 기본값 설정의 출처도 읽어 볼 수 있습니다. 다음 역시 세 운영체제 공통 명령입니다.
git config --show-origin --get init.defaultObjectFormat
값이 없으면 출력 없이 종료될 수 있습니다. 그 자체가 SHA-256을 사용한다는 뜻은 아닙니다. 실제 초기화에서는 명령줄 옵션이나 환경 변수도 영향을 줄 수 있으므로 최종 생성 결과를 확인해야 합니다. git-init의 설정 우선순위
현재 저장소의 형식과 앞으로 만들 저장소의 기본값은 서로 다른 질문입니다. init.defaultObjectFormat을 바꿔도 지금 열어 둔 SHA-1 저장소가 자동으로 SHA-256으로 변환되지는 않습니다. 팀에서 진단 기록을 공유할 때는 Git 버전, 해당 저장소의 저장 형식, 새 저장소 생성 설정을 각각 적어야 원인을 좁힐 수 있습니다.
호환성 확인은 별도의 빈 저장소에서
공식 git-init 문서는 지원되는 빌드에서 --object-format=sha256을 지정할 수 있다고 안내합니다. 동시에 SHA-1 저장소와 SHA-256 저장소 사이의 상호운용 제약도 명시합니다. 형식 간 매핑을 설명하는 설계 문서가 있다고 해서 모든 상호운용 기능이 이미 사용 가능하다고 해석해서는 안 됩니다. git-init 객체 형식 옵션
다음은 실험용 새 디렉터리를 만드는 문서 기반 예시입니다. 중요한 프로젝트 밖에서 아직 존재하지 않는 디렉터리 이름을 선택합니다. Windows PowerShell·macOS·Linux에서 같은 Git 명령을 사용할 수 있으며, 기존 저장소에 적용하는 변환 명령이 아닙니다.
git init --object-format=sha256 git-sha256-sandbox
git -C git-sha256-sandbox rev-parse --show-object-format=storage
지원되는 환경이라면 두 번째 명령에서 sha256이 나오는 것을 기대할 수 있습니다. 아직 원격 호스팅 지원이나 CI 호환성을 검증한 것은 아닙니다. 이 작은 확인 다음에 실제 사용하는 도구의 연결 경로를 별도 테스트 환경에서 점검해야 합니다.
- 로컬 생성과 읽기CLI와 IDE가 같은 실험용 저장소를 열고 이력을 읽는지 확인합니다.
- 원격 전달호스팅의 공식 지원 상태를 먼저 확인한 뒤 테스트 저장소의 push와 clone을 검증합니다.
- CI와 연동체크아웃, 캐시 키, 커밋 ID 저장, 릴리스 자동화가 객체 ID 길이를 가정하는지 살펴봅니다.
이 경로에서 실패했다면 무조건 해시 알고리즘 자체의 문제로 결론내리기보다, 어느 도구가 어떤 오류를 냈는지 기록해야 합니다. 예를 들어 CLI는 읽는데 내부 분석 서비스만 실패한다면 그 서비스의 라이브러리와 입력 검증이 조사 대상입니다.
새 SDK의 릴리스 자동화가 ‘커밋 ID는 정확히 40자리’라는 입력 검사를 한다고 가정해 보겠습니다. 64자리 ID가 들어오면 저장소 생성은 성공했어도 릴리스 기록 저장에서 실패할 수 있습니다. 이때 ID를 40자리로 잘라 넣으면 형식 지원을 해결한 것이 아니라 다른 문자열로 바꾼 셈입니다. 입력 검증, 저장 필드, 그 ID로 커밋을 조회하는 코드까지 같은 형식을 이해해야 합니다. 화면용 단축 표시는 그 뒤의 별도 선택입니다.
GitHub의 SHA-256 지원 논의에도 로컬 지원과 원격 push·가져오기 지원의 차이를 묻는 사례가 쌓여 있습니다. 개별 실패 보고를 서비스 전체의 영구적인 미지원 판정으로 쓰지는 않되, 로컬에서 만들어졌다는 이유만으로 전달 경로가 완성된 것은 아니다라는 점검 질문은 가져올 수 있습니다.
연동 도구 때문에 새 저장소를 당분간 SHA-1로 만들어야 한다면, git init --object-format=sha1로 형식을 명시하는 선택이 공식 문서에 있습니다. 이것은 새 저장소 생성의 호환성 선택이며 이미 만든 저장소를 되돌리는 명령이 아닙니다. 기존 이력 변환이나 호스팅 이전은 별도의 작업으로 계획해야 합니다.
지금 바꿀 것은 이력보다 전환 준비
기존 저장소를 사용하는 팀이라면 객체 형식을 확인하고, 커밋 ID를 처리하는 내부 코드의 가정을 점검하는 데서 시작할 수 있습니다. 새 저장소를 대량으로 만드는 팀은 템플릿·초기화 스크립트와 호스팅·CI 조합을 함께 검증해야 합니다. 두 팀의 우선순위가 같을 필요는 없습니다.
| 구분 | 역할 | 설명 | 예시 |
|---|---|---|---|
| 기존 서비스 팀 | 현재 형식과 연동 파악 | 업그레이드만으로 이력을 재작성한다고 가정하지 않습니다. | 객체 형식 확인과 고정 길이 검사 점검 |
| 새 저장소 관리자 | 생성 경로 검증 | 선택한 객체 형식이 원격과 CI까지 전달되는지 봅니다. | 분리된 테스트 저장소에서 연결 확인 |
| 도구 개발자 | 형식 가정 제거 | 입력 검증·저장 공간·라이브러리 지원을 점검합니다. | 40자리 해시만 허용하는 코드 조사 |
Git 3.0의 SHA-256 계획이 기존 저장소와 무관하다는 뜻은 아닙니다. 함께 사용하는 도구 생태계가 변하면 운영에도 영향이 옵니다. 다만 첫 행동은 오래된 이력을 서둘러 바꾸는 일이 아니라, 새 기본값이 들어올 때 자신의 생성·전달·검증 경로가 준비됐는지 확인하는 일입니다.
대표 이미지의 Git 로고: Git Logo by Jason Long, CC BY 3.0. 원형을 유지해 배치했습니다.
VIEW—