From 76be528c0d04e9ae5cd3f4dca5c887e5a194509a Mon Sep 17 00:00:00 2001 From: Mark Nauwelaerts Date: Mon, 27 Nov 2017 20:49:03 +0100 Subject: [PATCH] Optionally ignore some remote Mercurial revision names ... in particular when these would otherwise map to unsupported refnames. Fixes mnauw/git-remote-hg#10 --- README.asciidoc | 17 +++++++++++++++++ doc/git-remote-hg.txt | 8 ++++++++ git-remote-hg | 28 +++++++++++++++++++++++----- test/main.t | 22 ++++++++++++++++++++++ 4 files changed, 70 insertions(+), 5 deletions(-) diff --git a/README.asciidoc b/README.asciidoc index 3bc53b0..d0cdbe2 100644 --- a/README.asciidoc +++ b/README.asciidoc @@ -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 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 -------------------------------------- diff --git a/doc/git-remote-hg.txt b/doc/git-remote-hg.txt index 9ae2953..6a8d53b 100644 --- a/doc/git-remote-hg.txt +++ b/doc/git-remote-hg.txt @@ -94,6 +94,14 @@ for an existing repo: Note that one should perform a fetch from each remote to properly complete the 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 ----- diff --git a/git-remote-hg b/git-remote-hg index 9e21272..acf620b 100755 --- a/git-remote-hg +++ b/git-remote-hg @@ -96,8 +96,8 @@ def check_version(*check): return True return hg_version >= check -def get_config(config): - cmd = ['git', 'config', '--get', config] +def get_config(config, getall=False): + cmd = ['git', 'config', '--get' if not getall else '--get-all', config] process = subprocess.Popen(cmd, stdout=subprocess.PIPE) output, _ = process.communicate() return output @@ -707,6 +707,22 @@ def do_list(parser): 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 push command a fake one is provided # that avoids having the ref status reported as a new branch/tag @@ -717,18 +733,20 @@ def do_list(parser): if track_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: if bmarks[bmark].hex() == '0' * 40: warn("Ignoring invalid bookmark '%s'", bmark) - else: + elif not ignore('bookmark', bmark): print "%s refs/heads/%s" % (sha1, gitref(bmark)) for tag, node in repo.tagslist(): if tag == 'tip': continue - print "%s refs/tags/%s" % (sha1, gitref(tag)) + if not ignore('tag', tag): + print "%s refs/tags/%s" % (sha1, gitref(tag)) print diff --git a/test/main.t b/test/main.t index 9a94d11..35624de 100755 --- a/test/main.t +++ b/test/main.t @@ -1201,6 +1201,28 @@ test_expect_success 'clone replace directory with a 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" then test_done