f03884fbff08cd246aeb5d3317ffa99eca95ec33
[invirt/scripts/git-migration.git] / git-migrate
1 #!/usr/bin/python
2
3 import os
4 import sys
5 import subprocess
6 import shutil
7
8 def tagBase(pkg):
9     p = subprocess.Popen(['git', 'tag',
10                           '-l',
11                           'base'],
12                          cwd='%s.git' % pkg,
13                          stdout=subprocess.PIPE)
14     p.wait()
15     if p.stdout.read().strip() != '':
16         return
17     
18     p = subprocess.Popen(['git', 'rev-list',
19                           '--reverse',
20                           'master'],
21                          cwd='%s.git' % pkg,
22                          stdout=subprocess.PIPE)
23     p.wait()
24     base = p.stdout.read().split()[0]
25     
26     subprocess.check_call(['git', 'tag',
27                            'base',
28                            base],
29                           cwd='%s.git' % pkg)
30
31 def clonePackage(base, pkg):
32     if not os.path.isdir('%s.git' % pkg):
33         if os.path.isdir(pkg):
34             shutil.rmtree(pkg)
35         # Use --no-follow-parent because we're going to handle that with
36         # grafts.
37         subprocess.check_call(['git', 'svn', 'clone',
38                                '--no-follow-parent',
39                                '-Aauthors',
40                                '-q',
41                                '--no-metadata',
42                                '%s/packages/%s' % (base, pkg)],
43                               stdout=subprocess.PIPE)
44         
45         # Then make the repository bare, because git-svn can't do this
46         shutil.move('%s/.git' % pkg, '%s.git' % pkg)
47         shutil.rmtree(pkg)
48         subprocess.check_call(['git', 'config', 'core.bare', 'true'],
49                               cwd='%s.git' % pkg)
50         
51     # Some of these repos have a rev where everything was deleted
52     # as a result of the move. We don't want that rev to exist.
53     p = subprocess.Popen(['git', 'ls-tree', 'HEAD'],
54                          cwd='%s.git' % pkg,
55                          stdout=subprocess.PIPE)
56     p.wait()
57     if len(p.stdout.read()) == 0:
58         subprocess.check_call(['git', 'reset', '--soft', 'HEAD^'],
59                               cwd='%s.git' % pkg)
60     
61     tagBase(pkg)
62
63 def cloneAllPackages(base):
64     for pkg in open('package-list'):
65         clonePackage(base, pkg.strip())
66
67 def mergeHistory(old_pkg, new_pkg, n):
68     n = int(n)
69     
70     subprocess.check_call(['git', 'push',
71                            '../%s.git' % new_pkg,
72                            'master:refs/heads/%s' % old_pkg],
73                           cwd='%s.git' % old_pkg)
74     
75     # Find the merge commit
76     if n == 0:
77         p = subprocess.Popen(['git', 'rev-parse',
78                               'base'],
79                              cwd='%s.git' % new_pkg,
80                              stdout=subprocess.PIPE)
81     else:
82         p = subprocess.Popen(['git', 'rev-list',
83                               '--reverse',
84                               '--boundary',
85                               '--skip=%s' % (n - 1),
86                               'base..master'],
87                              cwd='%s.git' % new_pkg,
88                              stdout=subprocess.PIPE)
89     p.wait()
90     new_rev = p.stdout.read().split()[0].strip('-')
91     
92     # Find any other parents of the merge commit
93     p = subprocess.Popen(['git', 'log',
94                           '-1',
95                           '--pretty=format:%P',
96                           new_rev],
97                          cwd='%s.git' % new_pkg,
98                          stdout=subprocess.PIPE)
99     p.wait()
100     parents = p.stdout.read().split()
101     
102     # Find the additional parent we're adding
103     p = subprocess.Popen(['git', 'rev-parse',
104                           old_pkg],
105                          cwd='%s.git' % new_pkg,
106                          stdout=subprocess.PIPE)
107     p.wait()
108     parents.append(p.stdout.read().strip())
109     
110     # Write out the grafts file
111     f = open('%s.git/info/grafts' % new_pkg, 'a')
112     print >>f, '%s %s' % (new_rev, ' '.join(parents))
113     f.close()
114     
115     # Run filter-branch
116     subprocess.call(['git', 'filter-branch',
117                      '--tag-name-filter', 'cat',
118                      '--',
119                      '--all'],
120                     cwd='%s.git' % new_pkg)
121
122 def mergeHistories():
123     merges = []
124     for line in open('merges'):
125         line = line.strip()
126         if line == '' or line[0] == '#':
127             continue
128         
129         merges.append(line.split())
130     
131     for merge in merges:
132         mergeHistory(*merge)
133
134 if __name__ == '__main__':
135     try:
136         base = sys.argv[1]
137     except:
138         base = 'svn://invirt.mit.edu/trunk'
139     
140     cloneAllPackages(base)
141     mergeHistories()