28.4.4 Version control and release

2025.10.06.
AI Security Blog

Once code is reviewed and merged, how it’s versioned and released determines its reliability and usability for the community. A disciplined approach to version control and releases is not just a technical formality; it’s the foundation of a project’s stability and the basis for building user trust.

The Foundation: Versioning Strategy

A consistent versioning scheme is the language you use to communicate the nature of changes to your users. It allows them to manage dependencies and understand the impact of an update without reading every line of code. For nearly all modern software, the standard is Semantic Versioning (SemVer).

Kapcsolati űrlap - EN

Do you have a question about AI Security? Reach out to us here:

Semantic Versioning (SemVer)

SemVer uses a three-part number format: MAJOR.MINOR.PATCH. Each part is incremented based on the type of changes introduced in the release.

Component Example Meaning and When to Increment
MAJOR 1.2.3 → 2.0.0 Incremented for incompatible API changes. A MAJOR version bump signals to users that the new release may break their existing integrations.
MINOR 1.2.3 → 1.3.0 Incremented when you add functionality in a backward-compatible manner. Users can typically upgrade without changing their own code.
PATCH 1.2.3 → 1.2.4 Incremented for backward-compatible bug fixes. This is the safest type of update for users to apply.

Adopting SemVer signals professionalism and makes your AI security tool predictable for downstream users, especially those in enterprise environments who must manage update risks carefully.

Managing Code Flow: Branching Models

A branching model provides structure to your development process, ensuring that the main codebase remains stable while new features and fixes are developed in isolation. For most open-source projects, a simple, streamlined model is most effective.

A Practical Approach: GitHub Flow

A simplified flow, often called GitHub Flow, is an excellent choice. It’s built around a single primary branch (e.g., main or master) that always represents a production-ready state. All development happens on short-lived feature branches.

A simplified branching model showing a feature branch created from main, receiving commits, and then being merged back into main via a pull request, resulting in a new release tag. main feature/new-detector v1.2.0 1. Create Branch Commit A Commit B 2. Open Pull Request 3. Review & Merge v1.3.0

The process is straightforward:

  1. Create a Branch: Start any new work (feature, bugfix) by creating a descriptive branch from the latest main.
  2. Commit Changes: Make your changes and commit them to your feature branch.
  3. Open a Pull Request (PR): When ready, open a PR to merge your branch back into main. This triggers the code review process (see Chapter 28.4.3).
  4. Merge: Once the PR is approved and passes all automated checks, it’s merged into main.

At this point, the main branch contains new code, and you can decide if it warrants a new release.

The Release Lifecycle: From Code to Distribution

A release is more than just a point in your Git history; it’s a packaged, documented, and distributed version of your project. Automating this process is critical for consistency and reducing human error.

The Release Checklist

A typical manual release process involves these key steps, which should ideally be automated via a CI/CD pipeline:

  • Verify Tests: Ensure all automated tests are passing on the target commit.
  • Update Version Number: Increment the version number in your project’s configuration files (e.g., pyproject.toml, package.json) according to SemVer.
  • Finalize Changelog: Consolidate commit messages and PR descriptions into a human-readable entry in your CHANGELOG.md file for the new version.
  • Create a Git Tag: This is the most crucial step. A Git tag creates an immutable pointer to a specific commit, marking it as a formal release.
  • Publish Artifacts: The CI/CD pipeline builds the project and pushes the resulting packages to a repository like PyPI (for Python) or npm (for JavaScript).
  • Create Release Notes: On platforms like GitHub or GitLab, create a formal “Release” from the tag, attaching the changelog notes and any compiled binaries.

Automation and Tooling

The core of a release is the Git tag. Creating an annotated tag is essential as it contains metadata like the tagger, date, and a message—making it a more robust artifact.

# Create an annotated tag for version 1.3.0
git tag -a v1.3.0 -m "Release version 1.3.0: Added new prompt injection detector"

# Push the commit and the new tag to the remote repository
git push origin main
git push origin v1.3.0

Triggering your CI/CD pipeline (e.g., with GitHub Actions) upon the creation of a new tag is a standard pattern. The pipeline then handles the build, test, and publishing steps, ensuring every release is processed identically.

Communicating Change: Release Notes and Changelogs

Your work isn’t done until you’ve communicated the changes to your users. A well-maintained changelog is a sign of a healthy, user-focused project.

  • Changelog (`CHANGELOG.md`): This is a file in your repository that provides a chronological list of all notable changes for each version of the project. It’s for developers and power users who need a detailed history. Keep it simple, with sections for “Added,” “Changed,” “Fixed,” and “Removed.”
  • Release Notes: These are the user-friendly summaries you publish on platforms like GitHub. They are based on the changelog but are often higher-level, highlighting key features and thanking contributors. This is your primary marketing tool for new versions.

By establishing and following a clear process for versioning and releases, you provide the stability and predictability that allows a community to build upon and trust your work. This systematic approach transforms a collection of code into a reliable and professional open-source tool.