Search code examples
gitgit-submodules

Git merge submodule into parent tree cleanly and preserving commit history


I have a repository with two submodules that I want to convert into a single project. Many answers involve scripts, and some seem to be overcomplicated.

[submodule "site"]
    path = wp-content/themes/site
    url = https://ajf-@bitbucket.org/ajf-/site.git
    fetchRecurseSubmodules = true
    ignore = all
[submodule "wpsite"]
    path = wp-content/themes/wpsite
    url = https://ajf-@bitbucket.org/ajf-/wpsite.git
    fetchRecurseSubmodules = true
    ignore = all

Is there an officially supported / documented way to merge these submodules into the parent repository?


Solution

  • The best approach is to do subtree merging.

    First, remove the submodules and related configuration from your superproject; Edit your .gitmodules file to remove the submodules affected, or delete the file entirely if you intend to merge all submodules. Delete the submodule directories as well.

    Next, add the submodule repositories as proper remotes to your superproject:

    git remote add site https://ajf-@bitbucket.org/ajf-/site.git
    git remote add wpsite https://ajf-@bitbucket.org/ajf-/wpsite.git
    

    Then, fetch the remotes:

    git fetch --all
    

    Now, check out the branches that you want to graft to your main project from each sub-project:

    git checkout -b site-branch site/some_branch
    git checkout -b wpsite-branch wpsite/some_other_branch
    

    After that, return to the master branch, or to the branch where you want to create the combined superproject:

    git checkout master
    

    If you want to create a (possibly temporary) extra branch for the operation, do this instead:

    git checkout -b new-superproject master
    

    You're now ready to merge the module branches as subtrees with your main project (in the master branch in this example):

    git merge --strategy=ours --no-commit --allow-unrelated-histories site-branch
    git read-tree --prefix=site/ -u site-branch
    git commit -m "Merge 'site' from submodule"
    

    Repeat this step for all branches created from the submodules. Check the final result with gitk --all or another history visualizer.

    If you do not want to keep the history of the submodules, then only do the read-tree step and omit the merge/commit steps.

    Since you want to convert into a single project, you're not going to update the subprojects independently, so I'm not going to describe how that works.

    You can read up on this in the chapter on advanced merging from Pro Git. Subtree merging is explained at the end of the chapter, but omits the step that creates a proper merge commit, so it will not preserve history of the submodule.