mirror of
https://github.com/facebook/sapling.git
synced 2024-10-10 00:45:18 +03:00
merge crew and main
This commit is contained in:
commit
c5ab8c0508
@ -213,7 +213,9 @@ class repowatcher(object):
|
|||||||
if time != int(st_mtime):
|
if time != int(st_mtime):
|
||||||
return 'l'
|
return 'l'
|
||||||
return 'n'
|
return 'n'
|
||||||
if type_ == '?' and self.dirstate._ignore(fn):
|
if type_ == '?' and self.dirstate._dirignore(fn):
|
||||||
|
# we must check not only if the file is ignored, but if any part
|
||||||
|
# of its path match an ignore pattern
|
||||||
return 'i'
|
return 'i'
|
||||||
return type_
|
return type_
|
||||||
|
|
||||||
|
@ -476,6 +476,11 @@ class queue(object):
|
|||||||
write_list(self.full_series, self.series_path)
|
write_list(self.full_series, self.series_path)
|
||||||
if self.guards_dirty:
|
if self.guards_dirty:
|
||||||
write_list(self.active_guards, self.guards_path)
|
write_list(self.active_guards, self.guards_path)
|
||||||
|
if self.added:
|
||||||
|
qrepo = self.qrepo()
|
||||||
|
if qrepo:
|
||||||
|
qrepo[None].add(self.added)
|
||||||
|
self.added = []
|
||||||
|
|
||||||
def removeundo(self, repo):
|
def removeundo(self, repo):
|
||||||
undo = repo.sjoin('undo')
|
undo = repo.sjoin('undo')
|
||||||
@ -1623,7 +1628,6 @@ class queue(object):
|
|||||||
if (len(files) > 1 or len(rev) > 1) and patchname:
|
if (len(files) > 1 or len(rev) > 1) and patchname:
|
||||||
raise util.Abort(_('option "-n" not valid when importing multiple '
|
raise util.Abort(_('option "-n" not valid when importing multiple '
|
||||||
'patches'))
|
'patches'))
|
||||||
self.added = []
|
|
||||||
if rev:
|
if rev:
|
||||||
# If mq patches are applied, we can only import revisions
|
# If mq patches are applied, we can only import revisions
|
||||||
# that form a linear path to qbase.
|
# that form a linear path to qbase.
|
||||||
@ -1810,9 +1814,6 @@ def qimport(ui, repo, *filename, **opts):
|
|||||||
git=opts['git'])
|
git=opts['git'])
|
||||||
finally:
|
finally:
|
||||||
q.save_dirty()
|
q.save_dirty()
|
||||||
qrepo = q.qrepo()
|
|
||||||
if qrepo:
|
|
||||||
qrepo[None].add(q.added)
|
|
||||||
|
|
||||||
if opts.get('push') and not opts.get('rev'):
|
if opts.get('push') and not opts.get('rev'):
|
||||||
return q.push(repo, None)
|
return q.push(repo, None)
|
||||||
|
@ -271,9 +271,9 @@ def concludenode(repo, rev, p1, p2, commitmsg=None, extrafn=None):
|
|||||||
'Commit the changes and store useful information in extra'
|
'Commit the changes and store useful information in extra'
|
||||||
try:
|
try:
|
||||||
repo.dirstate.setparents(repo[p1].node(), repo[p2].node())
|
repo.dirstate.setparents(repo[p1].node(), repo[p2].node())
|
||||||
if commitmsg is None:
|
|
||||||
commitmsg = repo[rev].description()
|
|
||||||
ctx = repo[rev]
|
ctx = repo[rev]
|
||||||
|
if commitmsg is None:
|
||||||
|
commitmsg = ctx.description()
|
||||||
extra = {'rebase_source': ctx.hex()}
|
extra = {'rebase_source': ctx.hex()}
|
||||||
if extrafn:
|
if extrafn:
|
||||||
extrafn(ctx, extra)
|
extrafn(ctx, extra)
|
||||||
@ -347,23 +347,25 @@ def isagitpatch(repo, patchname):
|
|||||||
def updatemq(repo, state, skipped, **opts):
|
def updatemq(repo, state, skipped, **opts):
|
||||||
'Update rebased mq patches - finalize and then import them'
|
'Update rebased mq patches - finalize and then import them'
|
||||||
mqrebase = {}
|
mqrebase = {}
|
||||||
for p in repo.mq.applied:
|
mq = repo.mq
|
||||||
if repo[p.node].rev() in state:
|
for p in mq.applied:
|
||||||
|
rev = repo[p.node].rev()
|
||||||
|
if rev in state:
|
||||||
repo.ui.debug('revision %d is an mq patch (%s), finalize it.\n' %
|
repo.ui.debug('revision %d is an mq patch (%s), finalize it.\n' %
|
||||||
(repo[p.node].rev(), p.name))
|
(rev, p.name))
|
||||||
mqrebase[repo[p.node].rev()] = (p.name, isagitpatch(repo, p.name))
|
mqrebase[rev] = (p.name, isagitpatch(repo, p.name))
|
||||||
|
|
||||||
if mqrebase:
|
if mqrebase:
|
||||||
repo.mq.finish(repo, mqrebase.keys())
|
mq.finish(repo, mqrebase.keys())
|
||||||
|
|
||||||
# We must start import from the newest revision
|
# We must start import from the newest revision
|
||||||
for rev in sorted(mqrebase, reverse=True):
|
for rev in sorted(mqrebase, reverse=True):
|
||||||
if rev not in skipped:
|
if rev not in skipped:
|
||||||
repo.ui.debug('import mq patch %d (%s)\n'
|
name, isgit = mqrebase[rev]
|
||||||
% (state[rev], mqrebase[rev][0]))
|
repo.ui.debug('import mq patch %d (%s)\n' % (state[rev], name))
|
||||||
repo.mq.qimport(repo, (), patchname=mqrebase[rev][0],
|
mq.qimport(repo, (), patchname=name, git=isgit,
|
||||||
git=mqrebase[rev][1],rev=[str(state[rev])])
|
rev=[str(state[rev])])
|
||||||
repo.mq.save_dirty()
|
mq.save_dirty()
|
||||||
|
|
||||||
def storestatus(repo, originalwd, target, state, collapse, keep, keepbranches,
|
def storestatus(repo, originalwd, target, state, collapse, keep, keepbranches,
|
||||||
external):
|
external):
|
||||||
|
@ -353,6 +353,10 @@ class filectx(object):
|
|||||||
return self._filelog.size(self._filerev)
|
return self._filelog.size(self._filerev)
|
||||||
|
|
||||||
def cmp(self, text):
|
def cmp(self, text):
|
||||||
|
"""compare text with stored file revision
|
||||||
|
|
||||||
|
returns True if text is different than what is stored.
|
||||||
|
"""
|
||||||
return self._filelog.cmp(self._filenode, text)
|
return self._filelog.cmp(self._filenode, text)
|
||||||
|
|
||||||
def renamed(self):
|
def renamed(self):
|
||||||
@ -932,7 +936,11 @@ class workingfilectx(filectx):
|
|||||||
return (t, tz)
|
return (t, tz)
|
||||||
|
|
||||||
def cmp(self, text):
|
def cmp(self, text):
|
||||||
return self._repo.wread(self._path) == text
|
"""compare text with disk content
|
||||||
|
|
||||||
|
returns True if text is different than what is on disk.
|
||||||
|
"""
|
||||||
|
return self._repo.wread(self._path) != text
|
||||||
|
|
||||||
class memctx(object):
|
class memctx(object):
|
||||||
"""Use memctx to perform in-memory commits via localrepo.commitctx().
|
"""Use memctx to perform in-memory commits via localrepo.commitctx().
|
||||||
|
@ -53,14 +53,27 @@ class filelog(revlog.revlog):
|
|||||||
if self.renamed(node):
|
if self.renamed(node):
|
||||||
return len(self.read(node))
|
return len(self.read(node))
|
||||||
|
|
||||||
|
# XXX if self.read(node).startswith("\1\n"), this returns (size+4)
|
||||||
return revlog.revlog.size(self, rev)
|
return revlog.revlog.size(self, rev)
|
||||||
|
|
||||||
def cmp(self, node, text):
|
def cmp(self, node, text):
|
||||||
"""compare text with a given file revision"""
|
"""compare text with a given file revision
|
||||||
|
|
||||||
# for renames, we have to go the slow way
|
returns True if text is different than what is stored.
|
||||||
if text.startswith('\1\n') or self.renamed(node):
|
"""
|
||||||
|
|
||||||
|
t = text
|
||||||
|
if text.startswith('\1\n'):
|
||||||
|
t = '\1\n\1\n' + text
|
||||||
|
|
||||||
|
samehashes = not revlog.revlog.cmp(self, 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)
|
t2 = self.read(node)
|
||||||
return t2 != text
|
return t2 != text
|
||||||
|
|
||||||
return revlog.revlog.cmp(self, node, text)
|
return True
|
||||||
|
@ -221,7 +221,7 @@ def clone(ui, source, dest=None, pull=False, rev=None, update=True,
|
|||||||
src_repo = repository(ui, source)
|
src_repo = repository(ui, source)
|
||||||
else:
|
else:
|
||||||
src_repo = source
|
src_repo = source
|
||||||
branch = None
|
branch = (None, [])
|
||||||
origsource = source = src_repo.url()
|
origsource = source = src_repo.url()
|
||||||
rev, checkout = addbranchrevs(src_repo, src_repo, branch, rev)
|
rev, checkout = addbranchrevs(src_repo, src_repo, branch, rev)
|
||||||
|
|
||||||
|
@ -10,6 +10,26 @@ import util, encoding
|
|||||||
import os, smtplib, socket, quopri
|
import os, smtplib, socket, quopri
|
||||||
import email.Header, email.MIMEText, email.Utils
|
import email.Header, email.MIMEText, email.Utils
|
||||||
|
|
||||||
|
_oldheaderinit = email.Header.Header.__init__
|
||||||
|
def _unifiedheaderinit(self, *args, **kw):
|
||||||
|
"""
|
||||||
|
Python2.7 introduces a backwards incompatible change
|
||||||
|
(Python issue1974, r70772) in email.Generator.Generator code:
|
||||||
|
pre-2.7 code passed "continuation_ws='\t'" to the Header
|
||||||
|
constructor, and 2.7 removed this parameter.
|
||||||
|
|
||||||
|
Default argument is continuation_ws=' ', which means that the
|
||||||
|
behaviour is different in <2.7 and 2.7
|
||||||
|
|
||||||
|
We consider the 2.7 behaviour to be preferable, but need
|
||||||
|
to have an unified behaviour for versions 2.4 to 2.7
|
||||||
|
"""
|
||||||
|
# override continuation_ws
|
||||||
|
kw['continuation_ws'] = ' '
|
||||||
|
_oldheaderinit(self, *args, **kw)
|
||||||
|
|
||||||
|
email.Header.Header.__dict__['__init__'] = _unifiedheaderinit
|
||||||
|
|
||||||
def _smtp(ui):
|
def _smtp(ui):
|
||||||
'''build an smtp connection and return a function to send mail'''
|
'''build an smtp connection and return a function to send mail'''
|
||||||
local_hostname = ui.config('smtp', 'local_hostname')
|
local_hostname = ui.config('smtp', 'local_hostname')
|
||||||
|
@ -943,7 +943,10 @@ class revlog(object):
|
|||||||
raise LookupError(id, self.indexfile, _('no match found'))
|
raise LookupError(id, self.indexfile, _('no match found'))
|
||||||
|
|
||||||
def cmp(self, node, text):
|
def cmp(self, node, text):
|
||||||
"""compare text with a given file revision"""
|
"""compare text with a given file revision
|
||||||
|
|
||||||
|
returns True if text is different than what is stored.
|
||||||
|
"""
|
||||||
p1, p2 = self.parents(node)
|
p1, p2 = self.parents(node)
|
||||||
return hash(text, p1, p2) != node
|
return hash(text, p1, p2) != node
|
||||||
|
|
||||||
|
@ -137,21 +137,21 @@ hg ci -m "b3 (HN)"
|
|||||||
echo '% case NN: msg'
|
echo '% case NN: msg'
|
||||||
hg up -q null
|
hg up -q null
|
||||||
hg branch -f b
|
hg branch -f b
|
||||||
echo 1 > B
|
echo 1 > bb
|
||||||
hg ci -Am "b4 (NN): new topo root for branch b"
|
hg ci -Am "b4 (NN): new topo root for branch b"
|
||||||
|
|
||||||
echo '% case HN: no msg'
|
echo '% case HN: no msg'
|
||||||
echo 2 >> B
|
echo 2 >> bb
|
||||||
hg ci -m "b5 (HN)"
|
hg ci -m "b5 (HN)"
|
||||||
|
|
||||||
echo '% case BN: msg'
|
echo '% case BN: msg'
|
||||||
hg branch -f default
|
hg branch -f default
|
||||||
echo 1 > A
|
echo 1 > aa
|
||||||
hg ci -Am "a6 (BN): new branch root"
|
hg ci -Am "a6 (BN): new branch root"
|
||||||
|
|
||||||
echo '% case CN: msg'
|
echo '% case CN: msg'
|
||||||
hg up -q 4
|
hg up -q 4
|
||||||
echo 3 >> BB
|
echo 3 >> bbb
|
||||||
hg ci -Am "b7 (CN): regular new head"
|
hg ci -Am "b7 (CN): regular new head"
|
||||||
|
|
||||||
echo '% case BB: msg'
|
echo '% case BB: msg'
|
||||||
|
@ -187,15 +187,15 @@ marked working directory as branch b
|
|||||||
adding b
|
adding b
|
||||||
% case NN: msg
|
% case NN: msg
|
||||||
marked working directory as branch b
|
marked working directory as branch b
|
||||||
adding B
|
adding bb
|
||||||
created new head
|
created new head
|
||||||
% case HN: no msg
|
% case HN: no msg
|
||||||
% case BN: msg
|
% case BN: msg
|
||||||
marked working directory as branch default
|
marked working directory as branch default
|
||||||
adding A
|
adding aa
|
||||||
created new head
|
created new head
|
||||||
% case CN: msg
|
% case CN: msg
|
||||||
adding BB
|
adding bbb
|
||||||
created new head
|
created new head
|
||||||
% case BB: msg
|
% case BB: msg
|
||||||
marked working directory as branch default
|
marked working directory as branch default
|
||||||
|
@ -199,4 +199,14 @@ hg -R a parents --template "{node|short}\n"
|
|||||||
hg -R ua parents --template "{node|short}\n"
|
hg -R ua parents --template "{node|short}\n"
|
||||||
rm -r ua
|
rm -r ua
|
||||||
|
|
||||||
|
cat <<EOF > simpleclone.py
|
||||||
|
from mercurial import ui, hg
|
||||||
|
myui = ui.ui()
|
||||||
|
repo = hg.repository(myui, 'a')
|
||||||
|
hg.clone(myui, repo, dest="ua")
|
||||||
|
EOF
|
||||||
|
|
||||||
|
python simpleclone.py
|
||||||
|
rm -r ua
|
||||||
|
|
||||||
exit 0
|
exit 0
|
||||||
|
@ -312,3 +312,5 @@ summary: hacked default
|
|||||||
% same revision checked out in repo a and ua
|
% same revision checked out in repo a and ua
|
||||||
e8ece76546a6
|
e8ece76546a6
|
||||||
e8ece76546a6
|
e8ece76546a6
|
||||||
|
updating to branch default
|
||||||
|
3 files updated, 0 files merged, 0 files removed, 0 files unresolved
|
||||||
|
50
tests/test-filelog
Normal file
50
tests/test-filelog
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
"""
|
||||||
|
Tests the behaviour of filelog w.r.t. data starting with '\1\n'
|
||||||
|
"""
|
||||||
|
from mercurial import ui, hg
|
||||||
|
from mercurial.node import nullid, hex
|
||||||
|
|
||||||
|
myui = ui.ui()
|
||||||
|
repo = hg.repository(myui, path='.', create=True)
|
||||||
|
|
||||||
|
fl = repo.file('foobar')
|
||||||
|
|
||||||
|
def addrev(text, renamed=False):
|
||||||
|
if renamed:
|
||||||
|
# data doesnt matter. Just make sure filelog.renamed() returns True
|
||||||
|
meta = dict(copyrev=hex(nullid), copy='bar')
|
||||||
|
else:
|
||||||
|
meta = {}
|
||||||
|
|
||||||
|
t = repo.transaction('commit')
|
||||||
|
try:
|
||||||
|
node = fl.add(text, meta, t, 0, nullid, nullid)
|
||||||
|
return node
|
||||||
|
finally:
|
||||||
|
t.close()
|
||||||
|
|
||||||
|
def error(text):
|
||||||
|
print 'ERROR: ' + text
|
||||||
|
|
||||||
|
textwith = '\1\nfoo'
|
||||||
|
without = 'foo'
|
||||||
|
|
||||||
|
node = addrev(textwith)
|
||||||
|
if not textwith == fl.read(node):
|
||||||
|
error('filelog.read for data starting with \\1\\n')
|
||||||
|
if fl.cmp(node, textwith) or not fl.cmp(node, without):
|
||||||
|
error('filelog.cmp for data starting with \\1\\n')
|
||||||
|
if fl.size(0) != len(textwith):
|
||||||
|
error('FIXME: This is a known failure of filelog.size for data starting '
|
||||||
|
'with \\1\\n')
|
||||||
|
|
||||||
|
node = addrev(textwith, renamed=True)
|
||||||
|
if not textwith == fl.read(node):
|
||||||
|
error('filelog.read for a renaming + data starting with \\1\\n')
|
||||||
|
if fl.cmp(node, textwith) or not fl.cmp(node, without):
|
||||||
|
error('filelog.cmp for a renaming + data starting with \\1\\n')
|
||||||
|
if fl.size(1) != len(textwith):
|
||||||
|
error('filelog.size for a renaming + data starting with \\1\\n')
|
||||||
|
|
||||||
|
print 'OK.'
|
2
tests/test-filelog.out
Normal file
2
tests/test-filelog.out
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
ERROR: FIXME: This is a known failure of filelog.size for data starting with \1\n
|
||||||
|
OK.
|
@ -97,4 +97,17 @@ hg ci -m 'working'
|
|||||||
echo b >> 1844/foo
|
echo b >> 1844/foo
|
||||||
hg ci 1844 -m 'broken'
|
hg ci 1844 -m 'broken'
|
||||||
|
|
||||||
|
# Test for issue884: "Build products not ignored until .hgignore is touched"
|
||||||
|
echo '^build$' > .hgignore
|
||||||
|
hg add .hgignore
|
||||||
|
hg ci .hgignore -m 'ignorelist'
|
||||||
|
|
||||||
|
# Now, lets add some build products...
|
||||||
|
mkdir build
|
||||||
|
touch build/x
|
||||||
|
touch build/y
|
||||||
|
|
||||||
|
# build/x & build/y shouldn't appear in "hg st"
|
||||||
|
hg st
|
||||||
|
|
||||||
kill `cat hg.pid`
|
kill `cat hg.pid`
|
||||||
|
@ -101,6 +101,11 @@ hg qref --git -m 'P0 (git)'
|
|||||||
hg qnew f.patch
|
hg qnew f.patch
|
||||||
echo 'mq2' > p
|
echo 'mq2' > p
|
||||||
hg qref -m 'P1'
|
hg qref -m 'P1'
|
||||||
|
hg qcommit -m 'save patch state'
|
||||||
|
echo '% patch series step 1/2'
|
||||||
|
hg qseries -s
|
||||||
|
echo '% patch queue manifest step 1/2'
|
||||||
|
hg -R .hg/patches manifest
|
||||||
|
|
||||||
echo '% Git patch'
|
echo '% Git patch'
|
||||||
cat .hg/patches/f_git.patch | filterpatch
|
cat .hg/patches/f_git.patch | filterpatch
|
||||||
@ -112,6 +117,11 @@ cat .hg/patches/f.patch | filterpatch
|
|||||||
echo
|
echo
|
||||||
echo '% Rebase the applied mq patches'
|
echo '% Rebase the applied mq patches'
|
||||||
hg rebase -s 2 -d 1 --quiet
|
hg rebase -s 2 -d 1 --quiet
|
||||||
|
hg qcommit -m 'save patch state'
|
||||||
|
echo '% patch series step 2/2'
|
||||||
|
hg qseries -s
|
||||||
|
echo '% patch queue manifest step 2/2'
|
||||||
|
hg -R .hg/patches manifest
|
||||||
|
|
||||||
echo '% And the patches are correct'
|
echo '% And the patches are correct'
|
||||||
echo '% Git patch'
|
echo '% Git patch'
|
||||||
|
@ -80,6 +80,14 @@ popping f2.patch
|
|||||||
popping f.patch
|
popping f.patch
|
||||||
patch queue now empty
|
patch queue now empty
|
||||||
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
|
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
|
||||||
|
% patch series step 1/2
|
||||||
|
f_git.patch: P0 (git)
|
||||||
|
f.patch: P1
|
||||||
|
% patch queue manifest step 1/2
|
||||||
|
.hgignore
|
||||||
|
f.patch
|
||||||
|
f_git.patch
|
||||||
|
series
|
||||||
% Git patch
|
% Git patch
|
||||||
P0 (git)
|
P0 (git)
|
||||||
|
|
||||||
@ -101,6 +109,14 @@ diff -r x p
|
|||||||
+mq2
|
+mq2
|
||||||
|
|
||||||
% Rebase the applied mq patches
|
% Rebase the applied mq patches
|
||||||
|
% patch series step 2/2
|
||||||
|
f_git.patch: P0 (git)
|
||||||
|
f.patch: P1
|
||||||
|
% patch queue manifest step 2/2
|
||||||
|
.hgignore
|
||||||
|
f.patch
|
||||||
|
f_git.patch
|
||||||
|
series
|
||||||
% And the patches are correct
|
% And the patches are correct
|
||||||
% Git patch
|
% Git patch
|
||||||
# HG changeset patch
|
# HG changeset patch
|
||||||
|
Loading…
Reference in New Issue
Block a user