def hard_reset_to_ref(self, branch, ref, checkout=True): """Perform a hard reset of a local branch to any reference. :param str branch: Local branch to reset :param str ref: Reference (commit, tag, ...) to reset to :param bool checkout: Whether to checkout the new branch """ # Ensure the reference maps to a commit try: commit = git.repo.fun.name_to_object(self.git_repo.repo, ref) except git.exc.BadName as ex: msg = "Could not find reference {0}.".format(ref) raise_from(exceptions.ReferenceNotFoundException(msg), ex) try: # Preserve the reference name if there is one orig = self.git_repo.repo.head.ref.name except TypeError: # Detached head orig = self.git_repo.repo.head.commit.hexsha # Switch to the branch try: self.git_repo.git.checkout(branch) except git.GitCommandError as ex: msg = ( "Could not checkout branch {branch}. Error: {error}".format( branch=branch, error=ex) ) raise_from(exceptions.CheckoutException(msg), ex) # Reset --hard to that reference try: self.git_repo.repo.head.reset(commit=commit, index=True, working_tree=True) except git.GitCommandError as ex: msg = ( "Error resetting branch {branch} to {ref}. " "Error: {error}".format(ref=ref, branch=branch, error=ex) ) raise_from(exceptions.ResetException(msg), ex) # Return to the original head if required if not checkout: try: self.git_repo.git.checkout(orig) except git.GitCommandError as ex: msg = ( "Could not checkout {orig}. Error: {error}".format( orig=orig, error=ex) ) raise_from(exceptions.CheckoutException(msg), ex)
def rebase_to_hash(self, branch_name, hash_): """Perform a rebase from a specific reference to another. :param str branch_name: The name of the branch to rebase on :param str hash_: The commit hash or reference to rebase to """ self.logger.debug( "Rebasing branch %s to hash %s. Repo currently at commit %s.", branch_name, hash_, self.git_repo.repo.head.commit ) if self.git_repo.repo.is_dirty(): msg = ("Repository {0} is dirty. Please clean workspace " "before proceeding.".format(self.git_repo.repo.working_dir)) raise exceptions.DirtyRepositoryException(msg) # Checkout try: self.git_repo.git.checkout(branch_name) except git.GitCommandError as ex: msg = "Could not checkout branch {name}. Error: {error}".format(name=branch_name, error=ex) raise_from(exceptions.CheckoutException(msg), ex) # Rebase try: self.git_repo.git.rebase(hash_) except git.GitCommandError as ex: msg = "Could not rebase hash {hash_} onto branch {name}. Error: {error}".format(hash_=hash_, name=branch_name, error=ex) raise_from(exceptions.RebaseException(msg), ex) self.logger.debug("Successfully rebased branch %s to %s", branch_name, hash_)
def apply_patch(self, branch_name, path, keep_square_brackets=False): """Apply a git patch file on top of the specified branch. :param str branch_name: The name of the branch or reference to apply the patch to :param str path: Path to a git-formatted patch file (cf. git format-patch) :param bool keep_square_brackets: Preserve non-[PATCH] brackets in commit subject """ # Expand file (also needed for git-am) and check it exists full_path = self._expand_file_path(path) # Checkout try: self.git_repo.git.checkout(branch_name) except git.GitCommandError as ex: msg = "Could not checkout branch {name}. Error: {error}".format(name=branch_name, error=ex) raise_from(exceptions.CheckoutException(msg), ex) # Apply the patch file try: if keep_square_brackets: self.git_repo.git.am("--keep-non-patch", full_path) else: self.git_repo.git.am(full_path) except git.GitCommandError as ex: msg = "Could not apply patch {path} on branch {name}. Error: {error}".format(path=full_path, name=branch_name, error=ex) raise_from(exceptions.ChangeNotAppliedException(msg), ex)
def rebase_to_hash(self, branch_name, hash_): """Perform a rebase from a specific reference to another. :param str branch_name: The name of the branch to rebase on :param str hash_: The commit hash or reference to rebase to """ self.logger.debug( f"Rebasing branch {branch_name} to hash {hash_}. " f"Repo currently at commit {self.git_repo.repo.head.commit}.") if self.git_repo.repo.is_dirty(): working_dir = self.git_repo.repo.working_dir msg = ( f"Repository {working_dir} is dirty. Please clean workspace " "before proceeding.") raise exceptions.DirtyRepositoryException(msg) # Checkout try: self.git_repo.git.checkout(branch_name) except git.GitCommandError as ex: msg = f"Could not checkout branch {branch_name}. Error: {ex}" raise exceptions.CheckoutException(msg) from ex # Rebase try: self.git_repo.git.rebase(hash_) except git.GitCommandError as ex: msg = (f"Could not rebase hash {hash_} onto branch {branch_name}. " f"Error: {ex}") raise exceptions.RebaseException(msg) from ex msg = f"Successfully rebased branch {branch_name} to {hash_}" self.logger.debug(msg)
def hard_reset_to_ref(self, branch, ref): """Perform a hard reset of a local branch to any reference. :param str branch: Local branch to reset :param str ref: Reference (commit, tag, ...) to reset to """ # Ensure the reference maps to a commit try: commit = git.repo.fun.name_to_object(self.git_repo.repo, ref) except git.exc.BadName as ex: msg = "Could not find reference {0}.".format(ref) raise_from(exceptions.ReferenceNotFoundException(msg), ex) # Switch to the branch try: self.git_repo.git.checkout(branch) except git.GitCommandError as ex: msg = ( "Could not checkout branch {branch}. Error: {error}".format( branch=branch, error=ex) ) raise_from(exceptions.CheckoutException(msg), ex) # Reset --hard to that reference try: self.git_repo.repo.head.reset(commit=commit, index=True, working_tree=True) except git.GitCommandError as ex: msg = ( "Error resetting branch {branch} to {ref}. " "Error: {error}".format(ref=ref, branch=branch, error=ex) ) raise_from(exceptions.ResetException(msg), ex)
def apply_diff(self, branch_name, diff_path, message, signoff=False): """Apply a diff on top of the specified branch. :param str branch_name: The name of the branch or reference to apply the diff to :param str diff_path: Path to the diff file :param str message: Commit message :param bool signoff: Whether to add signed-off-by to commit message """ # Ensure we don't commit more than we mean to if self.git_repo.repo.is_dirty(): msg = ("Repository {repo} contains uncommitted changes. Please clean workspace " "before proceeding.".format(repo=self.git_repo.repo.working_dir)) raise exceptions.DirtyRepositoryException(msg) # Check diff file exists full_path = self._expand_file_path(diff_path) # Checkout try: self.git_repo.git.checkout(branch_name) except git.GitCommandError as ex: msg = "Could not checkout branch {name}. Error: {error}".format(name=branch_name, error=ex) raise_from(exceptions.CheckoutException(msg), ex) # Apply the diff try: self.git_repo.git.apply(full_path) except git.GitCommandError as ex: msg = "Could not apply diff {path} on branch {name}. Error: {error}".format(path=full_path, name=branch_name, error=ex) raise_from(exceptions.ChangeNotAppliedException(msg), ex) # Commit self.git_repo.commit.commit(message, signoff)
def cherrypick(self, sha, branch_name): """Apply given sha on given branch :param str sha: The SHA1 of the commit to cherry-pick :param str branch_name: The branch to apply it to """ if self.git_repo.repo.is_dirty(): working_dir = self.git_repo.repo.working_dir msg = (f"Repository {working_dir} is dirty. Please clean " "workspace before proceeding.") raise exceptions.DirtyRepositoryException(msg) # Checkout try: self.git_repo.git.checkout(branch_name) except git.GitCommandError as ex: msg = f"Could not checkout branch {branch_name}. Error: {ex}" raise exceptions.CheckoutException(msg) from ex # Cherry-pick try: self.git_repo.git.cherry_pick(sha) except git.GitCommandError as ex: msg = (f"Could not cherry-pick commit {sha} on {branch_name}. " f"Error: {ex}") raise exceptions.ChangeNotAppliedException(msg) from ex msg = f"Successfully cherry-picked commit {sha} on {branch_name}" self.logger.debug(msg)
def cherrypick(self, sha, branch_name): """Apply given sha on given branch :param str sha: The SHA1 of the commit to cherry-pick :param str branch_name: The branch to apply it to """ if self.git_repo.repo.is_dirty(): msg = ("Repository {0} is dirty. Please clean workspace " "before proceeding.".format(self.git_repo.repo.working_dir)) raise exceptions.DirtyRepositoryException(msg) # Checkout try: self.git_repo.git.checkout(branch_name) except git.GitCommandError as ex: msg = "Could not checkout branch {name}. Error: {error}".format(name=branch_name, error=ex) raise_from(exceptions.CheckoutException(msg), ex) # Cherry-pick try: self.git_repo.git.cherry_pick(sha) except git.GitCommandError as ex: msg = "Could not cherry-pick commit {sha} on {name}. Error: {error}".format(name=branch_name, sha=sha, error=ex) raise_from(exceptions.ChangeNotAppliedException(msg), ex) self.logger.debug("Successfully cherry-picked commit %s on %s", sha, branch_name)
def to_hash(self, branch_name, hash_): """Perform a rebase from a specific reference to another. :param str branch_name: The name of the branch or reference to start from :param str hash_: The commit hash or reference to rebase to """ logger.debug( "Rebasing branch %s to hash %s. Repo currently at commit %s.", branch_name, hash_, self.repo.head.commit) if self.repo.is_dirty(): msg = "Repository %s is dirty. Please clean workspace before proceeding." % self.repo.working_dir raise exceptions.DirtyRepositoryException(msg) # Does the branch exist? try: branch = git.repo.fun.name_to_object(self.repo, branch_name) except git.exc.BadName as ex: msg = "Could not find branch %s." % branch_name raise exceptions.ReferenceNotFoundException(msg) from ex # Does the hash exists? try: commit = git.repo.fun.name_to_object(self.repo, hash_) except git.exc.BadName as ex: msg = "Could not find hash %s." % hash_ raise exceptions.ReferenceNotFoundException(msg) from ex # Checkout try: self.repo.git.checkout(branch.hexsha) except git.GitCommandError as ex: msg = "Could not checkout branch %s. Error: %s" % (branch_name, ex) raise exceptions.CheckoutException(msg) from ex # Rebase try: self.repo.git.rebase(commit.hexsha) except git.GitCommandError as ex: msg = "Could not rebase hash %s onto branch %s. Error: %s" % ( hash_, branch_name, ex) raise exceptions.RebaseException(msg) from ex logger.debug("Successfully rebased branch %s (%s) to %s" % (branch_name, branch.hexsha, hash_))
def apply_diff(self, branch_name, diff_path, message, signoff=False): """Apply a diff on top of the specified branch. :param str branch_name: The name of the branch or reference to apply the diff to :param str diff_path: Path to the diff file :param str message: Commit message :param bool signoff: Whether to add signed-off-by to commit message """ # Ensure we don't commit more than we mean to if self.git_repo.repo.is_dirty(untracked_files=True): repo = self.git_repo.repo.working_dir msg = (f"Repository {repo} contains uncommitted changes. Please " "clean workspace before proceeding.") raise exceptions.DirtyRepositoryException(msg) # Check diff file exists full_path = self._expand_file_path(diff_path) # Checkout try: self.git_repo.git.checkout(branch_name) except git.GitCommandError as ex: msg = f"Could not checkout branch {branch_name}. Error: {ex}" raise exceptions.CheckoutException(msg) from ex # Apply the diff try: self.git_repo.git.apply(full_path) except git.GitCommandError as ex: msg = (f"Could not apply diff {full_path} on branch " f"{branch_name}. Error: {ex}") raise exceptions.ChangeNotAppliedException(msg) from ex # The diff may have added new files, ensure they are staged self.git_repo.git.add(".") # Commit self.git_repo.commit.commit(message, signoff)