# HG changeset patch # User Brendan Cully # Date 1155782985 25200 # Node ID 2f190e998eb3f0fdc7fd68daf134fc49c9d647fe # Parent 439fd013360d560e1e5188d3568e8e5ba61e4b36 Teach mq about git patches diff --git a/hgext/mq.py b/hgext/mq.py --- a/hgext/mq.py +++ b/hgext/mq.py @@ -252,6 +252,9 @@ class queue: for line in file(pf): line = line.rstrip() + if line.startswith('diff --git'): + diffstart = 2 + break if diffstart: if line.startswith('+++ '): diffstart = 2 @@ -408,7 +411,7 @@ class queue: self.ui.warn("patch failed, unable to continue (try -v)\n") return (False, [], False) - return (True, files.keys(), fuzz) + return (True, files, fuzz) def apply(self, repo, series, list=False, update_status=True, strict=False, patchdir=None, merge=None, wlock=None): @@ -421,42 +424,37 @@ class queue: lock = repo.lock() tr = repo.transaction() n = None - for patch in series: - pushable, reason = self.pushable(patch) + for patchname in series: + pushable, reason = self.pushable(patchname) if not pushable: - self.explain_pushable(patch, all_patches=True) + self.explain_pushable(patchname, all_patches=True) continue - self.ui.warn("applying %s\n" % patch) - pf = os.path.join(patchdir, patch) + self.ui.warn("applying %s\n" % patchname) + pf = os.path.join(patchdir, patchname) try: - message, comments, user, date, patchfound = self.readheaders(patch) + message, comments, user, date, patchfound = self.readheaders(patchname) except: - self.ui.warn("Unable to read %s\n" % pf) + self.ui.warn("Unable to read %s\n" % patchname) err = 1 break if not message: - message = "imported patch %s\n" % patch + message = "imported patch %s\n" % patchname else: if list: - message.append("\nimported patch %s" % patch) + message.append("\nimported patch %s" % patchname) message = '\n'.join(message) (patcherr, files, fuzz) = self.patch(repo, pf) patcherr = not patcherr - if merge and len(files) > 0: + if merge and files: # Mark as merged and update dirstate parent info - repo.dirstate.update(repo.dirstate.filterfiles(files), 'm') + repo.dirstate.update(repo.dirstate.filterfiles(files.keys()), 'm') p1, p2 = repo.dirstate.parents() repo.dirstate.setparents(p1, merge) - if len(files) > 0: - cwd = repo.getcwd() - cfiles = files - if cwd: - cfiles = [util.pathto(cwd, f) for f in files] - cmdutil.addremove(repo, cfiles, wlock=wlock) + files = patch.updatedir(self.ui, repo, files, wlock=wlock) n = repo.commit(files, message, user, date, force=1, lock=lock, wlock=wlock) @@ -464,11 +462,11 @@ class queue: raise util.Abort(_("repo commit failed")) if update_status: - self.applied.append(statusentry(revlog.hex(n), patch)) + self.applied.append(statusentry(revlog.hex(n), patchname)) if patcherr: if not patchfound: - self.ui.warn("patch %s is empty\n" % patch) + self.ui.warn("patch %s is empty\n" % patchname) err = 0 else: self.ui.warn("patch failed, rejects left in working dir\n") @@ -999,7 +997,10 @@ class queue: changes = repo.changelog.read(tip) repo.dirstate.setparents(*cparents) + copies = [(f, repo.dirstate.copied(f)) for f in a] repo.dirstate.update(a, 'a') + for dst, src in copies: + repo.dirstate.copy(src, dst) repo.dirstate.update(r, 'r') repo.dirstate.update(m, 'n') repo.dirstate.forget(forget) diff --git a/mercurial/patch.py b/mercurial/patch.py --- a/mercurial/patch.py +++ b/mercurial/patch.py @@ -343,10 +343,27 @@ def diff(repo, node1=None, node2=None, f if not node1: node1 = repo.dirstate.parents()[0] + + clcache = {} + def getchangelog(n): + if n not in clcache: + clcache[n] = repo.changelog.read(n) + return clcache[n] + mcache = {} + def getmanifest(n): + if n not in mcache: + mcache[n] = repo.manifest.read(n) + return mcache[n] + fcache = {} + def getfile(f): + if f not in fcache: + fcache[f] = repo.file(f) + return fcache[f] + # reading the data for node1 early allows it to play nicely # with repo.status and the revlog cache. - change = repo.changelog.read(node1) - mmap = repo.manifest.read(change[0]) + change = getchangelog(node1) + mmap = getmanifest(change[0]) date1 = util.datestr(change[2]) if not changes: @@ -367,17 +384,32 @@ def diff(repo, node1=None, node2=None, f if not modified and not added and not removed: return + def renamedbetween(f, n1, n2): + r1, r2 = map(repo.changelog.rev, (n1, n2)) + src = None + while r2 > r1: + cl = getchangelog(n2)[0] + m = getmanifest(cl) + try: + src = getfile(f).renamed(m[f]) + except KeyError: + return None + if src: + f = src[0] + n2 = repo.changelog.parents(n2)[0] + r2 = repo.changelog.rev(n2) + return src + if node2: - change = repo.changelog.read(node2) - mmap2 = repo.manifest.read(change[0]) + change = getchangelog(node2) + mmap2 = getmanifest(change[0]) _date2 = util.datestr(change[2]) def date2(f): return _date2 def read(f): - return repo.file(f).read(mmap2[f]) + return getfile(f).read(mmap2[f]) def renamed(f): - src = repo.file(f).renamed(mmap2[f]) - return src and src[0] or None + return renamedbetween(f, node1, node2) else: tz = util.makedate()[1] _date2 = util.datestr() @@ -390,7 +422,18 @@ def diff(repo, node1=None, node2=None, f def read(f): return repo.wread(f) def renamed(f): - return repo.dirstate.copies.get(f) + src = repo.dirstate.copies.get(f) + parent = repo.dirstate.parents()[0] + if src: + f = src[0] + of = renamedbetween(f, node1, parent) + if of: + return of + elif src: + cl = getchangelog(parent)[0] + return (src, getmanifest(cl)[src]) + else: + return None if repo.ui.quiet: r = None @@ -404,7 +447,7 @@ def diff(repo, node1=None, node2=None, f src = renamed(f) if src: copied[f] = src - srcs = [x[1] for x in copied.items()] + srcs = [x[1][0] for x in copied.items()] all = modified + added + removed all.sort() @@ -413,7 +456,7 @@ def diff(repo, node1=None, node2=None, f tn = None dodiff = True if f in mmap: - to = repo.file(f).read(mmap[f]) + to = getfile(f).read(mmap[f]) if f not in removed: tn = read(f) if opts.git: @@ -432,13 +475,13 @@ def diff(repo, node1=None, node2=None, f else: mode = gitmode(util.is_exec(repo.wjoin(f), None)) if f in copied: - a = copied[f] + a, arev = copied[f] omode = gitmode(mmap.execf(a)) addmodehdr(header, omode, mode) op = a in removed and 'rename' or 'copy' header.append('%s from %s\n' % (op, a)) header.append('%s to %s\n' % (op, f)) - to = repo.file(a).read(mmap[a]) + to = getfile(a).read(arev) else: header.append('new file mode %s\n' % mode) elif f in removed: diff --git a/tests/test-mq b/tests/test-mq --- a/tests/test-mq +++ b/tests/test-mq @@ -126,3 +126,28 @@ echo x>x hg ci -Ama hg strip tip 2>&1 | sed 's/\(saving bundle to \).*/\1/' hg unbundle .hg/strip-backup/* + +cat >>$HGTMP/.hgrc < new +chmod +x new +hg add new +hg qrefresh +sed -e "s/\(\(---\|+++\) [a-zA-Z0-9_/.-]*\).*/\1/" .hg/patches/new + +hg qnew -m'copy file' copy +hg cp new copy +hg qrefresh +sed -e "s/\(\(---\|+++\) [a-zA-Z0-9_/.-]*\).*/\1/" .hg/patches/copy + +hg qpop +hg qpush +hg qdiff diff --git a/tests/test-mq.out b/tests/test-mq.out --- a/tests/test-mq.out +++ b/tests/test-mq.out @@ -127,3 +127,22 @@ adding manifests adding file changes added 1 changesets with 1 changes to 1 files (run 'hg update' to get a working copy) +new file + +diff --git a/new b/new +new file mode 100755 +--- /dev/null ++++ b/new +@@ -0,0 +1,1 @@ ++foo +copy file + +diff --git a/new b/copy +copy from new +copy to copy +Now at: new +applying copy +Now at: copy +diff --git a/new b/copy +copy from new +copy to copy