<commit_before># coding=utf-8
"""
Python implementation of git-up.

Why use git-up? ``git pull` has two problems:
  - It merges upstream changes by default, when it's really more polite to
    rebase over them, unless your collaborators enjoy a commit graph that
    looks like bedhead.
  - It only updates the branch you're currently on, which means git push
    will shout at you for being behind on branches you don't particularly
    care about right now.
(from the orignial git-up https://github.com/aanand/git-up/)

Project Author: <NAME> <<EMAIL>>
Project URL: https://github.com/msiemens/PyGitUp
"""

from __future__ import print_function

__all__ = ['GitUp']

###############################################################################
# IMPORTS and LIBRARIES SETUP
###############################################################################

# Python libs
import sys
import os
from contextlib import contextmanager
import subprocess

# 3rd party libs
import colorama
from termcolor import colored

from git import Repo, GitCmdObjectDB

# PyGitUp libs
from PyGitUp.utils import execute, uniq
from PyGitUp.git_wrapper import GitWrapper, GitError

###############################################################################
# Setup of 3rd party libs
###############################################################################

colorama.init(autoreset=True)

###############################################################################
# Setup global vars
###############################################################################

# Initialize frequently used globals
try:
    path = execute('git rev-parse --show-toplevel')
except IndexError:
    sys.exit(1)

repo = Repo(path, odbt=GitCmdObjectDB)
git = GitWrapper(repo)


###############################################################################
# GitUp
###############################################################################

class GitUp(object):
    """ Conainter class for GitUp methods """

    def __init__(self):
        # remote_map: map local branch names to remote branches
        self.remote_map = dict()

        for branch in repo.branches:
            remote = git.remote_ref_for_branch(branch)
            if remote:
                self.remote_map[branch.name] = remote

        # branches: all local branches that has a corresponding remote branch
        self.branches = [
            branch for branch in repo.branches
            if branch.name in list(self.remote_map.keys())
        ]
        self.branches.sort(key=lambda b: b.name)

        # remotes: all remotes that are associated with local branches
        self.remotes = uniq(
            [r.name.split('/', 2)[0] for r in list(self.remote_map.values())]
        )

        # change_count
        self.change_count = len(
            git.status(porcelain=True, untracked_files='no').split('\n')
        )

    def run(self):
        """ Run all the git-up stuff. """
        try:
            self.fetch()

            with git.stash():
                with self.returning_to_current_branch():
                    self.rebase_all_branches()

            if self.with_bundler():
                self.check_bundler()

        except GitError as error:
            print(colored(error.message, 'red'))

            # Print more information about the error
            if error.stdout or error.stderr:
                print()
                print("Here's what git said:")
                print()

                if error.stdout:
                    print(error.stdout)
                if error.stderr:
                    print(error.stderr)

            if error.details:
                print()
                print("Here's what we know:")
                print(str(error.details))
                print()


    def rebase_all_branches(self):
        """ Rebase all branches, if possible. """
        col_width = max([len(b.name) for b in self.branches]) + 1

        for branch in self.branches:
            remote = self.remote_map[branch.name]
            print(colored(branch.name.ljust(col_width), attrs=['bold']),
                  end=' ')

            if remote.commit.hexsha == branch.commit.hexsha:
                print(colored('up to date', 'green'))
                continue

            base = git.merge_base(branch.name, remote.name)

            if base == remote.commit.hexsha:
                print(colored('ahead of upstream', 'green'))<commit_msg>Fixed #4: Handle deletion of remote branch<commit_after># coding=utf-8
"""
Python implementation of git-up.

Why use git-up? ``git pull` has two problems:
  - It merges upstream changes by default, when it's really more polite to
    rebase over them, unless your collaborators enjoy a commit graph that
    looks like bedhead.
  - It only updates the branch you're currently on, which means git push
    will shout at you for being behind on branches you don't particularly
    care about right now.
(from the orignial git-up https://github.com/aanand/git-up/)

Project Author: <NAME> <<EMAIL>>
Project URL: https://github.com/msiemens/PyGitUp
"""

from __future__ import print_function

__all__ = ['GitUp']

###############################################################################
# IMPORTS and LIBRARIES SETUP
###############################################################################

# Python libs
import sys
import os
from contextlib import contextmanager
import subprocess

# 3rd party libs
import colorama
from termcolor import colored

from git import Repo, GitCmdObjectDB

# PyGitUp libs
from PyGitUp.utils import execute, uniq
from PyGitUp.git_wrapper import GitWrapper, GitError

###############################################################################
# Setup of 3rd party libs
###############################################################################

colorama.init(autoreset=True)

###############################################################################
# Setup global vars
###############################################################################

# Initialize frequently used globals
try:
    path = execute('git rev-parse --show-toplevel')
except IndexError:
    sys.exit(1)

repo = Repo(path, odbt=GitCmdObjectDB)
git = GitWrapper(repo)


###############################################################################
# GitUp
###############################################################################

class GitUp(object):
    """ Conainter class for GitUp methods """

    def __init__(self):
        # remote_map: map local branch names to remote branches
        self.remote_map = dict()

        for branch in repo.branches:
            remote = git.remote_ref_for_branch(branch)
            if remote:
                self.remote_map[branch.name] = remote

        # branches: all local branches that has a corresponding remote branch
        self.branches = [
            branch for branch in repo.branches
            if branch.name in list(self.remote_map.keys())
        ]
        self.branches.sort(key=lambda b: b.name)

        # remotes: all remotes that are associated with local branches
        self.remotes = uniq(
            [r.name.split('/', 2)[0] for r in list(self.remote_map.values())]
        )

        # change_count
        self.change_count = len(
            git.status(porcelain=True, untracked_files='no').split('\n')
        )

    def run(self):
        """ Run all the git-up stuff. """
        try:
            self.fetch()

            with git.stash():
                with self.returning_to_current_branch():
                    self.rebase_all_branches()

            if self.with_bundler():
                self.check_bundler()

        except GitError as error:
            print(colored(error.message, 'red'))

            # Print more information about the error
            if error.stdout or error.stderr:
                print()
                print("Here's what git said:")
                print()

                if error.stdout:
                    print(error.stdout)
                if error.stderr:
                    print(error.stderr)

            if error.details:
                print()
                print("Here's what we know:")
                print(str(error.details))
                print()


    def rebase_all_branches(self):
        """ Rebase all branches, if possible. """
        col_width = max([len(b.name) for b in self.branches]) + 1

        for branch in self.branches:
            remote = self.remote_map[branch.name]
            print(colored(branch.name.ljust(col_width), attrs=['bold']),
                  end=' ')

            try:
                remote.commit
            except ValueError:
                # Remote branch doesn't exist!
                print(colored('error: remote branch doesn\'t exist', 'red'))
                continue

            if remote.commit.hexsha == branch.commit.hexsha:
                print(colored('up to date', 'green'))
                continue

            base = git.merge_base(branch.name, remote.name)

            if base == remote.commit.hexsha:
                print(colored('ahead of upstream', 'green'))
{'fraction_non_alphanumeric': 0.21886957472395321, 'fraction_numerical': 0.0016398819285011479, 'mean_word_length': 2.565081839438815, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 9, 'https://': 4, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '866422', 'n_tokens_mistral': 2400, 'n_tokens_neox': 2241, 'n_words': 668}