We are doing projects, but we reuse a lot of code between the projects and have lots of libraries that contain our common code. As we implement new projects we find more ways to factor out common code and put it into libraries. The libraries depend on each other, and the projects depend on the libraries. Each project, and all libraries used in that project, need to use the same version of all the libraries they are referring to. If we release a piece of software we will have to fix bugs and maybe add new features for many years, sometimes for decades. We have about a dozen libraries, changes often cut across more than two, and several teams work on several projects in parallel, making concurrent changes to all these libraries.
We have recently switched to git and set up repositories for each library and each project. We use stash as a common repository, do new stuff on feature branches, then make pull requests and merge them only after review.
Many of the issues we have to deal with in projects requires us to do changes across several libraries and the project's specific code. These often include changes of library interfaces, some of which are incompatible. (If you think this sounds fishy: We interface with hardware, and hide specific hardware behind generic interfaces. Almost each time we integrate some other vendor's hardware we run into cases our current interfaces did not anticipate, and so have to refine them.) For example, imagine a project P1
using the libraries L1
, L2
, and L3
. L1
also uses L2
and L3
, and L2
uses L3
as well. The dependency graph looks like this:
<-------L1<--+
P1 <----+ ^ |
<-+ | | |
| +--L2 |
| ^ |
| | |
+-----L3---+
Now imagine a feature for this project requires changes in P1
and L3
which change the interface of L3
. Now add projects P2
and P3
into the mix, which also refer to these libraries. We cannot afford to switch them all to the new interface, run all the tests, and deploy the new software. So what's the alternative?
- implement the new interface in
L3
- make a pull request for
L3
and wait for the review - merge the change
- create a new release of
L3
- start working on the feature in
P1
by making it refer toL3
's new release, then implement the feature onP1
's feature branch - make a pull request, have this reviewed, and merged
(I just noticed that I forgot to switch L1
and L2
to the new release. And I don't even know where to stick this in, because it would need to be done in parallel with P1
...)
This is a tedious, error-prone, and very long process to implement this feature, it requires to independent reviews (which makes it much harder to review), does not scale at all, and is likely to put us out of business because we get so bogged down in process we never get anything done.
But how do we employ branching and tagging in order to create a process that allows us to implement new features in new projects without too much overhead?