24

I'm trying to ascertain best-practices for shared code amongst Git repositories.

So far, I've obviously come across submodules which seem like they - almost - fit the bill. My project is a PHP MVC framework with a simple structure:

  • /app
  • core.php
  • /core

Where app is a folder containing application-specific controllers, models, views etc. while core contains those of general use, e.g. a login controller. The core.php file itself is the global handler for all requests.

As such, the shared code amongst all of my deployments of this MVC framework is core.php and core.

I can see how it is possible to turn core into a Git submodule, but not core.php.

Is this even possible? Do I need to re-architecture my framework so that core.php resides inside the core folder so I can make the whole folder a submodule, or is there a better way?

Will Croft
  • 713
  • 3
  • 7
  • 18

3 Answers3

9

If you can use symlinks (e.g. you are not using Windows), then you can set up core and core.php like this:

# "base" repository layout:
core/
core.app

# each app repository layout:
base/
  core/
  core.php
core -> base/core/
core.php -> base/core.php
app/

In each app repository, the base/ directory is either a submodule that uses the “base” repository or a subtree merge of the “base” repository.

Both methods will let you start making changes to the base code in the context of a particular app and later pull those changes back into the main base repository. When using submodules you have to be careful to always publish new base commits before publishing any app commits that reference those new base commits (this is not a problem when using subtree merges because each app is “flat” and effectively has its own copy of the base).

The third-party git subtree command seems like a very nice way to manage the subtree merge, if you decide against submodules.

Subtree

git init newapp
cd newapp
ln -s base/core
ln -s base/core.php
git add core core.php
git commit -m'point to base (to be added next)'

# hook up base
git subtree add --prefix=base git@git.example.com:me/app_base.git master

mkdir app
# edit app/bar.php

# update base
git subtree pull --prefix=base git@git.example.com:me/app_base.git master

.
|-- .git/
|   |-- ...
|   `-- ...
|-- app/
|   `-- bar.php
|-- base/
|   |-- core/
|   |   `-- foo.php
|   `-- core.php
|-- core -> base/core/
`-- core.php -> base/core.php

Submodule

git init newapp
cd newapp
ln -s base/core
ln -s base/core.php
git add core core.php
git commit -m'point to base (to be added next)'

# hook up "base"
git submodule add git@git.example.com:me/app_base.git base
git commit -m'incorporate base'

mkdir app
# edit app/bar.php

# update base
(cd base && git fetch origin && git merge origin/master)
git add base
git commit -m'updated base'
.
|-- .git/
|   |-- ...
|   `-- ...
|-- .gitmodules
|-- app/
|   `-- bar.php
|-- base/
|   |-- .git/
|   |   |-- ...
|   |   `-- ...
|   |-- core/
|   |   `-- foo.php
|   `-- core.php
|-- core -> base/core/
`-- core.php -> base/core.php
Chris Johnsen
  • 214,407
  • 26
  • 209
  • 186
7

A submodule is a git repository, with its own .git directory, so it must be contained in a directory. I don't believe there's any way to easily get around that. You're going to have to package your stuff into a directory somehow - and if core.php goes with the stuff in core, it makes complete sense for them to be together in a submodule repo!

rmk's answer, suggesting you do this all in one repo, using core and core.php as a starting point is another reasonable one. You should make your decision based on your anticipated workflow. A submodule will be good if you plan on modifying the core* content separately from the projects which use it; you can then update the submodules in the various projects that use it. A baseline repository will be good if you want to modify the core* content to suit a specific project; you can then pull from the baseline repo to get updates, merging them with the changes you've made in the project repo.

Community
  • 1
  • 1
Cascabel
  • 479,068
  • 72
  • 370
  • 318
  • Thanks for the clear explanation Jefromi, I thought as much. My workflow is that I want collaborators to be able to edit `core*` files in either the application-specific repos or the framework's repo and have those changes merge-able in either direction without bringing application-specific code into the framework repo and without always having to resort to `git cherry-pick`. Does this make sense - and sound most feasible - with a submodule or rmk's solution? – Will Croft Nov 13 '10 at 16:52
  • 1
    @Will: There are two primary approaches there. Probably the simpler one is [`git-subtree`](https://github.com/apenwarr/git-subtree), which I've personally never used, but is all about merging and splitting subtrees from and back to projects. The other one would be to be very careful about development on core* files - do it all on topic branches that only have them, so that they can cleanly merge both into the core project and any other projects. – Cascabel Nov 13 '10 at 17:24
  • Thanks Jefromi, perfect. Looks like `git-subtree` is the way forward for me based on the Pro Git book's example. – Will Croft Nov 13 '10 at 17:48
7

Perhaps you are best off maintaining core.php and core in a separate repo, and then using it as a remote. Then you can manage it by pulling it into any project it is used. In order to do this, just start the new project as a separate git repo, and then pull in the 'core' repo as a subtree.

This chapter shows you how to do it:

Updated Reference: http://git-scm.com/book/en/v2/Git-Tools-Advanced-Merging#_subtree_merge Original Reference: https://git-scm.com/book/en/v1/Git-Tools-Subtree-Merging

It is a little better for you than the setup advised in the previous section of the book (6.6).

Look at it; it might be helpful.

Brandon Bertelsen
  • 43,807
  • 34
  • 160
  • 255
rmk
  • 4,395
  • 3
  • 27
  • 32
  • Thank-you rmk, definitely looks like `read-tree` is a viable solution. Just to clarify (and I think this is what the final paragraphs of your link indicate), is it therefore possible to make changes in my application repo to `core*` and merge that back into the framework's repo without bringing all the application-specific code and without `cherry-pick`? – Will Croft Nov 13 '10 at 16:47
  • Yes, you can push changes from your application repo to core via git-push. – rmk Nov 14 '10 at 03:09
  • 1
    Note: the progit book link is giving a 404. The original content is available at http://git-scm.com/book/en/v1/Git-Tools-Subtree-Merging (version 1 of the book), and version 2 of the book also has this same topic, as a sub-section of a broader page: http://git-scm.com/book/en/v2/Git-Tools-Advanced-Merging#_subtree_merge – lindes May 13 '15 at 21:32
  • looks like sparce-checkout is the answer: https://stackoverflow.com/questions/5303496/how-to-change-a-git-submodule-to-point-to-a-subfolder (check the top comment/answer) – Pencilcheck Nov 30 '22 at 10:25