Updating Semantic Version between multiple developers

Viewed 227

I've been thinking about semantic versioning recently and thought of a hypothetical situation that I can't quite seem to reconcile.

My understanding of the Semantic Versioning Scheme is as follows:

A particular unique state of computer software can be identified with a 3-part version number of the form:

M.m.p

Where

  • M = Major #
  • m = Minor #
  • p = patch #

A major change is any change to the software such that the new version with the change is no longer compatible with the previous version before the change. A minor change is any feature added or removed from the software that does not compromise compatibility with its previous version before the change. and any change that fixes a bug or error is just a patch change. Whenever a major change occurs M is incremented and m and p are reset back to 0. Similarly when a minor change occurs m is incremented and p is reset back to 0. and patch changes merely increment p

(I know there are additional components of semantic versioning like -alpha, -beta and so on but for now I am keeping it simple and constrained to the above)

The Hypothetical situation that is confusing me is this:

Suppose a software project exists in a certain state X.Y.Z in a repository of a version control system (for the sake of the hypothetical lets assume this is Git/GitHub). Suppose there are two developer A and B for the software project. Each clones down a copy of the software project in state X.Y.Z in order to work on some change for it, both are working on a different change (they may be of the same type - M/m/p but the content is different).

Now suppose that developer A finishes their change (whether it be major, minor or patch) and pushes it to the repository (thereby changing the state of the software project to (X.Y.Z)+1 [again we don't know the nature of the change here]). And suppose they do this before developer B is finished with their changes.

How should this influence the work flow of developer B?

if A's change was just a patch should developer B just ignore the update and continue working on their change as if nothing happened (especially if their change was major)?

if A's change was minor or major should developer B scrap whatever progress they've made on their change and start over on the assumption that A's change will have influence on theirs (B's)?

With the nature of problem outline above how should updating semantic versions be handled between multiple developers?

2 Answers

Usually, this is handled by communication. Major versions are rare and planned, so they are overwhelmingly planned and communicated ahead of time.

For the difference between minor and patch versions, there's often some sort of branching scheme. For example, Git LFS uses a branch like release-3.1 for the 3.1.x branch and main for minor versions. All code goes into main, and then if a patch release needs to be done, the changes are cherry-picked into the release-* branches. The core team discusses the plans for the next release and whether they'd like to do a periodic minor release next or whether they think a patch release is necessary.

Of course, there are many other ways to handle this and this is just one. But communication among developers about expectations for the project and plans is going to be important anyway, so it's an ideal approach to decide the way the project would like to deal with managing this kind of issue.

This conundrum only arises as a product of a common misunderstanding about how versioning actually works. Ask yourself "what am I versioning here?".

It was a long standing practice to maintain the version number in a revision controlled file, where it could be modified by developers. In hind sight, it's a terrible practice, but actually made sense to us at the time. But let's stop and think about what it is we are versioning and look at how all the various artifacts are tracked in modern development systems.

One best practice today, that wasn't very common a couple decades ago, is to use a revision control system to automagically track changes to files. Developers no longer have to remember to bump a revision number at the top of each source file when they make changes. Instead, the RCS tracks file version when they are committed (not on every change!). Still most of the various RCS's offered a means to automatically update the source file header, but that practice is rarely used today because it's redundant/wasteful and does not scale well.

Another best practice today is to use some form of semantic versioning on publication artifacts, and there's a lot of variation in the tooling that supports that, but most of it is embedded in a handful of packaging tools and package archive services/feeds. Note that not every change in the source code requires a version bump here. The RCS tracks individual changes committed by developers and the release/publication management system determines the appropriate version to apply to the packaging artifacts.

The primary best practice today is the use of build pipelines. Modern DevOps best practice is to build the product on managed servers for all forms of publication. You typically have separate internal and external publication requirements, but they are all built in controlled, non-developer environments.

Add something like semantic commits (Brk, NB, NIB, and many other notations) to commit messages, automated test results and publication/release policies, and the appropriate version number to apply to any artifact can be derived automatically.

Suggested policies are:

  1. No single developer can publish an artifact to a public facing feed.
  2. Developer builds are versioned based on highest release version available for the repo hash they forked from, plus a -a.Dev. prerelease tag.
  3. No -a.Dev. prerelease artifact shall be shared beyond the developers own workstation.
  4. Continuous integration builds shall be published internally as YYYY.MMDD.Increment-a.Integration
  5. Etc.

Note that the possible variations are endless and determined by your organizations internal needs and commitments to customers.

Circling back on your conundrum, it should be obvious by now that it is a fallacy that the version number should be changed for every change in the source code. Modern tooling and best practices negate the need for it, and it is no longer desired.

If you look through my history of answers here, you should find several rants on why the RCS is not the correct place to track version numbers, but the primary reason is, we just don't use the RCS to store the artifacts we publish. It's okay to add publication tags to specific RCS states for developer convenience, but for CI/CD environments, the best place to keep the product version number, is in your publication feed system or an independent database.

Related