예제 #1
0
def rebasenode(repo, rev, target, state, skipped, targetancestors, collapse,
               extrafn):
    'Rebase a single revision'
    repo.ui.debug(_("rebasing %d:%s\n") % (rev, repo[rev]))

    p1, p2 = defineparents(repo, rev, target, state, targetancestors)

    repo.ui.debug(
        _(" future parents are %d and %d\n") %
        (repo[p1].rev(), repo[p2].rev()))

    # Merge phase
    if len(repo.parents()) != 2:
        # Update to target and merge it with local
        if repo['.'].rev() != repo[p1].rev():
            repo.ui.debug(_(" update to %d:%s\n") % (repo[p1].rev(), repo[p1]))
            merge.update(repo, p1, False, True, False)
        else:
            repo.ui.debug(_(" already in target\n"))
        repo.dirstate.write()
        repo.ui.debug(
            _(" merge against %d:%s\n") % (repo[rev].rev(), repo[rev]))
        first = repo[rev].rev() == repo[min(state)].rev()
        stats = rebasemerge(repo, rev, first)

        if stats[3] > 0:
            raise util.Abort(
                _('fix unresolved conflicts with hg resolve then '
                  'run hg rebase --continue'))
    else:  # we have an interrupted rebase
        repo.ui.debug(_('resuming interrupted rebase\n'))

    # Keep track of renamed files in the revision that is going to be rebased
    # Here we simulate the copies and renames in the source changeset
    cop, diver = copies.copies(repo, repo[rev], repo[target], repo[p2], True)
    m1 = repo[rev].manifest()
    m2 = repo[target].manifest()
    for k, v in cop.iteritems():
        if k in m1:
            if v in m1 or v in m2:
                repo.dirstate.copy(v, k)
                if v in m2 and v not in m1:
                    repo.dirstate.remove(v)

    newrev = concludenode(repo, rev, p1, p2, state, collapse, extrafn=extrafn)

    # Update the state
    if newrev is not None:
        state[rev] = repo[newrev].rev()
    else:
        if not collapse:
            repo.ui.note(_('no changes, revision %d skipped\n') % rev)
            repo.ui.debug(_('next revision set to %s\n') % p1)
            skipped.add(rev)
        state[rev] = p1
예제 #2
0
def rebasenode(repo, rev, target, state, skipped, targetancestors, collapse,
               extrafn):
    'Rebase a single revision'
    repo.ui.debug(_("rebasing %d:%s\n") % (rev, repo[rev]))

    p1, p2 = defineparents(repo, rev, target, state, targetancestors)

    repo.ui.debug(_(" future parents are %d and %d\n") % (repo[p1].rev(),
                                                            repo[p2].rev()))

    # Merge phase
    if len(repo.parents()) != 2:
        # Update to target and merge it with local
        if repo['.'].rev() != repo[p1].rev():
            repo.ui.debug(_(" update to %d:%s\n") % (repo[p1].rev(), repo[p1]))
            merge.update(repo, p1, False, True, False)
        else:
            repo.ui.debug(_(" already in target\n"))
        repo.dirstate.write()
        repo.ui.debug(_(" merge against %d:%s\n") % (repo[rev].rev(), repo[rev]))
        first = repo[rev].rev() == repo[min(state)].rev()
        stats = rebasemerge(repo, rev, first)

        if stats[3] > 0:
            raise util.Abort(_('fix unresolved conflicts with hg resolve then '
                                                'run hg rebase --continue'))
    else: # we have an interrupted rebase
        repo.ui.debug(_('resuming interrupted rebase\n'))

    # Keep track of renamed files in the revision that is going to be rebased
    # Here we simulate the copies and renames in the source changeset
    cop, diver = copies.copies(repo, repo[rev], repo[target], repo[p2], True)
    m1 = repo[rev].manifest()
    m2 = repo[target].manifest()
    for k, v in cop.iteritems():
        if k in m1:
            if v in m1 or v in m2:
                repo.dirstate.copy(v, k)
                if v in m2 and v not in m1:
                    repo.dirstate.remove(v)

    newrev = concludenode(repo, rev, p1, p2, state, collapse,
                          extrafn=extrafn)

    # Update the state
    if newrev is not None:
        state[rev] = repo[newrev].rev()
    else:
        if not collapse:
            repo.ui.note(_('no changes, revision %d skipped\n') % rev)
            repo.ui.debug(_('next revision set to %s\n') % p1)
            skipped.add(rev)
        state[rev] = p1
예제 #3
0
파일: rebase.py 프로젝트: ThissDJ/designhub
def updatedirstate(repo, rev, p1, p2):
    """Keep track of renamed files in the revision that is going to be rebased
    """
    # Here we simulate the copies and renames in the source changeset
    cop, diver = copies.copies(repo, repo[rev], repo[p1], repo[p2], True)
    m1 = repo[rev].manifest()
    m2 = repo[p1].manifest()
    for k, v in cop.iteritems():
        if k in m1:
            if v in m1 or v in m2:
                repo.dirstate.copy(v, k)
                if v in m2 and v not in m1:
                    repo.dirstate.remove(v)
예제 #4
0
def updatedirstate(repo, rev, p1, p2):
    """Keep track of renamed files in the revision that is going to be rebased
    """
    # Here we simulate the copies and renames in the source changeset
    cop, diver = copies.copies(repo, repo[rev], repo[p1], repo[p2], True)
    m1 = repo[rev].manifest()
    m2 = repo[p1].manifest()
    for k, v in cop.iteritems():
        if k in m1:
            if v in m1 or v in m2:
                repo.dirstate.copy(v, k)
                if v in m2 and v not in m1:
                    repo.dirstate.remove(v)
예제 #5
0
def visualdiff(ui, repo, pats, opts):
    revs = opts.get('rev', [])
    change = opts.get('change')

    try:
        ctx1b = None
        if change:
            ctx2 = repo[change]
            p = ctx2.parents()
            if len(p) > 1:
                ctx1a, ctx1b = p
            else:
                ctx1a = p[0]
        else:
            n1, n2 = hglib.revpair(repo, revs)
            ctx1a, ctx2 = repo[n1], repo[n2]
            p = ctx2.parents()
            if not revs and len(p) > 1:
                ctx1b = p[1]
    except (error.LookupError, error.RepoError):
        QMessageBox.warning(None,
                       _('Unable to find changeset'),
                       _('You likely need to refresh this application'))
        return None

    pats = hglib.expandpats(pats)
    m = match.match(repo.root, '', pats, None, None, 'relpath')
    n2 = ctx2.node()
    mod_a, add_a, rem_a = map(set, repo.status(ctx1a.node(), n2, m)[:3])
    if ctx1b:
        mod_b, add_b, rem_b = map(set, repo.status(ctx1b.node(), n2, m)[:3])
        cpy = copies.copies(repo, ctx1a, ctx1b, ctx1a.ancestor(ctx1b))[0]
    else:
        cpy = copies.copies(repo, ctx1a, ctx2, repo[-1])[0]
        mod_b, add_b, rem_b = set(), set(), set()
    MA = mod_a | add_a | mod_b | add_b
    MAR = MA | rem_a | rem_b
    if not MAR:
        QMessageBox.information(None,
                _('No file changes'),
                _('There are no file changes to view'))
        return None

    detectedtools = hglib.difftools(repo.ui)
    if not detectedtools:
        QMessageBox.warning(None,
                _('No diff tool found'),
                _('No visual diff tools were detected'))
        return None

    preferred = besttool(repo.ui, detectedtools, opts.get('tool'))

    # Build tool list based on diff-patterns matches
    toollist = set()
    patterns = repo.ui.configitems('diff-patterns')
    patterns = [(p, t) for p,t in patterns if t in detectedtools]
    for path in MAR:
        for pat, tool in patterns:
            mf = match.match(repo.root, '', [pat])
            if mf(path):
                toollist.add(tool)
                break
        else:
            toollist.add(preferred)

    cto = cpy.keys()
    for path in MAR:
        if path in cto:
            hascopies = True
            break
    else:
        hascopies = False
    force = repo.ui.configbool('tortoisehg', 'forcevdiffwin')
    if len(toollist) > 1 or (hascopies and len(MAR) > 1) or force:
        usewin = True
    else:
        preferred = toollist.pop()
        dirdiff = repo.ui.configbool('merge-tools', preferred + '.dirdiff')
        dir3diff = repo.ui.configbool('merge-tools', preferred + '.dir3diff')
        usewin = repo.ui.configbool('merge-tools', preferred + '.usewin')
        if not usewin and len(MAR) > 1:
            if ctx1b is not None:
                usewin = not dir3diff
            else:
                usewin = not dirdiff
    if usewin:
        # Multiple required tools, or tool does not support directory diffs
        sa = [mod_a, add_a, rem_a]
        sb = [mod_b, add_b, rem_b]
        dlg = FileSelectionDialog(repo, pats, ctx1a, sa, ctx1b, sb, ctx2, cpy)
        return dlg

    # We can directly use the selected tool, without a visual diff window
    diffcmd, diffopts, mergeopts = detectedtools[preferred]

    # Disable 3-way merge if there is only one parent or no tool support
    do3way = False
    if ctx1b:
        if mergeopts:
            do3way = True
            args = mergeopts
        else:
            args = diffopts
            if str(ctx1b.rev()) in revs:
                ctx1a = ctx1b
    else:
        args = diffopts

    def dodiff():
        assert not (hascopies and len(MAR) > 1), \
                'dodiff cannot handle copies when diffing dirs'

        sa = [mod_a, add_a, rem_a]
        sb = [mod_b, add_b, rem_b]
        ctxs = [ctx1a, ctx1b, ctx2]

        # If more than one file, diff on working dir copy.
        copyworkingdir = len(MAR) > 1
        dirs, labels, fns_and_mtimes = snapshotset(repo, ctxs, sa, sb, cpy,
                                                   copyworkingdir)
        dir1a, dir1b, dir2 = dirs
        label1a, label1b, label2 = labels
        fns_and_mtime = fns_and_mtimes[2]

        if len(MAR) > 1 and label2 == '':
            label2 = 'working files'

        def getfile(fname, dir, label):
            file = os.path.join(qtlib.gettempdir(), dir, fname)
            if os.path.isfile(file):
                return fname+label, file
            nullfile = os.path.join(qtlib.gettempdir(), 'empty')
            fp = open(nullfile, 'w')
            fp.close()
            return (hglib.fromunicode(_nonexistant, 'replace') + label,
                    nullfile)

        # If only one change, diff the files instead of the directories
        # Handle bogus modifies correctly by checking if the files exist
        if len(MAR) == 1:
            file2 = util.localpath(MAR.pop())
            if file2 in cto:
                file1 = util.localpath(cpy[file2])
            else:
                file1 = file2
            label1a, dir1a = getfile(file1, dir1a, label1a)
            if do3way:
                label1b, dir1b = getfile(file1, dir1b, label1b)
            label2, dir2 = getfile(file2, dir2, label2)
        if do3way:
            label1a += '[local]'
            label1b += '[other]'
            label2 += '[merged]'

        replace = dict(parent=dir1a, parent1=dir1a, parent2=dir1b,
                       plabel1=label1a, plabel2=label1b,
                       phash1=str(ctx1a), phash2=str(ctx1b),
                       repo=hglib.fromunicode(repo.displayname),
                       clabel=label2, child=dir2, chash=str(ctx2))
        launchtool(diffcmd, args, replace, True)

        # detect if changes were made to mirrored working files
        for copy_fn, working_fn, mtime in fns_and_mtime:
            try:
                if os.lstat(copy_fn).st_mtime != mtime:
                    ui.debug('file changed while diffing. '
                            'Overwriting: %s (src: %s)\n' % (working_fn, copy_fn))
                    util.copyfile(copy_fn, working_fn)
            except EnvironmentError:
                pass # Ignore I/O errors or missing files

    def dodiffwrapper():
        try:
            dodiff()
        finally:
            # cleanup happens atexit
            ui.note(_('cleaning up temp directory\n'))

    if opts.get('mainapp'):
        dodiffwrapper()
    else:
        # We are not the main application, so this must be done in a
        # background thread
        thread = threading.Thread(target=dodiffwrapper, name='visualdiff')
        thread.setDaemon(True)
        thread.start()