{"thread":{"id":"33575","subject":"[PATCH 00/16] remote-hg: second round of improvements","startedAt":"2013-04-22T21:55:08Z","lastAt":"2013-04-22T23:03:08Z","messageCount":24,"participants":["Felipe Contreras","Junio C Hamano","Dusty Phillips"],"isPatch":true,"patchVersion":1,"patchTotal":16},"messages":[{"id":"215160","messageId":"1366667724-567-1-git-send-email-felipe.contreras@gmail.com","threadId":"33575","inReplyTo":null,"subject":"[PATCH 00/16] remote-hg: second round of improvements","fromName":"Felipe Contreras","fromEmail":"felipe.contreras@gmail.com","sentAt":"2013-04-22T21:55:08Z","receivedAt":"2013-04-22T21:55:08Z","isPatch":true,"sender":{"key":"felipe.contreras@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8358?v=4"},"body":"Hi,\n\nNow that the safter first round is merged to master, it's time for the second\nround which is a little tricker. Most of the patches should be safe, but the\nlater ones might be not. All the tests pass, even gitifyhg ones, so everything\nseems to be fine, but we shall see.\n\nAmong the important changes are:\n\n * Proper support for tags (they are global, and we can push them)\n * Improved e-mail sanitaztion (a bit similar to gitifyhg, but better)\n * Support for hg schemes (like bb://felipec/repo)\n * Support for tags, bookmarks and branches with spaces\n * Performance improvements\n\nGood stuff we should probably merge to master if there are no issues.\n\nCheers.\n\nDusty Phillips (1):\n  remote-helpers: avoid has_key\n\nFelipe Contreras (15):\n  remote-hg: safer bookmark pushing\n  remote-hg: use python urlparse\n  remote-hg: properly mark branches up-to-date\n  remote-hg: add branch_tip() helper\n  remote-hg: add support for tag objects\n  remote-hg: custom method to write tags\n  remote-hg: write tags in the appropriate branch\n  remote-hg: add custom local tag write code\n  remote-hg: improve email sanitation\n  remote-hg: add support for schemes extension\n  remote-hg: don't update bookmarks unnecessarily\n  remote-hg: allow refs with spaces\n  remote-hg: small performance improvement\n  remote-hg: use marks instead of inlined files\n  remote-hg: strip extra newline\n\n contrib/remote-helpers/git-remote-bzr |   2 +-\n contrib/remote-helpers/git-remote-hg  | 167 +++++++++++++++++++++++++++-------\n contrib/remote-helpers/test-hg.sh     |   8 +-\n 3 files changed, 141 insertions(+), 36 deletions(-)\n\n-- \n1.8.2.1.790.g4588561\n"},{"id":"215161","messageId":"1366667724-567-2-git-send-email-felipe.contreras@gmail.com","threadId":"33575","inReplyTo":"1366667724-567-1-git-send-email-felipe.contreras@gmail.com","subject":"[PATCH 01/16] remote-helpers: avoid has_key","fromName":"Felipe Contreras","fromEmail":"felipe.contreras@gmail.com","sentAt":"2013-04-22T21:55:09Z","receivedAt":"2013-04-22T21:55:09Z","isPatch":true,"sender":{"key":"felipe.contreras@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8358?v=4"},"body":"From: Dusty Phillips <dusty@linux.ca>\n\nIt is deprecated.\n\n[fc: do the same in remote-bzr]\n\nSigned-off-by: Felipe Contreras <felipe.contreras@gmail.com>\n---\n contrib/remote-helpers/git-remote-bzr | 2 +-\n contrib/remote-helpers/git-remote-hg  | 2 +-\n 2 files changed, 2 insertions(+), 2 deletions(-)\n\ndiff --git a/contrib/remote-helpers/git-remote-bzr b/contrib/remote-helpers/git-remote-bzr\nindex aa7bc97..cc6609b 100755\n--- a/contrib/remote-helpers/git-remote-bzr\n+++ b/contrib/remote-helpers/git-remote-bzr\n@@ -94,7 +94,7 @@ class Marks:\n         return self.last_mark\n \n     def is_marked(self, rev):\n-        return self.marks.has_key(rev)\n+        return str(rev) in self.marks\n \n     def new_mark(self, rev, mark):\n         self.marks[rev] = mark\ndiff --git a/contrib/remote-helpers/git-remote-hg b/contrib/remote-helpers/git-remote-hg\nindex 5481331..2cd1996 100755\n--- a/contrib/remote-helpers/git-remote-hg\n+++ b/contrib/remote-helpers/git-remote-hg\n@@ -129,7 +129,7 @@ class Marks:\n         self.last_mark = mark\n \n     def is_marked(self, rev):\n-        return self.marks.has_key(str(rev))\n+        return str(rev) in self.marks\n \n     def get_tip(self, branch):\n         return self.tips.get(branch, 0)\n-- \n1.8.2.1.790.g4588561\n"},{"id":"215162","messageId":"1366667724-567-3-git-send-email-felipe.contreras@gmail.com","threadId":"33575","inReplyTo":"1366667724-567-1-git-send-email-felipe.contreras@gmail.com","subject":"[PATCH 02/16] remote-hg: safer bookmark pushing","fromName":"Felipe Contreras","fromEmail":"felipe.contreras@gmail.com","sentAt":"2013-04-22T21:55:10Z","receivedAt":"2013-04-22T21:55:10Z","isPatch":true,"sender":{"key":"felipe.contreras@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8358?v=4"},"body":"It is possible that the remote has changed the bookmarks, so let's fetch\nthem before we make any assumptions, just the way mercurial does.\n\nProbably doesn't make a difference, but better be safe than sorry.\n\nSigned-off-by: Felipe Contreras <felipe.contreras@gmail.com>\n---\n contrib/remote-helpers/git-remote-hg | 2 ++\n 1 file changed, 2 insertions(+)\n\ndiff --git a/contrib/remote-helpers/git-remote-hg b/contrib/remote-helpers/git-remote-hg\nindex 2cd1996..dcf6c98 100755\n--- a/contrib/remote-helpers/git-remote-hg\n+++ b/contrib/remote-helpers/git-remote-hg\n@@ -782,6 +782,8 @@ def do_export(parser):\n             continue\n \n         if peer:\n+            rb = peer.listkeys('bookmarks')\n+            old = rb.get(bmark, '')\n             if not peer.pushkey('bookmarks', bmark, old, new):\n                 print \"error %s\" % ref\n                 continue\n-- \n1.8.2.1.790.g4588561\n"},{"id":"215163","messageId":"1366667724-567-4-git-send-email-felipe.contreras@gmail.com","threadId":"33575","inReplyTo":"1366667724-567-1-git-send-email-felipe.contreras@gmail.com","subject":"[PATCH 03/16] remote-hg: use python urlparse","fromName":"Felipe Contreras","fromEmail":"felipe.contreras@gmail.com","sentAt":"2013-04-22T21:55:11Z","receivedAt":"2013-04-22T21:55:11Z","isPatch":true,"sender":{"key":"felipe.contreras@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8358?v=4"},"body":"It's simpler, and we don't need to depend on certain Mercurial versions.\n\nAlso, now we don't update the URL if 'file://' is not present.\n\nSigned-off-by: Felipe Contreras <felipe.contreras@gmail.com>\n---\n contrib/remote-helpers/git-remote-hg | 9 +++++----\n 1 file changed, 5 insertions(+), 4 deletions(-)\n\ndiff --git a/contrib/remote-helpers/git-remote-hg b/contrib/remote-helpers/git-remote-hg\nindex dcf6c98..b6589a3 100755\n--- a/contrib/remote-helpers/git-remote-hg\n+++ b/contrib/remote-helpers/git-remote-hg\n@@ -22,6 +22,7 @@ import shutil\n import subprocess\n import urllib\n import atexit\n+import urlparse\n \n #\n # If you want to switch to hg-git compatibility mode:\n@@ -793,11 +794,11 @@ def do_export(parser):\n     print\n \n def fix_path(alias, repo, orig_url):\n-    repo_url = util.url(repo.url())\n-    url = util.url(orig_url)\n-    if str(url) == str(repo_url):\n+    url = urlparse.urlparse(orig_url, 'file')\n+    if url.scheme != 'file' or os.path.isabs(url.path):\n         return\n-    cmd = ['git', 'config', 'remote.%s.url' % alias, \"hg::%s\" % repo_url]\n+    abs_url = urlparse.urljoin(\"%s/\" % os.getcwd(), orig_url)\n+    cmd = ['git', 'config', 'remote.%s.url' % alias, \"hg::%s\" % abs_url]\n     subprocess.call(cmd)\n \n def main(args):\n-- \n1.8.2.1.790.g4588561\n"},{"id":"215165","messageId":"1366667724-567-5-git-send-email-felipe.contreras@gmail.com","threadId":"33575","inReplyTo":"1366667724-567-1-git-send-email-felipe.contreras@gmail.com","subject":"[PATCH 04/16] remote-hg: properly mark branches up-to-date","fromName":"Felipe Contreras","fromEmail":"felipe.contreras@gmail.com","sentAt":"2013-04-22T21:55:12Z","receivedAt":"2013-04-22T21:55:12Z","isPatch":true,"sender":{"key":"felipe.contreras@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8358?v=4"},"body":"Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>\n---\n contrib/remote-helpers/git-remote-hg | 4 ++++\n 1 file changed, 4 insertions(+)\n\ndiff --git a/contrib/remote-helpers/git-remote-hg b/contrib/remote-helpers/git-remote-hg\nindex b6589a3..a4db5b0 100755\n--- a/contrib/remote-helpers/git-remote-hg\n+++ b/contrib/remote-helpers/git-remote-hg\n@@ -742,6 +742,10 @@ def do_export(parser):\n \n     for ref, node in parsed_refs.iteritems():\n         if ref.startswith('refs/heads/branches'):\n+            branch = ref[len('refs/heads/branches/'):]\n+            if branch in branches and node in branches[branch]:\n+                # up to date\n+                continue\n             print \"ok %s\" % ref\n         elif ref.startswith('refs/heads/'):\n             bmark = ref[len('refs/heads/'):]\n-- \n1.8.2.1.790.g4588561\n"},{"id":"215164","messageId":"1366667724-567-6-git-send-email-felipe.contreras@gmail.com","threadId":"33575","inReplyTo":"1366667724-567-1-git-send-email-felipe.contreras@gmail.com","subject":"[PATCH 05/16] remote-hg: add branch_tip() helper","fromName":"Felipe Contreras","fromEmail":"felipe.contreras@gmail.com","sentAt":"2013-04-22T21:55:13Z","receivedAt":"2013-04-22T21:55:13Z","isPatch":true,"sender":{"key":"felipe.contreras@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8358?v=4"},"body":"Idea from gitifyhg, the backwards compatibility is how Mercurial used to\ndo it.\n\nSigned-off-by: Felipe Contreras <felipe.contreras@gmail.com>\n---\n contrib/remote-helpers/git-remote-hg | 11 ++++++++---\n 1 file changed, 8 insertions(+), 3 deletions(-)\n\ndiff --git a/contrib/remote-helpers/git-remote-hg b/contrib/remote-helpers/git-remote-hg\nindex a4db5b0..bd93f82 100755\n--- a/contrib/remote-helpers/git-remote-hg\n+++ b/contrib/remote-helpers/git-remote-hg\n@@ -457,6 +457,13 @@ def do_capabilities(parser):\n \n     print\n \n+def branch_tip(repo, branch):\n+    # older versions of mercurial don't have this\n+    if hasattr(repo, 'branchtip'):\n+        return repo.branchtip(branch)\n+    else:\n+        return repo.branchtags()[branch]\n+\n def get_branch_tip(repo, branch):\n     global branches\n \n@@ -467,9 +474,7 @@ def get_branch_tip(repo, branch):\n     # verify there's only one head\n     if (len(heads) > 1):\n         warn(\"Branch '%s' has more than one head, consider merging\" % branch)\n-        # older versions of mercurial don't have this\n-        if hasattr(repo, \"branchtip\"):\n-            return repo.branchtip(branch)\n+        return branch_tip(repo, branch)\n \n     return heads[0]\n \n-- \n1.8.2.1.790.g4588561\n"},{"id":"215166","messageId":"1366667724-567-7-git-send-email-felipe.contreras@gmail.com","threadId":"33575","inReplyTo":"1366667724-567-1-git-send-email-felipe.contreras@gmail.com","subject":"[PATCH 06/16] remote-hg: add support for tag objects","fromName":"Felipe Contreras","fromEmail":"felipe.contreras@gmail.com","sentAt":"2013-04-22T21:55:14Z","receivedAt":"2013-04-22T21:55:14Z","isPatch":true,"sender":{"key":"felipe.contreras@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8358?v=4"},"body":"Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>\n---\n contrib/remote-helpers/git-remote-hg | 10 +++++++---\n 1 file changed, 7 insertions(+), 3 deletions(-)\n\ndiff --git a/contrib/remote-helpers/git-remote-hg b/contrib/remote-helpers/git-remote-hg\nindex bd93f82..4a1c637 100755\n--- a/contrib/remote-helpers/git-remote-hg\n+++ b/contrib/remote-helpers/git-remote-hg\n@@ -722,7 +722,7 @@ def parse_tag(parser):\n     data = parser.get_data()\n     parser.next()\n \n-    # nothing to do\n+    parsed_tags[name] = (tagger, data)\n \n def do_export(parser):\n     global parsed_refs, bmarks, peer\n@@ -758,9 +758,11 @@ def do_export(parser):\n             continue\n         elif ref.startswith('refs/tags/'):\n             tag = ref[len('refs/tags/'):]\n+            author, msg = parsed_tags.get(tag, (None, None))\n             if mode == 'git':\n-                msg = 'Added tag %s for changeset %s' % (tag, hghex(node[:6]));\n-                parser.repo.tag([tag], node, msg, False, None, {})\n+                if not msg:\n+                    msg = 'Added tag %s for changeset %s' % (tag, hghex(node[:6]));\n+                parser.repo.tag([tag], node, msg, False, author[0], {})\n             else:\n                 parser.repo.tag([tag], node, None, True, None, {})\n             print \"ok %s\" % ref\n@@ -815,6 +817,7 @@ def main(args):\n     global marks, blob_marks, parsed_refs\n     global peer, mode, bad_mail, bad_name\n     global track_branches, force_push, is_tmp\n+    global parsed_tags\n \n     alias = args[1]\n     url = args[2]\n@@ -857,6 +860,7 @@ def main(args):\n     blob_marks = {}\n     parsed_refs = {}\n     marks = None\n+    parsed_tags = {}\n \n     repo = get_repo(url, alias)\n     prefix = 'refs/hg/%s' % alias\n-- \n1.8.2.1.790.g4588561\n"},{"id":"215167","messageId":"1366667724-567-8-git-send-email-felipe.contreras@gmail.com","threadId":"33575","inReplyTo":"1366667724-567-1-git-send-email-felipe.contreras@gmail.com","subject":"[PATCH 07/16] remote-hg: custom method to write tags","fromName":"Felipe Contreras","fromEmail":"felipe.contreras@gmail.com","sentAt":"2013-04-22T21:55:15Z","receivedAt":"2013-04-22T21:55:15Z","isPatch":true,"sender":{"key":"felipe.contreras@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8358?v=4"},"body":"The one from mercurial is meant for users, on top of the latest tip.\n\nSigned-off-by: Felipe Contreras <felipe.contreras@gmail.com>\n---\n contrib/remote-helpers/git-remote-hg | 33 ++++++++++++++++++++++++++++++++-\n 1 file changed, 32 insertions(+), 1 deletion(-)\n\ndiff --git a/contrib/remote-helpers/git-remote-hg b/contrib/remote-helpers/git-remote-hg\nindex 4a1c637..f5e4ba7 100755\n--- a/contrib/remote-helpers/git-remote-hg\n+++ b/contrib/remote-helpers/git-remote-hg\n@@ -724,6 +724,37 @@ def parse_tag(parser):\n \n     parsed_tags[name] = (tagger, data)\n \n+def write_tag(repo, tag, node, msg, author):\n+    tip = repo['tip']\n+\n+    def getfilectx(repo, memctx, f):\n+        try:\n+            fctx = tip.filectx(f)\n+            data = fctx.data()\n+        except error.ManifestLookupError:\n+            data = \"\"\n+        content = data + \"%s %s\\n\" % (hghex(node), tag)\n+        return context.memfilectx(f, content, False, False, None)\n+\n+    p1 = tip.hex()\n+    p2 = '\\0' * 20\n+    if not author:\n+        author = (None, 0, 0)\n+    user, date, tz = author\n+\n+    ctx = context.memctx(repo, (p1, p2), msg,\n+            ['.hgtags'], getfilectx,\n+            user, (date, tz), {})\n+\n+    tmp = encoding.encoding\n+    encoding.encoding = 'utf-8'\n+\n+    tagnode = repo.commitctx(ctx)\n+\n+    encoding.encoding = tmp\n+\n+    return tagnode\n+\n def do_export(parser):\n     global parsed_refs, bmarks, peer\n \n@@ -762,7 +793,7 @@ def do_export(parser):\n             if mode == 'git':\n                 if not msg:\n                     msg = 'Added tag %s for changeset %s' % (tag, hghex(node[:6]));\n-                parser.repo.tag([tag], node, msg, False, author[0], {})\n+                write_tag(parser.repo, tag, node, msg, author)\n             else:\n                 parser.repo.tag([tag], node, None, True, None, {})\n             print \"ok %s\" % ref\n-- \n1.8.2.1.790.g4588561\n"},{"id":"215168","messageId":"1366667724-567-9-git-send-email-felipe.contreras@gmail.com","threadId":"33575","inReplyTo":"1366667724-567-1-git-send-email-felipe.contreras@gmail.com","subject":"[PATCH 08/16] remote-hg: write tags in the appropriate branch","fromName":"Felipe Contreras","fromEmail":"felipe.contreras@gmail.com","sentAt":"2013-04-22T21:55:16Z","receivedAt":"2013-04-22T21:55:16Z","isPatch":true,"sender":{"key":"felipe.contreras@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8358?v=4"},"body":"Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>\n---\n contrib/remote-helpers/git-remote-hg | 6 ++++--\n 1 file changed, 4 insertions(+), 2 deletions(-)\n\ndiff --git a/contrib/remote-helpers/git-remote-hg b/contrib/remote-helpers/git-remote-hg\nindex f5e4ba7..f685990 100755\n--- a/contrib/remote-helpers/git-remote-hg\n+++ b/contrib/remote-helpers/git-remote-hg\n@@ -725,7 +725,9 @@ def parse_tag(parser):\n     parsed_tags[name] = (tagger, data)\n \n def write_tag(repo, tag, node, msg, author):\n-    tip = repo['tip']\n+    branch = repo[node].branch()\n+    tip = branch_tip(repo, branch)\n+    tip = repo[tip]\n \n     def getfilectx(repo, memctx, f):\n         try:\n@@ -744,7 +746,7 @@ def write_tag(repo, tag, node, msg, author):\n \n     ctx = context.memctx(repo, (p1, p2), msg,\n             ['.hgtags'], getfilectx,\n-            user, (date, tz), {})\n+            user, (date, tz), {'branch' : branch})\n \n     tmp = encoding.encoding\n     encoding.encoding = 'utf-8'\n-- \n1.8.2.1.790.g4588561\n"},{"id":"215169","messageId":"1366667724-567-10-git-send-email-felipe.contreras@gmail.com","threadId":"33575","inReplyTo":"1366667724-567-1-git-send-email-felipe.contreras@gmail.com","subject":"[PATCH 09/16] remote-hg: add custom local tag write code","fromName":"Felipe Contreras","fromEmail":"felipe.contreras@gmail.com","sentAt":"2013-04-22T21:55:17Z","receivedAt":"2013-04-22T21:55:17Z","isPatch":true,"sender":{"key":"felipe.contreras@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8358?v=4"},"body":"There's no point in calling the tag method for such simple action. Not\nthat we care much about the hg-git compat mode, it's mostly just for\ncomparison testing purposes.\n\nSigned-off-by: Felipe Contreras <felipe.contreras@gmail.com>\n---\n contrib/remote-helpers/git-remote-hg | 4 +++-\n 1 file changed, 3 insertions(+), 1 deletion(-)\n\ndiff --git a/contrib/remote-helpers/git-remote-hg b/contrib/remote-helpers/git-remote-hg\nindex f685990..3c6eeb7 100755\n--- a/contrib/remote-helpers/git-remote-hg\n+++ b/contrib/remote-helpers/git-remote-hg\n@@ -797,7 +797,9 @@ def do_export(parser):\n                     msg = 'Added tag %s for changeset %s' % (tag, hghex(node[:6]));\n                 write_tag(parser.repo, tag, node, msg, author)\n             else:\n-                parser.repo.tag([tag], node, None, True, None, {})\n+                fp = parser.repo.opener('localtags', 'a')\n+                fp.write('%s %s\\n' % (hghex(node), tag))\n+                fp.close()\n             print \"ok %s\" % ref\n         else:\n             # transport-helper/fast-export bugs\n-- \n1.8.2.1.790.g4588561\n"},{"id":"215170","messageId":"1366667724-567-11-git-send-email-felipe.contreras@gmail.com","threadId":"33575","inReplyTo":"1366667724-567-1-git-send-email-felipe.contreras@gmail.com","subject":"[PATCH 10/16] remote-hg: improve email sanitation","fromName":"Felipe Contreras","fromEmail":"felipe.contreras@gmail.com","sentAt":"2013-04-22T21:55:18Z","receivedAt":"2013-04-22T21:55:18Z","isPatch":true,"sender":{"key":"felipe.contreras@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8358?v=4"},"body":"Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>\n---\n contrib/remote-helpers/git-remote-hg | 10 ++++++++--\n contrib/remote-helpers/test-hg.sh    |  8 ++++----\n 2 files changed, 12 insertions(+), 6 deletions(-)\n\ndiff --git a/contrib/remote-helpers/git-remote-hg b/contrib/remote-helpers/git-remote-hg\nindex 3c6eeb7..0084709 100755\n--- a/contrib/remote-helpers/git-remote-hg\n+++ b/contrib/remote-helpers/git-remote-hg\n@@ -51,6 +51,7 @@ import urlparse\n \n NAME_RE = re.compile('^([^<>]+)')\n AUTHOR_RE = re.compile('^([^<>]+?)? ?<([^<>]*)>$')\n+EMAIL_RE = re.compile('^([^<>]+[^ \\\\\\t<>])?\\\\b(?:[ \\\\t<>]*?)\\\\b([^ \\\\t<>]+@[^ \\\\t<>]+)')\n AUTHOR_HG_RE = re.compile('^(.*?) ?<(.*?)(?:>(.+)?)?$')\n RAW_AUTHOR_RE = re.compile('^(\\w+) (?:(.+)? )?<(.*)> (\\d+) ([+-]\\d+)')\n \n@@ -245,9 +246,14 @@ def fixup_user_git(user):\n         name = m.group(1)\n         mail = m.group(2).strip()\n     else:\n-        m = NAME_RE.match(user)\n+        m = EMAIL_RE.match(user)\n         if m:\n-            name = m.group(1).strip()\n+            name = m.group(1)\n+            mail = m.group(2)\n+        else:\n+            m = NAME_RE.match(user)\n+            if m:\n+                name = m.group(1).strip()\n     return (name, mail)\n \n def fixup_user_hg(user):\ndiff --git a/contrib/remote-helpers/test-hg.sh b/contrib/remote-helpers/test-hg.sh\nindex d5b8730..8de2aa7 100755\n--- a/contrib/remote-helpers/test-hg.sh\n+++ b/contrib/remote-helpers/test-hg.sh\n@@ -137,15 +137,15 @@ test_expect_success 'authors' '\n \n   author_test alpha \"\" \"H G Wells <wells@example.com>\" &&\n   author_test beta \"test\" \"test <unknown>\" &&\n-  author_test beta \"test <test@example.com> (comment)\" \"test <unknown>\" &&\n+  author_test beta \"test <test@example.com> (comment)\" \"test <test@example.com>\" &&\n   author_test gamma \"<test@example.com>\" \"Unknown <test@example.com>\" &&\n   author_test delta \"name<test@example.com>\" \"name <test@example.com>\" &&\n-  author_test epsilon \"name <test@example.com\" \"name <unknown>\" &&\n+  author_test epsilon \"name <test@example.com\" \"name <test@example.com>\" &&\n   author_test zeta \" test \" \"test <unknown>\" &&\n   author_test eta \"test < test@example.com >\" \"test <test@example.com>\" &&\n-  author_test theta \"test >test@example.com>\" \"test <unknown>\" &&\n+  author_test theta \"test >test@example.com>\" \"test <test@example.com>\" &&\n   author_test iota \"test < test <at> example <dot> com>\" \"test <unknown>\" &&\n-  author_test kappa \"test@example.com\" \"test@example.com <unknown>\"\n+  author_test kappa \"test@example.com\" \"Unknown <test@example.com>\"\n   ) &&\n \n   git clone \"hg::$PWD/hgrepo\" gitrepo &&\n-- \n1.8.2.1.790.g4588561\n"},{"id":"215171","messageId":"1366667724-567-12-git-send-email-felipe.contreras@gmail.com","threadId":"33575","inReplyTo":"1366667724-567-1-git-send-email-felipe.contreras@gmail.com","subject":"[PATCH 11/16] remote-hg: add support for schemes extension","fromName":"Felipe Contreras","fromEmail":"felipe.contreras@gmail.com","sentAt":"2013-04-22T21:55:19Z","receivedAt":"2013-04-22T21:55:19Z","isPatch":true,"sender":{"key":"felipe.contreras@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8358?v=4"},"body":"So that we can use shortened URLs, for example 'bb:://felipec/repo'\n(Bitbucket).\n\nSigned-off-by: Felipe Contreras <felipe.contreras@gmail.com>\n---\n contrib/remote-helpers/git-remote-hg | 8 +++++++-\n 1 file changed, 7 insertions(+), 1 deletion(-)\n\ndiff --git a/contrib/remote-helpers/git-remote-hg b/contrib/remote-helpers/git-remote-hg\nindex 0084709..4f6c7b7 100755\n--- a/contrib/remote-helpers/git-remote-hg\n+++ b/contrib/remote-helpers/git-remote-hg\n@@ -12,7 +12,7 @@\n # For remote repositories a local clone is stored in\n # \"$GIT_DIR/hg/origin/clone/.hg/\".\n \n-from mercurial import hg, ui, bookmarks, context, util, encoding, node, error\n+from mercurial import hg, ui, bookmarks, context, util, encoding, node, error, extensions\n \n import re\n import sys\n@@ -305,6 +305,12 @@ def get_repo(url, alias):\n     except subprocess.CalledProcessError:\n         pass\n \n+    try:\n+        mod = extensions.load(myui, 'hgext.schemes', None)\n+        mod.extsetup(myui)\n+    except ImportError:\n+        pass\n+\n     if hg.islocal(url):\n         repo = hg.repository(myui, url)\n     else:\n-- \n1.8.2.1.790.g4588561\n"},{"id":"215173","messageId":"1366667724-567-13-git-send-email-felipe.contreras@gmail.com","threadId":"33575","inReplyTo":"1366667724-567-1-git-send-email-felipe.contreras@gmail.com","subject":"[PATCH 12/16] remote-hg: don't update bookmarks unnecessarily","fromName":"Felipe Contreras","fromEmail":"felipe.contreras@gmail.com","sentAt":"2013-04-22T21:55:20Z","receivedAt":"2013-04-22T21:55:20Z","isPatch":true,"sender":{"key":"felipe.contreras@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8358?v=4"},"body":"Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>\n---\n contrib/remote-helpers/git-remote-hg | 3 +++\n 1 file changed, 3 insertions(+)\n\ndiff --git a/contrib/remote-helpers/git-remote-hg b/contrib/remote-helpers/git-remote-hg\nindex 4f6c7b7..dbb4091 100755\n--- a/contrib/remote-helpers/git-remote-hg\n+++ b/contrib/remote-helpers/git-remote-hg\n@@ -830,6 +830,9 @@ def do_export(parser):\n         else:\n             old = ''\n \n+        if old == new:\n+            continue\n+\n         if bmark == 'master' and 'master' not in parser.repo._bookmarks:\n             # fake bookmark\n             pass\n-- \n1.8.2.1.790.g4588561\n"},{"id":"215174","messageId":"1366667724-567-14-git-send-email-felipe.contreras@gmail.com","threadId":"33575","inReplyTo":"1366667724-567-1-git-send-email-felipe.contreras@gmail.com","subject":"[PATCH 13/16] remote-hg: allow refs with spaces","fromName":"Felipe Contreras","fromEmail":"felipe.contreras@gmail.com","sentAt":"2013-04-22T21:55:21Z","receivedAt":"2013-04-22T21:55:21Z","isPatch":true,"sender":{"key":"felipe.contreras@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8358?v=4"},"body":"Mercurial supports them, Git doesn't.\n\nSigned-off-by: Felipe Contreras <felipe.contreras@gmail.com>\n---\n contrib/remote-helpers/git-remote-hg | 25 +++++++++++++++++--------\n 1 file changed, 17 insertions(+), 8 deletions(-)\n\ndiff --git a/contrib/remote-helpers/git-remote-hg b/contrib/remote-helpers/git-remote-hg\nindex dbb4091..6f4afd7 100755\n--- a/contrib/remote-helpers/git-remote-hg\n+++ b/contrib/remote-helpers/git-remote-hg\n@@ -75,6 +75,12 @@ def hgmode(mode):\n def hghex(node):\n     return hg.node.hex(node)\n \n+def hgref(ref):\n+    return ref.replace('___', ' ')\n+\n+def gitref(ref):\n+    return ref.replace(' ', '___')\n+\n def get_config(config):\n     cmd = ['git', 'config', '--get', config]\n     process = subprocess.Popen(cmd, stdout=subprocess.PIPE)\n@@ -437,10 +443,10 @@ def export_ref(repo, name, kind, head):\n     marks.set_tip(ename, rev)\n \n def export_tag(repo, tag):\n-    export_ref(repo, tag, 'tags', repo[tag])\n+    export_ref(repo, tag, 'tags', repo[hgref(tag)])\n \n def export_bookmark(repo, bmark):\n-    head = bmarks[bmark]\n+    head = bmarks[hgref(bmark)]\n     export_ref(repo, bmark, 'bookmarks', head)\n \n def export_branch(repo, branch):\n@@ -479,14 +485,14 @@ def branch_tip(repo, branch):\n def get_branch_tip(repo, branch):\n     global branches\n \n-    heads = branches.get(branch, None)\n+    heads = branches.get(hgref(branch), None)\n     if not heads:\n         return None\n \n     # verify there's only one head\n     if (len(heads) > 1):\n         warn(\"Branch '%s' has more than one head, consider merging\" % branch)\n-        return branch_tip(repo, branch)\n+        return branch_tip(repo, hgref(branch))\n \n     return heads[0]\n \n@@ -508,6 +514,7 @@ def list_head(repo, cur):\n             head = 'master'\n         bmarks[head] = node\n \n+    head = gitref(head)\n     print \"@refs/heads/%s HEAD\" % head\n     g_head = (head, node)\n \n@@ -529,15 +536,15 @@ def do_list(parser):\n                 branches[branch] = heads\n \n         for branch in branches:\n-            print \"? refs/heads/branches/%s\" % branch\n+            print \"? refs/heads/branches/%s\" % gitref(branch)\n \n     for bmark in bmarks:\n-        print \"? refs/heads/%s\" % bmark\n+        print \"? refs/heads/%s\" % gitref(bmark)\n \n     for tag, node in repo.tagslist():\n         if tag == 'tip':\n             continue\n-        print \"? refs/tags/%s\" % tag\n+        print \"? refs/tags/%s\" % gitref(tag)\n \n     print\n \n@@ -674,7 +681,8 @@ def parse_commit(parser):\n \n     # Check if the ref is supposed to be a named branch\n     if ref.startswith('refs/heads/branches/'):\n-        extra['branch'] = ref[len('refs/heads/branches/'):]\n+        branch = ref[len('refs/heads/branches/'):]\n+        extra['branch'] = hgref(branch)\n \n     if mode == 'hg':\n         i = data.find('\\n--HG--\\n')\n@@ -803,6 +811,7 @@ def do_export(parser):\n             continue\n         elif ref.startswith('refs/tags/'):\n             tag = ref[len('refs/tags/'):]\n+            tag = hgref(tag)\n             author, msg = parsed_tags.get(tag, (None, None))\n             if mode == 'git':\n                 if not msg:\n-- \n1.8.2.1.790.g4588561\n"},{"id":"215175","messageId":"1366667724-567-15-git-send-email-felipe.contreras@gmail.com","threadId":"33575","inReplyTo":"1366667724-567-1-git-send-email-felipe.contreras@gmail.com","subject":"[PATCH 14/16] remote-hg: small performance improvement","fromName":"Felipe Contreras","fromEmail":"felipe.contreras@gmail.com","sentAt":"2013-04-22T21:55:22Z","receivedAt":"2013-04-22T21:55:22Z","isPatch":true,"sender":{"key":"felipe.contreras@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8358?v=4"},"body":"Load previous manifest first as Mercurial does; for caching reasons.\n\nSigned-off-by: Felipe Contreras <felipe.contreras@gmail.com>\n---\n contrib/remote-helpers/git-remote-hg | 3 ++-\n 1 file changed, 2 insertions(+), 1 deletion(-)\n\ndiff --git a/contrib/remote-helpers/git-remote-hg b/contrib/remote-helpers/git-remote-hg\nindex 6f4afd7..f80236b 100755\n--- a/contrib/remote-helpers/git-remote-hg\n+++ b/contrib/remote-helpers/git-remote-hg\n@@ -230,8 +230,9 @@ def get_filechanges(repo, ctx, parent):\n     added = set()\n     removed = set()\n \n-    cur = ctx.manifest()\n+    # load earliest manifest first for caching reasons\n     prev = repo[parent].manifest().copy()\n+    cur = ctx.manifest()\n \n     for fn in cur:\n         if fn in prev:\n-- \n1.8.2.1.790.g4588561\n"},{"id":"215176","messageId":"1366667724-567-16-git-send-email-felipe.contreras@gmail.com","threadId":"33575","inReplyTo":"1366667724-567-1-git-send-email-felipe.contreras@gmail.com","subject":"[PATCH 15/16] remote-hg: use marks instead of inlined files","fromName":"Felipe Contreras","fromEmail":"felipe.contreras@gmail.com","sentAt":"2013-04-22T21:55:23Z","receivedAt":"2013-04-22T21:55:23Z","isPatch":true,"sender":{"key":"felipe.contreras@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8358?v=4"},"body":"So that we can find already exported ones. We can never be 100% sure\nthat we already exported such data, due to mercurial design, it at least\nsometimes we should detect them, and so should give ups some performance\nboost.\n\nSigned-off-by: Felipe Contreras <felipe.contreras@gmail.com>\n---\n contrib/remote-helpers/git-remote-hg | 41 +++++++++++++++++++++++++++++-------\n 1 file changed, 33 insertions(+), 8 deletions(-)\n\ndiff --git a/contrib/remote-helpers/git-remote-hg b/contrib/remote-helpers/git-remote-hg\nindex f80236b..d0e552c 100755\n--- a/contrib/remote-helpers/git-remote-hg\n+++ b/contrib/remote-helpers/git-remote-hg\n@@ -126,6 +126,10 @@ class Marks:\n     def to_rev(self, mark):\n         return self.rev_marks[mark]\n \n+    def next_mark(self):\n+        self.last_mark += 1\n+        return self.last_mark\n+\n     def get_mark(self, rev):\n         self.last_mark += 1\n         self.marks[str(rev)] = self.last_mark\n@@ -218,12 +222,29 @@ def fix_file_path(path):\n         return path\n     return os.path.relpath(path, '/')\n \n-def export_file(fc):\n-    d = fc.data()\n-    path = fix_file_path(fc.path())\n-    print \"M %s inline %s\" % (gitmode(fc.flags()), path)\n-    print \"data %d\" % len(d)\n-    print d\n+def export_files(files):\n+    global marks, filenodes\n+\n+    final = []\n+    for f in files:\n+        fid = node.hex(f.filenode())\n+\n+        if fid in filenodes:\n+            mark = filenodes[fid]\n+        else:\n+            mark = marks.next_mark()\n+            filenodes[fid] = mark\n+            d = f.data()\n+\n+            print \"blob\"\n+            print \"mark :%u\" % mark\n+            print \"data %d\" % len(d)\n+            print d\n+\n+        path = fix_file_path(f.path())\n+        final.append((gitmode(f.flags()), mark, path))\n+\n+    return final\n \n def get_filechanges(repo, ctx, parent):\n     modified = set()\n@@ -413,6 +434,8 @@ def export_ref(repo, name, kind, head):\n         if len(parents) == 0 and rev:\n             print 'reset %s/%s' % (prefix, ename)\n \n+        modified_final = export_files(c.filectx(f) for f in modified)\n+\n         print \"commit %s/%s\" % (prefix, ename)\n         print \"mark :%d\" % (marks.get_mark(rev))\n         print \"author %s\" % (author)\n@@ -425,8 +448,8 @@ def export_ref(repo, name, kind, head):\n             if len(parents) > 1:\n                 print \"merge :%s\" % (rev_to_mark(parents[1]))\n \n-        for f in modified:\n-            export_file(c.filectx(f))\n+        for f in modified_final:\n+            print \"M %s :%u %s\" % f\n         for f in removed:\n             print \"D %s\" % (fix_file_path(f))\n         print\n@@ -878,6 +901,7 @@ def main(args):\n     global peer, mode, bad_mail, bad_name\n     global track_branches, force_push, is_tmp\n     global parsed_tags\n+    global filenodes\n \n     alias = args[1]\n     url = args[2]\n@@ -921,6 +945,7 @@ def main(args):\n     parsed_refs = {}\n     marks = None\n     parsed_tags = {}\n+    filenodes = {}\n \n     repo = get_repo(url, alias)\n     prefix = 'refs/hg/%s' % alias\n-- \n1.8.2.1.790.g4588561\n"},{"id":"215177","messageId":"1366667724-567-17-git-send-email-felipe.contreras@gmail.com","threadId":"33575","inReplyTo":"1366667724-567-1-git-send-email-felipe.contreras@gmail.com","subject":"[PATCH 16/16] remote-hg: strip extra newline","fromName":"Felipe Contreras","fromEmail":"felipe.contreras@gmail.com","sentAt":"2013-04-22T21:55:24Z","receivedAt":"2013-04-22T21:55:24Z","isPatch":true,"sender":{"key":"felipe.contreras@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8358?v=4"},"body":"There's no functional change since mercurial commit operation strips\nthat anyway, but that's no excuse for us not to do the right thing. So\nlet's be explicit about it.\n\nSigned-off-by: Felipe Contreras <felipe.contreras@gmail.com>\n---\n contrib/remote-helpers/git-remote-hg | 4 ++++\n 1 file changed, 4 insertions(+)\n\ndiff --git a/contrib/remote-helpers/git-remote-hg b/contrib/remote-helpers/git-remote-hg\nindex d0e552c..fda4199 100755\n--- a/contrib/remote-helpers/git-remote-hg\n+++ b/contrib/remote-helpers/git-remote-hg\n@@ -652,6 +652,10 @@ def parse_commit(parser):\n         if parser.check('merge'):\n             die('octopus merges are not supported yet')\n \n+    # fast-export adds an extra newline\n+    if data[-1] == '\\n':\n+        data = data[:-1]\n+\n     files = {}\n \n     for line in parser:\n-- \n1.8.2.1.790.g4588561\n"},{"id":"215182","messageId":"7va9oqnqs9.fsf@alter.siamese.dyndns.org","threadId":"33575","inReplyTo":"1366667724-567-2-git-send-email-felipe.contreras@gmail.com","subject":"Re: [PATCH 01/16] remote-helpers: avoid has_key","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2013-04-22T22:28:54Z","receivedAt":"2013-04-22T22:28:54Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Felipe Contreras <felipe.contreras@gmail.com> writes:\n\n> From: Dusty Phillips <dusty@linux.ca>\n>\n> It is deprecated.\n>\n> [fc: do the same in remote-bzr]\n>\n> Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>\n> ---\n\nNo sign-off by the author?\n\nIt does not matter for something so trivial like this that there is\nno other way to write, but it is a good habit you should encourage\nyour contributors to acquire, so that you do not have to waste time\nwith \"please sign off\" when their next contribution that is more\nsubstantial comes.\n\n>  contrib/remote-helpers/git-remote-bzr | 2 +-\n>  contrib/remote-helpers/git-remote-hg  | 2 +-\n>  2 files changed, 2 insertions(+), 2 deletions(-)\n>\n> diff --git a/contrib/remote-helpers/git-remote-bzr b/contrib/remote-helpers/git-remote-bzr\n> index aa7bc97..cc6609b 100755\n> --- a/contrib/remote-helpers/git-remote-bzr\n> +++ b/contrib/remote-helpers/git-remote-bzr\n> @@ -94,7 +94,7 @@ class Marks:\n>          return self.last_mark\n>  \n>      def is_marked(self, rev):\n> -        return self.marks.has_key(rev)\n> +        return str(rev) in self.marks\n>  \n>      def new_mark(self, rev, mark):\n>          self.marks[rev] = mark\n> diff --git a/contrib/remote-helpers/git-remote-hg b/contrib/remote-helpers/git-remote-hg\n> index 5481331..2cd1996 100755\n> --- a/contrib/remote-helpers/git-remote-hg\n> +++ b/contrib/remote-helpers/git-remote-hg\n> @@ -129,7 +129,7 @@ class Marks:\n>          self.last_mark = mark\n>  \n>      def is_marked(self, rev):\n> -        return self.marks.has_key(str(rev))\n> +        return str(rev) in self.marks\n>  \n>      def get_tip(self, branch):\n>          return self.tips.get(branch, 0)\n"},{"id":"215183","messageId":"7v61zenqm4.fsf@alter.siamese.dyndns.org","threadId":"33575","inReplyTo":"1366667724-567-14-git-send-email-felipe.contreras@gmail.com","subject":"Re: [PATCH 13/16] remote-hg: allow refs with spaces","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2013-04-22T22:32:35Z","receivedAt":"2013-04-22T22:32:35Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Felipe Contreras <felipe.contreras@gmail.com> writes:\n\n> Mercurial supports them, Git doesn't.\n\nAnother important thing to note is that you represent a SP with\nthree underscores on our side, no?\n\n> Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>\n> ---\n>  contrib/remote-helpers/git-remote-hg | 25 +++++++++++++++++--------\n>  1 file changed, 17 insertions(+), 8 deletions(-)\n>\n> diff --git a/contrib/remote-helpers/git-remote-hg b/contrib/remote-helpers/git-remote-hg\n> index dbb4091..6f4afd7 100755\n> --- a/contrib/remote-helpers/git-remote-hg\n> +++ b/contrib/remote-helpers/git-remote-hg\n> @@ -75,6 +75,12 @@ def hgmode(mode):\n>  def hghex(node):\n>      return hg.node.hex(node)\n>  \n> +def hgref(ref):\n> +    return ref.replace('___', ' ')\n> +\n> +def gitref(ref):\n> +    return ref.replace(' ', '___')\n> +\n>  def get_config(config):\n>      cmd = ['git', 'config', '--get', config]\n>      process = subprocess.Popen(cmd, stdout=subprocess.PIPE)\n> @@ -437,10 +443,10 @@ def export_ref(repo, name, kind, head):\n>      marks.set_tip(ename, rev)\n>  \n>  def export_tag(repo, tag):\n> -    export_ref(repo, tag, 'tags', repo[tag])\n> +    export_ref(repo, tag, 'tags', repo[hgref(tag)])\n>  \n>  def export_bookmark(repo, bmark):\n> -    head = bmarks[bmark]\n> +    head = bmarks[hgref(bmark)]\n>      export_ref(repo, bmark, 'bookmarks', head)\n>  \n>  def export_branch(repo, branch):\n> @@ -479,14 +485,14 @@ def branch_tip(repo, branch):\n>  def get_branch_tip(repo, branch):\n>      global branches\n>  \n> -    heads = branches.get(branch, None)\n> +    heads = branches.get(hgref(branch), None)\n>      if not heads:\n>          return None\n>  \n>      # verify there's only one head\n>      if (len(heads) > 1):\n>          warn(\"Branch '%s' has more than one head, consider merging\" % branch)\n> -        return branch_tip(repo, branch)\n> +        return branch_tip(repo, hgref(branch))\n>  \n>      return heads[0]\n>  \n> @@ -508,6 +514,7 @@ def list_head(repo, cur):\n>              head = 'master'\n>          bmarks[head] = node\n>  \n> +    head = gitref(head)\n>      print \"@refs/heads/%s HEAD\" % head\n>      g_head = (head, node)\n>  \n> @@ -529,15 +536,15 @@ def do_list(parser):\n>                  branches[branch] = heads\n>  \n>          for branch in branches:\n> -            print \"? refs/heads/branches/%s\" % branch\n> +            print \"? refs/heads/branches/%s\" % gitref(branch)\n>  \n>      for bmark in bmarks:\n> -        print \"? refs/heads/%s\" % bmark\n> +        print \"? refs/heads/%s\" % gitref(bmark)\n>  \n>      for tag, node in repo.tagslist():\n>          if tag == 'tip':\n>              continue\n> -        print \"? refs/tags/%s\" % tag\n> +        print \"? refs/tags/%s\" % gitref(tag)\n>  \n>      print\n>  \n> @@ -674,7 +681,8 @@ def parse_commit(parser):\n>  \n>      # Check if the ref is supposed to be a named branch\n>      if ref.startswith('refs/heads/branches/'):\n> -        extra['branch'] = ref[len('refs/heads/branches/'):]\n> +        branch = ref[len('refs/heads/branches/'):]\n> +        extra['branch'] = hgref(branch)\n>  \n>      if mode == 'hg':\n>          i = data.find('\\n--HG--\\n')\n> @@ -803,6 +811,7 @@ def do_export(parser):\n>              continue\n>          elif ref.startswith('refs/tags/'):\n>              tag = ref[len('refs/tags/'):]\n> +            tag = hgref(tag)\n>              author, msg = parsed_tags.get(tag, (None, None))\n>              if mode == 'git':\n>                  if not msg:\n"},{"id":"215184","messageId":"7v1ua2nqky.fsf@alter.siamese.dyndns.org","threadId":"33575","inReplyTo":"1366667724-567-16-git-send-email-felipe.contreras@gmail.com","subject":"Re: [PATCH 15/16] remote-hg: use marks instead of inlined files","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2013-04-22T22:33:17Z","receivedAt":"2013-04-22T22:33:17Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Felipe Contreras <felipe.contreras@gmail.com> writes:\n\n> So that we can find already exported ones. We can never be 100% sure\n> that we already exported such data, due to mercurial design, it at least\n> sometimes we should detect them, and so should give ups some performance\n\ns/ups/us/ (will locally tweak).\n\n> boost.\n>\n> Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>\n> ---\n>  contrib/remote-helpers/git-remote-hg | 41 +++++++++++++++++++++++++++++-------\n>  1 file changed, 33 insertions(+), 8 deletions(-)\n>\n> diff --git a/contrib/remote-helpers/git-remote-hg b/contrib/remote-helpers/git-remote-hg\n> index f80236b..d0e552c 100755\n> --- a/contrib/remote-helpers/git-remote-hg\n> +++ b/contrib/remote-helpers/git-remote-hg\n> @@ -126,6 +126,10 @@ class Marks:\n>      def to_rev(self, mark):\n>          return self.rev_marks[mark]\n>  \n> +    def next_mark(self):\n> +        self.last_mark += 1\n> +        return self.last_mark\n> +\n>      def get_mark(self, rev):\n>          self.last_mark += 1\n>          self.marks[str(rev)] = self.last_mark\n> @@ -218,12 +222,29 @@ def fix_file_path(path):\n>          return path\n>      return os.path.relpath(path, '/')\n>  \n> -def export_file(fc):\n> -    d = fc.data()\n> -    path = fix_file_path(fc.path())\n> -    print \"M %s inline %s\" % (gitmode(fc.flags()), path)\n> -    print \"data %d\" % len(d)\n> -    print d\n> +def export_files(files):\n> +    global marks, filenodes\n> +\n> +    final = []\n> +    for f in files:\n> +        fid = node.hex(f.filenode())\n> +\n> +        if fid in filenodes:\n> +            mark = filenodes[fid]\n> +        else:\n> +            mark = marks.next_mark()\n> +            filenodes[fid] = mark\n> +            d = f.data()\n> +\n> +            print \"blob\"\n> +            print \"mark :%u\" % mark\n> +            print \"data %d\" % len(d)\n> +            print d\n> +\n> +        path = fix_file_path(f.path())\n> +        final.append((gitmode(f.flags()), mark, path))\n> +\n> +    return final\n>  \n>  def get_filechanges(repo, ctx, parent):\n>      modified = set()\n> @@ -413,6 +434,8 @@ def export_ref(repo, name, kind, head):\n>          if len(parents) == 0 and rev:\n>              print 'reset %s/%s' % (prefix, ename)\n>  \n> +        modified_final = export_files(c.filectx(f) for f in modified)\n> +\n>          print \"commit %s/%s\" % (prefix, ename)\n>          print \"mark :%d\" % (marks.get_mark(rev))\n>          print \"author %s\" % (author)\n> @@ -425,8 +448,8 @@ def export_ref(repo, name, kind, head):\n>              if len(parents) > 1:\n>                  print \"merge :%s\" % (rev_to_mark(parents[1]))\n>  \n> -        for f in modified:\n> -            export_file(c.filectx(f))\n> +        for f in modified_final:\n> +            print \"M %s :%u %s\" % f\n>          for f in removed:\n>              print \"D %s\" % (fix_file_path(f))\n>          print\n> @@ -878,6 +901,7 @@ def main(args):\n>      global peer, mode, bad_mail, bad_name\n>      global track_branches, force_push, is_tmp\n>      global parsed_tags\n> +    global filenodes\n>  \n>      alias = args[1]\n>      url = args[2]\n> @@ -921,6 +945,7 @@ def main(args):\n>      parsed_refs = {}\n>      marks = None\n>      parsed_tags = {}\n> +    filenodes = {}\n>  \n>      repo = get_repo(url, alias)\n>      prefix = 'refs/hg/%s' % alias\n"},{"id":"215185","messageId":"CAMP44s1XaOOnHCCAHL3C=ZQFe6v4vOD+n7mwzFT0nEZAwGfqrg@mail.gmail.com","threadId":"33575","inReplyTo":"7va9oqnqs9.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH 01/16] remote-helpers: avoid has_key","fromName":"Felipe Contreras","fromEmail":"felipe.contreras@gmail.com","sentAt":"2013-04-22T22:35:48Z","receivedAt":"2013-04-22T22:35:48Z","isPatch":true,"sender":{"key":"felipe.contreras@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8358?v=4"},"body":"On Mon, Apr 22, 2013 at 5:28 PM, Junio C Hamano <gitster@pobox.com> wrote:\n> Felipe Contreras <felipe.contreras@gmail.com> writes:\n>\n>> From: Dusty Phillips <dusty@linux.ca>\n>>\n>> It is deprecated.\n>>\n>> [fc: do the same in remote-bzr]\n>>\n>> Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>\n>> ---\n>\n> No sign-off by the author?\n>\n> It does not matter for something so trivial like this that there is\n> no other way to write, but it is a good habit you should encourage\n> your contributors to acquire, so that you do not have to waste time\n> with \"please sign off\" when their next contribution that is more\n> substantial comes.\n\nHe is not a contributor, he sent a few patches, and then immediately\nstarted gitifyhg, I haven't heard a word from him.\n\nStill, he was the original author, so...\n\n-- \nFelipe Contreras\n"},{"id":"215187","messageId":"CAMP44s0f+gJNNESJbYXQgG05Xn0xkkFJMJq6=XC9RsnCdAGzMw@mail.gmail.com","threadId":"33575","inReplyTo":"7v61zenqm4.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH 13/16] remote-hg: allow refs with spaces","fromName":"Felipe Contreras","fromEmail":"felipe.contreras@gmail.com","sentAt":"2013-04-22T22:38:45Z","receivedAt":"2013-04-22T22:38:45Z","isPatch":true,"sender":{"key":"felipe.contreras@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8358?v=4"},"body":"On Mon, Apr 22, 2013 at 5:32 PM, Junio C Hamano <gitster@pobox.com> wrote:\n> Felipe Contreras <felipe.contreras@gmail.com> writes:\n>\n>> Mercurial supports them, Git doesn't.\n>\n> Another important thing to note is that you represent a SP with\n> three underscores on our side, no?\n\nProbably, I don't think it's really important. Perhaps some users\nwould benefit from this information, but they would be better served\nby a README, or a wiki, the commit message doesn't help them.\n\n-- \nFelipe Contreras\n"},{"id":"215192","messageId":"5175BEF0.7040509@buchuki.com","threadId":"33575","inReplyTo":"CAMP44s1XaOOnHCCAHL3C=ZQFe6v4vOD+n7mwzFT0nEZAwGfqrg@mail.gmail.com","subject":"Re: [PATCH 01/16] remote-helpers: avoid has_key","fromName":"Dusty Phillips","fromEmail":"dusty@buchuki.com","sentAt":"2013-04-22T22:51:28Z","receivedAt":"2013-04-22T22:51:28Z","isPatch":true,"sender":{"key":"dusty@buchuki.com","avatar":null},"body":"On 04/22/2013 04:35 PM, Felipe Contreras wrote:\n> On Mon, Apr 22, 2013 at 5:28 PM, Junio C Hamano <gitster@pobox.com> wrote:\n>> Felipe Contreras <felipe.contreras@gmail.com> writes:\n>>\n>>> From: Dusty Phillips <dusty@linux.ca>\n>>>\n>>> It is deprecated.\n>>>\n>>> [fc: do the same in remote-bzr]\n>>>\n>>> Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>\n>>> ---\n>> No sign-off by the author?\n>>\n>> It does not matter for something so trivial like this that there is\n>> no other way to write, but it is a good habit you should encourage\n>> your contributors to acquire, so that you do not have to waste time\n>> with \"please sign off\" when their next contribution that is more\n>> substantial comes.\n> He is not a contributor, he sent a few patches, and then immediately\n> started gitifyhg, I haven't heard a word from him.\n>\n> Still, he was the original author, so...\n\nAcknowledged that I will not likely be contributing any more patches. I \napologize for the lack of signoffs on the pull requests; I wasn't \nactually aware that they were going into git mainline already. I will \nstate for the record that all patches I submitted to Felipe's github \nfork of git in November and December, 2012 were authored by me and only \nme and I submitted them with the understanding and expectation that they \nwould be licensed under the GPL.\n\nDusty\n"},{"id":"215191","messageId":"7vmwsqmamr.fsf@alter.siamese.dyndns.org","threadId":"33575","inReplyTo":"CAMP44s0f+gJNNESJbYXQgG05Xn0xkkFJMJq6=XC9RsnCdAGzMw@mail.gmail.com","subject":"Re: [PATCH 13/16] remote-hg: allow refs with spaces","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2013-04-22T23:03:08Z","receivedAt":"2013-04-22T23:03:08Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Felipe Contreras <felipe.contreras@gmail.com> writes:\n\n> On Mon, Apr 22, 2013 at 5:32 PM, Junio C Hamano <gitster@pobox.com> wrote:\n>> Felipe Contreras <felipe.contreras@gmail.com> writes:\n>>\n>>> Mercurial supports them, Git doesn't.\n>>\n>> Another important thing to note is that you represent a SP with\n>> three underscores on our side, no?\n>\n> Probably, I don't think it's really important. Perhaps some users\n> would benefit from this information, but they would be better served\n> by a README, or a wiki, the commit message doesn't help them.\n\nTrue, but it helps a reviewer to notice the missing documentation\n;-)\n"}]}