@@ -104,6 +104,7 @@ def write(self):
104104 return rval
105105 # END overridden methods
106106
107+
107108class Submodule (base .IndexObject , Iterable , Traversable ):
108109 """Implements access to a git submodule. They are special in that their sha
109110 represents a commit in the submodule's repository which is to be checked out
@@ -172,7 +173,10 @@ def _get_intermediate_items(self, item):
172173
173174 def __eq__ (self , other ):
174175 """Compare with another submodule"""
175- return self .path == other .path and self .url == other .url and super (Submodule , self ).__eq__ (other )
176+ # we may only compare by name as this should be the ID they are hashed with
177+ # Otherwise this type wouldn't be hashable
178+ # return self.path == other.path and self.url == other.url and super(Submodule, self).__eq__(other)
179+ return self ._name == other ._name
176180
177181 def __ne__ (self , other ):
178182 """Compare with another submodule for inequality"""
@@ -185,6 +189,9 @@ def __hash__(self):
185189 def __str__ (self ):
186190 return self ._name
187191
192+ def __repr__ (self ):
193+ return "git.%s(name=%s, path=%s, url=%s, branch=%s)" % (type (self ).__name__ , self ._name , self .path , self .url , self .branch )
194+
188195 @classmethod
189196 def _config_parser (cls , repo , parent_commit , read_only ):
190197 """:return: Config Parser constrained to our submodule in read or write mode
@@ -459,23 +466,29 @@ def update(self, recursive=False, init=True, to_latest_revision=False):
459466 return self
460467
461468 @unbare_repo
462- def move (self , module_path , module_only = False ):
469+ def move (self , module_path , configuration = True , module = True ):
463470 """Move the submodule to a another module path. This involves physically moving
464471 the repository at our current path, changing the configuration, as well as
465472 adjusting our index entry accordingly.
466473 :param module_path: the path to which to move our module, given as
467474 repository-relative path. Intermediate directories will be created
468475 accordingly. If the path already exists, it must be empty.
469476 Trailling (back)slashes are removed automatically
470- :param module_only: if True, only the repository managed by this submodule
477+ :param configuration: if True, the configuration will be adjusted to let
478+ the submodule point to the given path.
479+ :param module: if True, the repository managed by this submodule
471480 will be moved, not the configuration. This will effectively
472481 leave your repository in an inconsistent state unless the configuration
473- and index already point to the target location.
482+ and index already point to the target location.
474483 :return: self
475484 :raise ValueError: if the module path existed and was not empty, or was a file
476485 :note: Currently the method is not atomic, and it could leave the repository
477486 in an inconsistent state if a sub-step fails for some reason
478487 """
488+ if module + configuration < 1 :
489+ raise ValueError ("You must specify to move at least the module or the configuration of the submodule" )
490+ #END handle input
491+
479492 module_path = to_native_path_linux (module_path )
480493 if module_path .endswith ('/' ):
481494 module_path = module_path [:- 1 ]
@@ -494,54 +507,64 @@ def move(self, module_path, module_only=False):
494507 index = self .repo .index
495508 tekey = index .entry_key (module_path , 0 )
496509 # if the target item already exists, fail
497- if not module_only and tekey in index .entries :
510+ if configuration and tekey in index .entries :
498511 raise ValueError ("Index entry for target path did alredy exist" )
499512 #END handle index key already there
500513
501514 # remove existing destination
502- if os .path .exists (dest_path ):
503- if len (os .listdir (dest_path )):
504- raise ValueError ("Destination module directory was not empty" )
505- #END handle non-emptyness
506-
507- if os .path .islink (dest_path ):
508- os .remove (dest_path )
515+ if module :
516+ if os .path .exists (dest_path ):
517+ if len (os .listdir (dest_path )):
518+ raise ValueError ("Destination module directory was not empty" )
519+ #END handle non-emptyness
520+
521+ if os .path .islink (dest_path ):
522+ os .remove (dest_path )
523+ else :
524+ os .rmdir (dest_path )
525+ #END handle link
509526 else :
510- os .rmdir (dest_path )
511- #END handle link
512- else :
513- # recreate parent directories
514- # NOTE: renames() does that now
515- pass
516- #END handle existance
527+ # recreate parent directories
528+ # NOTE: renames() does that now
529+ pass
530+ #END handle existance
531+ # END handle module
517532
518533 # move the module into place if possible
519534 cur_path = self .abspath
520- if os .path .exists (cur_path ):
535+ renamed_module = False
536+ if module and os .path .exists (cur_path ):
521537 os .renames (cur_path , dest_path )
538+ renamed_module = True
522539 #END move physical module
523540
524- # NOTE: from now on, we would have to undo the rename !
525541
526542 # rename the index entry - have to manipulate the index directly as
527543 # git-mv cannot be used on submodules ... yeah
528- if not module_only :
529- try :
530- ekey = index .entry_key (self .path , 0 )
531- entry = index .entries [ekey ]
532- del (index .entries [ekey ])
533- nentry = git .IndexEntry (entry [:3 ]+ (module_path ,)+ entry [4 :])
534- index .entries [tekey ] = nentry
535- except KeyError :
536- raise ValueError ("Submodule's entry at %r did not exist" % (self .path ))
537- #END handle submodule doesn't exist
538-
539- # update configuration
540- writer = self .config_writer (index = index ) # auto-write
541- writer .set_value ('path' , module_path )
542- self .path = module_path
543- del (writer )
544- # END handle module_only
544+ try :
545+ if configuration :
546+ try :
547+ ekey = index .entry_key (self .path , 0 )
548+ entry = index .entries [ekey ]
549+ del (index .entries [ekey ])
550+ nentry = git .IndexEntry (entry [:3 ]+ (module_path ,)+ entry [4 :])
551+ index .entries [tekey ] = nentry
552+ except KeyError :
553+ raise InvalidGitRepositoryError ("Submodule's entry at %r did not exist" % (self .path ))
554+ #END handle submodule doesn't exist
555+
556+ # update configuration
557+ writer = self .config_writer (index = index ) # auto-write
558+ writer .set_value ('path' , module_path )
559+ self .path = module_path
560+ del (writer )
561+ # END handle configuration flag
562+ except Exception :
563+ if renamed_module :
564+ os .renames (dest_path , cur_path )
565+ # END undo module renaming
566+ raise
567+ #END handle undo rename
545568
546569 return self
547570
@@ -917,7 +940,7 @@ def update(self, previous_commit=None, recursive=True, force_remove=False, init=
917940 ##################
918941 cur_commit = repo .head .commit
919942 if previous_commit is None :
920- symref = SymbolicReference ( repo , SymbolicReference . to_full_path ( 'ORIG_HEAD' ) )
943+ symref = repo . head . orig_head ( )
921944 try :
922945 previous_commit = symref .commit
923946 except Exception :
@@ -936,8 +959,8 @@ def update(self, previous_commit=None, recursive=True, force_remove=False, init=
936959
937960
938961 # HANDLE REMOVALS
939- psms = type ( self ) .list_items (repo , parent_commit = previous_commit )
940- sms = self .children ( )
962+ psms = self .list_items (repo , parent_commit = previous_commit )
963+ sms = self .list_items ( self . module () )
941964 spsms = set (psms )
942965 ssms = set (sms )
943966
@@ -958,7 +981,7 @@ def update(self, previous_commit=None, recursive=True, force_remove=False, init=
958981
959982 if sm .path != psm .path and psm .module_exists ():
960983 # move the module to the new path
961- psm .move (sm .path , module_only = True )
984+ psm .move (sm .path , module = True , configuration = False )
962985 # END handle path changes
963986
964987 if sm .module_exists ():
@@ -970,26 +993,39 @@ def update(self, previous_commit=None, recursive=True, force_remove=False, init=
970993 nn = '__new_origin__'
971994 smm = sm .module ()
972995 rmts = smm .remotes
973- assert nn not in rmts
974- smr = smm .create_remote (nn , sm .url )
975- srm .fetch ()
976-
977- # now delete the changed one
978- orig_name = None
979- for remote in rmts :
980- if remote .url == psm .url :
981- orig_name = remote .name
982- smm .delete_remote (remote )
983- break
984- # END if urls match
985- # END for each remote
986996
987- # rename the new remote back to what it was
988- # if we have not found any remote with the original url
989- # we may not have a name. This is a special case,
990- # and its okay to fail her
991- assert orig_name is not None , "Couldn't find original remote-repo at url %r" % psm .url
992- smr .rename (orig_name )
997+ # don't do anything if we already have the url we search in place
998+ if len ([r for r in rmts if r .url == sm .url ]) == 0 :
999+ assert nn not in [r .name for r in rmts ]
1000+ smr = smm .create_remote (nn , sm .url )
1001+ smr .fetch ()
1002+
1003+ # now delete the changed one
1004+ orig_name = None
1005+ for remote in rmts :
1006+ if remote .url == psm .url :
1007+ orig_name = remote .name
1008+ smm .delete_remote (remote )
1009+ break
1010+ # END if urls match
1011+ # END for each remote
1012+
1013+ # if we didn't find a matching remote, but have exactly one,
1014+ # we can safely use this one
1015+ if len (rmts ) == 1 :
1016+ orig_name = rmts [0 ].name
1017+ smm .delete_remote (rmts [0 ])
1018+ else :
1019+ # if we have not found any remote with the original url
1020+ # we may not have a name. This is a special case,
1021+ # and its okay to fail here
1022+ # Alternatively we could just generate a unique name
1023+ raise InvalidGitRepositoryError ("Couldn't find original remote-repo at url %r" % psm .url )
1024+ # END only one remove
1025+
1026+ # rename the new remote back to what it was
1027+ smr .rename (orig_name )
1028+ # END skip remote handling if new url already exists in module
9931029 # END handle url
9941030
9951031 if sm .branch != psm .branch :
@@ -1020,11 +1056,13 @@ def update(self, previous_commit=None, recursive=True, force_remove=False, init=
10201056 # FINALLY UPDATE ALL ACTUAL SUBMODULES
10211057 ##########################################
10221058 for sm in sms :
1059+ # update the submodule using the default method
10231060 sm .update (recursive = True , init = init , to_latest_revision = to_latest_revision )
10241061
10251062 # update recursively depth first - question is which inconsitent
10261063 # state will be better in case it fails somewhere. Defective branch
1027- # or defective depth
1064+ # or defective depth. The RootSubmodule type will never process itself,
1065+ # which was done in the previous expression
10281066 if recursive :
10291067 type (cls )(sm .module ()).update (recursive = True , force_remove = force_remove ,
10301068 init = init , to_latest_revision = to_latest_revision )
0 commit comments