CHANGELOG.md: ce conține și cum îl ții la zi
6 min de citit
Un CHANGELOG.md e un fișier Markdown din rădăcina unui repository care listează, pentru fiecare versiune lansată, ce s-a schimbat, în termeni pe baza cărora un utilizator al proiectului poate acționa. Fișierul e citit de oamenii care decid dacă să actualizeze, de oamenii care depanează după o actualizare și de registrele de pachete și uneltele de lansare care îl afișează pe pagina proiectului. Formatul urmat de cele mai multe proiecte e cel descris la keepachangelog.com: versiunea cea mai nouă sus, o secțiune Unreleased deasupra ei și intrări grupate sub Added, Changed, Deprecated, Removed, Fixed și Security.
| Secțiune | Ce conține | Exemplu de linie |
|---|---|---|
Unreleased | Schimbări integrate, dar încă neincluse într-o versiune | - Exportul rulează acum în flux, deci fișierele de peste 100 MB nu mai expiră. |
Added | Capabilitate nouă la care ajunge un utilizator | - Opțiunea \—dry-run` pe `deploy` afișează planul fără să-l aplice.` |
Changed | Comportament existent care funcționează acum altfel | - Timeout-ul implicit a crescut de la 30 s la 60 s. |
Deprecated | Încă funcționează, programat pentru eliminare | - \legacyAuth()` va fi eliminat în 3.0; folosiți `auth()`.` |
Removed | Dispărut în această versiune | - Suportul pentru Node 16 a fost eliminat. |
Fixed | O eroare pe care un utilizator o putea întâlni | - Căutarea nu mai eșuează la interogări care conțin o cratimă. |
Security | Corecții pentru care cititorul ar trebui să actualizeze azi | - Corectat un path traversal în handler-ul de fișiere statice (CVE în așteptare). |
Ce este un fișier CHANGELOG.md?
E istoricul lizibil pentru oameni al unui proiect, versiune cu versiune, ținut lângă cod ca să fie livrat odată cu el. Diferă de git log prin public și prin selecție: jurnalul git înregistrează fiecare commit pentru oamenii care l-au scris, în timp ce changelog-ul înregistrează schimbările pe care le-ar observa un utilizator, scrise pentru persoana care nu le-a scris. Un commit care redenumește o variabilă internă nu are linie în changelog. Un commit care schimbă un timeout implicit are una, chiar dacă diff-ul a fost un singur caracter.
Fișierul stă în rădăcina repository-ului, sub exact acel nume, pentru că uneltele îl caută acolo. GitHub îl leagă din pagina repository-ului, npm și PyPI îl afișează când e inclus în pachet, iar unelte de lansare precum release-please și semantic-release îl citesc și îl scriu pe loc. changelog.md cu litere mici și CHANGES.md merg și ele pentru oameni, dar unele unelte caută doar numele canonic.
Cum arată un CHANGELOG.md complet?
Un exemplu scurt și corect valorează mai mult decât o descriere lungă. Acesta urmează structura Keep a Changelog 1.1.0 și semantic versioning pentru numere.
# Changelog
Toate schimbările notabile ale acestui proiect sunt listate aici.
Format: Keep a Changelog. Versiuni: Semantic Versioning.
## [Unreleased]
### Added
- Opțiunea `--dry-run` pe `deploy` afișează planul fără să-l aplice.
## [2.3.1] - 2026-10-01
### Fixed
- Căutarea nu mai eșuează la interogări care conțin o cratimă.
Stricată din 2.3.0.
### Security
- Corectat un path traversal în handler-ul de fișiere statice.
Actualizați azi dacă serviți fișiere încărcate de utilizatori.
## [2.3.0] - 2026-09-18
### Added
- Export în flux. Fișierele de peste 100 MB nu mai expiră.
### Deprecated
- `legacyAuth()` încă funcționează, dar va fi eliminat în 3.0.
Folosiți `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
Patru detalii poartă cea mai mare parte din valoare. Fiecare versiune are o dată în format ISO, ca cititorul s-o potrivească cu momentul în care a început problema lui. Fiecare titlu de versiune e un link către vizualizarea de comparare, deci diff-ul complet e la un clic distanță. O corecție spune ce versiune a stricat lucrul respectiv. Iar secțiunea Security stă separat, ca cineva care scanează după „trebuie să actualizez acum?” s-o găsească în câteva secunde.
Cum ții un CHANGELOG.md la zi?
Scrieți linia în același pull request cu schimbarea, sub Unreleased, și mutați secțiunea sub un titlu de versiune când lansați. Asta e toată metoda. Fișierul se învechește când linia e scrisă mai târziu, de altcineva, la momentul lansării, dintr-o listă de mesaje de commit pe care nu le-a scris.
Două lucruri fac obiceiul să prindă. Primul e un check în CI care respinge un pull request ce atinge src/ fără să atingă changelog-ul, cu o etichetă care îl sare pentru schimbările fără efect vizibil pentru utilizator; un check de changelog ca GitHub Action arată versiunea de patruzeci de linii. Al doilea e un pas de lansare care redenumește Unreleased în versiune și dată printr-o singură comandă, ca nimeni să nu trebuiască să-și amintească s-o facă de mână. Cine scrie changelog-ul acoperă cum lămuresc echipele a cui treabă e linia.
Ar trebui generat changelog-ul din commit-uri?
Generarea vă dă o ciornă completă; nu vă dă un changelog. Uneltele construite pe conventional commits și automatizările de lansare precum release-please citesc prefixele feat:, fix: și BREAKING CHANGE: și produc o listă grupată, cu fiecare pull request legat. Lista e la fel de bună ca subiectele commit-urilor, iar subiectele commit-urilor descriu codul.
Calea de mijloc care funcționează e să generați, apoi să editați. Lăsați unealta să creeze secțiunea Unreleased din commit-uri și puneți pull request-ul de lansare să rescrie liniile pe care le-ar citi un utilizator: simptomul în loc de numele funcției, setarea care s-a mutat în loc de fișierul care s-a schimbat. De la conventional commits la un changelog parcurge pipeline-ul, iar un generator de changelog în browser e suficient ca să obțineți o ciornă dintr-un git log lipit, fără să instalați nimic.
Ce nu ar trebui să intre în CHANGELOG.md?
Refactorizări interne, actualizări de dependențe fără schimbare de comportament, commit-uri doar cu teste, configurări de CI și schimbări de formatare. Locul lor e în istoricul git, unde le poate găsi oricine are nevoie de ele. Includerea lor îngroapă liniile care contează și îi învață pe cititori să sară peste fișier.
Celălalt lucru de lăsat deoparte e versiunea de marketing a unei schimbări. „Exporturi fulgerător de rapide” nu-i spune cititorului nimic ce poate verifica. „Exportul rulează acum în flux; fișierele de peste 100 MB nu mai expiră” îi spune. Fișierul e un document de referință, iar tonul ar trebui să se potrivească: linii scurte, substantive concrete, o versiune sau o dată pe fiecare lucru. Keep a Changelog, implementat acoperă părțile specificației pe care echipele le lasă cel mai des deoparte, iar formatele de fișier changelog acoperă când o sursă JSON sau YAML lângă fișierul Markdown își merită locul.
Un produs cu pagină de changelog mai are nevoie de fișier?
O bibliotecă are, pentru că fișierul e ce afișează registrele de pachete și ce citește un dezvoltator offline. Un produs SaaS fără artefact instalabil se poate descurca doar cu pagina, fiindcă utilizatorii lui nu văd niciodată repository-ul. Multe echipe le țin pe amândouă: fișierul ca înregistrare de inginerie și o pagină de changelog publică, scrisă din el pentru un public mai larg, cu detaliile împărțite așa cum descrie changelog vs release notes. Dacă pagina e alimentată din fișier, păstrați fișierul ca sursă de adevăr și generați pagina, ca să existe un singur loc de editat.
FAQ
Care e diferența dintre CHANGELOG.md și release notes? Changelog-ul e înregistrarea completă, continuă, a fiecărei schimbări notabile, ținută în repository. Release notes sunt un mesaj despre o singură lansare, adesea mai scurt și rescris pentru un public mai larg. Multe proiecte publică secțiunea din changelog a unei versiuni drept release notes ale ei.
Unde ar trebui să stea CHANGELOG.md? În rădăcina repository-ului, cu exact acel nume, ca GitHub, registrele de pachete și uneltele de lansare să-l găsească. Un monorepo ține câte unul per pachet, lângă manifestul fiecărui pachet.
Ar trebui să generez CHANGELOG.md din commit-urile git? Generați ciorna, apoi editați liniile pe care le va citi un utilizator. Mesajele de commit descriu schimbarea din cod; changelog-ul descrie ce observă un utilizator. Unelte precum conventional-changelog și release-please produc un punct de plecare bun.
Are fiecare commit nevoie de o intrare în changelog? Nu. Doar schimbările pe care le-ar putea observa un utilizator al proiectului: capabilități noi, comportament schimbat, deprecieri, eliminări, corecții și patch-uri de securitate. Refactorizările, schimbările de teste și editările de CI rămân în istoricul git.
Afirmațiile tehnice din acest articol nu au fost verificate independent. Dacă ceva nu e corect, spune-ne și vom corecta.