@@ -429,7 +429,7 @@ def add(cls, repo, name, path, url=None, branch=None, no_checkout=False):
429
429
return sm
430
430
431
431
def update (self , recursive = False , init = True , to_latest_revision = False , progress = None , dry_run = False ,
432
- force = False ):
432
+ force = False , keep_going = False ):
433
433
"""Update the repository of this submodule to point to the checkout
434
434
we point at with the binsha of this instance.
435
435
@@ -450,6 +450,10 @@ def update(self, recursive=False, init=True, to_latest_revision=False, progress=
450
450
remote branch. This will essentially 'forget' commits.
451
451
If False, local tracking branches that are in the future of their respective remote branches will simply
452
452
not be moved.
453
+ :param keep_going: if True, we will ignore but log all errors, and keep going recursively.
454
+ Unless dry_run is set as well, keep_going could cause subsequent/inherited errors you wouldn't see
455
+ otherwise.
456
+ In conjunction with dry_run, it can be useful to anticipate all errors when updating submodules
453
457
:note: does nothing in bare repositories
454
458
:note: method is definitely not atomic if recurisve is True
455
459
:return: self"""
@@ -470,152 +474,158 @@ def update(self, recursive=False, init=True, to_latest_revision=False, progress=
470
474
mrepo = None
471
475
# END init mrepo
472
476
473
- # ASSURE REPO IS PRESENT AND UPTODATE
474
- #####################################
475
477
try :
476
- mrepo = self .module ()
477
- rmts = mrepo .remotes
478
- len_rmts = len (rmts )
479
- for i , remote in enumerate (rmts ):
480
- op = FETCH
481
- if i == 0 :
482
- op |= BEGIN
483
- # END handle start
484
-
485
- progress .update (op , i , len_rmts , prefix + "Fetching remote %s of submodule %r" % (remote , self .name ))
486
- #===============================
478
+ # ASSURE REPO IS PRESENT AND UPTODATE
479
+ #####################################
480
+ try :
481
+ mrepo = self .module ()
482
+ rmts = mrepo .remotes
483
+ len_rmts = len (rmts )
484
+ for i , remote in enumerate (rmts ):
485
+ op = FETCH
486
+ if i == 0 :
487
+ op |= BEGIN
488
+ # END handle start
489
+
490
+ progress .update (op , i , len_rmts , prefix + "Fetching remote %s of submodule %r" % (remote , self .name ))
491
+ #===============================
492
+ if not dry_run :
493
+ remote .fetch (progress = progress )
494
+ # END handle dry-run
495
+ #===============================
496
+ if i == len_rmts - 1 :
497
+ op |= END
498
+ # END handle end
499
+ progress .update (op , i , len_rmts , prefix + "Done fetching remote of submodule %r" % self .name )
500
+ # END fetch new data
501
+ except InvalidGitRepositoryError :
502
+ if not init :
503
+ return self
504
+ # END early abort if init is not allowed
505
+
506
+ # there is no git-repository yet - but delete empty paths
507
+ checkout_module_abspath = self .abspath
508
+ if not dry_run and os .path .isdir (checkout_module_abspath ):
509
+ try :
510
+ os .rmdir (checkout_module_abspath )
511
+ except OSError :
512
+ raise OSError ("Module directory at %r does already exist and is non-empty"
513
+ % checkout_module_abspath )
514
+ # END handle OSError
515
+ # END handle directory removal
516
+
517
+ # don't check it out at first - nonetheless it will create a local
518
+ # branch according to the remote-HEAD if possible
519
+ progress .update (BEGIN | CLONE , 0 , 1 , prefix + "Cloning url '%s' to '%s' in submodule %r" %
520
+ (self .url , checkout_module_abspath , self .name ))
487
521
if not dry_run :
488
- remote . fetch ( progress = progress )
522
+ mrepo = self . _clone_repo ( self . repo , self . url , self . path , self . name , n = True )
489
523
# END handle dry-run
490
- #===============================
491
- if i == len_rmts - 1 :
492
- op |= END
493
- # END handle end
494
- progress .update (op , i , len_rmts , prefix + "Done fetching remote of submodule %r" % self .name )
495
- # END fetch new data
496
- except InvalidGitRepositoryError :
497
- if not init :
498
- return self
499
- # END early abort if init is not allowed
524
+ progress .update (END | CLONE , 0 , 1 , prefix + "Done cloning to %s" % checkout_module_abspath )
500
525
501
- # there is no git-repository yet - but delete empty paths
502
- checkout_module_abspath = self .abspath
503
- if not dry_run and os .path .isdir (checkout_module_abspath ):
504
- try :
505
- os .rmdir (checkout_module_abspath )
506
- except OSError :
507
- raise OSError ("Module directory at %r does already exist and is non-empty"
508
- % checkout_module_abspath )
509
- # END handle OSError
510
- # END handle directory removal
511
-
512
- # don't check it out at first - nonetheless it will create a local
513
- # branch according to the remote-HEAD if possible
514
- progress .update (BEGIN | CLONE , 0 , 1 , prefix + "Cloning %s to %s in submodule %r" %
515
- (self .url , checkout_module_abspath , self .name ))
516
- if not dry_run :
517
- mrepo = self ._clone_repo (self .repo , self .url , self .path , self .name , n = True )
518
- # END handle dry-run
519
- progress .update (END | CLONE , 0 , 1 , prefix + "Done cloning to %s" % checkout_module_abspath )
520
-
521
- if not dry_run :
522
- # see whether we have a valid branch to checkout
523
- try :
524
- # find a remote which has our branch - we try to be flexible
525
- remote_branch = find_first_remote_branch (mrepo .remotes , self .branch_name )
526
- local_branch = mkhead (mrepo , self .branch_path )
527
-
528
- # have a valid branch, but no checkout - make sure we can figure
529
- # that out by marking the commit with a null_sha
530
- local_branch .set_object (util .Object (mrepo , self .NULL_BIN_SHA ))
531
- # END initial checkout + branch creation
532
-
533
- # make sure HEAD is not detached
534
- mrepo .head .set_reference (local_branch , logmsg = "submodule: attaching head to %s" % local_branch )
535
- mrepo .head .ref .set_tracking_branch (remote_branch )
536
- except IndexError :
537
- log .warn ("Failed to checkout tracking branch %s" , self .branch_path )
538
- # END handle tracking branch
539
-
540
- # NOTE: Have to write the repo config file as well, otherwise
541
- # the default implementation will be offended and not update the repository
542
- # Maybe this is a good way to assure it doesn't get into our way, but
543
- # we want to stay backwards compatible too ... . Its so redundant !
544
- writer = self .repo .config_writer ()
545
- writer .set_value (sm_section (self .name ), 'url' , self .url )
546
- writer .release ()
526
+ if not dry_run :
527
+ # see whether we have a valid branch to checkout
528
+ try :
529
+ # find a remote which has our branch - we try to be flexible
530
+ remote_branch = find_first_remote_branch (mrepo .remotes , self .branch_name )
531
+ local_branch = mkhead (mrepo , self .branch_path )
532
+
533
+ # have a valid branch, but no checkout - make sure we can figure
534
+ # that out by marking the commit with a null_sha
535
+ local_branch .set_object (util .Object (mrepo , self .NULL_BIN_SHA ))
536
+ # END initial checkout + branch creation
537
+
538
+ # make sure HEAD is not detached
539
+ mrepo .head .set_reference (local_branch , logmsg = "submodule: attaching head to %s" % local_branch )
540
+ mrepo .head .ref .set_tracking_branch (remote_branch )
541
+ except IndexError :
542
+ log .warn ("Failed to checkout tracking branch %s" , self .branch_path )
543
+ # END handle tracking branch
544
+
545
+ # NOTE: Have to write the repo config file as well, otherwise
546
+ # the default implementation will be offended and not update the repository
547
+ # Maybe this is a good way to assure it doesn't get into our way, but
548
+ # we want to stay backwards compatible too ... . Its so redundant !
549
+ writer = self .repo .config_writer ()
550
+ writer .set_value (sm_section (self .name ), 'url' , self .url )
551
+ writer .release ()
552
+ # END handle dry_run
553
+ # END handle initalization
554
+
555
+ # DETERMINE SHAS TO CHECKOUT
556
+ ############################
557
+ binsha = self .binsha
558
+ hexsha = self .hexsha
559
+ if mrepo is not None :
560
+ # mrepo is only set if we are not in dry-run mode or if the module existed
561
+ is_detached = mrepo .head .is_detached
547
562
# END handle dry_run
548
- # END handle initalization
549
-
550
- # DETERMINE SHAS TO CHECKOUT
551
- ############################
552
- binsha = self .binsha
553
- hexsha = self .hexsha
554
- if mrepo is not None :
555
- # mrepo is only set if we are not in dry-run mode or if the module existed
556
- is_detached = mrepo .head .is_detached
557
- # END handle dry_run
558
-
559
- if mrepo is not None and to_latest_revision :
560
- msg_base = "Cannot update to latest revision in repository at %r as " % mrepo .working_dir
561
- if not is_detached :
562
- rref = mrepo .head .ref .tracking_branch ()
563
- if rref is not None :
564
- rcommit = rref .commit
565
- binsha = rcommit .binsha
566
- hexsha = rcommit .hexsha
567
- else :
568
- log .error ("%s a tracking branch was not set for local branch '%s'" , msg_base , mrepo .head .ref )
569
- # END handle remote ref
570
- else :
571
- log .error ("%s there was no local tracking branch" , msg_base )
572
- # END handle detached head
573
- # END handle to_latest_revision option
574
-
575
- # update the working tree
576
- # handles dry_run
577
- if mrepo is not None and mrepo .head .commit .binsha != binsha :
578
- # We must assure that our destination sha (the one to point to) is in the future of our current head.
579
- # Otherwise, we will reset changes that might have been done on the submodule, but were not yet pushed
580
- # We also handle the case that history has been rewritten, leaving no merge-base. In that case
581
- # we behave conservatively, protecting possible changes the user had done
582
- may_reset = True
583
- if mrepo .head .commit .binsha != self .NULL_BIN_SHA :
584
- base_commit = mrepo .merge_base (mrepo .head .commit , hexsha )
585
- if len (base_commit ) == 0 or base_commit [0 ].hexsha == hexsha :
586
- if force :
587
- log .debug ("Will force checkout or reset on local branch that is possibly in the future of" +
588
- "the commit it will be checked out to, effectively 'forgetting' new commits" )
563
+
564
+ if mrepo is not None and to_latest_revision :
565
+ msg_base = "Cannot update to latest revision in repository at %r as " % mrepo .working_dir
566
+ if not is_detached :
567
+ rref = mrepo .head .ref .tracking_branch ()
568
+ if rref is not None :
569
+ rcommit = rref .commit
570
+ binsha = rcommit .binsha
571
+ hexsha = rcommit .hexsha
589
572
else :
590
- log .info ("Skipping %s on branch '%s' of submodule repo '%s' as it contains un-pushed commits" ,
591
- is_detached and "checkout" or "reset" , mrepo .head , mrepo )
592
- may_reset = False
593
- # end handle force
594
- # end handle if we are in the future
595
-
596
- if may_reset and not force and mrepo .is_dirty (index = True , working_tree = True , untracked_files = True ):
597
- raise RepositoryDirtyError (mrepo , "Cannot reset a dirty repository" )
598
- # end handle force and dirty state
599
- # end handle empty repo
600
-
601
- # end verify future/past
602
- progress .update (BEGIN | UPDWKTREE , 0 , 1 , prefix +
603
- "Updating working tree at %s for submodule %r to revision %s"
604
- % (self .path , self .name , hexsha ))
605
-
606
- if not dry_run and may_reset :
607
- if is_detached :
608
- # NOTE: for now we force, the user is no supposed to change detached
609
- # submodules anyway. Maybe at some point this becomes an option, to
610
- # properly handle user modifications - see below for future options
611
- # regarding rebase and merge.
612
- mrepo .git .checkout (hexsha , force = force )
573
+ log .error ("%s a tracking branch was not set for local branch '%s'" , msg_base , mrepo .head .ref )
574
+ # END handle remote ref
613
575
else :
614
- mrepo .head .reset (hexsha , index = True , working_tree = True )
615
- # END handle checkout
616
- # if we may reset/checkout
617
- progress .update (END | UPDWKTREE , 0 , 1 , prefix + "Done updating working tree for submodule %r" % self .name )
618
- # END update to new commit only if needed
576
+ log .error ("%s there was no local tracking branch" , msg_base )
577
+ # END handle detached head
578
+ # END handle to_latest_revision option
579
+
580
+ # update the working tree
581
+ # handles dry_run
582
+ if mrepo is not None and mrepo .head .commit .binsha != binsha :
583
+ # We must assure that our destination sha (the one to point to) is in the future of our current head.
584
+ # Otherwise, we will reset changes that might have been done on the submodule, but were not yet pushed
585
+ # We also handle the case that history has been rewritten, leaving no merge-base. In that case
586
+ # we behave conservatively, protecting possible changes the user had done
587
+ may_reset = True
588
+ if mrepo .head .commit .binsha != self .NULL_BIN_SHA :
589
+ base_commit = mrepo .merge_base (mrepo .head .commit , hexsha )
590
+ if len (base_commit ) == 0 or base_commit [0 ].hexsha == hexsha :
591
+ if force :
592
+ log .debug ("Will force checkout or reset on local branch that is possibly in the future of" +
593
+ "the commit it will be checked out to, effectively 'forgetting' new commits" )
594
+ else :
595
+ log .info ("Skipping %s on branch '%s' of submodule repo '%s' as it contains un-pushed commits" ,
596
+ is_detached and "checkout" or "reset" , mrepo .head , mrepo )
597
+ may_reset = False
598
+ # end handle force
599
+ # end handle if we are in the future
600
+
601
+ if may_reset and not force and mrepo .is_dirty (index = True , working_tree = True , untracked_files = True ):
602
+ raise RepositoryDirtyError (mrepo , "Cannot reset a dirty repository" )
603
+ # end handle force and dirty state
604
+ # end handle empty repo
605
+
606
+ # end verify future/past
607
+ progress .update (BEGIN | UPDWKTREE , 0 , 1 , prefix +
608
+ "Updating working tree at %s for submodule %r to revision %s"
609
+ % (self .path , self .name , hexsha ))
610
+
611
+ if not dry_run and may_reset :
612
+ if is_detached :
613
+ # NOTE: for now we force, the user is no supposed to change detached
614
+ # submodules anyway. Maybe at some point this becomes an option, to
615
+ # properly handle user modifications - see below for future options
616
+ # regarding rebase and merge.
617
+ mrepo .git .checkout (hexsha , force = force )
618
+ else :
619
+ mrepo .head .reset (hexsha , index = True , working_tree = True )
620
+ # END handle checkout
621
+ # if we may reset/checkout
622
+ progress .update (END | UPDWKTREE , 0 , 1 , prefix + "Done updating working tree for submodule %r" % self .name )
623
+ # END update to new commit only if needed
624
+ except Exception as err :
625
+ if not keep_going :
626
+ raise
627
+ log .error (str (err ))
628
+ # end handle keep_going
619
629
620
630
# HANDLE RECURSION
621
631
##################
@@ -624,7 +634,7 @@ def update(self, recursive=False, init=True, to_latest_revision=False, progress=
624
634
if mrepo is not None :
625
635
for submodule in self .iter_items (self .module ()):
626
636
submodule .update (recursive , init , to_latest_revision , progress = progress , dry_run = dry_run ,
627
- force = force )
637
+ force = force , keep_going = keep_going )
628
638
# END handle recursive update
629
639
# END handle dry run
630
640
# END for each submodule
@@ -887,13 +897,16 @@ def remove(self, module=True, force=False, configuration=True, dry_run=False):
887
897
def set_parent_commit (self , commit , check = True ):
888
898
"""Set this instance to use the given commit whose tree is supposed to
889
899
contain the .gitmodules blob.
890
- :param commit: Commit'ish reference pointing at the root_tree, or None to always point to the
900
+
901
+ :param commit:
902
+ Commit'ish reference pointing at the root_tree, or None to always point to the
891
903
most recent commit
892
- :param check: if True, relatively expensive checks will be performed to verify
904
+ :param check:
905
+ if True, relatively expensive checks will be performed to verify
893
906
validity of the submodule.
894
907
:raise ValueError: if the commit's tree didn't contain the .gitmodules blob.
895
- :raise ValueError: if the parent commit didn't store this submodule under the
896
- current path
908
+ :raise ValueError:
909
+ if the parent commit didn't store this submodule under the current path
897
910
:return: self"""
898
911
if commit is None :
899
912
self ._parent_commit = None
@@ -976,7 +989,7 @@ def rename(self, new_name):
976
989
pw .release ()
977
990
978
991
# .gitmodules
979
- cw = self .config_writer (write = False ).config
992
+ cw = self .config_writer (write = True ).config
980
993
cw .rename_section (sm_section (self .name ), sm_section (new_name ))
981
994
cw .release ()
982
995
0 commit comments