예제 #1
0
파일: rebase.py 프로젝트: lamby/stgit
def func(parser, options, args):
    """Rebase the current stack
    """
    if len(args) != 1:
        parser.error('incorrect number of arguments')

    repository = directory.repository
    stack = repository.get_stack()
    iw = repository.default_iw

    if stack.protected:
        raise CmdException('This branch is protected. Rebase is not permitted')

    target = git_commit(args[0], repository)

    applied = stack.patchorder.applied

    retval = prepare_rebase(stack, 'rebase')
    if retval:
        return retval

    rebase(stack, iw, target)
    if not options.nopush:
        return post_rebase(stack,
                           applied,
                           'rebase',
                           check_merged=options.merged)
예제 #2
0
def __create_branch(branch_name, committish):
    repository = directory.repository

    branch_commit = None
    if committish is not None:
        parentbranch = None
        try:
            branchpoint = repository.run(
                ['git', 'rev-parse', '--symbolic-full-name', committish]
            ).output_one_line()

            if branchpoint.startswith('refs/heads/') or branchpoint.startswith(
                'refs/remotes/'
            ):
                # committish is a valid ref from the branchpoint setting above
                parentbranch = committish

        except RunException:
            out.info(
                'Do not know how to determine parent branch from "%s"' % committish
            )
            # exception in branch = rev_parse() leaves branchpoint unbound
            branchpoint = None

        branch_commit = git_commit(branchpoint or committish, repository)

        if parentbranch:
            out.info('Recording "%s" as parent branch' % parentbranch)
        else:
            out.info(
                'Do not know how to determine parent branch from "%s"' % committish
            )
    else:
        try:
            # branch stack off current branch
            parentbranch = repository.head_ref
        except DetachedHeadException:
            parentbranch = None

    if parentbranch:
        parentremote = config.get('branch.%s.remote' % parentbranch)
        if parentremote:
            out.info('Using remote "%s" to pull parent from' % parentremote)
        else:
            out.info('Recording as a local branch')
    else:
        # no known parent branch, can't guess the remote
        parentremote = None

    stack = Stack.create(
        repository,
        name=branch_name,
        msg='create %s' % branch_name,
        create_at=branch_commit,
        parent_remote=parentremote,
        parent_branch=parentbranch,
        switch_to=True,
    )

    return stack
예제 #3
0
def func(parser, options, args):
    """Integrate a GNU diff patch into the current patch"""
    if len(args) > 1:
        parser.error('incorrect number of arguments')

    repository = directory.repository
    stack = repository.get_stack()

    check_local_changes(repository)
    check_conflicts(repository.default_iw)
    check_head_top_equal(stack)

    if len(args) == 1:
        filename = args[0]
    else:
        filename = None

    applied = stack.patchorder.applied
    if not applied:
        raise CmdException('No patches applied')

    current = applied[-1]

    if filename:
        if os.path.exists(filename):
            out.start('Folding patch "%s"' % filename)
            with io.open(filename, 'rb') as f:
                diff = f.read()
        else:
            raise CmdException('No such file: %s' % filename)
    else:
        out.start('Folding patch from stdin')
        diff = sys.stdin.buffer.read()

    if options.threeway:
        top_patch = stack.patches.get(current)
        apply_patch(
            stack,
            diff,
            base=top_patch.commit.data.parent,
            strip=options.strip,
            reject=options.reject,
        )
    elif options.base:
        apply_patch(
            stack,
            diff,
            base=git_commit(options.base, repository),
            reject=options.reject,
            strip=options.strip,
        )
    else:
        apply_patch(
            stack,
            diff,
            strip=options.strip,
            reject=options.reject,
        )

    out.done()
예제 #4
0
def func(parser, options, args):
    """Show the tree diff"""
    repository = directory.repository

    if options.revs:
        rev_list = options.revs.split('..')
        if len(rev_list) not in [1, 2] or not rev_list[0]:
            parser.error('incorrect parameters to -r')
        elif len(rev_list) == 1:
            rev1 = git_commit(rev_list[0], repository)
            rev2 = None
        else:
            rev1 = git_commit(rev_list[0], repository)
            if rev_list[1]:
                rev2 = git_commit(rev_list[1], repository)
            else:
                rev2 = None
    else:
        rev1 = repository.rev_parse('HEAD')
        rev2 = None

    iw = repository.default_iw

    files = iw.ls_files(rev1.data.tree, args)

    diff_opts = color_diff_flags()
    diff_opts.extend(options.diff_flags)

    if rev1 and rev2:
        diff = repository.diff_tree(
            rev1.data.tree,
            rev2.data.tree,
            diff_opts=diff_opts,
            pathlimits=files,
            stat=options.stat,
            binary=False,
        )
    else:
        diff = iw.diff(
            rev1.data.tree,
            diff_opts=diff_opts,
            pathlimits=files,
            stat=options.stat,
            binary=False,
        )

    pager(diff)
예제 #5
0
def func(parser, options, args):
    """Show the applied patches"""
    if len(args) == 0:
        id_str = 'HEAD'
    elif len(args) == 1:
        id_str = args[0]
    else:
        parser.error('incorrect number of arguments')

    out.stdout(git_commit(id_str, directory.repository).sha1)
예제 #6
0
파일: id.py 프로젝트: miracle2k/stgit
def func(parser, options, args):
    """Show the applied patches
    """
    if len(args) == 0:
        id_str = 'HEAD'
    elif len(args) == 1:
        id_str = args[0]
    else:
        parser.error('incorrect number of arguments')

    out.stdout(common.git_commit(id_str, directory.repository).sha1)
예제 #7
0
def func(parser, options, args):
    """Rebase the current stack"""

    if options.interactive:
        # destination is optional for '--interactive'
        if len(args) not in (0, 1):
            parser.error('incorrect number of arguments')
    else:
        if len(args) != 1:
            parser.error('incorrect number of arguments')

    repository = directory.repository
    stack = repository.get_stack()
    iw = repository.default_iw

    if stack.protected:
        raise CmdException('This branch is protected. Rebase is not permitted')

    if len(args) > 0:
        target = git_commit(args[0], repository)
    else:
        target = stack.base

    if options.autostash and not iw.worktree_clean():
        repository.run(['git', 'stash', 'push']).run()
        stashed_worktree = True
    else:
        stashed_worktree = False

    applied = stack.patchorder.applied
    retval = prepare_rebase(stack, 'rebase')
    if retval:
        return retval
    rebase(stack, iw, target)

    if options.interactive:
        retval = __do_rebase_interactive(repository,
                                         applied,
                                         check_merged=options.merged)
    elif not options.nopush:
        retval = post_rebase(stack,
                             applied,
                             'rebase',
                             check_merged=options.merged)
    else:
        retval = None

    if stashed_worktree:
        try:
            repository.run(['git', 'stash', 'pop']).run()
        except RunException:
            raise StashPopConflictException()

    return retval
예제 #8
0
파일: rebase.py 프로젝트: wildmichael/stgit
def func(parser, options, args):
    """Rebase the current stack"""

    if options.interactive:
        # destination is optional for '--interactive'
        if len(args) not in (0, 1):
            parser.error('incorrect number of arguments')
    else:
        if len(args) != 1:
            parser.error('incorrect number of arguments')

    repository = directory.repository
    stack = repository.get_stack()
    iw = repository.default_iw

    if stack.protected:
        raise CmdException('This branch is protected. Rebase is not permitted')

    if len(args) > 0:
        target = git_commit(args[0], repository)
    else:
        target = stack.base

    applied = stack.patchorder.applied
    retval = prepare_rebase(stack, 'rebase')
    if retval:
        return retval
    rebase(stack, iw, target)

    if options.interactive:
        return __do_rebase_interactive(repository,
                                       applied,
                                       check_merged=options.merged)
    elif not options.nopush:
        return post_rebase(stack,
                           applied,
                           'rebase',
                           check_merged=options.merged)
예제 #9
0
def func(parser, options, args):
    """Import a commit object as a new patch
    """
    if not args:
        parser.error('incorrect number of arguments')

    if options.file and not options.fold:
        parser.error('--file can only be specified with --fold')

    repository = directory.repository
    stack = repository.get_stack()
    iw = repository.default_iw

    if not options.unapplied:
        check_local_changes(repository)
        check_conflicts(iw)
        check_head_top_equal(stack)

    if options.ref_branch:
        ref_stack = repository.get_stack(options.ref_branch)
    else:
        ref_stack = stack

    try:
        patches = parse_patches(
            args,
            ref_stack.patchorder.all_visible,
            len(ref_stack.patchorder.applied),
        )
        commit = None
    except CmdException:
        if len(args) > 1:
            raise

        branch, patch = parse_rev(args[0])

        if not branch:
            commit = git_commit(patch, repository, options.ref_branch)
            patches = []
        else:
            ref_stack = repository.get_stack(branch)
            patches = parse_patches(
                [patch],
                ref_stack.patchorder.all_visible,
                len(ref_stack.patchorder.applied),
            )
            commit = None

    if not commit and len(patches) > 1:
        if options.name:
            raise CmdException('--name can only be specified with one patch')
        if options.parent:
            raise CmdException('--parent can only be specified with one patch')

    if options.update and not stack.patchorder.applied:
        raise CmdException('No patches applied')

    if commit:
        patchname = None
        retval = __pick_commit(stack, ref_stack, iw, commit, patchname,
                               options)
    else:
        if options.unapplied:
            patches.reverse()
        for patchname in patches:
            commit = git_commit(patchname, repository, ref_stack.name)
            retval = __pick_commit(stack, ref_stack, iw, commit, patchname,
                                   options)
            if retval != STGIT_SUCCESS:
                break

    if retval == STGIT_SUCCESS:
        print_current_patch(stack)

    return retval
예제 #10
0
def __pick_commit(stack, ref_stack, iw, commit, patchname, options):
    """Pick a commit."""
    repository = stack.repository

    if options.name:
        patchname = options.name
    elif patchname and options.revert:
        patchname = 'revert-' + patchname

    if patchname:
        patchname = find_patch_name(patchname, stack.patches.exists)
    else:
        patchname = make_patch_name(commit.data.message_str,
                                    stack.patches.exists)

    if options.parent:
        parent = git_commit(options.parent, repository, ref_stack.name)
    else:
        parent = commit.data.parent

    if not options.revert:
        bottom = parent
        top = commit
    else:
        bottom = commit
        top = parent

    if options.fold:
        out.start('Folding commit %s' % commit.sha1)

        diff = repository.diff_tree(bottom.data.tree,
                                    top.data.tree,
                                    pathlimits=options.file)

        if diff:
            try:
                # try a direct git apply first
                iw.apply(diff, quiet=True)
            except MergeException:
                if options.file:
                    out.done('conflict(s)')
                    out.error('%s does not apply cleanly' % patchname)
                    return STGIT_CONFLICT
                else:
                    try:
                        iw.merge(
                            bottom.data.tree,
                            stack.head.data.tree,
                            top.data.tree,
                        )
                    except MergeConflictException as e:
                        out.done('%s conflicts' % len(e.conflicts))
                        out.error('%s does not apply cleanly' % patchname,
                                  *e.conflicts)
                        return STGIT_CONFLICT
            out.done()
        else:
            out.done('no changes')
        return STGIT_SUCCESS
    elif options.update:
        files = [
            fn1 for _, _, _, _, _, fn1, fn2 in repository.diff_tree_files(
                stack.top.data.parent.data.tree, stack.top.data.tree)
        ]

        diff = repository.diff_tree(bottom.data.tree,
                                    top.data.tree,
                                    pathlimits=files)

        out.start('Updating with commit %s' % commit.sha1)

        try:
            iw.apply(diff, quiet=True)
        except MergeException:
            out.done('conflict(s)')
            out.error('%s does not apply cleanly' % patchname)
            return STGIT_CONFLICT
        else:
            out.done()
            return STGIT_SUCCESS
    else:
        author = commit.data.author
        message = commit.data.message_str

        if options.revert:
            author = Person.author()
            if message:
                lines = message.splitlines()
                subject = lines[0]
                body = '\n'.join(lines[2:])
            else:
                subject = commit.sha1
                body = ''
            message = 'Revert "%s"\n\nThis reverts commit %s.\n\n%s\n' % (
                subject,
                commit.sha1,
                body,
            )
        elif options.expose:
            fmt = config.get('stgit.pick.expose-format')
            message = Run('git', 'show', '--no-patch', '--pretty=' + fmt,
                          commit.sha1).raw_output()
            message = message.rstrip() + '\n'

        out.start('Importing commit %s' % commit.sha1)

        new_commit = repository.commit(
            CommitData(
                tree=top.data.tree,
                parents=[bottom],
                message=message,
                author=author,
            ))

        trans = StackTransaction(
            stack, 'pick %s from %s' % (patchname, ref_stack.name))
        trans.patches[patchname] = new_commit

        trans.unapplied.append(patchname)
        if not options.unapplied:
            try:
                trans.push_patch(patchname, iw, allow_interactive=True)
            except TransactionHalted:
                pass

        retval = trans.run(iw, print_current_patch=False)

        if retval == STGIT_CONFLICT:
            out.done('conflict(s)')
        elif stack.patches.get(patchname).is_empty():
            out.done('empty patch')
        else:
            out.done()

        return retval
예제 #11
0
def func(parser, options, args):
    """Pull the changes from a remote repository"""
    repository = directory.repository
    iw = repository.default_iw
    stack = repository.get_stack()
    policy = config.get('branch.%s.stgit.pull-policy' %
                        stack.name) or config.get('stgit.pull-policy')

    if policy not in ['pull', 'fetch-rebase', 'rebase']:
        raise GitConfigException('Unsupported pull-policy "%s"' % policy)

    remote_name = None
    if policy == 'rebase':
        # parent is local
        if len(args) == 1:
            parser.error(
                'specifying a repository is meaningless for policy="%s"' %
                (policy, ))
        elif len(args) > 0:
            parser.error('incorrect number of arguments')
    else:
        # parent is remote
        if len(args) > 1:
            parser.error('incorrect number of arguments')

        if len(args) >= 1:
            remote_name = args[0]
        else:
            remote_name = stack.parent_remote

    if policy in ['pull', 'fetch-rebase'] and remote_name is None:
        parser.error(
            'There is no tracking information for the current branch.\n'
            'Please specify the remote repository to pull from.')

    if stack.protected:
        raise CmdException('This branch is protected. Pulls are not permitted')

    applied = stack.patchorder.applied

    retval = prepare_rebase(stack, 'pull')
    if retval:
        return retval

    # pull the remote changes
    if policy == 'pull':
        out.info('Pulling from "%s"' % remote_name)
        pull(repository, remote_name)
    elif policy == 'fetch-rebase':
        out.info('Fetching from "%s"' % remote_name)
        fetch(repository, remote_name)
        try:
            target = repository.rev_parse('FETCH_HEAD')
        except RepositoryException:
            out.error('Could not find the remote head to rebase onto - '
                      'fix branch.%s.merge in .git/config' % stack.name)
            out.error('Pushing any patches back...')
            post_rebase(stack, applied, 'pull', check_merged=False)
            raise

        rebase(stack, iw, target)
    elif policy == 'rebase':
        value = config.get('branch.%s.stgit.parentbranch' % stack.name)
        if value:
            parent_commit = git_commit(value, repository)
        else:
            try:
                parent_commit = repository.rev_parse('heads/origin')
            except RepositoryException:
                raise CmdException('Cannot find a parent branch for "%s"' %
                                   stack.name)
            else:
                out.warn(
                    'No parent branch declared for stack "%s", defaulting to'
                    '"heads/origin".' % stack.name,
                    'Consider setting "branch.%s.stgit.parentbranch" with '
                    '"git config".' % stack.name,
                )
        rebase(stack, iw, parent_commit)

    if not options.nopush:
        post_rebase(stack, applied, 'pull', check_merged=options.merged)

    # maybe tidy up
    if config.getbool('stgit.keepoptimized'):
        repository.repack()