Guest User

Untitled

a guest
Feb 19th, 2018
279
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 7.69 KB | None | 0 0
  1. #! /usr/bin/python
  2.  
  3. """ hg-to-git.py - A Mercurial to GIT converter
  4.  
  5. Copyright (C)2007 Stelian Pop <stelian@popies.net>
  6.  
  7. This program is free software; you can redistribute it and/or modify
  8. it under the terms of the GNU General Public License as published by
  9. the Free Software Foundation; either version 2, or (at your option)
  10. any later version.
  11.  
  12. This program is distributed in the hope that it will be useful,
  13. but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. GNU General Public License for more details.
  16.  
  17. You should have received a copy of the GNU General Public License
  18. along with this program; if not, write to the Free Software
  19. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20. """
  21.  
  22. import os, os.path, sys
  23. import tempfile, popen2, pickle, getopt
  24. import re
  25.  
  26. # Maps hg version -> git version
  27. hgvers = {}
  28. # List of children for each hg revision
  29. hgchildren = {}
  30. # List of parents for each hg revision
  31. hgparents = {}
  32. # Current branch for each hg revision
  33. hgbranch = {}
  34. # Number of new changesets converted from hg
  35. hgnewcsets = 0
  36.  
  37. #------------------------------------------------------------------------------
  38.  
  39. def usage():
  40.  
  41. print """\
  42. %s: [OPTIONS] <hgprj>
  43.  
  44. options:
  45. -s, --gitstate=FILE: name of the state to be saved/read
  46. for incrementals
  47. -n, --nrepack=INT: number of changesets that will trigger
  48. a repack (default=0, -1 to deactivate)
  49. -v, --verbose: be verbose
  50.  
  51. required:
  52. hgprj: name of the HG project to import (directory)
  53. """ % sys.argv[0]
  54.  
  55. #------------------------------------------------------------------------------
  56.  
  57. def getgitenv(user, date):
  58. env = ''
  59. elems = re.compile('(.*?)\s+<(.*)>').match(user)
  60. if elems:
  61. env += 'export GIT_AUTHOR_NAME="%s" ;' % elems.group(1)
  62. #env += 'export GIT_COMMITER_NAME="%s" ;' % elems.group(1)
  63. env += 'export GIT_AUTHOR_EMAIL="%s" ;' % elems.group(2)
  64. #env += 'export GIT_COMMITER_EMAIL="%s" ;' % elems.group(2)
  65. else:
  66. env += 'export GIT_AUTHOR_NAME="%s" ;' % user
  67. #env += 'export GIT_COMMITER_NAME="%s" ;' % user
  68. env += 'export GIT_AUTHOR_EMAIL= ;'
  69. #env += 'export GIT_COMMITER_EMAIL= ;'
  70.  
  71. env += 'export GIT_AUTHOR_DATE="%s" ;' % date
  72. #env += 'export GIT_COMMITTER_DATE="%s" ;' % date
  73. return env
  74.  
  75. #------------------------------------------------------------------------------
  76.  
  77. state = ''
  78. opt_nrepack = 0
  79. verbose = False
  80.  
  81. try:
  82. opts, args = getopt.getopt(sys.argv[1:], 's:t:n:v', ['gitstate=', 'tempdir=', 'nrepack=', 'verbose'])
  83. for o, a in opts:
  84. if o in ('-s', '--gitstate'):
  85. state = a
  86. state = os.path.abspath(state)
  87. if o in ('-n', '--nrepack'):
  88. opt_nrepack = int(a)
  89. if o in ('-v', '--verbose'):
  90. verbose = True
  91. if len(args) != 1:
  92. raise Exception('params')
  93. except:
  94. usage()
  95. sys.exit(1)
  96.  
  97. hgprj = args[0]
  98. os.chdir(hgprj)
  99.  
  100. if state:
  101. if os.path.exists(state):
  102. if verbose:
  103. print 'State does exist, reading'
  104. f = open(state, 'r')
  105. hgvers = pickle.load(f)
  106. else:
  107. print 'State does not exist, first run'
  108.  
  109. sock = os.popen('hg tip --template "{rev}"')
  110. tip = sock.read()
  111. if sock.close():
  112. sys.exit(1)
  113. if verbose:
  114. print 'tip is', tip
  115.  
  116. # Calculate the branches
  117. if verbose:
  118. print 'analysing the branches...'
  119. hgchildren["0"] = ()
  120. hgparents["0"] = (None, None)
  121. hgbranch["0"] = "master"
  122. for cset in range(1, int(tip) + 1):
  123. hgchildren[str(cset)] = ()
  124. prnts = os.popen('hg log -r %d --template "{parents}"' % cset).read().strip().split(' ')
  125. prnts = map(lambda x: x[:x.find(':')], prnts)
  126. if prnts[0] != '':
  127. parent = prnts[0].strip()
  128. else:
  129. parent = str(cset - 1)
  130. hgchildren[parent] += ( str(cset), )
  131. if len(prnts) > 1:
  132. mparent = prnts[1].strip()
  133. hgchildren[mparent] += ( str(cset), )
  134. else:
  135. mparent = None
  136.  
  137. hgparents[str(cset)] = (parent, mparent)
  138.  
  139. if mparent:
  140. # For merge changesets, take either one, preferably the 'master' branch
  141. if hgbranch[mparent] == 'master':
  142. hgbranch[str(cset)] = 'master'
  143. else:
  144. hgbranch[str(cset)] = hgbranch[parent]
  145. else:
  146. # Normal changesets
  147. # For first children, take the parent branch, for the others create a new branch
  148. if hgchildren[parent][0] == str(cset):
  149. hgbranch[str(cset)] = hgbranch[parent]
  150. else:
  151. hgbranch[str(cset)] = "branch-" + str(cset)
  152.  
  153. if not hgvers.has_key("0"):
  154. print 'creating repository'
  155. os.system('git init')
  156.  
  157. # loop through every hg changeset
  158. for cset in range(int(tip) + 1):
  159.  
  160. # incremental, already seen
  161. if hgvers.has_key(str(cset)):
  162. continue
  163. hgnewcsets += 1
  164.  
  165. # get info
  166. log_data = os.popen('hg log -r %d --template "{tags}\n{date|date}\n{author}\n"' % cset).readlines()
  167. tag = log_data[0].strip()
  168. date = log_data[1].strip()
  169. user = log_data[2].strip()
  170. parent = hgparents[str(cset)][0]
  171. mparent = hgparents[str(cset)][1]
  172.  
  173. #get comment
  174. (fdcomment, filecomment) = tempfile.mkstemp()
  175. csetcomment = os.popen('hg log -r %d --template "{desc}"' % cset).read().strip()
  176. os.write(fdcomment, csetcomment)
  177. os.close(fdcomment)
  178.  
  179. print '-----------------------------------------'
  180. print 'cset:', cset
  181. print 'branch:', hgbranch[str(cset)]
  182. print 'user:', user
  183. print 'date:', date
  184. print 'comment:', csetcomment
  185. if parent:
  186. print 'parent:', parent
  187. if mparent:
  188. print 'mparent:', mparent
  189. if tag:
  190. print 'tag:', tag
  191. print '-----------------------------------------'
  192.  
  193. # checkout the parent if necessary
  194. if cset != 0:
  195. if hgbranch[str(cset)] == "branch-" + str(cset):
  196. print 'creating new branch', hgbranch[str(cset)]
  197. os.system('git checkout -b %s %s' % (hgbranch[str(cset)], hgvers[parent]))
  198. else:
  199. print 'checking out branch', hgbranch[str(cset)]
  200. os.system('git checkout %s' % hgbranch[str(cset)])
  201.  
  202. # merge
  203. if mparent:
  204. if hgbranch[parent] == hgbranch[str(cset)]:
  205. otherbranch = hgbranch[mparent]
  206. else:
  207. otherbranch = hgbranch[parent]
  208. print 'merging', otherbranch, 'into', hgbranch[str(cset)]
  209. os.system(getgitenv(user, date) + 'git merge --no-commit -s ours "" %s %s' % (hgbranch[str(cset)], otherbranch))
  210.  
  211. # remove everything except .git and .hg directories
  212. os.system('find . \( -path "./.hg" -o -path "./.git" \) -prune -o ! -name "." -print | xargs rm -rf')
  213.  
  214. # repopulate with checkouted files
  215. os.system('hg update -C %d' % cset)
  216.  
  217. # add new files
  218. os.system('git ls-files -x .hg --others | git update-index --add --stdin')
  219. # delete removed files
  220. os.system('git ls-files -x .hg --deleted | git update-index --remove --stdin')
  221.  
  222. # commit
  223. os.system(getgitenv(user, date) + 'git commit --allow-empty -a -F %s' % filecomment)
  224. os.unlink(filecomment)
  225.  
  226. # tag
  227. if tag and tag != 'tip':
  228. os.system(getgitenv(user, date) + 'git tag %s' % tag)
  229.  
  230. # delete branch if not used anymore...
  231. if mparent and len(hgchildren[str(cset)]):
  232. print "Deleting unused branch:", otherbranch
  233. os.system('git branch -d %s' % otherbranch)
  234.  
  235. # retrieve and record the version
  236. vvv = os.popen('git show --quiet --pretty=format:%H').read()
  237. print 'record', cset, '->', vvv
  238. hgvers[str(cset)] = vvv
  239.  
  240. if hgnewcsets >= opt_nrepack and opt_nrepack != -1:
  241. os.system('git repack -a -d')
  242.  
  243. # write the state for incrementals
  244. if state:
  245. if verbose:
  246. print 'Writing state'
  247. f = open(state, 'w')
  248. pickle.dump(hgvers, f)
  249.  
  250. # vim: et ts=8 sw=4 sts=4
Add Comment
Please, Sign In to add comment