Merge branch 'fc/remote-hg'

* fc/remote-hg: (50 commits)
  remote-hg: add support for --force
  remote-hg: add support for --dry-run
  remote-hg: check if a fetch is needed
  remote-hg: trivial cleanup
  remote-helpers: improve marks usage
  remote-hg: add check_push() helper
  remote-hg: add setup_big_push() helper
  remote-hg: remove files before modifications
  remote-hg: improve lightweight tag author
  remote-hg: use remote 'default' not local one
  remote-hg: improve branch listing
  remote-hg: simplify branch_tip()
  remote-hg: check diverged bookmarks
  remote-hg: pass around revision refs
  remote-hg: implement custom checkheads()
  remote-hg: implement custom push()
  remote-hg: only update necessary revisions
  remote-hg: force remote bookmark push selectively
  remote-hg: reorganize bookmark handling
  remote-hg: add test for failed double push
  ...
This commit is contained in:
Junio C Hamano 2013-06-11 13:30:24 -07:00
commit 8d3b97ae51
6 changed files with 1275 additions and 497 deletions

View File

@ -116,7 +116,10 @@ class Marks:
self.last_mark = mark self.last_mark = mark
def get_tip(self, branch): def get_tip(self, branch):
return self.tips.get(branch, None) try:
return str(self.tips[branch])
except KeyError:
return None
def set_tip(self, branch, tip): def set_tip(self, branch, tip):
self.tips[branch] = tip self.tips[branch] = tip

View File

@ -12,7 +12,7 @@
# For remote repositories a local clone is stored in # For remote repositories a local clone is stored in
# "$GIT_DIR/hg/origin/clone/.hg/". # "$GIT_DIR/hg/origin/clone/.hg/".
from mercurial import hg, ui, bookmarks, context, encoding, node, error, extensions from mercurial import hg, ui, bookmarks, context, encoding, node, error, extensions, discovery, util
import re import re
import sys import sys
@ -29,9 +29,6 @@ import urlparse, hashlib
# named branches: # named branches:
# git config --global remote-hg.track-branches false # git config --global remote-hg.track-branches false
# #
# If you don't want to force pushes (and thus risk creating new remote heads):
# git config --global remote-hg.force-push false
#
# If you want the equivalent of hg's clone/pull--insecure option: # If you want the equivalent of hg's clone/pull--insecure option:
# git config --global remote-hg.insecure true # git config --global remote-hg.insecure true
# #
@ -55,6 +52,8 @@ EMAIL_RE = re.compile('^([^<>]+[^ \\\t<>])?\\b(?:[ \\t<>]*?)\\b([^ \\t<>]+@[^ \\
AUTHOR_HG_RE = re.compile('^(.*?) ?<(.*?)(?:>(.+)?)?$') AUTHOR_HG_RE = re.compile('^(.*?) ?<(.*?)(?:>(.+)?)?$')
RAW_AUTHOR_RE = re.compile('^(\w+) (?:(.+)? )?<(.*)> (\d+) ([+-]\d+)') RAW_AUTHOR_RE = re.compile('^(\w+) (?:(.+)? )?<(.*)> (\d+) ([+-]\d+)')
VERSION = 2
def die(msg, *args): def die(msg, *args):
sys.stderr.write('ERROR: %s\n' % (msg % args)) sys.stderr.write('ERROR: %s\n' % (msg % args))
sys.exit(1) sys.exit(1)
@ -72,8 +71,11 @@ def hgmode(mode):
m = { '100755': 'x', '120000': 'l' } m = { '100755': 'x', '120000': 'l' }
return m.get(mode, '') return m.get(mode, '')
def hghex(node): def hghex(n):
return hg.node.hex(node) return node.hex(n)
def hgbin(n):
return node.bin(n)
def hgref(ref): def hgref(ref):
return ref.replace('___', ' ') return ref.replace('___', ' ')
@ -81,6 +83,11 @@ def hgref(ref):
def gitref(ref): def gitref(ref):
return ref.replace(' ', '___') return ref.replace(' ', '___')
def check_version(*check):
if not hg_version:
return True
return hg_version >= check
def get_config(config): def get_config(config):
cmd = ['git', 'config', '--get', config] cmd = ['git', 'config', '--get', config]
process = subprocess.Popen(cmd, stdout=subprocess.PIPE) process = subprocess.Popen(cmd, stdout=subprocess.PIPE)
@ -98,14 +105,27 @@ def get_config_bool(config, default=False):
class Marks: class Marks:
def __init__(self, path): def __init__(self, path, repo):
self.path = path self.path = path
self.repo = repo
self.clear()
self.load()
if self.version < VERSION:
if self.version == 1:
self.upgrade_one()
# upgraded?
if self.version < VERSION:
self.clear()
self.version = VERSION
def clear(self):
self.tips = {} self.tips = {}
self.marks = {} self.marks = {}
self.rev_marks = {} self.rev_marks = {}
self.last_mark = 0 self.last_mark = 0
self.version = 0
self.load()
def load(self): def load(self):
if not os.path.exists(self.path): if not os.path.exists(self.path):
@ -116,12 +136,21 @@ class Marks:
self.tips = tmp['tips'] self.tips = tmp['tips']
self.marks = tmp['marks'] self.marks = tmp['marks']
self.last_mark = tmp['last-mark'] self.last_mark = tmp['last-mark']
self.version = tmp.get('version', 1)
for rev, mark in self.marks.iteritems(): for rev, mark in self.marks.iteritems():
self.rev_marks[mark] = int(rev) self.rev_marks[mark] = rev
def upgrade_one(self):
def get_id(rev):
return hghex(self.repo.changelog.node(int(rev)))
self.tips = dict((name, get_id(rev)) for name, rev in self.tips.iteritems())
self.marks = dict((get_id(rev), mark) for rev, mark in self.marks.iteritems())
self.rev_marks = dict((mark, get_id(rev)) for mark, rev in self.rev_marks.iteritems())
self.version = 2
def dict(self): def dict(self):
return { 'tips': self.tips, 'marks': self.marks, 'last-mark' : self.last_mark } return { 'tips': self.tips, 'marks': self.marks, 'last-mark' : self.last_mark, 'version' : self.version }
def store(self): def store(self):
json.dump(self.dict(), open(self.path, 'w')) json.dump(self.dict(), open(self.path, 'w'))
@ -130,10 +159,10 @@ class Marks:
return str(self.dict()) return str(self.dict())
def from_rev(self, rev): def from_rev(self, rev):
return self.marks[str(rev)] return self.marks[rev]
def to_rev(self, mark): def to_rev(self, mark):
return self.rev_marks[mark] return str(self.rev_marks[mark])
def next_mark(self): def next_mark(self):
self.last_mark += 1 self.last_mark += 1
@ -141,19 +170,19 @@ class Marks:
def get_mark(self, rev): def get_mark(self, rev):
self.last_mark += 1 self.last_mark += 1
self.marks[str(rev)] = self.last_mark self.marks[rev] = self.last_mark
return self.last_mark return self.last_mark
def new_mark(self, rev, mark): def new_mark(self, rev, mark):
self.marks[str(rev)] = mark self.marks[rev] = mark
self.rev_marks[mark] = rev self.rev_marks[mark] = rev
self.last_mark = mark self.last_mark = mark
def is_marked(self, rev): def is_marked(self, rev):
return str(rev) in self.marks return rev in self.marks
def get_tip(self, branch): def get_tip(self, branch):
return self.tips.get(branch, 0) return str(self.tips[branch])
def set_tip(self, branch, tip): def set_tip(self, branch, tip):
self.tips[branch] = tip self.tips[branch] = tip
@ -261,7 +290,7 @@ def get_filechanges(repo, ctx, parent):
removed = set() removed = set()
# load earliest manifest first for caching reasons # load earliest manifest first for caching reasons
prev = repo[parent].manifest().copy() prev = parent.manifest().copy()
cur = ctx.manifest() cur = ctx.manifest()
for fn in cur: for fn in cur:
@ -329,6 +358,21 @@ def fixup_user(user):
return '%s <%s>' % (name, mail) return '%s <%s>' % (name, mail)
def updatebookmarks(repo, peer):
remotemarks = peer.listkeys('bookmarks')
localmarks = repo._bookmarks
if not remotemarks:
return
for k, v in remotemarks.iteritems():
localmarks[k] = hgbin(v)
if hasattr(localmarks, 'write'):
localmarks.write()
else:
bookmarks.write(repo)
def get_repo(url, alias): def get_repo(url, alias):
global dirname, peer global dirname, peer
@ -339,35 +383,41 @@ def get_repo(url, alias):
if get_config_bool('remote-hg.insecure'): if get_config_bool('remote-hg.insecure'):
myui.setconfig('web', 'cacerts', '') myui.setconfig('web', 'cacerts', '')
try: extensions.loadall(myui)
mod = extensions.load(myui, 'hgext.schemes', None)
mod.extsetup(myui)
except ImportError:
pass
if hg.islocal(url): if hg.islocal(url) and not os.environ.get('GIT_REMOTE_HG_TEST_REMOTE'):
repo = hg.repository(myui, url) repo = hg.repository(myui, url)
if not os.path.exists(dirname):
os.makedirs(dirname)
else: else:
shared_path = os.path.join(gitdir, 'hg')
if not os.path.exists(shared_path):
try:
hg.clone(myui, {}, url, shared_path, update=False, pull=True)
except:
die('Repository error')
if not os.path.exists(dirname):
os.makedirs(dirname)
local_path = os.path.join(dirname, 'clone') local_path = os.path.join(dirname, 'clone')
if not os.path.exists(local_path): if not os.path.exists(local_path):
try: hg.share(myui, shared_path, local_path, update=False)
peer, dstpeer = hg.clone(myui, {}, url, local_path, update=True, pull=True)
except: repo = hg.repository(myui, local_path)
die('Repository error') try:
repo = dstpeer.local() peer = hg.peer(myui, {}, url)
else: except:
repo = hg.repository(myui, local_path) die('Repository error')
try: repo.pull(peer, heads=None, force=True)
peer = hg.peer(myui, {}, url)
except: updatebookmarks(repo, peer)
die('Repository error')
repo.pull(peer, heads=None, force=True)
return repo return repo
def rev_to_mark(rev): def rev_to_mark(rev):
global marks global marks
return marks.from_rev(rev) return marks.from_rev(rev.hex())
def mark_to_rev(mark): def mark_to_rev(mark):
global marks global marks
@ -377,17 +427,24 @@ def export_ref(repo, name, kind, head):
global prefix, marks, mode global prefix, marks, mode
ename = '%s/%s' % (kind, name) ename = '%s/%s' % (kind, name)
tip = marks.get_tip(ename) try:
tip = marks.get_tip(ename)
tip = repo[tip].rev()
except:
tip = 0
revs = xrange(tip, head.rev() + 1) revs = xrange(tip, head.rev() + 1)
count = 0 total = len(revs)
revs = [rev for rev in revs if not marks.is_marked(rev)]
for rev in revs: for rev in revs:
c = repo[rev] c = repo[rev]
(manifest, user, (time, tz), files, desc, extra) = repo.changelog.read(c.node()) node = c.node()
if marks.is_marked(c.hex()):
continue
(manifest, user, (time, tz), files, desc, extra) = repo.changelog.read(node)
rev_branch = extra['branch'] rev_branch = extra['branch']
author = "%s %d %s" % (fixup_user(user), time, gittz(tz)) author = "%s %d %s" % (fixup_user(user), time, gittz(tz))
@ -397,7 +454,7 @@ def export_ref(repo, name, kind, head):
else: else:
committer = author committer = author
parents = [p for p in repo.changelog.parentrevs(rev) if p >= 0] parents = [repo[p] for p in repo.changelog.parentrevs(rev) if p >= 0]
if len(parents) == 0: if len(parents) == 0:
modified = c.manifest().keys() modified = c.manifest().keys()
@ -439,7 +496,7 @@ def export_ref(repo, name, kind, head):
modified_final = export_files(c.filectx(f) for f in modified) modified_final = export_files(c.filectx(f) for f in modified)
print "commit %s/%s" % (prefix, ename) print "commit %s/%s" % (prefix, ename)
print "mark :%d" % (marks.get_mark(rev)) print "mark :%d" % (marks.get_mark(c.hex()))
print "author %s" % (author) print "author %s" % (author)
print "committer %s" % (committer) print "committer %s" % (committer)
print "data %d" % (len(desc)) print "data %d" % (len(desc))
@ -450,22 +507,22 @@ def export_ref(repo, name, kind, head):
if len(parents) > 1: if len(parents) > 1:
print "merge :%s" % (rev_to_mark(parents[1])) print "merge :%s" % (rev_to_mark(parents[1]))
for f in modified_final:
print "M %s :%u %s" % f
for f in removed: for f in removed:
print "D %s" % (fix_file_path(f)) print "D %s" % (fix_file_path(f))
for f in modified_final:
print "M %s :%u %s" % f
print print
count += 1 progress = (rev - tip)
if (count % 100 == 0): if (progress % 100 == 0):
print "progress revision %d '%s' (%d/%d)" % (rev, name, count, len(revs)) print "progress revision %d '%s' (%d/%d)" % (rev, name, progress, total)
# make sure the ref is updated # make sure the ref is updated
print "reset %s/%s" % (prefix, ename) print "reset %s/%s" % (prefix, ename)
print "from :%u" % rev_to_mark(rev) print "from :%u" % rev_to_mark(head)
print print
marks.set_tip(ename, rev) marks.set_tip(ename, head.hex())
def export_tag(repo, tag): def export_tag(repo, tag):
export_ref(repo, tag, 'tags', repo[hgref(tag)]) export_ref(repo, tag, 'tags', repo[hgref(tag)])
@ -497,15 +554,12 @@ def do_capabilities(parser):
if os.path.exists(path): if os.path.exists(path):
print "*import-marks %s" % path print "*import-marks %s" % path
print "*export-marks %s" % path print "*export-marks %s" % path
print "option"
print print
def branch_tip(repo, branch): def branch_tip(branch):
# older versions of mercurial don't have this return branches[branch][-1]
if hasattr(repo, 'branchtip'):
return repo.branchtip(branch)
else:
return repo.branchtags()[branch]
def get_branch_tip(repo, branch): def get_branch_tip(repo, branch):
global branches global branches
@ -517,27 +571,21 @@ def get_branch_tip(repo, branch):
# verify there's only one head # verify there's only one head
if (len(heads) > 1): if (len(heads) > 1):
warn("Branch '%s' has more than one head, consider merging" % branch) warn("Branch '%s' has more than one head, consider merging" % branch)
return branch_tip(repo, hgref(branch)) return branch_tip(hgref(branch))
return heads[0] return heads[0]
def list_head(repo, cur): def list_head(repo, cur):
global g_head, bmarks global g_head, bmarks, fake_bmark
head = bookmarks.readcurrent(repo) if 'default' not in branches:
if head: # empty repo
node = repo[head] return
else:
# fake bookmark from current branch node = repo[branch_tip('default')]
head = cur head = 'master' if not 'master' in bmarks else 'default'
node = repo['.'] fake_bmark = head
if not node: bmarks[head] = node
node = repo['tip']
if not node:
return
if head == 'default':
head = 'master'
bmarks[head] = node
head = gitref(head) head = gitref(head)
print "@refs/heads/%s HEAD" % head print "@refs/heads/%s HEAD" % head
@ -551,15 +599,17 @@ def do_list(parser):
bmarks[bmark] = repo[node] bmarks[bmark] = repo[node]
cur = repo.dirstate.branch() cur = repo.dirstate.branch()
orig = peer if peer else repo
for branch, heads in orig.branchmap().iteritems():
# only open heads
heads = [h for h in heads if 'close' not in repo.changelog.read(h)[5]]
if heads:
branches[branch] = heads
list_head(repo, cur) list_head(repo, cur)
if track_branches: if track_branches:
for branch in repo.branchmap():
heads = repo.branchheads(branch)
if len(heads):
branches[branch] = heads
for branch in branches: for branch in branches:
print "? refs/heads/branches/%s" % gitref(branch) print "? refs/heads/branches/%s" % gitref(branch)
@ -582,6 +632,7 @@ def do_import(parser):
if os.path.exists(path): if os.path.exists(path):
print "feature import-marks=%s" % path print "feature import-marks=%s" % path
print "feature export-marks=%s" % path print "feature export-marks=%s" % path
print "feature force"
sys.stdout.flush() sys.stdout.flush()
tmp = encoding.encoding tmp = encoding.encoding
@ -671,6 +722,11 @@ def parse_commit(parser):
die('Unknown file command: %s' % line) die('Unknown file command: %s' % line)
files[path] = f files[path] = f
# only export the commits if we are on an internal proxy repo
if dry_run and not peer:
parsed_refs[ref] = None
return
def getfilectx(repo, memctx, f): def getfilectx(repo, memctx, f):
of = files[f] of = files[f]
if 'deleted' in of: if 'deleted' in of:
@ -692,14 +748,14 @@ def parse_commit(parser):
extra['committer'] = "%s %u %u" % committer extra['committer'] = "%s %u %u" % committer
if from_mark: if from_mark:
p1 = repo.changelog.node(mark_to_rev(from_mark)) p1 = mark_to_rev(from_mark)
else: else:
p1 = '\0' * 20 p1 = '0' * 40
if merge_mark: if merge_mark:
p2 = repo.changelog.node(mark_to_rev(merge_mark)) p2 = mark_to_rev(merge_mark)
else: else:
p2 = '\0' * 20 p2 = '0' * 40
# #
# If files changed from any of the parents, hg wants to know, but in git if # If files changed from any of the parents, hg wants to know, but in git if
@ -735,14 +791,12 @@ def parse_commit(parser):
tmp = encoding.encoding tmp = encoding.encoding
encoding.encoding = 'utf-8' encoding.encoding = 'utf-8'
node = repo.commitctx(ctx) node = hghex(repo.commitctx(ctx))
encoding.encoding = tmp encoding.encoding = tmp
rev = repo[node].rev()
parsed_refs[ref] = node parsed_refs[ref] = node
marks.new_mark(rev, commit_mark) marks.new_mark(node, commit_mark)
def parse_reset(parser): def parse_reset(parser):
global parsed_refs global parsed_refs
@ -758,8 +812,11 @@ def parse_reset(parser):
from_mark = parser.get_mark() from_mark = parser.get_mark()
parser.next() parser.next()
node = parser.repo.changelog.node(mark_to_rev(from_mark)) try:
parsed_refs[ref] = node rev = mark_to_rev(from_mark)
except KeyError:
rev = None
parsed_refs[ref] = rev
def parse_tag(parser): def parse_tag(parser):
name = parser[1] name = parser[1]
@ -775,7 +832,7 @@ def parse_tag(parser):
def write_tag(repo, tag, node, msg, author): def write_tag(repo, tag, node, msg, author):
branch = repo[node].branch() branch = repo[node].branch()
tip = branch_tip(repo, branch) tip = branch_tip(branch)
tip = repo[tip] tip = repo[tip]
def getfilectx(repo, memctx, f): def getfilectx(repo, memctx, f):
@ -784,18 +841,28 @@ def write_tag(repo, tag, node, msg, author):
data = fctx.data() data = fctx.data()
except error.ManifestLookupError: except error.ManifestLookupError:
data = "" data = ""
content = data + "%s %s\n" % (hghex(node), tag) content = data + "%s %s\n" % (node, tag)
return context.memfilectx(f, content, False, False, None) return context.memfilectx(f, content, False, False, None)
p1 = tip.hex() p1 = tip.hex()
p2 = '\0' * 20 p2 = '0' * 40
if not author: if author:
author = (None, 0, 0) user, date, tz = author
user, date, tz = author date_tz = (date, tz)
else:
cmd = ['git', 'var', 'GIT_COMMITTER_IDENT']
process = subprocess.Popen(cmd, stdout=subprocess.PIPE)
output, _ = process.communicate()
m = re.match('^.* <.*>', output)
if m:
user = m.group(0)
else:
user = repo.ui.username()
date_tz = None
ctx = context.memctx(repo, (p1, p2), msg, ctx = context.memctx(repo, (p1, p2), msg,
['.hgtags'], getfilectx, ['.hgtags'], getfilectx,
user, (date, tz), {'branch' : branch}) user, date_tz, {'branch' : branch})
tmp = encoding.encoding tmp = encoding.encoding
encoding.encoding = 'utf-8' encoding.encoding = 'utf-8'
@ -804,12 +871,132 @@ def write_tag(repo, tag, node, msg, author):
encoding.encoding = tmp encoding.encoding = tmp
return tagnode return (tagnode, branch)
def checkheads_bmark(repo, ref, ctx):
bmark = ref[len('refs/heads/'):]
if not bmark in bmarks:
# new bmark
return True
ctx_old = bmarks[bmark]
ctx_new = ctx
if not repo.changelog.descendant(ctx_old.rev(), ctx_new.rev()):
if force_push:
print "ok %s forced update" % ref
else:
print "error %s non-fast forward" % ref
return False
return True
def checkheads(repo, remote, p_revs):
remotemap = remote.branchmap()
if not remotemap:
# empty repo
return True
new = {}
ret = True
for node, ref in p_revs.iteritems():
ctx = repo[node]
branch = ctx.branch()
if not branch in remotemap:
# new branch
continue
if not ref.startswith('refs/heads/branches'):
if ref.startswith('refs/heads/'):
if not checkheads_bmark(repo, ref, ctx):
ret = False
# only check branches
continue
new.setdefault(branch, []).append(ctx.rev())
for branch, heads in new.iteritems():
old = [repo.changelog.rev(x) for x in remotemap[branch]]
for rev in heads:
if check_version(2, 3):
ancestors = repo.changelog.ancestors([rev], stoprev=min(old))
else:
ancestors = repo.changelog.ancestors(rev)
found = False
for x in old:
if x in ancestors:
found = True
break
if found:
continue
node = repo.changelog.node(rev)
ref = p_revs[node]
if force_push:
print "ok %s forced update" % ref
else:
print "error %s non-fast forward" % ref
ret = False
return ret
def push_unsafe(repo, remote, parsed_refs, p_revs):
force = force_push
fci = discovery.findcommonincoming
commoninc = fci(repo, remote, force=force)
common, _, remoteheads = commoninc
if not checkheads(repo, remote, p_revs):
return None
cg = repo.getbundle('push', heads=list(p_revs), common=common)
unbundle = remote.capable('unbundle')
if unbundle:
if force:
remoteheads = ['force']
return remote.unbundle(cg, remoteheads, 'push')
else:
return remote.addchangegroup(cg, 'push', repo.url())
def push(repo, remote, parsed_refs, p_revs):
if hasattr(remote, 'canpush') and not remote.canpush():
print "error cannot push"
if not p_revs:
# nothing to push
return
lock = None
unbundle = remote.capable('unbundle')
if not unbundle:
lock = remote.lock()
try:
ret = push_unsafe(repo, remote, parsed_refs, p_revs)
finally:
if lock is not None:
lock.release()
return ret
def check_tip(ref, kind, name, heads):
try:
ename = '%s/%s' % (kind, name)
tip = marks.get_tip(ename)
except KeyError:
return True
else:
return tip in heads
def do_export(parser): def do_export(parser):
global parsed_refs, bmarks, peer global parsed_refs, bmarks, peer
p_bmarks = [] p_bmarks = []
p_revs = {}
parser.next() parser.next()
@ -827,72 +1014,114 @@ def do_export(parser):
else: else:
die('unhandled export command: %s' % line) die('unhandled export command: %s' % line)
need_fetch = False
for ref, node in parsed_refs.iteritems(): for ref, node in parsed_refs.iteritems():
bnode = hgbin(node) if node else None
if ref.startswith('refs/heads/branches'): if ref.startswith('refs/heads/branches'):
branch = ref[len('refs/heads/branches/'):] branch = ref[len('refs/heads/branches/'):]
if branch in branches and node in branches[branch]: if branch in branches and bnode in branches[branch]:
# up to date # up to date
continue continue
if peer:
remotemap = peer.branchmap()
if remotemap and branch in remotemap:
heads = [hghex(e) for e in remotemap[branch]]
if not check_tip(ref, 'branches', branch, heads):
print "error %s fetch first" % ref
need_fetch = True
continue
p_revs[bnode] = ref
print "ok %s" % ref print "ok %s" % ref
elif ref.startswith('refs/heads/'): elif ref.startswith('refs/heads/'):
bmark = ref[len('refs/heads/'):] bmark = ref[len('refs/heads/'):]
p_bmarks.append((bmark, node)) new = node
continue old = bmarks[bmark].hex() if bmark in bmarks else ''
if old == new:
continue
print "ok %s" % ref
if bmark != fake_bmark and \
not (bmark == 'master' and bmark not in parser.repo._bookmarks):
p_bmarks.append((ref, bmark, old, new))
if peer:
remote_old = peer.listkeys('bookmarks').get(bmark)
if remote_old:
if not check_tip(ref, 'bookmarks', bmark, remote_old):
print "error %s fetch first" % ref
need_fetch = True
continue
p_revs[bnode] = ref
elif ref.startswith('refs/tags/'): elif ref.startswith('refs/tags/'):
if dry_run:
print "ok %s" % ref
continue
tag = ref[len('refs/tags/'):] tag = ref[len('refs/tags/'):]
tag = hgref(tag) tag = hgref(tag)
author, msg = parsed_tags.get(tag, (None, None)) author, msg = parsed_tags.get(tag, (None, None))
if mode == 'git': if mode == 'git':
if not msg: if not msg:
msg = 'Added tag %s for changeset %s' % (tag, hghex(node[:6])); msg = 'Added tag %s for changeset %s' % (tag, node[:12]);
write_tag(parser.repo, tag, node, msg, author) tagnode, branch = write_tag(parser.repo, tag, node, msg, author)
p_revs[tagnode] = 'refs/heads/branches/' + gitref(branch)
else: else:
fp = parser.repo.opener('localtags', 'a') fp = parser.repo.opener('localtags', 'a')
fp.write('%s %s\n' % (hghex(node), tag)) fp.write('%s %s\n' % (node, tag))
fp.close() fp.close()
p_revs[bnode] = ref
print "ok %s" % ref print "ok %s" % ref
else: else:
# transport-helper/fast-export bugs # transport-helper/fast-export bugs
continue continue
if need_fetch:
print
return
if dry_run:
if peer and not force_push:
checkheads(parser.repo, peer, p_revs)
print
return
if peer: if peer:
parser.repo.push(peer, force=force_push, newbranch=True) if not push(parser.repo, peer, parsed_refs, p_revs):
# do not update bookmarks
print
return
# handle bookmarks # update remote bookmarks
for bmark, node in p_bmarks: remote_bmarks = peer.listkeys('bookmarks')
ref = 'refs/heads/' + bmark for ref, bmark, old, new in p_bmarks:
new = hghex(node) if force_push:
old = remote_bmarks.get(bmark, '')
if bmark in bmarks:
old = bmarks[bmark].hex()
else:
old = ''
if old == new:
continue
if bmark == 'master' and 'master' not in parser.repo._bookmarks:
# fake bookmark
print "ok %s" % ref
continue
elif bookmarks.pushbookmark(parser.repo, bmark, old, new):
# updated locally
pass
else:
print "error %s" % ref
continue
if peer:
rb = peer.listkeys('bookmarks')
old = rb.get(bmark, '')
if not peer.pushkey('bookmarks', bmark, old, new): if not peer.pushkey('bookmarks', bmark, old, new):
print "error %s" % ref print "error %s" % ref
continue else:
# update local bookmarks
print "ok %s" % ref for ref, bmark, old, new in p_bmarks:
if not bookmarks.pushbookmark(parser.repo, bmark, old, new):
print "error %s" % ref
print print
def do_option(parser):
global dry_run, force_push
_, key, value = parser.line.split(' ')
if key == 'dry-run':
dry_run = (value == 'true')
print 'ok'
elif key == 'force':
force_push = (value == 'true')
print 'ok'
else:
print 'unsupported'
def fix_path(alias, repo, orig_url): def fix_path(alias, repo, orig_url):
url = urlparse.urlparse(orig_url, 'file') url = urlparse.urlparse(orig_url, 'file')
if url.scheme != 'file' or os.path.isabs(url.path): if url.scheme != 'file' or os.path.isabs(url.path):
@ -902,12 +1131,14 @@ def fix_path(alias, repo, orig_url):
subprocess.call(cmd) subprocess.call(cmd)
def main(args): def main(args):
global prefix, dirname, branches, bmarks global prefix, gitdir, dirname, branches, bmarks
global marks, blob_marks, parsed_refs global marks, blob_marks, parsed_refs
global peer, mode, bad_mail, bad_name global peer, mode, bad_mail, bad_name
global track_branches, force_push, is_tmp global track_branches, force_push, is_tmp
global parsed_tags global parsed_tags
global filenodes global filenodes
global fake_bmark, hg_version
global dry_run
alias = args[1] alias = args[1]
url = args[2] url = args[2]
@ -915,7 +1146,7 @@ def main(args):
hg_git_compat = get_config_bool('remote-hg.hg-git-compat') hg_git_compat = get_config_bool('remote-hg.hg-git-compat')
track_branches = get_config_bool('remote-hg.track-branches', True) track_branches = get_config_bool('remote-hg.track-branches', True)
force_push = get_config_bool('remote-hg.force-push') force_push = False
if hg_git_compat: if hg_git_compat:
mode = 'hg' mode = 'hg'
@ -941,6 +1172,12 @@ def main(args):
marks = None marks = None
parsed_tags = {} parsed_tags = {}
filenodes = {} filenodes = {}
fake_bmark = None
try:
hg_version = tuple(int(e) for e in util.version().split('.'))
except:
hg_version = None
dry_run = False
repo = get_repo(url, alias) repo = get_repo(url, alias)
prefix = 'refs/hg/%s' % alias prefix = 'refs/hg/%s' % alias
@ -948,11 +1185,8 @@ def main(args):
if not is_tmp: if not is_tmp:
fix_path(alias, peer or repo, url) fix_path(alias, peer or repo, url)
if not os.path.exists(dirname):
os.makedirs(dirname)
marks_path = os.path.join(dirname, 'marks-hg') marks_path = os.path.join(dirname, 'marks-hg')
marks = Marks(marks_path) marks = Marks(marks_path, repo)
if sys.platform == 'win32': if sys.platform == 'win32':
import msvcrt import msvcrt
@ -968,6 +1202,8 @@ def main(args):
do_import(parser) do_import(parser)
elif parser.check('export'): elif parser.check('export'):
do_export(parser) do_export(parser)
elif parser.check('option'):
do_option(parser)
else: else:
die('unhandled command: %s' % line) die('unhandled command: %s' % line)
sys.stdout.flush() sys.stdout.flush()

View File

@ -12,86 +12,90 @@ if ! test_have_prereq PYTHON; then
test_done test_done
fi fi
if ! "$PYTHON_PATH" -c 'import bzrlib'; then if ! python -c 'import bzrlib'; then
skip_all='skipping remote-bzr tests; bzr not available' skip_all='skipping remote-bzr tests; bzr not available'
test_done test_done
fi fi
check () { check () {
(cd $1 && echo $3 > expected &&
git log --format='%s' -1 && git --git-dir=$1/.git log --format='%s' -1 $2 > actual
git symbolic-ref HEAD) > actual &&
(echo $2 &&
echo "refs/heads/$3") > expected &&
test_cmp expected actual test_cmp expected actual
} }
bzr whoami "A U Thor <author@example.com>" bzr whoami "A U Thor <author@example.com>"
test_expect_success 'cloning' ' test_expect_success 'cloning' '
(bzr init bzrrepo && (
cd bzrrepo && bzr init bzrrepo &&
echo one > content && cd bzrrepo &&
bzr add content && echo one > content &&
bzr commit -m one bzr add content &&
) && bzr commit -m one
) &&
git clone "bzr::$PWD/bzrrepo" gitrepo && git clone "bzr::bzrrepo" gitrepo &&
check gitrepo one master check gitrepo HEAD one
' '
test_expect_success 'pulling' ' test_expect_success 'pulling' '
(cd bzrrepo && (
echo two > content && cd bzrrepo &&
bzr commit -m two echo two > content &&
) && bzr commit -m two
) &&
(cd gitrepo && git pull) && (cd gitrepo && git pull) &&
check gitrepo two master check gitrepo HEAD two
' '
test_expect_success 'pushing' ' test_expect_success 'pushing' '
(cd gitrepo && (
echo three > content && cd gitrepo &&
git commit -a -m three && echo three > content &&
git push git commit -a -m three &&
) && git push
) &&
echo three > expected && echo three > expected &&
cat bzrrepo/content > actual && cat bzrrepo/content > actual &&
test_cmp expected actual test_cmp expected actual
' '
test_expect_success 'roundtrip' ' test_expect_success 'roundtrip' '
(cd gitrepo && (
git pull && cd gitrepo &&
git log --format="%s" -1 origin/master > actual) && git pull &&
echo three > expected && git log --format="%s" -1 origin/master > actual
test_cmp expected actual && ) &&
echo three > expected &&
test_cmp expected actual &&
(cd gitrepo && git push && git pull) && (cd gitrepo && git push && git pull) &&
(cd bzrrepo && (
echo four > content && cd bzrrepo &&
bzr commit -m four echo four > content &&
) && bzr commit -m four
) &&
(cd gitrepo && git pull && git push) && (cd gitrepo && git pull && git push) &&
check gitrepo four master && check gitrepo HEAD four &&
(cd gitrepo && (
echo five > content && cd gitrepo &&
git commit -a -m five && echo five > content &&
git push && git pull git commit -a -m five &&
) && git push && git pull
) &&
(cd bzrrepo && bzr revert) && (cd bzrrepo && bzr revert) &&
echo five > expected && echo five > expected &&
cat bzrrepo/content > actual && cat bzrrepo/content > actual &&
test_cmp expected actual test_cmp expected actual
' '
cat > expected <<EOF cat > expected <<EOF
@ -101,29 +105,35 @@ cat > expected <<EOF
EOF EOF
test_expect_success 'special modes' ' test_expect_success 'special modes' '
(cd bzrrepo && (
echo exec > executable cd bzrrepo &&
chmod +x executable && echo exec > executable
bzr add executable chmod +x executable &&
bzr commit -m exec && bzr add executable
ln -s content link bzr commit -m exec &&
bzr add link ln -s content link
bzr commit -m link && bzr add link
mkdir dir && bzr commit -m link &&
bzr add dir && mkdir dir &&
bzr commit -m dir) && bzr add dir &&
bzr commit -m dir
) &&
(cd gitrepo && (
git pull cd gitrepo &&
git ls-tree HEAD > ../actual) && git pull
git ls-tree HEAD > ../actual
) &&
test_cmp expected actual && test_cmp expected actual &&
(cd gitrepo && (
git cat-file -p HEAD:link > ../actual) && cd gitrepo &&
git cat-file -p HEAD:link > ../actual
) &&
printf content > expected && printf content > expected &&
test_cmp expected actual test_cmp expected actual
' '
cat > expected <<EOF cat > expected <<EOF
@ -134,134 +144,145 @@ cat > expected <<EOF
EOF EOF
test_expect_success 'moving directory' ' test_expect_success 'moving directory' '
(cd bzrrepo && (
mkdir movedir && cd bzrrepo &&
echo one > movedir/one && mkdir movedir &&
echo two > movedir/two && echo one > movedir/one &&
bzr add movedir && echo two > movedir/two &&
bzr commit -m movedir && bzr add movedir &&
bzr mv movedir movedir-new && bzr commit -m movedir &&
bzr commit -m movedir-new) && bzr mv movedir movedir-new &&
bzr commit -m movedir-new
) &&
(cd gitrepo && (
git pull && cd gitrepo &&
git ls-tree HEAD > ../actual) && git pull &&
git ls-tree HEAD > ../actual
) &&
test_cmp expected actual test_cmp expected actual
' '
test_expect_success 'different authors' ' test_expect_success 'different authors' '
(cd bzrrepo && (
echo john >> content && cd bzrrepo &&
bzr commit -m john \ echo john >> content &&
--author "Jane Rey <jrey@example.com>" \ bzr commit -m john \
--author "John Doe <jdoe@example.com>") && --author "Jane Rey <jrey@example.com>" \
--author "John Doe <jdoe@example.com>"
) &&
(cd gitrepo && (
git pull && cd gitrepo &&
git show --format="%an <%ae>, %cn <%ce>" --quiet > ../actual) && git pull &&
git show --format="%an <%ae>, %cn <%ce>" --quiet > ../actual
) &&
echo "Jane Rey <jrey@example.com>, A U Thor <author@example.com>" > expected && echo "Jane Rey <jrey@example.com>, A U Thor <author@example.com>" > expected &&
test_cmp expected actual test_cmp expected actual
' '
# cleanup previous stuff
rm -rf bzrrepo gitrepo
test_expect_success 'fetch utf-8 filenames' ' test_expect_success 'fetch utf-8 filenames' '
mkdir -p tmp && cd tmp && test_when_finished "rm -rf bzrrepo gitrepo && LC_ALL=C" &&
test_when_finished "cd .. && rm -rf tmp && LC_ALL=C" &&
LC_ALL=en_US.UTF-8 LC_ALL=en_US.UTF-8
export LC_ALL export LC_ALL
(
bzr init bzrrepo &&
cd bzrrepo &&
echo test >> "ærø" && (
bzr add "ærø" && bzr init bzrrepo &&
echo test >> "ø~?" && cd bzrrepo &&
bzr add "ø~?" &&
bzr commit -m add-utf-8 &&
echo test >> "ærø" &&
bzr commit -m test-utf-8 &&
bzr rm "ø~?" &&
bzr mv "ærø" "ø~?" &&
bzr commit -m bzr-mv-utf-8
) &&
( echo test >> "ærø" &&
git clone "bzr::$PWD/bzrrepo" gitrepo && bzr add "ærø" &&
cd gitrepo && echo test >> "ø~?" &&
git -c core.quotepath=false ls-files > ../actual bzr add "ø~?" &&
) && bzr commit -m add-utf-8 &&
echo "ø~?" > expected && echo test >> "ærø" &&
test_cmp expected actual bzr commit -m test-utf-8 &&
bzr rm "ø~?" &&
bzr mv "ærø" "ø~?" &&
bzr commit -m bzr-mv-utf-8
) &&
(
git clone "bzr::bzrrepo" gitrepo &&
cd gitrepo &&
git -c core.quotepath=false ls-files > ../actual
) &&
echo "ø~?" > expected &&
test_cmp expected actual
' '
test_expect_success 'push utf-8 filenames' ' test_expect_success 'push utf-8 filenames' '
mkdir -p tmp && cd tmp && test_when_finished "rm -rf bzrrepo gitrepo && LC_ALL=C" &&
test_when_finished "cd .. && rm -rf tmp && LC_ALL=C" &&
LC_ALL=en_US.UTF-8 mkdir -p tmp && cd tmp &&
export LC_ALL
( LC_ALL=en_US.UTF-8
bzr init bzrrepo && export LC_ALL
cd bzrrepo &&
echo one >> content && (
bzr add content && bzr init bzrrepo &&
bzr commit -m one cd bzrrepo &&
) &&
( echo one >> content &&
git clone "bzr::$PWD/bzrrepo" gitrepo && bzr add content &&
cd gitrepo && bzr commit -m one
) &&
echo test >> "ærø" && (
git add "ærø" && git clone "bzr::bzrrepo" gitrepo &&
git commit -m utf-8 && cd gitrepo &&
git push echo test >> "ærø" &&
) && git add "ærø" &&
git commit -m utf-8 &&
(cd bzrrepo && bzr ls > ../actual) && git push
printf "content\nærø\n" > expected && ) &&
test_cmp expected actual
(cd bzrrepo && bzr ls > ../actual) &&
printf "content\nærø\n" > expected &&
test_cmp expected actual
' '
test_expect_success 'pushing a merge' ' test_expect_success 'pushing a merge' '
mkdir -p tmp && cd tmp && test_when_finished "rm -rf bzrrepo gitrepo" &&
test_when_finished "cd .. && rm -rf tmp" &&
( (
bzr init bzrrepo && bzr init bzrrepo &&
cd bzrrepo && cd bzrrepo &&
echo one > content && echo one > content &&
bzr add content && bzr add content &&
bzr commit -m one bzr commit -m one
) && ) &&
git clone "bzr::$PWD/bzrrepo" gitrepo && git clone "bzr::bzrrepo" gitrepo &&
( (
cd bzrrepo && cd bzrrepo &&
echo two > content && echo two > content &&
bzr commit -m two bzr commit -m two
) && ) &&
( (
cd gitrepo && cd gitrepo &&
echo three > content && echo three > content &&
git commit -a -m three && git commit -a -m three &&
git fetch && git fetch &&
git merge origin/master || true && git merge origin/master || true &&
echo three > content && echo three > content &&
git commit -a --no-edit && git commit -a --no-edit &&
git push git push
) && ) &&
echo three > expected && echo three > expected &&
cat bzrrepo/content > actual && cat bzrrepo/content > actual &&
test_cmp expected actual test_cmp expected actual
' '
cat > expected <<EOF cat > expected <<EOF
@ -271,71 +292,70 @@ origin/trunk
EOF EOF
test_expect_success 'proper bzr repo' ' test_expect_success 'proper bzr repo' '
mkdir -p tmp && cd tmp && test_when_finished "rm -rf bzrrepo gitrepo" &&
test_when_finished "cd .. && rm -rf tmp" &&
bzr init-repo bzrrepo && bzr init-repo bzrrepo &&
bzr init bzrrepo/trunk && (
( bzr init bzrrepo/trunk &&
cd bzrrepo/trunk && cd bzrrepo/trunk &&
echo one >> content && echo one >> content &&
bzr add content && bzr add content &&
bzr commit -m one bzr commit -m one
) && ) &&
bzr branch bzrrepo/trunk bzrrepo/branch && (
( bzr branch bzrrepo/trunk bzrrepo/branch &&
cd bzrrepo/branch && cd bzrrepo/branch &&
echo two >> content && echo two >> content &&
bzr commit -m one bzr commit -m one
) && ) &&
git clone "bzr::$PWD/bzrrepo" gitrepo && (
( git clone "bzr::bzrrepo" gitrepo &&
cd gitrepo && cd gitrepo &&
git for-each-ref --format "%(refname:short)" refs/remotes/origin > ../actual git for-each-ref --format "%(refname:short)" refs/remotes/origin > ../actual
) && ) &&
test_cmp ../expected actual test_cmp expected actual
' '
test_expect_success 'strip' ' test_expect_success 'strip' '
# Do not imitate this style; always chdir inside a subshell instead test_when_finished "rm -rf bzrrepo gitrepo" &&
mkdir -p tmp && cd tmp &&
test_when_finished "cd .. && rm -rf tmp" &&
( (
bzr init bzrrepo && bzr init bzrrepo &&
cd bzrrepo && cd bzrrepo &&
echo one >> content && echo one >> content &&
bzr add content && bzr add content &&
bzr commit -m one && bzr commit -m one &&
echo two >> content && echo two >> content &&
bzr commit -m two bzr commit -m two
) && ) &&
git clone "bzr::$PWD/bzrrepo" gitrepo && git clone "bzr::bzrrepo" gitrepo &&
( (
cd bzrrepo && cd bzrrepo &&
bzr uncommit --force && bzr uncommit --force &&
echo three >> content && echo three >> content &&
bzr commit -m three && bzr commit -m three &&
echo four >> content && echo four >> content &&
bzr commit -m four && bzr commit -m four &&
bzr log --line | sed -e "s/^[0-9][0-9]*: //" > ../expected bzr log --line | sed -e "s/^[0-9][0-9]*: //" > ../expected
) && ) &&
(cd gitrepo && (
git fetch && cd gitrepo &&
git log --format="%an %ad %s" --date=short origin/master > ../actual) && git fetch &&
git log --format="%an %ad %s" --date=short origin/master > ../actual
) &&
test_cmp expected actual test_cmp expected actual
' '
test_done test_done

View File

@ -15,23 +15,22 @@ if ! test_have_prereq PYTHON; then
test_done test_done
fi fi
if ! "$PYTHON_PATH" -c 'import mercurial'; then if ! python -c 'import mercurial'; then
skip_all='skipping remote-hg tests; mercurial not available' skip_all='skipping remote-hg tests; mercurial not available'
test_done test_done
fi fi
# clone to a git repo # clone to a git repo
git_clone () { git_clone () {
git clone -q "hg::$PWD/$1" $2 git clone -q "hg::$1" $2
} }
# clone to an hg repo # clone to an hg repo
hg_clone () { hg_clone () {
( (
hg init $2 && hg init $2 &&
hg -R $2 bookmark -i master &&
cd $1 && cd $1 &&
git push -q "hg::$PWD/../$2" 'refs/tags/*:refs/tags/*' 'refs/heads/*:refs/heads/*' git push -q "hg::../$2" 'refs/tags/*:refs/tags/*' 'refs/heads/*:refs/heads/*'
) && ) &&
(cd $2 && hg -q update) (cd $2 && hg -q update)
@ -41,17 +40,15 @@ hg_clone () {
hg_push () { hg_push () {
( (
cd $2 cd $2
old=$(git symbolic-ref --short HEAD)
git checkout -q -b tmp && git checkout -q -b tmp &&
git fetch -q "hg::$PWD/../$1" 'refs/tags/*:refs/tags/*' 'refs/heads/*:refs/heads/*' && git fetch -q "hg::../$1" 'refs/tags/*:refs/tags/*' 'refs/heads/*:refs/heads/*' &&
git checkout -q $old && git checkout -q @{-1} &&
git branch -q -D tmp 2> /dev/null || true git branch -q -D tmp 2> /dev/null || true
) )
} }
hg_log () { hg_log () {
hg -R $1 log --graph --debug >log && hg -R $1 log --graph --debug
grep -v 'tag: *default/' log
} }
setup () { setup () {
@ -67,6 +64,7 @@ setup () {
echo "graphlog =" echo "graphlog ="
) >> "$HOME"/.hgrc && ) >> "$HOME"/.hgrc &&
git config --global remote-hg.hg-git-compat true git config --global remote-hg.hg-git-compat true
git config --global remote-hg.track-branches true
HGEDITOR=/usr/bin/true HGEDITOR=/usr/bin/true
GIT_AUTHOR_DATE="2007-01-01 00:00:00 +0230" GIT_AUTHOR_DATE="2007-01-01 00:00:00 +0230"
@ -77,8 +75,7 @@ setup () {
setup setup
test_expect_success 'encoding' ' test_expect_success 'encoding' '
mkdir -p tmp && cd tmp && test_when_finished "rm -rf gitrepo* hgrepo*" &&
test_when_finished "cd .. && rm -rf tmp" &&
( (
git init -q gitrepo && git init -q gitrepo &&
@ -115,8 +112,7 @@ test_expect_success 'encoding' '
' '
test_expect_success 'file removal' ' test_expect_success 'file removal' '
mkdir -p tmp && cd tmp && test_when_finished "rm -rf gitrepo* hgrepo*" &&
test_when_finished "cd .. && rm -rf tmp" &&
( (
git init -q gitrepo && git init -q gitrepo &&
@ -148,8 +144,7 @@ test_expect_success 'file removal' '
' '
test_expect_success 'git tags' ' test_expect_success 'git tags' '
mkdir -p tmp && cd tmp && test_when_finished "rm -rf gitrepo* hgrepo*" &&
test_when_finished "cd .. && rm -rf tmp" &&
( (
git init -q gitrepo && git init -q gitrepo &&
@ -177,8 +172,7 @@ test_expect_success 'git tags' '
' '
test_expect_success 'hg branch' ' test_expect_success 'hg branch' '
mkdir -p tmp && cd tmp && test_when_finished "rm -rf gitrepo* hgrepo*" &&
test_when_finished "cd .. && rm -rf tmp" &&
( (
git init -q gitrepo && git init -q gitrepo &&
@ -194,7 +188,7 @@ test_expect_success 'hg branch' '
hg_clone gitrepo hgrepo && hg_clone gitrepo hgrepo &&
cd hgrepo && cd hgrepo &&
hg -q co master && hg -q co default &&
hg mv alpha beta && hg mv alpha beta &&
hg -q commit -m "rename alpha to beta" && hg -q commit -m "rename alpha to beta" &&
hg branch gamma | grep -v "permanent and global" && hg branch gamma | grep -v "permanent and global" &&
@ -214,8 +208,7 @@ test_expect_success 'hg branch' '
' '
test_expect_success 'hg tags' ' test_expect_success 'hg tags' '
mkdir -p tmp && cd tmp && test_when_finished "rm -rf gitrepo* hgrepo*" &&
test_when_finished "cd .. && rm -rf tmp" &&
( (
git init -q gitrepo && git init -q gitrepo &&
@ -231,7 +224,7 @@ test_expect_success 'hg tags' '
hg_clone gitrepo hgrepo && hg_clone gitrepo hgrepo &&
cd hgrepo && cd hgrepo &&
hg co master && hg co default &&
hg tag alpha hg tag alpha
) && ) &&

View File

@ -15,19 +15,20 @@ if ! test_have_prereq PYTHON; then
test_done test_done
fi fi
if ! "$PYTHON_PATH" -c 'import mercurial'; then if ! python -c 'import mercurial'; then
skip_all='skipping remote-hg tests; mercurial not available' skip_all='skipping remote-hg tests; mercurial not available'
test_done test_done
fi fi
if ! "$PYTHON_PATH" -c 'import hggit'; then if ! python -c 'import hggit'; then
skip_all='skipping remote-hg tests; hg-git not available' skip_all='skipping remote-hg tests; hg-git not available'
test_done test_done
fi fi
# clone to a git repo with git # clone to a git repo with git
git_clone_git () { git_clone_git () {
git clone -q "hg::$PWD/$1" $2 git clone -q "hg::$1" $2 &&
(cd $2 && git checkout master && git branch -D default)
} }
# clone to an hg repo with git # clone to an hg repo with git
@ -36,7 +37,7 @@ hg_clone_git () {
hg init $2 && hg init $2 &&
hg -R $2 bookmark -i master && hg -R $2 bookmark -i master &&
cd $1 && cd $1 &&
git push -q "hg::$PWD/../$2" 'refs/tags/*:refs/tags/*' 'refs/heads/*:refs/heads/*' git push -q "hg::../$2" 'refs/tags/*:refs/tags/*' 'refs/heads/*:refs/heads/*'
) && ) &&
(cd $2 && hg -q update) (cd $2 && hg -q update)
@ -61,10 +62,10 @@ hg_clone_hg () {
hg_push_git () { hg_push_git () {
( (
cd $2 cd $2
old=$(git symbolic-ref --short HEAD)
git checkout -q -b tmp && git checkout -q -b tmp &&
git fetch -q "hg::$PWD/../$1" 'refs/tags/*:refs/tags/*' 'refs/heads/*:refs/heads/*' && git fetch -q "hg::../$1" 'refs/tags/*:refs/tags/*' 'refs/heads/*:refs/heads/*' &&
git checkout -q $old && git branch -D default &&
git checkout -q @{-1} &&
git branch -q -D tmp 2> /dev/null || true git branch -q -D tmp 2> /dev/null || true
) )
} }
@ -104,18 +105,18 @@ setup () {
git config --global remote-hg.hg-git-compat true git config --global remote-hg.hg-git-compat true
git config --global remote-hg.track-branches false git config --global remote-hg.track-branches false
HGEDITOR=/usr/bin/true HGEDITOR=true
HGMERGE=true
GIT_AUTHOR_DATE="2007-01-01 00:00:00 +0230" GIT_AUTHOR_DATE="2007-01-01 00:00:00 +0230"
GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE" GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE"
export HGEDITOR GIT_AUTHOR_DATE GIT_COMMITTER_DATE export HGEDITOR HGMERGE GIT_AUTHOR_DATE GIT_COMMITTER_DATE
} }
setup setup
test_expect_success 'executable bit' ' test_expect_success 'executable bit' '
mkdir -p tmp && cd tmp && test_when_finished "rm -rf gitrepo* hgrepo*" &&
test_when_finished "cd .. && rm -rf tmp" &&
( (
git init -q gitrepo && git init -q gitrepo &&
@ -150,8 +151,7 @@ test_expect_success 'executable bit' '
' '
test_expect_success 'symlink' ' test_expect_success 'symlink' '
mkdir -p tmp && cd tmp && test_when_finished "rm -rf gitrepo* hgrepo*" &&
test_when_finished "cd .. && rm -rf tmp" &&
( (
git init -q gitrepo && git init -q gitrepo &&
@ -181,8 +181,7 @@ test_expect_success 'symlink' '
' '
test_expect_success 'merge conflict 1' ' test_expect_success 'merge conflict 1' '
mkdir -p tmp && cd tmp && test_when_finished "rm -rf gitrepo* hgrepo*" &&
test_when_finished "cd .. && rm -rf tmp" &&
( (
hg init hgrepo1 && hg init hgrepo1 &&
@ -198,7 +197,7 @@ test_expect_success 'merge conflict 1' '
echo C > afile && echo C > afile &&
hg ci -m "A->C" && hg ci -m "A->C" &&
hg merge -r1 || true && hg merge -r1 &&
echo C > afile && echo C > afile &&
hg resolve -m afile && hg resolve -m afile &&
hg ci -m "merge to C" hg ci -m "merge to C"
@ -216,8 +215,7 @@ test_expect_success 'merge conflict 1' '
' '
test_expect_success 'merge conflict 2' ' test_expect_success 'merge conflict 2' '
mkdir -p tmp && cd tmp && test_when_finished "rm -rf gitrepo* hgrepo*" &&
test_when_finished "cd .. && rm -rf tmp" &&
( (
hg init hgrepo1 && hg init hgrepo1 &&
@ -251,8 +249,7 @@ test_expect_success 'merge conflict 2' '
' '
test_expect_success 'converged merge' ' test_expect_success 'converged merge' '
mkdir -p tmp && cd tmp && test_when_finished "rm -rf gitrepo* hgrepo*" &&
test_when_finished "cd .. && rm -rf tmp" &&
( (
hg init hgrepo1 && hg init hgrepo1 &&
@ -287,8 +284,7 @@ test_expect_success 'converged merge' '
' '
test_expect_success 'encoding' ' test_expect_success 'encoding' '
mkdir -p tmp && cd tmp && test_when_finished "rm -rf gitrepo* hgrepo*" &&
test_when_finished "cd .. && rm -rf tmp" &&
( (
git init -q gitrepo && git init -q gitrepo &&
@ -327,8 +323,7 @@ test_expect_success 'encoding' '
' '
test_expect_success 'file removal' ' test_expect_success 'file removal' '
mkdir -p tmp && cd tmp && test_when_finished "rm -rf gitrepo* hgrepo*" &&
test_when_finished "cd .. && rm -rf tmp" &&
( (
git init -q gitrepo && git init -q gitrepo &&
@ -367,8 +362,7 @@ test_expect_success 'file removal' '
' '
test_expect_success 'git tags' ' test_expect_success 'git tags' '
mkdir -p tmp && cd tmp && test_when_finished "rm -rf gitrepo* hgrepo*" &&
test_when_finished "cd .. && rm -rf tmp" &&
( (
git init -q gitrepo && git init -q gitrepo &&
@ -394,8 +388,7 @@ test_expect_success 'git tags' '
' '
test_expect_success 'hg author' ' test_expect_success 'hg author' '
mkdir -p tmp && cd tmp && test_when_finished "rm -rf gitrepo* hgrepo*" &&
test_when_finished "cd .. && rm -rf tmp" &&
for x in hg git; do for x in hg git; do
( (
@ -461,8 +454,7 @@ test_expect_success 'hg author' '
' '
test_expect_success 'hg branch' ' test_expect_success 'hg branch' '
mkdir -p tmp && cd tmp && test_when_finished "rm -rf gitrepo* hgrepo*" &&
test_when_finished "cd .. && rm -rf tmp" &&
for x in hg git; do for x in hg git; do
( (
@ -498,8 +490,7 @@ test_expect_success 'hg branch' '
' '
test_expect_success 'hg tags' ' test_expect_success 'hg tags' '
mkdir -p tmp && cd tmp && test_when_finished "rm -rf gitrepo* hgrepo*" &&
test_when_finished "cd .. && rm -rf tmp" &&
for x in hg git; do for x in hg git; do
( (

View File

@ -15,143 +15,678 @@ if ! test_have_prereq PYTHON; then
test_done test_done
fi fi
if ! "$PYTHON_PATH" -c 'import mercurial'; then if ! python -c 'import mercurial'; then
skip_all='skipping remote-hg tests; mercurial not available' skip_all='skipping remote-hg tests; mercurial not available'
test_done test_done
fi fi
check () { check () {
(cd $1 && echo $3 > expected &&
git log --format='%s' -1 && git --git-dir=$1/.git log --format='%s' -1 $2 > actual
git symbolic-ref HEAD) > actual &&
(echo $2 &&
echo "refs/heads/$3") > expected &&
test_cmp expected actual test_cmp expected actual
} }
check_branch () {
if [ -n "$3" ]; then
echo $3 > expected &&
hg -R $1 log -r $2 --template '{desc}\n' > actual &&
test_cmp expected actual
else
hg -R $1 branches > out &&
! grep $2 out
fi
}
check_bookmark () {
if [ -n "$3" ]; then
echo $3 > expected &&
hg -R $1 log -r "bookmark('$2')" --template '{desc}\n' > actual &&
test_cmp expected actual
else
hg -R $1 bookmarks > out &&
! grep $2 out
fi
}
check_push () {
local expected_ret=$1 ret=0 ref_ret=0 IFS=':'
shift
git push origin "$@" 2> error
ret=$?
cat error
while read branch kind
do
case "$kind" in
'new')
grep "^ \* \[new branch\] *${branch} -> ${branch}$" error || ref_ret=1
;;
'non-fast-forward')
grep "^ ! \[rejected\] *${branch} -> ${branch} (non-fast-forward)$" error || ref_ret=1
;;
'fetch-first')
grep "^ ! \[rejected\] *${branch} -> ${branch} (fetch first)$" error || ref_ret=1
;;
'forced-update')
grep "^ + [a-f0-9]*\.\.\.[a-f0-9]* *${branch} -> ${branch} (forced update)$" error || ref_ret=1
;;
'')
grep "^ [a-f0-9]*\.\.[a-f0-9]* *${branch} -> ${branch}$" error || ref_ret=1
;;
esac
let 'ref_ret' && echo "match for '$branch' failed" && break
done
if let 'expected_ret != ret || ref_ret'
then
return 1
fi
return 0
}
setup () { setup () {
( (
echo "[ui]" echo "[ui]"
echo "username = H G Wells <wells@example.com>" echo "username = H G Wells <wells@example.com>"
) >> "$HOME"/.hgrc echo "[extensions]"
echo "mq ="
) >> "$HOME"/.hgrc &&
GIT_AUTHOR_DATE="2007-01-01 00:00:00 +0230" &&
GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE" &&
export GIT_COMMITTER_DATE GIT_AUTHOR_DATE
} }
setup setup
test_expect_success 'cloning' ' test_expect_success 'cloning' '
test_when_finished "rm -rf gitrepo*" && test_when_finished "rm -rf gitrepo*" &&
( (
hg init hgrepo && hg init hgrepo &&
cd hgrepo && cd hgrepo &&
echo zero > content && echo zero > content &&
hg add content && hg add content &&
hg commit -m zero hg commit -m zero
) && ) &&
git clone "hg::$PWD/hgrepo" gitrepo && git clone "hg::hgrepo" gitrepo &&
check gitrepo zero master check gitrepo HEAD zero
' '
test_expect_success 'cloning with branches' ' test_expect_success 'cloning with branches' '
test_when_finished "rm -rf gitrepo*" && test_when_finished "rm -rf gitrepo*" &&
( (
cd hgrepo && cd hgrepo &&
hg branch next && hg branch next &&
echo next > content && echo next > content &&
hg commit -m next hg commit -m next
) && ) &&
git clone "hg::$PWD/hgrepo" gitrepo && git clone "hg::hgrepo" gitrepo &&
check gitrepo next next && check gitrepo origin/branches/next next
(cd hgrepo && hg checkout default) &&
git clone "hg::$PWD/hgrepo" gitrepo2 &&
check gitrepo2 zero master
' '
test_expect_success 'cloning with bookmarks' ' test_expect_success 'cloning with bookmarks' '
test_when_finished "rm -rf gitrepo*" && test_when_finished "rm -rf gitrepo*" &&
( (
cd hgrepo && cd hgrepo &&
hg bookmark feature-a && hg checkout default &&
echo feature-a > content && hg bookmark feature-a &&
hg commit -m feature-a echo feature-a > content &&
) && hg commit -m feature-a
) &&
git clone "hg::$PWD/hgrepo" gitrepo && git clone "hg::hgrepo" gitrepo &&
check gitrepo feature-a feature-a check gitrepo origin/feature-a feature-a
'
test_expect_success 'cloning with detached head' '
test_when_finished "rm -rf gitrepo*" &&
(
cd hgrepo &&
hg update -r 0
) &&
git clone "hg::$PWD/hgrepo" gitrepo &&
check gitrepo zero master
' '
test_expect_success 'update bookmark' ' test_expect_success 'update bookmark' '
test_when_finished "rm -rf gitrepo*" && test_when_finished "rm -rf gitrepo*" &&
( (
cd hgrepo && cd hgrepo &&
hg bookmark devel hg bookmark devel
) && ) &&
( (
git clone "hg::$PWD/hgrepo" gitrepo && git clone "hg::hgrepo" gitrepo &&
cd gitrepo && cd gitrepo &&
git checkout devel && git checkout --quiet devel &&
echo devel > content && echo devel > content &&
git commit -a -m devel && git commit -a -m devel &&
git push git push --quiet
) && ) &&
hg -R hgrepo bookmarks | egrep "devel[ ]+3:" check_bookmark hgrepo devel devel
' '
test_expect_success 'new bookmark' '
test_when_finished "rm -rf gitrepo*" &&
(
git clone "hg::hgrepo" gitrepo &&
cd gitrepo &&
git checkout --quiet -b feature-b &&
echo feature-b > content &&
git commit -a -m feature-b &&
git push --quiet origin feature-b
) &&
check_bookmark hgrepo feature-b feature-b
'
# cleanup previous stuff
rm -rf hgrepo
author_test () { author_test () {
echo $1 >> content && echo $1 >> content &&
hg commit -u "$2" -m "add $1" && hg commit -u "$2" -m "add $1" &&
echo "$3" >> ../expected echo "$3" >> ../expected
} }
test_expect_success 'authors' ' test_expect_success 'authors' '
mkdir -p tmp && cd tmp && test_when_finished "rm -rf hgrepo gitrepo" &&
test_when_finished "cd .. && rm -rf tmp" &&
( (
hg init hgrepo && hg init hgrepo &&
cd hgrepo && cd hgrepo &&
touch content && touch content &&
hg add content && hg add content &&
author_test alpha "" "H G Wells <wells@example.com>" && > ../expected &&
author_test beta "test" "test <unknown>" && author_test alpha "" "H G Wells <wells@example.com>" &&
author_test beta "test <test@example.com> (comment)" "test <test@example.com>" && author_test beta "test" "test <unknown>" &&
author_test gamma "<test@example.com>" "Unknown <test@example.com>" && author_test beta "test <test@example.com> (comment)" "test <test@example.com>" &&
author_test delta "name<test@example.com>" "name <test@example.com>" && author_test gamma "<test@example.com>" "Unknown <test@example.com>" &&
author_test epsilon "name <test@example.com" "name <test@example.com>" && author_test delta "name<test@example.com>" "name <test@example.com>" &&
author_test zeta " test " "test <unknown>" && author_test epsilon "name <test@example.com" "name <test@example.com>" &&
author_test eta "test < test@example.com >" "test <test@example.com>" && author_test zeta " test " "test <unknown>" &&
author_test theta "test >test@example.com>" "test <test@example.com>" && author_test eta "test < test@example.com >" "test <test@example.com>" &&
author_test iota "test < test <at> example <dot> com>" "test <unknown>" && author_test theta "test >test@example.com>" "test <test@example.com>" &&
author_test kappa "test@example.com" "Unknown <test@example.com>" author_test iota "test < test <at> example <dot> com>" "test <unknown>" &&
) && author_test kappa "test@example.com" "Unknown <test@example.com>"
) &&
git clone "hg::$PWD/hgrepo" gitrepo && git clone "hg::hgrepo" gitrepo &&
git --git-dir=gitrepo/.git log --reverse --format="%an <%ae>" > actual && git --git-dir=gitrepo/.git log --reverse --format="%an <%ae>" > actual &&
test_cmp expected actual test_cmp expected actual
'
test_expect_success 'strip' '
test_when_finished "rm -rf hgrepo gitrepo" &&
(
hg init hgrepo &&
cd hgrepo &&
echo one >> content &&
hg add content &&
hg commit -m one &&
echo two >> content &&
hg commit -m two
) &&
git clone "hg::hgrepo" gitrepo &&
(
cd hgrepo &&
hg strip 1 &&
echo three >> content &&
hg commit -m three &&
echo four >> content &&
hg commit -m four
) &&
(
cd gitrepo &&
git fetch &&
git log --format="%s" origin/master > ../actual
) &&
hg -R hgrepo log --template "{desc}\n" > expected &&
test_cmp actual expected
'
test_expect_success 'remote push with master bookmark' '
test_when_finished "rm -rf hgrepo gitrepo*" &&
(
hg init hgrepo &&
cd hgrepo &&
echo zero > content &&
hg add content &&
hg commit -m zero &&
hg bookmark master &&
echo one > content &&
hg commit -m one
) &&
(
git clone "hg::hgrepo" gitrepo &&
cd gitrepo &&
echo two > content &&
git commit -a -m two &&
git push
) &&
check_branch hgrepo default two
'
cat > expected <<EOF
changeset: 0:6e2126489d3d
tag: tip
user: A U Thor <author@example.com>
date: Mon Jan 01 00:00:00 2007 +0230
summary: one
EOF
test_expect_success 'remote push from master branch' '
test_when_finished "rm -rf hgrepo gitrepo*" &&
hg init hgrepo &&
(
git init gitrepo &&
cd gitrepo &&
git remote add origin "hg::../hgrepo" &&
echo one > content &&
git add content &&
git commit -a -m one &&
git push origin master
) &&
hg -R hgrepo log > actual &&
cat actual &&
test_cmp expected actual &&
check_branch hgrepo default one
'
GIT_REMOTE_HG_TEST_REMOTE=1
export GIT_REMOTE_HG_TEST_REMOTE
test_expect_success 'remote cloning' '
test_when_finished "rm -rf gitrepo*" &&
(
hg init hgrepo &&
cd hgrepo &&
echo zero > content &&
hg add content &&
hg commit -m zero
) &&
git clone "hg::hgrepo" gitrepo &&
check gitrepo HEAD zero
'
test_expect_success 'remote update bookmark' '
test_when_finished "rm -rf gitrepo*" &&
(
cd hgrepo &&
hg bookmark devel
) &&
(
git clone "hg::hgrepo" gitrepo &&
cd gitrepo &&
git checkout --quiet devel &&
echo devel > content &&
git commit -a -m devel &&
git push --quiet
) &&
check_bookmark hgrepo devel devel
'
test_expect_success 'remote new bookmark' '
test_when_finished "rm -rf gitrepo*" &&
(
git clone "hg::hgrepo" gitrepo &&
cd gitrepo &&
git checkout --quiet -b feature-b &&
echo feature-b > content &&
git commit -a -m feature-b &&
git push --quiet origin feature-b
) &&
check_bookmark hgrepo feature-b feature-b
'
test_expect_success 'remote push diverged' '
test_when_finished "rm -rf gitrepo*" &&
git clone "hg::hgrepo" gitrepo &&
(
cd hgrepo &&
hg checkout default &&
echo bump > content &&
hg commit -m bump
) &&
(
cd gitrepo &&
echo diverge > content &&
git commit -a -m diverged &&
check_push 1 <<-EOF
master:non-fast-forward
EOF
) &&
check_branch hgrepo default bump
'
test_expect_success 'remote update bookmark diverge' '
test_when_finished "rm -rf gitrepo*" &&
(
cd hgrepo &&
hg checkout tip^ &&
hg bookmark diverge
) &&
git clone "hg::hgrepo" gitrepo &&
(
cd hgrepo &&
echo "bump bookmark" > content &&
hg commit -m "bump bookmark"
) &&
(
cd gitrepo &&
git checkout --quiet diverge &&
echo diverge > content &&
git commit -a -m diverge &&
check_push 1 <<-EOF
diverge:fetch-first
EOF
) &&
check_bookmark hgrepo diverge "bump bookmark"
'
test_expect_success 'remote new bookmark multiple branch head' '
test_when_finished "rm -rf gitrepo*" &&
(
git clone "hg::hgrepo" gitrepo &&
cd gitrepo &&
git checkout --quiet -b feature-c HEAD^ &&
echo feature-c > content &&
git commit -a -m feature-c &&
git push --quiet origin feature-c
) &&
check_bookmark hgrepo feature-c feature-c
'
# cleanup previous stuff
rm -rf hgrepo
setup_big_push () {
(
hg init hgrepo &&
cd hgrepo &&
echo zero > content &&
hg add content &&
hg commit -m zero &&
hg bookmark bad_bmark1 &&
echo one > content &&
hg commit -m one &&
hg bookmark bad_bmark2 &&
hg bookmark good_bmark &&
hg bookmark -i good_bmark &&
hg -q branch good_branch &&
echo "good branch" > content &&
hg commit -m "good branch" &&
hg -q branch bad_branch &&
echo "bad branch" > content &&
hg commit -m "bad branch"
) &&
git clone "hg::hgrepo" gitrepo &&
(
cd gitrepo &&
echo two > content &&
git commit -q -a -m two &&
git checkout -q good_bmark &&
echo three > content &&
git commit -q -a -m three &&
git checkout -q bad_bmark1 &&
git reset --hard HEAD^ &&
echo four > content &&
git commit -q -a -m four &&
git checkout -q bad_bmark2 &&
git reset --hard HEAD^ &&
echo five > content &&
git commit -q -a -m five &&
git checkout -q -b new_bmark master &&
echo six > content &&
git commit -q -a -m six &&
git checkout -q branches/good_branch &&
echo seven > content &&
git commit -q -a -m seven &&
echo eight > content &&
git commit -q -a -m eight &&
git checkout -q branches/bad_branch &&
git reset --hard HEAD^ &&
echo nine > content &&
git commit -q -a -m nine &&
git checkout -q -b branches/new_branch master &&
echo ten > content &&
git commit -q -a -m ten
)
}
test_expect_success 'remote big push' '
test_when_finished "rm -rf hgrepo gitrepo*" &&
setup_big_push
(
cd gitrepo &&
check_push 1 --all <<-EOF
master
good_bmark
branches/good_branch
new_bmark:new
branches/new_branch:new
bad_bmark1:non-fast-forward
bad_bmark2:non-fast-forward
branches/bad_branch:non-fast-forward
EOF
) &&
check_branch hgrepo default one &&
check_branch hgrepo good_branch "good branch" &&
check_branch hgrepo bad_branch "bad branch" &&
check_branch hgrepo new_branch '' &&
check_bookmark hgrepo good_bmark one &&
check_bookmark hgrepo bad_bmark1 one &&
check_bookmark hgrepo bad_bmark2 one &&
check_bookmark hgrepo new_bmark ''
'
test_expect_success 'remote big push fetch first' '
test_when_finished "rm -rf hgrepo gitrepo*" &&
(
hg init hgrepo &&
cd hgrepo &&
echo zero > content &&
hg add content &&
hg commit -m zero &&
hg bookmark bad_bmark &&
hg bookmark good_bmark &&
hg bookmark -i good_bmark &&
hg -q branch good_branch &&
echo "good branch" > content &&
hg commit -m "good branch" &&
hg -q branch bad_branch &&
echo "bad branch" > content &&
hg commit -m "bad branch"
) &&
git clone "hg::hgrepo" gitrepo &&
(
cd hgrepo &&
hg bookmark -f bad_bmark &&
echo update_bmark > content &&
hg commit -m "update bmark"
) &&
(
cd gitrepo &&
echo two > content &&
git commit -q -a -m two &&
git checkout -q good_bmark &&
echo three > content &&
git commit -q -a -m three &&
git checkout -q bad_bmark &&
echo four > content &&
git commit -q -a -m four &&
git checkout -q branches/bad_branch &&
echo five > content &&
git commit -q -a -m five &&
check_push 1 --all <<-EOF
master
good_bmark
new_bmark:new
new_branch:new
bad_bmark:fetch-first
branches/bad_branch:festch-first
EOF
git fetch &&
check_push 1 --all <<-EOF
master
good_bmark
bad_bmark:non-fast-forward
branches/bad_branch:non-fast-forward
EOF
)
'
test_expect_failure 'remote big push force' '
test_when_finished "rm -rf hgrepo gitrepo*" &&
setup_big_push
(
cd gitrepo &&
check_push 0 --force --all <<-EOF
master
good_bmark
branches/good_branch
new_bmark:new
branches/new_branch:new
bad_bmark1:forced-update
bad_bmark2:forced-update
branches/bad_branch:forced-update
EOF
) &&
check_branch hgrepo default six &&
check_branch hgrepo good_branch eight &&
check_branch hgrepo bad_branch nine &&
check_branch hgrepo new_branch ten &&
check_bookmark hgrepo good_bmark three &&
check_bookmark hgrepo bad_bmark1 four &&
check_bookmark hgrepo bad_bmark2 five &&
check_bookmark hgrepo new_bmark six
'
test_expect_failure 'remote big push dry-run' '
test_when_finished "rm -rf hgrepo gitrepo*" &&
setup_big_push
(
cd gitrepo &&
check_push 0 --dry-run --all <<-EOF
master
good_bmark
branches/good_branch
new_bmark:new
branches/new_branch:new
bad_bmark1:non-fast-forward
bad_bmark2:non-fast-forward
branches/bad_branch:non-fast-forward
EOF
check_push 0 --dry-run master good_bmark new_bmark branches/good_branch branches/new_branch <<-EOF
master
good_bmark
branches/good_branch
new_bmark:new
branches/new_branch:new
EOF
) &&
check_branch hgrepo default one &&
check_branch hgrepo good_branch "good branch" &&
check_branch hgrepo bad_branch "bad branch" &&
check_branch hgrepo new_branch '' &&
check_bookmark hgrepo good_bmark one &&
check_bookmark hgrepo bad_bmark1 one &&
check_bookmark hgrepo bad_bmark2 one &&
check_bookmark hgrepo new_bmark ''
'
test_expect_success 'remote double failed push' '
test_when_finished "rm -rf hgrepo gitrepo*" &&
(
hg init hgrepo &&
cd hgrepo &&
echo zero > content &&
hg add content &&
hg commit -m zero &&
echo one > content &&
hg commit -m one
) &&
(
git clone "hg::hgrepo" gitrepo &&
cd gitrepo &&
git reset --hard HEAD^ &&
echo two > content &&
git commit -a -m two &&
test_expect_code 1 git push &&
test_expect_code 1 git push
)
' '
test_done test_done