def branch(self): """:return: The branch instance that we are to checkout :raise InvalidGitRepositoryError: if our module is not yet checked out""" return mkhead(self.module(), self._branch_path)
def update(self, recursive=False, init=True, to_latest_revision=False, progress=None, dry_run=False): """Update the repository of this submodule to point to the checkout we point at with the binsha of this instance. :param recursive: if True, we will operate recursively and update child- modules as well. :param init: if True, the module repository will be cloned into place if necessary :param to_latest_revision: if True, the submodule's sha will be ignored during checkout. Instead, the remote will be fetched, and the local tracking branch updated. This only works if we have a local tracking branch, which is the case if the remote repository had a master branch, or of the 'branch' option was specified for this submodule and the branch existed remotely :param progress: UpdateProgress instance or None of no progress should be shown :param dry_run: if True, the operation will only be simulated, but not performed. All performed operations are read-only :note: does nothing in bare repositories :note: method is definitely not atomic if recurisve is True :return: self""" if self.repo.bare: return self #END pass in bare mode if progress is None: progress = UpdateProgress() #END handle progress prefix = '' if dry_run: prefix = "DRY-RUN: " #END handle prefix # to keep things plausible in dry-run mode if dry_run: mrepo = None #END init mrepo # ASSURE REPO IS PRESENT AND UPTODATE ##################################### try: mrepo = self.module() rmts = mrepo.remotes len_rmts = len(rmts) for i, remote in enumerate(rmts): op = FETCH if i == 0: op |= BEGIN #END handle start progress.update( op, i, len_rmts, prefix + "Fetching remote %s of submodule %r" % (remote, self.name)) #=============================== if not dry_run: remote.fetch(progress=progress) #END handle dry-run #=============================== if i == len_rmts - 1: op |= END #END handle end progress.update( op, i, len_rmts, prefix + "Done fetching remote of submodule %r" % self.name) #END fetch new data except InvalidGitRepositoryError: if not init: return self # END early abort if init is not allowed import git # there is no git-repository yet - but delete empty paths module_path = join_path_native(self.repo.working_tree_dir, self.path) if not dry_run and os.path.isdir(module_path): try: os.rmdir(module_path) except OSError: raise OSError( "Module directory at %r does already exist and is non-empty" % module_path) # END handle OSError # END handle directory removal # don't check it out at first - nonetheless it will create a local # branch according to the remote-HEAD if possible progress.update( BEGIN | CLONE, 0, 1, prefix + "Cloning %s to %s in submodule %r" % (self.url, module_path, self.name)) if not dry_run: mrepo = git.Repo.clone_from(self.url, module_path, n=True) #END handle dry-run progress.update(END | CLONE, 0, 1, prefix + "Done cloning to %s" % module_path) if not dry_run: # see whether we have a valid branch to checkout try: # find a remote which has our branch - we try to be flexible remote_branch = find_first_remote_branch( mrepo.remotes, self.branch_name) local_branch = mkhead(mrepo, self.branch_path) # have a valid branch, but no checkout - make sure we can figure # that out by marking the commit with a null_sha local_branch.set_object( util.Object(mrepo, self.NULL_BIN_SHA)) # END initial checkout + branch creation # make sure HEAD is not detached mrepo.head.set_reference( local_branch, logmsg="submodule: attaching head to %s" % local_branch) mrepo.head.ref.set_tracking_branch(remote_branch) except IndexError: print >> sys.stderr, "Warning: Failed to checkout tracking branch %s" % self.branch_path #END handle tracking branch # NOTE: Have to write the repo config file as well, otherwise # the default implementation will be offended and not update the repository # Maybe this is a good way to assure it doesn't get into our way, but # we want to stay backwards compatible too ... . Its so redundant ! self.repo.config_writer().set_value(sm_section(self.name), 'url', self.url) #END handle dry_run #END handle initalization # DETERMINE SHAS TO CHECKOUT ############################ binsha = self.binsha hexsha = self.hexsha if mrepo is not None: # mrepo is only set if we are not in dry-run mode or if the module existed is_detached = mrepo.head.is_detached #END handle dry_run if mrepo is not None and to_latest_revision: msg_base = "Cannot update to latest revision in repository at %r as " % mrepo.working_dir if not is_detached: rref = mrepo.head.ref.tracking_branch() if rref is not None: rcommit = rref.commit binsha = rcommit.binsha hexsha = rcommit.hexsha else: print >> sys.stderr, "%s a tracking branch was not set for local branch '%s'" % ( msg_base, mrepo.head.ref) # END handle remote ref else: print >> sys.stderr, "%s there was no local tracking branch" % msg_base # END handle detached head # END handle to_latest_revision option # update the working tree # handles dry_run if mrepo is not None and mrepo.head.commit.binsha != binsha: progress.update( BEGIN | UPDWKTREE, 0, 1, prefix + "Updating working tree at %s for submodule %r to revision %s" % (self.path, self.name, hexsha)) if not dry_run: if is_detached: # NOTE: for now we force, the user is no supposed to change detached # submodules anyway. Maybe at some point this becomes an option, to # properly handle user modifications - see below for future options # regarding rebase and merge. mrepo.git.checkout(hexsha, force=True) else: # TODO: allow to specify a rebase, merge, or reset # TODO: Warn if the hexsha forces the tracking branch off the remote # branch - this should be prevented when setting the branch option mrepo.head.reset(hexsha, index=True, working_tree=True) # END handle checkout #END handle dry_run progress.update( END | UPDWKTREE, 0, 1, prefix + "Done updating working tree for submodule %r" % self.name) # END update to new commit only if needed # HANDLE RECURSION ################## if recursive: # in dry_run mode, the module might not exist if mrepo is not None: for submodule in self.iter_items(self.module()): submodule.update(recursive, init, to_latest_revision, progress=progress, dry_run=dry_run) # END handle recursive update #END handle dry run # END for each submodule return self
def update(self, recursive=False, init=True, to_latest_revision=False, progress=None, dry_run=False, ): """Update the repository of this submodule to point to the checkout we point at with the binsha of this instance. :param recursive: if True, we will operate recursively and update child- modules as well. :param init: if True, the module repository will be cloned into place if necessary :param to_latest_revision: if True, the submodule's sha will be ignored during checkout. Instead, the remote will be fetched, and the local tracking branch updated. This only works if we have a local tracking branch, which is the case if the remote repository had a master branch, or of the 'branch' option was specified for this submodule and the branch existed remotely :param progress: UpdateProgress instance or None of no progress should be shown :param dry_run: if True, the operation will only be simulated, but not performed. All performed operations are read-only :note: does nothing in bare repositories :note: method is definitely not atomic if recurisve is True :return: self""" if self.repo.bare: return self #END pass in bare mode if progress is None: progress = UpdateProgress() #END handle progress prefix = '' if dry_run: prefix = "DRY-RUN: " #END handle prefix # to keep things plausible in dry-run mode if dry_run: mrepo = None #END init mrepo # ASSURE REPO IS PRESENT AND UPTODATE ##################################### try: mrepo = self.module() rmts = mrepo.remotes len_rmts = len(rmts) for i, remote in enumerate(rmts): op = FETCH if i == 0: op |= BEGIN #END handle start progress.update(op, i, len_rmts, prefix+"Fetching remote %s of submodule %r" % (remote, self.name)) #=============================== if not dry_run: remote.fetch(progress=progress) #END handle dry-run #=============================== if i == len_rmts-1: op |= END #END handle end progress.update(op, i, len_rmts, prefix+"Done fetching remote of submodule %r" % self.name) #END fetch new data except InvalidGitRepositoryError: if not init: return self # END early abort if init is not allowed # there is no git-repository yet - but delete empty paths module_path = join_path_native(self.repo.working_tree_dir, self.path) if not dry_run and os.path.isdir(module_path): try: os.rmdir(module_path) except OSError: raise OSError("Module directory at %r does already exist and is non-empty" % module_path) # END handle OSError # END handle directory removal # don't check it out at first - nonetheless it will create a local # branch according to the remote-HEAD if possible progress.update(BEGIN|CLONE, 0, 1, prefix+"Cloning %s to %s in submodule %r" % (self.url, module_path, self.name)) if not dry_run: mrepo = type(self.repo).clone_from(self.url, module_path, n=True) #END handle dry-run progress.update(END|CLONE, 0, 1, prefix+"Done cloning to %s" % module_path) if not dry_run: # see whether we have a valid branch to checkout try: # find a remote which has our branch - we try to be flexible remote_branch = find_first_remote_branch(mrepo.remotes, self.branch_name) local_branch = mkhead(mrepo, self.branch_path) # have a valid branch, but no checkout - make sure we can figure # that out by marking the commit with a null_sha local_branch.set_object(util.Object(mrepo, self.NULL_BIN_SHA)) # END initial checkout + branch creation # make sure HEAD is not detached mrepo.head.set_reference(local_branch, logmsg="submodule: attaching head to %s" % local_branch) mrepo.head.ref.set_tracking_branch(remote_branch) except IndexError: print >> sys.stderr, "Warning: Failed to checkout tracking branch %s" % self.branch_path #END handle tracking branch # NOTE: Have to write the repo config file as well, otherwise # the default implementation will be offended and not update the repository # Maybe this is a good way to assure it doesn't get into our way, but # we want to stay backwards compatible too ... . Its so redundant ! self.repo.config_writer().set_value(sm_section(self.name), 'url', self.url) #END handle dry_run #END handle initalization # DETERMINE SHAS TO CHECKOUT ############################ binsha = self.binsha hexsha = self.hexsha if mrepo is not None: # mrepo is only set if we are not in dry-run mode or if the module existed is_detached = mrepo.head.is_detached #END handle dry_run if mrepo is not None and to_latest_revision: msg_base = "Cannot update to latest revision in repository at %r as " % mrepo.working_dir if not is_detached: rref = mrepo.head.ref.tracking_branch() if rref is not None: rcommit = rref.commit binsha = rcommit.binsha hexsha = rcommit.hexsha else: print >> sys.stderr, "%s a tracking branch was not set for local branch '%s'" % (msg_base, mrepo.head.ref) # END handle remote ref else: print >> sys.stderr, "%s there was no local tracking branch" % msg_base # END handle detached head # END handle to_latest_revision option # update the working tree # handles dry_run if mrepo is not None and mrepo.head.commit.binsha != binsha: progress.update(BEGIN|UPDWKTREE, 0, 1, prefix+"Updating working tree at %s for submodule %r to revision %s" % (self.path, self.name, hexsha)) if not dry_run: if is_detached: # NOTE: for now we force, the user is no supposed to change detached # submodules anyway. Maybe at some point this becomes an option, to # properly handle user modifications - see below for future options # regarding rebase and merge. mrepo.git.checkout(hexsha, force=True) else: # TODO: allow to specify a rebase, merge, or reset # TODO: Warn if the hexsha forces the tracking branch off the remote # branch - this should be prevented when setting the branch option mrepo.head.reset(hexsha, index=True, working_tree=True) # END handle checkout #END handle dry_run progress.update(END|UPDWKTREE, 0, 1, prefix+"Done updating working tree for submodule %r" % self.name) # END update to new commit only if needed # HANDLE RECURSION ################## if recursive: # in dry_run mode, the module might not exist if mrepo is not None: for submodule in self.iter_items(self.module()): submodule.update(recursive, init, to_latest_revision, progress=progress, dry_run=dry_run) # END handle recursive update #END handle dry run # END for each submodule return self