Inżynieria

Semantic versioning a twój changelog

5 min czytania

Semantic versioning mówi wywołującej, jak bardzo może ją zaboleć wydanie, zanim przeczyta jeden wpis z changeloga. Przejście z 2.4.1 do 2.5.0 mówi: nowa zdolność, nic się nie psuje. Przejście z 2.5.0 do 3.0.0 mówi: przeczytaj ten wpis przed aktualizacją. Changelog i numer wersji mają twierdzić to samo w dwóch formatach, i większość tarć między nimi pojawia się właśnie wtedy, gdy się nie zgadzają, co zdarza się częściej, niż sugerowałaby specyfikacja.

Co naprawdę obiecuje każda cyfra w wersji?

Semantic versioning definiuje trzy cyfry, MAJOR.MINOR.PATCH, każda z surową regułą co ją wyzwala. Skok MAJOR oznacza zmianę niekompatybilną: coś, co poprawna, istniejąca integracja mogłaby zauważyć i przez co musiałaby się zmienić. Skok MINOR oznacza nową, wstecznie kompatybilną funkcjonalność: nic istniejącego się nie psuje, coś nowego jest dostępne. Skok PATCH oznacza wstecznie kompatybilną poprawkę: zachowanie zbliża się do udokumentowanego, i nikt, kto celowo polegał na starym zachowaniu, nie powinien niczego zauważyć.

SkokZnaczenieWpis powinien brzmieć jak
MAJOR (1.x.x -> 2.0.0)Zmiana niekompatybilna“Wymaga działania przed aktualizacją”
MINOR (1.2.x -> 1.3.0)Nowa, kompatybilna zdolność“Dostępne od teraz, nic innego się nie zmienia”
PATCH (1.2.3 -> 1.2.4)Kompatybilna poprawka“Teraz zachowuje się zgodnie z dokumentacją”

Tabela to też test wsteczny: jeśli wpis nie czyta się jak swój wiersz, albo numer wersji jest błędny, albo wpis niedosprzedaje lub przesprzedaje to, co naprawdę się stało.

Co liczy się jako niekompatybilne do celów wersjonowania?

Ten sam test, który decyduje, czy coś należy do changeloga API: czy poprawna wywołująca, napisana przeciw staremu zachowaniu i niedotknięta od tamtej pory, mogłaby zachować się inaczej z powodu tej zmiany. Czym jest zmiana niekompatybilna, i jak ją wydać opisuje decyzję w całości, wraz z przypadkami, które wyglądają na niekompatybilne, a nie są, i tymi, które wyglądają na małe, a nie są. Krótko dla celów wersjonowania: jeśli odpowiedź brzmi tak, skok jest MAJOR bez względu na to, ile kodu zmiana naprawdę dotknęła wewnętrznie. Numery wersji śledzą konsekwencję dla wywołującej, nie wysiłek zespołu.

Jak wpis w changelogu powinien odpowiadać skokowi wersji?

Jeden wpis, jedna kategoria skoku, podana od razu. Wzór z tabeli kontynuuje się bezpośrednio: wpis niekompatybilny stoi pod wersją, która go wprowadziła, sformułowany najpierw jako ostrzeżenie, potem jako opis. Wpis addytywny stoi pod swoją wersją MINOR, sformułowany jako dostępność. Poprawka stoi pod swoją wersją PATCH, sformułowana jako korekta. Mieszanie kategorii w jednym wpisie, jak wplatanie zmiany niekompatybilnej w ten sam akapit co niezwiązana poprawka, to sposób, w jaki czytelniczka pomija właśnie tę jedną rzecz, która naprawdę się liczyła.

## 3.0.0 (2026-09-07)

### Changed
- **BREAKING:** `GET /reports` zwraca teraz kwoty jako liczby
  całkowite w najmniejszej jednostce waluty (grosze) zamiast ułamków.
  Zaktualizuj kod czytający `amount` bezpośrednio.

## 2.9.0 (2026-09-01)

### Added
- Raporty można teraz filtrować według `status`.

## 2.8.4 (2026-08-28)

### Fixed
- `GET /reports?status=` zwracał pustą stronę zamiast 400 dla
  nieznanego statusu.

Czytane od góry do dołu, numer wersji i etykieta sekcji mówią to samo dwa razy, i o to właśnie chodzi: czytelniczka, która przegląda tylko nagłówki, dostaje poprawną ocenę ryzyka, zanim otworzy jedną linię.

Czy zasada zmiany niekompatybilnej działa tak samo przed 1.0.0?

Nie, i stąd bierze się większość zamieszania wokół “czy to naprawdę było niekompatybilne”. SemVer wprost mówi, że główna wersja zero, 0.y.z, jest dla początkowego rozwoju: wszystko może się zmienić w dowolnym momencie, a publiczne API nie powinno być uznawane za stabilne. Skok z 0.4.0 do 0.5.0 może nieść zmianę niekompatybilną bez łamania specyfikacji, bo gwarancja głównej wersji zaczyna obowiązywać dopiero, gdy projekt wyda 1.0.0. Wpis w changelogu wciąż jest winien czytelniczkom tę samą uczciwość co do tego, co się zepsuło; zmienia się tylko to, że sam numer wersji nie jest sygnałem, na którym można polegać przed nadejściem 1.0.0.

A jeśli twój produkt nie wydaje dyskretnych wersji?

Większość produktów SaaS wdraża się w sposób ciągły i nigdy nie pokazuje wywołującej numeru wersji, co nie eliminuje potrzeby tej dyscypliny, tylko cyfrę, która normalnie by ją niosła. Wpis w changelogu musi wykonać całą pracę sam: jasno powiedzieć, czy zmiana jest niekompatybilna, addytywna, czy jest poprawką, tymi samymi trzema słowami, których używa semantic versioning, nawet bez pola wersji, do którego można je przypiąć. Niektóre zespoły utrzymują czysto wewnętrzną wersję tylko po to, żeby zakotwiczyć wpisy changeloga w czymś, do czego można linkować, nigdy nie pokazując jej bezpośrednio wywołującej.

Jak dotyczy to konkretnie changeloga API?

Ściślej niż niemal wszędzie indziej, bo wywołujące API to kod, nie ludzie, którzy mogą wzruszyć ramionami na nieoczekiwaną zmianę. Changelog API: co publikować i kto go czyta opisuje pełną formę tego dokumentu; dyscyplina wersjonowania tutaj jest tym, co utrzymuje uczciwość jego sekcji breaking i addytywnych. API, które oferuje kilka wersji jednocześnie, jak v1 i v2 serwowane równolegle podczas okna migracji, faktycznie stosuje semantic versioning na skali całego interfejsu zamiast jednego pakietu, i to samo trzysłowowe słownictwo nadal dotyczy każdego wpisu.

Co Keep a Changelog mówi o wersjonowaniu?

Łączy się bezpośrednio z nazwy z semantic versioning i zaleca to samo słownictwo kategorii, którego używa ten artykuł: Added, Changed, Deprecated, Removed, Fixed, Security. Keep a Changelog, w praktyce przechodzi przez to, jak przyjąć tę specyfikację, wraz z miejscami, gdzie zespoły zwykle od niej odbiegają. Nakładanie się nie jest przypadkiem: obie specyfikacje próbują rozwiązać ten sam problem z przeciwnych stron, jedna standaryzuje numer wersji, druga wpis, który go wyjaśnia.

FAQ

Czy każdy wpis w changelogu potrzebuje numeru wersji? Jeśli produkt wydaje wersje, tak, bo cyfra pozwala czytelniczce od razu przeskoczyć do “jak bardzo mnie to dotyczy” bez czytania wpisu najpierw. Jeśli produkt wdraża się w sposób ciągły bez pola wersji, sformułowanie wpisu musi nieść ten sygnał samo.

Jaka jest różnica między skokiem MAJOR a wpisem zmiany niekompatybilnej? Powinny opisywać to samo wydarzenie na dwa sposoby. Numer wersji to sygnał czytelny dla maszyn (narzędzia wywołującej mogą na niego reagować); wpis w changelogu to czytelne dla człowieka wyjaśnienie tego, co konkretnie się zmieniło.

Czy wydanie PATCH może być niekompatybilne? Z definicji nie powinno. Jeśli mimo to takie wyszło, nie edytujcie opublikowanej wersji ani nie zmieniajcie jej tagu: FAQ SemVer zaleca wydanie nowej wersji, która przywraca kompatybilność, albo nowej wersji MAJOR, jeśli niekompatybilność zostaje, oraz udokumentowanie wadliwej wersji, żeby użytkownicy wiedzieli, że mają ją pominąć.

Czy czysto wewnętrzne zmiany potrzebują skoku wersji? Nie. Semantic versioning śledzi publiczny interfejs. Refaktoryzacja bez obserwowalnego efektu dla wywołującej nie potrzebuje ani skoku, ani wpisu w changelogu, nawet jeśli była znaczącą pracą inżynieryjną.


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, Dokumentacja dla deweloperów

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