问题
I have several branches with features in my Git repo.
Every feature is some foreign repo, plugged in as a submodule.
What should I do to correct switching between branches, with and without submodules?
Example:
$ git init
$ git commit -m "empty" --allow-empty
$ git checkout -b feature
$ git submodule init
$ git submodule add git://feature.git feature
$ git commit -a -m "add feature"
$ git checkout master
warning: unable to rmdir feature: Directory is not empty
And we have a feature in our master branch work directory.
How to prevent this?
回答1:
It seems the easiest way is manually deleting the submodule directories. The price is you have to git submodule init && git submodule update after every checkout.
To match the directories from .gitmodules:
grep path .gitmodules | sed 's/.*= //'
*From Prelang/gist/git-submodule-names
To remove it:
grep path .gitmodules | sed 's/.*= //' | xargs rm -rf
回答2:
git submodule deinit .
may do the trick
回答3:
With Git 2.27 (Q2 2020), the situation should improve, and "git checkout --recurse-submodules" works better with a nested submodule hierarchy.
See commit 846f34d, commit e84704f, commit 16f2b6b, commit 8d48dd1, commit d5779b6, commit bd35645 (17 Feb 2020) by Philippe Blain (phil-blain).
(Merged by Junio C Hamano -- gitster -- in commit fe87060, 27 Mar 2020)
unpack-trees: check for missing submodule directory in
merged_entryReported-by: Philippe Blain
Reported-by: Damien Robert
Signed-off-by: Philippe BlainUsing
git checkout --recurse-submodulesto switch between a branch with no submodules and a branch with initialized nested submodules currently causes a fatal error:$ git checkout --recurse-submodules branch-with-nested-submodules fatal: exec '--super-prefix=submodule/nested/': cd to 'nested' failed: No such file or directory error: Submodule 'nested' could not be updated. error: Submodule 'submodule/nested' cannot checkout new HEAD. error: Submodule 'submodule' could not be updated. M submodule Switched to branch 'branch-with-nested-submodules'The checkout succeeds, but the worktree and index of the first level submodule are left empty:
$ cd submodule $ git -c status.submoduleSummary=1 status HEAD detached at b3ce885 Changes to be committed: (use "git restore --staged <file>..." to unstage) deleted: .gitmodules deleted: first.t deleted: nested fatal: not a git repository: 'nested/.git' Submodule changes to be committed: * nested 1e96f59...0000000: $ git ls-files -s $ # empty $ ls -A .gitThe reason for the fatal error during the checkout is that a child git process tries to
cdinto the yet unexisting nested submodule directory.The sequence is the following:
The main git process (the one running in the superproject) eventually reaches
write_entry()in entry.c, which creates the first level submodule directory and then callssubmodule_move_head()in submodule.c, which spawnsgit read-treein the submodule directory.The first child git process (the one in the submodule of the superproject) eventually calls
check_submodule_move_head()atunpack_trees.c:2021, which callssubmodule_move_headin dry-run mode, which spawnsgit read-treein the nested submodule directory.The second child git process tries to
chdir()in the yet unexisting nested submodule directory instart_command()at run-command.c and dies before exec'ing.The reason why
check_submodule_move_head()is reached in the first child and not in the main process is that it is inside anif(submodule_from_ce())construct, andsubmodule_from_ce()returns a valid struct submodule pointer, whereas it returns a null pointer in the main git process.The reason why
submodule_from_ce()returns a null pointer in the maingitprocess is because the call tocache_lookup_path()inconfig_from()(called fromsubmodule_from_path()insubmodule_from_ce()) returns a null pointer since the hashmap"for_path"in thesubmodule_cacheofthe_repositoryis not yet populated.
It is not populated because bothrepo_get_oid(repo, GITMODULES_INDEX, &oid)andrepo_get_oid(repo, GITMODULES_HEAD, &oid)inconfig_from_gitmodules()at submodule-config.c return-1, as at this stage of the operation, neither the HEAD of the superproject nor its index contain any.gitmodulesfile.In contrast, in the first child the hashmap is populated because
repo_get_oid(repo, GITMODULES_HEAD, &oid)returns 0 as the HEAD of the first level submodule, i.e..git/modules/submodule/HEAD, points to a commit where.gitmodulesis present and records 'nested' as a submodule.Fix this bug by checking that the submodule directory exists before calling
check_submodule_move_head()inmerged_entry()in theif(!old)branch, i.e. if going from a commit with no submodule to a commit with a submodule present.Also protect the other call to
check_submodule_move_head()inmerged_entry()the same way as it is safer, even though theelse if (!(old->ce_flags & CE_CONFLICTED))branch of the code is not at play in the present bug.The other calls to
check_submodule_move_head()in other functions inunpack_trees.care all already protected by calls tolstat()somewhere in the program flow so we don't need additional protection for them.All commands in the
unpack_treesmachinery are affected, i.e. checkout, reset and read-tree when called with the--recurse-submodulesflag.This bug was first reported here.
来源:https://stackoverflow.com/questions/27265383/git-submodules-removing-on-checkout-another-branch