git.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* Mercurial to git converter.
@ 2007-01-11 17:49 Stelian Pop
  2007-01-12 19:28 ` Jakub Narebski
  2008-06-14 10:23 ` Mercurial to git converter Nick Andrew
  0 siblings, 2 replies; 15+ messages in thread
From: Stelian Pop @ 2007-01-11 17:49 UTC (permalink / raw)
  To: git

Hi all,

I switched recently from Mercurial to git for some of my projects, and
needed a conversion tool with branch support (unlike tailor). I didn't
find any, so I ended up writing my own one. 

hg-to-git.py can probably be greatly improved (it's a rather crude
combination of shell and python) but it does already work quite well for
me. Features:
	- supports incremental conversion (keep a git repo in sync with a hg
one)
	- supports hg branches
	- converts hg tags 

Feel free to use it, improve it or even include it in mainline git (like
git-svn and friends).

Stelian.

#! /usr/bin/python

""" hg-to-svn.py - A Mercurial to GIT converter

    Copyright (C)2007 Stelian Pop <stelian@popies.net>

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2, or (at your option)
    any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
"""

import os, os.path, sys
import tempfile, popen2, pickle, getopt
import re

# Maps hg version -> git version
hgvers = {}
# List of children for each hg revision
hgchildren = {}
# Current branch for each hg revision
hgbranch = {}

#------------------------------------------------------------------------------

def usage():

        print """\
%s: [OPTIONS] <hgprj>

options:
    -s, --gitstate=FILE: name of the state to be saved/read
                         for incrementals

required:
    hgprj:  name of the HG project to import (directory)
""" % sys.argv[0]

#------------------------------------------------------------------------------

def getgitenv(user, date):
    env = ''
    elems = re.compile('(.*?)\s+<(.*)>').match(user)
    if elems:
        env += 'export GIT_AUTHOR_NAME="%s" ;' % elems.group(1)
        env += 'export GIT_COMMITER_NAME="%s" ;' % elems.group(1)
        env += 'export GIT_AUTHOR_EMAIL="%s" ;' % elems.group(2)
        env += 'export GIT_COMMITER_EMAIL="%s" ;' % elems.group(2)
    else:
        env += 'export GIT_AUTHOR_NAME="%s" ;' % user
        env += 'export GIT_COMMITER_NAME="%s" ;' % user
        env += 'export GIT_AUTHOR_EMAIL= ;'
        env += 'export GIT_COMMITER_EMAIL= ;'

    env += 'export GIT_AUTHOR_DATE="%s" ;' % date
    env += 'export GIT_COMMITTER_DATE="%s" ;' % date
    return env

#------------------------------------------------------------------------------

state = ''

try:
    opts, args = getopt.getopt(sys.argv[1:], 's:t:', ['gitstate=', 'tempdir='])
    for o, a in opts:
        if o in ('-s', '--gitstate'):
            state = a
            state = os.path.abspath(state)

    if len(args) != 1:
        raise('params')
except:
    usage()
    sys.exit(1)

hgprj = args[0]
os.chdir(hgprj)

if state:
    if os.path.exists(state):
        print 'State does exist, reading'
        f = open(state, 'r')
        hgvers = pickle.load(f)
    else:
        print 'State does not exist, first run'

tip = os.popen('hg tip | head -1 | cut -f 2 -d :').read().strip()
print 'tip is', tip

# Calculate the branches
print 'analysing the branches...'
hgchildren["0"] = ()
hgbranch["0"] = "master"
for cset in range(1, int(tip) + 1):
    hgchildren[str(cset)] = ()
    prnts = os.popen('hg log -r %d | grep ^parent: | cut -f 2 -d :' % cset).readlines()
    if len(prnts) > 0:
        parent = prnts[0].strip()
    else:
        parent = str(cset - 1)
    hgchildren[parent] += ( str(cset), )
    if len(prnts) > 1:
        mparent = prnts[1].strip()
        hgchildren[mparent] += ( str(cset), )
    else:
        mparent = None

    if mparent:
        # For merge changesets, take either one, preferably the 'master' branch
        if hgbranch[mparent] == 'master':
            hgbranch[str(cset)] = 'master'
        else:
            hgbranch[str(cset)] = hgbranch[parent]
    else:
        # Normal changesets
        # For first children, take the parent branch, for the others create a new branch
        if hgchildren[parent][0] == str(cset):
            hgbranch[str(cset)] = hgbranch[parent]
        else:
            hgbranch[str(cset)] = "branch-" + str(cset)

if not hgvers.has_key("0"):
    print 'creating repository'
    os.system('git-init-db')

# loop through every hg changeset
for cset in range(int(tip) + 1):

    # incremental, already seen
    if hgvers.has_key(str(cset)):
        continue

    # get info
    prnts = os.popen('hg log -r %d | grep ^parent: | cut -f 2 -d :' % cset).readlines()
    if len(prnts) > 0:
        parent = prnts[0].strip()
    else:
        parent = str(cset - 1)
    if len(prnts) > 1:
        mparent = prnts[1].strip()
    else:
        mparent = None

    (fdcomment, filecomment) = tempfile.mkstemp()
    csetcomment = os.popen('hg log -r %d -v | grep -v ^changeset: | grep -v ^parent: | grep -v ^user: | grep -v ^date | grep -v ^files: | grep -v ^description: | grep -v ^tag:' % cset).read().strip()
    os.write(fdcomment, csetcomment)
    os.close(fdcomment)

    date = os.popen('hg log -r %d | grep ^date: | cut -f 2- -d :' % cset).read().strip()

    tag = os.popen('hg log -r %d | grep ^tag: | cut -f 2- -d :' % cset).read().strip()

    user = os.popen('hg log -r %d | grep ^user: | cut -f 2- -d :' % cset).read().strip()

    print '-----------------------------------------'
    print 'cset:', cset
    print 'branch:', hgbranch[str(cset)]
    print 'user:', user
    print 'date:', date
    print 'comment:', csetcomment
    print 'parent:', parent
    if mparent:
        print 'mparent:', mparent
    if tag:
        print 'tag:', tag
    print '-----------------------------------------'

    # checkout the parent if necessary
    if cset != 0:
        if hgbranch[str(cset)] == "branch-" + str(cset):
            print 'creating new branch', hgbranch[str(cset)]
            os.system('git-checkout -b %s %s' % (hgbranch[str(cset)], hgvers[parent]))
        else:
            print 'checking out branch', hgbranch[str(cset)]
            os.system('git-checkout %s' % hgbranch[str(cset)])

    # merge
    if mparent:
        if hgbranch[parent] == hgbranch[str(cset)]:
            otherbranch = hgbranch[mparent]
        else:
            otherbranch = hgbranch[parent]
        print 'merging', otherbranch, 'into', hgbranch[str(cset)]
        os.system(getgitenv(user, date) + 'git-merge --no-commit -s ours "" %s %s' % (hgbranch[str(cset)], otherbranch))

    # remove everything except .git and .hg directories
    os.system('find . \( -path "./.hg" -o -path "./.git" \) -prune -o ! -name "." -print | xargs rm -rf')

    # repopulate with checkouted files
    os.system('hg update -C %d' % cset)

    # add new files
    os.system('git-ls-files -x .hg --others | git-update-index --add --stdin')
    # delete removed files
    os.system('git-ls-files -x .hg --deleted | git-update-index --remove --stdin')

    # commit
    os.system(getgitenv(user, date) + 'git-commit -a -F %s' % filecomment)
    os.unlink(filecomment)

    # tag
    if tag and tag != 'tip':
        os.system(getgitenv(user, date) + 'git-tag %s' % tag)

    # delete branch if not used anymore...
    if mparent and len(hgchildren[str(cset)]):
        print "Deleting unused branch:", otherbranch
        os.system('git-branch -d %s' % otherbranch)

    # retrieve and record the version
    vvv = os.popen('git-show | head -1').read()
    vvv = vvv[vvv.index(' ') + 1 : ].strip()
    print 'record', cset, '->', vvv
    hgvers[str(cset)] = vvv

os.system('git-repack -a -d')

# write the state for incrementals
if state:
    print 'Writing state'
    f = open(state, 'w')
    pickle.dump(hgvers, f)

# vim: et ts=8 sw=4 sts=4

-- 
Stelian Pop <stelian@popies.net>

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: Mercurial to git converter.
  2007-01-11 17:49 Mercurial to git converter Stelian Pop
@ 2007-01-12 19:28 ` Jakub Narebski
  2007-01-12 20:14   ` Stelian Pop
  2008-06-14 10:23 ` Mercurial to git converter Nick Andrew
  1 sibling, 1 reply; 15+ messages in thread
From: Jakub Narebski @ 2007-01-12 19:28 UTC (permalink / raw)
  To: git

Stelian Pop wrote:

> I switched recently from Mercurial to git for some of my projects, and
> needed a conversion tool with branch support (unlike tailor). I didn't
> find any, so I ended up writing my own one. 
> 
> hg-to-git.py can probably be greatly improved (it's a rather crude
> combination of shell and python) but it does already work quite well for
> me. Features:
>       - supports incremental conversion (keep a git repo in sync 
>         with a hg repository)
>       - supports hg branches
>       - converts hg tags 
> 
> Feel free to use it, improve it or even include it in mainline git (like
> git-svn and friends).

Thanks. Added to
  http://git.or.cz/gitwiki/InterfacesFrontendsAndTools#hg-to-git

(Perhaps you should send it as git patch adding file contrib/hg-to-git.py
or contrib/git-hgimport/hg-to-git.py ?)
-- 
Jakub Narebski
Warsaw, Poland
ShadeHawk on #git

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: Mercurial to git converter.
  2007-01-12 19:28 ` Jakub Narebski
@ 2007-01-12 20:14   ` Stelian Pop
  2007-01-12 21:57     ` [PATCH] Add hg-to-git conversion utility Stelian Pop
  0 siblings, 1 reply; 15+ messages in thread
From: Stelian Pop @ 2007-01-12 20:14 UTC (permalink / raw)
  To: Jakub Narebski; +Cc: git

Le vendredi 12 janvier 2007 à 20:28 +0100, Jakub Narebski a écrit :
> Stelian Pop wrote:
> 
> > I switched recently from Mercurial to git for some of my projects, and
> > needed a conversion tool with branch support (unlike tailor). I didn't
> > find any, so I ended up writing my own one. 
> > 
> > hg-to-git.py can probably be greatly improved (it's a rather crude
> > combination of shell and python) but it does already work quite well for
> > me. Features:
> >       - supports incremental conversion (keep a git repo in sync 
> >         with a hg repository)
> >       - supports hg branches
> >       - converts hg tags 
> > 
> > Feel free to use it, improve it or even include it in mainline git (like
> > git-svn and friends).
> 
> Thanks. Added to
>   http://git.or.cz/gitwiki/InterfacesFrontendsAndTools#hg-to-git

Thanks.

> (Perhaps you should send it as git patch adding file contrib/hg-to-git.py
> or contrib/git-hgimport/hg-to-git.py ?)

Sure, I can do that (patch against 'master', right ?)

Do I put this in contrib/ as you suggest or directly in / (where friends
like git-p4import.py live) ? What is most likely to be accepted ?

Stelian.
-- 
Stelian Pop <stelian@popies.net>

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH] Add hg-to-git conversion utility.
  2007-01-12 20:14   ` Stelian Pop
@ 2007-01-12 21:57     ` Stelian Pop
  2007-01-12 22:15       ` Shawn O. Pearce
  0 siblings, 1 reply; 15+ messages in thread
From: Stelian Pop @ 2007-01-12 21:57 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git

hg-to-git.py  is able to convert a Mercurial repository into a git one,
and preserves the branches in the process (unlike tailor)

hg-to-git.py can probably be greatly improved (it's a rather crude
combination of shell and python) but it does already work quite well for
me. Features:
	- supports incremental conversion
	  (for keeping a git repo in sync with a hg one)
	- supports hg branches
	- converts hg tags

Signed-off-by: Stelian Pop <stelian@popies.net>
---
 Documentation/git-tools.txt     |    7 +
 contrib/hg-to-git/hg-to-git.py  |  233 +++++++++++++++++++++++++++++++++++++++
 contrib/hg-to-git/hg-to-git.txt |   22 ++++
 3 files changed, 262 insertions(+), 0 deletions(-)

diff --git a/Documentation/git-tools.txt b/Documentation/git-tools.txt
index 0914cbb..4d245d5 100644
--- a/Documentation/git-tools.txt
+++ b/Documentation/git-tools.txt
@@ -68,6 +68,13 @@ History Viewers
 Foreign SCM interface
 ---------------------
 
+   - *hg-to-git* (contrib/)
+
+   hg-to-git converts a Mercurial repository into a git one, and
+   preserves the full branch history in the process. hg-to-git can
+   also be used in an incremental way to keep the git repository
+   in sync with the master Mercurial repository.
+
    - *git-svn* (contrib/)
 
    git-svn is a simple conduit for changesets between a single Subversion
diff --git a/contrib/hg-to-git/hg-to-git.py b/contrib/hg-to-git/hg-to-git.py
new file mode 100755
index 0000000..37337ff
--- /dev/null
+++ b/contrib/hg-to-git/hg-to-git.py
@@ -0,0 +1,233 @@
+#! /usr/bin/python
+
+""" hg-to-svn.py - A Mercurial to GIT converter
+
+    Copyright (C)2007 Stelian Pop <stelian@popies.net>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2, or (at your option)
+    any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+"""
+
+import os, os.path, sys
+import tempfile, popen2, pickle, getopt
+import re
+
+# Maps hg version -> git version
+hgvers = {}
+# List of children for each hg revision
+hgchildren = {}
+# Current branch for each hg revision
+hgbranch = {}
+
+#------------------------------------------------------------------------------
+
+def usage():
+
+        print """\
+%s: [OPTIONS] <hgprj>
+
+options:
+    -s, --gitstate=FILE: name of the state to be saved/read
+                         for incrementals
+
+required:
+    hgprj:  name of the HG project to import (directory)
+""" % sys.argv[0]
+
+#------------------------------------------------------------------------------
+
+def getgitenv(user, date):
+    env = ''
+    elems = re.compile('(.*?)\s+<(.*)>').match(user)
+    if elems:
+        env += 'export GIT_AUTHOR_NAME="%s" ;' % elems.group(1)
+        env += 'export GIT_COMMITER_NAME="%s" ;' % elems.group(1)
+        env += 'export GIT_AUTHOR_EMAIL="%s" ;' % elems.group(2)
+        env += 'export GIT_COMMITER_EMAIL="%s" ;' % elems.group(2)
+    else:
+        env += 'export GIT_AUTHOR_NAME="%s" ;' % user
+        env += 'export GIT_COMMITER_NAME="%s" ;' % user
+        env += 'export GIT_AUTHOR_EMAIL= ;'
+        env += 'export GIT_COMMITER_EMAIL= ;'
+
+    env += 'export GIT_AUTHOR_DATE="%s" ;' % date
+    env += 'export GIT_COMMITTER_DATE="%s" ;' % date
+    return env
+
+#------------------------------------------------------------------------------
+
+state = ''
+
+try:
+    opts, args = getopt.getopt(sys.argv[1:], 's:t:', ['gitstate=', 'tempdir='])
+    for o, a in opts:
+        if o in ('-s', '--gitstate'):
+            state = a
+            state = os.path.abspath(state)
+
+    if len(args) != 1:
+        raise('params')
+except:
+    usage()
+    sys.exit(1)
+
+hgprj = args[0]
+os.chdir(hgprj)
+
+if state:
+    if os.path.exists(state):
+        print 'State does exist, reading'
+        f = open(state, 'r')
+        hgvers = pickle.load(f)
+    else:
+        print 'State does not exist, first run'
+
+tip = os.popen('hg tip | head -1 | cut -f 2 -d :').read().strip()
+print 'tip is', tip
+
+# Calculate the branches
+print 'analysing the branches...'
+hgchildren["0"] = ()
+hgbranch["0"] = "master"
+for cset in range(1, int(tip) + 1):
+    hgchildren[str(cset)] = ()
+    prnts = os.popen('hg log -r %d | grep ^parent: | cut -f 2 -d :' % cset).readlines()
+    if len(prnts) > 0:
+        parent = prnts[0].strip()
+    else:
+        parent = str(cset - 1)
+    hgchildren[parent] += ( str(cset), )
+    if len(prnts) > 1:
+        mparent = prnts[1].strip()
+        hgchildren[mparent] += ( str(cset), )
+    else:
+        mparent = None
+
+    if mparent:
+        # For merge changesets, take either one, preferably the 'master' branch
+        if hgbranch[mparent] == 'master':
+            hgbranch[str(cset)] = 'master'
+        else:
+            hgbranch[str(cset)] = hgbranch[parent]
+    else:
+        # Normal changesets
+        # For first children, take the parent branch, for the others create a new branch
+        if hgchildren[parent][0] == str(cset):
+            hgbranch[str(cset)] = hgbranch[parent]
+        else:
+            hgbranch[str(cset)] = "branch-" + str(cset)
+
+if not hgvers.has_key("0"):
+    print 'creating repository'
+    os.system('git-init-db')
+
+# loop through every hg changeset
+for cset in range(int(tip) + 1):
+
+    # incremental, already seen
+    if hgvers.has_key(str(cset)):
+        continue
+
+    # get info
+    prnts = os.popen('hg log -r %d | grep ^parent: | cut -f 2 -d :' % cset).readlines()
+    if len(prnts) > 0:
+        parent = prnts[0].strip()
+    else:
+        parent = str(cset - 1)
+    if len(prnts) > 1:
+        mparent = prnts[1].strip()
+    else:
+        mparent = None
+
+    (fdcomment, filecomment) = tempfile.mkstemp()
+    csetcomment = os.popen('hg log -r %d -v | grep -v ^changeset: | grep -v ^parent: | grep -v ^user: | grep -v ^date | grep -v ^files: | grep -v ^description: | grep -v ^tag:' % cset).read().strip()
+    os.write(fdcomment, csetcomment)
+    os.close(fdcomment)
+
+    date = os.popen('hg log -r %d | grep ^date: | cut -f 2- -d :' % cset).read().strip()
+
+    tag = os.popen('hg log -r %d | grep ^tag: | cut -f 2- -d :' % cset).read().strip()
+
+    user = os.popen('hg log -r %d | grep ^user: | cut -f 2- -d :' % cset).read().strip()
+
+    print '-----------------------------------------'
+    print 'cset:', cset
+    print 'branch:', hgbranch[str(cset)]
+    print 'user:', user
+    print 'date:', date
+    print 'comment:', csetcomment
+    print 'parent:', parent
+    if mparent:
+        print 'mparent:', mparent
+    if tag:
+        print 'tag:', tag
+    print '-----------------------------------------'
+
+    # checkout the parent if necessary
+    if cset != 0:
+        if hgbranch[str(cset)] == "branch-" + str(cset):
+            print 'creating new branch', hgbranch[str(cset)]
+            os.system('git-checkout -b %s %s' % (hgbranch[str(cset)], hgvers[parent]))
+        else:
+            print 'checking out branch', hgbranch[str(cset)]
+            os.system('git-checkout %s' % hgbranch[str(cset)])
+
+    # merge
+    if mparent:
+        if hgbranch[parent] == hgbranch[str(cset)]:
+            otherbranch = hgbranch[mparent]
+        else:
+            otherbranch = hgbranch[parent]
+        print 'merging', otherbranch, 'into', hgbranch[str(cset)]
+        os.system(getgitenv(user, date) + 'git-merge --no-commit -s ours "" %s %s' % (hgbranch[str(cset)], otherbranch))
+
+    # remove everything except .git and .hg directories
+    os.system('find . \( -path "./.hg" -o -path "./.git" \) -prune -o ! -name "." -print | xargs rm -rf')
+
+    # repopulate with checkouted files
+    os.system('hg update -C %d' % cset)
+
+    # add new files
+    os.system('git-ls-files -x .hg --others | git-update-index --add --stdin')
+    # delete removed files
+    os.system('git-ls-files -x .hg --deleted | git-update-index --remove --stdin')
+
+    # commit
+    os.system(getgitenv(user, date) + 'git-commit -a -F %s' % filecomment)
+    os.unlink(filecomment)
+
+    # tag
+    if tag and tag != 'tip':
+        os.system(getgitenv(user, date) + 'git-tag %s' % tag)
+
+    # delete branch if not used anymore...
+    if mparent and len(hgchildren[str(cset)]):
+        print "Deleting unused branch:", otherbranch
+        os.system('git-branch -d %s' % otherbranch)
+
+    # retrieve and record the version
+    vvv = os.popen('git-show | head -1').read()
+    vvv = vvv[vvv.index(' ') + 1 : ].strip()
+    print 'record', cset, '->', vvv
+    hgvers[str(cset)] = vvv
+
+os.system('git-repack -a -d')
+
+# write the state for incrementals
+if state:
+    print 'Writing state'
+    f = open(state, 'w')
+    pickle.dump(hgvers, f)
+
+# vim: et ts=8 sw=4 sts=4
diff --git a/contrib/hg-to-git/hg-to-git.txt b/contrib/hg-to-git/hg-to-git.txt
new file mode 100644
index 0000000..cf1c735
--- /dev/null
+++ b/contrib/hg-to-git/hg-to-git.txt
@@ -0,0 +1,22 @@
+hg-to-git.py is able to convert a Mercurial repository into a git one,
+and preserves the branches in the process (unlike tailor)
+
+hg-to-git.py can probably be greatly improved (it's a rather crude
+combination of shell and python) but it does already work quite well for
+me. Features:
+	- supports incremental conversion
+	  (for keeping a git repo in sync with a hg one)
+        - supports hg branches
+        - converts hg tags 
+
+Note that the git repository will be created 'in place' (at the same
+location as the source hg repo). You will have to manually remove the
+'.hg' directory after the conversion.
+
+Also note that the incremental conversion uses 'simple' hg changesets
+identifiers (ordinals, as opposed to SHA-1 ids), and since these ids
+are not stable across different repositories the hg-to-git.py state file
+is forever tied to one hg repository.
+
+-- 
+Stelian Pop <stelian@popies.net>
-- 
1.4.4.4

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* Re: [PATCH] Add hg-to-git conversion utility.
  2007-01-12 21:57     ` [PATCH] Add hg-to-git conversion utility Stelian Pop
@ 2007-01-12 22:15       ` Shawn O. Pearce
  2007-01-12 23:00         ` Stelian Pop
  0 siblings, 1 reply; 15+ messages in thread
From: Shawn O. Pearce @ 2007-01-12 22:15 UTC (permalink / raw)
  To: Stelian Pop; +Cc: git

Stelian Pop <stelian@popies.net> wrote:
> hg-to-git.py  is able to convert a Mercurial repository into a git one,
> and preserves the branches in the process (unlike tailor)

Cool!

You've already written the converter, but you may want to look at
using git-fast-import as the backend interface to Git.  I think
your code may come out shorter, be clearer, and will run faster.

For example Simon Schubert's cvs -> git converter was written in
one night (last night) in Ruby using git-fast-import as the backend
(Simon already had the heavy lifting CVS portions done).  I peeked
at his source and its quite readable, though maybe that's just the
Ruby talking.  ;-) Simon is apparently trying to import FreeBSD's
CVS repository to Git.  A non-trivial task.

Chris Lee also has an svn -> git converter that uses gfi as its
backend. Its only 150 or so lines of Python and is also quite
readable.  Chris is apparently trying to import KDE to Git.
An equally non-trivial task.

I think the common thread between the two implementations is
that there's less process forking and less manipulation of ugly
environment variables.  So the import runs faster and its a little
easier to organize the code.


The gitweb (and mirror URLs) for gfi is available here:

  http://repo.or.cz/w/git/fastimport.git

Post 1.5.0 I'm going to nudge Junio to get gfi added to the main
git.git repository.  (Right now I don't want to distract him from
the release.)

-- 
Shawn.

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] Add hg-to-git conversion utility.
  2007-01-12 22:15       ` Shawn O. Pearce
@ 2007-01-12 23:00         ` Stelian Pop
  2007-01-12 23:14           ` Junio C Hamano
  0 siblings, 1 reply; 15+ messages in thread
From: Stelian Pop @ 2007-01-12 23:00 UTC (permalink / raw)
  To: Shawn O. Pearce; +Cc: git

Shawn O. Pearce a écrit :
> Stelian Pop <stelian@popies.net> wrote:
>> hg-to-git.py  is able to convert a Mercurial repository into a git one,
>> and preserves the branches in the process (unlike tailor)
> 
> Cool!
> 
> You've already written the converter, but you may want to look at
> using git-fast-import as the backend interface to Git.  I think
> your code may come out shorter, be clearer, and will run faster.
[...]
> Post 1.5.0 I'm going to nudge Junio to get gfi added to the main
> git.git repository.  (Right now I don't want to distract him from
> the release.)

Rebasing hg-to-git.py on gfi will probably be a very good idea once gfi 
is in the tree.

But I wrote this since I had a need for it, and once my repositories 
converted to git I'm not sure I'll need it again :) So don't count too 
much on me to do this rebasing :)

But who knows, on a cold rainy day...

-- 
Stelian Pop <stelian@popies.net>

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] Add hg-to-git conversion utility.
  2007-01-12 23:00         ` Stelian Pop
@ 2007-01-12 23:14           ` Junio C Hamano
  2007-01-12 23:18             ` Stelian Pop
  0 siblings, 1 reply; 15+ messages in thread
From: Junio C Hamano @ 2007-01-12 23:14 UTC (permalink / raw)
  To: Stelian Pop; +Cc: git

Stelian Pop <stelian@popies.net> writes:

> But I wrote this since I had a need for it, and once my repositories
> converted to git I'm not sure I'll need it again :)

It is not a good strategy to say upfront that you are not going
to maintain it, when you are submitting something for inclusion.

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] Add hg-to-git conversion utility.
  2007-01-12 23:14           ` Junio C Hamano
@ 2007-01-12 23:18             ` Stelian Pop
  0 siblings, 0 replies; 15+ messages in thread
From: Stelian Pop @ 2007-01-12 23:18 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git

Junio C Hamano a écrit :
> Stelian Pop <stelian@popies.net> writes:
> 
>> But I wrote this since I had a need for it, and once my repositories
>> converted to git I'm not sure I'll need it again :)
> 
> It is not a good strategy to say upfront that you are not going
> to maintain it, when you are submitting something for inclusion.

Hey, I didn't say I won't fix it if it breaks !

I may not have the time and need to make it better than it already is 
though.

-- 
Stelian Pop <stelian@popies.net>

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: Mercurial to git converter.
  2007-01-11 17:49 Mercurial to git converter Stelian Pop
  2007-01-12 19:28 ` Jakub Narebski
@ 2008-06-14 10:23 ` Nick Andrew
  2008-06-14 15:53   ` Johannes Schindelin
  1 sibling, 1 reply; 15+ messages in thread
From: Nick Andrew @ 2008-06-14 10:23 UTC (permalink / raw)
  To: git

Stelian Pop <stelian <at> popies.net> writes:

> I switched recently from Mercurial to git for some of my projects, and
> needed a conversion tool with branch support (unlike tailor). I didn't
> find any, so I ended up writing my own one. 
> 
> hg-to-git.py can probably be greatly improved (it's a rather crude
> combination of shell and python) but it does already work quite well for
> me. [...]

Thanks for that. One small problem is that it does not get the changelog right 
if a commit is made on a local branch. It thinks the "branch:" line is part of 
the changelog.

Here's a patch to fix that:

diff -u -r1.1 hg-to-git.py
--- hg-to-git.py
+++ hg-to-git.py
@@ -151,7 +151,7 @@
         mparent = None

     (fdcomment, filecomment) = tempfile.mkstemp()
-    csetcomment = os.popen('hg log -r %d -v | grep -v ^changeset: | grep -v 
^parent: | grep -v ^user: | grep -v ^date | grep -v ^files: | grep -v 
^description: | grep -v ^tag:' % cset).read().strip()
+    csetcomment = os.popen('hg log -r %d -v | egrep -v "^(changeset|parent|
user|date|files|description|tag|branch):" ' % cset).read().strip()
     os.write(fdcomment, csetcomment)
     os.close(fdcomment)


Nick.

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: Mercurial to git converter.
  2008-06-14 10:23 ` Mercurial to git converter Nick Andrew
@ 2008-06-14 15:53   ` Johannes Schindelin
  2008-06-14 16:48     ` Jakub Narebski
                       ` (2 more replies)
  0 siblings, 3 replies; 15+ messages in thread
From: Johannes Schindelin @ 2008-06-14 15:53 UTC (permalink / raw)
  To: Nick Andrew; +Cc: git

Hi,

On Sat, 14 Jun 2008, Nick Andrew wrote:

> Stelian Pop <stelian <at> popies.net> writes:
> 
> > I switched recently from Mercurial to git for some of my projects, and
> > needed a conversion tool with branch support (unlike tailor). I didn't
> > find any, so I ended up writing my own one. 
> > 
> > hg-to-git.py can probably be greatly improved (it's a rather crude 
> > combination of shell and python) but it does already work quite well 
> > for me. [...]
> 
> Thanks for that. One small problem is that it does not get the changelog 
> right if a commit is made on a local branch. It thinks the "branch:" 
> line is part of the changelog.

FWIW I switched my local mercurial2git conversion to the hg-fast-export 
solution from 

	git://repo.or.cz/fast-export.git

Even if it's documentation leaves almost completely to be desired, after 
figuring out how to operate it by reading the source, it works pretty 
nicely, and fast, because it uses fast-import.

Originally, I did not try it because I thought it cannot operate in 
incremental mode, but it can.

Ciao,
Dscho

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: Mercurial to git converter.
  2008-06-14 15:53   ` Johannes Schindelin
@ 2008-06-14 16:48     ` Jakub Narebski
  2008-06-16  2:24       ` Shawn O. Pearce
  2008-06-16  8:21     ` Nick Andrew
  2008-06-16  8:26     ` Mike Hommey
  2 siblings, 1 reply; 15+ messages in thread
From: Jakub Narebski @ 2008-06-14 16:48 UTC (permalink / raw)
  To: Johannes Schindelin; +Cc: Nick Andrew, git

Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:
> On Sat, 14 Jun 2008, Nick Andrew wrote: 
>> Stelian Pop <stelian <at> popies.net> writes:
>> 
>>> hg-to-git.py can probably be greatly improved (it's a rather crude 
>>> combination of shell and python) but it does already work quite well 
>>> for me. [...]
[...]
 
> FWIW I switched my local mercurial2git conversion to the hg-fast-export 
> solution from 
> 
> 	git://repo.or.cz/fast-export.git
>
[...] 
> Originally, I did not try it because I thought it cannot operate in 
> incremental mode, but it can.

It can, or it can recently thanks to --export-marks / --import-marks
work?


It is nice that SCM-to-SCM converters seems to standarize on using
fast-import language as intermediary.  

IIRC fast-import by Shawn O. Pearce started as fast backend for first
cvs2git (unfortunately fork and not extension of cvs2svn) by Jon Smirl
(?) around time when Mozilla looked for SCM to move to from CVS.  (In
the end they choose Mercurial, mainly because of better Windows
support, and I think also better Windows GUI; I wonder how it works
for them now?).

-- 
Jakub Narebski
Poland
ShadeHawk on #git

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: Mercurial to git converter.
  2008-06-14 16:48     ` Jakub Narebski
@ 2008-06-16  2:24       ` Shawn O. Pearce
  0 siblings, 0 replies; 15+ messages in thread
From: Shawn O. Pearce @ 2008-06-16  2:24 UTC (permalink / raw)
  To: Jakub Narebski; +Cc: Johannes Schindelin, Nick Andrew, git

Jakub Narebski <jnareb@gmail.com> wrote:
> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:
> > FWIW I switched my local mercurial2git conversion to the hg-fast-export 
> > solution from 
> > 
> > 	git://repo.or.cz/fast-export.git
> >
> [...] 
> > Originally, I did not try it because I thought it cannot operate in 
> > incremental mode, but it can.
> 
> It can, or it can recently thanks to --export-marks / --import-marks
> work?

The recent --export-marks/import-marks work you speak of was adding
these options to git-fast-export, making it easier to perform an
incremental _export_ from Git to another SCM.  I believe Dscho
is speaking about an Hg->Git conversion, which would rely on
git-fast-import's previously existing --export-marks/import-marks
feature.
 
> It is nice that SCM-to-SCM converters seems to standarize on using
> fast-import language as intermediary.  

Turns out the little format we knocked together for this is able
to represent most conversions for SCMs.  I'm just happy users are
easily able to convert into Git.

> IIRC fast-import by Shawn O. Pearce started as fast backend for first
> cvs2git (unfortunately fork and not extension of cvs2svn) by Jon Smirl
> (?) around time when Mozilla looked for SCM to move to from CVS.  (In
> the end they choose Mercurial, mainly because of better Windows
> support, and I think also better Windows GUI; I wonder how it works
> for them now?).

Your history is correct.  The current version of cvs2svn also
supports cvs2git, and may also support cvs2bzr by using the
git-fast-import backend and bzr-fast-import as the parser.

-- 
Shawn.

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: Mercurial to git converter.
  2008-06-14 15:53   ` Johannes Schindelin
  2008-06-14 16:48     ` Jakub Narebski
@ 2008-06-16  8:21     ` Nick Andrew
  2008-06-16  8:26     ` Mike Hommey
  2 siblings, 0 replies; 15+ messages in thread
From: Nick Andrew @ 2008-06-16  8:21 UTC (permalink / raw)
  To: Johannes Schindelin; +Cc: git

[-- Attachment #1: Type: text/plain, Size: 648 bytes --]

On Sat, Jun 14, 2008 at 04:53:04PM +0100, Johannes Schindelin wrote:
> FWIW I switched my local mercurial2git conversion to the hg-fast-export 
> solution from 
> 
> 	git://repo.or.cz/fast-export.git

Yep.

In my case I needed to convert only a single repository with only a
few tens of commits, so the slow script was adequate for my use
... except for that problem with the changelog messages - which was
trivially fixed, so I posted to the list only to document the fix.

Nick.
-- 
PGP Key ID = 0x418487E7                      http://www.nick-andrew.net/
PGP Key fingerprint = B3ED 6894 8E49 1770 C24A  67E3 6266 6EB9 4184 87E7

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: Mercurial to git converter.
  2008-06-14 15:53   ` Johannes Schindelin
  2008-06-14 16:48     ` Jakub Narebski
  2008-06-16  8:21     ` Nick Andrew
@ 2008-06-16  8:26     ` Mike Hommey
  2008-06-17  9:12       ` Johannes Schindelin
  2 siblings, 1 reply; 15+ messages in thread
From: Mike Hommey @ 2008-06-16  8:26 UTC (permalink / raw)
  To: Johannes Schindelin; +Cc: git

On Sat, Jun 14, 2008 at 04:53:04PM +0100, Johannes Schindelin wrote:
> Hi,
> 
> On Sat, 14 Jun 2008, Nick Andrew wrote:
> 
> > Stelian Pop <stelian <at> popies.net> writes:
> > 
> > > I switched recently from Mercurial to git for some of my projects, and
> > > needed a conversion tool with branch support (unlike tailor). I didn't
> > > find any, so I ended up writing my own one. 
> > > 
> > > hg-to-git.py can probably be greatly improved (it's a rather crude 
> > > combination of shell and python) but it does already work quite well 
> > > for me. [...]
> > 
> > Thanks for that. One small problem is that it does not get the changelog 
> > right if a commit is made on a local branch. It thinks the "branch:" 
> > line is part of the changelog.
> 
> FWIW I switched my local mercurial2git conversion to the hg-fast-export 
> solution from 
> 
> 	git://repo.or.cz/fast-export.git

Would you happen to have a clonable mirror or this ? repo.or.cz doesn't
respond.

Mike

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: Mercurial to git converter.
  2008-06-16  8:26     ` Mike Hommey
@ 2008-06-17  9:12       ` Johannes Schindelin
  0 siblings, 0 replies; 15+ messages in thread
From: Johannes Schindelin @ 2008-06-17  9:12 UTC (permalink / raw)
  To: Mike Hommey; +Cc: git

Hi,

On Mon, 16 Jun 2008, Mike Hommey wrote:

> Would you happen to have a clonable mirror or this ? repo.or.cz doesn't 
> respond.

I'm sorry, I was travelling all day yesterday.  repo.or.cz is back, but I 
have a mirror for fast-export.git.  However, a few months ago, mugwump 
and me set up a mirror that should work (but AFAICT is http:// only): 
http://git.utsl.gen.nz/mirror/repo.or.cz/.

Ciao,
Dscho

^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2008-06-17  9:14 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-01-11 17:49 Mercurial to git converter Stelian Pop
2007-01-12 19:28 ` Jakub Narebski
2007-01-12 20:14   ` Stelian Pop
2007-01-12 21:57     ` [PATCH] Add hg-to-git conversion utility Stelian Pop
2007-01-12 22:15       ` Shawn O. Pearce
2007-01-12 23:00         ` Stelian Pop
2007-01-12 23:14           ` Junio C Hamano
2007-01-12 23:18             ` Stelian Pop
2008-06-14 10:23 ` Mercurial to git converter Nick Andrew
2008-06-14 15:53   ` Johannes Schindelin
2008-06-14 16:48     ` Jakub Narebski
2008-06-16  2:24       ` Shawn O. Pearce
2008-06-16  8:21     ` Nick Andrew
2008-06-16  8:26     ` Mike Hommey
2008-06-17  9:12       ` Johannes Schindelin

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).