1

I'm working on a program developed in different variants: a common basic version and various customizations that not only use different logos and images but also add functionalities.

I'm trying to figure out what can be the best approach to saving the project inside our DVCS GIT (I was thinking of using gitea but I'm open to suggestions).

The code for the basic version must always be merged into customizations and never rarely the opposite.

I am in doubt whether to treat the custom versions as FORK of the basic version or as branches.

What may be the advantages and disadvantages of the two modes?

What are the best practices about it?

EDIT: My colleague's proposal was to manage custom versions in separate repositories that are populated through a batch copy of the source from the base version repository. My impression is that this is not a recommended practice. Isn't it?

5

We have to distinguish two kinds of versions:

  • VCS like Git store the development history of the software.
  • These versions have nothing to do with different editions or variants of the software.

Trying to conflate both is a recipe for pain.

Especially with Git, a commit represents a specific state of the software and not just a set of changes. So if you have a base branch and a branch for one software variant, merging between them always involves reconciling the current state of both variants. This is far more work than re-applying the same changes (which is possible in Git with git cherry-pick, but that creates a completely unrelated new commit without the history of the original commit).

For Git, a fork is effectively the same as a branch. Creating a separate forked repository has no particular technical advantages.

If Git branches are unsuitable for maintaining multiple variants of the software, what are they for? Branches are effectively floating tags that point to some commit. That makes them suitable to denote “the most recent X”, where X might be “the latest stable version” (e.g. for the master branch), or “the current development version” (if you have a development branch). Additionally, branches are suitable for concurrent threads of development. E.g. work can proceed independently on multiple feature branches until they are merged together.

How can we maintain multiple variants/editions if we cannot use branches? The trick is that you should only have one variant of your source code, and instead generate the editions through a build process or through configuration.

For example, you might want to create an app with different branding. Then create multiple asset bundles for each branding. When you build your app, select only the asset bundle for the variant you are currently developing. An “asset bundle” might be as simple as two directories customer-1/ and customer-2/ that each contain a banner.png image.

If you want variants that behave differently, things do get a bit more complicated. We can now use feature toggles and/or dependency injection to configure the behaviour of the software. This may happen at build time or run time. These toggles might be conditionals or ifdefs, but using dependency injection with the Strategy Pattern can keep your code simple.

E.g. if you have a standard edition and a pro edition, and some operation is only supported in the pro edition, then the code that performs this operation will behave differently depending on the configuration: the pro edition will just perform the operation, whereas the standard edition might hide the UI for that operation, or raise an exception, or prompt the user to upgrade.

By maintaining a single code base for all your variants, your code does become a bit more complex because it exhibits more configuration points and more possible code paths.

However, you do get a lot more flexibility and agility for your development:

  • You can make broad changes without having to tediously merge them into other variants.
  • In particular, you only need to fix bugs once for all your editions.
  • Common behaviour only has to be tested once.
  • Because you have one code base, you will see incompatibilities between various features earlier – and can fix them, before it's too late.

The last time I worked on a “one branch per customer” repository, this lead to considerable difficulties. A lot of work that would benefit all branches (like improved build processes, tests, and bug fixes) effectively had to be reimplemented for each branch because they had subtly diverged. As merges became increasingly inconvenient, code was copied and pasted between branches. One branch saw an extremely helpful refactoring that impacted all modules. Upon merging other branches, the refactoring work had to be effectively repeated in order to account for subtle modifications. I'd estimate we wasted around 10% – 30% of our effort through this setup, which in retrospect was far more than the time needed to add feature toggles to our build process – which we eventually had to do anyway.

  • Thanks for your reply. what do you think about my colleagues proposal? – sgargel Jun 1 '18 at 20:21
  • 1
    @sgargel Separate repositories have no technical advantages over using multiple branches. For Git they are practically equivalent, but some related tools such as issue trackers might treat them differently. The same drawbacks as using one branch per customer still apply. You might be able to do a batch copy or fork when creating a new branch or repository, but you will have increasing difficulties maintaining all of them and merging updates. Git is simply not well-suited for long-lived branches like this. If you try to fight it and use such branches or forks anyway, you will have a bad time. – amon Jun 1 '18 at 20:47
  • if Git is not well suited for that is there some other VCS you suggest for that scenario? – sgargel Jun 2 '18 at 6:46
  • OK.. I found also this answer that helped me to clarifying softwareengineering.stackexchange.com/questions/302147/… – sgargel Jun 2 '18 at 6:52
  • @sgargel Git is the de-facto industry standard. Even though Git is not perfect, it makes little sense to use anything else. Mercurial is one of the significant contenders, but I don't think it has technical advantages regarding this problem. – amon Jun 2 '18 at 10:07

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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