##// END OF EJS Templates
shelve: use rebase instead of merge (issue4068)...
shelve: use rebase instead of merge (issue4068) Previously, shelve used merge to unshelve things. This meant that if you shelved changes on one branch, then unshelved on another, all the changes from the first branch would be present in the second branch, and not just the shelved changes. The fix is to use rebase to pick the shelve commit off the original branch and place it on top of the new branch. This means only the shelved changes are brought across. This has the side effect of fixing several other issues in shelve: - you can now unshelve into a file that already has pending changes - unshelve a mv/cp now has the correct dirstate value (A instead of M) - you can now unshelve to an ancestor of the shelve - unshelve now no longer deletes untracked .orig files Updates tests and adds a new one to cover the issue. The test changes fall into a few categories: - I removed some excess output - The --continue/--abort state is a little different, so the parents and dirstate needed updating - Removed some untracked files at certain points that cluttered the output

File last commit:

r19148:3bda242b default
r19961:1d7a36ff stable
Show More
filelog.py
92 lines | 2.7 KiB | text/x-python | PythonLexer
# filelog.py - file history class for mercurial
#
# Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
#
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
import revlog
import re
_mdre = re.compile('\1\n')
def _parsemeta(text):
"""return (metadatadict, keylist, metadatasize)"""
# text can be buffer, so we can't use .startswith or .index
if text[:2] != '\1\n':
return None, None, None
s = _mdre.search(text, 2).start()
mtext = text[2:s]
meta = {}
keys = []
for l in mtext.splitlines():
k, v = l.split(": ", 1)
meta[k] = v
keys.append(k)
return meta, keys, (s + 2)
def _packmeta(meta, keys=None):
if not keys:
keys = sorted(meta.iterkeys())
return "".join("%s: %s\n" % (k, meta[k]) for k in keys)
class filelog(revlog.revlog):
def __init__(self, opener, path):
super(filelog, self).__init__(opener,
"/".join(("data", path + ".i")))
def read(self, node):
t = self.revision(node)
if not t.startswith('\1\n'):
return t
s = t.index('\1\n', 2)
return t[s + 2:]
def add(self, text, meta, transaction, link, p1=None, p2=None):
if meta or text.startswith('\1\n'):
text = "\1\n%s\1\n%s" % (_packmeta(meta), text)
return self.addrevision(text, transaction, link, p1, p2)
def renamed(self, node):
if self.parents(node)[0] != revlog.nullid:
return False
t = self.revision(node)
m = _parsemeta(t)[0]
if m and "copy" in m:
return (m["copy"], revlog.bin(m["copyrev"]))
return False
def size(self, rev):
"""return the size of a given revision"""
# for revisions with renames, we have to go the slow way
node = self.node(rev)
if self.renamed(node):
return len(self.read(node))
# XXX if self.read(node).startswith("\1\n"), this returns (size+4)
return super(filelog, self).size(rev)
def cmp(self, node, text):
"""compare text with a given file revision
returns True if text is different than what is stored.
"""
t = text
if text.startswith('\1\n'):
t = '\1\n\1\n' + text
samehashes = not super(filelog, self).cmp(node, t)
if samehashes:
return False
# renaming a file produces a different hash, even if the data
# remains unchanged. Check if it's the case (slow):
if self.renamed(node):
t2 = self.read(node)
return t2 != text
return True
def _file(self, f):
return filelog(self.opener, f)