def parse_subrepos(ctx): sub = util.OrderedDict() if '.hgsub' in ctx: sub = util.parse_hgsub(ctx['.hgsub'].data().splitlines()) substate = util.OrderedDict() if '.hgsubstate' in ctx: substate = util.parse_hgsubstate( ctx['.hgsubstate'].data().splitlines()) return sub, substate
def _handle_subrepos(self, ctx): substate = util.parse_hgsubstate(ctx[".hgsubstate"].data().splitlines()) sub = util.OrderedDict() if ".hgsub" in ctx: sub = util.parse_hgsub(ctx[".hgsub"].data().splitlines()) for path, sha in substate.iteritems(): # Ignore non-Git repositories keeping state in .hgsubstate. if path in sub and not sub[path].startswith("[git]"): continue d = os.path.dirname(path) tree = self._dirs.setdefault(d, dulobjs.Tree()) tree.add(os.path.basename(path), dulobjs.S_IFGITLINK, sha)
def _handle_subrepos(self, ctx, dirty_trees): substate = util.parse_hgsubstate(ctx['.hgsubstate'].data().splitlines()) sub = util.OrderedDict() if '.hgsub' in ctx: sub = util.parse_hgsub(ctx['.hgsub'].data().splitlines()) for path, sha in substate.iteritems(): # Ignore non-Git repositories keeping state in .hgsubstate. if path in sub and not sub[path].startswith('[git]'): continue d = os.path.dirname(path) dirty_trees.add(d) tree = self._dirs.setdefault(d, dulobjs.Tree()) tree.add(os.path.basename(path), dulobjs.S_IFGITLINK, sha)
def import_git_commit(self, commit): self.ui.debug(_("importing: %s\n") % commit.id) (strip_message, hg_renames, hg_branch, extra) = self.extract_hg_metadata(commit.message) # get a list of the changed, added, removed files files = self.get_files_changed(commit) # Handle gitlinks: collect gitlinks = self.collect_gitlinks(commit.tree) git_commit_tree = self.git[commit.tree] # Analyze hgsubstate and build an updated version # using SHAs from gitlinks hgsubstate = None if gitlinks: hgsubstate = util.parse_hgsubstate(self.git_file_readlines(git_commit_tree, '.hgsubstate')) for path, sha in gitlinks: hgsubstate[path] = sha # in case .hgsubstate wasn't among changed files # force its inclusion files['.hgsubstate'] = (False, 0100644, None) # Analyze .hgsub and merge with .gitmodules hgsub = None gitmodules = self.parse_gitmodules(git_commit_tree) if gitmodules or gitlinks: hgsub = util.parse_hgsub(self.git_file_readlines(git_commit_tree, '.hgsub')) for (sm_path, sm_url, sm_name) in gitmodules: hgsub[sm_path] = '[git]' + sm_url files['.hgsub'] = (False, 0100644, None) elif commit.parents and '.gitmodules' in self.git[self.git[commit.parents[0]].tree]: # no .gitmodules in this commit, however present in the parent # mark its hg counterpart as deleted (assuming .hgsub is there # due to the same import_git_commit process files['.hgsub'] = (True, 0100644, None) date = (commit.author_time, -commit.author_timezone) text = strip_message origtext = text try: text.decode('utf-8') except UnicodeDecodeError: text = self.decode_guess(text, commit.encoding) text = '\n'.join([l.rstrip() for l in text.splitlines()]).strip('\n') if text + '\n' != origtext: extra['message'] = create_delta(text +'\n', origtext) author = commit.author # convert extra data back to the end if ' ext:' in commit.author: m = RE_GIT_AUTHOR_EXTRA.match(commit.author) if m: name = m.group(1) ex = urllib.unquote(m.group(2)) email = m.group(3) author = name + ' <' + email + '>' + ex if ' <none@none>' in commit.author: author = commit.author[:-12] try: author.decode('utf-8') except UnicodeDecodeError: origauthor = author author = self.decode_guess(author, commit.encoding) extra['author'] = create_delta(author, origauthor) oldenc = self.swap_out_encoding() def findconvergedfiles(p1, p2): # If any files have the same contents in both parents of a merge # (and are therefore not reported as changed by Git) but are at # different file revisions in Mercurial (because they arrived at # those contents in different ways), we need to include them in # the list of changed files so that Mercurial can join up their # filelog histories (same as if the merge was done in Mercurial to # begin with). if p2 == nullid: return [] manifest1 = self.repo.changectx(p1).manifest() manifest2 = self.repo.changectx(p2).manifest() return [path for path, node1 in manifest1.iteritems() if path not in files and manifest2.get(path, node1) != node1] def getfilectx(repo, memctx, f): info = files.get(f) if info != None: # it's a file reported as modified from Git delete, mode, sha = info if delete: raise IOError if not sha: # indicates there's no git counterpart e = '' copied_path = None if '.hgsubstate' == f: data = util.serialize_hgsubstate(hgsubstate) elif '.hgsub' == f: data = util.serialize_hgsub(hgsub) else: data = self.git[sha].data copied_path = hg_renames.get(f) e = self.convert_git_int_mode(mode) else: # it's a converged file fc = context.filectx(self.repo, f, changeid=memctx.p1().rev()) data = fc.data() e = fc.flags() copied_path = fc.renamed() return context.memfilectx(f, data, 'l' in e, 'x' in e, copied_path) gparents = map(self.map_hg_get, commit.parents) p1, p2 = (nullid, nullid) octopus = False if len(gparents) > 1: # merge, possibly octopus 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)) octopus = len(gparents) > 2 p2 = gparents.pop() p1 = gparents.pop() while len(gparents) > 0: p2 = commit_octopus(p1, p2) p1 = gparents.pop() else: if gparents: p1 = gparents.pop() pa = None if not (p2 == nullid): node1 = self.repo.changectx(p1) node2 = self.repo.changectx(p2) pa = node1.ancestor(node2) # if named branch, add to extra if hg_branch: extra['branch'] = hg_branch # if committer is different than author, add it to extra if commit.author != commit.committer \ or commit.author_time != commit.commit_time \ or commit.author_timezone != commit.commit_timezone: extra['committer'] = "%s %d %d" % ( commit.committer, commit.commit_time, -commit.commit_timezone) if commit.encoding: extra['encoding'] = commit.encoding if hg_branch: extra['branch'] = hg_branch if octopus: extra['hg-git'] ='octopus-done' # TODO use 'n in self.repo' when we require hg 1.5 def repo_contains(n): try: return bool(self.repo.lookup(n)) except error.RepoLookupError: return False if not (repo_contains(p1) and repo_contains(p2)): raise hgutil.Abort(_('you appear to have run strip - ' 'please run hg git-cleanup')) ctx = context.memctx(self.repo, (p1, p2), text, list(files) + findconvergedfiles(p1, p2), getfilectx, author, date, extra) node = self.repo.commitctx(ctx) self.swap_out_encoding(oldenc) # save changeset to mapping file cs = hex(node) self.map_set(commit.id, cs)