mirror of
https://github.com/mnauw/git-remote-hg.git
synced 2025-10-25 23:06:04 +02:00
Transform invalid reserved pathname components
Fixes mnauw/git-remote-hg#58
This commit is contained in:
@@ -104,6 +104,20 @@ the invalid '~'
|
||||
% git config --global remote-hg.ignore-name ~
|
||||
--------------------------------------
|
||||
|
||||
Even though the "gitdir" is configurable (using `GIT_DIR`), git does not accept
|
||||
certain pathname components, e.g. `.git` or `.gitmodules` (case-insensitive).
|
||||
Problems arise if the hg repo contains such pathnames, and recent git versions
|
||||
will reject this in a very hard way. So these pathnames are now mapped
|
||||
from "hg space" to "git space" in a one-to-one way, where (e.g.)
|
||||
`.git[0 or more suffix]` is mapped to `.git[1 or more suffix]` (obviously by
|
||||
appending or removing a suffix). The "suffix" in question defaults to `_`,
|
||||
but can be configured using
|
||||
|
||||
--------------------------------------
|
||||
% git config --global remote-hg.dotfile-suffix _
|
||||
--------------------------------------
|
||||
|
||||
|
||||
NOTES
|
||||
-----
|
||||
|
||||
|
||||
@@ -438,7 +438,7 @@ def export_file(ctx, fname):
|
||||
puts(b"data %d" % len(d))
|
||||
puts(f.data())
|
||||
|
||||
path = fix_file_path(f.path())
|
||||
path = fixup_path_to_git(fix_file_path(f.path()))
|
||||
return (gitmode(f.flags()), mark, path)
|
||||
|
||||
def get_filechanges(repo, ctx, parent):
|
||||
@@ -518,6 +518,51 @@ def fixup_user(user):
|
||||
|
||||
return b'%s <%s>' % (name, mail)
|
||||
|
||||
# (recent) git fast-import does not accept .git or .gitmodule component names
|
||||
# (anywhere, case-insensitive)
|
||||
# in any case, surprising things may happen, so add some front-end replacement magic;
|
||||
# transform of (hg) .git(0 or more suffix) to (git) .git(1 or more suffix)
|
||||
# (likewise so for any invalid git keyword)
|
||||
def fixup_dotfile_path(path, suffix, add):
|
||||
def subst(part):
|
||||
if (not part) or part[0] != ord(b'.'):
|
||||
return part
|
||||
for prefix in (b'.git', b'.gitmodules'):
|
||||
pl = len(prefix)
|
||||
tail = len(part) - pl
|
||||
if tail < 0:
|
||||
continue
|
||||
if part[0:pl].lower() == prefix and part[pl:] == suffix * tail:
|
||||
if add:
|
||||
return part + suffix
|
||||
elif tail == 0:
|
||||
# .git should not occur in git space
|
||||
# so complain
|
||||
if pl == 3:
|
||||
die('invalid path component %s' % part)
|
||||
else:
|
||||
# but .gitmodules might
|
||||
# leave as-is, it is handled/ignored elsewhere
|
||||
return part
|
||||
else:
|
||||
return part[0:-1]
|
||||
return part
|
||||
# quick optimization check;
|
||||
if (not path) or (path[0] != ord(b'.') and path.find(b'/.') < 0):
|
||||
return path
|
||||
sep = b'/'
|
||||
return sep.join((subst(part) for part in path.split(sep)))
|
||||
|
||||
def fixup_path_to_git(path):
|
||||
if not dotfile_suffix:
|
||||
return path
|
||||
return fixup_dotfile_path(path, dotfile_suffix, True)
|
||||
|
||||
def fixup_path_from_git(path):
|
||||
if not dotfile_suffix:
|
||||
return path
|
||||
return fixup_dotfile_path(path, dotfile_suffix, False)
|
||||
|
||||
def updatebookmarks(repo, peer):
|
||||
remotemarks = peer.listkeys(b'bookmarks')
|
||||
|
||||
@@ -749,7 +794,7 @@ def export_ref(repo, name, kind, head):
|
||||
puts(b"merge :%u" % (rev_to_mark(parents[1])))
|
||||
|
||||
for f in removed:
|
||||
puts(b"D %s" % (fix_file_path(f)))
|
||||
puts(b"D %s" % fixup_path_to_git(fix_file_path(f)))
|
||||
for f in modified_final:
|
||||
puts(b"M %s :%u %s" % f)
|
||||
puts()
|
||||
@@ -1042,6 +1087,7 @@ def parse_commit(parser):
|
||||
else:
|
||||
die(b'Unknown file command: %s' % line)
|
||||
path = c_style_unescape(path)
|
||||
path = fixup_path_from_git(path)
|
||||
files[path] = files.get(path, {})
|
||||
files[path].update(f)
|
||||
|
||||
@@ -1867,6 +1913,7 @@ def main(args):
|
||||
global capability_push
|
||||
global remove_username_quotes
|
||||
global marksdir
|
||||
global dotfile_suffix
|
||||
|
||||
marks = None
|
||||
is_tmp = False
|
||||
@@ -1886,6 +1933,7 @@ def main(args):
|
||||
track_branches = get_config_bool('remote-hg.track-branches', True)
|
||||
capability_push = get_config_bool('remote-hg.capability-push', True)
|
||||
remove_username_quotes = get_config_bool('remote-hg.remove-username-quotes', True)
|
||||
dotfile_suffix = get_config('remote-hg.dotfile-suffix').strip() or b'_'
|
||||
force_push = False
|
||||
|
||||
if hg_git_compat:
|
||||
|
||||
35
test/main.t
35
test/main.t
@@ -268,6 +268,41 @@ test_expect_success 'strip' '
|
||||
test_cmp actual expected
|
||||
'
|
||||
|
||||
test_expect_success 'dotfiles' '
|
||||
test_when_finished "rm -rf hgrepo gitrepo" &&
|
||||
|
||||
(
|
||||
hg init hgrepo &&
|
||||
cd hgrepo &&
|
||||
|
||||
echo one >.git &&
|
||||
echo ONE >.GIT &&
|
||||
mkdir a && echo two > a/.gitmodules &&
|
||||
hg add .git .GIT a/.gitmodules &&
|
||||
hg commit -m zero
|
||||
) &&
|
||||
|
||||
git clone "hg::hgrepo" gitrepo &&
|
||||
test_cmp gitrepo/.git_ hgrepo/.git &&
|
||||
test_cmp gitrepo/.GIT_ hgrepo/.GIT &&
|
||||
test_cmp gitrepo/a/.gitmodules_ hgrepo/a/.gitmodules &&
|
||||
|
||||
(
|
||||
cd gitrepo &&
|
||||
echo three >.git_ &&
|
||||
echo THREE >.GIT &&
|
||||
echo four >a/.gitmodules_ &&
|
||||
git add .git_ .GIT_ a/.gitmodules_ &&
|
||||
git commit -m one &&
|
||||
git push
|
||||
) &&
|
||||
|
||||
hg -R hgrepo update &&
|
||||
test_cmp gitrepo/.git_ hgrepo/.git &&
|
||||
test_cmp gitrepo/.GIT_ hgrepo/.GIT &&
|
||||
test_cmp gitrepo/a/.gitmodules_ hgrepo/a/.gitmodules
|
||||
'
|
||||
|
||||
test_expect_success 'remote push with master bookmark' '
|
||||
test_when_finished "rm -rf hgrepo gitrepo*" &&
|
||||
|
||||
|
||||
Reference in New Issue
Block a user