Mercurial > hg
changeset 2803:987c31e2a08c
Merge with crew
author | Matt Mackall <mpm@selenic.com> |
---|---|
date | Mon, 07 Aug 2006 16:47:06 -0500 |
parents | fdc232d8a193 (current diff) df220d0974dd (diff) |
children | 4b20daa25f15 |
files | hgext/mq.py mercurial/commands.py mercurial/localrepo.py mercurial/merge.py |
diffstat | 10 files changed, 369 insertions(+), 95 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hgext/fetch.py Mon Aug 07 16:47:06 2006 -0500 @@ -0,0 +1,93 @@ +# fetch.py - pull and merge remote changes +# +# Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com> +# +# This software may be used and distributed according to the terms +# of the GNU General Public License, incorporated herein by reference. + +from mercurial.demandload import * +from mercurial.i18n import gettext as _ +from mercurial.node import * +demandload(globals(), 'mercurial:commands,hg,node,util') + +def fetch(ui, repo, source='default', **opts): + '''Pull changes from a remote repository, merge new changes if needed. + + This finds all changes from the repository at the specified path + or URL and adds them to the local repository. + + If the pulled changes add a new head, the head is automatically + merged, and the result of the merge is committed. Otherwise, the + working directory is updated.''' + + def postincoming(other, modheads): + if modheads == 0: + return 0 + if modheads == 1: + return commands.doupdate(ui, repo) + newheads = repo.heads(parent) + newchildren = [n for n in repo.heads(parent) if n != parent] + newparent = parent + if newchildren: + commands.doupdate(ui, repo, node=hex(newchildren[0])) + newparent = newchildren[0] + newheads = [n for n in repo.heads() if n != newparent] + err = False + if newheads: + ui.status(_('merging with new head %d:%s\n') % + (repo.changelog.rev(newheads[0]), short(newheads[0]))) + err = repo.update(newheads[0], allow=True, remind=False) + if not err and len(newheads) > 1: + ui.status(_('not merging with %d other new heads ' + '(use "hg heads" and "hg merge" to merge them)') % + (len(newheads) - 1)) + if not err: + mod, add, rem = repo.status()[:3] + message = (commands.logmessage(opts) or + (_('Automated merge with %s') % other.url())) + n = repo.commit(mod + add + rem, message, + opts['user'], opts['date'], + force_editor=opts.get('force_editor')) + ui.status(_('new changeset %d:%s merges remote changes ' + 'with local\n') % (repo.changelog.rev(n), + short(n))) + def pull(): + commands.setremoteconfig(ui, opts) + + other = hg.repository(ui, ui.expandpath(source)) + ui.status(_('pulling from %s\n') % source) + revs = None + if opts['rev'] and not other.local(): + raise util.Abort(_("fetch -r doesn't work for remote repositories yet")) + elif opts['rev']: + revs = [other.lookup(rev) for rev in opts['rev']] + modheads = repo.pull(other, heads=revs) + return postincoming(other, modheads) + + parent, p2 = repo.dirstate.parents() + if parent != repo.changelog.tip(): + raise util.Abort(_('working dir not at tip ' + '(use "hg update" to check out tip)')) + if p2 != nullid: + raise util.Abort(_('outstanding uncommitted merge')) + mod, add, rem = repo.status()[:3] + if mod or add or rem: + raise util.Abort(_('outstanding uncommitted changes')) + if len(repo.heads()) > 1: + raise util.Abort(_('multiple heads in this repository ' + '(use "hg heads" and "hg merge" to merge them)')) + return pull() + +cmdtable = { + 'fetch': + (fetch, + [('e', 'ssh', '', _('specify ssh command to use')), + ('m', 'message', '', _('use <text> as commit message')), + ('l', 'logfile', '', _('read the commit message from <file>')), + ('d', 'date', '', _('record datecode as commit date')), + ('u', 'user', '', _('record user as commiter')), + ('r', 'rev', [], _('a specific revision you would like to pull')), + ('f', 'force-editor', None, _('edit commit message')), + ('', 'remotecmd', '', _('hg command to run on the remote side'))], + 'hg fetch [SOURCE]'), + }
--- a/hgext/mq.py Mon Aug 07 16:27:09 2006 -0500 +++ b/hgext/mq.py Mon Aug 07 16:47:06 2006 -0500 @@ -39,6 +39,16 @@ commands.norepo += " qclone qversion" +class StatusEntry: + def __init__(self, rev, name=None): + if not name: + self.rev, self.name = rev.split(':') + else: + self.rev, self.name = rev, name + + def __str__(self): + return self.rev + ':' + self.name + class queue: def __init__(self, ui, path, patchdir=None): self.basepath = path @@ -60,7 +70,8 @@ self.parse_series() if os.path.exists(os.path.join(self.path, self.status_path)): - self.applied = self.opener(self.status_path).read().splitlines() + self.applied = [StatusEntry(l) + for l in self.opener(self.status_path).read().splitlines()] def find_series(self, patch): pre = re.compile("(\s*)([^#]+)") @@ -88,7 +99,7 @@ for i in items: print >> fp, i fp.close() - if self.applied_dirty: write_list(self.applied, self.status_path) + if self.applied_dirty: write_list(map(str, self.applied), self.status_path) if self.series_dirty: write_list(self.full_series, self.series_path) def readheaders(self, patch): @@ -209,12 +220,10 @@ return p1 if len(self.applied) == 0: return None - (top, patch) = self.applied[-1].split(':') - top = revlog.bin(top) - return top + return revlog.bin(self.applied[-1].rev) pp = repo.changelog.parents(rev) if pp[1] != revlog.nullid: - arevs = [ x.split(':')[0] for x in self.applied ] + arevs = [ x.rev for x in self.applied ] p0 = revlog.hex(pp[0]) p1 = revlog.hex(pp[1]) if p0 in arevs: @@ -234,7 +243,7 @@ pname = ".hg.patches.merge.marker" n = repo.commit(None, '[mq]: merge marker', user=None, force=1, wlock=wlock) - self.applied.append(revlog.hex(n) + ":" + pname) + self.applied.append(StatusEntry(revlog.hex(n), pname)) self.applied_dirty = 1 head = self.qparents(repo) @@ -252,7 +261,7 @@ rev = revlog.bin(info[1]) (err, head) = self.mergeone(repo, mergeq, head, patch, rev, wlock) if head: - self.applied.append(revlog.hex(head) + ":" + patch) + self.applied.append(StatusEntry(revlog.hex(head), patch)) self.applied_dirty = 1 if err: return (err, head) @@ -263,8 +272,8 @@ patchfile: file name of patch''' try: pp = util.find_in_path('gpatch', os.environ.get('PATH', ''), 'patch') - f = os.popen("%s -d '%s' -p1 --no-backup-if-mismatch < '%s'" % - (pp, repo.root, patchfile)) + f = os.popen("%s -d %s -p1 --no-backup-if-mismatch < %s" % + (pp, util.shellquote(repo.root), util.shellquote(patchfile))) except: self.ui.warn("patch failed, unable to continue (try -v)\n") return (None, [], False) @@ -275,11 +284,7 @@ if self.ui.verbose: self.ui.warn(l + "\n") if l[:14] == 'patching file ': - pf = os.path.normpath(l[14:]) - # when patch finds a space in the file name, it puts - # single quotes around the filename. strip them off - if pf[0] == "'" and pf[-1] == "'": - pf = pf[1:-1] + pf = os.path.normpath(util.parse_patch_output(l)) if pf not in files: files.append(pf) printed_file = False @@ -351,7 +356,7 @@ raise util.Abort(_("repo commit failed")) if update_status: - self.applied.append(revlog.hex(n) + ":" + patch) + self.applied.append(StatusEntry(revlog.hex(n), patch)) if patcherr: if not patchfound: @@ -389,8 +394,7 @@ def check_toppatch(self, repo): if len(self.applied) > 0: - (top, patch) = self.applied[-1].split(':') - top = revlog.bin(top) + top = revlog.bin(self.applied[-1].rev) pp = repo.dirstate.parents() if top not in pp: raise util.Abort(_("queue top not at same revision as working directory")) @@ -421,7 +425,7 @@ if n == None: raise util.Abort(_("repo commit failed")) self.full_series[insert:insert] = [patch] - self.applied.append(revlog.hex(n) + ":" + patch) + self.applied.append(StatusEntry(revlog.hex(n), patch)) self.parse_series() self.series_dirty = 1 self.applied_dirty = 1 @@ -501,9 +505,9 @@ # we go in two steps here so the strip loop happens in a # sensible order. When stripping many files, this helps keep # our disk access patterns under control. - list = seen.keys() - list.sort() - for f in list: + seen_list = seen.keys() + seen_list.sort() + for f in seen_list: ff = repo.file(f) filerev = seen[f] if filerev != 0: @@ -535,7 +539,6 @@ saveheads = [] savebases = {} - tip = chlog.tip() heads = limitheads(chlog, rev) seen = {} @@ -566,7 +569,7 @@ savebases[x] = 1 # create a changegroup for all the branches we need to keep - if backup is "all": + if backup == "all": backupch = repo.changegroupsubset([rev], chlog.heads(), 'strip') bundle(backupch) if saveheads: @@ -581,16 +584,15 @@ if saveheads: self.ui.status("adding branch\n") commands.unbundle(self.ui, repo, chgrpfile, update=False) - if backup is not "strip": + if backup != "strip": os.unlink(chgrpfile) def isapplied(self, patch): """returns (index, rev, patch)""" for i in xrange(len(self.applied)): - p = self.applied[i] - a = p.split(':') - if a[1] == patch: - return (i, a[0], a[1]) + a = self.applied[i] + if a.name == patch: + return (i, a.rev, a.name) return None # if the exact patch name does not exist, we try a few @@ -693,7 +695,7 @@ ret = self.mergepatch(repo, mergeq, s, wlock) else: ret = self.apply(repo, s, list, wlock=wlock) - top = self.applied[-1].split(':')[1] + top = self.applied[-1].name if ret[0]: self.ui.write("Errors during apply, please fix and refresh %s\n" % top) @@ -730,7 +732,7 @@ if not update: parents = repo.dirstate.parents() - rr = [ revlog.bin(x.split(':')[0]) for x in self.applied ] + rr = [ revlog.bin(x.rev) for x in self.applied ] for p in parents: if p in rr: self.ui.warn("qpop: forcing dirstate update\n") @@ -751,7 +753,7 @@ if popi >= end: self.ui.warn("qpop: %s is already at the top\n" % patch) return - info = [ popi ] + self.applied[popi].split(':') + info = [ popi ] + [self.applied[popi].rev, self.applied[popi].name] start = info[0] rev = revlog.bin(info[1]) @@ -784,7 +786,7 @@ self.strip(repo, rev, update=False, backup='strip', wlock=wlock) del self.applied[start:end] if len(self.applied): - self.ui.write("Now at: %s\n" % self.applied[-1].split(':')[1]) + self.ui.write("Now at: %s\n" % self.applied[-1].name) else: self.ui.write("Patch queue now empty\n") @@ -802,8 +804,7 @@ return wlock = repo.wlock() self.check_toppatch(repo) - qp = self.qparents(repo) - (top, patch) = self.applied[-1].split(':') + (top, patch) = (self.applied[-1].rev, self.applied[-1].name) top = revlog.bin(top) cparents = repo.changelog.parents(top) patchparent = self.qparents(repo, top) @@ -899,7 +900,7 @@ self.strip(repo, top, update=False, backup='strip', wlock=wlock) n = repo.commit(filelist, message, changes[1], force=1, wlock=wlock) - self.applied[-1] = revlog.hex(n) + ':' + patch + self.applied[-1] = StatusEntry(revlog.hex(n), patch) self.applied_dirty = 1 else: commands.dodiff(patchf, self.ui, repo, patchparent, None) @@ -921,10 +922,7 @@ start = self.series_end() else: start = self.series.index(patch) + 1 - for p in self.series[start:]: - if self.ui.verbose: - self.ui.write("%d " % self.series.index(p)) - self.ui.write("%s\n" % p) + return [(i, self.series[i]) for i in xrange(start, len(self.series))] def qseries(self, repo, missing=None, summary=False): start = self.series_end() @@ -944,7 +942,7 @@ msg = '' self.ui.write('%s%s\n' % (patch, msg)) else: - list = [] + msng_list = [] for root, dirs, files in os.walk(self.path): d = root[len(self.path) + 1:] for f in files: @@ -952,13 +950,12 @@ if (fl not in self.series and fl not in (self.status_path, self.series_path) and not fl.startswith('.')): - list.append(fl) - list.sort() - if list: - for x in list: - if self.ui.verbose: - self.ui.write("D ") - self.ui.write("%s\n" % x) + msng_list.append(fl) + msng_list.sort() + for x in msng_list: + if self.ui.verbose: + self.ui.write("D ") + self.ui.write("%s\n" % x) def issaveline(self, l): name = l.split(':')[1] @@ -987,12 +984,11 @@ qpp = [ hg.bin(x) for x in l ] elif datastart != None: l = lines[i].rstrip() - index = l.index(':') - id = l[:index] - file = l[index + 1:] - if id: - applied.append(l) - series.append(file) + se = StatusEntry(l) + file_ = se.name + if se.rev: + applied.append(se) + series.append(file_) if datastart == None: self.ui.warn("No saved patch data found\n") return 1 @@ -1043,18 +1039,18 @@ pp = r.dirstate.parents() msg += "\nDirstate: %s %s" % (hg.hex(pp[0]), hg.hex(pp[1])) msg += "\n\nPatch Data:\n" - text = msg + "\n".join(self.applied) + '\n' + (ar and "\n".join(ar) + text = msg + "\n".join(str(self.applied)) + '\n' + (ar and "\n".join(ar) + '\n' or "") n = repo.commit(None, text, user=None, force=1) if not n: self.ui.warn("repo commit failed\n") return 1 - self.applied.append(revlog.hex(n) + ":" + '.hg.patches.save.line') + self.applied.append(StatusEntry(revlog.hex(n),'.hg.patches.save.line')) self.applied_dirty = 1 def full_series_end(self): if len(self.applied) > 0: - (top, p) = self.applied[-1].split(':') + p = self.applied[-1].name end = self.find_series(p) if end == None: return len(self.full_series) @@ -1064,7 +1060,7 @@ def series_end(self): end = 0 if len(self.applied) > 0: - (top, p) = self.applied[-1].split(':') + p = self.applied[-1].name try: end = self.series.index(p) except ValueError: @@ -1084,8 +1080,7 @@ self.ui.write("%s\n" % p) def appliedname(self, index): - p = self.applied[index] - pname = p.split(':')[1] + pname = self.applied[index].name if not self.ui.verbose: p = pname else: @@ -1173,8 +1168,10 @@ def unapplied(ui, repo, patch=None, **opts): """print the patches not yet applied""" - repo.mq.unapplied(repo, patch) - return 0 + for i, p in repo.mq.unapplied(repo, patch): + if ui.verbose: + ui.write("%d " % i) + ui.write("%s\n" % p) def qimport(ui, repo, *filename, **opts): """import a patch""" @@ -1223,7 +1220,7 @@ if sr.local(): reposetup(ui, sr) if sr.mq.applied: - qbase = revlog.bin(sr.mq.applied[0].split(':')[0]) + qbase = revlog.bin(sr.mq.applied[0].rev) if not hg.islocal(dest): destrev = sr.parents(qbase)[0] ui.note(_('cloning main repo\n')) @@ -1286,7 +1283,7 @@ If neither is specified, the patch header is empty and the commit message is 'New patch: PATCH'""" q = repo.mq - message=commands.logmessage(**opts) + message = commands.logmessage(**opts) q.new(repo, patch, msg=message, force=opts['force']) q.save_dirty() return 0 @@ -1294,11 +1291,11 @@ def refresh(ui, repo, **opts): """update the current patch""" q = repo.mq - message=commands.logmessage(**opts) + message = commands.logmessage(**opts) if opts['edit']: if message: raise util.Abort(_('option "-e" incompatible with "-m" or "-l"')) - patch = q.applied[-1].split(':')[1] + patch = q.applied[-1].name (message, comment, user, date, hasdiff) = q.readheaders(patch) message = ui.edit('\n'.join(message), user or ui.username()) q.refresh(repo, msg=message, short=opts['short']) @@ -1331,7 +1328,7 @@ if not q.check_toppatch(repo): raise util.Abort(_('No patches applied\n')) - message=commands.logmessage(**opts) + message = commands.logmessage(**opts) if opts['edit']: if message: raise util.Abort(_('option "-e" incompatible with "-m" or "-l"')) @@ -1342,7 +1339,7 @@ for f in files: patch = q.lookup(f) if patch in patches or patch == parent: - self.ui.warn(_('Skipping already folded patch %s') % patch) + ui.warn(_('Skipping already folded patch %s') % patch) if q.isapplied(patch): raise util.Abort(_('qfold cannot fold already applied patch %s') % patch) patches.append(patch) @@ -1388,20 +1385,20 @@ ui.write('\n'.join(message) + '\n') def lastsavename(path): - (dir, base) = os.path.split(path) - names = os.listdir(dir) + (directory, base) = os.path.split(path) + names = os.listdir(directory) namere = re.compile("%s.([0-9]+)" % base) - max = None + maxindex = None maxname = None for f in names: m = namere.match(f) if m: index = int(m.group(1)) - if max == None or index > max: - max = index + if maxindex == None or index > maxindex: + maxindex = index maxname = f if maxname: - return (os.path.join(dir, maxname), max) + return (os.path.join(directory, maxname), maxindex) return (None, None) def savename(path): @@ -1482,7 +1479,7 @@ info = q.isapplied(patch) if info: - q.applied[info[0]] = info[1] + ':' + name + q.applied[info[0]] = StatusEntry(info[1], name) q.applied_dirty = 1 util.rename(os.path.join(q.path, patch), absdest) @@ -1508,7 +1505,7 @@ def save(ui, repo, **opts): """save current queue state""" q = repo.mq - message=commands.logmessage(**opts) + message = commands.logmessage(**opts) ret = q.save(repo, msg=message) if ret: return ret @@ -1563,7 +1560,7 @@ if not q.applied: return tagscache - mqtags = [patch.split(':') for patch in q.applied] + mqtags = [(patch.rev, patch.name) for patch in q.applied] mqtags.append((mqtags[-1][0], 'qtip')) mqtags.append((mqtags[0][0], 'qbase')) for patch in mqtags:
--- a/hgext/notify.py Mon Aug 07 16:27:09 2006 -0500 +++ b/hgext/notify.py Mon Aug 07 16:47:06 2006 -0500 @@ -255,7 +255,7 @@ changegroup. else send one email per changeset.''' n = notifier(ui, repo, hooktype) if not n.subs: - ui.debug(_('notify: no subscribers to this repo\n')) + ui.debug(_('notify: no subscribers to repo %s\n' % n.root)) return if n.skipsource(source): ui.debug(_('notify: changes have source "%s" - skipping\n') %
--- a/hgext/patchbomb.py Mon Aug 07 16:27:09 2006 -0500 +++ b/hgext/patchbomb.py Mon Aug 07 16:47:06 2006 -0500 @@ -288,7 +288,8 @@ fp.close() else: ui.status('Sending ', m['Subject'], ' ...\n') - m.__delitem__('bcc') + # Exim does not remove the Bcc field + del m['Bcc'] mail.sendmail(sender, to + bcc + cc, m.as_string(0)) cmdtable = {
--- a/mercurial/commands.py Mon Aug 07 16:27:09 2006 -0500 +++ b/mercurial/commands.py Mon Aug 07 16:47:06 2006 -0500 @@ -40,7 +40,7 @@ return [util.normpath(os.path.join(cwd, x)) for x in args] return args -def logmessage(**opts): +def logmessage(opts): """ get the log message according to -m and -l option """ message = opts['message'] logfile = opts['logfile'] @@ -125,12 +125,22 @@ files, matchfn, anypats = matchpats(repo, pats, opts) - follow = opts.get('follow') + follow = opts.get('follow') or opts.get('follow_first') if repo.changelog.count() == 0: return [], False, matchfn - revs = map(int, revrange(ui, repo, opts['rev'] or ['tip:0'])) + if follow: + p = repo.dirstate.parents()[0] + if p == nullid: + ui.warn(_('No working directory revision; defaulting to tip\n')) + start = 'tip' + else: + start = repo.changelog.rev(p) + defrange = '%s:0' % start + else: + defrange = 'tip:0' + revs = map(int, revrange(ui, repo, opts['rev'] or [defrange])) wanted = {} slowpath = anypats fncache = {} @@ -206,10 +216,55 @@ wanted[rev] = 1 def iterate(): + class followfilter: + def __init__(self, onlyfirst=False): + self.startrev = -1 + self.roots = [] + self.onlyfirst = onlyfirst + + def match(self, rev): + def realparents(rev): + if self.onlyfirst: + return repo.changelog.parentrevs(rev)[0:1] + else: + return filter(lambda x: x != -1, repo.changelog.parentrevs(rev)) + + if self.startrev == -1: + self.startrev = rev + return True + + if rev > self.startrev: + # forward: all descendants + if not self.roots: + self.roots.append(self.startrev) + for parent in realparents(rev): + if parent in self.roots: + self.roots.append(rev) + return True + else: + # backwards: all parents + if not self.roots: + self.roots.extend(realparents(self.startrev)) + if rev in self.roots: + self.roots.remove(rev) + self.roots.extend(realparents(rev)) + return True + + return False + + if follow and not files: + ff = followfilter(onlyfirst=opts.get('follow_first')) + def want(rev): + if rev not in wanted: + return False + return ff.match(rev) + else: + def want(rev): + return rev in wanted + for i, window in increasing_windows(0, len(revs)): yield 'window', revs[0] < revs[-1], revs[-1] - nrevs = [rev for rev in revs[i:i+window] - if rev in wanted] + nrevs = [rev for rev in revs[i:i+window] if want(rev)] srevs = list(nrevs) srevs.sort() for rev in srevs: @@ -1041,7 +1096,7 @@ If no commit message is specified, the editor configured in your hgrc or in the EDITOR environment variable is started to enter a message. """ - message = logmessage(**opts) + message = logmessage(opts) if opts['addremove']: addremove_lock(ui, repo, pats, opts) @@ -1972,8 +2027,14 @@ project. File history is shown without following rename or copy history of - files. Use -f/--follow to follow history across renames and - copies. + files. Use -f/--follow with a file name to follow history across + renames and copies. --follow without a file name will only show + ancestors or descendants of the starting revision. --follow-first + only follows the first parent of merge revisions. + + If no revision range is specified, the default is tip:0 unless + --follow is set, in which case the working directory parent is + used as the starting revision. By default this command outputs: changeset id and hash, tags, non-trivial parents, user, date and time, and a summary for each @@ -2728,8 +2789,8 @@ necessary. The file '.hg/localtags' is used for local tags (not shared among repositories). """ - if name == "tip": - raise util.Abort(_("the name 'tip' is reserved")) + if name in ['tip', '.']: + raise util.Abort(_("the name '%s' is reserved") % name) if rev_ is not None: ui.warn(_("use of 'hg tag NAME [REV]' is deprecated, " "please use 'hg tag [-r REV] NAME' instead\n")) @@ -3087,7 +3148,9 @@ (log, [('b', 'branches', None, _('show branches')), ('f', 'follow', None, - _('follow file history across copies and renames')), + _('follow changeset history, or file history across copies and renames')), + ('', 'follow-first', None, + _('only follow the first parent of merge changesets')), ('k', 'keyword', [], _('search for a keyword')), ('l', 'limit', '', _('limit number of changes displayed')), ('r', 'rev', [], _('show the specified revision or range')),
--- a/mercurial/localrepo.py Mon Aug 07 16:27:09 2006 -0500 +++ b/mercurial/localrepo.py Mon Aug 07 16:47:06 2006 -0500 @@ -292,6 +292,10 @@ try: return self.tags()[key] except KeyError: + if key == '.': + key = self.dirstate.parents()[0] + if key == nullid: + raise repo.RepoError(_("no revision checked out")) try: return self.changelog.lookup(key) except: @@ -1693,6 +1697,7 @@ return newheads - oldheads + 1 + def stream_in(self, remote): fp = remote.stream_out() resp = int(fp.readline())
--- a/mercurial/merge.py Mon Aug 07 16:27:09 2006 -0500 +++ b/mercurial/merge.py Mon Aug 07 16:47:06 2006 -0500 @@ -48,7 +48,8 @@ return r def update(repo, node, allow=False, force=False, choose=None, - moddirstate=True, forcemerge=False, wlock=None, show_stats=True): + moddirstate=True, forcemerge=False, wlock=None, show_stats=True, + remind=True): pl = repo.dirstate.parents() if not force and pl[1] != nullid: raise util.Abort(_("outstanding uncommitted merges")) @@ -337,7 +338,7 @@ " hg merge %s\n" % (repo.changelog.rev(p1), repo.changelog.rev(p2)))) - else: + elif remind: repo.ui.status(_("(branch merge, don't forget to commit)\n")) elif failedmerge: repo.ui.status(_("There are unresolved merges with"
--- a/mercurial/util.py Mon Aug 07 16:27:09 2006 -0500 +++ b/mercurial/util.py Mon Aug 07 16:47:06 2006 -0500 @@ -99,9 +99,9 @@ patcher = find_in_path('gpatch', os.environ.get('PATH', ''), 'patch') args = [] if cwd: - args.append('-d "%s"' % cwd) - fp = os.popen('%s %s -p%d < "%s"' % (patcher, ' '.join(args), strip, - patchname)) + args.append('-d %s' % shellquote(cwd)) + fp = os.popen('%s %s -p%d < %s' % (patcher, ' '.join(args), strip, + shellquote(patchname))) files = {} for line in fp: line = line.rstrip() @@ -611,6 +611,9 @@ def samestat(s1, s2): return False + def shellquote(s): + return '"%s"' % s.replace('"', '\\"') + def explain_exit(code): return _("exited with status %d") % code, code @@ -700,6 +703,9 @@ else: raise + def shellquote(s): + return "'%s'" % s.replace("'", "'\\''") + def testpid(pid): '''return False if pid dead, True if running or not sure''' try:
--- a/tests/test-log Mon Aug 07 16:27:09 2006 -0500 +++ b/tests/test-log Mon Aug 07 16:47:06 2006 -0500 @@ -28,3 +28,38 @@ hg log -vf a echo % many renames hg log -vf e + +# log --follow tests +hg init ../follow +cd ../follow +echo base > base +hg ci -Ambase -d '1 0' + +echo r1 >> base +hg ci -Amr1 -d '1 0' +echo r2 >> base +hg ci -Amr2 -d '1 0' + +hg up -C 1 +echo b1 > b1 +hg ci -Amb1 -d '1 0' + +echo % log -f +hg log -f + +hg up -C 0 +echo b2 > b2 +hg ci -Amb2 -d '1 0' + +echo % log -f -r 1:tip +hg log -f -r 1:tip + +hg up -C 3 +hg merge tip +hg ci -mm12 -d '1 0' + +echo postm >> b1 +hg ci -Amb1.1 -d'1 0' + +echo % log --follow-first +hg log --follow-first
--- a/tests/test-log.out Mon Aug 07 16:27:09 2006 -0500 +++ b/tests/test-log.out Mon Aug 07 16:47:06 2006 -0500 @@ -76,3 +76,76 @@ a +adding base +1 files updated, 0 files merged, 0 files removed, 0 files unresolved +adding b1 +% log -f +changeset: 3:e62f78d544b4 +tag: tip +parent: 1:3d5bf5654eda +user: test +date: Thu Jan 01 00:00:01 1970 +0000 +summary: b1 + +changeset: 1:3d5bf5654eda +user: test +date: Thu Jan 01 00:00:01 1970 +0000 +summary: r1 + +changeset: 0:67e992f2c4f3 +user: test +date: Thu Jan 01 00:00:01 1970 +0000 +summary: base + +1 files updated, 0 files merged, 1 files removed, 0 files unresolved +adding b2 +% log -f -r 1:tip +changeset: 1:3d5bf5654eda +user: test +date: Thu Jan 01 00:00:01 1970 +0000 +summary: r1 + +changeset: 2:60c670bf5b30 +user: test +date: Thu Jan 01 00:00:01 1970 +0000 +summary: r2 + +changeset: 3:e62f78d544b4 +parent: 1:3d5bf5654eda +user: test +date: Thu Jan 01 00:00:01 1970 +0000 +summary: b1 + +2 files updated, 0 files merged, 1 files removed, 0 files unresolved +1 files updated, 0 files merged, 0 files removed, 0 files unresolved +(branch merge, don't forget to commit) +% log --follow-first +changeset: 6:2404bbcab562 +tag: tip +user: test +date: Thu Jan 01 00:00:01 1970 +0000 +summary: b1.1 + +changeset: 5:302e9dd6890d +parent: 3:e62f78d544b4 +parent: 4:ddb82e70d1a1 +user: test +date: Thu Jan 01 00:00:01 1970 +0000 +summary: m12 + +changeset: 3:e62f78d544b4 +parent: 1:3d5bf5654eda +user: test +date: Thu Jan 01 00:00:01 1970 +0000 +summary: b1 + +changeset: 1:3d5bf5654eda +user: test +date: Thu Jan 01 00:00:01 1970 +0000 +summary: r1 + +changeset: 0:67e992f2c4f3 +user: test +date: Thu Jan 01 00:00:01 1970 +0000 +summary: base +