def commitextra(ui, repo, *pats, **opts): '''make a commit with extra fields''' fields = opts.get('field') extras = {} for field in fields: k, v = field.split(b'=', 1) extras[k] = v message = cmdutil.logmessage(ui, pycompat.byteskwargs(opts)) repo.commit(message, opts.get('user'), opts.get('date'), match=scmutil.match(repo[None], pats, pycompat.byteskwargs(opts)), extra=extras) return 0
def _getpatchmsgs(repo, sender, revs, patchnames=None, **opts): """return a list of emails from a list of patches This involves introduction message creation if necessary. This function returns a list of "email" tuples (subject, content, None). """ bytesopts = pycompat.byteskwargs(opts) ui = repo.ui _charsets = mail._charsets(ui) patches = list(_getpatches(repo, revs, **opts)) msgs = [] ui.write(_('this patch series consists of %d patches.\n\n') % len(patches)) # build the intro message, or skip it if the user declines if introwanted(ui, bytesopts, len(patches)): msg = _makeintro(repo, sender, revs, patches, **opts) if msg: msgs.append(msg) # are we going to send more than one message? numbered = len(msgs) + len(patches) > 1 # now generate the actual patch messages name = None assert len(revs) == len(patches) for i, (r, p) in enumerate(zip(revs, patches)): if patchnames: name = patchnames[i] msg = makepatch(ui, repo, r, p, bytesopts, _charsets, i + 1, len(patches), numbered, name) msgs.append(msg) return msgs
def log(orig, ui, repo, *pats, **opts): if not isenabled(repo): return orig(ui, repo, *pats, **opts) follow = opts.get('follow') revs = opts.get('rev') if pats: # Force slowpath for non-follow patterns and follows that start from # non-working-copy-parent revs. if not follow or revs: # This forces the slowpath opts['removed'] = True # If this is a non-follow log without any revs specified, recommend that # the user add -f to speed it up. if not follow and not revs: match = scmutil.match(repo[b'.'], pats, pycompat.byteskwargs(opts)) isfile = not match.anypats() if isfile: for file in match.files(): if not os.path.isfile(repo.wjoin(file)): isfile = False break if isfile: ui.warn( _(b"warning: file log can be slow on large repos - " + b"use -f to speed it up\n")) return orig(ui, repo, *pats, **opts)
def extdiff(ui, repo, *pats, **opts): '''use external program to diff repository (or selected files) Show differences between revisions for the specified files, using an external program. The default program used is diff, with default options "-Npru". To select a different program, use the -p/--program option. The program will be passed the names of two directories to compare. To pass additional options to the program, use -o/--option. These will be passed before the names of the directories to compare. When two revision arguments are given, then changes are shown between those revisions. If only one revision is specified then that revision is compared to the working directory, and, when no revisions are specified, the working directory files are compared to its parent.''' opts = pycompat.byteskwargs(opts) program = opts.get('program') option = opts.get('option') if not program: program = 'diff' option = option or ['-Npru'] cmdline = ' '.join(map(util.shellquote, [program] + option)) return dodiff(ui, repo, cmdline, pats, opts)
def purge(ui, repo, *dirs, **opts): '''removes files not tracked by Mercurial Delete files not known to Mercurial. This is useful to test local and uncommitted changes in an otherwise-clean source tree. This means that purge will delete the following by default: - Unknown files: files marked with "?" by :hg:`status` - Empty directories: in fact Mercurial ignores directories unless they contain files under source control management But it will leave untouched: - Modified and unmodified tracked files - Ignored files (unless --all is specified) - New files added to the repository (with :hg:`add`) The --files and --dirs options can be used to direct purge to delete only files, only directories, or both. If neither option is given, both will be deleted. If directories are given on the command line, only files in these directories are considered. Be careful with purge, as you could irreversibly delete some files you forgot to add to the repository. If you only want to print the list of files that this program would delete, use the --print option. ''' opts = pycompat.byteskwargs(opts) act = not opts.get(b'print') eol = b'\n' if opts.get(b'print0'): eol = b'\0' act = False # --print0 implies --print removefiles = opts.get(b'files') removedirs = opts.get(b'dirs') if not removefiles and not removedirs: removefiles = True removedirs = True match = scmutil.match(repo[None], dirs, opts) paths = mergemod.purge( repo, match, ignored=opts.get(b'all', False), removeemptydirs=removedirs, removefiles=removefiles, abortonerror=opts.get(b'abort_on_err'), noop=not act, ) for path in paths: if not act: ui.write(b'%s%s' % (path, eol))
def children(ui, repo, file_=None, **opts): """show the children of the given or working directory revision Print the children of the working directory's revisions. If a revision is given via -r/--rev, the children of that revision will be printed. If a file argument is given, revision in which the file was last changed (after the working directory revision or the argument to --rev if given) is printed. Please use :hg:`log` instead:: hg children => hg log -r "children(.)" hg children -r REV => hg log -r "children(REV)" See :hg:`help log` and :hg:`help revsets.children`. """ opts = pycompat.byteskwargs(opts) rev = opts.get('rev') if file_: fctx = repo.filectx(file_, changeid=rev) childctxs = [fcctx.changectx() for fcctx in fctx.children()] else: ctx = repo[rev] childctxs = ctx.children() displayer = cmdutil.show_changeset(ui, repo, opts) for cctx in childctxs: displayer.show(cctx) displayer.close()
def extdiff2(ui, repo, *pats, **opts): """use external program to diff repository (or selected files) Show differences between revisions for the specified files, using an external program. The default program used is diff, with default options "-Npru". To select a different program, use the -p/--program option. The program will be passed the names of two directories to compare. To pass additional options to the program, use -o/--option. These will be passed before the names of the directories to compare. When two revision arguments are given, then changes are shown between those revisions. If only one revision is specified then that revision is compared to the working directory, and, when no revisions are specified, the working directory files are compared to its parent. """ opts = pycompat.byteskwargs(opts) program = opts.get('program') option = opts.get('option') if not program: program = 'diff' option = option or ['-Npru'] cmdline = ' '.join(map(procutil.shellquote, [program] + option)) return dodiff(ui, repo, cmdline, pats, opts)
def phabupdate(ui, repo, spec, **opts): """update Differential Revision in batch DREVSPEC selects revisions. See :hg:`help phabread` for its usage. """ opts = pycompat.byteskwargs(opts) flags = [ n for n in b'accept reject abandon reclaim'.split() if opts.get(n) ] if len(flags) > 1: raise error.Abort(_(b'%s cannot be used together') % b', '.join(flags)) actions = [] for f in flags: actions.append({b'type': f, b'value': b'true'}) drevs = querydrev(repo, spec) for i, drev in enumerate(drevs): if i + 1 == len(drevs) and opts.get(b'comment'): actions.append({b'type': b'comment', b'value': opts[b'comment']}) if actions: params = { b'objectIdentifier': drev[b'phid'], b'transactions': actions } callconduit(ui, b'differential.revision.edit', params)
def absorbcmd(ui, repo, *pats, **opts): """incorporate corrections into the stack of draft changesets absorb analyzes each change in your working directory and attempts to amend the changed lines into the changesets in your stack that first introduced those lines. If absorb cannot find an unambiguous changeset to amend for a change, that change will be left in the working directory, untouched. They can be observed by :hg:`status` or :hg:`diff` afterwards. In other words, absorb does not write to the working directory. Changesets outside the revset `::. and not public() and not merge()` will not be changed. Changesets that become empty after applying the changes will be deleted. By default, absorb will show what it plans to do and prompt for confirmation. If you are confident that the changes will be absorbed to the correct place, run :hg:`absorb -a` to apply the changes immediately. Returns 0 on success, 1 if all chunks were ignored and nothing amended. """ opts = pycompat.byteskwargs(opts) with repo.wlock(), repo.lock(): if not opts[b'dry_run']: cmdutil.checkunfinished(repo) state = absorb(ui, repo, pats=pats, opts=opts) if sum(s[0] for s in state.chunkstats.values()) == 0: return 1
def __call__(self, ui, repo, *pats, **opts): opts = pycompat.byteskwargs(opts) options = b' '.join(map(procutil.shellquote, opts[b'option'])) if options: options = b' ' + options return dodiff( ui, repo, self._cmdline + options, pats, opts, guitool=self._isgui )
def fix(ui, repo, *pats, **opts): """rewrite file content in changesets or working directory Runs any configured tools to fix the content of files. Only affects files with changes, unless file arguments are provided. Only affects changed lines of files, unless the --whole flag is used. Some tools may always affect the whole file regardless of --whole. If revisions are specified with --rev, those revisions will be checked, and they may be replaced with new revisions that have fixed file content. It is desirable to specify all descendants of each specified revision, so that the fixes propagate to the descendants. If all descendants are fixed at the same time, no merging, rebasing, or evolution will be required. If --working-dir is used, files with uncommitted changes in the working copy will be fixed. If the checked-out revision is also fixed, the working directory will update to the replacement revision. When determining what lines of each file to fix at each revision, the whole set of revisions being fixed is considered, so that fixes to earlier revisions are not forgotten in later ones. The --base flag can be used to override this default behavior, though it is not usually desirable to do so. """ opts = pycompat.byteskwargs(opts) if opts['all']: if opts['rev']: raise error.Abort(_('cannot specify both "--rev" and "--all"')) opts['rev'] = ['not public() and not obsolete()'] opts['working_dir'] = True with repo.wlock(), repo.lock(): revstofix = getrevstofix(ui, repo, opts) basectxs = getbasectxs(repo, opts, revstofix) workqueue, numitems = getworkqueue(ui, repo, pats, opts, revstofix, basectxs) filedata = collections.defaultdict(dict) replacements = {} fixers = getfixers(ui) # Some day this loop can become a worker pool, but for now it's easier # to fix everything serially in topological order. for rev, path in sorted(workqueue): ctx = repo[rev] olddata = ctx[path].data() newdata = fixfile(ui, opts, fixers, ctx, path, basectxs[rev]) if newdata != olddata: filedata[rev][path] = newdata numitems[rev] -= 1 if not numitems[rev]: if rev == wdirrev: writeworkingdir(repo, ctx, filedata[rev], replacements) else: replacerev(ui, repo, ctx, filedata[rev], replacements) del filedata[rev] replacements = { prec: [succ] for prec, succ in replacements.iteritems() } scmutil.cleanupnodes(repo, replacements, 'fix')
def countrate(ui, repo, amap, *pats, **opts): """Calculate stats""" opts = pycompat.byteskwargs(opts) if opts.get(b'dateformat'): def getkey(ctx): t, tz = ctx.date() date = datetime.datetime(*time.gmtime(float(t) - tz)[:6]) return encoding.strtolocal( date.strftime(encoding.strfromlocal(opts[b'dateformat'])) ) else: tmpl = opts.get(b'oldtemplate') or opts.get(b'template') tmpl = logcmdutil.maketemplater(ui, repo, tmpl) def getkey(ctx): ui.pushbuffer() tmpl.show(ctx) return ui.popbuffer() progress = ui.makeprogress( _(b'analyzing'), unit=_(b'revisions'), total=len(repo) ) rate = {} df = False if opts.get(b'date'): df = dateutil.matchdate(opts[b'date']) m = scmutil.match(repo[None], pats, opts) def prep(ctx, fns): rev = ctx.rev() if df and not df(ctx.date()[0]): # doesn't match date format return key = getkey(ctx).strip() key = amap.get(key, key) # alias remap if opts.get(b'changesets'): rate[key] = (rate.get(key, (0,))[0] + 1, 0) else: parents = ctx.parents() if len(parents) > 1: ui.note(_(b'revision %d is a merge, ignoring...\n') % (rev,)) return ctx1 = parents[0] lines = changedlines(ui, repo, ctx1, ctx, fns) rate[key] = [r + l for r, l in zip(rate.get(key, (0, 0)), lines)] progress.increment() for ctx in cmdutil.walkchangerevs(repo, m, opts, prep): continue progress.complete() return rate
def files(ui, repo, *pats, **opts): '''show files configured for keyword expansion List which files in the working directory are matched by the [keyword] configuration patterns. Useful to prevent inadvertent keyword expansion and to speed up execution by including only files that are actual candidates for expansion. See :hg:`help keyword` on how to construct patterns both for inclusion and exclusion of files. With -A/--all and -v/--verbose the codes used to show the status of files are:: K = keyword expansion candidate k = keyword expansion candidate (not tracked) I = ignored i = ignored (not tracked) ''' kwt = getattr(repo, '_keywordkwt', None) wctx = repo[None] status = _status(ui, repo, wctx, kwt, *pats, **opts) if pats: cwd = repo.getcwd() else: cwd = '' files = [] opts = pycompat.byteskwargs(opts) if not opts.get('unknown') or opts.get('all'): files = sorted(status.modified + status.added + status.clean) kwfiles = kwt.iskwfile(files, wctx) kwdeleted = kwt.iskwfile(status.deleted, wctx) kwunknown = kwt.iskwfile(status.unknown, wctx) if not opts.get('ignore') or opts.get('all'): showfiles = kwfiles, kwdeleted, kwunknown else: showfiles = [], [], [] if opts.get('all') or opts.get('ignore'): showfiles += ([f for f in files if f not in kwfiles], [f for f in status.unknown if f not in kwunknown]) kwlabels = 'enabled deleted enabledunknown ignored ignoredunknown'.split() kwstates = zip(kwlabels, 'K!kIi', showfiles) fm = ui.formatter('kwfiles', opts) fmt = '%.0s%s\n' if opts.get('all') or ui.verbose: fmt = '%s %s\n' for kwstate, char, filenames in kwstates: label = 'kwfiles.' + kwstate for f in filenames: fm.startitem() fm.write('kwstatus path', fmt, char, repo.pathto(f, cwd), label=label) fm.end()
def changesetentry(orig, web, ctx): """Wraps webutil.changesetentry to provide extra metadata.""" d = orig(web, ctx) d = pycompat.byteskwargs(d) addmetadata(web.repo, ctx, d) return pycompat.strkwargs(d)
def _call(self, cmd, **args): args = pycompat.byteskwargs(args) res = wireprotov1server.dispatch(self.serverrepo, proto(args), cmd) if isinstance(res, wireprototypes.bytesresponse): return res.data elif isinstance(res, bytes): return res else: raise error.Abort('dummy client does not support response type')
def _pull(orig, ui, repo, source="default", **opts): opts = pycompat.byteskwargs(opts) # Copy paste from `pull` command source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch')) scratchbookmarks = {} unfi = repo.unfiltered() unknownnodes = [] for rev in opts.get('rev', []): if rev not in unfi: unknownnodes.append(rev) if opts.get('bookmark'): bookmarks = [] revs = opts.get('rev') or [] for bookmark in opts.get('bookmark'): if _scratchbranchmatcher(bookmark): # rev is not known yet # it will be fetched with listkeyspatterns next scratchbookmarks[bookmark] = 'REVTOFETCH' else: bookmarks.append(bookmark) if scratchbookmarks: other = hg.peer(repo, opts, source) fetchedbookmarks = other.listkeyspatterns( 'bookmarks', patterns=scratchbookmarks) for bookmark in scratchbookmarks: if bookmark not in fetchedbookmarks: raise error.Abort('remote bookmark %s not found!' % bookmark) scratchbookmarks[bookmark] = fetchedbookmarks[bookmark] revs.append(fetchedbookmarks[bookmark]) opts['bookmark'] = bookmarks opts['rev'] = revs if scratchbookmarks or unknownnodes: # Set anyincoming to True extensions.wrapfunction(discovery, 'findcommonincoming', _findcommonincoming) try: # Remote scratch bookmarks will be deleted because remotenames doesn't # know about them. Let's save it before pull and restore after remotescratchbookmarks = _readscratchremotebookmarks(ui, repo, source) result = orig(ui, repo, source, **pycompat.strkwargs(opts)) # TODO(stash): race condition is possible # if scratch bookmarks was updated right after orig. # But that's unlikely and shouldn't be harmful. if common.isremotebooksenabled(ui): remotescratchbookmarks.update(scratchbookmarks) _saveremotebookmarks(repo, remotescratchbookmarks, source) else: _savelocalbookmarks(repo, scratchbookmarks) return result finally: if scratchbookmarks: extensions.unwrapfunction(discovery, 'findcommonincoming')
def _status(ui, repo, wctx, kwt, *pats, **opts): '''Bails out if [keyword] configuration is not active. Returns status of working directory.''' if kwt: opts = pycompat.byteskwargs(opts) return repo.status(match=scmutil.match(wctx, pats, opts), clean=True, unknown=opts.get('unknown') or opts.get('all')) if ui.configitems('keyword'): raise error.Abort(_('[keyword] patterns cannot match')) raise error.Abort(_('no [keyword] patterns configured'))
def view(ui, repo, *etc, **opts): "start interactive history viewer" opts = pycompat.byteskwargs(opts) os.chdir(repo.root) optstr = ' '.join(['--%s %s' % (k, v) for k, v in opts.iteritems() if v]) if repo.filtername is None: optstr += '--hidden' cmd = ui.config("hgk", "path") + " %s %s" % (optstr, " ".join(etc)) ui.debug("running %s\n" % cmd) ui.system(cmd, blockedtag='hgk_view')
def _push(orig, ui, repo, *dests, **opts): opts = pycompat.byteskwargs(opts) bookmark = opts.get(b'bookmark') # we only support pushing one infinitepush bookmark at once if len(bookmark) == 1: bookmark = bookmark[0] else: bookmark = b'' oldphasemove = None overrides = {(experimental, configbookmark): bookmark} with ui.configoverride(overrides, b'infinitepush'): scratchpush = opts.get(b'bundle_store') if _scratchbranchmatcher(bookmark): scratchpush = True # bundle2 can be sent back after push (for example, bundle2 # containing `pushkey` part to update bookmarks) ui.setconfig(experimental, b'bundle2.pushback', True) if scratchpush: # this is an infinitepush, we don't want the bookmark to be applied # rather that should be stored in the bundlestore opts[b'bookmark'] = [] ui.setconfig(experimental, configscratchpush, True) oldphasemove = extensions.wrapfunction( exchange, b'_localphasemove', _phasemove ) paths = list(urlutil.get_push_paths(repo, ui, dests)) if len(paths) > 1: msg = _(b'cannot push to multiple path with infinitepush') raise error.Abort(msg) path = paths[0] destpath = path.pushloc or path.loc # Remote scratch bookmarks will be deleted because remotenames doesn't # know about them. Let's save it before push and restore after remotescratchbookmarks = _readscratchremotebookmarks(ui, repo, destpath) result = orig(ui, repo, *dests, **pycompat.strkwargs(opts)) if common.isremotebooksenabled(ui): if bookmark and scratchpush: other = hg.peer(repo, opts, destpath) try: fetchedbookmarks = other.listkeyspatterns( b'bookmarks', patterns=[bookmark] ) remotescratchbookmarks.update(fetchedbookmarks) finally: other.close() _saveremotebookmarks(repo, remotescratchbookmarks, destpath) if oldphasemove: exchange._localphasemove = oldphasemove return result
def close_branch(ui, repo, *revs, **opts): """close the given head revisions This is equivalent to checking out each revision in a clean tree and running ``hg commit --close-branch``, except that it doesn't change the working directory. The commit message must be specified with -l or -m. """ def docommit(rev): cctx = context.memctx( repo, parents=[rev, None], text=message, files=[], filectxfn=None, user=opts.get(b'user'), date=opts.get(b'date'), extra=extra, ) tr = repo.transaction(b'commit') ret = repo.commitctx(cctx, True) bookmarks.update(repo, [rev, None], ret) cctx.markcommitted(ret) tr.close() opts = pycompat.byteskwargs(opts) revs += tuple(opts.get(b'rev', [])) revs = scmutil.revrange(repo, revs) if not revs: raise error.Abort(_(b'no revisions specified')) heads = [] for branch in repo.branchmap(): heads.extend(repo.branchheads(branch)) heads = {repo[h].rev() for h in heads} for rev in revs: if rev not in heads: raise error.Abort(_(b'revision is not an open head: %d') % rev) message = cmdutil.logmessage(ui, opts) if not message: raise error.Abort(_(b"no commit message specified with -l or -m")) extra = {b'close': b'1'} with repo.wlock(), repo.lock(): for rev in revs: r = repo[rev] branch = r.branch() extra[b'branch'] = branch docommit(r) return 0
def convert(ui, src, dest=None, revmapfile=None, **opts): opts = pycompat.byteskwargs(opts) global orig_encoding orig_encoding = encoding.encoding encoding.encoding = b'UTF-8' # support --authors as an alias for --authormap if not opts.get(b'authormap'): opts[b'authormap'] = opts.get(b'authors') if not dest: dest = hg.defaultdest(src) + b"-hg" ui.status(_(b"assuming destination %s\n") % dest) destc = convertsink(ui, dest, opts.get(b'dest_type')) destc = scmutil.wrapconvertsink(destc) try: srcc, defaultsort = convertsource( ui, src, opts.get(b'source_type'), opts.get(b'rev') ) except Exception: for path in destc.created: shutil.rmtree(path, True) raise sortmodes = (b'branchsort', b'datesort', b'sourcesort', b'closesort') sortmode = [m for m in sortmodes if opts.get(m)] if len(sortmode) > 1: raise error.Abort(_(b'more than one sort mode specified')) if sortmode: sortmode = sortmode[0] else: sortmode = defaultsort if sortmode == b'sourcesort' and not srcc.hasnativeorder(): raise error.Abort( _(b'--sourcesort is not supported by this data source') ) if sortmode == b'closesort' and not srcc.hasnativeclose(): raise error.Abort( _(b'--closesort is not supported by this data source') ) fmap = opts.get(b'filemap') if fmap: srcc = filemap.filemap_source(ui, srcc, fmap) destc.setfilemapmode(True) if not revmapfile: revmapfile = destc.revmapfile() c = converter(ui, srcc, destc, revmapfile, opts) c.convert(sortmode)
def debugbuildannotatecache(ui, repo, *pats, **opts): """incrementally build fastannotate cache up to REV for specified files If REV is not specified, use the config 'fastannotate.mainbranch'. If fastannotate.client is True, download the annotate cache from the server. Otherwise, build the annotate cache locally. The annotate cache will be built using the default diff and follow options and lives in '.hg/fastannotate/default'. """ opts = pycompat.byteskwargs(opts) rev = opts.get(b'REV') or ui.config(b'fastannotate', b'mainbranch') if not rev: raise error.Abort( _(b'you need to provide a revision'), hint=_(b'set fastannotate.mainbranch or use --rev'), ) if ui.configbool(b'fastannotate', b'unfilteredrepo'): repo = repo.unfiltered() ctx = scmutil.revsingle(repo, rev) m = scmutil.match(ctx, pats, opts) paths = list(ctx.walk(m)) if util.safehasattr(repo, 'prefetchfastannotate'): # client if opts.get(b'REV'): raise error.Abort(_(b'--rev cannot be used for client')) repo.prefetchfastannotate(paths) else: # server, or full repo progress = ui.makeprogress(_(b'building'), total=len(paths)) for i, path in enumerate(paths): progress.update(i) with facontext.annotatecontext(repo, path) as actx: try: if actx.isuptodate(rev): continue actx.annotate(rev, rev) except (faerror.CannotReuseError, faerror.CorruptedFileError): # the cache is broken (could happen with renaming so the # file history gets invalidated). rebuild and try again. ui.debug(b'fastannotate: %s: rebuilding broken cache\n' % path) actx.rebuild() try: actx.annotate(rev, rev) except Exception as ex: # possibly a bug, but should not stop us from building # cache for other files. ui.warn( _(b'fastannotate: %s: failed to ' b'build cache: %r\n') % (path, ex)) progress.complete()
def _push(orig, ui, repo, dest=None, *args, **opts): opts = pycompat.byteskwargs(opts) bookmark = opts.get(b'bookmark') # we only support pushing one infinitepush bookmark at once if len(bookmark) == 1: bookmark = bookmark[0] else: bookmark = b'' oldphasemove = None overrides = {(experimental, configbookmark): bookmark} with ui.configoverride(overrides, b'infinitepush'): scratchpush = opts.get(b'bundle_store') if _scratchbranchmatcher(bookmark): scratchpush = True # bundle2 can be sent back after push (for example, bundle2 # containing `pushkey` part to update bookmarks) ui.setconfig(experimental, b'bundle2.pushback', True) if scratchpush: # this is an infinitepush, we don't want the bookmark to be applied # rather that should be stored in the bundlestore opts[b'bookmark'] = [] ui.setconfig(experimental, configscratchpush, True) oldphasemove = extensions.wrapfunction(exchange, b'_localphasemove', _phasemove) # Copy-paste from `push` command path = ui.paths.getpath(dest, default=(b'default-push', b'default')) if not path: raise error.Abort( _(b'default repository not configured!'), hint=_(b"see 'hg help config.paths'"), ) destpath = path.pushloc or path.loc # Remote scratch bookmarks will be deleted because remotenames doesn't # know about them. Let's save it before push and restore after remotescratchbookmarks = _readscratchremotebookmarks( ui, repo, destpath) result = orig(ui, repo, dest, *args, **pycompat.strkwargs(opts)) if common.isremotebooksenabled(ui): if bookmark and scratchpush: other = hg.peer(repo, opts, destpath) fetchedbookmarks = other.listkeyspatterns(b'bookmarks', patterns=[bookmark]) remotescratchbookmarks.update(fetchedbookmarks) _saveremotebookmarks(repo, remotescratchbookmarks, destpath) if oldphasemove: exchange._localphasemove = oldphasemove return result
def fastexport(ui, repo, *revs, **opts): """export repository as git fast-import stream This command lets you dump a repository as a human-readable text stream. It can be piped into corresponding import routines like "git fast-import". Incremental dumps can be created by using marks files. """ opts = pycompat.byteskwargs(opts) revs += tuple(opts.get(b"rev", [])) if not revs: revs = scmutil.revrange(repo, [b":"]) else: revs = scmutil.revrange(repo, revs) if not revs: raise error.Abort(_(b"no revisions matched")) authorfile = opts.get(b"authormap") if authorfile: authormap = convcmd.readauthormap(ui, authorfile) else: authormap = {} import_marks = opts.get(b"import_marks") marks = {} if import_marks: with open(import_marks, "rb") as import_marks_file: for line in import_marks_file: line = line.strip() if not isrev.match(line) or line in marks: raise error.Abort(_(b"Corrupted marks file")) marks[line] = len(marks) + 1 revs.sort() with ui.makeprogress(_(b"exporting"), unit=_(b"revisions"), total=len(revs)) as progress: for rev in revs: export_commit(ui, repo, rev, marks, authormap) progress.increment() export_marks = opts.get(b"export_marks") if export_marks: with open(export_marks, "wb") as export_marks_file: output_marks = [None] * len(marks) for k, v in marks.items(): output_marks[v - 1] = k for k in output_marks: export_marks_file.write(k + b"\n")
def amend(ui, repo, *pats, **opts): """amend the working copy parent with all or specified outstanding changes Similar to :hg:`commit --amend`, but reuse the commit message without invoking editor, unless ``--edit`` was set. See :hg:`help commit` for more details. """ opts = pycompat.byteskwargs(opts) cmdutil.checknotesize(ui, opts) with repo.wlock(), repo.lock(): if not opts.get(b'logfile'): opts[b'message'] = opts.get(b'message') or repo[b'.'].description() opts[b'amend'] = True return commands._docommit(ui, repo, *pats, **pycompat.strkwargs(opts))
def amend(ui, repo, *pats, **opts): """amend the working copy parent with all or specified outstanding changes Similar to :hg:`commit --amend`, but reuse the commit message without invoking editor, unless ``--edit`` was set. See :hg:`help commit` for more details. """ opts = pycompat.byteskwargs(opts) if len(opts['note']) > 255: raise error.Abort(_("cannot store a note of more than 255 bytes")) with repo.wlock(), repo.lock(): if not opts.get('logfile'): opts['message'] = opts.get('message') or repo['.'].description() opts['amend'] = True return commands._docommit(ui, repo, *pats, **pycompat.strkwargs(opts))
def _annotatewrapper(orig, ui, repo, *pats, **opts): """used by wrapdefault""" # we need this hack until the obsstore has 0.0 seconds perf impact if ui.configbool(b'fastannotate', b'unfilteredrepo'): repo = repo.unfiltered() # treat the file as text (skip the isbinary check) if ui.configbool(b'fastannotate', b'forcetext'): opts['text'] = True # check if we need to do prefetch (client-side) rev = opts.get('rev') if util.safehasattr(repo, 'prefetchfastannotate') and rev is not None: paths = list(_matchpaths(repo, rev, pats, pycompat.byteskwargs(opts))) repo.prefetchfastannotate(paths) return orig(ui, repo, *pats, **opts)
def clonenarrowcmd(orig, ui, repo, *args, **opts): """Wraps clone command, so 'hg clone' first wraps localrepo.clone().""" opts = pycompat.byteskwargs(opts) wrappedextraprepare = util.nullcontextmanager() opts_narrow = opts['narrow'] if opts_narrow: def pullbundle2extraprepare_widen(orig, pullop, kwargs): # Create narrow spec patterns from clone flags includepats = narrowspec.parsepatterns(opts['include']) excludepats = narrowspec.parsepatterns(opts['exclude']) # If necessary, ask the server to expand the narrowspec. includepats, excludepats = expandpull(pullop, includepats, excludepats) if not includepats and excludepats: # If nothing was included, we assume the user meant to include # everything, except what they asked to exclude. includepats = {'path:.'} pullop.repo.setnarrowpats(includepats, excludepats) # This will populate 'includepats' etc with the values from the # narrowspec we just saved. orig(pullop, kwargs) if opts.get('depth'): kwargs['depth'] = opts['depth'] wrappedextraprepare = extensions.wrappedfunction( exchange, '_pullbundle2extraprepare', pullbundle2extraprepare_widen) def pullnarrow(orig, repo, *args, **kwargs): if opts_narrow: repo.requirements.add(changegroup.NARROW_REQUIREMENT) repo._writerequirements() return orig(repo, *args, **kwargs) wrappedpull = extensions.wrappedfunction(exchange, 'pull', pullnarrow) with wrappedextraprepare, wrappedpull: return orig(ui, repo, *args, **pycompat.strkwargs(opts))
def uncommit(ui, repo, *pats, **opts): """uncommit part or all of a local changeset This command undoes the effect of a local commit, returning the affected files to their uncommitted state. This means that files modified or deleted in the changeset will be left unchanged, and so will remain modified in the working directory. If no files are specified, the commit will be pruned, unless --keep is given. """ opts = pycompat.byteskwargs(opts) with repo.wlock(), repo.lock(): if not pats and not repo.ui.configbool('experimental', 'uncommitondirtywdir'): cmdutil.bailifchanged(repo) old = repo['.'] rewriteutil.precheck(repo, [old.rev()], 'uncommit') if len(old.parents()) > 1: raise error.Abort(_("cannot uncommit merge changeset")) with repo.transaction('uncommit'): match = scmutil.match(old, pats, opts) keepcommit = opts.get('keep') or pats newid = _commitfiltered(repo, old, match, keepcommit) if newid is None: ui.status(_("nothing to uncommit\n")) return 1 mapping = {} if newid != old.p1().node(): # Move local changes on filtered changeset mapping[old.node()] = (newid, ) else: # Fully removed the old commit mapping[old.node()] = () scmutil.cleanupnodes(repo, mapping, 'uncommit') with repo.dirstate.parentchange(): repo.dirstate.setparents(newid, node.nullid) s = repo.status(old.p1(), old, match=match) _fixdirstate(repo, old, repo[newid], s)
def clonenarrowcmd(orig, ui, repo, *args, **opts): """Wraps clone command, so 'hg clone' first wraps localrepo.clone().""" opts = pycompat.byteskwargs(opts) wrappedextraprepare = util.nullcontextmanager() narrowspecfile = opts[b'narrowspec'] if narrowspecfile: filepath = os.path.join(encoding.getcwd(), narrowspecfile) ui.status(_(b"reading narrowspec from '%s'\n") % filepath) try: fdata = util.readfile(filepath) except IOError as inst: raise error.Abort( _(b"cannot read narrowspecs from '%s': %s") % (filepath, encoding.strtolocal(inst.strerror))) includes, excludes, profiles = sparse.parseconfig(ui, fdata, b'narrow') if profiles: raise error.Abort( _(b"cannot specify other files using '%include' in" b" narrowspec")) narrowspec.validatepatterns(includes) narrowspec.validatepatterns(excludes) # narrowspec is passed so we should assume that user wants narrow clone opts[b'narrow'] = True opts[b'include'].extend(includes) opts[b'exclude'].extend(excludes) if opts[b'narrow']: def pullbundle2extraprepare_widen(orig, pullop, kwargs): orig(pullop, kwargs) if opts.get(b'depth'): kwargs[b'depth'] = opts[b'depth'] wrappedextraprepare = extensions.wrappedfunction( exchange, b'_pullbundle2extraprepare', pullbundle2extraprepare_widen) with wrappedextraprepare: return orig(ui, repo, *args, **pycompat.strkwargs(opts))
def mvcheck(orig, ui, repo, *pats, **opts): """Hook to check for moves at commit time""" opts = pycompat.byteskwargs(opts) renames = None disabled = opts.pop('no_automv', False) if not disabled: threshold = ui.configint('automv', 'similarity') if not 0 <= threshold <= 100: raise error.Abort(_('automv.similarity must be between 0 and 100')) if threshold > 0: match = scmutil.match(repo[None], pats, opts) added, removed = _interestingfiles(repo, match) renames = _findrenames(repo, match, added, removed, threshold / 100.0) with repo.wlock(): if renames is not None: scmutil._markchanges(repo, (), (), renames) return orig(ui, repo, *pats, **pycompat.strkwargs(opts))
def __call__(self, ui, repo, *pats, **opts): opts = pycompat.byteskwargs(opts) options = ' '.join(map(procutil.shellquote, opts['option'])) if options: options = ' ' + options return dodiff(ui, repo, self._cmdline + options, pats, opts)