def patchcmds(ui, repo, pats, opts, subcommand): """subcommand that displays shelves""" if len(pats) == 0: shelved = listshelves(repo) if len(shelved) < 1: raise error.Abort(_("no shelves found")) pats = [util.split(shelved[0][1])[1]] for shelfname in pats: if not shelvedfile(repo, shelfname, patchextension).exists(): raise error.Abort(_("cannot find shelf %s") % shelfname) listcmd(ui, repo, pats, opts)
def listcmd(ui, repo, pats, opts): """subcommand that displays the list of shelves""" pats = set(pats) width = 80 if not ui.plain(): width = ui.termwidth() namelabel = "shelve.newest" ui.pager("shelve") for mtime, name in listshelves(repo): sname = util.split(name)[1] if pats and sname not in pats: continue ui.write(sname, label=namelabel) namelabel = "shelve.name" if ui.quiet: ui.write("\n") continue ui.write(" " * (16 - len(sname))) used = 16 age = "(%s)" % templatefilters.age(util.makedate(mtime), abbrev=True) ui.write(age, label="shelve.age") ui.write(" " * (12 - len(age))) used += 12 with open(name + "." + patchextension, "rb") as fp: while True: line = fp.readline() if not line: break if not line.startswith(b"#"): desc = pycompat.decodeutf8(line.rstrip()) if ui.formatted: desc = util.ellipsis(desc, width - used) ui.write(desc) break ui.write("\n") if not (opts["patch"] or opts["stat"]): continue difflines = fp.readlines() if opts["patch"]: for chunk, label in patch.difflabel(iter, difflines): ui.writebytes(chunk, label=label) if opts["stat"]: for chunk, label in patch.diffstatui(difflines, width=width): ui.write(chunk, label=label)
def applytomirrors(repo, status, sourcepath, mirrors, action): """Applies the changes that are in the sourcepath to all the mirrors.""" mirroredfiles = set() # Detect which mirror this file comes from sourcemirror = None for mirror in mirrors: if sourcepath.startswith(mirror): sourcemirror = mirror break if not sourcemirror: raise error.Abort( _("unable to detect source mirror of '%s'") % (sourcepath, )) relpath = sourcepath[len(sourcemirror):] # Apply the change to each mirror one by one allchanges = set(status.modified + status.removed + status.added) for mirror in mirrors: if mirror == sourcemirror: continue mirrorpath = mirror + relpath mirroredfiles.add(mirrorpath) if mirrorpath in allchanges: wctx = repo[None] if (sourcepath not in wctx and mirrorpath not in wctx and sourcepath in status.removed and mirrorpath in status.removed): if repo.ui.verbose: repo.ui.status( _("not mirroring remove of '%s' to '%s';" " it is already removed\n") % (sourcepath, mirrorpath)) continue if wctx[sourcepath].data() == wctx[mirrorpath].data(): if repo.ui.verbose: repo.ui.status( _("not mirroring '%s' to '%s'; it already " "matches\n") % (sourcepath, mirrorpath)) continue raise error.Abort( _("path '%s' needs to be mirrored to '%s', but " "the target already has pending changes") % (sourcepath, mirrorpath)) fullsource = repo.wjoin(sourcepath) fulltarget = repo.wjoin(mirrorpath) dirstate = repo.dirstate if action == "m" or action == "a": mirrorpathdir, unused = util.split(mirrorpath) util.makedirs(repo.wjoin(mirrorpathdir)) util.copyfile(fullsource, fulltarget) if dirstate[mirrorpath] in "?r": dirstate.add(mirrorpath) if action == "a": # For adds, detect copy data as well copysource = dirstate.copied(sourcepath) if copysource and copysource.startswith(sourcemirror): mirrorcopysource = mirror + copysource[len(sourcemirror):] dirstate.copy(mirrorcopysource, mirrorpath) repo.ui.status( _("mirrored copy '%s -> %s' to '%s -> %s'\n") % (copysource, sourcepath, mirrorcopysource, mirrorpath)) else: repo.ui.status( _("mirrored adding '%s' to '%s'\n") % (sourcepath, mirrorpath)) else: repo.ui.status( _("mirrored changes in '%s' to '%s'\n") % (sourcepath, mirrorpath)) elif action == "r": try: util.unlink(fulltarget) except OSError as e: if e.errno == errno.ENOENT: repo.ui.status( _("not mirroring remove of '%s' to '%s'; it " "is already removed\n") % (sourcepath, mirrorpath)) else: raise else: dirstate.remove(mirrorpath) repo.ui.status( _("mirrored remove of '%s' to '%s'\n") % (sourcepath, mirrorpath)) return mirroredfiles
def listshelvesfiles(repo): """return all shelves in the repo as list of filenames from the repo root""" return [util.split(filetuple[1])[1] for filetuple in listshelves(repo)]
def _dounshelve(ui, repo, *shelved, **opts): abortf = opts.get("abort") continuef = opts.get("continue") if not abortf and not continuef: cmdutil.checkunfinished(repo) shelved = list(shelved) if opts.get("name"): shelved.append(opts["name"]) if abortf or continuef: if abortf and continuef: raise error.Abort(_("cannot use both abort and continue")) if shelved: raise error.Abort( _("cannot combine abort/continue with " "naming a shelved change")) if abortf and opts.get("tool", False): ui.warn(_("tool option will be ignored\n")) try: state = shelvedstate.load(repo) if opts.get("keep") is None: opts["keep"] = state.keep except IOError as err: if err.errno != errno.ENOENT: raise cmdutil.wrongtooltocontinue(repo, _("unshelve")) except error.CorruptedState as err: ui.debug(str(err) + "\n") if continuef: msg = _("corrupted shelved state file") hint = _("please run hg unshelve --abort to abort unshelve " "operation") raise error.Abort(msg, hint=hint) elif abortf: msg = _("could not read shelved state file, your working copy " "may be in an unexpected state\nplease update to some " "commit\n") ui.warn(msg) shelvedstate.clear(repo) return if abortf: return unshelveabort(ui, repo, state, opts) elif continuef: return unshelvecontinue(ui, repo, state, opts) elif len(shelved) > 1: raise error.Abort(_("can only unshelve one change at a time")) elif not shelved: shelved = listshelves(repo) if not shelved: raise error.Abort(_("no shelved changes to apply!")) basename = util.split(shelved[0][1])[1] ui.status(_("unshelving change '%s'\n") % basename) else: basename = shelved[0] if not shelvedfile(repo, basename, patchextension).exists(): raise error.Abort(_("shelved change '%s' not found") % basename) lock = tr = None obsshelve = True obsshelvedfile = shelvedfile(repo, basename, "oshelve") if not obsshelvedfile.exists(): # although we can unshelve a obs-based shelve technically, # this particular shelve was created using a traditional way obsshelve = False ui.note( _("falling back to traditional unshelve since " "shelve was traditional")) try: lock = repo.lock() tr = repo.transaction("unshelve", report=lambda x: None) oldtiprev = len(repo) pctx = repo["."] tmpwctx = pctx # The goal is to have a commit structure like so: # ...-> pctx -> tmpwctx -> shelvectx # where tmpwctx is an optional commit with the user's pending changes # and shelvectx is the unshelved changes. Then we merge it all down # to the original pctx. activebookmark = _backupactivebookmark(repo) tmpwctx, addedbefore = _commitworkingcopychanges( ui, repo, opts, tmpwctx) repo, shelvectx = _unshelverestorecommit(ui, repo, basename, obsshelve) _checkunshelveuntrackedproblems(ui, repo, shelvectx) branchtorestore = "" if shelvectx.branch() != shelvectx.p1().branch(): branchtorestore = shelvectx.branch() rebaseconfigoverrides = { ("ui", "forcemerge"): opts.get("tool", ""), ("experimental", "rebaseskipobsolete"): "off", } with ui.configoverride(rebaseconfigoverrides, "unshelve"): shelvectx = _rebaserestoredcommit( ui, repo, opts, tr, oldtiprev, basename, pctx, tmpwctx, shelvectx, branchtorestore, activebookmark, obsshelve, ) mergefiles(ui, repo, pctx, shelvectx) restorebranch(ui, repo, branchtorestore) _forgetunknownfiles(repo, shelvectx, addedbefore) if obsshelve: _obsoleteredundantnodes(repo, tr, pctx, shelvectx, tmpwctx) shelvedstate.clear(repo) _finishunshelve(repo, oldtiprev, tr, activebookmark, obsshelve) unshelvecleanup(ui, repo, basename, opts) finally: if tr: tr.release() lockmod.release(lock)