[You can also view the single-page version of this document.]

Making Subversion Releases

This document can generally be broken into three parts, in increasing order of specificity:

Subversion release managers use a set of steps codified in a Python script named release.py. This script can be used to perform most of the automated steps in the release process. Run it with the -h option to get more information.

In addition to the following project-specific guidelines, aspiring release managers may also want to read up on the general Apache release policies. They can seem a bit patchwork at times, but give a good idea of general best practice and how Subversion fits in the larger ASF ecosystem.

Subversion release process

Release numbering

Subversion uses "MAJOR.MINOR.PATCH" release numbers. We do not use the "even==stable, odd==unstable" convention; any unqualified triplet indicates a stable release:

   1.0.1  -->  first stable patch release of 1.0
   1.1.0  -->  next stable minor release of 1.x after 1.0.x
   1.1.1  -->  first stable patch release of 1.1.x
   1.1.2  -->  second stable patch release of 1.1.x
   1.2.0  -->  next stable minor release after that

The order of releases is semi-nonlinear — a 1.0.3 might come out after a 1.1.0. But it's only "semi"-nonlinear because eventually we declare a patch line defunct and tell people to upgrade to the next minor release, so over the long run the numbering is basically linear.

The numbers may have multiple digits. For example, 1.7.19 is the nineteenth patch release in the 1.7.x line; it was released three years after 1.7.2, and three months before 1.7.20.

Subversion releases may be qualified by text following the version number, which all represent various steps in the pre-release process. In order from least- to most-stable:

Qualifier Meaning Example Output of svn --version
Alpha We know or expect there to be problems, but solicit testing from interested individuals. subversion-1.7.0-alpha2 version 1.7.0 (Alpha 2)
Beta We don't expect there to be problems, but be wary just in case. subversion-1.7.0-beta1 version 1.7.0 (Beta 1)
RC (Release Candidate) This release is a candidate to become the final proposed version. If no serious bugs are found, the -rc tag will be dropped, and the contents of this release will be declared stable. subversion-1.7.0-rc4 version 1.7.0 (Release Candidate 4)

When you 'make install' subversion-1.7.0-rc1, it still installs as though it were "1.7.0", of course. The qualifiers are metadata on the release; we want each subsequent prerelease release to overwrite the previous one, and the final release to overwrite the last prerelease.

For working copy builds, there is no tarball name to worry about, but 'svn --version' still produces special output:

   version 1.7.1-dev (under development)

The version number is the next version that project is working towards. The important thing is to say "under development". This indicates that the build came from a working copy, which is useful in bug reports.

Alpha and beta releases

When we want new features to get wide testing before we enter the formal stabilization period, we'll sometimes release alpha and beta tarballs. There is no requirement to do any beta releases even if there were "alpha1", "alpha2", etc releases; we could just jump straight to "rc1". However, there are circumstances where a beta can be useful: for example, if we're unsure of a UI decision and want to get wider user feedback before solidifying it into a formal release candidate.

Alphas and betas are only for people who want to help test, and who understand that there may be incompatible changes before the final release. The signature requirements are at the release manager's discretion. Typically, the RM will require only 1 or 2 signatures for each platform, and to tell signers that they can still sign even if their testing reveals minor failures, as long as they think the code is solid enough to make testing by others worthwhile. The RM should request that signers include a description of any errors along with their signatures, so the problems can be published when the alpha or beta release is announced.

When the alpha or beta is publicly announced, distribution packagers should be firmly warned off packaging it. See this mail from Hyrum K. Wright for a good model.

Breaking compatibility

Our compatibility rules (as detailed below) only start to apply once a final x.y.0 version has been blessed and released. Any API's, wire protocols, and on-disk formats that appeared on trunk or in an alpha/beta/rc pre-release are not subject to any compatibility promises; we may change them arbitrarily until the final release, if we find a good reason to do so. We might even remove entirely an interface or serialization format that we are not comfortable with.

This is particularly a problem for persistent data (working copies and repositories), since we might not provide an upgrade path—code paths or designated scripts for the legacy format—with the final release. (Of course, we might provide such scripts for the benefit of developers and users who test our pre-releases; but we do not obligate ourselves to do so.) Consequently, pre-releases should never be trusted with any data meant for long-term safe-keeping.

At the same time, we wish to remind the reader that the best time to point out API design bugs is before they are released and set in stone—in other words, during the initial design and pre-release stages.

Reuse of release names

If a release or candidate release needs to be quickly re-issued due to some non-code problem (say, a packaging glitch), it's okay to reuse the same name, as long as the tarball hasn't been blessed by signing yet. However, if it has been uploaded to the standard distribution area with signatures, or if the re-issue was due to a change in code a user might run, then the old name must be tossed and the next name used.

If the old name is tossed before the would-be release tarball was published and announced to users, the tossed name is considered a non-public release, and documentation (such as CHANGES and the tag's log message) should be updated to reflect that. (See 1.8.7 for an example.) Tags and tarballs of tossed releases remain in the repository history, but they are not supported for general use (on the contrary, they are known to have release-blocker bugs).

Inter-release compatibility

Subversion follows strict compatibility, with the same guidelines as APR (see https://apr.apache.org/versioning.html), plus a few extensions, described later. These guidelines are in place to ensure various forms of client/server interoperability, and make sure users have a clear upgrade path between MAJOR.MINOR Subversion releases.

Compatibility can span a number of axes: everything from APIs and ABIs to command line output formats. We try to balance the need to modify the existing architecture to support new features, while still supporting current users to the greatest extent possible. The general idea is:

  1. Upgrading/downgrading between different patch releases in the same MAJOR.MINOR line never breaks code. It may cause bugfixes to disappear/reappear, but API signatures and semantics remain the same. (Of course, the semantics may change in the trivial ways appropriate for bugfixes, just not in ways that would force adjustments in calling code.)

  2. Upgrading to a new minor release in the same major line may cause new APIs to appear, but not remove any APIs. Any code written to the old minor number will work with any later minor number in that line. However, downgrading afterwards may not work, if new code has been written that takes advantage of the new APIs.

    (Occasionally, bugs are found which require the behavior of old APIs to be modified slightly. This typically only manifests itself in various corner cases and other uncommon areas. These changes are documented as API errata for each MAJOR.MINOR release.)

  3. When the major number changes, all bets are off. This is the only opportunity for a full reset of the APIs, and while we try not to gratuitously remove interfaces, we will use it to clean house a bit.

Subversion extends the APR guidelines to cover client/server compatibility questions:

  1. A patch or minor number release of a server (or client) never breaks compatibility with a client (or server) in the same major line. However, new features offered by the release might be unsupported without a corresponding upgrade to the other side of the connection. For updating ra_svn code specifically, please observe these principles:

    1. Fields can be added to any tuple; old clients will simply ignore them. (Right now, the marshalling implementation does not let you put number or boolean values in the optional part of a tuple, but changing that will not affect the protocol.)

      We can use this mechanism when information is added to an API call.

    2. At connection establishment time, clients and servers exchange a list of capability keywords.

      We can use this mechanism for more complicated changes, like introducing pipelining or removing information from API calls.

    3. New commands can be added; trying to use an unsupported command will result in an error which can be checked and dealt with.

    4. The protocol version number can be bumped to allow graceful refusal of old clients or servers, or to allow a client or server to detect when it has to do things the old way.

      This mechanism is a last resort, to be used when capability keywords would be too hard to manage.

  2. Working copy and repository formats are backward- and forward-compatible for all patch releases in the same minor series. They are forward-compatible for all minor releases in the same major series; however, a minor release is allowed to make a working copy or repository that doesn't work with previous minor releases, where "make" could mean "upgrade" as well as "create".

Security releases

Occasionally, security issues are reported or discovered in the Subversion which warrant special treatment when releasing. The general release process is the same, and details of how the developers treat these issues is covered elsewhere.

Custom releases

Subversion does not distribute binary packages, but instead relies upon third-party packagers to do so. Luckily, many individuals and companies have stepped in to volunteer their efforts in this regard, and we are grateful for their efforts.

If you are a third-party packager, you may encounter instances when a bug fix or other change is important for your users, and you want to get it to them more quickly than the standard Subversion release cycle. Or you may maintain a set of patches locally which benefit your target audience. If possible, it is preferred to use the patch process and have your changes accepted and applied to trunk to be released on the normal Subversion release schedule.

However, if you feel that you need to make changes that would not be widely accepted by the Subversion developer community, or need to provide early access to unreleased features, you should follow the guidelines below. They are intended to help prevent confusion in the user community, and make both your distribution and the official Subversion releases as successful as possible.

First, make sure you follow the ASF trademark policy. You will need to differentiate your release from the standard Subversion releases to reduce any potential confusion caused by your custom release.

Second, consider creating a branch in the public Subversion repository to track your changes and to potentially allow your custom changes to be merged into mainline Subversion. (If you do not have it already, ask for commit access.)

Third, if your custom release is likely to generate bug reports that would not be relevant to mainline Subversion, please stay in touch with the users of the custom release so you can intercept and filter those reports. But of course, the best option would be not to be in that situation in the first place — the more your custom release diverges from mainline Subversion, the more confusion it invites. If you must make custom releases, please try to keep them as temporary and as non-divergent as possible.


When a new, improved version of an API is introduced, the old one remains for compatibility, at least until the next major release (2.0.0). However, we mark the old one as deprecated and point to the new one, so people know to write to the new API if at all possible. When deprecating, mention the release after which the deprecation was introduced, and point to the new API. If possible, replace the old API documentation with a diff to the new one. For example:

    * Similar to svn_repos_dump_fs3(), but with a @a feedback_stream instead of
    * handling feedback via the @a notify_func handler
    * @since New in 1.1.
    * @deprecated Provided for backward compatibility with the 1.6 API.
   svn_error_t *
   svn_repos_dump_fs2(svn_repos_t *repos,
                      svn_stream_t *dumpstream,
                      svn_stream_t *feedback_stream,
                      svn_revnum_t start_rev,
                      svn_revnum_t end_rev,
                      svn_boolean_t incremental,
                      svn_boolean_t use_deltas,
                      svn_cancel_func_t cancel_func,
                      void *cancel_baton,
                      apr_pool_t *pool);

When the major release number changes, the "best" new API in a series generally replaces all the previous ones (assuming it subsumes their functionality), and it will take the name of the original API. Thus, marking 'svn_repos_dump_fs' as deprecated in 1.1.x doesn't mean that 2.0.0 doesn't have 'svn_repos_dump_fs', it just means the function's signature will be different: it will have the signature held by svn_repos_dump_fs2 (or svn_repos_dump_fs3, or whatever) in 1.1.x. The numbered-suffix names disappear, and there is a single (shiny, new) svn_repos_dump_fs again.

One exception to this replacement strategy is when the old function has a totally unsatisfying name anyway. Deprecation is a chance to fix that: we give the new API a totally new name, mark the old API as deprecated, point to the new API; then at the major version change, we remove the old API, but don't rename the new one to the old name, because its new name is fine.

Stabilizing and maintaining releases


Minor and major number releases go through a stabilization period before release, and remain in maintenance (bugfix) mode after release. To start the release process, we create an "A.B.x" branch based on the latest trunk.

The stabilization period for a new A.B.0 release normally lasts four weeks, and allows us to make conservative bugfixes and discover showstopper issues. The stabilization period begins with a release candidate tarball with the version A.B.0-rc1. Further release candidate tarballs may be made as blocking bugs are fixed; for example, if a set of language bindings is found to be broken, it is prudent to make a new release candidate when they are fixed so that those language bindings may be tested.

Once the A.B.x branch has been created, no source code changes are ever committed to it directly; changes are backported from trunk to the A.B.x branch after being voted on, by the process described in the next sections.

At the beginning of the final week of the stabilization period, a new release candidate tarball should be made if there are any showstopper changes pending since the last one. The final week of the stabilization period is reserved for critical bugfixes; fixes for minor bugs should be deferred to the A.B.1 release. A critical bug is a non-edge-case crash, a data corruption problem, a major security hole, or something equally serious.

Under some circumstances, the stabilization period will be extended:


  • If a potentially destabilizing change must be made in order to fix a bug, the entire four-week stabilization period is restarted. A potentially destabilizing change is one which could affect many parts of Subversion in unpredictable ways, or which involves adding a substantial amount of new code. Any incompatible API change (only allowable in the first place if the new release is an A.0.0 release) should be considered a potentially destabilizing change.

  • If a critical bugfix is made during the final week of the stabilization period, the final week is restarted. The final A.B.0 release is always identical to the release candidate made one week before (with the exceptions discussed below).

After the A.B.0 release is out, patch releases (A.B.1, A.B.2, etc.) follow when bugfixes warrant them. Patch releases do not require a four week soak, because only conservative changes go into the line.

What changes are eligible for backport

Certain kinds of commits can go into A.B.0 without restarting the soak period, or into a later release without affecting the testing schedule or release date:

  • Without voting:

    • Changes to the STATUS file.

    • Documentation fixes.

    • Changes that are a normal part of release bookkeeping, for example, the steps listed in Rolling a release and Creating and maintaining release branches.

    • Changes to dist.sh by, or approved by, the release manager.

    • Changes to message translations in .po files or additions of new .po files.

  • With voting:

    • Anything affecting only tools/, packages/, or bindings/.

    • Changes to printed output, such as error and usage messages, as long as format string "%" codes and their args are not touched.

NOTE: The requirements on message translation changes are looser than for text messages in C code. Changing format specifiers in .po files is allowed because their validity can be checked mechanically (with the -c flag on msgfmt of GNU gettext). This is done at build time if GNU gettext is in use.

Core code changes, of course, require voting, and restart the soak or test period, since otherwise the change could be undertested.

Voting overview and the electorate

A change to the A.B.x line must be first proposed in the A.B.x/STATUS file. Each proposal consists of a short identifying block (e.g., the revision number of a trunk or related-line commit, or perhaps an issue number), a brief description of the change, an at-most-one-line justification of why it should be in A.B.x, perhaps some notes/concerns, and finally the votes. The notes and concerns are meant to be brief summaries to help a reader get oriented. Don't use the STATUS file for actual discussion; use dev@ instead.

Here's an example, probably as complex as an entry would ever get:

   * r98765 (issue #56789)
     Make commit editor take a closure object for future mindreading.
       API stability, as prep for future enhancement.
     Branch: 1.8.x-r98765
       There was consensus on the desirability of this feature in
       the near future; see thread at http://... (Message-Id: blahblah).
       Merge with --accept=mc.
       Vetoed by jerenkrantz due to privacy concerns with the
       implementation; see thread at http://... (Message-Id: blahblah)
       +1: ghudson, bliss
       +0: cmpilato
       -0: gstein
       -1: jerenkrantz

Anyone may vote, but only full committers and partial committers for the involved areas have binding votes. When committers cast a non-binding vote (such as a partial committer voting for a change outside his nominated area), they should annotate their vote as non-binding, like this:

 * r31833
   svndumpfilter: Don't match prefixes to partial path components.
   Fixes #desc4 of issue #1853.
     +1: danielsh, hwright
     +1 (non-binding): stylesen

This distinction is made in all kinds of voting—backport voting, release voting, and the mythical votes caused by failure to reach consensus—but for different reasons. In release votes, this distinction is legally required for the release to enter ASF's legal shield, whereas in backport votes, it's closer to being an advisory distinction. After all, if someone votes -1 on a change for a sound reason, their accreditations don't matter; if their analysis is correct, the change won't be backported. Likewise, if a change fails to receive the required number of binding +1 votes but has some non-binding +1 votes, that may help it be approved.

In other words, the purpose of the backport process is to ensure destabilizing changes won't enter patch releases. Voting serves that purpose by forcing each change to undergo a certain amount of review. Since karma is not transferable, we measure "amount of review" in terms of binding votes—but as ever, anyone can give input to the process and be listened to.

Types of votes

The voter's opinion of a change is encoded as +1, -1, +0, or -0.

Define "veto" or refer to a definition

If you cast a veto (i.e. -1), please state the reason in the concerns field, and include a url / message-id for the list discussion if any. You can go back and add the link later if the thread isn't available at the time you commit the veto.

A -0 vote means you somewhat object to a change—state your reasons in on dev@, or summarize them in a parenthetical—but won't stand in the way of consensus.

Voting +1 on a change doesn't just mean you approve of it in principle. It means you have thoroughly reviewed the change, and find it correct and as nondisruptive as possible. When it is committed to the release branch, the log message will include the names of all who voted for it, as well as the original author and the person making the commit. All of these people are considered equally answerable for bugs. Committers are trusted to know what they don't know and not cast +1 votes lightly.

If you've reviewed a patch, and like it but have some reservations, you can write "+1 (concept)" and then ask questions on the list about your concerns. You can write "+0" if you like the general idea but haven't reviewed the patch carefully. Neither of these votes counts toward the total, but they can be useful for tracking down people who are following the change and might be willing to spend more time on it.

How many votes are required

For a non-LTS ("regular") release line, a change is approved if it receives two +1s and no vetoes. (Only binding votes count; see above.)

For an LTS release line, a change is approved if it receives three +1s and no vetoes. (Only binding votes count; see above.)

Notwithstanding the above, for any release line, a change that affects only areas that are not core code (for example, tools/, packages/, bindings/, test scripts, etc.), and that does not affect the build system, can go in with one +1 from a full committer or a partial committer for that area, at least one +0 or "concept +1" from any other committer, and no vetoes.

The goal is to get at least two pairs of eyes on the change, without demanding that every reviewer have the same amount of expertise as the area maintainer. This way one can review for general sanity, accurate comments, obvious mistakes, etc, without being forced to assert "Yes, I understand these changes in every detail and have tested them."

How to nominate changes into STATUS

Before proposing a change in STATUS, you should try merging it onto the branch to ensure that it doesn't produce merge conflicts. If conflicts occur, please create a new temporary branch from the release branch with your changes merged and the conflicts resolved. The branch should be named A.B.x-rYYYY, where YYYY is the first revision of your change in the STATUS file. Add a note in the STATUS file about the existence of the temporary branch in the form of a Branch: A.B.x-rYYYY or Branch: ^/subversion/branches/A.B.x-rYYYY header (use this exact form; scripts parse it). If the change involves further work, you can merge those revisions to the branch. When the entry for this change is removed from STATUS, this temporary branch should also be removed to avoid cluttering the /branches directory.

A temporary branch is also used in the rare case that a change should be made to the A.B.x branch that isn't a backport of a change from trunk.

If you nominate an entry that causes merge conflicts until another nomination is merged, note that in the nomination. Put a "Depends:" header in the entry; that will keep the hourly "detect nominations with merge conflict" buildbot job green. (The value of the "Depends:" header is not parsed.)

The tools/dist/nominate.pl script (in trunk) automates the process of adding a new nomination. The same script also has a REPL loop that helps with the process of reviewing nominations and casting votes; see tools/dist/README.backport (in trunk).

NOTE: Changes to STATUS regarding the temporary branch, including voting, are always kept on the main release branch.

Editing STATUS and annotating votes

When adding revisions to a nomination that others have already voted on, annotate their entries with "(rX only)" to clarify what parts they have and haven't voted on, like this:

   * r30643, r30653, r30785
     Update bash completion script.
       +1: arfrever (r30785 only), stylesen

Obvious fixes do not require '(rX only)' to be mentioned.

If you commit someone else's vote that was communicated via other means, note that in your log message.

Creating a Subversion release

Notify translators

Before the actual release, send an e-mail to the translators to request updates of the .po files. Take their e-mail addresses from the COMMITTERS file in trunk, using a command such as:

sed -e '/^ *Translat.*:$/,/:$/!d' -e 's/^ *[^ ]* *\([^>]*>\).*/\1/;t;d' COMMITTERS

Include a translation status report produced by:


This should be done after all localised strings have stabilised in their final form for the release, but sufficiently in advance of the actual release to allow the translators to do their work. As a rule of thumb, send the notification at the least one week, preferably more, prior to the intended release. If many strings have changed, as would be the case for the first release from a new branch, then let more time pass.

Preparing to roll a release

Install pristine versions of some build tools

So, a release branch has stabilized, and you are gearing up to roll the release. The details of the rolling process are automated by the release.py helper script. To run this script, you'll need a Subversion trunk working copy. Run release.py -h to get a list of available subcommands.

Before you can actually roll the archives, you need to set up a white-room rolling environment. This environment must contain pristine versions of some build tools.

It is important that you do not use distribution shipped versions of this software as they are often patched in ways that are not portable (e.g., Debian's libtool patch: #291641, #320698.) The version numbers given in tools/dist/release-lines.yaml should normally be reconsidered and increased to the latest stable upstream release in the time leading up to an A.B.0 release. Changing the version within an A.B.x series should only be done with careful consideration.

Autoconf, Libtool and SWIG: Pick a directory to contain your special build tools for Subversion RM duties - for example /opt/svnrm. Configure, build and install the three pieces of software with the release.py build-env command.

mkdir -p /opt/svnrm && cd /opt/svnrm && $SVN_SRC_DIR/tools/dist/release.py build-env X.Y.Z

Install some more build tools

The rolling scripts also require the following commands to be available: pax, xgettext, m4, and python -c 'import yaml'.

Install these from your OS packages. (On Debian systems, that'd be apt install pax gettext m4 python-yaml subversion.)

Rolling a release

Before rolling:

  1. Make sure that the latest version of the CHANGES file from trunk is merged into the release branch, and that the date at the top of CHANGES matches the planned release date of the tarball. (See Managing the CHANGES file.)
  2. Make sure that get-deps.sh works on the release branch.

Create the tarballs: Run:

./release.py roll X.Y.Z 1234
When release.py is done you'll have tarballs within the /opt/svnrm/deploy directory.

Test one or both of the tarballs:

    a) tar zxvf subversion-X.Y.Z.tar.gz;  cd subversion-X.Y.Z
    b) ./configure
       See INSTALL, section III.B for detailed instructions on
       configuring/building Subversion.
       If you installed Apache in some place other than the default, as
       mentioned above, you will need to use the same
       --prefix=/usr/local/apache2 option as used to configure Apache.
       You may also want to use --enable-mod-activation, which will
       automatically enable the required Subversion modules in the
       Apache config file.
    c) make
    d) make check
    e) make install (this activates mod_dav)
    f) make davcheck
       For this, start up Apache after having configured according to
       the directions in subversion/tests/cmdline/README.
       Make sure, that if you maintain a development installation of
       apache, that you check the config file and update it for the
       new release area where you're testing the tar-ball.
       (Unless you rename the tree which gets extracted from the
       tarball to match what's in httpd.conf, you will need to edit
    g) make svncheck
       First, start up svnserve with these args:
          $ subversion/svnserve/svnserve -d -r \
       -d tells svnserve to run as a daemon
       -r tells svnserve to use the following directory as the
          logical file system root directory.
       After svnserve is running as a daemon 'make svncheck' should run
    h) Then test that you can check out the Subversion repository
       with this environment:
          subversion/svn/svn co https://svn.apache.org/repos/asf/subversion/trunk
    i) Verify that the perl, python, and ruby swig bindings at least compile.
       If you can't do this, then have another developer verify.
       (see bindings/swig/INSTALL for details)
       Ensure that ./configure detected a suitable version of swig,
       perl, python, and ruby.  Then:
          make swig-py
          make check-swig-py
          sudo make install-swig-py
          make swig-pl
          make check-swig-pl
          sudo make install-swig-pl
          make swig-rb
          make check-swig-rb
          sudo make install-swig-rb

    j) Verify that the javahl bindings at least compile.
       If you can't do this, then have another developer verify.
       (see subversion/bindings/javahl/README for details)
       Ensure that ./configure detected a suitable jdk, and then
       possibly re-run with '--enable-javahl', '--with-jdk=' and
          make javahl
          sudo make install-javahl
          make check-javahl

    k) Verify that the ctypes python bindings at least compile.
       If you can't do this then have another developer verify.

       (see subversion/bindings/ctypes-python/README for details)

       Ensure that ./configure detected a suitable ctypesgen, and
       then possibly re-run with '--with-ctypesgen':

          make ctypes-python
          sudo make install-ctypes-python
          make check-ctypes-python 

    l) Verify that get-deps.sh works and does not emit any errors.


Use GnuPG to sign release:

Use release.py to sign the release:
    release.py sign-candidates X.Y.Z
This will run the equivalent of the following commands for you:
    gpg -ba subversion-X.Y.Z.tar.bz2
    gpg -ba subversion-X.Y.Z.tar.gz
    gpg -ba subversion-X.Y.Z.zip
and append gpg signatures to the corresponding .asc files.

Subversion Operations

Create the tag with the svn_version.h that reflects the final release. You do this using:

    release.py create-tag X.Y.Z 1234

Note: Please always make a tag, even for release candidates.

create-tag will bump the version number in the STATUS and svn_version.h files for the original branch. If you just did 1.0.2 then both files should have the proper value for 1.0.3 and so on.

Commit the tarballs, signatures and checksums to https://dist.apache.org/repos/dist/dev/subversion There is a release.py subcommand that automates this step:

release.py post-candidates 1.7.0

Announce that the candidates are available for testing and signing:

  • send an email to the dev@ list, something like this:

    Subject: Subversion X.Y.Z up for testing/signing
    The X.Y.Z release artifacts are now available for testing/signing.
    Please get the tarballs from
    and add your signatures there.
  • adjust the topic on #svn-dev to mention "X.Y.Z is up for testing/signing"

Update the issue tracker to have appropriate versions/milestones. If releasing a new minor release a version for 1.MINOR.x should be added. All releases should add a version for the next release (i.e. 1.MINOR.x+1). If you do not have permissions to do so please send an email to the dev@ list.

Signing source distribution packages (a.k.a tarballs)

Why releases are signed

Subversion releases are distributed through a global Content Distribution Network (CDN). (This replaced the former ASF mirror network as of late 2021. Nevertheless, there may exist other organizations that choose to continue mirroring ASF releases.)

It is important that end-users be able to verify the authenticity of the source code packages they download. Checksums are sufficient to detect corruption in the download process, but to prevent a malicious individual or mirror operator from distributing replacement packages, each source code package must be cryptographically signed by members of the Subversion PMC. These signatures are done using each committer's private PGP key, and are then published with the release so that end users can verify the integrity of the downloaded packages.

Voting and signing requirements

Before a Subversion release is officially made public, it requires:

  • three +1 votes from members of the Subversion PMC [ASF policy]
  • , and
  • testing and signatures from at least one PMC member on each of the major platforms we support: Windows and *nix [project policy]

How to sign a release

When creating the initial set of tarballs, the release manager will also create the first set of signatures. While the tarballs themselves may be built on people.apache.org, it is important that the signatures are not generated there. Signing tarballs requires a private key, and storing private keys on ASF hardware is strongly discouraged. After signing the tarballs (using the process below) the release manager should upload the signatures to the preliminary distribution location, and place them in the same directory as the tarballs.

Members of the PMC, as well as enthusiastic community members are encouraged to download the tarballs from the preliminary distribution location, run the tests, and then provide their signatures. The public keys for these signatures should be included in the ASF LDAP instance through id.apache.org. (A list of the current public keys of Subversion committers and PMC members is autogenerated from LDAP each day.) The release manager is encouraged to wait at least 5 days for the signatures before announcing the release to allow anybody testing the version to complete signing the release before its announcement.

Signing a tarball means that you assert certain things about it. When announcing your signature, indicate in the mail what steps you've taken to verify that the tarball is correct, such as verifying the contents against the proper tag in the repository. Running make check over all RA layers and FS backends is also a good idea, as well as building and testing the bindings.

To obtain the release candidate, check out a working copy of https://dist.apache.org/repos/dist/dev/subversion. Verify the release manager's PGP signatures on the tarballs. release.py automates this step:

    release.py get-keys
    release.py --target /path/to/dist/dev/subversion/wc check-sigs 1.7.0-rc4

After having verified, extracted, and tested the tarball, you should sign by creating an armored detached signature using gpg. To append your signature to a .asc file, use a command like:

    gpg -ba -o - subversion-1.7.0-rc4.tar.bz2 >> subversion-1.7.0-rc4.tar.bz2.asc
The release.py script can automate this step:
 release.py --target /path/to/dist/dev/subversion/wc sign-candidates 1.7.0-rc4

After adding your signatures, commit the locally modified .asc files to the dist.apache.org repository.

If you've downloaded and tested a .tar.bz2 file, it is possible to sign a .tar.gz file with the same contents without having to download and test it separately. The trick is to extract the .bz2 file, and pack it using gzip like this:

    bzip2 -cd subversion-1.7.0-rc4.tar.bz2 \
    | gzip -9n > subversion-1.7.0-rc4.tar.gz

The resulting file should be identical to the file generated by the release manager, and thus can be signed as described above. To verify that the files are identical, you may use either the checksums or the release manager's signature, both of which should be provided with the tarballs.

But, if the checksum is not identical it doesn't have to be the case that the file signature is wrong, or the file has been tampered with. It could very well be the case that you don't have an identical gzip version as the release manager.

The actual releasing

After the tarballs are created, and all the signatures are created and validated, the release is ready for publication. This section outlines the steps needed to publish a Subversion release.

Uploading the release

Subversion artifacts are distributed through a global Content Distribution Network (CDN). The source code download page automatically assists users in selecting a suitable download link. We usually host only the latest stable release for the supported release lines on the project's distribution directory, while all previous Subversion releases are available in the archives.

To upload a release to the CDN:

release.py move-to-dist 1.7.0
This moves the tarballs, signatures and checksums from ^/dev/subversion to ^/release/subversion. It takes the content delivery network (CDN) approximately 15 minutes to pick up the new release. The archive will also automatically pick up the release. Although running move-to-dist will move the signature files, committers are still able to commit new signatures to ^/release/subversion; however it will take up to 15 minutes for those signatures to appear on the CDN. Any such signatures cannot be included in the release announcement unless 15 minutes have passed since they were committed.

At this point, the release may be publicly available, but its still a good idea to hold off on announcing it until after the CDN has picked it up. After the 15 minute period has passed, giving the CDN enough time to sync, the release manager will send the announcement and publish the changes to the Subversion website, as described below.

It's also a good time to clean out any old releases from ^/release/subversion; only the most recent release for each supported release line should be in that directory. Releases that have been available at ^/release/subversion for at least 24 hours will continue to remain available in the archives. You can clean old releases using:

release.py clean-dist

Submit the version number of the new release on reporter.apache.org. The following command

curl -u USERNAME "https://reporter.apache.org/addrelease.py?date=`date +%s`&committee=subversion&version=VERSION&xdate=`date +%F`"
will add the release, it should probably be added to release.py.

Update the website

Even though the steps below indicate to update the published website directly, you may prepare the changes on ^/subversion/site/staging. In that case:

  • Do a catch-up merge from ^/subversion/site/publish.

  • Commit any changes to ^/subversion/site/staging and check the results on https://subversion-staging.apache.org.

  • When ready to publish, merge the changes back to ^/subversion/site/publish (review the merge in case there are other changes on staging not ready to be merged).

For any release, including pre-releases (alpha/beta/rc):

  • Edit ^/subversion/site/publish/download.html to note the latest release. Use release.py write-downloads to generate the table. If this is a stable release, update the [version] or [supported] ezt macro definition (e.g. [define version]1.7.0[end]); If this is a pre-release, uncomment the <div id="pre-releases">; if this is a 1.x.0 release that obsoletes the pre-release, comment it back out.

  • Add new News item to ^/subversion/site/publish/news.html announcing the release. Add the same item to the News list on ^/subversion/site/publish/index.html, also removing the oldest News item from that page. Use release.py write-news to generate a template news item, which should then be customized. In the news item there is a section that should contain a link to the announcement mail. For now it is commented out, the link is added later. Check that the date is correct if you generated the template in advance of the release date.

In addition, if this is a stable release X.Y.Z (not alpha/beta/rc):

  • List the new release on ^/subversion/site/publish/doap.rdf

    There should be a <release> section for each supported minor release with the <created> and <revision> being updated to the current release date and patch release number. Do not change anything else in the file (in particular the <created> under <Project> is the date when the Subversion project was created).

  • List the new release on ^/subversion/site/publish/docs/release-notes/release-history.html

In addition, if this is a new minor release X.Y.0:

  • Update the community release support levels on the "Supported Versions" section of ^/subversion/site/publish/docs/release-notes/index.html

  • Update supported_release_lines in release.py, removing old lines as necessary.

  • Remove the "draft" warning from ^/subversion/site/publish/docs/release-notes/X.Y.html

  • Create or update the versioned documentation snapshots in ^/site/publish/docs/api/X.Y and ^/site/publish/docs/javahl/X.Y, and ensure that the "latest" symlinks which are siblings of those directories always point to the directories of the latest release series.


    make doc
    cp -a doc/doxygen/html $DOCS_WC/api/$VER
    cp -a doc/javadoc $DOCS_WC/javahl/$VER
    for D in $DOCS_WC/api $DOCS_WC/javahl; do
      svn add $D/$VER
      rm $D/latest && ln -s $VER $D/latest
    svn ci -m "In 'staging': Add $VER API docs." $DOCS_WC/api $DOCS_WC/javahl

    Update the links to the API docs on the index page docs/index.html#api.

Commit the modifications to "publish" (or merge them from "staging" to "publish") on the release date.

Press releases for 1.x.0 releases

New minor releases (numbered 1.x.0) may be accompanied by press releases. All details of the prospective press release are handled on the private@ list, in coordination with press@a.o.

As a rule of thumb, start a thread on private@ / press@ at the start of the soak; it is better to give press@ too long an advance warning than too short one.

Announcing the release

Write a release announcement, referring to previous ones for guidance. Remember to include the URL and checksums in the announcement! The release.py write-announcement subcommand creates a template announcement which can be customized for specific circumstances. If the release fixes security issues, pass the --security flag, in order to generate the correct Subject, Cc, and description in the output.

If the community support levels are changing with this release, be sure to update the recommended_release variable in release.py before using it to generate the announcement.

Send the announcement from your @apache.org email address. (Mail to announce@ will bounce if sent from any other address. For best results, follow the instructions on the committer email page and send your message through the official mail relay.) Ensure that your mailer doesn't wrap the URLs over multiple lines.

NOTE: We update the website before announcing the release to make sure any links in the release announcement are valid. After announcing the release, links to the release announcement e-mail are added to the website.

There are two announce@ mailing lists where the release announcement gets posted: The Subversion project's announce@subversion.apache.org list, and the ASF-wide announce@apache.org list. It is possible that your message to the ASF-wide announce@ list will be rejected. This generates a moderation notification with a Subject line such as: Returned post for announce@apache.org. The moderator who ordered the mailing list software to reject the message may neglect to sign their name to the rejection message, making the rejection anonymous, and the grounds for the rejection may be invalid. Be that as it may, keep calm and forward the rejection to the dev@ mailing list so the project can discuss whether anything needs to be done about it. (If necessary, announce@ mailing list moderators can be contacted via the announce-owner@ handle.)

If this is an X.Y.0 release, update the community support level at the very top of the STATUS files of any branches that have changed support status. This would usually be X.Y.x/STATUS, X.$((Y-1)).x/STATUS, and if the new release is an LTS release, then the oldest supported LTS branch's STATUS file as well.

It is then time for the release manager to go and enjoy his $favorite_beverage.

Creating and maintaining release branches

A new release branch is created for each new major and minor release. So, for example, a new release branch is created when preparing to release version 2.0.0, or version 1.3.0. However, when preparing to release 1.3.1 (a patch-version increment), the release branch created at the time of 1.3.0 is used.

If you are preparing for a patch release, then there is no release branch to create. You just pick up where you left off in the current minor version series release branch.

The time at which a new release branch needs to be created is fuzzy at best. Generally, we have a soft schedule of releasing a new minor version every 6 months. So, approximately 4 months after the previous minor release is a good time to start proposing a branch. But remember that this is flexible, depending on what features are being developed.

Preparing to create a new minor release branch

Creating a new minor release branch

Once people agree that a new release branch should be made, the Release Manager creates it with one of the following procedures (substitute A.B with the version you're preparing, eg. 1.3, or 2.0).

Automated Procedure with release.py

Most of the work to create a release branch can be automated by tools/dist/release.py:

Run this in an empty-ish directory where it will make some temporary checkouts:

release.py --verbose create-release-branch A.B.0

If not done previously, create the release notes template for the project website:

release.py --verbose write-release-notes A.B.0 > .../docs/release-notes/A.B.html
svn add .../docs/release-notes/A.B.html
svn ci -m "Add release notes template." .../docs/release-notes/A.B.html
Some steps are not automated by release.py and must be done manually—skip to the end of the following section, where they are highlighted:

Manual Procedure

Most of the steps in this section can be automated by tools/dist/release.py—see above—but are documented here in case the Release Manager wants to do them manually:

  • Create the new release branch with a server-side copy:

          svn cp ^/subversion/trunk \
                 ^/subversion/branches/A.B.x \
                 -m "Create the A.B.x release branch."
  • Edit subversion/include/svn_version.h on trunk and increment the version numbers there. Do not commit these changes yet.

    The version number on trunk always reflects the major/minor version that will immediately follow the one for which you just created a branch (eg. 2.1.0 for the 2.0.x branch, and 1.4.0 for the 1.3.x branch).

  • Edit subversion/bindings/javahl/src/org/apache/subversion/javahl/NativeResources.java on trunk and increment SVN_VER_MINOR. Do not commit these changes yet.

  • Edit subversion/tests/cmdline/svntest/main.py on trunk and increment SVN_VER_MINOR. Do not commit these changes yet.

  • Edit CHANGES on trunk to introduce a new section for the upcoming release if it is not already there, and also a new section for the next minor release to be made in the future. Each section starts with:

          Version A.B.0
          (?? ??? 20XX, from /branches/A.B.x)

    Leave the release date blank for now. It will remain this way until rolling time.

  • Commit these changes with a log message something like the following:

          Increment the trunk version number to A.$((B+1)), and introduce a new CHANGES
          section, following the creation of the A.B.x release branch.
          * subversion/include/svn_version.h,
              (SVN_VER_MINOR): Increment to $((B+1)).
          * CHANGES: New section for A.$((B+1)).0.
  • Create a new STATUS file on the release branch.

  • Make sure all buildbot builders are building the new release branch.

    Add A.B to the MINOR_LINES list in https://svn.apache.org/repos/infra/infrastructure/buildbot/aegis/buildmaster/master1/projects/subversion.conf.

  • Create a template release-notes document, site/publish/docs/release-notes/A.B.html

The following steps must be done manually, even when using release.py to automate most of the other steps:
  • Ask someone with appropriate access to add the A.B.x branch to the backport merge bot.

  • Decide whether the release would be regular or LTS and record the decision in lts_release_lines in tools/dist/release-lines.yaml for release.py.

Managing the Backport Merge Bot

The backport merge bot runs nightly on the svn-qavm1 machine, under the svnsvn local user account, making commits using the svn-role Subversion account name.

This configuration currently requires someone with admin access to the machine, to manage changes to the set of branches.

The bot merges approved backports on each branch A.B.x for which a WC directory exists at ~svnsvn/src/svn/A.B.x .

The checkout there was created by running (as svnsvn user, e.g. with sudo) something like:

svn checkout --depth=empty https://svn-master.apache.org/repos/asf/subversion/branches ~svnsvn/src/svn
svn up ~svnsvn/src/svn/A.B.x  # for each supported branch

The repo URL is svn-master.a.o because the backports merger runs svn ci && svn up in a loop, and assumes svn up will update it to the revision it just committed. That's not guaranteed when updating from a mirror (and svn.a.o may point to a mirror). The buildbot slaves do this too, for the same reason.

Each branch is in a subdirectory of the WC root. To add a new branch, populate the source tree with svn up:

sudo -H -u svnsvn  svn up ~svnsvn/src/svn/A.B.x

To remove a no-longer-supported branch, use svn up -r0:

sudo -H -u svnsvn  svn up -r0 ~svnsvn/src/svn/Z.Z.x

More notes on the setup can be found in machines/svn-qavm1/ and in the Subversion PMC's private repository. There are also historical notes on previous incarnations in the history of machines/.

Porting changes to a release branch

Once a release branch has been created, no development ever takes place there. The only changes permitted are ones made to various bookkeeping files such as STATUS, and changes merged in from trunk. In rare cases, a feature branch may be created from the A.B.x branch to address issues specific to the release branch (for example, to fix a bug that does not affect trunk).

The protocol used to accept or refuse the merging of changes from trunk is of interest to all Subversion developers, and as such is documented in the release stabilization section.

Managing the CHANGES file

The CHANGES file is the project changelog file. Before a release, it must be brought up to date to list all changes since the last release.

Below, we describe the manual process. For partial automation, see

release.py write-changelog

For patch-releases, this is fairly easy: you just need to walk through the commit logs for the branch since the last "golden" revision, and note all interesting merges. For minor and major releases, this is more complex: you need to traverse the commit log on trunk since the last release branch was forked, and make note of all changes there. It's the same procedure, but a lot longer, and somewhat more complex as it involves filtering out changesets that have already been backported to previous release branches and released from there.

Remember that CHANGES should always be edited on trunk and then merged over to the release branch(es) when necessary. It is very important that all changes of all releases be documented in the CHANGES file on trunk, both for future reference and so that future release branches contain the sum of all previous change logs.

Keep the bullet point for each change concise, preferably no more than one line long. Sometimes that can be a challenge, but it really adds to the overall readability of the document. Think to yourself: If it takes more than one line to describe, maybe I'm getting too detailed?

Writing the initial content for a branch

Run svn log --stop-on-copy ^/subversion/branches/A.B.x. This should give you every change ever made to the A.B.x line, including backports made to the A.B.x branch. You then need to remove logs of changes that have already been released in micro releases of the previous major/minor branch. Run svn log -q --stop-on-copy on the previous release branch, and then write a script to parse the revnums and remove them from your primary log output. (Karl and Ben used to use emacs macros to do that, but suggest that we write a more general script.) (Update: nowadays, svn mergeinfo --show-revs eligible should simplify obtaining the set of relevant revisions—use the minor branch as the source, and the previous minor branch as the target.)

Read that log from oldest to newest, summarizing points as you go. The trick is to know what level of detail to write at: you don't want to mention every tiny little commit, but you don't want to be too general either. Set your filter-level by reading through a few pages of the CHANGES file before starting on the new section, just to keep things consistent.

Adding content for patch release

As part of release stabilization, CHANGES should be updated as bug fixes are ported to the release branch. Generally, if you merge a revision or group of revisions (i.e., an item in STATUS) to the release branch, you should also add an item to CHANGES on trunk, following the same guidelines outlined above. This list will then be merged to the release branch when a patch release is made.

In practice, CHANGES does not get updated each time a fix is backported to the release branch. Normally, the release manager updates CHANGES as one of the first steps to make a patch release.

A convenient way to get the list of backports that should be mentioned in CHANGES is to use the same tool that populates Coming up in the next patch release on the Subversion website. This is the upcoming.py script in https://svn.apache.org/repos/asf/subversion/site/tools. Run it while the current working directory is the root of a working copy of the minor branch.

How not to make a Subversion release

For an enlightening case study of the bungled Subversion 1.5 release cycle, see this paper.