def returning_to_current_branch(self): """ A contextmanager returning to the current branch. """ if self.repo.head.is_detached: raise GitError("You're not currently on a branch. I'm exiting" " in case you're in the middle of something.") branch_name = self.repo.active_branch.name yield if (self.repo.head.is_detached # Only on Travis CI, # we get a detached head after doing our rebase *confused*. # Running self.repo.active_branch would fail. or not self.repo.active_branch.name == branch_name): print(colored('returning to {0}'.format(branch_name), 'magenta')) self.git.checkout(branch_name)
def rebase_all_branches(self): """ Rebase all branches, if possible. """ col_width = max(len(b.name) for b in self.branches) + 1 if self.repo.head.is_detached: raise GitError("You're not currently on a branch. I'm exiting" " in case you're in the middle of something.") original_branch = self.repo.active_branch with self.git.stasher() as stasher: for branch in self.branches: target = self.target_map[branch.name] # Print branch name if branch.name == original_branch.name: attrs = ['bold'] else: attrs = [] print(colored(branch.name.ljust(col_width), attrs=attrs), end=' ') # Check, if target branch exists try: if target.name.startswith('./'): # Check, if local branch exists self.git.rev_parse(target.name[2:]) else: # Check, if remote branch exists _ = target.commit except (ValueError, GitError): # Remote branch doesn't exist! print(colored('error: remote branch doesn\'t exist', 'red')) self.states.append('remote branch doesn\'t exist') continue # Get tracking branch if target.is_local: target = find(self.repo.branches, lambda b: b.name == target.name[2:]) # Check status and act appropriately if target.commit.hexsha == branch.commit.hexsha: print(colored('up to date', 'green')) self.states.append('up to date') continue # Do not do anything base = self.git.merge_base(branch.name, target.name) if base == target.commit.hexsha: print(colored('ahead of upstream', 'cyan')) self.states.append('ahead') continue # Do not do anything fast_fastforward = False if base == branch.commit.hexsha: print(colored('fast-forwarding...', 'yellow'), end='') self.states.append('fast-forwarding') # Don't fast fast-forward the currently checked-out branch fast_fastforward = (branch.name != self.repo.active_branch.name) elif not self.settings['rebase.auto']: print(colored('diverged', 'red')) self.states.append('diverged') continue # Do not do anything else: print(colored('rebasing', 'yellow'), end='') self.states.append('rebasing') if self.settings['rebase.show-hashes']: print(' {}..{}'.format(base[0:7], target.commit.hexsha[0:7])) else: print() self.log(branch, target) if fast_fastforward: branch.commit = target.commit else: stasher() self.git.checkout(branch.name) self.git.rebase(target) if (self.repo.head.is_detached # Only on Travis CI, # we get a detached head after doing our rebase *confused*. # Running self.repo.active_branch would fail. or not self.repo.active_branch.name == original_branch.name): print( colored('returning to {0}'.format(original_branch.name), 'magenta')) original_branch.checkout()
def __init__(self, testing=False, sparse=False): # Sparse init: config only if sparse: self.git = GitWrapper(None) # Load configuration self.settings = self.default_settings.copy() self.load_config() return # Testing: redirect stderr to stdout self.testing = testing if self.testing: self.stderr = sys.stdout # Quiet testing else: # pragma: no cover self.stderr = sys.stderr self.states = [] self.should_fetch = True # Check, if we're in a git repo try: repo_dir = get_git_dir() except (EnvironmentError, OSError, GitCommandNotFound) as e: if isinstance(e, GitCommandNotFound) or e.errno == errno.ENOENT: exc = GitError("The git executable could not be found") raise exc else: raise else: if repo_dir is None: exc = GitError("We don't seem to be in a git repository.") raise exc self.repo = Repo(repo_dir, odbt=GitCmdObjectDB) # Check for branch tracking informatino if not any(b.tracking_branch() for b in self.repo.branches): exc = GitError("Can\'t update your repo because it doesn\'t has " "any branches with tracking information.") self.print_error(exc) raise exc self.git = GitWrapper(self.repo) # target_map: map local branch names to remote tracking branches #: :type: dict[str, git.refs.remote.RemoteReference] self.target_map = dict() for branch in self.repo.branches: target = branch.tracking_branch() if target: if target.name.startswith('./'): # Tracking branch is in local repo target.is_local = True else: target.is_local = False self.target_map[branch.name] = target # branches: all local branches with tracking information #: :type: list[git.refs.head.Head] self.branches = [b for b in self.repo.branches if b.tracking_branch()] self.branches.sort(key=lambda br: br.name) # remotes: all remotes that are associated with local branches #: :type: list[git.refs.remote.RemoteReference] self.remotes = uniq( # name = '<remote>/<branch>' -> '<remote>' [r.name.split('/', 2)[0] for r in list(self.target_map.values())]) # change_count: Number of unstaged changes self.change_count = len( self.git.status(porcelain=True, untracked_files='no').split('\n')) # Load configuration self.settings = self.default_settings.copy() self.load_config()
def __init__(self, testing=False, sparse=False): # Sparse init: config only if sparse: self.git = GitWrapper(None) # Load configuration self.settings = self.default_settings.copy() self.load_config() return # Testing: redirect stderr to stdout self.testing = testing if testing: self.stderr = sys.stdout # Quiet testing else: self.stderr = sys.stderr self.states = [] # Check, if we're in a git repo try: self.repo = Repo(execute('git rev-parse --show-toplevel'), odbt=GitCmdObjectDB) except IndexError: exc = GitError("We don't seem to be in a git repository.") self.print_error(exc) raise exc # Check for branch tracking informatino if not any(b.tracking_branch() for b in self.repo.branches): exc = GitError("Can\'t update your repo because it doesn\'t has " "any branches with tracking information.") self.print_error(exc) raise exc self.git = GitWrapper(self.repo) # target_map: map local branch names to remote tracking branches self.target_map = dict() for branch in self.repo.branches: target = branch.tracking_branch() if target: if target.name.startswith('./'): # Tracking branch is in local repo target.is_local = True else: target.is_local = False self.target_map[branch.name] = target # branches: all local branches with tracking information self.branches = [b for b in self.repo.branches if b.tracking_branch()] self.branches.sort(key=lambda br: br.name) # remotes: all remotes that are associated with local branches self.remotes = uniq( # name = '<remote>/<branch>' -> '<remote>' [r.name.split('/', 2)[0] for r in list(self.target_map.values())] ) # change_count: Number of unstaged changes self.change_count = len( self.git.status(porcelain=True, untracked_files='no').split('\n') ) # Load configuration self.settings = self.default_settings.copy() self.load_config()