I have a library (npm package, LIB) which is used by the application code (APP). In a release of APP, multiple features are worked on parallely. Sometimes these features need support from LIB, so the changes need to happen there too and LIB used semvar.

When multiple features like F1 and F2 are being worked on in APP, LIB is released with let's say x.y.1 for F1 and then x.y.2 for F2. Problem is the features are being developed and tested in parallel and it's possible that F2 lands but F1 doesn't. In which case LIB's release x.y.2 contains undesirable code of x.y.1.

Right now I solve this using two methods:

  1. Optimistically release LIB, revert undesirable code and release x.y.3 which is basically x.y.2 without x.y.1. Issues with this approach are:

    • x.y.3 is a new release and is probably needed to be tested again.
    • Overhead of reverting versions.
  2. Use dirty code from LIB's F1 and F2 branches before releasing, to test APP. Once one of the feature is ready to land, the version is released. Let's say F2 is ready to land, then x.y.1 of LIB is released with support for F2 just in time. Issues with this approach are:

    • Overhead of releasing the dependency (LIB) versions just ahead of release of APP.
    • Unversioned code using git branches is hard to manage and prone to bugs. We use something similar to git flow and reverting features from release branch of LIB because F2 has to go makes for more errors as reverting can cause errors. Also, the testing stands invalidated as the new release branch will be (F1 + F2 - F1) while the tests were done on (F1 + F2).

Both of these solutions have issues. I want to know how to solve this scenario where parallel development meets sequential semvar and I realize that reverting features just before release is an issue and unusual practice.

Thanks in advance.

2 Answers 2


Separate the versioning and make it a function of release. This means the versioning of APP from LIB as well as with respect to functionality.

For both APP and LIB, version a set of cohesive changes. For example, if F1 and F2 are two sets of highly related changes, as soon as one is finished, incorporate them into LIB and have a tested LIB. If you decide to go ahead and release LIB, then you can increment the version appropriately. You can also wait for the other to be finished and version LIB based on the set of changes. Since you're using semantic versioning, there are rules for how and when to update each part of the version identifier.

You will need to keep your feature development environments synchronized with the upstream branch. Since you are using fixed releases, I would recommend having a stable master branch, a develop branch that is "version next", and various feature branches that are merged into develop when the feature is complete and tested. If develop has new changes, those would need to be incorporated into all feature branches still under development. You could take an approach like git flow with release branches or you could take other approaches with master being your release branch.

If you find that "unversioned code using git branches is hard to manage and prone to bugs", I would suggest that there are other problems going on and those are what you should solve, and not trying to develop a convoluted system of versioning and removing changes.

I've written a more extensive answer on where QA testing should happen in the git flow branching model. If you had unlimited time and resources, the answer is that QA should do work in multiple branches. In order to test a feature in isolation in otherwise known good software, the feature branch is the best place. However, in reality, most of the testing will likely happen in the develop branch as well as on release branches (if you're using them). It's up to the whole team to ensure quality going in.

Having automated tests will go a long way, especially with regard to regression testing. If you have a stable develop branch with passing tests (and those tests are of decent quality) and tests fail on a feature branch, you know that you either have out-of-date tests or have introduced a regression. Having people focus their efforts on exploratory testing and identification of new, interesting test cases for automation will go a long way. You'll find that manual testing doesn't scale. If it takes you 2-3 days to perform regression testing over N features/functionality now, what happens when you have 2N features/functionality implemented? You shouldn't fully replace manual testing, but you also shouldn't rely on it.

I'll also add that having an x.y.3 version that has removed functionality from x.y.2 is unusual.

  • I updated the question with more insights on our branching strategy. I do agree with you when you say there are other problems going on. In this context I think it will come down to, should the QA happen on develop branch or release branch or both?
    – tbking
    Commented May 19, 2020 at 10:34
  • @tbking I will take a look later on and edit this answer as necessary. I will ask, however - what do you mean by "QA"? Are you referring to manual testing, automated testing, or both? What is the scope of your automated test coverage?
    – Thomas Owens
    Commented May 19, 2020 at 10:44
  • By QA I mean manual testing mostly. The scope is to make sure the existing features have not broken, and the new features are working as expected. It usually is half a 2-3 days process. I imagine things will be lot easier if the testing is automated.
    – tbking
    Commented May 19, 2020 at 11:16
  • @tbking I think I've expanded on a few points that needed it. The short story is that if you want to have quality software, you'll need to move away from the reliance on manual regression and be able to run automated tests at the unit, integration, and system level and get feedback to developers faster than a 2-3 day manual regression cycle. Reliance on manual testing simply doesn't scale as your application and library grow in complexity. The problem isn't the branching model or versioning scheme, but having confidence that your new work isn't introducing regressions and is low in defects.
    – Thomas Owens
    Commented May 20, 2020 at 0:54

Make your build process smarter.

On a stream/feature build checkout the library on the same stream/feature and build it, locally link it, and then build the main project. If the Library doesn't have a complementary stream/feature branch then use the release version of the library.

In fact this should be part of your build script. So that developers get this for free when building locally.

When the stream is ready to go to release, merge the code into the mainline. Building from the mainline uses the released version of the library.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.