##// END OF EJS Templates
convert_git: add --filemap support
Alexis S. L. Carvalho -
r5380:a5a7f7fd default
parent child Browse files
Show More
@@ -1,124 +1,142 b''
1 # git support for the convert extension
1 # git support for the convert extension
2
2
3 import os
3 import os
4 from mercurial import util
4 from mercurial import util
5
5
6 from common import NoRepo, commit, converter_source
6 from common import NoRepo, commit, converter_source
7
7
8 class convert_git(converter_source):
8 class convert_git(converter_source):
9 # Windows does not support GIT_DIR= construct while other systems
9 # Windows does not support GIT_DIR= construct while other systems
10 # cannot remove environment variable. Just assume none have
10 # cannot remove environment variable. Just assume none have
11 # both issues.
11 # both issues.
12 if hasattr(os, 'unsetenv'):
12 if hasattr(os, 'unsetenv'):
13 def gitcmd(self, s):
13 def gitcmd(self, s):
14 prevgitdir = os.environ.get('GIT_DIR')
14 prevgitdir = os.environ.get('GIT_DIR')
15 os.environ['GIT_DIR'] = self.path
15 os.environ['GIT_DIR'] = self.path
16 try:
16 try:
17 return os.popen(s)
17 return os.popen(s)
18 finally:
18 finally:
19 if prevgitdir is None:
19 if prevgitdir is None:
20 del os.environ['GIT_DIR']
20 del os.environ['GIT_DIR']
21 else:
21 else:
22 os.environ['GIT_DIR'] = prevgitdir
22 os.environ['GIT_DIR'] = prevgitdir
23 else:
23 else:
24 def gitcmd(self, s):
24 def gitcmd(self, s):
25 return os.popen('GIT_DIR=%s %s' % (self.path, s))
25 return os.popen('GIT_DIR=%s %s' % (self.path, s))
26
26
27 def __init__(self, ui, path, rev=None):
27 def __init__(self, ui, path, rev=None):
28 super(convert_git, self).__init__(ui, path, rev=rev)
28 super(convert_git, self).__init__(ui, path, rev=rev)
29
29
30 if os.path.isdir(path + "/.git"):
30 if os.path.isdir(path + "/.git"):
31 path += "/.git"
31 path += "/.git"
32 if not os.path.exists(path + "/objects"):
32 if not os.path.exists(path + "/objects"):
33 raise NoRepo("couldn't open GIT repo %s" % path)
33 raise NoRepo("couldn't open GIT repo %s" % path)
34 self.path = path
34 self.path = path
35
35
36 def getheads(self):
36 def getheads(self):
37 if not self.rev:
37 if not self.rev:
38 return self.gitcmd('git-rev-parse --branches').read().splitlines()
38 return self.gitcmd('git-rev-parse --branches').read().splitlines()
39 else:
39 else:
40 fh = self.gitcmd("git-rev-parse --verify %s" % self.rev)
40 fh = self.gitcmd("git-rev-parse --verify %s" % self.rev)
41 return [fh.read()[:-1]]
41 return [fh.read()[:-1]]
42
42
43 def catfile(self, rev, type):
43 def catfile(self, rev, type):
44 if rev == "0" * 40: raise IOError()
44 if rev == "0" * 40: raise IOError()
45 fh = self.gitcmd("git-cat-file %s %s 2>%s" % (type, rev,
45 fh = self.gitcmd("git-cat-file %s %s 2>%s" % (type, rev,
46 util.nulldev))
46 util.nulldev))
47 return fh.read()
47 return fh.read()
48
48
49 def getfile(self, name, rev):
49 def getfile(self, name, rev):
50 return self.catfile(rev, "blob")
50 return self.catfile(rev, "blob")
51
51
52 def getmode(self, name, rev):
52 def getmode(self, name, rev):
53 return self.modecache[(name, rev)]
53 return self.modecache[(name, rev)]
54
54
55 def getchanges(self, version):
55 def getchanges(self, version):
56 self.modecache = {}
56 self.modecache = {}
57 fh = self.gitcmd("git-diff-tree --root -m -r %s" % version)
57 fh = self.gitcmd("git-diff-tree --root -m -r %s" % version)
58 changes = []
58 changes = []
59 seen = {}
59 seen = {}
60 for l in fh:
60 for l in fh:
61 if "\t" not in l:
61 if "\t" not in l:
62 continue
62 continue
63 m, f = l[:-1].split("\t")
63 m, f = l[:-1].split("\t")
64 if f in seen:
64 if f in seen:
65 continue
65 continue
66 seen[f] = 1
66 seen[f] = 1
67 m = m.split()
67 m = m.split()
68 h = m[3]
68 h = m[3]
69 p = (m[1] == "100755")
69 p = (m[1] == "100755")
70 s = (m[1] == "120000")
70 s = (m[1] == "120000")
71 self.modecache[(f, h)] = (p and "x") or (s and "l") or ""
71 self.modecache[(f, h)] = (p and "x") or (s and "l") or ""
72 changes.append((f, h))
72 changes.append((f, h))
73 return (changes, {})
73 return (changes, {})
74
74
75 def getcommit(self, version):
75 def getcommit(self, version):
76 c = self.catfile(version, "commit") # read the commit hash
76 c = self.catfile(version, "commit") # read the commit hash
77 end = c.find("\n\n")
77 end = c.find("\n\n")
78 message = c[end+2:]
78 message = c[end+2:]
79 message = self.recode(message)
79 message = self.recode(message)
80 l = c[:end].splitlines()
80 l = c[:end].splitlines()
81 manifest = l[0].split()[1]
81 manifest = l[0].split()[1]
82 parents = []
82 parents = []
83 for e in l[1:]:
83 for e in l[1:]:
84 n, v = e.split(" ", 1)
84 n, v = e.split(" ", 1)
85 if n == "author":
85 if n == "author":
86 p = v.split()
86 p = v.split()
87 tm, tz = p[-2:]
87 tm, tz = p[-2:]
88 author = " ".join(p[:-2])
88 author = " ".join(p[:-2])
89 if author[0] == "<": author = author[1:-1]
89 if author[0] == "<": author = author[1:-1]
90 author = self.recode(author)
90 author = self.recode(author)
91 if n == "committer":
91 if n == "committer":
92 p = v.split()
92 p = v.split()
93 tm, tz = p[-2:]
93 tm, tz = p[-2:]
94 committer = " ".join(p[:-2])
94 committer = " ".join(p[:-2])
95 if committer[0] == "<": committer = committer[1:-1]
95 if committer[0] == "<": committer = committer[1:-1]
96 committer = self.recode(committer)
96 committer = self.recode(committer)
97 message += "\ncommitter: %s\n" % committer
97 message += "\ncommitter: %s\n" % committer
98 if n == "parent": parents.append(v)
98 if n == "parent": parents.append(v)
99
99
100 tzs, tzh, tzm = tz[-5:-4] + "1", tz[-4:-2], tz[-2:]
100 tzs, tzh, tzm = tz[-5:-4] + "1", tz[-4:-2], tz[-2:]
101 tz = -int(tzs) * (int(tzh) * 3600 + int(tzm))
101 tz = -int(tzs) * (int(tzh) * 3600 + int(tzm))
102 date = tm + " " + str(tz)
102 date = tm + " " + str(tz)
103 author = author or "unknown"
103 author = author or "unknown"
104
104
105 c = commit(parents=parents, date=date, author=author, desc=message,
105 c = commit(parents=parents, date=date, author=author, desc=message,
106 rev=version)
106 rev=version)
107 return c
107 return c
108
108
109 def gettags(self):
109 def gettags(self):
110 tags = {}
110 tags = {}
111 fh = self.gitcmd('git-ls-remote --tags "%s" 2>%s' % (self.path,
111 fh = self.gitcmd('git-ls-remote --tags "%s" 2>%s' % (self.path,
112 util.nulldev))
112 util.nulldev))
113 prefix = 'refs/tags/'
113 prefix = 'refs/tags/'
114 for line in fh:
114 for line in fh:
115 line = line.strip()
115 line = line.strip()
116 if not line.endswith("^{}"):
116 if not line.endswith("^{}"):
117 continue
117 continue
118 node, tag = line.split(None, 1)
118 node, tag = line.split(None, 1)
119 if not tag.startswith(prefix):
119 if not tag.startswith(prefix):
120 continue
120 continue
121 tag = tag[len(prefix):-3]
121 tag = tag[len(prefix):-3]
122 tags[tag] = node
122 tags[tag] = node
123
123
124 return tags
124 return tags
125
126 def getchangedfiles(self, version, i):
127 changes = []
128 if i is None:
129 fh = self.gitcmd("git-diff-tree --root -m -r %s" % version)
130 for l in fh:
131 if "\t" not in l:
132 continue
133 m, f = l[:-1].split("\t")
134 changes.append(f)
135 fh.close()
136 else:
137 fh = self.gitcmd("git-diff-tree --name-only --root -r %s %s^%s --"
138 % (version, version, i+1))
139 changes = [f.rstrip('\n') for f in fh]
140 fh.close()
141
142 return changes
@@ -1,56 +1,132 b''
1 #!/bin/sh
1 #!/bin/sh
2
2
3 "$TESTDIR/hghave" git || exit 80
3 "$TESTDIR/hghave" git || exit 80
4
4
5 echo "[extensions]" >> $HGRCPATH
5 echo "[extensions]" >> $HGRCPATH
6 echo "convert=" >> $HGRCPATH
6 echo "convert=" >> $HGRCPATH
7 echo 'hgext.graphlog =' >> $HGRCPATH
7
8
8 GIT_AUTHOR_NAME='test'; export GIT_AUTHOR_NAME
9 GIT_AUTHOR_NAME='test'; export GIT_AUTHOR_NAME
9 GIT_AUTHOR_EMAIL='test@example.org'; export GIT_AUTHOR_EMAIL
10 GIT_AUTHOR_EMAIL='test@example.org'; export GIT_AUTHOR_EMAIL
10 GIT_AUTHOR_DATE="2007-01-01 00:00:00 +0000"; export GIT_AUTHOR_DATE
11 GIT_AUTHOR_DATE="2007-01-01 00:00:00 +0000"; export GIT_AUTHOR_DATE
11 GIT_COMMITTER_NAME="$GIT_AUTHOR_NAME"; export GIT_COMMITTER_NAME
12 GIT_COMMITTER_NAME="$GIT_AUTHOR_NAME"; export GIT_COMMITTER_NAME
12 GIT_COMMITTER_EMAIL="$GIT_AUTHOR_EMAIL"; export GIT_COMMITTER_EMAIL
13 GIT_COMMITTER_EMAIL="$GIT_AUTHOR_EMAIL"; export GIT_COMMITTER_EMAIL
13 GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE"; export GIT_COMMITTER_DATE
14 GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE"; export GIT_COMMITTER_DATE
14
15
15 count=10
16 count=10
16 commit()
17 commit()
17 {
18 {
18 GIT_AUTHOR_DATE="2007-01-01 00:00:$count +0000"
19 GIT_AUTHOR_DATE="2007-01-01 00:00:$count +0000"
19 GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE"
20 GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE"
20 git commit "$@" >/dev/null 2>/dev/null || echo "git commit error"
21 git commit "$@" >/dev/null 2>/dev/null || echo "git commit error"
21 count=`expr $count + 1`
22 count=`expr $count + 1`
22 }
23 }
23
24
24 mkdir git-repo
25 mkdir git-repo
25 cd git-repo
26 cd git-repo
26 git init-db >/dev/null 2>/dev/null
27 git init-db >/dev/null 2>/dev/null
27 echo a > a
28 echo a > a
28 mkdir d
29 mkdir d
29 echo b > d/b
30 echo b > d/b
30 git add a d
31 git add a d
31 commit -a -m t1
32 commit -a -m t1
32
33
33 # Remove the directory, then try to replace it with a file
34 # Remove the directory, then try to replace it with a file
34 # (issue 754)
35 # (issue 754)
35 git rm -f d/b
36 git rm -f d/b
36 commit -m t2
37 commit -m t2
37 echo d > d
38 echo d > d
38 git add d
39 git add d
39 commit -m t3
40 commit -m t3
40
41
41 echo b >> a
42 echo b >> a
42 commit -a -m t4.1
43 commit -a -m t4.1
43
44
44 git checkout -b other HEAD^ >/dev/null 2>/dev/null
45 git checkout -b other HEAD^ >/dev/null 2>/dev/null
45 echo c > a
46 echo c > a
46 echo a >> a
47 echo a >> a
47 commit -a -m t4.2
48 commit -a -m t4.2
48
49
49 git checkout master >/dev/null 2>/dev/null
50 git checkout master >/dev/null 2>/dev/null
50 git pull --no-commit . other > /dev/null 2>/dev/null
51 git pull --no-commit . other > /dev/null 2>/dev/null
51 commit -m 'Merge branch other'
52 commit -m 'Merge branch other'
52 cd ..
53 cd ..
53
54
54 hg convert --datesort git-repo
55 hg convert --datesort git-repo
55
56
56 hg -R git-repo-hg tip -v
57 hg -R git-repo-hg tip -v
58
59 count=10
60 mkdir git-repo2
61 cd git-repo2
62 git init-db >/dev/null 2>/dev/null
63
64 echo foo > foo
65 git add foo
66 commit -a -m 'add foo'
67
68 echo >> foo
69 commit -a -m 'change foo'
70
71 git checkout -b Bar HEAD^ >/dev/null 2>/dev/null
72 echo quux >> quux
73 git add quux
74 commit -a -m 'add quux'
75
76 echo bar > bar
77 git add bar
78 commit -a -m 'add bar'
79
80 git checkout -b Baz HEAD^ >/dev/null 2>/dev/null
81 echo baz > baz
82 git add baz
83 commit -a -m 'add baz'
84
85 git checkout master >/dev/null 2>/dev/null
86 git pull --no-commit . Bar Baz > /dev/null 2>/dev/null
87 commit -m 'Octopus merge'
88
89 echo bar >> bar
90 commit -a -m 'change bar'
91
92 git checkout -b Foo HEAD^ >/dev/null 2>/dev/null
93 echo >> foo
94 commit -a -m 'change foo'
95
96 git checkout master >/dev/null 2>/dev/null
97 git pull --no-commit -s ours . Foo > /dev/null 2>/dev/null
98 commit -m 'Discard change to foo'
99
100 cd ..
101
102 glog()
103 {
104 hg glog --template '#rev# "#desc|firstline#" files: #files#\n' "$@"
105 }
106
107 splitrepo()
108 {
109 msg="$1"
110 files="$2"
111 opts=$3
112 echo "% $files: $msg"
113 prefix=`echo "$files" | sed -e 's/ /-/g'`
114 fmap="$prefix.fmap"
115 repo="$prefix.repo"
116 for i in $files; do
117 echo "include $i" >> "$fmap"
118 done
119 hg -q convert $opts --filemap "$fmap" --datesort git-repo2 "$repo"
120 glog -R "$repo"
121 hg -R "$repo" manifest --debug
122 }
123
124 echo '% full conversion'
125 hg -q convert --datesort git-repo2 fullrepo
126 glog -R fullrepo
127 hg -R fullrepo manifest --debug
128
129 splitrepo 'octopus merge' 'foo bar baz'
130
131 splitrepo 'only some parents of an octopus merge; "discard" a head' 'foo baz quux'
132
@@ -1,25 +1,90 b''
1 rm 'd/b'
1 rm 'd/b'
2 assuming destination git-repo-hg
2 assuming destination git-repo-hg
3 initializing destination git-repo-hg repository
3 initializing destination git-repo-hg repository
4 scanning source...
4 scanning source...
5 sorting...
5 sorting...
6 converting...
6 converting...
7 5 t1
7 5 t1
8 4 t2
8 4 t2
9 3 t3
9 3 t3
10 2 t4.1
10 2 t4.1
11 1 t4.2
11 1 t4.2
12 0 Merge branch other
12 0 Merge branch other
13 changeset: 5:c6d72c98aa00
13 changeset: 5:c6d72c98aa00
14 tag: tip
14 tag: tip
15 parent: 3:a18bdfccf429
15 parent: 3:a18bdfccf429
16 parent: 4:48cb5b72ce56
16 parent: 4:48cb5b72ce56
17 user: test <test@example.org>
17 user: test <test@example.org>
18 date: Mon Jan 01 00:00:15 2007 +0000
18 date: Mon Jan 01 00:00:15 2007 +0000
19 files: a
19 files: a
20 description:
20 description:
21 Merge branch other
21 Merge branch other
22
22
23 committer: test <test@example.org>
23 committer: test <test@example.org>
24
24
25
25
26 % full conversion
27 o 9 "Discard change to foo" files: foo
28 |\
29 | o 8 "change foo" files: foo
30 | |
31 o | 7 "change bar" files: bar
32 |/
33 o 6 "(octopus merge fixup)" files:
34 |\
35 | o 5 "Octopus merge" files: baz
36 | |\
37 o | | 4 "add baz" files: baz
38 | | |
39 +---o 3 "add bar" files: bar
40 | |
41 o | 2 "add quux" files: quux
42 | |
43 | o 1 "change foo" files: foo
44 |/
45 o 0 "add foo" files: foo
46
47 245a3b8bc653999c2b22cdabd517ccb47aecafdf 644 bar
48 354ae8da6e890359ef49ade27b68bbc361f3ca88 644 baz
49 9277c9cc8dd4576fc01a17939b4351e5ada93466 644 foo
50 88dfeab657e8cf2cef3dec67b914f49791ae76b1 644 quux
51 % foo bar baz: octopus merge
52 o 8 "Discard change to foo" files: foo
53 |\
54 | o 7 "change foo" files: foo
55 | |
56 o | 6 "change bar" files: bar
57 |/
58 o 5 "(octopus merge fixup)" files:
59 |\
60 | o 4 "Octopus merge" files: baz
61 | |\
62 o | | 3 "add baz" files: baz
63 | | |
64 +---o 2 "add bar" files: bar
65 | |
66 | o 1 "change foo" files: foo
67 |/
68 o 0 "add foo" files: foo
69
70 245a3b8bc653999c2b22cdabd517ccb47aecafdf 644 bar
71 354ae8da6e890359ef49ade27b68bbc361f3ca88 644 baz
72 9277c9cc8dd4576fc01a17939b4351e5ada93466 644 foo
73 % foo baz quux: only some parents of an octopus merge; "discard" a head
74 o 6 "Discard change to foo" files: foo
75 |
76 o 5 "change foo" files: foo
77 |
78 o 4 "Octopus merge" files:
79 |\
80 | o 3 "add baz" files: baz
81 | |
82 | o 2 "add quux" files: quux
83 | |
84 o | 1 "change foo" files: foo
85 |/
86 o 0 "add foo" files: foo
87
88 354ae8da6e890359ef49ade27b68bbc361f3ca88 644 baz
89 9277c9cc8dd4576fc01a17939b4351e5ada93466 644 foo
90 88dfeab657e8cf2cef3dec67b914f49791ae76b1 644 quux
General Comments 0
You need to be logged in to leave comments. Login now