엔지니어링

CHANGELOG.md에는 무엇을 쓰고 어떻게 최신으로 유지하는가

4분 분량

CHANGELOG.md는 저장소 루트에 있는 Markdown 파일로, 릴리스된 버전마다 무엇이 바뀌었는지를 프로젝트 사용자가 행동할 수 있는 말로 나열한다. 업그레이드할지 결정하는 사람, 업그레이드 뒤에 디버깅하는 사람, 그리고 프로젝트 페이지에 이 파일을 렌더링하는 패키지 레지스트리와 릴리스 도구가 이 파일을 읽는다. 대부분의 프로젝트가 따르는 형식은 keepachangelog.com에 설명된 것이다. 최신 버전이 맨 위에, 그 위에 Unreleased 절이 있고, 항목은 Added, Changed, Deprecated, Removed, Fixed, Security 아래로 묶인다.

절들어가는 것예시 줄
Unreleased병합되었지만 아직 버전에 들어가지 않은 변경- Export now streams, so files over 100 MB no longer time out.
Added사용자가 쓸 수 있는 새 기능- \—dry-run` flag on `deploy` prints the plan without applying it.`
Changed이제 다르게 동작하는 기존 동작- Default timeout raised from 30 s to 60 s.
Deprecated아직 동작하지만 제거가 예정된 것- \legacyAuth()` will be removed in 3.0; use `auth()`.`
Removed이 버전에서 사라진 것- Dropped Node 16 support.
Fixed사용자가 겪었을 수 있는 버그- Search no longer fails on queries containing a hyphen.
Security독자가 오늘 업그레이드해야 하는 수정- Fixed a path traversal in the static file handler (CVE pending).

CHANGELOG.md 파일이란 무엇인가

프로젝트의 사람이 읽을 수 있는 이력을 버전 단위로 적은 것이며, 코드 옆에 두어 코드와 함께 배포된다. git log와는 독자와 선별 기준이 다르다. git 로그는 모든 커밋을 그것을 쓴 사람들을 위해 기록하고, 체인지로그는 사용자가 알아챌 변경을 그것을 쓰지 않은 사람을 위해 기록한다. 내부 변수 이름을 바꾼 커밋에는 체인지로그 줄이 없다. 기본 타임아웃을 바꾼 커밋에는, diff가 글자 하나였더라도 줄이 있다.

파일이 정확히 그 이름으로 저장소 루트에 있는 이유는 도구가 그곳에서 찾기 때문이다. GitHub는 저장소 페이지에서 링크하고, npm과 PyPI는 패키지에 포함되면 렌더링하며, release-please나 semantic-release 같은 릴리스 도구는 그 자리에서 읽고 쓴다. 소문자 changelog.md나 CHANGES.md도 사람에게는 통하지만, 일부 도구는 정식 이름만 찾는다.

완전한 CHANGELOG.md는 어떤 모습인가

짧고 올바른 예시 하나가 긴 설명보다 낫다. 이 예시는 Keep a Changelog 1.1.0 배치를 따르고, 번호에는 시맨틱 버저닝을 쓴다.

# Changelog

All notable changes to this project are listed here.
Format: Keep a Changelog. Versions: Semantic Versioning.

## [Unreleased]

### Added
- `--dry-run` flag on `deploy` prints the plan without applying it.

## [2.3.1] - 2026-10-01

### Fixed
- Search no longer fails on queries containing a hyphen. Broken
  since 2.3.0.

### Security
- Fixed a path traversal in the static file handler. Upgrade today
  if you serve user-uploaded files.

## [2.3.0] - 2026-09-18

### Added
- Streaming export. Files over 100 MB no longer time out.

### Deprecated
- `legacyAuth()` still works but will be removed in 3.0.
  Use `auth()`.

[Unreleased]: https://github.com/acme/tool/compare/v2.3.1...HEAD
[2.3.1]: https://github.com/acme/tool/compare/v2.3.0...v2.3.1
[2.3.0]: https://github.com/acme/tool/compare/v2.2.0...v2.3.0

가치의 대부분은 네 가지 세부에서 나온다. 모든 버전에 ISO 형식의 날짜가 있어서 독자가 자기 문제가 시작된 시점과 맞춰 볼 수 있다. 각 버전 제목은 비교 화면으로 가는 링크라서 전체 diff가 한 번의 클릭 거리에 있다. 수정 항목은 어느 버전이 고장 냈는지 말한다. 그리고 Security 절이 따로 있어서 “지금 업그레이드해야 하나”를 찾는 사람이 몇 초 안에 발견한다.

CHANGELOG.md는 어떻게 최신으로 유지하는가

변경과 같은 pull request에서 Unreleased 아래에 줄을 쓰고, 릴리스할 때 그 절을 버전 제목 아래로 옮긴다. 방법은 그게 전부다. 파일이 낡는 것은 나중에 다른 사람이, 릴리스 시점에, 자기가 쓰지 않은 커밋 메시지 목록을 보고 줄을 쓸 때다.

습관이 붙게 하는 것은 두 가지다. 첫째는 체인지로그를 건드리지 않고 src/를 건드린 pull request를 실패시키는 CI 검사이며, 사용자에게 보이는 효과가 없는 변경을 위한 건너뛰기 라벨을 둔다. GitHub Action으로 하는 체인지로그 검사가 40줄짜리 버전을 보여준다. 둘째는 Unreleased를 버전과 날짜로 바꾸는 일을 명령 하나로 끝내는 릴리스 단계이며, 그러면 누구도 손으로 하는 것을 기억할 필요가 없다. 체인지로그는 누가 쓰는가는 팀이 그 줄이 누구 일인지 어떻게 정하는지 다룬다.

체인지로그를 커밋에서 생성해야 하는가

생성은 완전한 초안을 주지만 체인지로그를 주지는 않는다. conventional commits 위에 만들어진 도구와 release-please 같은 릴리스 자동화는 feat:, fix:, BREAKING CHANGE: 접두사를 읽어 모든 pull request가 링크된 묶음 목록을 만든다. 그 목록은 커밋 제목만큼만 좋고, 커밋 제목은 코드를 설명한다.

현실적인 중간 지점은 생성한 뒤 편집하는 것이다. 도구가 커밋으로 Unreleased 절을 만들게 하고, 릴리스 pull request에서 사용자가 읽을 줄을 다시 쓴다. 함수 이름 대신 증상을, 바뀐 파일 대신 옮겨진 설정을. Conventional commits에서 체인지로그까지가 그 파이프라인을 차근차근 보여주고, 브라우저에서 돌아가는 체인지로그 생성기는 아무것도 설치하지 않고 붙여 넣은 git log에서 초안을 얻기에 충분하다.

CHANGELOG.md에 넣지 말아야 할 것은 무엇인가

내부 리팩터링, 동작 변화가 없는 의존성 올리기, 테스트만 바꾼 커밋, CI 설정, 포매팅 변경이다. 이것들은 git 이력에 속하고, 필요한 사람은 그곳에서 찾을 수 있다. 넣으면 중요한 줄이 묻히고, 독자는 파일을 건너뛰도록 훈련된다.

빼야 할 또 하나는 변경의 마케팅 버전이다. “눈부시게 빠른 내보내기”는 독자가 확인할 수 있는 것을 아무것도 말하지 않는다. “내보내기가 이제 스트리밍됨. 100MB가 넘는 파일이 더 이상 시간 초과되지 않음”은 말한다. 이 파일은 참조 문서이고, 어조도 거기에 맞아야 한다. 짧은 줄, 구체적인 명사, 모든 것에 버전이나 날짜. Keep a Changelog 실제 적용은 팀이 가장 자주 빠뜨리는 명세 부분을 다루고, 체인지로그 파일 형식은 Markdown 파일 옆의 JSON이나 YAML 소스가 언제 제값을 하는지 다룬다.

체인지로그 페이지가 있는 제품에도 파일이 필요한가

라이브러리는 필요하다. 패키지 레지스트리가 렌더링하고 개발자가 오프라인으로 읽는 것이 파일이기 때문이다. 설치할 산출물이 없는 SaaS 제품은 페이지만으로도 버틸 수 있다. 사용자가 저장소를 볼 일이 없기 때문이다. 많은 팀이 둘 다 운영한다. 파일은 엔지니어링 기록으로, 공개 체인지로그 페이지는 더 넓은 독자를 위해 파일로부터 쓰며, 세부 사항은 체인지로그 대 릴리스 노트가 설명하는 방식으로 나눈다. 페이지가 파일에서 공급된다면 파일을 진실의 원천으로 두고 페이지를 생성하라. 그래야 편집할 곳이 하나다.

FAQ

CHANGELOG.md와 릴리스 노트의 차이는 무엇인가? 체인지로그는 저장소에 보관되는, 모든 주목할 만한 변경의 완전하고 이어지는 기록이다. 릴리스 노트는 한 릴리스에 관한 메시지로, 대개 더 짧고 더 넓은 독자를 위해 다시 쓰인다. 많은 프로젝트가 한 버전의 체인지로그 절을 그대로 릴리스 노트로 발행한다.

CHANGELOG.md는 어디에 두어야 하는가? 저장소 루트에, 정확히 그 이름으로 둔다. GitHub, 패키지 레지스트리, 릴리스 도구가 그곳에서 찾기 때문이다. 모노레포는 패키지마다 하나씩, 각 패키지의 매니페스트 옆에 둔다.

CHANGELOG.md를 git 커밋에서 생성해야 하는가? 초안을 생성한 뒤 사용자가 읽을 줄을 편집하라. 커밋 메시지는 코드 변경을 설명하고, 체인지로그는 사용자가 알아채는 것을 설명한다. conventional-changelog나 release-please 같은 도구가 좋은 출발점을 만들어 준다.

모든 커밋에 체인지로그 항목이 필요한가? 아니다. 프로젝트 사용자가 알아챌 수 있는 변경만이다. 새 기능, 바뀐 동작, 비추천, 제거, 수정, 보안 패치. 리팩터링, 테스트 변경, CI 편집은 git 이력에 남긴다.


이 글의 기술적 내용은 독립적으로 검토되지 않았습니다. 잘못된 부분이 있으면 알려 주세요. 바로잡겠습니다.

changeloop 관련 페이지: changelog 생성기, changelog 예시

changeloop
루프를 닫는 changelog를 만드는 팀입니다. 사용자가 무언가를 요청하면 팀이 전달하고, 요청한 사람은 알게 됩니다.