def revert(parent, ui, repo, files): revertopts = {'date': None, 'rev': '.', 'all': False} if len(repo.parents()) > 1: res = qtlib.CustomPrompt( _('Uncommited merge - please select a parent revision'), _('Revert files to local or other parent?'), parent, (_('&Local'), _('&Other'), _('Cancel')), 0, 2, files).run() if res == 0: revertopts['rev'] = repo[None].p1().rev() elif res == 1: revertopts['rev'] = repo[None].p2().rev() else: return False commands.revert(ui, repo, *files, **revertopts) else: wctx = repo[None] if [file for file in files if file in wctx.modified()]: res = qtlib.CustomPrompt( _('Confirm Revert'), _('Revert local file changes?'), parent, (_('&Revert with backup'), _('&Discard changes'), _('Cancel')), 2, 2, files).run() if res == 2: return False if res == 1: revertopts['no_backup'] = True else: res = qtlib.CustomPrompt(_('Confirm Revert'), _('Revert the following files?'), parent, (_('&Revert'), _('Cancel')), 1, 1, files).run() if res == 1: return False commands.revert(ui, repo, *files, **revertopts) return True
def revert(self, files, no_backup=True): opts = { 'no_backup': no_backup, 'date': '', 'rev': '', } commands.revert(self.ui, self.repository, *[os.path.join(self.path, fn) for fn in files], **opts)
def cleanup(self): try: commands.revert(self.repo.ui, self.repo, date=None, rev=None, all=True, no_backup=True) hg.clean(self.repo, self.branch, show_stats=False) except Exception, e: logger.error(e)
def makecollapsed(ui, repo, parent, revs): 'Creates the collapsed revision on top of parent' last = max(revs) ui.debug(_('updating to revision %d\n') % parent) merge.update(repo, parent.node(), False, False, False) ui.debug(_('reverting to revision %d\n') % last) commands.revert(ui, repo, rev=last, all=True, date=None) msg = '' first = True for r in revs: if not first: msg += '----------------\n' first = False msg += repo[r].description() + "\n" msg += "\nHG: Enter commit message. Lines beginning with 'HG:' are removed.\n" msg += "HG: Remove all lines to abort the collapse operation.\n" msg = ui.edit(msg, ui.username()) if not msg: raise util.Abort(_('empty commit message, collapse won\'t proceed')) newrev = repo.commit( text=msg, user=repo[last].user(), date=repo[last].date()) return repo[newrev]
def removeFile(self, wfile): repo = self.repo ctx = self.ctx if isinstance(ctx, patchctx): repo.thgbackup(ctx._path) fp = util.atomictempfile(ctx._path, 'wb') try: if ctx._ph.comments: fp.write('\n'.join(ctx._ph.comments)) fp.write('\n\n') for file in ctx._fileorder: if file == wfile: continue for chunk in ctx._files[file]: chunk.write(fp) fp.close() finally: del fp ctx.invalidate() else: fullpath = repo.wjoin(wfile) repo.thgbackup(fullpath) wasadded = wfile in repo[None].added() try: commands.revert(repo.ui, repo, fullpath, rev='.', no_backup=True) if wasadded and os.path.exists(fullpath): os.unlink(fullpath) except EnvironmentError: qtlib.InfoMsgBox(_("Unable to remove"), _("Unable to remove file %s,\n" "permission denied") % hglib.tounicode(wfile)) self.fileModified.emit()
def movedescendants(ui, repo, collapsed, tomove, movemap): 'Moves the descendants of the source revisions to the collapsed revision' sorted_tomove = list(tomove) sorted_tomove.sort() for r in sorted_tomove: ui.debug(_('moving revision %r\n') % r) parents = [p.rev() for p in repo[r].parents()] if len(parents) == 1: ui.debug(_('setting parent to %d\n') % movemap[parents[0]].rev()) repo.dirstate.setparents(movemap[parents[0]].node()) else: ui.debug(_('setting parents to %d and %d\n') % (movemap[parents[0]].rev(), movemap[parents[1]].rev())) repo.dirstate.setparents(movemap[parents[0]].node(), movemap[parents[1]].node()) repo.dirstate.write() ui.debug(_('reverting to revision %d\n') % r) commands.revert(ui, repo, rev=r, all=True, date=None) newrev = repo.commit(text=repo[r].description(), user=repo[r].user(), date=repo[r].date()) ctx = repo[newrev] movemap[r] = ctx
def cleanup(self, repo, pats, opts): '''removes all changes from the working copy and makes it so there isn't a patch applied''' # find added files in the user's chosen set m = cmdutil.match(repo, pats, opts) added = repo.status(match=m)[1] revertopts = { 'include': opts.get('include'), 'exclude': opts.get('exclude'), 'date': None, 'all': True, 'rev': '.', 'no_backup': True, } self.ui.pushbuffer() # silence revert try: commands.revert(self.ui, repo, *pats, **revertopts) # finish the job of reverting added files (safe because they are # saved in the attic patch) for fn in added: self.ui.status(_('removing %s\n') % fn) util.unlink(fn) finally: self.ui.popbuffer() self.applied = '' self.persiststate()
def cleanup(self, repo, pats, opts): '''removes all changes from the working copy and makes it so there isn't a patch applied''' # find added files in the user's chosen set m = cmdutil.match(repo, pats, opts) added = repo.status(match=m)[1] revertopts = { 'include': opts.get('include'), 'exclude': opts.get('exclude'), 'date': None, 'all': True, 'rev': '.', 'no_backup': True, } self.ui.pushbuffer() # silence revert try: commands.revert(self.ui, repo, *pats, **revertopts) # finish the job of reverting added files (safe because they are # saved in the attic patch) for fn in added: self.ui.status(_('removing %s\n') % fn) util.unlink(fn) finally: self.ui.popbuffer() self.applied = '' self.persiststate()
def clean_working_copy(self): self.strip_outgoing() self.ui.pushbuffer() try: commands.update(self.ui, self.repo, clean=True) commands.revert(self.ui, self.repo, all=True, no_backup=True) finally: self.ui.popbuffer()
def recreaterev(ui, repo, rev): ui.debug(_('reverting to revision %d\n') % rev) commands.revert(ui, repo, rev=rev, all=True, date=None) wctx = repo[None] node = repo[rev] ss = node.substate for path, info in ss.items(): ui.debug(_('updating subrepo %s to revision %s\n') % (path, info[1])) wctx.sub(path).get(info)
def recreaterev(ui, repo, rev): ui.debug(_('reverting to revision %d\n') % rev) commands.revert(ui, repo, rev=rev, all=True, date=None, no_backup=True) wctx = repo[None] node = repo[rev] ss = node.substate for path, info in ss.items(): ui.debug(_('updating subrepo %s to revision %s\n') % (path, info[1])) wctx.sub(path).get(info)
def clearShelfA(self): if self.comboa.currentIndex() == 0: if not qtlib.QuestionMsgBox(_('Are you sure?'), _('Revert all working copy changes?')): return try: self.repo.ui.quiet = True commands.revert(self.repo.ui, self.repo, all=True) self.repo.ui.quiet = False except (EnvironmentError, error.Abort), e: self.showMessage(hglib.tounicode(str(e))) self.refreshCombos() return
def clearShelfA(self): if self.comboa.currentIndex() == 0: if not qtlib.QuestionMsgBox(_('Are you sure?'), _('Revert all working copy changes?')): return try: self.repo.ui.quiet = True commands.revert(self.repo.ui, self.repo, all=True) self.repo.ui.quiet = False except (EnvironmentError, error.Abort), e: self.showMessage(hglib.tounicode(str(e))) self.refreshCombos() return
def cleanup(self, repo, pats=[], opts={}): '''removes all changes from the working copy and makes it so there isn't a patch applied''' node = repo.dirstate.parents()[0] if not pats and not opts.get('include') and not opts.get('exclude'): hg.clean(repo, node, False) else: opts['date'] = None opts['all'] = True # Just to trick revert opts['rev'] = node commands.revert(self.ui, repo, *pats, **opts) self.applied = '' self.persiststate()
def revert(self, paths, rev=None): # XXX: how to pass opts['all']? if rev is None: parents = self.repo.parents() if len(parents) != 1 and rev is None: # XXX: better exception type? raise Exception( "can't revert on top of a merge without explicit rev") rev = parents[0].rev() commands.revert(self.ui, self.repo, date=None, rev=rev, no_backup=False, *self.joined(paths))
def _revert_confirmed(self, repository, filepath): """Revert the given file to its pristine state.""" # The variable passing schema we use means that we'll have problems # with a repository named 'on'. We should look into a fix for that. # TODO Make this get require a post and spit back a confirmation form url = request.environ['routes.url'] if not repository or not filepath: redirect(url.current(action='index')) found = False for repoobj, root in self.repositories: if root == repository: found = True repo = repoobj break if not found: redirect(url.current(action='index')) repochroot = Chroot(repo.root) try: fullfilepath = repochroot(path.join(repo.root, filepath)) except IOError: error = 'Bad Filename' redirect(url.current(action='index', error=error)) # repo.status() returns a tuple of lists, each lists containing the # files containing a given status. Those are: # modified, added, removed, deleted, unknown, ignored, clean statusmapper = dict(enumerate(['modified', 'added', 'removed', 'deleted', 'unknown', 'ignored', 'clean'])) statuses = repo.status() for index, status in statusmapper.iteritems(): if status not in ['modified', 'added', 'removed', 'deleted']: # Unknown, ignored, and clean files can't be reverted... if filepath in statuses[index]: c.status = status c.error = "Can't revert this file" return render('dv/revert.html') continue if filepath in statuses[index]: commands.revert(self.ui, repo, fullfilepath, rev='tip', date=None) if status == 'added' and request.params.get('remove'): unlink(fullfilepath) redirect(url(repository=repository, controller='dv', action='index')) c.error = 'Not found' return render('dv/revert.html')
def removeFile(self, wfile): repo = self.repo ctx = self.ctx if isinstance(ctx, patchctx): repo.thgbackup(ctx._path) fp = util.atomictempfile(ctx._path, 'wb') try: if ctx._ph.comments: fp.write('\n'.join(ctx._ph.comments)) fp.write('\n\n') for file in ctx._fileorder: if file == wfile: continue for chunk in ctx._files[file]: chunk.write(fp) fp.close() finally: del fp ctx.invalidate() else: fullpath = repo.wjoin(wfile) repo.thgbackup(fullpath) wasadded = wfile in repo[None].added() try: commands.revert(repo.ui, repo, fullpath, rev='.', no_backup=True) if wasadded and os.path.exists(fullpath): os.unlink(fullpath) except EnvironmentError: qtlib.InfoMsgBox( _("Unable to remove"), _("Unable to remove file %s,\n" "permission denied") % hglib.tounicode(wfile)) self.fileModified.emit()
def revert(parent, ui, repo, files): revertopts = {'date': None, 'rev': '.', 'all': False} if len(repo.parents()) > 1: res = qtlib.CustomPrompt( _('Uncommited merge - please select a parent revision'), _('Revert files to local or other parent?'), parent, (_('&Local'), _('&Other'), _('Cancel')), 0, 2, files).run() if res == 0: revertopts['rev'] = repo[None].p1().rev() elif res == 1: revertopts['rev'] = repo[None].p2().rev() else: return False commands.revert(ui, repo, *files, **revertopts) else: wctx = repo[None] if [file for file in files if file in wctx.modified()]: res = qtlib.CustomPrompt( _('Confirm Revert'), _('Revert local file changes?'), parent, (_('&Revert with backup'), _('&Discard changes'), _('Cancel')), 2, 2, files).run() if res == 2: return False if res == 1: revertopts['no_backup'] = True else: res = qtlib.CustomPrompt( _('Confirm Revert'), _('Revert the following files?'), parent, (_('&Revert'), _('Cancel')), 1, 1, files).run() if res == 1: return False commands.revert(ui, repo, *files, **revertopts) return True
def revert(parent, ui, repo, files): revertopts = {"date": None, "rev": "."} if len(repo.parents()) > 1: res = qtlib.CustomPrompt( _("Uncommited merge - please select a parent revision"), _("Revert files to local or other parent?"), parent, (_("&Local"), _("&Other"), _("Cancel")), 0, 2, files, ).run() if res == 0: revertopts["rev"] = repo[None].p1().rev() elif res == 1: revertopts["rev"] = repo[None].p2().rev() else: return commands.revert(ui, repo, *files, **revertopts) else: res = qtlib.CustomPrompt( _("Confirm Revert"), _("Revert local file changes?"), parent, (_("&Revert with backup"), _("&Discard changes"), _("Cancel")), 2, 2, files, ).run() if res == 2: return False if res == 1: revertopts["no_backup"] = True commands.revert(ui, repo, *files, **revertopts) return True
def tclose(ui, repo, *args, **opts): """ close the current topic branch and push to the central repository """ mustBeTopicRepo(repo) # Sanity check if not isClean(ui, repo): return 1 if args: branches = args else: if not onTopicBranch(ui, repo): return 1 branches = [repo.dirstate.branch()] if 'tmenu' in opts: if ui.prompt("Branch '%s': close it?" % branches[0]).upper() != 'Y': return 1 opts = { 'nopull':False, 'nopush':False } pulled = False # only pull once for branch in branches: # Pull new changes from the central repo to avoid multiple-heads problem if not opts['nopull'] and not pulled: if tryCommand(ui, "pull", lambda:commands.pull(ui, repo, **opts) >= 2): return 1 pulled = True # Can't close already closed branches, nor any of the special branches if not repo.branchheads(branch) or branch in repo.topicSpecialBranches: ui.warn("Error: %s is not an open topic branch\n" % branch) return 1 # Now update to the head of the branch being closed if repo.dirstate.parents()[0] not in repo.branchheads(branch): if tryCommand(ui, "update %s" % quoteBranch(branch), lambda:commands.update(ui, repo, node=branch)): return 1 # Unlike a normal hg commit, if no text is specified we supply a reasonable default. branch = repo.dirstate.branch() text = opts.get('message') if text is None: text = "Closing %s" % branch # Close it if tryCommand(ui, "commit --close-branch", lambda:repo.commit(text, extra = {'close':'True'}) is None): return 1 # Aditionally, for this to not be considered a "head" it has to have a # child commit. So we have to merge into prod. First, update. # if tryCommand(ui, "update %s" % repo.topicProdBranch, lambda:commands.update(ui, repo, node=repo.topicProdBranch)): return 1 # Now merge, ignoring all conflicts. mergeOpts = copy.deepcopy(opts) mergeOpts['tool'] = "internal:fail" mergeOpts['noninteractive'] = True # Ignore return value... ok if merge fails tryCommand(ui, "merge -r %s" % quoteBranch(branch), lambda:commands.merge(ui, repo, node=branch, **mergeOpts), repo = repo) # Revert all files to prod (regardless of what happened on the branch) revertOpts = copy.deepcopy(opts) revertOpts['all'] = True revertOpts['rev'] = "." if tryCommand(ui, "revert -a -r .", lambda:commands.revert(ui, repo, **revertOpts), repo = repo): return 1 # Were there any merge conflicts? resolveOpts = copy.deepcopy(opts) resolveOpts['list'] = True if tryCommand(ui, "resolve -l", lambda:commands.resolve(ui, repo, **resolveOpts), repo = repo): return 1 # Anything that had a merge conflict, mark it resolved (by the revert) if ui.lastTryCommandOutput != '': resolveOpts = copy.deepcopy(opts) resolveOpts['all'] = True resolveOpts['mark'] = True if tryCommand(ui, "resolve -a -m", lambda:commands.resolve(ui, repo, **resolveOpts), repo = repo): return 1 # Commit the merge if tryCommand(ui, "commit", lambda:repo.commit(text) is None): return 1 # And push. if not opts['nopush']: pushOpts = copy.deepcopy(opts) if 'message' in pushOpts: del pushOpts['message'] pushOpts['force'] = True nameSet = set() for name, path in ui.configitems("paths"): nameSet.add(name) if tryCommand(ui, "push -f -b %s -b %s default" % (quoteBranch(branch), repo.topicProdBranch), lambda:commands.push(ui, repo, branch=(branch,repo.topicProdBranch), **pushOpts), repo=repo) > 1: return 1 if "dev" in nameSet: if tryCommand(ui, "push -f -b %s -b %s dev" % (quoteBranch(branch), repo.topicProdBranch), lambda:commands.push(ui, repo, branch=(branch,repo.topicProdBranch), dest="dev", **pushOpts), repo=repo) > 1: return 1 if "stage" in nameSet: if tryCommand(ui, "push -f -b %s -b %s stage" % (quoteBranch(branch), repo.topicProdBranch), lambda:commands.push(ui, repo, branch=(branch,repo.topicProdBranch), dest="stage", **pushOpts), repo=repo) > 1: return 1 if "prod" in nameSet: if tryCommand(ui, "push -f -b %s -b %s prod" % (quoteBranch(branch), repo.topicProdBranch), lambda:commands.push(ui, repo, branch=(branch,repo.topicProdBranch), dest="prod", **pushOpts), repo=repo) > 1: return 1 ui.status("Done.\n")
def dohgrevert(): commands.revert(self.stat.ui, self.stat.repo, *wfiles, **revertopts)
def split(ui, repo, *revs, **opts): """split a changeset into smaller changesets By default, split the current revision by prompting for all its hunks to be redistributed into new changesets. Use --rev to split a given changeset instead. """ tr = wlock = lock = None newcommits = [] revarg = (list(revs) + opts.get('rev')) or ['.'] if len(revarg) != 1: msg = _("more than one revset is given") hnt = _("use either `hg split <rs>` or `hg split --rev <rs>`, not both") raise error.Abort(msg, hint=hnt) rev = scmutil.revsingle(repo, revarg[0]) if opts.get('no_rebase'): torebase = () else: torebase = repo.revs('descendants(%d) - (%d)', rev, rev) try: wlock = repo.wlock() lock = repo.lock() cmdutil.bailifchanged(repo) if torebase: cmdutil.checkunfinished(repo) tr = repo.transaction('split') ctx = repo[rev] r = ctx.rev() disallowunstable = not obsolete.isenabled(repo, obsolete.allowunstableopt) if disallowunstable: # XXX We should check head revs if repo.revs("(%d::) - %d", rev, rev): raise error.Abort(_("cannot split commit: %s not a head") % ctx) if len(ctx.parents()) > 1: raise error.Abort(_("cannot split merge commits")) prev = ctx.p1() bmupdate = common.bookmarksupdater(repo, ctx.node(), tr) bookactive = repo._activebookmark if bookactive is not None: repo.ui.status(_("(leaving bookmark %s)\n") % repo._activebookmark) bookmarks.deactivate(repo) hg.update(repo, prev) commands.revert(ui, repo, rev=r, all=True) def haschanges(): modified, added, removed, deleted = repo.status()[:4] return modified or added or removed or deleted msg = ("HG: This is the original pre-split commit message. " "Edit it as appropriate.\n\n") msg += ctx.description() opts['message'] = msg opts['edit'] = True while haschanges(): pats = () cmdutil.dorecord(ui, repo, commands.commit, 'commit', False, cmdutil.recordfilter, *pats, **opts) # TODO: Does no seem like the best way to do this # We should make dorecord return the newly created commit newcommits.append(repo['.']) if haschanges(): if ui.prompt('Done splitting? [yN]', default='n') == 'y': commands.commit(ui, repo, **opts) newcommits.append(repo['.']) break else: ui.status(_("no more change to split\n")) if newcommits: tip = repo[newcommits[-1]] bmupdate(tip.node()) if bookactive is not None: bookmarks.activate(repo, bookactive) obsolete.createmarkers(repo, [(repo[r], newcommits)], operation='split') if torebase: top = repo.revs('allsuccessors(%d)', rev).last() common.restackonce(ui, repo, top) tr.close() finally: lockmod.release(tr, lock, wlock)
def deleteSelectedChunks(self): 'delete currently selected chunks' repo = self.repo chunks = self.diffbrowse.curchunks dchunks = [c for c in chunks[1:] if c.selected] if not dchunks: self.showMessage.emit(_('No deletable chunks')) return ctx = self.ctx kchunks = [c for c in chunks[1:] if not c.selected] revertall = False if not kchunks: if isinstance(ctx, patchctx): revertmsg = _('Completely remove file from patch?') else: revertmsg = _('Revert all file changes?') revertall = qtlib.QuestionMsgBox(_('No chunks remain'), revertmsg) if isinstance(ctx, patchctx): repo.thgbackup(ctx._path) fp = util.atomictempfile(ctx._path, 'wb') buf = cStringIO.StringIO() try: if ctx._ph.comments: buf.write('\n'.join(ctx._ph.comments)) buf.write('\n\n') needsnewline = False for wfile in ctx._fileorder: if wfile == self.currentFile: if revertall: continue chunks[0].write(buf) for chunk in kchunks: chunk.write(buf) else: if buf.tell() and buf.getvalue()[-1] != '\n': buf.write('\n') for chunk in ctx._files[wfile]: chunk.write(buf) fp.write(buf.getvalue()) fp.close() finally: del fp ctx.invalidate() self.fileModified.emit() else: path = repo.wjoin(self.currentFile) if not os.path.exists(path): self.showMessage.emit(_('file has been deleted, refresh')) return if self.mtime != os.path.getmtime(path): self.showMessage.emit(_('file has been modified, refresh')) return repo.thgbackup(path) if revertall: commands.revert(repo.ui, repo, path, no_backup=True) else: wlock = repo.wlock() try: # atomictemp can preserve file permission wf = repo.wopener(self.currentFile, 'wb', atomictemp=True) wf.write(self.diffbrowse.origcontents) wf.close() fp = cStringIO.StringIO() chunks[0].write(fp) for c in kchunks: c.write(fp) fp.seek(0) self.runPatcher(fp, self.currentFile, False) finally: wlock.release() self.fileModified.emit()
def subpull(ui, repo, name='', **opts): """Pull subtree(s)""" # change to root directory if repo.getcwd() != '': ui.warn( "Working directory is not repository root. At best, this directory won't exist when subpull is done.\n" ) repo.dirstate._cwd = repo.root os.chdir(repo.root) # if there are uncommitted change, abort --- we will be modifying the working copy quite drammatically modified, added, removed, deleted, _unknown, _ignored, _clean = repo.status( ) if modified or added or removed or deleted: raise error.Abort( "Uncommitted changes in the working copy. Subtree extension needs to modify the working copy, so it cannot proceed." ) # parse .hgsubtree hgsubtree = ui.config('subtree', 'hgsubtree', default=default_hgsubtree) subtrees = _parse_hgsubtree(os.path.join(repo.root, hgsubtree)) # if names not in .hgsubtree, abort # if names is empty, go through all repos in .hgsubtree if name: if name not in subtrees: raise error.Abort("Cannot find %s in %s." % (name, hgsubtree)) names = [name] else: if opts['source']: raise error.Abort( "Cannot use --source without specifying a repository") names = subtrees.keys() null = repo['null'] origin = str(repo[None]) commit_opts = {'edit': opts['edit']} bookmark_prefix = ui.config('subtree', 'bookmark', default=default_bookmark_prefix) nocache = ui.config('subtree', 'nocache', default='') for name in names: subtree = subtrees[name] if 'destination' not in subtree: raise error.Abort('No destination found for %s' % name) collapse = 'collapse' in subtree and subtree['collapse'] # figure out the revision to pull pull_opts = {} if 'rev' in subtree: pull_opts['rev'] = [subtree['rev']] if opts['rev']: pull_opts['rev'] = opts['rev'] # clone or pull into cache source = subtree['source'] if not opts['source'] else opts['source'] if not nocache: source = _clone_or_pull(ui, repo, name, source, pull_opts) # pull tip = repo['tip'] commands.pull(ui, repo, source=source, force=True, **pull_opts) if tip == repo['tip']: ui.status("no changes: nothing for subtree to do\n") continue # collapse or update -C if collapse: # find a matching bookmark bookmark_name = bookmark_prefix + name if bookmark_name in repo._bookmarks: commands.update(ui, repo, bookmark_name, clean=True) else: commands.update(ui, repo, 'null', clean=True) # set up the correct file state and commit as a new changeset pulled_tip = repo['tip'] commands.revert(ui, repo, rev='tip', all=True) hgsubrepo_meta = [ os.path.join(repo.root, '.hgsubstate'), os.path.join(repo.root, '.hgsub') ] for fn in hgsubrepo_meta: if os.path.exists(fn): ui.debug("removing %s\n" % fn) commands.remove(ui, repo, fn, force=True) os.remove(fn) changed = commands.commit(ui, repo, message=ui.config( 'subtree', 'collapse', default_collapse_comment).format( name=name, rev=str(pulled_tip)[:12]), **commit_opts) commands.bookmark(ui, repo, bookmark_name, inactive=True) if not opts['no_strip']: # delete bookmarks on the changesets that will be stripped; not # the most efficient procedure to find them, but will do for now remove_bookmarks = [] for k in repo._bookmarks.keys(): ctx = repo[k] if pulled_tip.ancestor(ctx) != null: remove_bookmarks.append(k) for bookmark in remove_bookmarks: commands.bookmark(ui, repo, bookmark, delete=True) strip.stripcmd(ui, repo, rev=['ancestors(%s)' % str(pulled_tip)], bookmark=[]) if changed == 1: # nothing changed ui.status("no changes: nothing for subtree to do\n") commands.update(ui, repo, origin[:12]) continue else: commands.update(ui, repo, 'tip', clean=True) # move or delete destinations = _destinations(subtree['destination']) # process destinations keep_list = [] for dest in destinations: if dest[0] == 'mkdir': if not os.path.exists(dest[1]): os.makedirs(dest[1]) elif dest[0] == 'mv': commands.rename(ui, repo, *dest[1:], force=False) elif dest[0] == 'cp': commands.copy(ui, repo, *dest[1:], force=False) elif dest[0] == 'rm': commands.remove(ui, repo, *dest[1:], force=False) elif dest[0] == 'keep': keep_list.append(' '.join(dest[1:])) # remove all untouched files, unless instructed to keep them if 'keep' not in subtree or not subtree['keep']: _modified, _added, _removed, _deleted, _unknown, _ignored, clean = repo.status( clean=True) for fn in clean: for keep_pattern in keep_list: if fnmatch(fn, keep_pattern): break else: commands.remove(ui, repo, fn) commands.commit( ui, repo, message=ui.config('subtree', 'move', default_move_comment).format(name=name), **commit_opts) merge_commit = str(repo[None]) # update to original and merge with the new commands.update(ui, repo, origin[:12]) commands.merge(ui, repo, merge_commit[:12]) commands.commit( ui, repo, message=ui.config('subtree', 'merge', default_merge_comment).format(name=name), **commit_opts) origin = str(repo[None])
def deleteSelectedChunks(self): 'delete currently selected chunks' repo = self.repo chunks = self.diffbrowse.curchunks dchunks = [c for c in chunks[1:] if c.selected] if not dchunks: self.showMessage.emit(_('No deletable chunks')) return ctx = self.ctx kchunks = [c for c in chunks[1:] if not c.selected] revertall = False if not kchunks: if isinstance(ctx, patchctx): revertmsg = _('Completely remove file from patch?') else: revertmsg = _('Revert all file changes?') revertall = qtlib.QuestionMsgBox(_('No chunks remain'), revertmsg) if isinstance(ctx, patchctx): repo.thgbackup(ctx._path) fp = util.atomictempfile(ctx._path, 'wb') buf = cStringIO.StringIO() try: if ctx._ph.comments: buf.write('\n'.join(ctx._ph.comments)) buf.write('\n\n') needsnewline = False for wfile in ctx._fileorder: if wfile == self.currentFile: if revertall: continue chunks[0].write(buf) for chunk in kchunks: chunk.write(buf) else: if buf.tell() and buf.getvalue()[-1] != '\n': buf.write('\n') for chunk in ctx._files[wfile]: chunk.write(buf) fp.write(buf.getvalue()) fp.close() finally: del fp ctx.invalidate() self.fileModified.emit() else: path = repo.wjoin(self.currentFile) if not os.path.exists(path): self.showMessage.emit(_('file has been deleted, refresh')) return if self.mtime != os.path.getmtime(path): self.showMessage.emit(_('file has been modified, refresh')) return repo.thgbackup(path) if revertall: commands.revert(repo.ui, repo, path, no_backup=True) else: wlock = repo.wlock() try: # atomictemp can preserve file permission wf = repo.wopener(self.currentFile, 'wb', atomictemp=True) wf.write(self.diffbrowse.origcontents) wf.close() fp = cStringIO.StringIO() chunks[0].write(fp) for c in kchunks: c.write(fp) fp.seek(0) self.runPatcher(fp, self.currentFile, False) finally: wlock.release() self.fileModified.emit()