Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions gitifyhg/gitexporter.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
from mercurial.bookmarks import pushbookmark
from mercurial.scmutil import revsingle

from .util import (log, die, output, git_to_hg_spaces, hgmode, branch_tip,
from .util import (log, die, output, name_git_to_hg, hgmode, branch_tip,
ref_to_name_reftype, BRANCH, BOOKMARK, TAG, user_config)


Expand Down Expand Up @@ -67,7 +67,7 @@ def process(self):
# This seems to be a git fast-export bug
continue
name, reftype = ref_to_name_reftype(ref)
name = git_to_hg_spaces(name)
name = name_git_to_hg(name)
if reftype == BRANCH:
if name not in self.hgremote.branches:
new_branch = True
Expand Down Expand Up @@ -208,7 +208,7 @@ def do_commit(self):

name, reftype = ref_to_name_reftype(ref)
if reftype == BRANCH:
extra['branch'] = git_to_hg_spaces(name)
extra['branch'] = name_git_to_hg(name)

def get_filectx(repo, memctx, file):
filespec = files[file]
Expand Down Expand Up @@ -241,7 +241,7 @@ def do_tag(self):
tagger = self.parser.read_author()
message = self.parser.read_data()
self.parser.read_line()
self.parsed_tags[git_to_hg_spaces(name)] = tagger, message
self.parsed_tags[name_git_to_hg(name)] = tagger, message

def do_feature(self):
pass # Ignore
Expand Down
8 changes: 4 additions & 4 deletions gitifyhg/gitifyhg.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
from mercurial.bookmarks import listbookmarks, readcurrent

from .util import (log, die, output, branch_head, GitMarks,
HGMarks, hg_to_git_spaces, name_reftype_to_ref, BRANCH, BOOKMARK, TAG,
HGMarks, name_hg_to_git, name_reftype_to_ref, BRANCH, BOOKMARK, TAG,
version, deactivate_stdout)
from .hgimporter import HGImporter
from .gitexporter import GitExporter
Expand Down Expand Up @@ -264,21 +264,21 @@ def do_list(self, parser):
for branch in self.branches:
output("%s %s" %
(self._change_hash(branch_head(self, branch)),
name_reftype_to_ref(hg_to_git_spaces(branch), BRANCH)))
name_reftype_to_ref(name_hg_to_git(branch), BRANCH)))

# list the bookmark references
for bookmark, changectx in self.bookmarks.items():
if bookmark != "master":
output("%s %s" %
(self._change_hash(changectx),
name_reftype_to_ref(hg_to_git_spaces(bookmark), BOOKMARK)))
name_reftype_to_ref(name_hg_to_git(bookmark), BOOKMARK)))

# list the tags
for tag, node in self.repo.tagslist():
if tag != "tip":
output("%s %s" %
(self._change_hash(self.repo[node]),
name_reftype_to_ref(hg_to_git_spaces(tag), TAG)))
name_reftype_to_ref(name_hg_to_git(tag), TAG)))

output()

Expand Down
14 changes: 7 additions & 7 deletions gitifyhg/hgimporter.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@
from mercurial import encoding

from .util import (log, output, gittz, gitmode,
git_to_hg_spaces, hg_to_git_spaces, branch_head, ref_to_name_reftype,
BRANCH, BOOKMARK, TAG)
name_git_to_hg, name_hg_to_git, branch_head, ref_to_name_reftype,
BRANCH, BOOKMARK, TAG, relative_path)

AUTHOR = re.compile(r'^([^<>]+)?(<(?:[^<>]*)>| [^ ]*@.*|[<>].*)$')

Expand Down Expand Up @@ -89,11 +89,11 @@ def process(self):
else:
name, reftype = ref_to_name_reftype(ref)
if reftype == BRANCH:
head = branch_head(self.hgremote, git_to_hg_spaces(name))
head = branch_head(self.hgremote, name_git_to_hg(name))
elif reftype == BOOKMARK:
head = self.hgremote.bookmarks[git_to_hg_spaces(name)]
head = self.hgremote.bookmarks[name_git_to_hg(name)]
elif reftype == TAG:
head = self.repo[git_to_hg_spaces(name)]
head = self.repo[name_git_to_hg(name)]
else:
assert False, "unexpected reftype: %s" % reftype
self.process_ref(name, reftype, head)
Expand Down Expand Up @@ -178,11 +178,11 @@ def process_ref(self, name, reftype, head):
filecontext = self.repo[rev].filectx(file)
data = filecontext.data()
output("M %s inline %s" % (
gitmode(filecontext.flags()), filecontext.path()))
gitmode(filecontext.flags()), relative_path(filecontext.path())))
output("data %d" % len(data))
output(data)
for file in removed:
output("D %s" % (file))
output("D %s" % (relative_path(file)))
output()

count += 1
Expand Down
28 changes: 19 additions & 9 deletions gitifyhg/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@
BRANCH = 'branch'
BOOKMARK = 'bookmark'
TAG = 'tag'
NAMES_HG_TO_GIT = {' ': '___',
'/': '_SLASH_',
}


actual_stdout = os.fdopen(sys.stdout.fileno(), 'w', 0) # Ensure stdout is unbuffered
def deactivate_stdout():
Expand Down Expand Up @@ -75,16 +79,17 @@ def hgmode(mode):
return modes.get(mode, '')


def hg_to_git_spaces(name):
'''Spaces are allowed in mercurial, but not in git. We convert them to
the unlikely string ___'''
return name.replace(' ', '___')


def git_to_hg_spaces(name):
'''But when we push back to mercurial, we need to convert it the other way.'''
return name.replace('___', ' ')
def name_hg_to_git(name):
"""Translate names from hg to git"""
for mapFrom, mapTo in NAMES_HG_TO_GIT.iteritems():
name = name.replace(mapFrom, mapTo)
return name

def name_git_to_hg(name):
"""Translate names from git to hg"""
for mapTo, mapFrom in NAMES_HG_TO_GIT.iteritems():
name = name.replace(mapFrom, mapTo)
return name

def branch_tip(repo, branch):
'''HG has a lovely branch_tip method, but it requires mercurial 2.4
Expand Down Expand Up @@ -155,6 +160,11 @@ def user_config():
hgrc.read(cfg)
return hgrc

def relative_path(path):
"""Ensure path is relative"""
return os.path.relpath(path, '/') if os.path.isabs(path) else path


class HGMarks(object):
'''Maps integer marks to specific string mercurial revision identifiers.
Identifiers are passed as binary nodes and converted to/from hex strings
Expand Down
46 changes: 46 additions & 0 deletions test/test_pull.py
Original file line number Diff line number Diff line change
Expand Up @@ -185,3 +185,49 @@ def test_pull_tag_with_spaces(git_dir, hg_repo):
sh.cd(git_repo)
sh.git.pull()
assert "tag___one" in sh.git.tag()


def test_pull_branch_with_slashes(git_dir, hg_repo):
sh.cd(hg_repo)
sh.hg.branch("feature/one")
make_hg_commit("b")
sh.hg.branch("feature")
make_hg_commit("c")
git_repo = clone_repo(git_dir, hg_repo)
sh.cd(hg_repo)
sh.hg.update("feature/one")
make_hg_commit("d")
sh.hg.update("feature")
sh.hg.branch("feature/two")
make_hg_commit("e")

def assert_branches(expected):
assert [b.strip() for b in sorted(sh.git('branch', '--list', '-a', 'origin/*'))] == sorted(expected)

sh.cd(git_repo)
assert_branches(["remotes/origin/HEAD -> origin/master",
"remotes/origin/branches/feature",
"remotes/origin/branches/feature_SLASH_one",
"remotes/origin/master",
])

sh.git.checkout("origin/branches/feature", track=True)
assert_git_messages(["c", "b", "a"])
assert_git_count(3)
sh.git.checkout("origin/branches/feature_SLASH_one", track=True)
assert_git_messages(["b", "a"])
assert_git_count(2)
sh.git.pull()
assert_branches(["remotes/origin/HEAD -> origin/master",
"remotes/origin/branches/feature",
"remotes/origin/branches/feature_SLASH_one",
"remotes/origin/branches/feature_SLASH_two",
"remotes/origin/master",
])
assert_git_messages(["d", "b", "a"])
assert_git_count(3)
sh.git.checkout("origin/branches/feature_SLASH_two", track=True)
sh.git.pull()
assert_git_messages(["e", "c", "b", "a"])
assert_git_count(4)