Building a Workflow to Backdate GitHub Releases with Claude Code
In the early stages of a project, development speed takes priority, and creating release notes often gets pushed aside. Our project was no exception—before we knew it, we had gone several months without any GitHub Releases.
To solve this problem, we built a semi-automated workflow using Claude Code to retroactively create release notes from past Pull Request merge history. In this article, we’ll introduce the specific methodology and the benefits we gained from implementing it.
While we were actively developing every day, it was difficult to tell from the GitHub repository information alone that the project was active. However, manually going back through the history to create release notes was far too inefficient and impractical.
We built a semi-automated workflow combining git commands, the gh CLI, and Claude Code. The purpose of this workflow is to extract release information from merge commits within a specific date range and create backdated GitHub Releases through interactive confirmation.
For this implementation, I chose a style where I confirmed each step, but it’s also possible to run it on autopilot for full automation.
The workflow consists of the following steps:
main branch on a specific day.First, use git log to list merge commits for a specified day. The --first-parent option is important—it filters to only direct merges to the main branch (PR merge commits).
git log --oneline --since="2025-05-01T00:00:00" --until="2025-05-02T00:00:00" --first-parent main --format="%h %s"Next, use the gh pr view command to get detailed information for each PR. When there are multiple PRs, use a for loop to process them efficiently in parallel.
# Batch retrieve multiple PR information
for pr in 1001 1002 1003; do
gh pr view $pr --json title,author --jq "{pr: $pr, title: .title, author: .author.login}"
doneThis is the heart of the workflow. Pass the retrieved PR information to Claude Code to generate a release notes draft and recommended version.
Example of actual interaction flow:
Claude: ## Merges for 2025-05-01
| PR | Title | Author |
|------|---------------------|-------------|
| #123 | Add new feature X | @developer1 |
| #124 | Fix bug in Y | @developer2 |
**Recommendation**: **v0.38.0** (minor) due to new feature addition
Create as **v0.38.0**? (ok/patch/minor)
User: ok
Claude: ✅ **v0.38.0** created successfully
---
## Checking merges for 2025-05-02
...Claude reads the PR titles to understand the changes (new features, bug fixes, etc.) and proposes a version based on the versioning policy. Developers can approve by simply typing ok, or override by typing patch or minor if needed. This “human final confirmation” step provides flexibility and peace of mind that full automation cannot offer.
To set the release date to a past date, execute the git tag command with the GIT_COMMITTER_DATE environment variable. This allows you to set the tag creation date to a past date.
GIT_COMMITTER_DATE="2025-05-01T23:59:00Z" git tag -a v0.38.0 <commit_hash> -m "v0.38.0"Finally, create the release with gh release create. Since the Published date displayed on GitHub’s UI cannot be changed, we add a line at the beginning of the release notes body stating Originally released: YYYY-MM-DD to clearly indicate the actual release date.
gh release create v0.38.0 --title "v0.38.0" --notes "Originally released: 2025-05-01
## What's Changed
* Feature A by @user1 in https://github.com/org/repo/pull/123
* Fix B by @user2 in https://github.com/org/repo/pull/124
**Full Changelog**: https://github.com/org/repo/compare/v0.37.0...v0.38.0"This workflow can be flexibly customized to match your project’s characteristics.
Adjusting versioning policy: By communicating project-specific rules to Claude’s prompt (e.g., “new features behind feature flags should be patch updates”), you can improve determination accuracy.
Error recovery: If you accidentally create a release with the wrong version, you can easily roll back with the following commands:
# Delete remote release and tag
gh release delete v0.12.0 --yes
git push origin --delete v0.12.0
# Delete local tag
git tag -d v0.12.0After that, simply recreate with the correct version.
Implementing this workflow provided the following benefits:
As a result, we were able to create approximately 7 months’ worth of accumulated release notes, from v0.7.0 to v0.38.0, in just a few hours.
Maintaining release notes is essential for healthy project management. By combining Claude Code with various CLI tools, we built a system to handle this tedious and often-neglected task efficiently and accurately. Not only did we clear our past technical debt, but we now have a framework in place to continuously create high-quality release notes using this workflow.
We hope this article provides some helpful insights for developers facing similar challenges.
That’s all from the Gemba, where we backdated Giselle Releases with Claude Code.