1

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
WaterFox
  • 850
  • 6
  • 18

1 Answers1

1

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.

jthill
  • 55,082
  • 5
  • 77
  • 137
  • thank you for your answer, it points me towards a direction. I am not sure I follow the sequence of git commands and what they are intended for. Would you mind precising ? From what I understand, you create a tag to remember the current state, then you delete the module folder, then you create the submodule. At this point it contains the naive remote state. So somehow you tell it to retrieve the state of the previously deleted folder. Am I right ? I don't get the `git push path/to/Module slice` and the `git read-tree -um slice` command. Thanks again :) – WaterFox Dec 06 '20 at 22:35
  • 1
    The push pushes that ref, the tag (of just that one no-ancestry commit of just that tree), to the (freshly-cloned) repository at path. The `git read-tree -um` is the core command underlying checkout, it does only the index and work tree changes. – jthill Dec 06 '20 at 22:52