I currently have a single pre-existing Git repo for a client/server solution that contains three subdirectories for 3 sub-projects:
/client - An Angular2 SPA application (client-side TypeScript)
/dtos - Language-agnostic web-service DTO (data contract) definitions written in T4
/client - T4-generated TypeScript typings *.d.ts files
/server - T4-generated C# DTO classes
/server - The web-service
So far this is all in a single master
branch, with appropriate temporary dev/
branches that are merged when their work is complete:
o--o--o--o - master
\ /
o-o - dev/foo
We need to do some A/B (or rather, A/B/C/D) testing on radically different UX options in the Angular2 project – I would like to branch-off for each UX option, to generate different builds we can test, then after our UX research is done we merge that specific branch back into master
for the remainder of the project:
o - master
\
o--o--o---o - ux/red-background
\
o--o----o - ux/new-sidebar
\
o--o - ux/new-sidebar-and-banner
However I only want to branch the /Client
directory off – so the /DTOs
and /Server
directories always contain the latest code.
In SVN and TFS this is easily doable because branches can be made from subdirectories, not just the entire repository (as they are with git), so if this were an SVN project then I would do something like this:
cd trunk # this is the solution root with the client, dtos and server directories
svn copy ^/trunk/client ^/branches/red-background
svn copy ^/branches/red-background ^/branches/new-sidebar
# then after some commits to 'new-sidebar'...
svn copy ^/branches/new-sidebar ^/branches/new-sidebar-and-banner
Then to build the solution with each different branch of /client
we modify the symlink:
cd trunk
# to 'checkout' the red-background version prior to building:
ln -s branches/red-background client
# or the new-sidebar version:
ln -s branches/new-sidebar client
The main advantage of this approach is that commits can continue to be made to the /dtos
and /server
directories without affecting client
at all – regardless of whatever branch of client
is being worked-in.
Whereas with git, a branch is a separate timeline entirely, so this scenario becomes impossible.
I understand that to get the result I want, I would still need to create different branches for each version to test or build, but changes to /dtos
or /server
would still need to happen in master
(just like in trunk
in SVN) but after every commit everyone working on the different client
branches would need to rebase
or merge
from master
, and that has the potential to get really ugly (especially if individual people rebase
from multiple commits to /server
choosing their own rebase points – they might end up with identical codebases but different commit hashes).
What's the solution?
(Another solution is to move client
to its own git repo – then merging it back into the solution repo when it's all done – I'm not opposed to this but let's pretend that we've hit our maximum repo count in our organizational GitHub account)
Best Answer
The ideal way is to move client to its own repository and make it a submodule of the super project. But if you do not want to create a new repository you can try one of these solutions.
Multiple directories in one branch
If you are able to configure your project to use directory /client_A instead of /client then you can clone the directory /client to multiple directories
and do separate development in each of these directories. Up to this point it is enough to use only master branch.
Later when you decide to "merge" directory /client_A to directory /client create a branch named e.g. branch_A. In this branch replace the content of directory /client with content of directory /client_A, delete directory /client_A and commit this state. Then merge branch_A to master and solve conflicts if any.
Do the same with directories /client_B and /client_C if you want to "merge" them with directory /client. You can choose different times for "merging" directories /client_A, /client_B and /client_C into directory /client.
Multiple branches without cloning directories
Choose a suitable start time and make as many branches from master as you want
From this start time use strictly
Use branch_A, branch_B, branch_C for building different versions of your project. Merge master branch into these branches before building. Avoid merging these branches into master branch (the opposite direction).
Later you can merge e.g. branch_A into master. But after doing this you can't merge master into branch_B or branch_C. This means that you need to choose suitable end time and merge all branches branch_A, branch_B, branch_C into master at this time.