# HG changeset patch # User Alexis S. L. Carvalho # Date 1170193016 7200 # Node ID 431f3c1d3a372dc12a3cccd8a1f13f2d4a0166fc # Parent 02205626335411d964f52dda2dd9675e776f50cf# Parent e7282dede8cd6b0a5b18a2c76e7f2a223d3d1f88 Merge with crew-stable diff --git a/doc/hgrc.5.txt b/doc/hgrc.5.txt --- a/doc/hgrc.5.txt +++ b/doc/hgrc.5.txt @@ -439,6 +439,9 @@ ui:: The committer of a changeset created when running "commit". Typically a person's name and email address, e.g. "Fred Widget ". Default is $EMAIL or username@hostname. + If the username in hgrc is empty, it has to be specified manually or + in a different hgrc file (e.g. $HOME/.hgrc, if the admin set "username =" + in the system hgrc). verbose;; Increase the amount of output printed. True or False. Default is False. diff --git a/mercurial/cmdutil.py b/mercurial/cmdutil.py --- a/mercurial/cmdutil.py +++ b/mercurial/cmdutil.py @@ -125,7 +125,7 @@ def make_file(repo, pat, node=None, pathname), mode) -def matchpats(repo, pats=[], opts={}, head=''): +def matchpats(repo, pats=[], opts={}, head='', globbed=False): cwd = repo.getcwd() if not pats and cwd: opts['include'] = [os.path.join(cwd, i) @@ -134,10 +134,12 @@ def matchpats(repo, pats=[], opts={}, he for x in opts.get('exclude', [])] cwd = '' return util.cmdmatcher(repo.root, cwd, pats or ['.'], opts.get('include'), - opts.get('exclude'), head) + opts.get('exclude'), head, globbed=globbed) -def walk(repo, pats=[], opts={}, node=None, head='', badmatch=None): - files, matchfn, anypats = matchpats(repo, pats, opts, head) +def walk(repo, pats=[], opts={}, node=None, head='', badmatch=None, + globbed=False): + files, matchfn, anypats = matchpats(repo, pats, opts, head, + globbed=globbed) exact = dict.fromkeys(files) for src, fn in repo.walk(node=node, files=files, match=matchfn, badmatch=badmatch): diff --git a/mercurial/commands.py b/mercurial/commands.py --- a/mercurial/commands.py +++ b/mercurial/commands.py @@ -604,7 +604,7 @@ def docopy(ui, repo, pats, opts, wlock): return res - pats = list(pats) + pats = util.expand_glob(pats) if not pats: raise util.Abort(_('no source or destination specified')) if len(pats) == 1: @@ -621,7 +621,8 @@ def docopy(ui, repo, pats, opts, wlock): copylist = [] for pat in pats: srcs = [] - for tag, abssrc, relsrc, exact in cmdutil.walk(repo, [pat], opts): + for tag, abssrc, relsrc, exact in cmdutil.walk(repo, [pat], opts, + globbed=True): origsrc = okaytocopy(abssrc, relsrc, exact) if origsrc: srcs.append((origsrc, abssrc, relsrc, exact)) @@ -769,10 +770,16 @@ def debugstate(ui, repo): keys = dc.keys() keys.sort() for file_ in keys: + if dc[file_][3] == -1: + # Pad or slice to locale representation + locale_len = len(time.strftime("%x %X", time.localtime(0))) + timestr = 'unset' + timestr = timestr[:locale_len] + ' '*(locale_len - len(timestr)) + else: + timestr = time.strftime("%x %X", time.localtime(dc[file_][3])) ui.write("%c %3o %10d %s %s\n" % (dc[file_][0], dc[file_][1] & 0777, dc[file_][2], - time.strftime("%x %X", - time.localtime(dc[file_][3])), file_)) + timestr, file_)) for f in repo.dirstate.copies(): ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f)) @@ -2478,7 +2485,11 @@ def unbundle(ui, repo, fname, **opts): Apply a compressed changegroup file generated by the bundle command. """ - gen = changegroup.readbundle(urllib.urlopen(fname), fname) + if os.path.exists(fname): + f = open(fname) + else: + f = urllib.urlopen(fname) + gen = changegroup.readbundle(f, fname) modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname) return postincoming(ui, repo, modheads, opts['update']) diff --git a/mercurial/localrepo.py b/mercurial/localrepo.py --- a/mercurial/localrepo.py +++ b/mercurial/localrepo.py @@ -616,6 +616,24 @@ class localrepository(repo.repository): meta = {} cp = self.dirstate.copied(fn) if cp: + # Mark the new revision of this file as a copy of another + # file. This copy data will effectively act as a parent + # of this new revision. If this is a merge, the first + # parent will be the nullid (meaning "look up the copy data") + # and the second one will be the other parent. For example: + # + # 0 --- 1 --- 3 rev1 changes file foo + # \ / rev2 renames foo to bar and changes it + # \- 2 -/ rev3 should have bar with all changes and + # should record that bar descends from + # bar in rev2 and foo in rev1 + # + # this allows this merge to succeed: + # + # 0 --- 1 --- 3 rev4 reverts the content change from rev2 + # \ / merging rev3 and rev4 should use bar@rev2 + # \- 2 --- 4 as the merge base + # meta["copy"] = cp if not manifest2: # not a branch merge meta["copyrev"] = hex(manifest1.get(cp, nullid)) @@ -624,7 +642,7 @@ class localrepository(repo.repository): meta["copyrev"] = hex(manifest1.get(cp, nullid)) elif fp1 != nullid: # copied on local side, reversed meta["copyrev"] = hex(manifest2.get(cp)) - fp2 = nullid + fp2 = fp1 else: # directory rename meta["copyrev"] = hex(manifest1.get(cp, nullid)) self.ui.debug(_(" %s: copy %s:%s\n") % diff --git a/mercurial/util.py b/mercurial/util.py --- a/mercurial/util.py +++ b/mercurial/util.py @@ -14,10 +14,13 @@ platform-specific details from the core. from i18n import _ import cStringIO, errno, getpass, popen2, re, shutil, sys, tempfile -import os, threading, time, calendar, ConfigParser, locale +import os, threading, time, calendar, ConfigParser, locale, glob -_encoding = os.environ.get("HGENCODING") or locale.getpreferredencoding() \ - or "ascii" +try: + _encoding = os.environ.get("HGENCODING") or locale.getpreferredencoding() \ + or "ascii" +except locale.Error: + _encoding = 'ascii' _encodingmode = os.environ.get("HGENCODINGMODE", "strict") _fallbackencoding = 'ISO-8859-1' @@ -233,6 +236,22 @@ class UnexpectedOutput(Abort): def always(fn): return True def never(fn): return False +def expand_glob(pats): + '''On Windows, expand the implicit globs in a list of patterns''' + if os.name != 'nt': + return list(pats) + ret = [] + for p in pats: + kind, name = patkind(p, None) + if kind is None: + globbed = glob.glob(name) + if globbed: + ret.extend(globbed) + continue + # if we couldn't expand the glob, just keep it around + ret.append(p) + return ret + def patkind(name, dflt_pat='glob'): """Split a string into an optional pattern kind prefix and the actual pattern.""" @@ -358,12 +377,11 @@ def canonpath(root, cwd, myname): def matcher(canonroot, cwd='', names=['.'], inc=[], exc=[], head='', src=None): return _matcher(canonroot, cwd, names, inc, exc, head, 'glob', src) -def cmdmatcher(canonroot, cwd='', names=['.'], inc=[], exc=[], head='', src=None): - if os.name == 'nt': - dflt_pat = 'glob' - else: - dflt_pat = 'relpath' - return _matcher(canonroot, cwd, names, inc, exc, head, dflt_pat, src) +def cmdmatcher(canonroot, cwd='', names=['.'], inc=[], exc=[], head='', + src=None, globbed=False): + if not globbed: + names = expand_glob(names) + return _matcher(canonroot, cwd, names, inc, exc, head, 'relpath', src) def _matcher(canonroot, cwd, names, inc, exc, head, dflt_pat, src): """build a function to match a set of file patterns diff --git a/tests/test-merge-commit b/tests/test-merge-commit new file mode 100755 --- /dev/null +++ b/tests/test-merge-commit @@ -0,0 +1,77 @@ +#!/bin/sh +# check that renames are correctly saved by a commit after a merge + +HGMERGE=merge +export HGMERGE + +# test with the merge on 3 having the rename on the local parent +hg init a +cd a + +echo line1 > foo +hg add foo +hg ci -m '0: add foo' -d '0 0' + +echo line2 >> foo +hg ci -m '1: change foo' -d '0 0' + +hg up -C 0 +hg mv foo bar +rm bar +echo line0 > bar +echo line1 >> bar +hg ci -m '2: mv foo bar; change bar' -d '0 0' + +hg merge 1 +echo '% contents of bar should be line0 line1 line2' +cat bar +hg ci -m '3: merge with local rename' -d '0 0' +hg debugindex .hg/store/data/bar.i +hg debugrename bar +hg debugindex .hg/store/data/foo.i + +# revert the content change from rev 2 +hg up -C 2 +rm bar +echo line1 > bar +hg ci -m '4: revert content change from rev 2' -d '0 0' + +hg log --template '#rev#:#node|short# #parents#\n' +echo '% this should use bar@rev2 as the ancestor' +hg --debug merge 3 +echo '% contents of bar should be line1 line2' +cat bar +hg ci -m '5: merge' -d '0 0' +hg debugindex .hg/store/data/bar.i + + +# same thing, but with the merge on 3 having the rename on the remote parent +echo +echo +cd .. +hg clone -U -r 1 -r 2 a b +cd b + +hg up -C 1 +hg merge 2 +echo '% contents of bar should be line0 line1 line2' +cat bar +hg ci -m '3: merge with remote rename' -d '0 0' +hg debugindex .hg/store/data/bar.i +hg debugrename bar +hg debugindex .hg/store/data/foo.i + +# revert the content change from rev 2 +hg up -C 2 +rm bar +echo line1 > bar +hg ci -m '4: revert content change from rev 2' -d '0 0' + +hg log --template '#rev#:#node|short# #parents#\n' +echo '% this should use bar@rev2 as the ancestor' +hg --debug merge 3 +echo '% contents of bar should be line1 line2' +cat bar +hg ci -m '5: merge' -d '0 0' +hg debugindex .hg/store/data/bar.i + diff --git a/tests/test-merge-commit.out b/tests/test-merge-commit.out new file mode 100644 --- /dev/null +++ b/tests/test-merge-commit.out @@ -0,0 +1,83 @@ +1 files updated, 0 files merged, 0 files removed, 0 files unresolved +merging bar and foo +0 files updated, 1 files merged, 0 files removed, 0 files unresolved +(branch merge, don't forget to commit) +% contents of bar should be line0 line1 line2 +line0 +line1 +line2 + rev offset length base linkrev nodeid p1 p2 + 0 0 77 0 2 da78c0659611 000000000000 000000000000 + 1 77 76 0 3 4b358025380b 000000000000 da78c0659611 +bar renamed from foo:9e25c27b87571a1edee5ae4dddee5687746cc8e2 + rev offset length base linkrev nodeid p1 p2 + 0 0 7 0 0 690b295714ae 000000000000 000000000000 + 1 7 13 1 1 9e25c27b8757 690b295714ae 000000000000 +1 files updated, 0 files merged, 0 files removed, 0 files unresolved +4:2d2f9a22c82b 2:0a3ab4856510 +3:7d3b554bfdf1 2:0a3ab4856510 1:5cd961e4045d +2:0a3ab4856510 0:2665aaee66e9 +1:5cd961e4045d +0:2665aaee66e9 +% this should use bar@rev2 as the ancestor +resolving manifests + overwrite None partial False + ancestor 0a3ab4856510 local 2d2f9a22c82b+ remote 7d3b554bfdf1 + bar: versions differ -> m +merging bar +my bar@2d2f9a22c82b+ other bar@7d3b554bfdf1 ancestor bar@0a3ab4856510 +0 files updated, 1 files merged, 0 files removed, 0 files unresolved +(branch merge, don't forget to commit) +% contents of bar should be line1 line2 +line1 +line2 + rev offset length base linkrev nodeid p1 p2 + 0 0 77 0 2 da78c0659611 000000000000 000000000000 + 1 77 76 0 3 4b358025380b 000000000000 da78c0659611 + 2 153 7 2 4 4defe5eec418 da78c0659611 000000000000 + 3 160 13 3 5 4663501da27b 4defe5eec418 4b358025380b + + +requesting all changes +adding changesets +adding manifests +adding file changes +added 3 changesets with 3 changes to 2 files (+1 heads) +1 files updated, 0 files merged, 0 files removed, 0 files unresolved +merging foo and bar +0 files updated, 1 files merged, 0 files removed, 0 files unresolved +(branch merge, don't forget to commit) +% contents of bar should be line0 line1 line2 +line0 +line1 +line2 + rev offset length base linkrev nodeid p1 p2 + 0 0 77 0 2 da78c0659611 000000000000 000000000000 + 1 77 76 0 3 4b358025380b 000000000000 da78c0659611 +bar renamed from foo:9e25c27b87571a1edee5ae4dddee5687746cc8e2 + rev offset length base linkrev nodeid p1 p2 + 0 0 7 0 0 690b295714ae 000000000000 000000000000 + 1 7 13 1 1 9e25c27b8757 690b295714ae 000000000000 +1 files updated, 0 files merged, 0 files removed, 0 files unresolved +4:2d2f9a22c82b 2:0a3ab4856510 +3:96ab80c60897 1:5cd961e4045d 2:0a3ab4856510 +2:0a3ab4856510 0:2665aaee66e9 +1:5cd961e4045d +0:2665aaee66e9 +% this should use bar@rev2 as the ancestor +resolving manifests + overwrite None partial False + ancestor 0a3ab4856510 local 2d2f9a22c82b+ remote 96ab80c60897 + bar: versions differ -> m +merging bar +my bar@2d2f9a22c82b+ other bar@96ab80c60897 ancestor bar@0a3ab4856510 +0 files updated, 1 files merged, 0 files removed, 0 files unresolved +(branch merge, don't forget to commit) +% contents of bar should be line1 line2 +line1 +line2 + rev offset length base linkrev nodeid p1 p2 + 0 0 77 0 2 da78c0659611 000000000000 000000000000 + 1 77 76 0 3 4b358025380b 000000000000 da78c0659611 + 2 153 7 2 4 4defe5eec418 da78c0659611 000000000000 + 3 160 13 3 5 4663501da27b 4defe5eec418 4b358025380b