def test_push_two_revs_different_local_branch(self): def filectxfn(repo, memctx, path): return context.memfilectx(path=path, data=path, islink=False, isexec=False, copied=False) oldtiphash = self.repo['default'].node() ctx = context.memctx(self.repo, (self.repo[0].node(), revlog.nullid, ), 'automated test', ['gamma', ], filectxfn, 'testy', '2008-12-21 16:32:00 -0500', {'branch': 'localbranch', }) newhash = self.repo.commitctx(ctx) ctx = context.memctx(self.repo, (newhash, revlog.nullid), 'automated test2', ['delta', ], filectxfn, 'testy', '2008-12-21 16:32:00 -0500', {'branch': 'localbranch', }) newhash = self.repo.commitctx(ctx) repo = self.repo hg.update(repo, newhash) commands.push(repo.ui, repo) self.assertEqual(self.repo['tip'].parents()[0].parents()[0].node(), oldtiphash) self.assertEqual(self.repo['tip'].files(), ['delta', ]) self.assertEqual(self.repo['tip'].manifest().keys(), ['alpha', 'beta', 'gamma', 'delta'])
def test_push_single_dir_at_subdir(self): repo = self._load_fixture_and_fetch('branch_from_tag.svndump', layout='single', subdir='trunk') def filectxfn(repo, memctx, path): return compathacks.makememfilectx(repo, memctx=memctx, path=path, data='contents of %s' % path, islink=False, isexec=False, copied=False) ctx = context.memctx(repo, (repo['tip'].node(), node.nullid), 'automated test', ['bogus'], filectxfn, 'an_author', '2009-10-19 18:49:30 -0500', { 'branch': 'localhacking', }) n = repo.commitctx(ctx) self.assertEqual(self.repo['tip']['bogus'].data(), 'contents of bogus') before = repo['tip'].hex() hg.update(repo, self.repo['tip'].hex()) self.pushrevisions() self.assertNotEqual(before, self.repo['tip'].hex()) self.assertEqual(self.repo['tip']['bogus'].data(), 'contents of bogus')
def test_push_single_dir_renamed_branch(self): # Tests pulling and pushing with a renamed branch # Based on test_push_single_dir repo_path = self.load_svndump('branch_from_tag.svndump') cmd = ['clone', '--quiet', '--layout=single', '--branch=flaf'] if self.stupid: cmd.append('--stupid') cmd += [test_util.fileurl(repo_path), self.wc_path] test_util.dispatch(cmd) def file_callback(repo, memctx, path): if path == 'adding_file': return compathacks.makememfilectx(repo, memctx=memctx, path=path, data='foo', islink=False, isexec=False, copied=False) raise IOError(errno.EINVAL, 'Invalid operation: ' + path) lr = self.repo ctx = context.memctx(lr, (lr['tip'].node(), node.nullid), 'automated test', ['adding_file'], file_callback, 'an_author', '2009-10-19 18:49:30 -0500', { 'branch': 'default', }) lr.commitctx(ctx) hg.update(self.repo, self.repo['tip'].node()) self.pushrevisions() self.assertTrue('adding_file' in test_util.svnls(repo_path, '')) self.assertEquals(set(['flaf']), set(self.repo[i].branch() for i in self.repo))
def putcommit(self, files, copies, parents, commit, source, revmap): files = dict(files) def getfilectx(repo, memctx, f): v = files[f] data, mode = source.getfile(f, v) if f == '.hgtags': data = self._rewritetags(source, revmap, data) return context.memfilectx(f, data, 'l' in mode, 'x' in mode, copies.get(f)) pl = [] for p in parents: if p not in pl: pl.append(p) parents = pl nparents = len(parents) if self.filemapmode and nparents == 1: m1node = self.repo.changelog.read(bin(parents[0]))[0] parent = parents[0] if len(parents) < 2: parents.append(nullid) if len(parents) < 2: parents.append(nullid) p2 = parents.pop(0) text = commit.desc sha1s = re.findall(sha1re, text) for sha1 in sha1s: oldrev = source.lookuprev(sha1) newrev = revmap.get(oldrev) if newrev is not None: text = text.replace(sha1, newrev[:len(sha1)]) extra = commit.extra.copy() if self.branchnames and commit.branch: extra['branch'] = commit.branch if commit.rev: extra['convert_revision'] = commit.rev while parents: p1 = p2 p2 = parents.pop(0) ctx = context.memctx(self.repo, (p1, p2), text, files.keys(), getfilectx, commit.author, commit.date, extra) self.repo.commitctx(ctx) text = "(octopus merge fixup)\n" p2 = hex(self.repo.changelog.tip()) if self.filemapmode and nparents == 1: man = self.repo.manifest mnode = self.repo.changelog.read(bin(p2))[0] closed = 'close' in commit.extra if not closed and not man.cmp(m1node, man.revision(mnode)): self.ui.status(_("filtering out empty revision\n")) self.repo.rollback(force=True) return parent return p2
def test_push_single_dir_one_incoming_and_two_outgoing(self): # Tests simple pushing from default branch to a single dir repo # Pushes two outgoing over one incoming svn rev # (used to cause an "unknown revision") # This can happen if someone committed to svn since our last pull (race). repo, repo_path = self.load_and_fetch('branch_from_tag.svndump', layout='single', subdir='trunk') self.add_svn_rev(repo_path, {'trunk/alpha': 'Changed'}) def file_callback(repo, memctx, path): return compathacks.makememfilectx(repo, memctx=memctx, path=path, data='data of %s' % path, islink=False, isexec=False, copied=False) for fn in ['one', 'two']: ctx = context.memctx(repo, (repo['tip'].node(), node.nullid), 'automated test', [fn], file_callback, 'an_author', '2009-10-19 18:49:30 -0500', { 'branch': 'default', }) repo.commitctx(ctx) hg.update(repo, repo['tip'].node()) self.pushrevisions(expected_extra_back=1) self.assertTrue('trunk/one' in test_util.svnls(repo_path, '')) self.assertTrue('trunk/two' in test_util.svnls(repo_path, ''))
def test_rebase(self): self._load_fixture_and_fetch('two_revs.svndump') parents = ( self.repo[0].node(), revlog.nullid, ) def filectxfn(repo, memctx, path): return compathacks.makememfilectx(repo, memctx=memctx, path=path, data='added', islink=False, isexec=False, copied=False) lr = self.repo ctx = context.memctx(lr, parents, 'automated test', [ 'added_bogus_file', 'other_added_file', ], filectxfn, 'testy', '2008-12-21 16:32:00 -0500', { 'branch': 'localbranch', }) lr.commitctx(ctx) self.assertEqual(self.repo['tip'].branch(), 'localbranch') beforerebasehash = self.repo['tip'].node() hg.update(self.repo, 'tip') wrappers.rebase(rebase.rebase, self.ui(), self.repo, svn=True) self.assertEqual(self.repo['tip'].branch(), 'localbranch') self.assertEqual(self.repo['tip'].parents()[0].parents()[0], self.repo[0]) self.assertNotEqual(beforerebasehash, self.repo['tip'].node())
def commit(self, items): def file_callback(repo, memctx, path): return context.memfilectx( path=path, data=items[path], islink=False, isexec=False, copied=False, ) local_repo = self._local_repo remote_repo = self._remote_repo lock = local_repo.lock() try: if remote_repo: local_repo.pull(self._remote_repo) ctx = context.memctx( repo=local_repo, parents=('tip', None), text=revision.message, files=items.keys(), filectxfn=file_callback, user=str(revision.user.id), ) version = node.hex(local_repo.commitctx(ctx)) # TODO: if we want the working copy of the repository to be updated as well add logic to enable this. # hg.update(local_repo, local_repo['tip'].node()) if remote_repo: local_repo.push(remote_repo) return version finally: lock.release()
def test_cant_push_empty_ctx(self): repo = self.repo def file_callback(repo, memctx, path): if path == 'adding_file': return compathacks.makememfilectx(repo, path=path, data='foo', islink=False, isexec=False, copied=False) raise IOError() ctx = context.memctx(repo, (repo['default'].node(), node.nullid), 'automated test', [], file_callback, 'an_author', '2008-10-07 20:59:48 -0500', {'branch': 'default', }) new_hash = repo.commitctx(ctx) hg.update(repo, repo['tip'].node()) old_tip = repo['tip'].node() self.pushrevisions() tip = self.repo['tip'] self.assertEqual(tip.node(), old_tip)
def test_cant_push_with_changes(self): repo = self.repo def file_callback(repo, memctx, path): return compathacks.makememfilectx(repo, path=path, data='foo', islink=False, isexec=False, copied=False) ctx = context.memctx(repo, (repo['default'].node(), node.nullid), 'automated test', ['adding_file'], file_callback, 'an_author', '2008-10-07 20:59:48 -0500', {'branch': 'default', }) new_hash = repo.commitctx(ctx) hg.update(repo, repo['tip'].node()) # Touch an existing file repo.wwrite('beta', 'something else', '') try: self.pushrevisions() except hgutil.Abort: pass tip = self.repo['tip'] self.assertEqual(new_hash, tip.node())
def overlaycontext(memworkingcopy, ctx, parents=None, extra=None): """({path: content}, ctx, (p1node, p2node)?, {}?) -> memctx memworkingcopy overrides file contents. """ # parents must contain 2 items: (node1, node2) if parents is None: parents = ctx.repo().changelog.parents(ctx.node()) if extra is None: extra = ctx.extra() date = ctx.date() desc = ctx.description() user = ctx.user() files = set(ctx.files()).union(memworkingcopy) store = overlaystore(ctx, memworkingcopy) return context.memctx( repo=ctx.repo(), parents=parents, text=desc, files=files, filectxfn=store, user=user, date=date, branch=None, extra=extra, )
def puttags(self, tags): try: parentctx = self.repo[self.tagsbranch] tagparent = parentctx.node() except error.RepoError: parentctx = None tagparent = nullid try: oldlines = sorted(parentctx['.hgtags'].data().splitlines(True)) except: oldlines = [] newlines = sorted([("%s %s\n" % (tags[tag], tag)) for tag in tags]) if newlines == oldlines: return None, None data = "".join(newlines) def getfilectx(repo, memctx, f): return context.memfilectx(f, data, False, False, None) self.ui.status(_("updating tags\n")) date = "%s 0" % int(time.mktime(time.gmtime())) extra = {'branch': self.tagsbranch} ctx = context.memctx(self.repo, (tagparent, None), "update tags", [".hgtags"], getfilectx, "convert-repo", date, extra) self.repo.commitctx(ctx) return hex(self.repo.changelog.tip()), hex(tagparent)
def test_push_to_default(self, commit=True): repo = self.repo old_tip = repo['tip'].node() expected_parent = repo['default'].node() def file_callback(repo, memctx, path): if path == 'adding_file': return context.memfilectx(path=path, data='foo', islink=False, isexec=False, copied=False) raise IOError(errno.EINVAL, 'Invalid operation: ' + path) ctx = context.memctx(repo, (repo['default'].node(), node.nullid), 'automated test', ['adding_file'], file_callback, 'an_author', '2008-10-07 20:59:48 -0500', {'branch': 'default',}) new_hash = repo.commitctx(ctx) if not commit: return # some tests use this test as an extended setup. hg.update(repo, repo['tip'].node()) self.pushrevisions() tip = self.repo['tip'] self.assertNotEqual(tip.node(), old_tip) self.assertEqual(node.hex(tip.parents()[0].node()), node.hex(expected_parent)) self.assertEqual(tip['adding_file'].data(), 'foo') self.assertEqual(tip.branch(), 'default')
def _graft(repo, rev, mapping): '''duplicate changeset "rev" with parents from "mapping"''' oldp1 = rev.p1().node() oldp2 = rev.p2().node() newp1 = mapping.get(oldp1, oldp1) newp2 = mapping.get(oldp2, oldp2) m = rev.manifest() def getfilectx(repo, memctx, path): if path in m: fctx = rev[path] flags = fctx.flags() copied = fctx.renamed() if copied: copied = copied[0] return context.memfilectx(repo, fctx.path(), fctx.data(), islink='l' in flags, isexec='x' in flags, copied=copied) else: return None # If the incoming commit has no parents, but requested a rebase, # allow it only for the first commit. The null/null commit will always # be the first commit since we only allow a nullid->nonnullid mapping if the # incoming commits are a completely distinct history (see `sharedparents` in # getrevs()), so there's no risk of commits with a single null parent # accidentally getting translated first. if oldp1 == nullid and oldp2 == nullid: if newp1 != nullid: newp2 = nullid del mapping[nullid] if oldp1 != nullid and oldp2 != nullid: # If it's a merge commit, Mercurial's rev.files() only returns the files # that are different from both p1 and p2, so it would not capture all of # the incoming changes from p2 (for instance, new files in p2). The fix # is to manually diff the rev manifest and it's p1 to get the list of # files that have changed. We only need to diff against p1, and not p2, # because Mercurial constructs new commits by applying our specified # files on top of a copy of the p1 manifest, so we only need the diff # against p1. bundlerepo = rev._repo files = rev.manifest().diff(bundlerepo[oldp1].manifest()).keys() else: files = rev.files() date = rev.date() if repo.ui.configbool('pushrebase', 'rewritedates'): date = (time.time(), date[1]) return context.memctx(repo, [newp1, newp2], rev.description(), files, getfilectx, rev.user(), date, rev.extra(), ).commit()
def putcommit(self, files, modes, copies, commit): def getfilectx(repo, memctx, name): fileid = files[name] if fileid is None: # deleted file raise IOError data = self.getblob(fileid) ctx = context.memfilectx(name, data, 'l' in modes, 'x' in modes, copies.get(name)) return ctx parents = list(set(commit.parents)) nparents = len(parents) if len(parents) < 2: parents.append(nullid) if len(parents) < 2: parents.append(nullid) p2 = parents.pop(0) text = commit.desc extra = commit.extra.copy() if self.branchnames and commit.branch: extra['branch'] = commit.branch while parents: p1 = p2 p2 = parents.pop(0) ctx = context.memctx(self.repo, (p1, p2), text, files.keys(), getfilectx, commit.author, commit.date, extra) self.repo.commitctx(ctx) text = "(octopus merge fixup)\n" p2 = hex(self.repo.changelog.tip()) return p2
def test_push_single_dir_renamed_branch(self, stupid=False): # Tests pulling and pushing with a renamed branch # Based on test_push_single_dir test_util.load_svndump_fixture(self.repo_path, 'branch_from_tag.svndump') cmd = ['clone', '--layout=single', '--branch=flaf'] if stupid: cmd.append('--stupid') cmd += [test_util.fileurl(self.repo_path), self.wc_path] dispatch.dispatch(cmd) def file_callback(repo, memctx, path): if path == 'adding_file': return context.memfilectx(path=path, data='foo', islink=False, isexec=False, copied=False) raise IOError(errno.EINVAL, 'Invalid operation: ' + path) ctx = context.memctx(self.repo, (self.repo['tip'].node(), node.nullid), 'automated test', ['adding_file'], file_callback, 'an_author', '2009-10-19 18:49:30 -0500', {'branch': 'default',}) self.repo.commitctx(ctx) hg.update(self.repo, self.repo['tip'].node()) self.pushrevisions() self.assertTrue('adding_file' in self.svnls('')) self.assertEquals(set(['flaf']), set(self.repo[i].branch() for i in self.repo))
def test_push_single_dir_one_incoming_and_two_outgoing(self): # Tests simple pushing from default branch to a single dir repo # Pushes two outgoing over one incoming svn rev # (used to cause an "unknown revision") # This can happen if someone committed to svn since our last pull (race). repo = self._load_fixture_and_fetch('branch_from_tag.svndump', stupid=False, layout='single', subdir='trunk') self._add_svn_rev({'trunk/alpha': 'Changed'}) def file_callback(repo, memctx, path): return context.memfilectx(path=path, data='data of %s' % path, islink=False, isexec=False, copied=False) for fn in ['one', 'two']: ctx = context.memctx(repo, (repo['tip'].node(), node.nullid), 'automated test', [fn], file_callback, 'an_author', '2009-10-19 18:49:30 -0500', {'branch': 'default',}) repo.commitctx(ctx) hg.update(repo, repo['tip'].node()) self.pushrevisions(expected_extra_back=1) self.assertTrue('trunk/one' in self.svnls('')) self.assertTrue('trunk/two' in self.svnls(''))
def test_push_single_dir_at_subdir(self): repo = self._load_fixture_and_fetch('branch_from_tag.svndump', stupid=False, layout='single', subdir='trunk') def filectxfn(repo, memctx, path): return context.memfilectx(path=path, data='contents of %s' % path, islink=False, isexec=False, copied=False) ctx = context.memctx(repo, (repo['tip'].node(), node.nullid), 'automated test', ['bogus'], filectxfn, 'an_author', '2009-10-19 18:49:30 -0500', {'branch': 'localhacking',}) n = repo.commitctx(ctx) self.assertEqual(self.repo['tip']['bogus'].data(), 'contents of bogus') before = repo['tip'].hex() hg.update(repo, self.repo['tip'].hex()) self.pushrevisions() self.assertNotEqual(before, self.repo['tip'].hex()) self.assertEqual(self.repo['tip']['bogus'].data(), 'contents of bogus')
def test_push_single_dir(self): # Tests simple pushing from default branch to a single dir repo repo = self._load_fixture_and_fetch('branch_from_tag.svndump', stupid=False, layout='single', subdir='') def file_callback(repo, memctx, path): if path == 'adding_file': return context.memfilectx(path=path, data='foo', islink=False, isexec=False, copied=False) raise IOError(errno.EINVAL, 'Invalid operation: ' + path) ctx = context.memctx(repo, (repo['tip'].node(), node.nullid), 'automated test', ['adding_file'], file_callback, 'an_author', '2009-10-19 18:49:30 -0500', {'branch': 'default',}) repo.commitctx(ctx) hg.update(repo, repo['tip'].node()) self.pushrevisions() self.assertTrue('adding_file' in self.svnls(''))
def harvest(ui, repo, branch, dest="default", **opts): """Close and merge a named branch into the destination branch""" if branch not in repo.branchtags(): ui.warn("Branch %s does not exist! (use 'hg branches' to get a list of branches)\n" % branch) return if dest not in repo.branchtags(): ui.warn("Destination branch %s does not exist! (use 'hg branches' to get a list of branches)\n" % branch) return heads = repo.branchheads(branch) if len(heads) == 0: ui.warn("Cannot harvest branch %s because it is currently closed. \nUse 'hg merge' to merge it manually.\n" % branch) return if len(heads) > 1: ui.warn("Branch %s has multiple heads. \nUse 'hg merge' to merge it manually.\n" % branch) return rev = repo.branchtip(branch) newrev = context.memctx(repo, [rev, None], "Closed branch %s" % branch, [], None, opts.get('user'), opts.get('date'), extra={'close':1, 'branch':branch}) newrev.commit() #don't need to switch if already on destination branch curr = repo[None].branch() if dest != curr: hg.clean(repo, dest, False) ui.status("Switched to branch %s before merging\n" % dest) failed = hg.merge(repo, branch, remind = False) if not failed: repo.commit("Merged %s" % branch, opts.get('user'), opts.get('date'), None) ui.status("Completed merge of %s into %s\n" % (branch, dest))
def test_push_to_default(self, commit=True): repo = self.repo old_tip = revsymbol(repo, 'tip').node() expected_parent = revsymbol(repo, 'default').node() def file_callback(repo, memctx, path): if path == 'adding_file': return compathacks.makememfilectx(repo, memctx=memctx, path=path, data='foo', islink=False, isexec=False, copied=False) raise IOError(errno.EINVAL, 'Invalid operation: ' + path) ctx = context.memctx(repo, (revsymbol(repo, 'default').node(), node.nullid), 'automated test', ['adding_file'], file_callback, 'an_author', '2008-10-07 20:59:48 -0500', { 'branch': 'default', }) new_hash = repo.commitctx(ctx) if not commit: return # some tests use this test as an extended setup. hg.update(repo, revsymbol(repo, 'tip').node()) self.pushrevisions() tip = revsymbol(self.repo, 'tip') self.assertNotEqual(tip.node(), old_tip) self.assertEqual(node.hex(tip.parents()[0].node()), node.hex(expected_parent)) self.assertEqual(tip['adding_file'].data(), 'foo') self.assertEqual(tip.branch(), 'default')
def test_push_to_branch(self, push=True): repo = self.repo def file_callback(repo, memctx, path): if path == 'adding_file': return compathacks.makememfilectx(repo, memctx=memctx, path=path, data='foo', islink=False, isexec=False, copied=False) raise IOError(errno.EINVAL, 'Invalid operation: ' + path) ctx = context.memctx( repo, (revsymbol(repo, 'the_branch').node(), node.nullid), 'automated test', ['adding_file'], file_callback, 'an_author', '2008-10-07 20:59:48 -0500', { 'branch': 'the_branch', }) new_hash = repo.commitctx(ctx) hg.update(repo, revsymbol(repo, 'tip').node()) if push: self.pushrevisions() tip = revsymbol(self.repo, 'tip') self.assertNotEqual(tip.node(), new_hash) self.assertEqual(tip['adding_file'].data(), 'foo') self.assertEqual(tip.branch(), 'the_branch')
def test_outgoing_output(self): self._load_fixture_and_fetch('two_heads.svndump') u = self.ui() parents = (self.repo['the_branch'].node(), revlog.nullid, ) def filectxfn(repo, memctx, path): return context.memfilectx(path=path, data='added', islink=False, isexec=False, copied=False) ctx = context.memctx(self.repo, parents, 'automated test', ['added_bogus_file', 'other_added_file', ], filectxfn, 'testy', '2008-12-21 16:32:00 -0500', {'branch': 'localbranch', }) new = self.repo.commitctx(ctx) hg.update(self.repo, new) u.pushbuffer() commands.outgoing(u, self.repo, self.repourl) actual = u.popbuffer() self.assertTrue(node.hex(self.repo['localbranch'].node())[:8] in actual) self.assertEqual(actual.strip(), '5:6de15430fa20') hg.update(self.repo, 'default') u.pushbuffer() commands.outgoing(u, self.repo, self.repourl) actual = u.popbuffer() self.assertEqual(actual, '')
def test_cant_push_with_changes(self): repo = self.repo def file_callback(repo, memctx, path): return compathacks.makememfilectx(repo, memctx=memctx, path=path, data='foo', islink=False, isexec=False, copied=False) ctx = context.memctx(repo, (revsymbol(repo, 'default').node(), node.nullid), 'automated test', ['adding_file'], file_callback, 'an_author', '2008-10-07 20:59:48 -0500', { 'branch': 'default', }) new_hash = repo.commitctx(ctx) hg.update(repo, revsymbol(repo, 'tip').node()) # Touch an existing file repo.wwrite('beta', 'something else', '') try: self.pushrevisions() except hgerror.Abort: pass tip = revsymbol(self.repo, 'tip') self.assertEqual(new_hash, tip.node())
def createfn(repo, ctx, revmap, filectxfn): parents = newparents(repo, ctx, revmap) description = ctx.description() if not opts['unmodified']: description += b'\n%d' % offset[0] memctx = context.memctx(repo, parents, description, ctx.files(), filectxfn, user=ctx.user(), date=ctx.date(), extra=ctx.extra()) status = ctx.p1().status(ctx) # TRACKING hg53 - status is an object instead of a tuple if util.versiontuple(n=2) >= (5, 3): memctx.modified = lambda: status.modified memctx.added = lambda: status.added memctx.removed = lambda: status.removed else: memctx.modified = lambda: status[0] memctx.added = lambda: status[1] memctx.removed = lambda: status[2] offset[0] += 1 return memctx
def copy_commit(repo, ctx, parent, date): mf = ctx.manifest() copied = copies.pathcopies(ctx.p1(), ctx) def _filectxfn(repo, memctx, path): if path in mf: fctx = ctx[path] flags = fctx.flags() return context.memfilectx( fctx.path(), fctx.data(), islink='l' in flags, isexec='x' in flags, copied=copied.get(path)) raise IOError new = context.memctx( repo, parents=(parent.node(), repo[-1].node()), text=ctx.description(), files=ctx.files(), filectxfn=_filectxfn, user=ctx.user(), date=date, extra=ctx.extra()) return repo.commitctx(new)
def _commitcontext(rdst, parents, ctx, dstfiles, getfilectx, revmap): mctx = context.memctx(rdst, parents, ctx.description(), dstfiles, getfilectx, ctx.user(), ctx.date(), ctx.extra()) ret = rdst.commitctx(mctx) lfutil.copyalltostore(rdst, ret) rdst.setparents(ret) revmap[ctx.node()] = rdst.changelog.tip()
def puttags(self, tags): try: parentctx = self.repo[self.tagsbranch] tagparent = parentctx.node() except error.RepoError: parentctx = None tagparent = nullid try: oldlines = sorted(parentctx['.hgtags'].data().splitlines(True)) except: oldlines = [] newlines = sorted([("%s %s\n" % (tags[tag], tag)) for tag in tags]) if newlines == oldlines: return None data = "".join(newlines) def getfilectx(repo, memctx, f): return context.memfilectx(f, data, False, False, None) self.ui.status(_("updating tags\n")) date = "%s 0" % int(time.mktime(time.gmtime())) extra = {'branch': self.tagsbranch} ctx = context.memctx(self.repo, (tagparent, None), "update tags", [".hgtags"], getfilectx, "convert-repo", date, extra) self.repo.commitctx(ctx) return hex(self.repo.changelog.tip())
def test_rebase(self): self._load_fixture_and_fetch('two_revs.svndump') parents = (self.repo[0].node(), revlog.nullid, ) def filectxfn(repo, memctx, path): return context.memfilectx(path=path, data='added', islink=False, isexec=False, copied=False) ctx = context.memctx(self.repo, parents, 'automated test', ['added_bogus_file', 'other_added_file', ], filectxfn, 'testy', '2008-12-21 16:32:00 -0500', {'branch': 'localbranch', }) self.repo.commitctx(ctx) self.assertEqual(self.repo['tip'].branch(), 'localbranch') beforerebasehash = self.repo['tip'].node() hg.update(self.repo, 'tip') wrappers.rebase(rebase.rebase, self.ui(), self.repo, svn=True) self.assertEqual(self.repo['tip'].branch(), 'localbranch') self.assertEqual(self.repo['tip'].parents()[0].parents()[0], self.repo[0]) self.assertNotEqual(beforerebasehash, self.repo['tip'].node())
def test_push_to_branch(self, push=True): repo = self.repo def file_callback(repo, memctx, path): if path == 'adding_file': return context.memfilectx(path=path, data='foo', islink=False, isexec=False, copied=False) raise IOError(errno.EINVAL, 'Invalid operation: ' + path) ctx = context.memctx(repo, (repo['the_branch'].node(), node.nullid), 'automated test', ['adding_file'], file_callback, 'an_author', '2008-10-07 20:59:48 -0500', {'branch': 'the_branch',}) new_hash = repo.commitctx(ctx) hg.update(repo, repo['tip'].node()) if push: self.pushrevisions() tip = self.repo['tip'] self.assertNotEqual(tip.node(), new_hash) self.assertEqual(tip['adding_file'].data(), 'foo') self.assertEqual(tip.branch(), 'the_branch')
def test_push_symlink_file(self): self.test_push_to_default(commit=True) repo = self.repo def file_callback(repo, memctx, path): if path == 'gamma': return context.memfilectx(path=path, data='foo', islink=True, isexec=False, copied=False) raise IOError(errno.EINVAL, 'Invalid operation: ' + path) ctx = context.memctx(repo, (repo['tip'].node(), node.nullid), 'message', ['gamma', ], file_callback, 'author', '2008-10-29 21:26:00 -0500', {'branch': 'default', }) new_hash = repo.commitctx(ctx) hg.update(repo, repo['tip'].node()) self.pushrevisions() tip = self.repo['tip'] self.assertNotEqual(tip.node(), new_hash) self.assertEqual(tip['gamma'].flags(), 'l') self.assertEqual(tip['gamma'].data(), 'foo') self.assertEqual([x for x in tip.manifest().keys() if 'l' not in tip[x].flags()], ['alpha', 'beta', 'adding_file', ])
def test_cant_push_empty_ctx(self): repo = self.repo def file_callback(repo, memctx, path): if path == 'adding_file': return compathacks.makememfilectx(repo, memctx=memctx, path=path, data='foo', islink=False, isexec=False, copied=False) raise IOError() ctx = context.memctx(repo, (revsymbol(repo, 'default').node(), node.nullid), 'automated test', [], file_callback, 'an_author', '2008-10-07 20:59:48 -0500', { 'branch': 'default', }) new_hash = repo.commitctx(ctx) hg.update(repo, revsymbol(repo, 'tip').node()) old_tip = revsymbol(repo, 'tip').node() self.pushrevisions() tip = revsymbol(self.repo, 'tip') self.assertEqual(tip.node(), old_tip)
def committags(self, rev, endbranches): if not self.addedtags and not self.deletedtags: return date = self.fixdate(rev.date) # determine additions/deletions per branch branches = {} for tags in (self.addedtags, self.deletedtags): for tag, (branch, srcrev) in tags.iteritems(): op = srcrev is None and 'rm' or 'add' branches.setdefault(branch, []).append((op, tag, srcrev)) for b, tags in branches.iteritems(): fromtag = self.get_path_tag(self.remotename(b)) # modify parent's .hgtags source parent = self.repo[self.get_parent_revision(rev.revnum, b)] if '.hgtags' not in parent: src = '' else: src = parent['.hgtags'].data() for op, tag, r in sorted(tags, reverse=True): if op == 'add': if fromtag: if fromtag in self.tags: tagged = node.hex(self.tags[fromtag]) else: tagged = node.hex(self.revmap[ self.get_parent_svn_branch_and_rev(r, b)]) else: tagged = node.hex(node.nullid) src += '%s %s\n' % (tagged, tag) self.tags[tag] = node.bin(tagged), rev.revnum # add new changeset containing updated .hgtags def fctxfun(repo, memctx, path): return context.memfilectx(path='.hgtags', data=src, islink=False, isexec=False, copied=None) extra = self.genextra(rev.revnum, b) if fromtag: extra['branch'] = parent.extra().get('branch', 'default') self.mapbranch(extra, b in endbranches or fromtag) ctx = context.memctx(self.repo, (parent.node(), node.nullid), rev.message or ' ', ['.hgtags'], fctxfun, self.authors[rev.author], date, extra) new = self.repo.commitctx(ctx) if not fromtag and (rev.revnum, b) not in self.revmap: self.revmap[rev.revnum, b] = new if b in endbranches: endbranches.pop(b) bname = b or 'default' self.ui.status('Marked branch %s as closed.\n' % bname)
def push_to_try(ui, repo, server, message=None): nodate = ui.configbool('push-to-try', 'nodate') if not message or 'try:' not in message: ui.status("STOP! A commit message with try syntax is required.\n") return cctx = context.workingctx(repo) status = repo.status() if status.modified + status.added + status.removed: ui.status('The following will be pushed to %s:\n' % server) # TODO: Achieve this by re-using the status call above to avoid the # cost of running it twice. commands.status(ui, repo) preserve_ctx = preservefilectx(cctx) def mk_memfilectx(repo, memctx, path): if path not in status.removed: return preserve_ctx(repo, memctx, path) return None # Invent a temporary commit with our message. ui.status("Creating temporary commit for remote...\n") mctx = context.memctx(repo, repo.dirstate.parents(), message, cctx.files(), mk_memfilectx, date="0 0" if nodate else None) # These messages are expected when we abort our transaction, but aren't # helpful to a user and may be misleading so we surpress them here. filtered_phrases = {_("transaction abort!\n"), _("rollback completed\n")} def filtered_warn(*msgs, **opts): if msgs: filtered = [m for m in msgs if m not in filtered_phrases] if filtered: ui.warn(*filtered, **opts) lock = tr = None try: lock = repo.lock() tr = repo.transaction('push-to-try', report=filtered_warn) m = mctx.commit() # Push to try. commands.push(ui, repo, server, force=True, rev=[repo[m].rev()]) ui.status('push complete\n') # And rollback to the previous state. tr.abort() finally: if tr: tr.release() if lock: lock.release() ui.status("temporary commit removed, repository restored\n")
def internal_push_over_svnserve(self, subdir='', commit=True): test_util.load_svndump_fixture(self.repo_path, 'simple_branch.svndump') open(os.path.join(self.repo_path, 'conf', 'svnserve.conf'), 'w').write('[general]\nanon-access=write\n[sasl]\n') self.port = random.randint(socket.IPPORT_USERRESERVED, 65535) self.host = 'localhost' args = ['svnserve', '--daemon', '--foreground', '--listen-port=%d' % self.port, '--listen-host=%s' % self.host, '--root=%s' % self.repo_path] svnserve = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) self.svnserve_pid = svnserve.pid try: time.sleep(2) import shutil shutil.rmtree(self.wc_path) commands.clone(self.ui(), 'svn://%s:%d/%s' % (self.host, self.port, subdir), self.wc_path, noupdate=True) repo = self.repo old_tip = repo['tip'].node() expected_parent = repo['default'].node() def file_callback(repo, memctx, path): if path == 'adding_file': return context.memfilectx(path=path, data='foo', islink=False, isexec=False, copied=False) raise IOError(errno.EINVAL, 'Invalid operation: ' + path) ctx = context.memctx(repo, parents=(repo['default'].node(), node.nullid), text='automated test', files=['adding_file'], filectxfn=file_callback, user='******', date='2008-10-07 20:59:48 -0500', extra={'branch': 'default',}) new_hash = repo.commitctx(ctx) if not commit: return # some tests use this test as an extended setup. hg.update(repo, repo['tip'].node()) oldauthor = repo['tip'].user() commands.push(repo.ui, repo) tip = self.repo['tip'] self.assertNotEqual(oldauthor, tip.user()) self.assertNotEqual(tip.node(), old_tip) self.assertEqual(tip.parents()[0].node(), expected_parent) self.assertEqual(tip['adding_file'].data(), 'foo') self.assertEqual(tip.branch(), 'default') # unintended behaviour: self.assertNotEqual('an_author', tip.user()) self.assertEqual('(no author)', tip.user().rsplit('@', 1)[0]) finally: # TODO: use svnserve.kill() in Python >2.5 test_util.kill_process(svnserve)
def commit_to_branch(name, parent): repo.commitctx( context.memctx(repo, (parent, node.nullid), 'automated test (%s)' % name, [name], file_callback(name), 'an_author', '2009-10-19 18:49:30 -0500', { 'branch': name, }))
def test_push_add_of_added_upstream_gives_sane_error(self): repo = self.repo def file_callback(repo, memctx, path): if path == 'adding_file': return compathacks.makememfilectx(repo, path=path, data='foo', islink=False, isexec=False, copied=False) raise IOError() p1 = repo['default'].node() ctx = context.memctx(repo, (p1, node.nullid), 'automated test', ['adding_file'], file_callback, 'an_author', '2008-10-07 20:59:48 -0500', {'branch': 'default', }) new_hash = repo.commitctx(ctx) hg.update(repo, repo['tip'].node()) old_tip = repo['tip'].node() self.pushrevisions() tip = self.repo['tip'] self.assertNotEqual(tip.node(), old_tip) # This node adds the same file as the first one we added, and # will be refused by the server for adding a file that already # exists. We should respond with an error suggesting the user # rebase. ctx = context.memctx(repo, (p1, node.nullid), 'automated test', ['adding_file'], file_callback, 'an_author', '2008-10-07 20:59:48 -0500', {'branch': 'default', }) new_hash = repo.commitctx(ctx) hg.update(repo, repo['tip'].node()) old_tip = repo['tip'].node() try: self.pushrevisions() except hgutil.Abort, e: assert "pull again and rebase" in str(e)
def unamend(ui, repo, **opts): """undo the most recent amend operation on a current changeset This command will roll back to the previous version of a changeset, leaving working directory in state in which it was before running `hg amend` (e.g. files modified as part of an amend will be marked as modified `hg status`) """ unfi = repo.unfiltered() with repo.wlock(), repo.lock(), repo.transaction(b'unamend'): # identify the commit from which to unamend curctx = repo[b'.'] rewriteutil.precheck(repo, [curctx.rev()], b'unamend') # identify the commit to which to unamend markers = list(predecessormarkers(curctx)) if len(markers) != 1: e = _( b"changeset must have one predecessor, found %i predecessors") raise error.Abort(e % len(markers)) prednode = markers[0].prednode() predctx = unfi[prednode] # add an extra so that we get a new hash # note: allowing unamend to undo an unamend is an intentional feature extras = predctx.extra() extras[b'unamend_source'] = curctx.hex() def filectxfn(repo, ctx_, path): try: return predctx.filectx(path) except KeyError: return None # Make a new commit same as predctx newctx = context.memctx( repo, parents=(predctx.p1(), predctx.p2()), text=predctx.description(), files=predctx.files(), filectxfn=filectxfn, user=predctx.user(), date=predctx.date(), extra=extras, ) newprednode = repo.commitctx(newctx) newpredctx = repo[newprednode] dirstate = repo.dirstate with dirstate.parentchange(): scmutil.movedirstate(repo, newpredctx) mapping = {curctx.node(): (newprednode, )} scmutil.cleanupnodes(repo, mapping, b'unamend', fixphase=True)
def replacerev(ui, repo, ctx, filedata, replacements): """Commit a new revision like the given one, but with file content changes "ctx" is the original revision to be replaced by a modified one. "filedata" is a dict that maps paths to their new file content. All other paths will be recreated from the original revision without changes. "filedata" may contain paths that didn't exist in the original revision; they will be added. "replacements" is a dict that maps a single node to a single node, and it is updated to indicate the original revision is replaced by the newly created one. No entry is added if the replacement's node already exists. The new revision has the same parents as the old one, unless those parents have already been replaced, in which case those replacements are the parents of this new revision. Thus, if revisions are replaced in topological order, there is no need to rebase them into the original topology later. """ p1rev, p2rev = repo.changelog.parentrevs(ctx.rev()) p1ctx, p2ctx = repo[p1rev], repo[p2rev] newp1node = replacements.get(p1ctx.node(), p1ctx.node()) newp2node = replacements.get(p2ctx.node(), p2ctx.node()) def filectxfn(repo, memctx, path): if path not in ctx: return None fctx = ctx[path] copied = fctx.renamed() if copied: copied = copied[0] return context.memfilectx( repo, memctx, path=fctx.path(), data=filedata.get(path, fctx.data()), islink=fctx.islink(), isexec=fctx.isexec(), copied=copied) memctx = context.memctx( repo, parents=(newp1node, newp2node), text=ctx.description(), files=set(ctx.files()) | set(filedata.keys()), filectxfn=filectxfn, user=ctx.user(), date=ctx.date(), extra=ctx.extra(), branch=ctx.branch(), editor=None) sucnode = memctx.commit() prenode = ctx.node() if prenode == sucnode: ui.debug('node %s already existed\n' % (ctx.hex())) else: replacements[ctx.node()] = sucnode
def _overlayrev(sourcerepo, sourceurl, sourcectx, destrepo, destctx, prefix): """Overlay a single commit into another repo.""" assert prefix.endswith(b'/') assert len(sourcectx.parents()) < 2 sourceman = sourcectx.manifest() def filectxfn(repo, memctx, path): sourcepath = path[len(prefix):] if sourcepath not in sourceman: return None node, flags = sourceman.find(sourcepath) sourcefl = sourcerepo.file(sourcepath) data = sourcefl.read(node) islink = b'l' in flags isexec = b'x' in flags copied = None renamed = sourcefl.renamed(node) if renamed: copied = b'%s%s' % (prefix, renamed[0]) # TRACKING hg50 - `copied` renamed to `copysource` if util.versiontuple(n=2) >= (5, 0): return context.memfilectx(repo, memctx, path, data, islink=islink, isexec=isexec, copysource=copied) else: return context.memfilectx(repo, memctx, path, data, islink=islink, isexec=isexec, copied=copied) parents = [destctx.node(), None] files = [b'%s%s' % (prefix, f) for f in sourcectx.files()] extra = dict(sourcectx.extra()) extra[REVISION_KEY] = sourcectx.hex() extra[SOURCE_KEY] = sourceurl memctx = context.memctx(destrepo, parents, sourcectx.description(), files, filectxfn, user=sourcectx.user(), date=sourcectx.date(), extra=extra) return memctx.commit()
def test_parent_output(self): self._load_fixture_and_fetch('two_heads.svndump') u = self.ui() u.pushbuffer() parents = ( revsymbol(self.repo, 'the_branch').node(), revlog.nullid, ) def filectxfn(repo, memctx, path): return compathacks.makememfilectx(repo, memctx=memctx, path=path, data='added', islink=False, isexec=False, copied=False) lr = self.repo ctx = context.memctx(lr, parents, 'automated test', [ 'added_bogus_file', 'other_added_file', ], filectxfn, 'testy', '2008-12-21 16:32:00 -0500', { 'branch': 'localbranch', }) new = lr.commitctx(ctx) hg.update(self.repo, new) wrappers.parents(lambda x, y: None, u, self.repo, svn=True) actual = u.popbuffer() # two hashes becaure in hg > 4.8 we try hard to reuse the manifest self.assertTrue(actual in ('3:4e256962fc5d\n', '3:13c5dc1514ad\n')) hg.update(self.repo, revsymbol(self.repo, 'default')) # Make sure styles work u.pushbuffer() wrappers.parents(lambda x, y: None, u, self.repo, svn=True, style='compact') actual = u.popbuffer() self.assertEqual(actual, '4:1083037b18d8\n') # custom templates too u.pushbuffer() wrappers.parents(lambda x, y: None, u, self.repo, svn=True, template='{node}\n') actual = u.popbuffer() self.assertEqual(actual, '1083037b18d85cd84fa211c5adbaeff0fea2cd9f\n') u.pushbuffer() wrappers.parents(lambda x, y: None, u, self.repo, svn=True) actual = u.popbuffer() self.assertEqual(actual, '4:1083037b18d8\n')
def commit_to_branch(name, parent): repo.commitctx(context.memctx(repo, (parent, node.nullid), 'automated test (%s)' % name, [name], file_callback(name), 'an_author', '2009-10-19 18:49:30 -0500', {'branch': name,}))
def delbranch(self, branch, node, rev): extra = self.genextra(rev.revnum, branch) self.mapbranch(extra, True) ctx = context.memctx(self.repo, (node, revlog.nullid), self.getmessage(rev), [], lambda x, y, z: None, util.forceutf8(self.authors[rev.author]), self.fixdate(rev.date), extra) self.repo.svn_commitctx(ctx) self.ui.status('Marked branch %s as closed.\n' % (branch or 'default'))
def test_push_in_subdir(self, commit=True): repo = self.repo old_tip = repo['tip'].node() def file_callback(repo, memctx, path): if path == 'adding_file' or path == 'newdir/new_file': testData = 'fooFirstFile' if path == 'newdir/new_file': testData = 'fooNewFile' return compathacks.makememfilectx(repo, path=path, data=testData, islink=False, isexec=False, copied=False) raise IOError(errno.EINVAL, 'Invalid operation: ' + path) ctx = context.memctx(repo, (repo['default'].node(), node.nullid), 'automated test', ['adding_file'], file_callback, 'an_author', '2012-12-13 20:59:48 -0500', {'branch': 'default', }) new_hash = repo.commitctx(ctx) p = os.path.join(repo.root, "newdir") os.mkdir(p) ctx = context.memctx(repo, (repo['default'].node(), node.nullid), 'automated test', ['newdir/new_file'], file_callback, 'an_author', '2012-12-13 20:59:48 -0500', {'branch': 'default', }) os.chdir(p) new_hash = repo.commitctx(ctx) hg.update(repo, repo['tip'].node()) self.pushrevisions() tip = self.repo['tip'] self.assertNotEqual(tip.node(), old_tip) self.assertEqual(p, os.getcwd()) self.assertEqual(tip['adding_file'].data(), 'fooFirstFile') self.assertEqual(tip['newdir/new_file'].data(), 'fooNewFile') self.assertEqual(tip.branch(), 'default')
def test_push_in_subdir(self, commit=True): repo = self.repo old_tip = revsymbol(repo, 'tip').node() def file_callback(repo, memctx, path): if path == 'adding_file' or path == 'newdir/new_file': testData = 'fooFirstFile' if path == 'newdir/new_file': testData = 'fooNewFile' return compathacks.makememfilectx(repo, memctx=memctx, path=path, data=testData, islink=False, isexec=False, copied=False) raise IOError(errno.EINVAL, 'Invalid operation: ' + path) ctx = context.memctx(repo, (revsymbol(repo, 'default').node(), node.nullid), 'automated test', ['adding_file'], file_callback, 'an_author', '2012-12-13 20:59:48 -0500', { 'branch': 'default', }) new_hash = repo.commitctx(ctx) p = os.path.join(repo.root, "newdir") os.mkdir(p) ctx = context.memctx(repo, (revsymbol(repo, 'default').node(), node.nullid), 'automated test', ['newdir/new_file'], file_callback, 'an_author', '2012-12-13 20:59:48 -0500', { 'branch': 'default', }) os.chdir(p) new_hash = repo.commitctx(ctx) hg.update(repo, revsymbol(repo, 'tip').node()) self.pushrevisions() tip = revsymbol(self.repo, 'tip') self.assertNotEqual(tip.node(), old_tip) self.assertEqual(p, os.getcwd()) self.assertEqual(tip['adding_file'].data(), 'fooFirstFile') self.assertEqual(tip['newdir/new_file'].data(), 'fooNewFile') self.assertEqual(tip.branch(), 'default')
def commit(self): repo = self.repo.repo def get_file(repo, ctx, path): # XXX: copy sources # XXX: renames # XXX: deletes if path in rn and path not in self.contents: raise IOError() if path in rrn: assert base is not None parent = self.base_commit.rev[rrn[path]] if path in self.contents: data = self.contents[path] else: data = parent.data() copied = rrn[path] else: data = self.contents[path] copied = False # XXX: real flags islink = False isexec = False return context.memfilectx( repo=self.repo, path=path, data=data, islink=islink, isexec=isexec, copied=copied, ) rn = dict( (k, v) for k, v in self.renames if self.base_commit.exists(k)) rrn = dict(reversed(x) for x in self.renames) # XXX: directory renames files = set(self.contents) files.update(rn.keys()) files.update(rn.values()) if self.base_commit is not None: base = self.base_commit.rev.node() else: base = None ctx = context.memctx( repo=repo, parents=[base, None], text=self.extra['message'], files=sorted(files), filectxfn=get_file, user=self.author, date="%(time_unix)d %(time_offset)s" % self.__dict__, ) repo.commitctx(ctx)
def createfn(repo, ctx, revmap, filectxfn): parents = newparents(repo, ctx, revmap) files = ctx.files() files.pop() memctx = context.memctx(repo, parents, ctx.description(), files, filectxfn, user=ctx.user(), date=ctx.date(), extra=ctx.extra()) return memctx
def test_push_add_of_added_upstream_gives_sane_error(self): repo = self.repo def file_callback(repo, memctx, path): if path == 'adding_file': return compathacks.makememfilectx(repo, memctx=memctx, path=path, data='foo', islink=False, isexec=False, copied=False) raise IOError() p1 = revsymbol(repo, 'default').node() ctx = context.memctx(repo, (p1, node.nullid), 'automated test', ['adding_file'], file_callback, 'an_author', '2008-10-07 20:59:48 -0500', { 'branch': 'default', }) new_hash = repo.commitctx(ctx) hg.update(repo, revsymbol(repo, 'tip').node()) old_tip = revsymbol(repo, 'tip').node() self.pushrevisions() tip = revsymbol(self.repo, 'tip') self.assertNotEqual(tip.node(), old_tip) # This node adds the same file as the first one we added, and # will be refused by the server for adding a file that already # exists. We should respond with an error suggesting the user # rebase. ctx = context.memctx(repo, (p1, node.nullid), 'automated test', ['adding_file'], file_callback, 'an_author', '2008-10-07 20:59:48 -0500', { 'branch': 'default', }) new_hash = repo.commitctx(ctx) hg.update(repo, revsymbol(repo, 'tip').node()) old_tip = revsymbol(repo, 'tip').node() try: self.pushrevisions() except hgerror.Abort, e: assert "pull again and rebase" in str(e)
def createfn(repo, ctx, revmap, filectxfn): parents = newparents(repo, ctx, revmap) files = ctx.files() files.pop() memctx = context.memctx( repo, parents, ctx.description(), files, filectxfn, user=ctx.user(), date=ctx.date(), extra=ctx.extra() ) return memctx
def commitchanges(self, changes, parent='tip', message='automated test'): """Commit changes to mercurial directory 'changes' is a sequence of tuples (source, dest, data). It can look like: - (source, source, data) to set source content to data - (source, dest, None) to set dest content to source one, and mark it as copied from source. - (source, dest, data) to set dest content to data, and mark it as copied from source. - (source, None, None) to remove source. """ repo = self.repo if isinstance(parent, int): parentctx = repo[parent] else: parentctx = revsymbol(repo, parent) changed, removed = [], [] for source, dest, newdata in changes: if dest is None: removed.append(source) else: changed.append(dest) def filectxfn(repo, memctx, path): if path in removed: return compathacks.filectxfn_deleted(memctx, path) entry = [e for e in changes if path == e[1]][0] source, dest, newdata = entry if newdata is None: newdata = parentctx[source].data() copied = None if source != dest: copied = source return compathacks.makememfilectx(repo, memctx=memctx, path=dest, data=newdata, islink=False, isexec=False, copied=copied) ctx = context.memctx(repo, (parentctx.node(), node.nullid), message, changed + removed, filectxfn, 'an_author', '2008-10-07 20:59:48 -0500', {'branch': parentctx.branch()}) nodeid = repo.commitctx(ctx) repo = self.repo hg.clean(repo, nodeid) return nodeid
def puttags(self, tags): tagparent = self.repo.branchtip(self.tagsbranch, ignoremissing=True) tagparent = tagparent or self.repo.nullid oldlines = set() for branch, heads in pycompat.iteritems(self.repo.branchmap()): for h in heads: if b'.hgtags' in self.repo[h]: oldlines.update( set(self.repo[h][b'.hgtags'].data().splitlines(True))) oldlines = sorted(list(oldlines)) newlines = sorted([(b"%s %s\n" % (tags[tag], tag)) for tag in tags]) if newlines == oldlines: return None, None # if the old and new tags match, then there is nothing to update oldtags = set() newtags = set() for line in oldlines: s = line.strip().split(b' ', 1) if len(s) != 2: continue oldtags.add(s[1]) for line in newlines: s = line.strip().split(b' ', 1) if len(s) != 2: continue if s[1] not in oldtags: newtags.add(s[1].strip()) if not newtags: return None, None data = b"".join(newlines) def getfilectx(repo, memctx, f): return context.memfilectx(repo, memctx, f, data, False, False, None) self.ui.status(_(b"updating tags\n")) date = b"%d 0" % int(time.mktime(time.gmtime())) extra = {b'branch': self.tagsbranch} ctx = context.memctx( self.repo, (tagparent, None), b"update tags", [b".hgtags"], getfilectx, b"convert-repo", date, extra, ) node = self.repo.commitctx(ctx) return hex(node), hex(tagparent)
def delbranch(self, branch, node, rev): pctx = self.repo[node] files = pctx.manifest().keys() extra = self.genextra(rev.revnum, branch) self.mapbranch(extra, True) ctx = context.memctx(self.repo, (node, revlog.nullid), rev.message or util.default_commit_msg(self.ui), [], lambda x, y, z: None, self.authors[rev.author], self.fixdate(rev.date), extra) new = self.repo.commitctx(ctx) self.ui.status('Marked branch %s as closed.\n' % (branch or 'default'))
def commit_octopus(p1, p2): ctx = context.memctx( self.repo, (p1, p2), text, list(files) + findconvergedfiles(p1, p2), getfilectx, author, date, {"hg-git": "octopus"}, ) return hex(self.repo.commitctx(ctx))
def addcommitid(repo, ctx, revmap, copyfilectxfn): parents = newparents(repo, ctx, revmap) # Need to make a copy otherwise modification is made on original, # which is just plain wrong. extra = dict(ctx.extra()) assert "commitid" not in extra extra["commitid"] = genid(repo) memctx = context.memctx( repo, parents, ctx.description(), ctx.files(), copyfilectxfn, user=ctx.user(), date=ctx.date(), extra=extra ) return memctx
def putcommit(self, files, copies, parents, commit, source, revmap): files = dict(files) def getfilectx(repo, memctx, f): v = files[f] data, mode = source.getfile(f, v) if f == '.hgtags': data = self._rewritetags(source, revmap, data) return context.memfilectx(f, data, 'l' in mode, 'x' in mode, copies.get(f)) pl = [] for p in parents: if p not in pl: pl.append(p) parents = pl nparents = len(parents) if self.filemapmode and nparents == 1: m1node = self.repo.changelog.read(bin(parents[0]))[0] parent = parents[0] if len(parents) < 2: parents.append(nullid) if len(parents) < 2: parents.append(nullid) p2 = parents.pop(0) text = commit.desc extra = commit.extra.copy() if self.branchnames and commit.branch: extra['branch'] = commit.branch if commit.rev: extra['convert_revision'] = commit.rev while parents: p1 = p2 p2 = parents.pop(0) ctx = context.memctx(self.repo, (p1, p2), text, files.keys(), getfilectx, commit.author, commit.date, extra) self.repo.commitctx(ctx) text = "(octopus merge fixup)\n" p2 = hex(self.repo.changelog.tip()) if self.filemapmode and nparents == 1: man = self.repo.manifest mnode = self.repo.changelog.read(bin(p2))[0] closed = 'close' in commit.extra if not closed and not man.cmp(m1node, man.revision(mnode)): self.ui.status(_("filtering out empty revision\n")) self.repo.rollback() return parent return p2
def makememctx(repo, ctx, revmap, copyfilectxfn): parents = newparents(repo, ctx, revmap) # Need to make a copy otherwise modification is made on original, # which is just plain wrong. msg = encoding.fromlocal(ctx.description()) new_msg, changed = addcommitid(msg, repo=repo) memctx = context.memctx(repo, parents, encoding.tolocal(new_msg), ctx.files(), copyfilectxfn, user=ctx.user(), date=ctx.date(), extra=dict(ctx.extra())) return memctx