Tạo CHANGELOG.md từ danh sách commit của cả một đợt phát hành
Dán đầu ra của lệnh git log vào ô nhập, công cụ đọc từng dòng theo chuẩn Conventional Commits, xếp chúng vào sáu mục của Keep a Changelog, tách riêng phần phá vỡ tương thích và đề xuất mức tăng phiên bản theo semver. Kết quả là một khối Markdown dán thẳng được lên đầu tệp CHANGELOG.md.
Tính năng nổi bật
- Nhận thẳng đầu ra của git log, tự bỏ mã băm ở đầu dòng và dấu gạch đầu dòng nếu bạn dán từ danh sách khác
- Phân loại theo mười ba loại commit quen thuộc: feat, fix, perf, refactor, revert, security, deprecate, docs, style, test, build, ci, chore
- Gom vào sáu mục chuẩn Keep a Changelog: Added, Changed, Deprecated, Removed, Fixed, Security
- Nhận diện phá vỡ tương thích qua dấu chấm than sau scope và qua dòng BREAKING CHANGE trong phần thân commit, đưa lên mục riêng ở đầu
- Đề xuất phiên bản kế tiếp theo semver dựa trên đúng những loại commit có mặt, kèm cách xử lý riêng cho dòng 0.x
- Tùy chọn nhóm các mục con theo scope, hợp với dự án nhiều mô đun
- Tùy chọn kèm hoặc bỏ commit bảo trì nội bộ, và tùy chọn kèm phần đầu tệp CHANGELOG.md
- Bảng đối chiếu từng commit rơi vào mục nào, kèm danh sách dòng chưa nhận dạng để bạn sửa tay
Vì sao nên dựng changelog từ lịch sử commit thay vì viết lại từ trí nhớ
Đến ngày phát hành, việc nhớ lại hai tuần vừa qua đã làm gì luôn cho ra một danh sách thiếu. Những thay đổi nhỏ nhưng đáng nói, chẳng hạn một tham số đổi tên hoặc một mặc định đổi giá trị, là thứ bị bỏ sót đầu tiên, và cũng chính là thứ khiến người dùng thư viện của bạn gặp lỗi khó hiểu. Lịch sử commit thì không quên gì cả, vấn đề chỉ là nó dài và lộn xộn. Công cụ này lấy đúng phần cấu trúc đã có sẵn trong tiêu đề commit, tức loại, scope và dấu phá vỡ tương thích, rồi sắp xếp lại theo cách người đọc changelog mong đợi. Bạn không phải đọc thủ công một trăm dòng để tìm ra bốn dòng bắt đầu bằng feat. Quan trọng hơn, cùng một tập commit luôn cho ra cùng một cách phân loại, nên changelog của các đợt phát hành nhất quán với nhau thay vì tùy thuộc người viết hôm đó là ai. Phần bạn cần làm chỉ còn là biên tập lại câu chữ cho người đọc và bổ sung phần hướng dẫn nâng cấp cho những thay đổi phá vỡ tương thích.
Lợi ích khi sử dụng
- Không bỏ sót thay đổi vì mọi commit trong khoảng đều được liệt kê và xếp mục
- Changelog các đợt phát hành nhất quán về cấu trúc, người đọc quen mắt và tìm nhanh
- Thấy ngay đợt này có phá vỡ tương thích hay không trước khi quyết định số phiên bản
- Tiết kiệm bước tra cứu quy tắc semver mỗi lần phát hành, nhất là với dự án còn ở dòng 0.x
- Chạy hoàn toàn trong trình duyệt nên lịch sử commit của dự án nội bộ không rời khỏi máy bạn
Cách tạo CHANGELOG.md từ lịch sử commit
- 1Mở thư mục dự án trong cửa sổ dòng lệnh và chạy git log --pretty=format:"%s" kèm khoảng từ tag phát hành gần nhất tới HEAD, ví dụ v1.4.2..HEAD.
- 2Dán toàn bộ đầu ra vào ô danh sách commit. Công cụ tự bỏ mã băm nếu bạn dùng git log --oneline.
- 3Nhập phiên bản hiện tại để công cụ tính được phiên bản kế tiếp, rồi kiểm tra ô phiên bản phát hành và ngày phát hành.
- 4Bật tùy chọn nhóm theo scope nếu dự án chia nhiều mô đun, bật tùy chọn kèm commit bảo trì nếu changelog của bạn dành cho nội bộ.
- 5Mở tab phân loại từng commit để soát lại các dòng chưa nhận dạng, sau đó chép hoặc tải khối Markdown và dán lên đầu tệp CHANGELOG.md.
Hai chuẩn, một bảng ánh xạ: Conventional Commits đi vào Keep a Changelog thế nào
Conventional Commits mô tả công việc của lập trình viên nên nó có nhiều loại: feat, fix, perf, refactor, revert, docs, style, test, build, ci, chore. Keep a Changelog lại mô tả thay đổi dưới góc nhìn người dùng nên chỉ có sáu mục: Added, Changed, Deprecated, Removed, Fixed, Security. Hai tập này không khớp một đối một, và chỗ lệch nhau chính là nơi cần quyết định. Công cụ ánh xạ feat sang Added, fix sang Fixed, còn perf, refactor và revert đều sang Changed vì với người dùng, chúng đều là hành vi cũ được làm lại. Nhóm docs, style, test, ci và chore không có mục tương ứng, vì người cài thư viện của bạn không quan tâm bạn vừa sắp xếp lại thư mục kiểm thử. Vì vậy nhóm này mặc định bị loại khỏi changelog, và bạn bật lại được nếu tệp changelog của bạn phục vụ nội bộ. Riêng build được xếp vào nhóm bảo trì nhưng vẫn tính là ảnh hưởng mức patch, vì nâng phụ thuộc đôi khi đổi hành vi thật. Hai mục Deprecated và Removed hiếm khi có loại commit tương ứng nên công cụ đoán thêm theo từ khóa trong tiêu đề, và bạn tắt được phần đoán này.
Hai cách đánh dấu phá vỡ tương thích, và vì sao chúng phải nằm ở mục riêng
Conventional Commits cho hai cách báo hiệu một thay đổi làm hỏng mã của người dùng. Cách thứ nhất là dấu chấm than đặt ngay trước dấu hai chấm, ví dụ feat(api)!: đổi định dạng phản hồi lỗi. Cách này gọn và luôn hiện trong tiêu đề nên lệnh git log ngắn nhất cũng thấy được. Cách thứ hai là một dòng bắt đầu bằng BREAKING CHANGE trong phần thân commit, kèm mô tả cụ thể điều gì hỏng. Cách này chứa được nhiều thông tin hơn nhưng nằm ở phần thân, nên nếu bạn chỉ lấy tiêu đề bằng định dạng phần trăm s thì nó biến mất. Muốn công cụ đọc được cả hai, hãy lấy kèm phần thân bằng định dạng ghép tiêu đề với thân commit, khi đó dòng BREAKING CHANGE sẽ được gán cho commit ngay phía trên nó. Về cách trình bày, công cụ đưa toàn bộ commit phá vỡ tương thích lên một mục riêng đặt đầu bản phát hành và không lặp lại chúng ở mục bên dưới. Lý do rất thực tế: người đọc changelog trước khi nâng cấp chỉ cần trả lời một câu hỏi duy nhất là nâng lên có gãy gì không, và câu trả lời phải nằm ở dòng đầu tiên chứ không lẫn giữa danh sách tính năng.
Từ tập commit ra mức tăng phiên bản, và cái bẫy của dòng 0.x
Quy tắc suy ra mức tăng rất ngắn. Có ít nhất một commit phá vỡ tương thích thì tăng major. Không có commit nào như vậy nhưng có feat thì tăng minor. Chỉ có fix, perf, refactor hoặc build thì tăng patch. Chỉ toàn commit bảo trì thì về lý thuyết không cần phát hành. Vấn đề nằm ở dự án còn mang số major bằng không. Đặc tả semver nói thẳng rằng mọi thứ trong dòng 0.x có thể thay đổi bất cứ lúc nào và API chưa được coi là ổn định, nên quy ước phổ biến trong hệ sinh thái là commit phá vỡ tương thích ở dòng 0.x chỉ tăng minor chứ không đẩy lên 1.0.0. Công cụ áp dụng đúng quy ước này và nói rõ trong phần giải thích, đồng thời nhắc rằng nếu bạn đã sẵn sàng cam kết ổn định thì đây chính là lúc lên 1.0.0. Một hệ quả ít người để ý: ở dòng 0.x, ngay cả bản chỉ thêm tính năng cũng không được các dự án cài bằng dấu mũ tự nhận, vì dấu mũ khóa số khác không đầu tiên. Con số công cụ đề xuất là điểm khởi đầu, quyết định cuối vẫn thuộc về bạn.
Biên tập lại các dòng trước khi phát hành: changelog viết cho người, không cho máy
Đầu ra của công cụ là bản nháp có cấu trúc đúng, nhưng câu chữ vẫn là câu chữ bạn viết lúc commit, tức viết cho đồng nghiệp đang đọc mã. Người đọc changelog thì khác: họ không biết tên hàm nội bộ, không biết tệp nào nằm ở đâu, và họ đọc để quyết định có nâng cấp không. Vì vậy nên rà lại vài điểm. Một dòng như sửa lỗi tại hàm calcShipping nên đổi thành sửa lỗi cộng sai phí vận chuyển khi khách đổi tỉnh, vì đó mới là điều người dùng nhìn thấy. Những commit chia nhỏ của cùng một việc nên gộp thành một dòng, chẳng hạn ba commit dựng phần đăng nhập bằng Google chỉ cần một dòng trong mục Added. Mỗi mục phá vỡ tương thích nên có thêm một câu chỉ đường nâng cấp, ví dụ nói rõ tham số cũ đổi thành gì. Ngược lại, đừng thêm vào changelog những thứ không thuộc về nó: chi tiết kỹ thuật dài dòng nên nằm trong tài liệu, còn lời cảm ơn người đóng góp nên gọn trong một dòng ở cuối bản phát hành.
Đặt changelog vào quy trình phát hành: thứ tự, tag và mục Unreleased
Một tệp CHANGELOG.md dùng lâu dài có ba đặc điểm nên giữ. Thứ nhất, bản mới nhất luôn nằm trên cùng, ngay dưới phần mở đầu, để người mở tệp thấy ngay thay đổi gần nhất mà không phải cuộn xuống. Vì vậy khối Markdown mà công cụ sinh ra được thiết kế để chèn vào đầu chứ không nối vào cuối, và bạn nên tắt tùy chọn kèm phần đầu tệp khi tệp đã có sẵn phần đó. Thứ hai, nên duy trì một mục Unreleased ở trên cùng để ghi dần các thay đổi trong lúc phát triển, đến ngày phát hành thì đổi tiêu đề mục đó thành số phiên bản kèm ngày. Thứ ba, ngày phát hành nên viết theo dạng năm, tháng, ngày ngăn bằng dấu gạch nối, tức chuẩn quốc tế, để tránh nhầm giữa cách viết ngày trước tháng và tháng trước ngày. Về thứ tự thao tác, hãy cập nhật changelog và số phiên bản trong cùng một commit chuẩn bị phát hành, rồi mới đặt tag lên đúng commit đó. Làm ngược lại sẽ khiến tag trỏ tới một commit chưa có changelog, và lần chạy git log của đợt sau sẽ lấy dư một dòng.
Câu hỏi thường gặp (FAQ)
Công cụ này khác gì công cụ tạo commit message trên trang?
Khác ở đầu vào và thời điểm dùng. Công cụ tạo commit message giúp bạn viết đúng một dòng cho một thay đổi chưa commit. Công cụ này nhận hàng chục commit đã có của cả một đợt và tổng hợp thành một mục phiên bản trong CHANGELOG.md. Dùng công cụ kia suốt kỳ phát triển, dùng công cụ này một lần khi phát hành.
Tôi dán lệnh nào để lấy danh sách commit?
Chạy git log --pretty=format:"%s" v1.4.2..HEAD, thay v1.4.2 bằng tag phát hành gần nhất của bạn. Không nhớ tên tag thì chạy git describe --tags --abbrev=0 để lấy. Chưa có tag nào thì bỏ phần khoảng, chỉ chạy git log --pretty=format:"%s".
Vì sao commit docs và chore của tôi không xuất hiện trong kết quả?
Vì nhóm bảo trì nội bộ gồm docs, style, test, build, ci và chore mặc định bị loại, do người dùng sản phẩm không quan tâm tới chúng. Bật công tắc kèm commit bảo trì nếu tệp changelog của bạn phục vụ nội bộ đội phát triển.
Dòng BREAKING CHANGE của tôi không được nhận, vì sao?
Nhiều khả năng bạn lấy log chỉ có tiêu đề nên phần thân commit không được in ra. Hãy dùng định dạng lấy kèm thân commit, tức ghép phần trăm s với phần trăm b. Dòng đó phải bắt đầu bằng đúng chữ BREAKING CHANGE hoặc BREAKING-CHANGE, theo sau là dấu hai chấm, và nằm ngay dưới commit tương ứng.
Commit phá vỡ tương thích có bị liệt kê hai lần không?
Không. Chúng chỉ nằm ở mục riêng đặt đầu bản phát hành, không lặp lại ở mục Added hay Changed bên dưới. Cách này giúp người đọc trả lời ngay câu hỏi quan trọng nhất là nâng cấp có gãy gì không, thay vì phải dò tìm giữa danh sách tính năng.
Dự án của tôi đang ở 0.5.2, có commit phá vỡ tương thích thì lên bao nhiêu?
Công cụ đề xuất 0.6.0 theo quy ước phổ biến, vì dòng 0.x được coi là API chưa ổn định nên thay đổi phá vỡ tương thích chỉ cần tăng minor. Nếu bạn đã sẵn sàng cam kết ổn định API với người dùng thì đây là thời điểm hợp lý để lên thẳng 1.0.0.
Nhóm theo scope thì kết quả trông thế nào?
Trong mỗi mục, các dòng được gom dưới một tiêu đề nhỏ là tên scope, những commit không có scope nằm dưới nhóm tên là chung. Cách này hợp với dự án chia nhiều mô đun. Khi tắt, mỗi dòng vẫn hiện scope ở đầu dòng dưới dạng chữ đậm.
Vì sao một commit fix lại bị xếp vào mục Security?
Vì tùy chọn đoán theo từ khóa đang bật và tiêu đề chứa từ liên quan tới bảo mật như security, lỗ hổng, xss hay injection. Đây là phỏng đoán để bạn không bỏ sót mục quan trọng. Tắt công tắc đó nếu bạn muốn giữ nguyên ánh xạ theo loại commit.
Những dòng không theo chuẩn Conventional Commits thì sao?
Chúng được liệt kê riêng trong phần cần xem lại và không đưa vào changelog, vì không có cơ sở nào để xếp mục. Bạn thêm tay vào kết quả nếu thấy cần. Từ đợt sau, viết commit theo dạng loại, scope trong ngoặc rồi dấu hai chấm sẽ giúp mọi thứ tự động.
Công cụ có gửi lịch sử commit của tôi lên máy chủ không?
Không. Toàn bộ việc đọc, phân loại và sinh Markdown chạy bằng JavaScript ngay trong trình duyệt của bạn. Không có lệnh gọi mạng, không lưu trữ, không tài khoản. Đóng tab là mọi dữ liệu bạn dán vào biến mất.
Tôi nên chèn kết quả vào đâu trong tệp CHANGELOG.md hiện có?
Chèn ngay dưới phần mở đầu và bên trên mục phiên bản gần nhất, vì quy ước là bản mới nhất nằm trên cùng. Khi tệp đã có phần mở đầu, hãy tắt tùy chọn kèm phần đầu tệp để kết quả chỉ gồm đúng khối phiên bản mới.
Số phiên bản công cụ đề xuất có dùng thẳng được không?
Dùng được trong đa số trường hợp, nhưng nên xem lại khi đợt phát hành có thay đổi mà tiêu đề commit không phản ánh hết, chẳng hạn đổi hành vi mặc định mà vẫn viết là fix. Muốn hiểu con số đó ảnh hưởng thế nào tới người đang phụ thuộc dự án, hãy kiểm tra range của họ bằng công cụ Semver Checker.
Từ khóa liên quan
- tạo changelog tự động
- changelog generator tiếng việt
- keep a changelog là gì
- conventional commits sang changelog
- cách viết file CHANGELOG.md
- git log lấy danh sách commit
- breaking change trong commit
- phân loại commit feat fix chore
- mức tăng phiên bản semver
- nên tăng major minor hay patch
- changelog cho dự án 0.x
- mục added changed fixed removed
- gom commit theo scope
- chuẩn bị release notes
- git describe tags abbrev 0
- tự động sinh release notes từ commit
- mẫu file changelog chuẩn
- công cụ tạo changelog online miễn phí
- quy trình phát hành phiên bản phần mềm
- changelog và semantic versioning
