Beispiel #1
0
    def track(self, identifier, name):
        """
        Track a branch of the given type, with the given short name,
        from `origin` (or whatever is configured as `remote` for
        gitflow.)

        :param identifier:
            The identifier for the type of branch to track.
            A :class:`BranchManager <git.branches.BranchManager>` for the given
            identifier must exist in the :attr:`self.managers`.

        :param name:
            The friendly (short) name to track.

        :param base:
            The alternative base to branch off from.  If not given, the default
            base for the given branch type is used.

        :returns:
            The newly created :class:`git.refs.Head` branch.
        """
        repo = self.repo
        mgr = self.managers[identifier]
        # sanity checks
        # :todo: require_clean_working_tree
        full_name = mgr.full_name(name)
        if full_name in repo.branches:
            raise BranchExistsError(full_name)
        self.origin().fetch(full_name)
        remote_branch = self.origin().refs[full_name]
        branch = repo.create_head(full_name, remote_branch)
        branch.set_tracking_branch(remote_branch)
        return branch.checkout()
Beispiel #2
0
    def publish(self, identifier, name):
        """
        Publish a branch of the given type, with the given short name,
        to `origin` (or whatever is configured as `remote` for gitflow.)

        :param identifier:
            The identifier for the type of branch to create.
            A :class:`BranchManager <git.branches.BranchManager>` for the given
            identifier must exist in the :attr:`self.managers`.

        :param name:
            The friendly (short) name to create.
        """
        repo = self.repo
        mgr = self.managers[identifier]

        # sanity checks
        # :todo: require_clean_working_tree
        full_name = mgr.full_name(name)
        remote_name = self.origin_name(full_name)
        if not full_name in repo.branches:
            raise NoSuchBranchError(full_name)
        if remote_name in repo.refs:
            raise BranchExistsError(remote_name)
        # :todo: check if full_name already has a tracking branch
        # :todo: check if full_name already has the same tracking branch

        # create remote branch
        origin = self.origin()
        info = origin.push('%s:refs/heads/%s' % (full_name, full_name))[0]
        origin.fetch()
        # configure remote tracking
        repo.branches[full_name].set_tracking_branch(info.remote_ref)

        return full_name
Beispiel #3
0
    def create(self,
               name,
               base=None,
               fetch=False,
               must_be_on_default_base=False):
        """
        Creates a branch of the type that this manager manages and checks it
        out.

        :param name:
            The (short) name of the branch to create.

        :param base:
            The base commit or ref to base the branch off from.  If a base is
            not provided explicitly, the default base for this type of branch is
            used.  See also :meth:`default_base`.

        :param fetch:
            If set, update the local repo with remote changes prior to
            creating the new branch.

        :param must_be_on_default_base:
            If set, the `base` must be a valid commit on the branch
            manager `default_base`.

        :returns:
            The newly created :class:`git.refs.Head` reference.
        """
        gitflow = self.gitflow
        repo = gitflow.repo

        if fetch:
            gitflow.origin().fetch()

        # Make sure the branch exists neither locally nor remotely.
        full_name = self.full_name(name)
        origin_name = gitflow.origin_name(full_name)
        for r in repo.refs:
            if r.name in (full_name, origin_name):
                raise BranchExistsError(full_name)

        # Make sure the base exists and is in sync.
        if base is None:
            base = self.default_base()
        elif must_be_on_default_base:
            if not gitflow.is_merged_into(base, self.default_base()):
                raise BaseNotOnBranch(base, self.default_base())

        origin_base = gitflow.origin_name(base)
        if base in repo.refs:
            if origin_base in repo.refs:
                gitflow.require_branches_equal(origin_base, base)
        elif origin_base in repo.refs:
            base = origin_base
        else:
            raise BaseNotFound('Base branch {0} not found.'.format(base))

        # Make sure there are no merge conflicts.
        gitflow.require_no_merge_conflict()
        if gitflow.has_staged_commits():
            raise WorkdirIsDirtyError('Contains local changes checked into '
                                      'the index but not committed.')

        # Finally, create and checkout.
        branch = repo.create_head(full_name, base)
        branch.checkout()
        return branch
Beispiel #4
0
    def create(self, name, base=None, fetch=False,
               must_be_on_default_base=False):
        """
        Creates a branch of the type that this manager manages and checks it
        out.

        :param name:
            The (short) name of the branch to create.

        :param base:
            The base commit or ref to base the branch off from.  If a base is
            not provided explicitly, the default base for this type of branch is
            used.  See also :meth:`default_base`.

        :param fetch:
            If set, update the local repo with remote changes prior to
            creating the new branch.

        :param must_be_on_default_base:
            If set, the `base` must be a valid commit on the branch
            manager `default_base`.

        :returns:
            The newly created :class:`git.refs.Head` reference.
        """
        gitflow = self.gitflow
        repo = gitflow.repo

        full_name = self.prefix + name
        if full_name in repo.branches:
            raise BranchExistsError(full_name)

        gitflow.require_no_merge_conflict()
        if gitflow.has_staged_commits():
            raise WorkdirIsDirtyError('Contains local changes checked into '
                                      'the index but not committed.')

        # update the local repo with remote changes, if asked
        if fetch:
            # :fixme: Should this be really `fetch`, not `update`?
            # :fixme:  `fetch` does not change any refs, so it is quite
            # :fixme:  useless. But `update` would advance `develop` and
            # :fixme:  moan about required merges.
            # :fixme:  OTOH, `update` would also give new remote refs,
            # :fixme:  e.g. a remote branch with the same name.
            gitflow.origin().fetch(self.default_base())

        # If the origin branch counterpart exists, assert that the
        # local branch isn't behind it (to avoid unnecessary rebasing).
        if gitflow.origin_name(self.default_base()) in repo.refs:
            # :todo: rethink: check this only if base == default_base()?
            gitflow.require_branches_equal(
                gitflow.origin_name(self.default_base()),
                self.default_base())

        if base is None:
            base = self.default_base()
        elif must_be_on_default_base:
            if not gitflow.is_merged_into(base, self.default_base()):
                raise BaseNotOnBranch(base, self.default_base())

        # If there is a remote branch with the same name, use it
        remote_branch = None
        if gitflow.origin_name(full_name) in repo.refs:
            remote_branch = repo.refs[gitflow.origin_name(full_name)]
            if fetch:
                gitflow.origin().fetch(remote_branch.remote_head)
            # Base must be on the remote branch, too, to avoid conflicts
            if not gitflow.is_merged_into(base, remote_branch):
                raise BaseNotOnBranch(base, remote_branch)
            # base the new local branch on the remote on
            base = remote_branch

        branch = repo.create_head(full_name, base)
        branch.checkout()
        if remote_branch:
            branch.set_tracking_branch(remote_branch)
        return branch