Optionally ignore some remote Mercurial revision names

... in particular when these would otherwise map to unsupported refnames.

Fixes mnauw/git-remote-hg#10
This commit is contained in:
Mark Nauwelaerts
2017-11-27 20:49:03 +01:00
parent 6c2f4d8ff4
commit 76be528c0d
4 changed files with 70 additions and 5 deletions

View File

@@ -243,6 +243,23 @@ also be enabled on an existing one by the following setting.
-------------------------------------- --------------------------------------
Note, however, that one should then perform a fetch from each relevant remote Note, however, that one should then perform a fetch from each relevant remote
to fully complete the conversion (prior to subsequent pushing). to fully complete the conversion (prior to subsequent pushing).
Some Mercurial names (of branches, bookmarks, tags) may not be a valid git
refname. See e.g. `man git-check-ref-format` for a rather involved set of rules.
Moreover, while a slash `/` is allowed, it is not supported to have both a `parent`
and `parent/child` branch (though only the latter is allowed). So, pending some
"nice" bidirectional encoding (not even e.g. URL encoding is safe actually), it is more
likely that only a few instances (out of a whole Mercurial repo) are
problematic. This could be handled by a single-branch clone and/or configuring
a suitable refspec. However, it might be more convenient to simply filter out a
few unimportant pesky cases, which can be done by configuring a regural
expression in following setting:
--------------------------------------
% git config remote-hg.ignore-name nasty/nested/name
--------------------------------------
Recall also that a config setting can be provided at clone time
(command line using `--config` option).
-------------------------------------- --------------------------------------
% git config --global remote-hg.remove-username-quotes false % git config --global remote-hg.remove-username-quotes false
-------------------------------------- --------------------------------------

View File

@@ -94,6 +94,14 @@ for an existing repo:
Note that one should perform a fetch from each remote to properly complete the Note that one should perform a fetch from each remote to properly complete the
conversion to shared marks files. conversion to shared marks files.
Mercurial name(s) (of a branch or bookmark) that are not a valid git refname,
can be ignored by configuring a suitable regular expression, e.g. avoiding
the invalid '~'
--------------------------------------
% git config --global remote-hg.ignore-name ~
--------------------------------------
NOTES NOTES
----- -----

View File

@@ -96,8 +96,8 @@ def check_version(*check):
return True return True
return hg_version >= check return hg_version >= check
def get_config(config): def get_config(config, getall=False):
cmd = ['git', 'config', '--get', config] cmd = ['git', 'config', '--get' if not getall else '--get-all', config]
process = subprocess.Popen(cmd, stdout=subprocess.PIPE) process = subprocess.Popen(cmd, stdout=subprocess.PIPE)
output, _ = process.communicate() output, _ = process.communicate()
return output return output
@@ -707,6 +707,22 @@ def do_list(parser):
list_head(repo, cur) list_head(repo, cur)
ignore_ref = get_config('remote-hg.ignore-name', True)
ignore_re = []
for exp in ignore_ref.splitlines():
if exp:
try:
#warn("checking %s" % (
ignore_re.append(re.compile(exp.strip()))
except:
warn("Invalid regular expression '%s'" % (exp))
def ignore(kind, name):
for r in ignore_re:
if r.search(name):
warn("Ignoring matched %s %s" % (kind, name))
return True
return False
# for export command a ref's old_sha1 is taken from private namespace ref # for export command a ref's old_sha1 is taken from private namespace ref
# for push command a fake one is provided # for push command a fake one is provided
# that avoids having the ref status reported as a new branch/tag # that avoids having the ref status reported as a new branch/tag
@@ -717,18 +733,20 @@ def do_list(parser):
if track_branches: if track_branches:
for branch in branches: for branch in branches:
print "%s refs/heads/branches/%s" % (sha1, gitref(branch)) if not ignore('branch', branch):
print "%s refs/heads/branches/%s" % (sha1, gitref(branch))
for bmark in bmarks: for bmark in bmarks:
if bmarks[bmark].hex() == '0' * 40: if bmarks[bmark].hex() == '0' * 40:
warn("Ignoring invalid bookmark '%s'", bmark) warn("Ignoring invalid bookmark '%s'", bmark)
else: elif not ignore('bookmark', bmark):
print "%s refs/heads/%s" % (sha1, gitref(bmark)) print "%s refs/heads/%s" % (sha1, gitref(bmark))
for tag, node in repo.tagslist(): for tag, node in repo.tagslist():
if tag == 'tip': if tag == 'tip':
continue continue
print "%s refs/tags/%s" % (sha1, gitref(tag)) if not ignore('tag', tag):
print "%s refs/tags/%s" % (sha1, gitref(tag))
print print

View File

@@ -1201,6 +1201,28 @@ test_expect_success 'clone replace directory with a file' '
check_files gitrepo "dir_or_file" check_files gitrepo "dir_or_file"
' '
test_expect_success 'clone can ignore invalid refnames' '
test_when_finished "rm -rf hgrepo gitrepo" &&
(
hg init hgrepo &&
cd hgrepo &&
touch test.txt &&
hg add test.txt &&
hg commit -m master &&
hg branch parent &&
echo test >test.txt &&
hg commit -m test &&
hg branch parent/child &&
echo test1 >test.txt &&
hg commit -m test1
) &&
git clone -c remote-hg.ignore-name=child "hg::hgrepo" gitrepo &&
check_files gitrepo "test.txt"
'
if test "$CAPABILITY_PUSH" != "t" if test "$CAPABILITY_PUSH" != "t"
then then
test_done test_done