Search code examples
c++gitdependenciesgit-submodulesgit-subtree

I copy/pasted/modified a dependency in my project. This was not a smart dependency management strategy. How do I step back?


Context:

MainProject depends on a header-only dependency Module.

Both MainProject and Module are:

  • still under development and subject to modifications
  • modern CMake projects
  • independent repositories on Github
  • controlled by me

Problem:

Few months before, I tried without success to manage this dependency using CMake and versioning. Pressed by deadlines, I ended up opting for the "simplest solution" to copy-paste project Module headers in MainProject. Developing MainProject led to add features and modify interfaces in the Module local copy. Now there are two diverging Module.

How it could have worked

  • It could have worked if Module was very stable (copy/pasting headers is actually the solution I opted for dependencies that are stable and for which I don't have ownership).

  • I could have modified/commited/pushed/recopy/repasted the Module repository for every modification I wanted to bring. But of course I did not because ... time and deadlines.

Question

Now I would like to step back from this solution (ie, reflect the modifications on the initial Module project) and chose a better dependency management strategy.

What I can think of

  • create a new branch update on Module git project, copy-paste the modified version, commit it and use git diff to check the differences with branch master
  • use one or a combination of these three approaches (but I don't know how to chose)
    • git submodules
    • git subtrees
    • C++20 modules

Solution

  • Your Module project literally is a Git submodule: an independently-updated history, from which your MainProject builds use specific revisions.

    Developing MainProject led to add features and modify interfaces in the Module local copy. Now there are two diverging Module

    Quickest: from a clean checkout of your current MainProject revision,

    git tag slice $(git commit-tree -m slice @:path/to/Module)
    git rm -rf path/to/Module
    git submodule add u://r/l path/to/Module
    git push path/to/Module slice
    cd path/to/Module
    git read-tree -um slice
    git commit -m 'Module content from MainProject'
    

    and now you've got your content and ancestry looking serviceable, and you can add labels and push it wherever it needs to go, e.g. git checkout -b MainProjectModule; git push -u origin MainProjectModule

    If you've got a long history of Module changes in your main project that you want to preserve in the Module history proper, it's doable, and even fairly efficient, but you'll need to adapt some history surgery to achieve it, instead of tagging a nonce commit, tag the submodule commit that command produces and merge that rather than just adding its tip content as a new commit.