1919
2020from git .config import (
2121SectionConstraint ,
22+ GitConfigParser ,
2223cp
2324)
2425from git .exc import (
@@ -231,7 +232,7 @@ def _clone_repo(cls, repo, url, path, name, **kwargs):
231232
232233clone = git .Repo .clone_from (url ,module_checkout_path ,** kwargs )
233234if cls ._need_gitfile_submodules (repo .git ):
234- cls ._write_git_file (module_checkout_path ,module_abspath )
235+ cls ._write_git_file_and_module_config (module_checkout_path ,module_abspath )
235236# end
236237return clone
237238
@@ -258,10 +259,13 @@ def _to_relative_path(cls, parent_repo, path):
258259return path
259260
260261@classmethod
261- def _write_git_file (cls ,working_tree_dir ,module_abspath ):
262+ def _write_git_file_and_module_config (cls ,working_tree_dir ,module_abspath ):
262263"""Writes a .git file containing a (preferably) relative path to the actual git module repository.
263264 It is an error if the module_abspath cannot be made into a relative path, relative to the working_tree_dir
264265 :note: will overwrite existing files !
266+ :note: as we rewrite both the git file as well as the module configuration, we might fail on the configuration
267+ and will not roll back changes done to the git file. This should be a non-issue, but may easily be fixed
268+ if it becomes one
265269 :param working_tree_dir: directory to write the .git file into
266270 :param module_abspath: absolute path to the bare repository
267271 """
@@ -271,6 +275,10 @@ def _write_git_file(cls, working_tree_dir, module_abspath):
271275fp .write (("gitdir: %s" % rela_path ).encode (defenc ))
272276fp .close ()
273277
278+ writer = GitConfigParser (os .path .join (module_abspath ,'config' ),read_only = False ,merge_includes = False )
279+ writer .set_value ('core' ,'worktree' ,os .path .relpath (working_tree_dir ,start = module_abspath ))
280+ writer .release ()
281+
274282#{ Edit Interface
275283
276284@classmethod
@@ -629,7 +637,7 @@ def move(self, module_path, configuration=True, module=True):
629637
630638if self ._need_gitfile_submodules (self .repo .git ):
631639module_abspath = self ._module_abspath (self .repo ,self .path ,self .name )
632- self ._write_git_file (module_checkout_abspath ,module_abspath )
640+ self ._write_git_file_and_module_config (module_checkout_abspath ,module_abspath )
633641# end handle git file rewrite
634642# END move physical module
635643
@@ -668,7 +676,7 @@ def remove(self, module=True, force=False, configuration=True, dry_run=False):
668676"""Remove this submodule from the repository. This will remove our entry
669677 from the .gitmodules file and the entry in the .git/config file.
670678
671- :param module: If True, the module we point to will be deleted
679+ :param module: If True, the modulecheckout we point to will be deleted
672680 as well. If the module is currently on a commit which is not part
673681 of any branch in the remote, if the currently checked out branch
674682 working tree, or untracked files,
@@ -687,15 +695,25 @@ def remove(self, module=True, force=False, configuration=True, dry_run=False):
687695 we would usually throw
688696 :return: self
689697 :note: doesn't work in bare repositories
698+ :note: doesn't work atomically, as failure to remove any part of the submodule will leave
699+ an inconsistent state
690700 :raise InvalidGitRepositoryError: thrown if the repository cannot be deleted
691701 :raise OSError: if directories or files could not be removed"""
692702if not (module + configuration ):
693703raise ValueError ("Need to specify to delete at least the module, or the configuration" )
694- # END handle params
704+ # END handle parameters
705+
706+ # Recursively remove children of this submodule
707+ for csm in self .children ():
708+ csm .remove (module ,force ,configuration ,dry_run )
709+ del (csm )
710+ # end
695711
696- # DELETEMODULE REPOSITORY
697- ##########################
712+ # DELETE REPOSITORY WORKING TREE
713+ ################################
698714if module and self .module_exists ():
715+ mod = self .module ()
716+ git_dir = mod .git_dir
699717if force :
700718# take the fast lane and just delete everything in our module path
701719# TODO: If we run into permission problems, we have a highly inconsistent
@@ -715,7 +733,6 @@ def remove(self, module=True, force=False, configuration=True, dry_run=False):
715733# END apply deletion method
716734else :
717735# verify we may delete our module
718- mod = self .module ()
719736if mod .is_dirty (untracked_files = True ):
720737raise InvalidGitRepositoryError (
721738"Cannot delete module at %s with any modifications, unless force is specified"
@@ -747,19 +764,17 @@ def remove(self, module=True, force=False, configuration=True, dry_run=False):
747764del (remote )
748765# END for each remote
749766
750- # gently remove all submodule repositories
751- for sm in self .children ():
752- sm .remove (module = True ,force = False ,configuration = False ,dry_run = dry_run )
753- del (sm )
754- # END for each child-submodule
755-
756767# finally delete our own submodule
757768if not dry_run :
758769wtd = mod .working_tree_dir
759770del (mod )# release file-handles (windows)
760771rmtree (wtd )
761772# END delete tree if possible
762773# END handle force
774+
775+ if os .path .isdir (git_dir ):
776+ rmtree (git_dir )
777+ # end handle separate bare repository
763778# END handle module deletion
764779
765780# DELETE CONFIGURATION
@@ -786,7 +801,6 @@ def remove(self, module=True, force=False, configuration=True, dry_run=False):
786801
787802# void our data not to delay invalid access
788803self ._clear_cache ()
789-
790804return self
791805
792806def set_parent_commit (self ,commit ,check = True ):