##// END OF EJS Templates
strip: make --keep option not set all dirstate times to 0...
strip: make --keep option not set all dirstate times to 0 hg strip -k was using dirstate.rebuild() which reset all the dirstate entries timestamps to 0. This meant that the next time hg status was run every file was considered to be 'unsure', which caused it to do expensive read operations on every filelog. On a repo with >150,000 files it took 70 seconds when everything was in memory. From a cold cache it took several minutes. The fix is to only reset files that have changed between the working context and the destination context. For reference, --keep means the working directory is left alone during the strip. We have users wanting to use this operation to store their work-in-progress as a commit on a branch while they go work on another branch, then come back later and be able to uncommit that work and continue working. They currently use 'git reset HARD^' to accomplish this in git.

File last commit:

r18572:5fe58f93 default
r18760:e74704c3 default
Show More
git.py
298 lines | 10.1 KiB | text/x-python | PythonLexer
Martin Geisler
convert: add copyright and license headers to back-ends
r8250 # git.py - git support for the convert extension
#
# Copyright 2005-2009 Matt Mackall <mpm@selenic.com> and others
#
# This software may be used and distributed according to the terms of the
Matt Mackall
Update license to GPLv2+
r10263 # GNU General Public License version 2 or any later version.
Brendan Cully
Split convert extension into common and repository type modules
r4536
import os
Ross Lagerwall
convert/git: catch errors from modern git-ls-remote (issue3428)...
r18570 import subprocess
YaNan Xu
convert: add support for converting git submodule (issue3528)...
r17929 from mercurial import util, config
Martin Geisler
clone, patch, convert: use hex(nullid) instead of '0'*40
r12144 from mercurial.node import hex, nullid
Martin Geisler
convert: mark strings for translation
r10939 from mercurial.i18n import _
Brendan Cully
Split convert extension into common and repository type modules
r4536
Patrick Mezard
convert: fail if an external required tool is not found
r5497 from common import NoRepo, commit, converter_source, checktool
Brendan Cully
Split convert extension into common and repository type modules
r4536
YaNan Xu
convert: add support for converting git submodule (issue3528)...
r17929 class submodule(object):
def __init__(self, path, node, url):
self.path = path
self.node = node
self.url = url
def hgsub(self):
return "%s = [git]%s" % (self.path, self.url)
def hgsubstate(self):
return "%s %s" % (self.node, self.path)
Brendan Cully
Split convert extension into common and repository type modules
r4536 class convert_git(converter_source):
Patrick Mezard
convert: fix issue702 about GIT_DIR= construct unsupported under Windows.
r5217 # Windows does not support GIT_DIR= construct while other systems
# cannot remove environment variable. Just assume none have
# both issues.
Augie Fackler
hgext: replace uses of hasattr with util.safehasattr
r14945 if util.safehasattr(os, 'unsetenv'):
Ross Lagerwall
convert/git: catch errors from modern git-ls-remote (issue3428)...
r18570 def gitopen(self, s, err=None):
Patrick Mezard
convert: fix issue702 about GIT_DIR= construct unsupported under Windows.
r5217 prevgitdir = os.environ.get('GIT_DIR')
os.environ['GIT_DIR'] = self.path
try:
Ross Lagerwall
convert/git: catch errors from modern git-ls-remote (issue3428)...
r18570 if err == subprocess.PIPE:
Edouard Gomez
convert: add bookmarks reading support to git backend
r13756 (stdin, stdout, stderr) = util.popen3(s)
return stdout
Ross Lagerwall
convert/git: catch errors from modern git-ls-remote (issue3428)...
r18570 elif err == subprocess.STDOUT:
return self.popen_with_stderr(s)
Edouard Gomez
convert: add bookmarks reading support to git backend
r13756 else:
return util.popen(s, 'rb')
Patrick Mezard
convert: fix issue702 about GIT_DIR= construct unsupported under Windows.
r5217 finally:
if prevgitdir is None:
del os.environ['GIT_DIR']
else:
os.environ['GIT_DIR'] = prevgitdir
else:
Ross Lagerwall
convert/git: catch errors from modern git-ls-remote (issue3428)...
r18570 def gitopen(self, s, err=None):
if err == subprocess.PIPE:
Edouard Gomez
convert: add bookmarks reading support to git backend
r13756 (sin, so, se) = util.popen3('GIT_DIR=%s %s' % (self.path, s))
timeless
convert: fix error in git solaris code
r14177 return so
Ross Lagerwall
convert/git: catch errors from modern git-ls-remote (issue3428)...
r18570 elif err == subprocess.STDOUT:
return self.popen_with_stderr(s)
Edouard Gomez
convert: add bookmarks reading support to git backend
r13756 else:
Mads Kiilerich
convert: fix git convert on solaris - it cannot remove environment variables
r14735 return util.popen('GIT_DIR=%s %s' % (self.path, s), 'rb')
Brendan Cully
convert: gitcmd wrapper for os.popen
r4767
Ross Lagerwall
convert/git: catch errors from modern git-ls-remote (issue3428)...
r18570 def popen_with_stderr(self, s):
p = subprocess.Popen(s, shell=True, bufsize=-1,
close_fds=util.closefds,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
universal_newlines=False,
env=None)
return p.stdout
Patrick Mezard
convert/git: check status when reading the whole output
r10986 def gitread(self, s):
fh = self.gitopen(s)
data = fh.read()
return data, fh.close()
Brendan Cully
convert: add -r argument specifying latest revision to convert
r4760 def __init__(self, ui, path, rev=None):
Brendan Cully
convert: call superclass init from engine init functions
r4807 super(convert_git, self).__init__(ui, path, rev=rev)
Brendan Cully
Split convert extension into common and repository type modules
r4536 if os.path.isdir(path + "/.git"):
path += "/.git"
if not os.path.exists(path + "/objects"):
Martin Geisler
convert: mark strings for translation
r10939 raise NoRepo(_("%s does not look like a Git repository") % path)
Patrick Mezard
convert: fail if an external required tool is not found
r5497
Dhruva Krishnamurthy
convert: use git executable only, with subcommands...
r6837 checktool('git', 'git')
Patrick Mezard
convert: fail if an external required tool is not found
r5497
Brendan Cully
Split convert extension into common and repository type modules
r4536 self.path = path
YaNan Xu
convert: add support for converting git submodule (issue3528)...
r17929 self.submodules = []
Brendan Cully
Split convert extension into common and repository type modules
r4536
def getheads(self):
Brendan Cully
convert: import all branches from git repositories
r4768 if not self.rev:
Patrick Mezard
convert/git: check status when reading the whole output
r10986 heads, ret = self.gitread('git rev-parse --branches --remotes')
heads = heads.splitlines()
Brendan Cully
convert: import all branches from git repositories
r4768 else:
Patrick Mezard
convert/git: check status when reading the whole output
r10986 heads, ret = self.gitread("git rev-parse --verify %s" % self.rev)
heads = [heads[:-1]]
if ret:
raise util.Abort(_('cannot retrieve git heads'))
return heads
Brendan Cully
Split convert extension into common and repository type modules
r4536
def catfile(self, rev, type):
Martin Geisler
clone, patch, convert: use hex(nullid) instead of '0'*40
r12144 if rev == hex(nullid):
Brodie Rao
cleanup: "raise SomeException()" -> "raise SomeException"
r16687 raise IOError
Patrick Mezard
convert/git: check status when reading the whole output
r10986 data, ret = self.gitread("git cat-file %s %s" % (type, rev))
if ret:
raise util.Abort(_('cannot read %r object at %s') % (type, rev))
return data
Brendan Cully
Split convert extension into common and repository type modules
r4536
def getfile(self, name, rev):
YaNan Xu
convert: add support for converting git submodule (issue3528)...
r17929 if name == '.hgsub':
data = '\n'.join([m.hgsub() for m in self.submoditer()])
mode = ''
elif name == '.hgsubstate':
data = '\n'.join([m.hgsubstate() for m in self.submoditer()])
mode = ''
else:
data = self.catfile(rev, "blob")
mode = self.modecache[(name, rev)]
Patrick Mezard
convert: merge sources getmode() into getfile()
r11134 return data, mode
Brendan Cully
Split convert extension into common and repository type modules
r4536
YaNan Xu
convert: add support for converting git submodule (issue3528)...
r17929 def submoditer(self):
null = hex(nullid)
for m in sorted(self.submodules, key=lambda p: p.path):
if m.node != null:
yield m
def parsegitmodules(self, content):
"""Parse the formatted .gitmodules file, example file format:
[submodule "sub"]\n
\tpath = sub\n
\turl = git://giturl\n
"""
self.submodules = []
c = config.config()
# Each item in .gitmodules starts with \t that cant be parsed
c.parse('.gitmodules', content.replace('\t',''))
for sec in c.sections():
s = c[sec]
if 'url' in s and 'path' in s:
self.submodules.append(submodule(s['path'], '', s['url']))
def retrievegitmodules(self, version):
modules, ret = self.gitread("git show %s:%s" % (version, '.gitmodules'))
if ret:
Bryan O'Sullivan
convert: fix a too-long line nag
r17930 raise util.Abort(_('cannot read submodules config file in %s') %
version)
YaNan Xu
convert: add support for converting git submodule (issue3528)...
r17929 self.parsegitmodules(modules)
for m in self.submodules:
node, ret = self.gitread("git rev-parse %s:%s" % (version, m.path))
if ret:
continue
m.node = node.strip()
Brendan Cully
Split convert extension into common and repository type modules
r4536 def getchanges(self, version):
self.modecache = {}
Patrick Mezard
convert/git: rename gitcmd() into gitopen() for readability
r10985 fh = self.gitopen("git diff-tree -z --root -m -r %s" % version)
Brendan Cully
Split convert extension into common and repository type modules
r4536 changes = []
Benoit Boissinot
convert: use set instead of dict
r8456 seen = set()
Patrick Mezard
convert: fix non-ASCII filenames retrieval from git sources (issue 1360)
r7242 entry = None
YaNan Xu
convert: add support for converting git submodule (issue3528)...
r17929 subexists = False
Patrick Mezard
convert: fix non-ASCII filenames retrieval from git sources (issue 1360)
r7242 for l in fh.read().split('\x00'):
if not entry:
if not l.startswith(':'):
continue
entry = l
Alexis S. L. Carvalho
convert_git: avoid returning two entries for the same file in getchanges...
r5335 continue
Patrick Mezard
convert: fix non-ASCII filenames retrieval from git sources (issue 1360)
r7242 f = l
if f not in seen:
Benoit Boissinot
convert: use set instead of dict
r8456 seen.add(f)
Patrick Mezard
convert: fix non-ASCII filenames retrieval from git sources (issue 1360)
r7242 entry = entry.split()
h = entry[3]
p = (entry[1] == "100755")
s = (entry[1] == "120000")
YaNan Xu
convert: add support for converting git submodule (issue3528)...
r17929
if f == '.gitmodules':
subexists = True
changes.append(('.hgsub', ''))
elif entry[1] == '160000' or entry[0] == ':160000':
subexists = True
else:
self.modecache[(f, h)] = (p and "x") or (s and "l") or ""
changes.append((f, h))
Patrick Mezard
convert: fix non-ASCII filenames retrieval from git sources (issue 1360)
r7242 entry = None
Patrick Mezard
convert/git: check status when reading output stream
r10987 if fh.close():
raise util.Abort(_('cannot read changes in %s') % version)
YaNan Xu
convert: add support for converting git submodule (issue3528)...
r17929
if subexists:
self.retrievegitmodules(version)
changes.append(('.hgsubstate', ''))
Brendan Cully
convert: look up copies in getchanges instead of getcommit...
r5121 return (changes, {})
Brendan Cully
Split convert extension into common and repository type modules
r4536
def getcommit(self, version):
c = self.catfile(version, "commit") # read the commit hash
end = c.find("\n\n")
Matt Mackall
many, many trivial check-code fixups
r10282 message = c[end + 2:]
Brendan Cully
convert: ove recode method into converter_source
r4759 message = self.recode(message)
Brendan Cully
Split convert extension into common and repository type modules
r4536 l = c[:end].splitlines()
parents = []
Richard Quirk
Add committer tag only when needed in git conversion...
r8271 author = committer = None
Brendan Cully
Split convert extension into common and repository type modules
r4536 for e in l[1:]:
n, v = e.split(" ", 1)
if n == "author":
p = v.split()
tm, tz = p[-2:]
author = " ".join(p[:-2])
if author[0] == "<": author = author[1:-1]
Brendan Cully
convert: ove recode method into converter_source
r4759 author = self.recode(author)
Brendan Cully
Split convert extension into common and repository type modules
r4536 if n == "committer":
p = v.split()
tm, tz = p[-2:]
committer = " ".join(p[:-2])
if committer[0] == "<": committer = committer[1:-1]
Brendan Cully
convert: ove recode method into converter_source
r4759 committer = self.recode(committer)
Matt Mackall
many, many trivial check-code fixups
r10282 if n == "parent":
parents.append(v)
Brendan Cully
Split convert extension into common and repository type modules
r4536
Richard Quirk
Add committer tag only when needed in git conversion...
r8271 if committer and committer != author:
message += "\ncommitter: %s\n" % committer
Brendan Cully
Split convert extension into common and repository type modules
r4536 tzs, tzh, tzm = tz[-5:-4] + "1", tz[-4:-2], tz[-2:]
tz = -int(tzs) * (int(tzh) * 3600 + int(tzm))
date = tm + " " + str(tz)
Brendan Cully
convert: record the source revision in the changelog
r4873 c = commit(parents=parents, date=date, author=author, desc=message,
rev=version)
Brendan Cully
Split convert extension into common and repository type modules
r4536 return c
def gettags(self):
tags = {}
Edouard Gomez
convert: support non annotated tags in git backend...
r16259 alltags = {}
Ross Lagerwall
convert/git: catch errors from modern git-ls-remote (issue3428)...
r18570 fh = self.gitopen('git ls-remote --tags "%s"' % self.path,
err=subprocess.STDOUT)
Brendan Cully
Split convert extension into common and repository type modules
r4536 prefix = 'refs/tags/'
Edouard Gomez
convert: support non annotated tags in git backend...
r16259
# Build complete list of tags, both annotated and bare ones
Brendan Cully
Split convert extension into common and repository type modules
r4536 for line in fh:
line = line.strip()
Augie Fackler
git convert: some versions of git use fatal: instead of error:...
r18572 if line.startswith("error:") or line.startswith("fatal:"):
Ross Lagerwall
convert/git: catch errors from modern git-ls-remote (issue3428)...
r18570 raise util.Abort(_('cannot read tags from %s') % self.path)
Brendan Cully
Split convert extension into common and repository type modules
r4536 node, tag = line.split(None, 1)
if not tag.startswith(prefix):
continue
Edouard Gomez
convert: support non annotated tags in git backend...
r16259 alltags[tag[len(prefix):]] = node
Patrick Mezard
convert/git: check status when reading output stream
r10987 if fh.close():
raise util.Abort(_('cannot read tags from %s') % self.path)
Brendan Cully
Split convert extension into common and repository type modules
r4536
Edouard Gomez
convert: support non annotated tags in git backend...
r16259 # Filter out tag objects for annotated tag refs
for tag in alltags:
if tag.endswith('^{}'):
tags[tag[:-3]] = alltags[tag]
else:
if tag + '^{}' in alltags:
continue
else:
tags[tag] = alltags[tag]
Brendan Cully
Split convert extension into common and repository type modules
r4536 return tags
Alexis S. L. Carvalho
convert_git: add --filemap support
r5380
def getchangedfiles(self, version, i):
changes = []
if i is None:
Patrick Mezard
convert/git: rename gitcmd() into gitopen() for readability
r10985 fh = self.gitopen("git diff-tree --root -m -r %s" % version)
Alexis S. L. Carvalho
convert_git: add --filemap support
r5380 for l in fh:
if "\t" not in l:
continue
m, f = l[:-1].split("\t")
changes.append(f)
else:
Brodie Rao
cleanup: eradicate long lines
r16683 fh = self.gitopen('git diff-tree --name-only --root -r %s '
'"%s^%s" --' % (version, version, i + 1))
Alexis S. L. Carvalho
convert_git: add --filemap support
r5380 changes = [f.rstrip('\n') for f in fh]
Patrick Mezard
convert/git: check status when reading output stream
r10987 if fh.close():
raise util.Abort(_('cannot read changes in %s') % version)
Alexis S. L. Carvalho
convert_git: add --filemap support
r5380
return changes
Edouard Gomez
convert: add bookmarks reading support to git backend
r13756
def getbookmarks(self):
bookmarks = {}
# Interesting references in git are prefixed
prefix = 'refs/heads/'
prefixlen = len(prefix)
# factor two commands
gitcmd = { 'remote/': 'git ls-remote --heads origin',
'': 'git show-ref'}
# Origin heads
for reftype in gitcmd:
try:
Ross Lagerwall
convert/git: catch errors from modern git-ls-remote (issue3428)...
r18570 fh = self.gitopen(gitcmd[reftype], err=subprocess.PIPE)
Edouard Gomez
convert: add bookmarks reading support to git backend
r13756 for line in fh:
line = line.strip()
rev, name = line.split(None, 1)
if not name.startswith(prefix):
continue
name = '%s%s' % (reftype, name[prefixlen:])
bookmarks[name] = rev
Brodie Rao
cleanup: replace naked excepts with except Exception: ...
r16689 except Exception:
Edouard Gomez
convert: add bookmarks reading support to git backend
r13756 pass
return bookmarks