Split a GitHub repository into a main repos and a submodule
Context
We have a local folder MAIN associated with a GitHub repository, also called MAIN. The structure is as follows:
Goal
We want to:
- keep the structure of
MAIN - make a new folder
TOTOassociated with the content of2_dir_B - keep the history of
2_dir_Bin the new repository - (default) keep the history of
2_dir_Bin the main repository - define
2_dir_Bas a submodule ofMAIN
Method
- Make sure that the
MAINrepository is up-to-date with your local folder, usinggit pulland/orgit pushcommands.
Duplicate the MAIN repository
- Clone the
MAINrepository to initate the new one:
- Move to
TOTO:
Get all branches
- (optional) Get all the branches and tags from the
MAINrepository, because they have not been imported usinggit clone:
- (optional) If there are SOME branches to copy, run:
Detach from origin
- Detach the local repository
TOTOfrom theMAINrepository.
Subset the new repository
- Filter the directory to keep only the
2_dir_Bfolder. We should--forcebecause there is no origin.
- Move the
2_dir_Bfolder content to the root:
-
Add the untracked files from
MAINtoTOTO. This step can/should/must be done manually by using the graphical file explorer… -
Check that
TOTOcontains everything present inMAIN/2_dir_B:
- Ensure to ignore the folders and files that should not be tracked by the
gitsystem:
- Define the commit, but do not push since there is no remote yet.
Define the new repository
-
On GitHub, create a new empty (no README, no LICENSE) repository, for instance called
TITI. -
Define the new origin for the
TOTOfolder:
- Push the changes. We use
--forceif no file has been changed but only the git history has been filtered. We use--allto include all the branches.
Define a submodule in MAIN
- Go to the
MAINdirectory:
- Remove the
2_dir_Bfolder, both from tracking and locally:
- (optional) To eventually remove this folder from the history, use
git filter-branch.
Note: I don’t know how to modify this to apply it on all branches. Actually, one should use git filter-repo --path 2_dir_B/ --invert-paths to remove a folder from history. But, it removes also the remote so I have no idea how to make it works.
- Define
2_dir_Bas a submodule ofMAIN. It creates a.gitmodulesfile.
That’s all ! :smile:
Output
The MAIN directory has not changed:
However, on the MAIN GitHub repository, 2_dir_B points to the last commit synchronized. For instance 2_dir_B @3c8464b.
The TOTO folder contains:
On the TITI GitHub repository, there is no trace of the MAIN, but the history of all the tracked files is conserved from their creation in the MAIN repository.
Resources
Useful resources: