changeset 765:70aba6b2fe7b

git_handler: export hg extra metadata as git extra metadata (issue121) We export new git commits with hg extra metadata stored as git extra fields. We also ensure that parsing old commits doesn't break.
author Siddharth Agarwal <sid0@fb.com>
date Sun, 31 Aug 2014 14:01:07 -0700
parents 13a3513f8e67
children 389676318d4c
files hggit/git_handler.py tests/test-encoding.t tests/test-extra.t
diffstat 3 files changed, 76 insertions(+), 11 deletions(-) [+]
line wrap: on
line diff
--- a/hggit/git_handler.py
+++ b/hggit/git_handler.py
@@ -37,6 +37,8 @@
 
 RE_GIT_AUTHOR_EXTRA = re.compile('^(.*?)\ ext:\((.*)\) <(.*)\>$')
 
+RE_GIT_EXTRA_KEY = re.compile('GIT([0-9]*)-(.*)')
+
 # Test for git:// and git+ssh:// URI.
 # Support several URL forms, including separating the
 # host and path with either a / or : (sepr)
@@ -447,7 +449,8 @@
 
                 commit.parents.append(git_sha)
 
-        commit.message = self.get_git_message(ctx)
+        commit.message, extra = self.get_git_message_and_extra(ctx)
+        commit.extra.extend(extra)
 
         if 'encoding' in extra:
             commit.encoding = extra['encoding']
@@ -562,7 +565,7 @@
 
         return parents
 
-    def get_git_message(self, ctx):
+    def get_git_message_and_extra(self, ctx):
         extra = ctx.extra()
 
         message = ctx.description() + "\n"
@@ -570,10 +573,29 @@
             message = "".join(apply_delta(message, extra['message']))
 
         # HG EXTRA INFORMATION
+
+        # test only -- do not document this!
+        extra_in_message = self.ui.configbool('git', 'debugextrainmessage',
+                                              False)
         extra_message = ''
+        git_extra = []
         if not ctx.branch() == 'default':
+            # we always store the branch in the extra message
             extra_message += "branch : " + ctx.branch() + "\n"
 
+        # Git native extra items always come first, followed by hg renames,
+        # followed by hg extra keys
+        git_extraitems = []
+        for key, value in extra.items():
+            m = RE_GIT_EXTRA_KEY.match(key)
+            if m is not None:
+                git_extraitems.append((int(m.group(1)), m.group(2), value))
+                del extra[key]
+
+        git_extraitems.sort()
+        for i, field, value in git_extraitems:
+            git_extra.append((urllib.unquote(field), urllib.unquote(value)))
+
         renames = []
         for f in ctx.files():
             if f not in ctx.manifest():
@@ -584,20 +606,33 @@
 
         if renames:
             for oldfile, newfile in renames:
-                extra_message += "rename : " + oldfile + " => " + newfile + "\n"
+                if extra_in_message:
+                    extra_message += ("rename : " + oldfile + " => " +
+                                      newfile + "\n")
+                else:
+                    spec = '%s:%s' % (urllib.quote(oldfile),
+                                      urllib.quote(newfile))
+                    git_extra.append(('HG:rename', spec))
 
+        # hg extra items always go at the end
         extraitems = extra.items()
         extraitems.sort()
         for key, value in extraitems:
             if key in ('author', 'committer', 'encoding', 'message', 'branch', 'hg-git'):
                 continue
             else:
-                extra_message += "extra : " + key + " : " +  urllib.quote(value) + "\n"
+                if extra_in_message:
+                    extra_message += ("extra : " + key + " : " +
+                                      urllib.quote(value) + "\n")
+                else:
+                    spec = '%s:%s' % (urllib.quote(key),
+                                      urllib.quote(value))
+                    git_extra.append(('HG:extra', spec))
 
         if extra_message:
             message += "\n--HG--\n" + extra_message
 
-        return message
+        return message, git_extra
 
     def getnewgitcommits(self, refs=None):
         # import heads and fetched tags as remote references
--- a/tests/test-encoding.t
+++ b/tests/test-encoding.t
@@ -101,7 +101,7 @@
 Latin1 commit messages started being automatically converted to UTF-8 in
 Git 1.8.0, so we accept the output of either version.
   $ git --git-dir=gitrepo2 log --pretty=medium
-  commit (da0edb01d4f3d1abf08b1be298379b0b2960e680|51c509c1c7eeb8f0a5b20aa3e894e8823f39171f) (re)
+  commit (e85fef6b515d555e45124a5dc39a019cf8db9ff0|2032391dc85cf3bb253678589abfc2dd1774b177) (re)
   Author: t\xe9st \xe8nc\xf6d\xeeng <test@example.org> (esc)
   Date:   Mon Jan 1 00:00:13 2007 +0000
   
--- a/tests/test-extra.t
+++ b/tests/test-extra.t
@@ -28,6 +28,7 @@
   1 files updated, 0 files merged, 1 files removed, 0 files unresolved
 
 Add a commit with multiple extra fields
+  $ hg bookmark b1
   $ touch d
   $ hg add d
   $ fn_hg_commitextra --field zzzzzzz=datazzz --field aaaaaaa=dataaaa
@@ -44,15 +45,29 @@
   o  0 ab83abcbf5717f738191aa2d42f52a7100ce06a8 a
      branch=default
   
-
-  $ hg bookmark b1
-  $ hg push -r b1
+Make sure legacy extra (in commit message, after '--HG--') doesn't break
+  $ hg push -r b1 --config git.debugextrainmessage=1
   pushing to $TESTTMP/gitrepo
   searching for changes
   adding objects
   added 3 commits with 3 trees and 0 blobs
   adding reference refs/heads/b1
 
+  $ hg bookmark b2
+  $ hg mv c c2
+  $ hg mv d d2
+  $ fn_hg_commitextra --field yyyyyyy=datayyy --field bbbbbbb=databbb
+  $ hg log --graph --template "{rev} {node} {desc|firstline}\n{join(extras, ' ')}\n\n" -l 1
+  @  4 71a7f7cc00a30dde4a0d5da37f119e51ded1820a
+  |  bbbbbbb=databbb branch=default yyyyyyy=datayyy
+  |
+  $ hg push -r b2
+  pushing to $TESTTMP/gitrepo
+  searching for changes
+  adding objects
+  added 1 commits with 1 trees and 0 blobs
+  adding reference refs/heads/b2
+
   $ cd ../gitrepo
   $ git cat-file commit b1
   tree 1b773a2eb70f29397356f8069c285394835ff85a
@@ -66,6 +81,18 @@
   extra : aaaaaaa : dataaaa
   extra : zzzzzzz : datazzz
 
+  $ git cat-file commit b2
+  tree 34ad62c6d6ad9464bfe62db5b3d2fa16aaa9fa9e
+  parent ca11864bb2a84c3996929d42cf38bae3d0f7aae0
+  author test <none@none> 1167609614 +0000
+  committer test <none@none> 1167609614 +0000
+  HG:rename c:c2
+  HG:rename d:d2
+  HG:extra bbbbbbb:databbb
+  HG:extra yyyyyyy:datayyy
+  
+  
+
   $ cd ../gitrepo
   $ git checkout b1
   Switched to branch 'b1'
@@ -111,8 +138,11 @@
   $ hg clone -q gitrepo hgrepo2
   $ cd hgrepo2
   $ hg log --graph --template "{rev} {node} {desc|firstline}\n{join(extras, ' ')}\n\n"
-  @  4 f5fddc070b0648a5cddb98b43bbd527e98f4b4d2 extra commit
-  |  GIT0-zzz%3Azzz=data%3Azzz GIT1-aaa%3Aaaa=data%3Aaaa branch=default hgaaa=dataaaa hgzzz=datazzz
+  @  5 71a7f7cc00a30dde4a0d5da37f119e51ded1820a
+  |  bbbbbbb=databbb branch=default yyyyyyy=datayyy
+  |
+  | o  4 f5fddc070b0648a5cddb98b43bbd527e98f4b4d2 extra commit
+  |/   GIT0-zzz%3Azzz=data%3Azzz GIT1-aaa%3Aaaa=data%3Aaaa branch=default hgaaa=dataaaa hgzzz=datazzz
   |
   o  3 f15e01c73845392d86a5ed10fb0753d09bca13d3
   |  aaaaaaa=dataaaa branch=default zzzzzzz=datazzz