##// END OF EJS Templates
hgk "committer:" bug...
Hollis Blanchard -
r1950:5f581f33 default
parent child Browse files
Show More
@@ -1,339 +1,339
1 # Minimal support for git commands on an hg repository
1 # Minimal support for git commands on an hg repository
2 #
2 #
3 # Copyright 2005 Chris Mason <mason@suse.com>
3 # Copyright 2005 Chris Mason <mason@suse.com>
4 #
4 #
5 # This software may be used and distributed according to the terms
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
7
7
8 import time, sys, signal, os
8 import time, sys, signal, os
9 from mercurial import hg, mdiff, fancyopts, commands, ui, util
9 from mercurial import hg, mdiff, fancyopts, commands, ui, util
10
10
11 def dodiff(fp, ui, repo, node1, node2, files=None, match=util.always,
11 def dodiff(fp, ui, repo, node1, node2, files=None, match=util.always,
12 changes=None, text=False):
12 changes=None, text=False):
13 def date(c):
13 def date(c):
14 return time.asctime(time.gmtime(c[2][0]))
14 return time.asctime(time.gmtime(c[2][0]))
15
15
16 if not changes:
16 if not changes:
17 changes = repo.changes(node1, node2, files, match=match)
17 changes = repo.changes(node1, node2, files, match=match)
18 modified, added, removed, deleted, unknown = changes
18 modified, added, removed, deleted, unknown = changes
19 if files:
19 if files:
20 modified, added, removed = map(lambda x: filterfiles(files, x),
20 modified, added, removed = map(lambda x: filterfiles(files, x),
21 (modified, added, removed))
21 (modified, added, removed))
22
22
23 if not modified and not added and not removed:
23 if not modified and not added and not removed:
24 return
24 return
25
25
26 if node2:
26 if node2:
27 change = repo.changelog.read(node2)
27 change = repo.changelog.read(node2)
28 mmap2 = repo.manifest.read(change[0])
28 mmap2 = repo.manifest.read(change[0])
29 date2 = date(change)
29 date2 = date(change)
30 def read(f):
30 def read(f):
31 return repo.file(f).read(mmap2[f])
31 return repo.file(f).read(mmap2[f])
32 else:
32 else:
33 date2 = time.asctime()
33 date2 = time.asctime()
34 if not node1:
34 if not node1:
35 node1 = repo.dirstate.parents()[0]
35 node1 = repo.dirstate.parents()[0]
36 def read(f):
36 def read(f):
37 return repo.wfile(f).read()
37 return repo.wfile(f).read()
38
38
39 change = repo.changelog.read(node1)
39 change = repo.changelog.read(node1)
40 mmap = repo.manifest.read(change[0])
40 mmap = repo.manifest.read(change[0])
41 date1 = date(change)
41 date1 = date(change)
42
42
43 for f in modified:
43 for f in modified:
44 to = None
44 to = None
45 if f in mmap:
45 if f in mmap:
46 to = repo.file(f).read(mmap[f])
46 to = repo.file(f).read(mmap[f])
47 tn = read(f)
47 tn = read(f)
48 fp.write("diff --git a/%s b/%s\n" % (f, f))
48 fp.write("diff --git a/%s b/%s\n" % (f, f))
49 fp.write(mdiff.unidiff(to, date1, tn, date2, f, None, text=text))
49 fp.write(mdiff.unidiff(to, date1, tn, date2, f, None, text=text))
50 for f in added:
50 for f in added:
51 to = None
51 to = None
52 tn = read(f)
52 tn = read(f)
53 fp.write("diff --git /dev/null b/%s\n" % (f))
53 fp.write("diff --git /dev/null b/%s\n" % (f))
54 fp.write(mdiff.unidiff(to, date1, tn, date2, f, None, text=text))
54 fp.write(mdiff.unidiff(to, date1, tn, date2, f, None, text=text))
55 for f in removed:
55 for f in removed:
56 to = repo.file(f).read(mmap[f])
56 to = repo.file(f).read(mmap[f])
57 tn = None
57 tn = None
58 fp.write("diff --git a/%s /dev/null\n" % (f))
58 fp.write("diff --git a/%s /dev/null\n" % (f))
59 fp.write(mdiff.unidiff(to, date1, tn, date2, f, None, text=text))
59 fp.write(mdiff.unidiff(to, date1, tn, date2, f, None, text=text))
60
60
61 def difftree(ui, repo, node1=None, node2=None, **opts):
61 def difftree(ui, repo, node1=None, node2=None, **opts):
62 """diff trees from two commits"""
62 """diff trees from two commits"""
63 def __difftree(repo, node1, node2):
63 def __difftree(repo, node1, node2):
64 def date(c):
64 def date(c):
65 return time.asctime(time.gmtime(c[2][0]))
65 return time.asctime(time.gmtime(c[2][0]))
66
66
67 if node2:
67 if node2:
68 change = repo.changelog.read(node2)
68 change = repo.changelog.read(node2)
69 mmap2 = repo.manifest.read(change[0])
69 mmap2 = repo.manifest.read(change[0])
70 modified, added, removed, deleted, unknown = repo.changes(node1, node2)
70 modified, added, removed, deleted, unknown = repo.changes(node1, node2)
71 def read(f): return repo.file(f).read(mmap2[f])
71 def read(f): return repo.file(f).read(mmap2[f])
72 date2 = date(change)
72 date2 = date(change)
73 else:
73 else:
74 date2 = time.asctime()
74 date2 = time.asctime()
75 modified, added, removed, deleted, unknown = repo.changes(node1)
75 modified, added, removed, deleted, unknown = repo.changes(node1)
76 if not node1:
76 if not node1:
77 node1 = repo.dirstate.parents()[0]
77 node1 = repo.dirstate.parents()[0]
78 def read(f): return file(os.path.join(repo.root, f)).read()
78 def read(f): return file(os.path.join(repo.root, f)).read()
79
79
80 change = repo.changelog.read(node1)
80 change = repo.changelog.read(node1)
81 mmap = repo.manifest.read(change[0])
81 mmap = repo.manifest.read(change[0])
82 date1 = date(change)
82 date1 = date(change)
83 empty = "0" * 40;
83 empty = "0" * 40;
84
84
85 for f in modified:
85 for f in modified:
86 # TODO get file permissions
86 # TODO get file permissions
87 print ":100664 100664 %s %s M\t%s\t%s" % (hg.hex(mmap[f]),
87 print ":100664 100664 %s %s M\t%s\t%s" % (hg.hex(mmap[f]),
88 hg.hex(mmap2[f]), f, f)
88 hg.hex(mmap2[f]), f, f)
89 for f in added:
89 for f in added:
90 print ":000000 100664 %s %s N\t%s\t%s" % (empty, hg.hex(mmap2[f]), f, f)
90 print ":000000 100664 %s %s N\t%s\t%s" % (empty, hg.hex(mmap2[f]), f, f)
91 for f in removed:
91 for f in removed:
92 print ":100664 000000 %s %s D\t%s\t%s" % (hg.hex(mmap[f]), empty, f, f)
92 print ":100664 000000 %s %s D\t%s\t%s" % (hg.hex(mmap[f]), empty, f, f)
93 ##
93 ##
94
94
95 while True:
95 while True:
96 if opts['stdin']:
96 if opts['stdin']:
97 try:
97 try:
98 line = raw_input().split(' ')
98 line = raw_input().split(' ')
99 node1 = line[0]
99 node1 = line[0]
100 if len(line) > 1:
100 if len(line) > 1:
101 node2 = line[1]
101 node2 = line[1]
102 else:
102 else:
103 node2 = None
103 node2 = None
104 except EOFError:
104 except EOFError:
105 break
105 break
106 node1 = repo.lookup(node1)
106 node1 = repo.lookup(node1)
107 if node2:
107 if node2:
108 node2 = repo.lookup(node2)
108 node2 = repo.lookup(node2)
109 else:
109 else:
110 node2 = node1
110 node2 = node1
111 node1 = repo.changelog.parents(node1)[0]
111 node1 = repo.changelog.parents(node1)[0]
112 if opts['patch']:
112 if opts['patch']:
113 if opts['pretty']:
113 if opts['pretty']:
114 catcommit(repo, node2, "")
114 catcommit(repo, node2, "")
115 dodiff(sys.stdout, ui, repo, node1, node2)
115 dodiff(sys.stdout, ui, repo, node1, node2)
116 else:
116 else:
117 __difftree(repo, node1, node2)
117 __difftree(repo, node1, node2)
118 if not opts['stdin']:
118 if not opts['stdin']:
119 break
119 break
120
120
121 def catcommit(repo, n, prefix, changes=None):
121 def catcommit(repo, n, prefix, changes=None):
122 nlprefix = '\n' + prefix;
122 nlprefix = '\n' + prefix;
123 (p1, p2) = repo.changelog.parents(n)
123 (p1, p2) = repo.changelog.parents(n)
124 (h, h1, h2) = map(hg.hex, (n, p1, p2))
124 (h, h1, h2) = map(hg.hex, (n, p1, p2))
125 (i1, i2) = map(repo.changelog.rev, (p1, p2))
125 (i1, i2) = map(repo.changelog.rev, (p1, p2))
126 if not changes:
126 if not changes:
127 changes = repo.changelog.read(n)
127 changes = repo.changelog.read(n)
128 print "tree %s" % (hg.hex(changes[0]))
128 print "tree %s" % (hg.hex(changes[0]))
129 if i1 != -1: print "parent %s" % (h1)
129 if i1 != -1: print "parent %s" % (h1)
130 if i2 != -1: print "parent %s" % (h2)
130 if i2 != -1: print "parent %s" % (h2)
131 date_ar = changes[2]
131 date_ar = changes[2]
132 date = int(float(date_ar[0]))
132 date = int(float(date_ar[0]))
133 lines = changes[4].splitlines()
133 lines = changes[4].splitlines()
134 if lines[-1].startswith('committer:'):
134 if lines[-1].startswith('committer:'):
135 committer = lines[-1].split(': ')[1].rstrip()
135 committer = lines[-1].split(': ')[1].rstrip()
136 else:
136 else:
137 committer = "%s %s %s" % (changes[1], date, date_ar[1])
137 committer = changes[1]
138
138
139 print "author %s %s %s" % (changes[1], date, date_ar[1])
139 print "author %s %s %s" % (changes[1], date, date_ar[1])
140 print "committer %s" % (committer)
140 print "committer %s %s %s" % (committer, date, date_ar[1])
141 print ""
141 print ""
142 if prefix != "":
142 if prefix != "":
143 print "%s%s" % (prefix, changes[4].replace('\n', nlprefix).strip())
143 print "%s%s" % (prefix, changes[4].replace('\n', nlprefix).strip())
144 else:
144 else:
145 print changes[4]
145 print changes[4]
146 if prefix:
146 if prefix:
147 sys.stdout.write('\0')
147 sys.stdout.write('\0')
148
148
149 def base(ui, repo, node1, node2):
149 def base(ui, repo, node1, node2):
150 """Output common ancestor information"""
150 """Output common ancestor information"""
151 node1 = repo.lookup(node1)
151 node1 = repo.lookup(node1)
152 node2 = repo.lookup(node2)
152 node2 = repo.lookup(node2)
153 n = repo.changelog.ancestor(node1, node2)
153 n = repo.changelog.ancestor(node1, node2)
154 print hg.hex(n)
154 print hg.hex(n)
155
155
156 def catfile(ui, repo, type=None, r=None, **opts):
156 def catfile(ui, repo, type=None, r=None, **opts):
157 """cat a specific revision"""
157 """cat a specific revision"""
158 # in stdin mode, every line except the commit is prefixed with two
158 # in stdin mode, every line except the commit is prefixed with two
159 # spaces. This way the our caller can find the commit without magic
159 # spaces. This way the our caller can find the commit without magic
160 # strings
160 # strings
161 #
161 #
162 prefix = ""
162 prefix = ""
163 if opts['stdin']:
163 if opts['stdin']:
164 try:
164 try:
165 (type, r) = raw_input().split(' ');
165 (type, r) = raw_input().split(' ');
166 prefix = " "
166 prefix = " "
167 except EOFError:
167 except EOFError:
168 return
168 return
169
169
170 else:
170 else:
171 if not type or not r:
171 if not type or not r:
172 ui.warn("cat-file: type or revision not supplied\n")
172 ui.warn("cat-file: type or revision not supplied\n")
173 commands.help_(ui, 'cat-file')
173 commands.help_(ui, 'cat-file')
174
174
175 while r:
175 while r:
176 if type != "commit":
176 if type != "commit":
177 sys.stderr.write("aborting hg cat-file only understands commits\n")
177 sys.stderr.write("aborting hg cat-file only understands commits\n")
178 sys.exit(1);
178 sys.exit(1);
179 n = repo.lookup(r)
179 n = repo.lookup(r)
180 catcommit(repo, n, prefix)
180 catcommit(repo, n, prefix)
181 if opts['stdin']:
181 if opts['stdin']:
182 try:
182 try:
183 (type, r) = raw_input().split(' ');
183 (type, r) = raw_input().split(' ');
184 except EOFError:
184 except EOFError:
185 break
185 break
186 else:
186 else:
187 break
187 break
188
188
189 # git rev-tree is a confusing thing. You can supply a number of
189 # git rev-tree is a confusing thing. You can supply a number of
190 # commit sha1s on the command line, and it walks the commit history
190 # commit sha1s on the command line, and it walks the commit history
191 # telling you which commits are reachable from the supplied ones via
191 # telling you which commits are reachable from the supplied ones via
192 # a bitmask based on arg position.
192 # a bitmask based on arg position.
193 # you can specify a commit to stop at by starting the sha1 with ^
193 # you can specify a commit to stop at by starting the sha1 with ^
194 def revtree(args, repo, full="tree", maxnr=0, parents=False):
194 def revtree(args, repo, full="tree", maxnr=0, parents=False):
195 def chlogwalk():
195 def chlogwalk():
196 ch = repo.changelog
196 ch = repo.changelog
197 count = ch.count()
197 count = ch.count()
198 i = count
198 i = count
199 l = [0] * 100
199 l = [0] * 100
200 chunk = 100
200 chunk = 100
201 while True:
201 while True:
202 if chunk > i:
202 if chunk > i:
203 chunk = i
203 chunk = i
204 i = 0
204 i = 0
205 else:
205 else:
206 i -= chunk
206 i -= chunk
207
207
208 for x in xrange(0, chunk):
208 for x in xrange(0, chunk):
209 if i + x >= count:
209 if i + x >= count:
210 l[chunk - x:] = [0] * (chunk - x)
210 l[chunk - x:] = [0] * (chunk - x)
211 break
211 break
212 if full != None:
212 if full != None:
213 l[x] = ch.read(ch.node(i + x))
213 l[x] = ch.read(ch.node(i + x))
214 else:
214 else:
215 l[x] = 1
215 l[x] = 1
216 for x in xrange(chunk-1, -1, -1):
216 for x in xrange(chunk-1, -1, -1):
217 if l[x] != 0:
217 if l[x] != 0:
218 yield (i + x, full != None and l[x] or None)
218 yield (i + x, full != None and l[x] or None)
219 if i == 0:
219 if i == 0:
220 break
220 break
221
221
222 # calculate and return the reachability bitmask for sha
222 # calculate and return the reachability bitmask for sha
223 def is_reachable(ar, reachable, sha):
223 def is_reachable(ar, reachable, sha):
224 if len(ar) == 0:
224 if len(ar) == 0:
225 return 1
225 return 1
226 mask = 0
226 mask = 0
227 for i in range(len(ar)):
227 for i in range(len(ar)):
228 if sha in reachable[i]:
228 if sha in reachable[i]:
229 mask |= 1 << i
229 mask |= 1 << i
230
230
231 return mask
231 return mask
232
232
233 reachable = []
233 reachable = []
234 stop_sha1 = []
234 stop_sha1 = []
235 want_sha1 = []
235 want_sha1 = []
236 count = 0
236 count = 0
237
237
238 # figure out which commits they are asking for and which ones they
238 # figure out which commits they are asking for and which ones they
239 # want us to stop on
239 # want us to stop on
240 for i in range(len(args)):
240 for i in range(len(args)):
241 if args[i].startswith('^'):
241 if args[i].startswith('^'):
242 s = repo.lookup(args[i][1:])
242 s = repo.lookup(args[i][1:])
243 stop_sha1.append(s)
243 stop_sha1.append(s)
244 want_sha1.append(s)
244 want_sha1.append(s)
245 elif args[i] != 'HEAD':
245 elif args[i] != 'HEAD':
246 want_sha1.append(repo.lookup(args[i]))
246 want_sha1.append(repo.lookup(args[i]))
247
247
248 # calculate the graph for the supplied commits
248 # calculate the graph for the supplied commits
249 for i in range(len(want_sha1)):
249 for i in range(len(want_sha1)):
250 reachable.append({});
250 reachable.append({});
251 n = want_sha1[i];
251 n = want_sha1[i];
252 visit = [n];
252 visit = [n];
253 reachable[i][n] = 1
253 reachable[i][n] = 1
254 while visit:
254 while visit:
255 n = visit.pop(0)
255 n = visit.pop(0)
256 if n in stop_sha1:
256 if n in stop_sha1:
257 continue
257 continue
258 for p in repo.changelog.parents(n):
258 for p in repo.changelog.parents(n):
259 if p not in reachable[i]:
259 if p not in reachable[i]:
260 reachable[i][p] = 1
260 reachable[i][p] = 1
261 visit.append(p)
261 visit.append(p)
262 if p in stop_sha1:
262 if p in stop_sha1:
263 continue
263 continue
264
264
265 # walk the repository looking for commits that are in our
265 # walk the repository looking for commits that are in our
266 # reachability graph
266 # reachability graph
267 #for i in range(repo.changelog.count()-1, -1, -1):
267 #for i in range(repo.changelog.count()-1, -1, -1):
268 for i, changes in chlogwalk():
268 for i, changes in chlogwalk():
269 n = repo.changelog.node(i)
269 n = repo.changelog.node(i)
270 mask = is_reachable(want_sha1, reachable, n)
270 mask = is_reachable(want_sha1, reachable, n)
271 if mask:
271 if mask:
272 parentstr = ""
272 parentstr = ""
273 if parents:
273 if parents:
274 pp = repo.changelog.parents(n)
274 pp = repo.changelog.parents(n)
275 if pp[0] != hg.nullid:
275 if pp[0] != hg.nullid:
276 parentstr += " " + hg.hex(pp[0])
276 parentstr += " " + hg.hex(pp[0])
277 if pp[1] != hg.nullid:
277 if pp[1] != hg.nullid:
278 parentstr += " " + hg.hex(pp[1])
278 parentstr += " " + hg.hex(pp[1])
279 if not full:
279 if not full:
280 print hg.hex(n) + parentstr
280 print hg.hex(n) + parentstr
281 elif full is "commit":
281 elif full is "commit":
282 print hg.hex(n) + parentstr
282 print hg.hex(n) + parentstr
283 catcommit(repo, n, ' ', changes)
283 catcommit(repo, n, ' ', changes)
284 else:
284 else:
285 (p1, p2) = repo.changelog.parents(n)
285 (p1, p2) = repo.changelog.parents(n)
286 (h, h1, h2) = map(hg.hex, (n, p1, p2))
286 (h, h1, h2) = map(hg.hex, (n, p1, p2))
287 (i1, i2) = map(repo.changelog.rev, (p1, p2))
287 (i1, i2) = map(repo.changelog.rev, (p1, p2))
288
288
289 date = changes[2][0]
289 date = changes[2][0]
290 print "%s %s:%s" % (date, h, mask),
290 print "%s %s:%s" % (date, h, mask),
291 mask = is_reachable(want_sha1, reachable, p1)
291 mask = is_reachable(want_sha1, reachable, p1)
292 if i1 != -1 and mask > 0:
292 if i1 != -1 and mask > 0:
293 print "%s:%s " % (h1, mask),
293 print "%s:%s " % (h1, mask),
294 mask = is_reachable(want_sha1, reachable, p2)
294 mask = is_reachable(want_sha1, reachable, p2)
295 if i2 != -1 and mask > 0:
295 if i2 != -1 and mask > 0:
296 print "%s:%s " % (h2, mask),
296 print "%s:%s " % (h2, mask),
297 print ""
297 print ""
298 if maxnr and count >= maxnr:
298 if maxnr and count >= maxnr:
299 break
299 break
300 count += 1
300 count += 1
301
301
302 # git rev-list tries to order things by date, and has the ability to stop
302 # git rev-list tries to order things by date, and has the ability to stop
303 # at a given commit without walking the whole repo. TODO add the stop
303 # at a given commit without walking the whole repo. TODO add the stop
304 # parameter
304 # parameter
305 def revlist(ui, repo, *revs, **opts):
305 def revlist(ui, repo, *revs, **opts):
306 """print revisions"""
306 """print revisions"""
307 if opts['header']:
307 if opts['header']:
308 full = "commit"
308 full = "commit"
309 else:
309 else:
310 full = None
310 full = None
311 copy = [x for x in revs]
311 copy = [x for x in revs]
312 revtree(copy, repo, full, opts['max_count'], opts['parents'])
312 revtree(copy, repo, full, opts['max_count'], opts['parents'])
313
313
314 def view(ui, repo, *etc):
314 def view(ui, repo, *etc):
315 "start interactive history viewer"
315 "start interactive history viewer"
316 os.chdir(repo.root)
316 os.chdir(repo.root)
317 os.system(ui.config("hgk", "path", "hgk") + " " + " ".join(etc))
317 os.system(ui.config("hgk", "path", "hgk") + " " + " ".join(etc))
318
318
319 cmdtable = {
319 cmdtable = {
320 "view": (view, [], 'hg view'),
320 "view": (view, [], 'hg view'),
321 "debug-diff-tree": (difftree, [('p', 'patch', None, 'generate patch'),
321 "debug-diff-tree": (difftree, [('p', 'patch', None, 'generate patch'),
322 ('r', 'recursive', None, 'recursive'),
322 ('r', 'recursive', None, 'recursive'),
323 ('P', 'pretty', None, 'pretty'),
323 ('P', 'pretty', None, 'pretty'),
324 ('s', 'stdin', None, 'stdin'),
324 ('s', 'stdin', None, 'stdin'),
325 ('C', 'copy', None, 'detect copies'),
325 ('C', 'copy', None, 'detect copies'),
326 ('S', 'search', "", 'search')],
326 ('S', 'search', "", 'search')],
327 "hg git-diff-tree [options] node1 node2"),
327 "hg git-diff-tree [options] node1 node2"),
328 "debug-cat-file": (catfile, [('s', 'stdin', None, 'stdin')],
328 "debug-cat-file": (catfile, [('s', 'stdin', None, 'stdin')],
329 "hg debug-cat-file [options] type file"),
329 "hg debug-cat-file [options] type file"),
330 "debug-merge-base": (base, [], "hg debug-merge-base node node"),
330 "debug-merge-base": (base, [], "hg debug-merge-base node node"),
331 "debug-rev-list": (revlist, [('H', 'header', None, 'header'),
331 "debug-rev-list": (revlist, [('H', 'header', None, 'header'),
332 ('t', 'topo-order', None, 'topo-order'),
332 ('t', 'topo-order', None, 'topo-order'),
333 ('p', 'parents', None, 'parents'),
333 ('p', 'parents', None, 'parents'),
334 ('n', 'max-count', 0, 'max-count')],
334 ('n', 'max-count', 0, 'max-count')],
335 "hg debug-rev-list [options] revs"),
335 "hg debug-rev-list [options] revs"),
336 }
336 }
337
337
338 def reposetup(ui, repo):
338 def reposetup(ui, repo):
339 pass
339 pass
General Comments 0
You need to be logged in to leave comments. Login now