Diamond dependencies with 'includeBuild()' and git repos

Hello gradle community!

I’m currently trying to use composite builds in gradle with git submodules, everything went right when I didn’t have nested dependencies in a project. However, I’m struggling with one error due to diamond dependencies that I don’t know how to fix in a good way (I literally cannot find anything about doing this and this error in particular)

I have lots of small independent libraries that I include with includeBuild(). As an example, lets say that I have git repos A, B, C and D.

A depends on the api of B, C, D
B depends on the api of C, D

The settings.gradle.kts for A is:

includeBuild("dep/B") // in build.gradle.kts I use compileOnly("com.example.B:B-api")
includeBuild("dep/C") // in build.gradle.kts I use compileOnly("com.example.C:C-api")
includeBuild("dep/D") // in build.gradle.kts I use compileOnly("com.example.D:D-api")

rootProject.name = "A"

The settings.gradle.kts for B is:

includeBuild("dep/C") // in build.gradle.kts I use compileOnly("com.example.C:C-api")
includeBuild("dep/D") // in build.gradle.kts I use compileOnly("com.example.D:D-api")

rootProject.name = "B"

The other settings and build files for A, B, C and D are ommited for brevity.
(I must add that I use the same version of C and D in A and B)

When I try to run the build/jar task, gradle errors with:

Could not determine the dependencies of task ':compileJava'.
> Could not resolve all task dependencies for configuration ':compileClasspath'.
   > Could not resolve com.example.C:C-api.
     Required by:
         project :
      > Module version 'com.example.C:C-api' is not unique in composite: can be provided by [project :B:C:C-api, project :C:C-api].
   > Could not resolve com.example.D:D-api.
     Required by:
         project :
      > Module version 'com.example.D:D-api' is not unique in composite: can be provided by [project :B:D:D-api, project :D:D-api].

Can I do what I’m trying to do? That is, have nested includeBuilds with diamond dependencies in a manageable way? (I could just comment the includeBuild("dep/C") and includeBuild("dep/D"), however I would need to change the settings.build.kts of A each time a dependency changes its dependencies)

Thanks for the help in advance!

The problem is, that you have multiple work-trees for C and D.
So for Gradle these are separate builds that produce the same artifacts.
If A and B would include the same work-trees for C and D, it would work properly.
I’m not sure whether you can get it working with multiple work-trees of the same build within one composite build.

So, basically I can’t have recursive git submodules (for example). I need to supply my dependencies in a flattened includeBuild() directory tree, that is, only including once the dependency. Well, at least I can forward the responsibility of adding all the dependencies and transitive dependencies to the root project by checking gradle.parent every time I add includeBuilds, that should flatten everything.

I’ve partially solved the problem.
Thanks for your help!

Well, the problem might also be, that different Git submodules could point to different commits.

We use source dependencies for this and let Gradle do the cloning of the Git repos for the dependencies.