Reputation: 29096
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")
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.
Is there a way to either
I am working on embedded firmware development where each new project is composed of:
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).
Upvotes: 4
Views: 10282
Reputation: 14459
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:
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.
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.
Upvotes: 5