After rewriting the history of a repository with git filter-branch
, all the SHAs change.
Now, if that repository (let's call it X
) is used as a git submodule in another repository (let's call it Y
), we have a problem.
Indeed, Y
knows what version of the submodule X
to load based on the SHA of the commit in that submodule. Since all the SHAs in X
have now changed, Y
points to SHAs that no longer exist.
Is there a way to rewrite the history of Y
such that it points to the new commit SHAs of the submodule X
(both in current and past commits)?
I would guess that given a correspondence between old SHAs and new ones, this is possible in principle, but I am afraid it would involve nasty bash scripts.
Is there anything easier?
Cloning a Project with Submodules If you pass --recurse-submodules to the git clone command, it will automatically initialize and update each submodule in the repository, including nested submodules if any of the submodules in the repository have submodules themselves.
Merging the submodule In the main repository run the commands: git remote add models-origin [email protected]/exampleUser/models. git fetch models-origin. git merge --allow-unrelated-histories models-origin/master.
In most cases, Git submodules are used when your project becomes more complex, and while your project depends on the main Git repository, you might want to keep their change history separate. Using the above as an example, the Room repository depends on the House repository, but they operate separately.
You can't just clone the repo any more, you have to clone recursively. You can't just checkout branches any more, you have to init and update the submodules too, with extra complications if the same submodules don't exist in all branches. You can't just commit/push, you have to commit/push the submodules first.
but I am afraid it would involve nasty bash scripts.
I am afraid it does.
Is there anything easier?
Not that I know of.
Here are some clues (not a full-fledged script) of what you would need for that script to work:
If you still have access to the rewritten repo, its original history (before the filter-branch) is kept in .git/refs/original
.
That means you can loop for that old history SHA1:
git -C /path/to/rewritten/repo for-each-ref --format="%(refname)" refs/original
If the changes were limited to one branch, you can match easily the new SHA1 with the old one (the first old one matches the first commit of the rewritten branch, the second old one... and so on)
If not, you would have to look for a revs in order to find a match (same date, sane commit message)
git rev-list --all \
| while read commit
do
...
Make sure the parent repo updates its refs for the submodule:
cd parent/repo
cd asubmodule
git fetch
That way, the new SHA1 are available.
Finally, you can do a filter-branch in the parent repo, looking for a gitlink, special entry in the index, matching one of the old SHA1.
For each match, you checkout the new SHA1 in the submodule folder, get back one level up to the parent repo, add and commit: that will record a new gitlink SHA1.
cd parent/repo/asubmodule
git checkout <new SHA1>
cd ..
git add .
git commit -m "Record new SHA1 for asubmodule"
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With