1

In the following example I want to demonstrate that making changes to a Git sub-module and commit it locally can lead to a very bad situation in which I would like to find a working solution (other than the answer "Dude, don't use Git sub-modules it's evil")

The example

I first create two repositories: a main project and its sub-module:

~ $ for r in main sub; do mkdir $r; cd $r; git init; cd ..; done
Initialized empty Git repository in ~/main/.git/
Initialized empty Git repository in ~/sub/.git/

Let's put some content to the sub-module:

~/ $ cd sub
~/sub $ touch sub && git add sub
~/sub $ git commit -m "Added sub"
[master (root-commit) a14ce2f] Added sub
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 sub

Then we import that submodule in the main project:

~/sub $ cd ../main
~/main $ git submodule add ../sub sub
Cloning into '~/main/sub'...
done.
~/main $ git commit -am "Added submodule sub"
[master (root-commit) bd37219] Added submodule sub
 2 files changed, 4 insertions(+)
 create mode 100644 .gitmodules
 create mode 160000 sub

Now the very question: the monkey patch where I want to modify the sub-module locally.

~/main $ cd sub
~/main/sub $ echo "Monkey patched"" >> sub
> echo "Monkey patched"^C>> sub
~/main/sub $ echo "Monkey patched" >> sub
~/main/sub $ git commit -am "Local hotfix"
[master 0b37958] Local hotfix
 1 file changed, 1 insertion(+)
~/main/sub $ ..
~/main $ git commit -am "Hijacked sub-module"
[master 1b3a4af] Hijacked sub-module
 1 file changed, 1 insertion(+), 1 deletion(-)

Everything looks beautiful because it seems so, but the evil is there.

Alice wants to work on that project so she clone the main repository (let's imagine instead that the main repository was pushed somewhere on the hub by Bob)

~/main $ ..
~/test $ git clone main alice
Cloning into 'alice'...
done.
~/test $ cd alice
~/alice $ git submodule init
Submodule 'sub' (~/sub) registered for path 'sub'

So far Alice is happy until this moment:

~/alice $ git submodule update
Cloning into '~/sub'...
done.
error: Server does not allow request for unadvertised object 0b3795831f31cf8e9c4444a021936c12210e24c6
Fetched in submodule path 'sub', but it did not contain 0b3795831f31cf8e9c4444a021936c12210e24c6. Direct fetching of that commit failed.

If is clear that Git didn't keep track of the monkey patch on the main repository, but on the local history of the sub-module instead.

This looks to me like a design failure of Git sub-modules, or I just misunderstood something that I am asking for today.

The main question

Is there a way to either

  • allow to hijack a Git sub-module locally or,
  • prevent users that are new to Git to do it so?

Why do I want to modify a sub-module locally?

I am working on embedded firmware development where each new project is composed of:

  • A development framework
  • A SDK related to the MCU I am using
  • Sub-modules which are the drivers for each physical components (bluetooth IC, io expander, led driver, ...) I am using on my board

It sometime happens that I need to monkey patch the code-base of a physical component. For example I want to extend the native range of the bluetooth IC by boosting the radio power (which is not a feature normally allowed by the driver).

too honest for this site
  • 11,417
  • 3
  • 27
  • 49
nowox
  • 19,233
  • 18
  • 91
  • 202

1 Answers1

3

Edit

My answer below if a bit off. The question here is how to change things locally without publishing it in the submodules' remote repository (since this is not always possible), but still allowing others to work with your changes.

You have to publish your changes to your teammates in some way. Thus, the changes cannot stay solely in your submodule. One of the following would achieve that:

  • Fork the repository in question and add your forked repository as a submodule. This way, you "own" the repo and can modify all you want and push the changes to your own forked remote repo.
  • Make the submodule part of your own repository: You can just merge the "submodule" repository to make it part of your own repository (for example as explained here).

Old answer

It's perfectly fine to modify a submodule locally. The one most important thing you have to remember is:

Push a submodule change in your main repository only after you pushed the changes in the submodule repository.

This is not really covered by your example, since you do not push to a remote server. I'm looking at a centralized workflow here, since that is what most people do in my experience.

When you modify a submodule, commit, and also commit the submodule changes in the main repository, but only push the latter, the remote main repository references a submodule commit that is not known on the server side, producing the Server does not allow request for unadvertised object error. When you push your submodule changes to the submodules' repository first, and then the main repository changes, Alice can just clone the main repo, initialize and update the submodule and go with your changes.

In your Example

The problem in your example now is that you modified the submodule only in ~/main/sub, but not in the submodule repository itself (the one in ~/sub/). When Alice clones from ~/main/, the submodule references ~/sub/, where the commit you updated to is not known. You would have to push your changes to ~/sub/ to make the commit publicy available, before you let anyone obtain the updated submodule commit in your main repository.

kowsky
  • 7,265
  • 1
  • 23
  • 37
  • If you push your changed to the `sub` repo it is not local patch anymore and you might compromise a repository that don't belong to you. Worse, it most likely unfortunate you can even push on that repository. – nowox Aug 01 '17 at 10:16
  • That's why I am starting to believe that subtree is perhaps a better solution in my case. – nowox Aug 01 '17 at 10:17
  • Ah, now I get it. You want your patch to stay local without publishing it in the remote repository, but still want others to be able to work on your patched submodule. It might be a better solution to make the submodule part of your main repository, then. – kowsky Aug 01 '17 at 10:28