Inżynieria

CHANGELOG.md: co w nim jest i jak trzymać go aktualnym

5 min czytania

CHANGELOG.md to plik Markdown w katalogu głównym repozytorium, który dla każdej wydanej wersji wylicza, co się zmieniło, słowami, na które użytkownik projektu może zareagować. Plik czytają ludzie decydujący, czy aktualizować, ludzie debugujący po aktualizacji, oraz rejestry pakietów i narzędzia wydawnicze, które renderują go na stronie projektu. Format, którego trzyma się większość projektów, to ten opisany na keepachangelog.com: najnowsza wersja na górze, sekcja Unreleased nad nią, a wpisy pogrupowane pod Added, Changed, Deprecated, Removed, Fixed i Security.

SekcjaCo do niej trafiaPrzykładowa linia
UnreleasedZmiany scalone, ale jeszcze nie w żadnej wersji- Eksport jest teraz strumieniowany, więc pliki powyżej 100 MB nie przekraczają już limitu czasu.
AddedNowa możliwość, do której użytkownik ma dostęp- Flaga \—dry-run` w `deploy` wypisuje plan bez jego stosowania.`
ChangedIstniejące zachowanie, które działa teraz inaczej- Domyślny limit czasu podniesiony z 30 s do 60 s.
DeprecatedNadal działa, zaplanowane do usunięcia- \legacyAuth()` zostanie usunięte w 3.0; używajcie `auth()`.`
RemovedZniknęło w tej wersji- Porzucono wsparcie dla Node 16.
FixedBłąd, na który użytkownik mógł trafić- Wyszukiwanie nie zawodzi już dla zapytań zawierających myślnik.
SecurityPoprawki, dla których czytelnik powinien zaktualizować dziś- Naprawiono path traversal w handlerze plików statycznych (CVE w toku).

Czym jest plik CHANGELOG.md?

To czytelna dla człowieka historia projektu, wersja po wersji, trzymana obok kodu, żeby wysyłała się razem z nim. Od git log różni się odbiorcą i doborem: git log rejestruje każdy commit dla ludzi, którzy je napisali, a changelog rejestruje zmiany, które zauważy użytkownik, napisane dla osoby, która ich nie napisała. Commit, który zmienia nazwę wewnętrznej zmiennej, nie ma linii w changelogu. Commit, który zmienia domyślny limit czasu, ma ją, nawet jeśli diff to jeden znak.

Plik leży w katalogu głównym repozytorium pod dokładnie tą nazwą, bo narzędzia szukają go właśnie tam. GitHub linkuje go ze strony repozytorium, npm i PyPI renderują go, gdy jest dołączony do pakietu, a narzędzia wydawnicze takie jak release-please i semantic-release czytają go i piszą w miejscu. Małe changelog.md i CHANGES.md też działają dla ludzi, ale część narzędzi szuka tylko kanonicznej nazwy.

Jak wygląda kompletny CHANGELOG.md?

Krótki, poprawny przykład jest wart więcej niż długi opis. Ten trzyma się układu Keep a Changelog 1.1.0 i wersjonowania semantycznego dla numerów.

# Changelog

Wszystkie istotne zmiany w tym projekcie są wymienione tutaj.
Format: Keep a Changelog. Wersje: Semantic Versioning.

## [Unreleased]

### Added
- Flaga `--dry-run` w `deploy` wypisuje plan bez jego stosowania.

## [2.3.1] - 2026-10-01

### Fixed
- Wyszukiwanie nie zawodzi już dla zapytań zawierających myślnik.
  Zepsute od 2.3.0.

### Security
- Naprawiono path traversal w handlerze plików statycznych.
  Zaktualizujcie dziś, jeśli serwujecie pliki wgrane przez
  użytkowników.

## [2.3.0] - 2026-09-18

### Added
- Eksport strumieniowany. Pliki powyżej 100 MB nie przekraczają
  już limitu czasu.

### Deprecated
- `legacyAuth()` nadal działa, ale zostanie usunięte w 3.0.
  Używajcie `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

Cztery szczegóły niosą większość wartości. Każda wersja ma datę w formacie ISO, więc czytelnik może ją zestawić z tym, kiedy zaczął się jego problem. Każdy nagłówek wersji jest linkiem do widoku porównania, więc pełny diff jest o jedno kliknięcie. Poprawka mówi, która wersja to zepsuła. A sekcja Security stoi osobno, więc ktoś skanujący plik z pytaniem “czy muszę aktualizować teraz” znajduje ją w kilka sekund.

Jak trzymać CHANGELOG.md aktualnym?

Piszcie linię w tym samym pull requeście co zmiana, pod Unreleased, i przenoście sekcję pod nagłówek wersji przy wydaniu. To cała metoda. Plik się dezaktualizuje, gdy linię pisze później ktoś inny, przy wydaniu, z listy komunikatów commitów, których nie jest autorem.

Dwie rzeczy utrwalają nawyk. Pierwsza to sprawdzenie w CI, które odrzuca pull request dotykający src/ bez dotknięcia changelogu, z etykietą pozwalającą je pominąć dla zmian bez widocznego dla użytkownika efektu; sprawdzanie changelogu jako GitHub Action pokazuje wersję na czterdzieści linii. Druga to krok wydania, który jednym poleceniem zmienia Unreleased na wersję i datę, żeby nikt nie musiał pamiętać, by zrobić to ręcznie. Kto pisze changelog opisuje, jak zespoły rozstrzygają, czyim zadaniem jest linia.

Czy changelog powinien być generowany z commitów?

Generowanie daje kompletny szkic; nie daje changelogu. Narzędzia zbudowane na conventional commits i automatyzacja wydań taka jak release-please czytają prefiksy feat:, fix: i BREAKING CHANGE: i produkują pogrupowaną listę z linkiem do każdego pull requesta. Lista jest tylko tak dobra, jak tematy commitów, a tematy commitów opisują kod.

Działający środek to generować, potem redagować. Niech narzędzie utworzy sekcję Unreleased z commitów, a pull request wydania przepisze linie, które użytkownik przeczyta: objaw zamiast nazwy funkcji, ustawienie, które się przeniosło, zamiast pliku, który się zmienił. Od conventional commits do changelogu przechodzi przez pipeline, a działający w przeglądarce generator changelogu wystarczy, by dostać szkic z wklejonego git log bez instalowania czegokolwiek.

Co nie powinno trafiać do CHANGELOG.md?

Wewnętrzne refaktory, podbicia zależności bez zmiany zachowania, commity tylko z testami, konfiguracja CI i zmiany formatowania. Ich miejsce jest w historii gita, gdzie każdy, kto ich potrzebuje, je znajdzie. Włączanie ich zakopuje linie, które mają znaczenie, i uczy czytelników pomijać plik.

Druga rzecz do pominięcia to marketingowa wersja zmiany. “Błyskawiczne eksporty” nie mówi czytelnikowi niczego, co mógłby sprawdzić. “Eksport jest teraz strumieniowany; pliki powyżej 100 MB nie przekraczają już limitu czasu” mówi. Plik to dokument referencyjny i jego ton powinien do tego pasować: krótkie linie, konkretne rzeczowniki, wersja lub data przy wszystkim. Keep a Changelog w praktyce omawia części specyfikacji, które zespoły najczęściej gubią, a formaty pliku changelogu opisuje, kiedy źródło JSON lub YAML obok pliku Markdown jest tego warte.

Czy produkt ze stroną changelogu nadal potrzebuje pliku?

Biblioteka tak, bo plik to to, co renderują rejestry pakietów i co deweloper czyta offline. Produkt SaaS bez instalowalnego artefaktu może obejść się samą stroną, bo jego użytkownicy nigdy nie widzą repozytorium. Wiele zespołów prowadzi oba: plik jako zapis inżynierski i publiczną stronę changelogu, pisaną z niego dla szerszej publiczności, ze szczegółami podzielonymi tak, jak opisuje changelog vs release notes. Jeśli strona jest zasilana z pliku, trzymajcie plik jako źródło prawdy i generujcie stronę, żeby było jedno miejsce do edycji.

FAQ

Jaka jest różnica między CHANGELOG.md a release notes? Changelog to kompletny, bieżący zapis każdej istotnej zmiany, trzymany w repozytorium. Release notes to wiadomość o jednym wydaniu, często krótsza i przepisana dla szerszej publiczności. Wiele projektów publikuje sekcję changelogu dla wersji jako jej release notes.

Gdzie powinien leżeć CHANGELOG.md? W katalogu głównym repozytorium, pod dokładnie tą nazwą, żeby GitHub, rejestry pakietów i narzędzia wydawnicze go znalazły. Monorepo trzyma jeden na pakiet, obok manifestu każdego pakietu.

Czy generować CHANGELOG.md z commitów gita? Generujcie szkic, potem redagujcie linie, które użytkownik przeczyta. Komunikaty commitów opisują zmianę w kodzie; changelog opisuje to, co zauważa użytkownik. Narzędzia takie jak conventional-changelog i release-please dają dobry punkt wyjścia.

Czy każdy commit potrzebuje wpisu w changelogu? Nie. Tylko zmiany, które użytkownik projektu mógłby zauważyć: nowa możliwość, zmienione zachowanie, deprecjacje, usunięcia, poprawki i łatki bezpieczeństwa. Refaktory, zmiany w testach i edycje CI zostają w historii gita.


Twierdzenia techniczne w tym artykule nie zostały niezależnie zweryfikowane. Jeśli coś się nie zgadza, daj nam znać, a poprawimy to.

Powiązane w changeloop: Generator changeloga, Przykłady changeloga

changeloop
Zespół, który tworzy changelog zamykający pętlę. Użytkownicy o coś proszą, Twój zespół to dostarcza, proszący się dowiaduje.