Mercurial > public > mercurial-scm > hg-stable
annotate mercurial/hg.py @ 576:da11baf5de7b
Handle unknown files better on update
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Handle unknown files better on update
If we spot an unknown file that's identical to one that's in the
update, we get the updated one so that it shows up in the dirstate
properly.
manifest hash: 988aca64f255df67c27d1c6f8694ea098e4ec159
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.0 (GNU/Linux)
iD8DBQFCxyFyywK+sNU5EO8RAjmiAKCTgINXMPB1CxHt0OgHYPucfjCS7QCcDpJJ
VgKqZS54hTAWN3jL2yllUhI=
=iPQD
-----END PGP SIGNATURE-----
author | mpm@selenic.com |
---|---|
date | Sat, 02 Jul 2005 15:21:22 -0800 |
parents | 7f5ce4bbdd7b |
children | e33c85d2812a |
rev | line source |
---|---|
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
1 # hg.py - repository classes for mercurial |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
2 # |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
3 # Copyright 2005 Matt Mackall <mpm@selenic.com> |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
4 # |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
5 # This software may be used and distributed according to the terms |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
6 # of the GNU General Public License, incorporated herein by reference. |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
7 |
249 | 8 import sys, struct, os |
419
28511fc21073
[PATCH] file seperator handling for the other 'OS'
mpm@selenic.com
parents:
418
diff
changeset
|
9 import util |
262 | 10 from revlog import * |
11 from demandload import * | |
12 demandload(globals(), "re lock urllib urllib2 transaction time socket") | |
434 | 13 demandload(globals(), "tempfile httprangereader bdiff") |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
14 |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
15 class filelog(revlog): |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
16 def __init__(self, opener, path): |
144
ea9188538222
Fix transaction handling bug by reverting fileopener change
mpm@selenic.com
parents:
140
diff
changeset
|
17 revlog.__init__(self, opener, |
ea9188538222
Fix transaction handling bug by reverting fileopener change
mpm@selenic.com
parents:
140
diff
changeset
|
18 os.path.join("data", path + ".i"), |
ea9188538222
Fix transaction handling bug by reverting fileopener change
mpm@selenic.com
parents:
140
diff
changeset
|
19 os.path.join("data", path + ".d")) |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
20 |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
21 def read(self, node): |
360 | 22 t = self.revision(node) |
23 if t[:2] != '\1\n': | |
24 return t | |
25 s = t.find('\1\n', 2) | |
26 return t[s+2:] | |
27 | |
28 def readmeta(self, node): | |
29 t = self.revision(node) | |
30 if t[:2] != '\1\n': | |
31 return t | |
32 s = t.find('\1\n', 2) | |
33 mt = t[2:s] | |
34 for l in mt.splitlines(): | |
35 k, v = l.split(": ", 1) | |
36 m[k] = v | |
37 return m | |
38 | |
39 def add(self, text, meta, transaction, link, p1=None, p2=None): | |
40 if meta or text[:2] == '\1\n': | |
41 mt = "" | |
42 if meta: | |
43 mt = [ "%s: %s\n" % (k, v) for k,v in meta.items() ] | |
44 text = "\1\n" + "".join(mt) + "\1\n" + text | |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
45 return self.addrevision(text, transaction, link, p1, p2) |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
46 |
79 | 47 def annotate(self, node): |
199 | 48 |
49 def decorate(text, rev): | |
436 | 50 return ([rev] * len(text.splitlines()), text) |
199 | 51 |
52 def pair(parent, child): | |
436 | 53 for a1, a2, b1, b2 in bdiff.blocks(parent[1], child[1]): |
471 | 54 child[0][b1:b2] = parent[0][a1:a2] |
55 return child | |
199 | 56 |
200 | 57 # find all ancestors |
216
201115f2859b
hg annotate: actually annotate the given version
mpm@selenic.com
parents:
210
diff
changeset
|
58 needed = {node:1} |
199 | 59 visit = [node] |
60 while visit: | |
61 n = visit.pop(0) | |
62 for p in self.parents(n): | |
63 if p not in needed: | |
64 needed[p] = 1 | |
65 visit.append(p) | |
200 | 66 else: |
67 # count how many times we'll use this | |
68 needed[p] += 1 | |
199 | 69 |
200 | 70 # sort by revision which is a topological order |
471 | 71 visit = [ (self.rev(n), n) for n in needed.keys() ] |
199 | 72 visit.sort() |
73 hist = {} | |
74 | |
471 | 75 for r,n in visit: |
199 | 76 curr = decorate(self.read(n), self.linkrev(n)) |
77 for p in self.parents(n): | |
78 if p != nullid: | |
79 curr = pair(hist[p], curr) | |
200 | 80 # trim the history of unneeded revs |
81 needed[p] -= 1 | |
82 if not needed[p]: | |
83 del hist[p] | |
199 | 84 hist[n] = curr |
85 | |
436 | 86 return zip(hist[n][0], hist[n][1].splitlines(1)) |
79 | 87 |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
88 class manifest(revlog): |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
89 def __init__(self, opener): |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
90 self.mapcache = None |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
91 self.listcache = None |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
92 self.addlist = None |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
93 revlog.__init__(self, opener, "00manifest.i", "00manifest.d") |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
94 |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
95 def read(self, node): |
313 | 96 if node == nullid: return {} # don't upset local cache |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
97 if self.mapcache and self.mapcache[0] == node: |
561 | 98 return self.mapcache[1] |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
99 text = self.revision(node) |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
100 map = {} |
276 | 101 flag = {} |
25
daa724b27300
Fix corruption from manifest.listcache optimization
mpm@selenic.com
parents:
20
diff
changeset
|
102 self.listcache = (text, text.splitlines(1)) |
daa724b27300
Fix corruption from manifest.listcache optimization
mpm@selenic.com
parents:
20
diff
changeset
|
103 for l in self.listcache[1]: |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
104 (f, n) = l.split('\0') |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
105 map[f] = bin(n[:40]) |
276 | 106 flag[f] = (n[40:-1] == "x") |
107 self.mapcache = (node, map, flag) | |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
108 return map |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
109 |
276 | 110 def readflags(self, node): |
313 | 111 if node == nullid: return {} # don't upset local cache |
358
9f4077d7ef6f
[PATCH] manifest.readflags performance buglet
mpm@selenic.com
parents:
350
diff
changeset
|
112 if not self.mapcache or self.mapcache[0] != node: |
276 | 113 self.read(node) |
114 return self.mapcache[2] | |
115 | |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
116 def diff(self, a, b): |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
117 # this is sneaky, as we're not actually using a and b |
140 | 118 if self.listcache and self.addlist and self.listcache[0] == a: |
98 | 119 d = mdiff.diff(self.listcache[1], self.addlist, 1) |
120 if mdiff.patch(a, d) != b: | |
121 sys.stderr.write("*** sortdiff failed, falling back ***\n") | |
122 return mdiff.textdiff(a, b) | |
123 return d | |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
124 else: |
44 | 125 return mdiff.textdiff(a, b) |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
126 |
276 | 127 def add(self, map, flags, transaction, link, p1=None, p2=None): |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
128 files = map.keys() |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
129 files.sort() |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
130 |
276 | 131 self.addlist = ["%s\000%s%s\n" % |
132 (f, hex(map[f]), flags[f] and "x" or '') | |
133 for f in files] | |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
134 text = "".join(self.addlist) |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
135 |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
136 n = self.addrevision(text, transaction, link, p1, p2) |
302 | 137 self.mapcache = (n, map, flags) |
25
daa724b27300
Fix corruption from manifest.listcache optimization
mpm@selenic.com
parents:
20
diff
changeset
|
138 self.listcache = (text, self.addlist) |
140 | 139 self.addlist = None |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
140 |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
141 return n |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
142 |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
143 class changelog(revlog): |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
144 def __init__(self, opener): |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
145 revlog.__init__(self, opener, "00changelog.i", "00changelog.d") |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
146 |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
147 def extract(self, text): |
37 | 148 if not text: |
40 | 149 return (nullid, "", "0", [], "") |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
150 last = text.index("\n\n") |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
151 desc = text[last + 2:] |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
152 l = text[:last].splitlines() |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
153 manifest = bin(l[0]) |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
154 user = l[1] |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
155 date = l[2] |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
156 files = l[3:] |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
157 return (manifest, user, date, files, desc) |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
158 |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
159 def read(self, node): |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
160 return self.extract(self.revision(node)) |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
161 |
203 | 162 def add(self, manifest, list, desc, transaction, p1=None, p2=None, |
163 user=None, date=None): | |
164 user = (user or | |
165 os.environ.get("HGUSER") or | |
55
2add70d51441
From: Thomas Arendsen Hein <thomas@intevation.de>
mpm@selenic.com
parents:
48
diff
changeset
|
166 os.environ.get("EMAIL") or |
504 | 167 (os.environ.get("LOGNAME", |
168 os.environ.get("USERNAME", "unknown")) | |
169 + '@' + socket.getfqdn())) | |
203 | 170 date = date or "%d %d" % (time.time(), time.timezone) |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
171 list.sort() |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
172 l = [hex(manifest), user, date] + list + ["", desc] |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
173 text = "\n".join(l) |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
174 return self.addrevision(text, transaction, self.count(), p1, p2) |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
175 |
220 | 176 class dirstate: |
244 | 177 def __init__(self, opener, ui, root): |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
178 self.opener = opener |
244 | 179 self.root = root |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
180 self.dirty = 0 |
20 | 181 self.ui = ui |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
182 self.map = None |
227 | 183 self.pl = None |
363 | 184 self.copies = {} |
220 | 185 |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
186 def __del__(self): |
220 | 187 if self.dirty: |
188 self.write() | |
189 | |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
190 def __getitem__(self, key): |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
191 try: |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
192 return self.map[key] |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
193 except TypeError: |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
194 self.read() |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
195 return self[key] |
220 | 196 |
197 def __contains__(self, key): | |
198 if not self.map: self.read() | |
199 return key in self.map | |
200 | |
227 | 201 def parents(self): |
202 if not self.pl: | |
203 self.read() | |
204 return self.pl | |
205 | |
206 def setparents(self, p1, p2 = nullid): | |
207 self.dirty = 1 | |
208 self.pl = p1, p2 | |
209 | |
220 | 210 def state(self, key): |
211 try: | |
212 return self[key][0] | |
213 except KeyError: | |
214 return "?" | |
215 | |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
216 def read(self): |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
217 if self.map is not None: return self.map |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
218 |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
219 self.map = {} |
227 | 220 self.pl = [nullid, nullid] |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
221 try: |
220 | 222 st = self.opener("dirstate").read() |
311 | 223 if not st: return |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
224 except: return |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
225 |
227 | 226 self.pl = [st[:20], st[20: 40]] |
227 | |
228 pos = 40 | |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
229 while pos < len(st): |
220 | 230 e = struct.unpack(">cllll", st[pos:pos+17]) |
231 l = e[4] | |
232 pos += 17 | |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
233 f = st[pos:pos + l] |
515 | 234 if '\0' in f: |
363 | 235 f, c = f.split('\0') |
236 self.copies[f] = c | |
220 | 237 self.map[f] = e[:4] |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
238 pos += l |
363 | 239 |
240 def copy(self, source, dest): | |
241 self.read() | |
242 self.dirty = 1 | |
243 self.copies[dest] = source | |
244 | |
245 def copied(self, file): | |
246 return self.copies.get(file, None) | |
515 | 247 |
220 | 248 def update(self, files, state): |
249 ''' current states: | |
250 n normal | |
231 | 251 m needs merging |
220 | 252 r marked for removal |
253 a marked for addition''' | |
254 | |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
255 if not files: return |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
256 self.read() |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
257 self.dirty = 1 |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
258 for f in files: |
220 | 259 if state == "r": |
260 self.map[f] = ('r', 0, 0, 0) | |
261 else: | |
253 | 262 s = os.stat(os.path.join(self.root, f)) |
263 self.map[f] = (state, s.st_mode, s.st_size, s.st_mtime) | |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
264 |
220 | 265 def forget(self, files): |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
266 if not files: return |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
267 self.read() |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
268 self.dirty = 1 |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
269 for f in files: |
20 | 270 try: |
271 del self.map[f] | |
272 except KeyError: | |
220 | 273 self.ui.warn("not in dirstate: %s!\n" % f) |
20 | 274 pass |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
275 |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
276 def clear(self): |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
277 self.map = {} |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
278 self.dirty = 1 |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
279 |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
280 def write(self): |
220 | 281 st = self.opener("dirstate", "w") |
227 | 282 st.write("".join(self.pl)) |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
283 for f, e in self.map.items(): |
363 | 284 c = self.copied(f) |
285 if c: | |
286 f = f + "\0" + c | |
220 | 287 e = struct.pack(">cllll", e[0], e[1], e[2], e[3], len(f)) |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
288 st.write(e + f) |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
289 self.dirty = 0 |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
290 |
536 | 291 def changes(self, files, ignore): |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
292 self.read() |
536 | 293 dc = self.map.copy() |
294 lookup, changed, added, unknown = [], [], [], [] | |
295 | |
296 # compare all files by default | |
297 if not files: files = [self.root] | |
298 | |
299 # recursive generator of all files listed | |
300 def walk(files): | |
556 | 301 for f in util.unique(files): |
537 | 302 f = os.path.join(self.root, f) |
536 | 303 if os.path.isdir(f): |
304 for dir, subdirs, fl in os.walk(f): | |
305 d = dir[len(self.root) + 1:] | |
306 if ".hg" in subdirs: subdirs.remove(".hg") | |
307 for fn in fl: | |
308 fn = util.pconvert(os.path.join(d, fn)) | |
309 yield fn | |
310 else: | |
311 yield f[len(self.root) + 1:] | |
312 | |
556 | 313 for fn in util.unique(walk(files)): |
536 | 314 try: s = os.stat(os.path.join(self.root, fn)) |
315 except: continue | |
316 | |
317 if fn in dc: | |
318 c = dc[fn] | |
319 del dc[fn] | |
320 | |
321 if c[0] == 'm': | |
322 changed.append(fn) | |
323 elif c[0] == 'a': | |
324 added.append(fn) | |
325 elif c[0] == 'r': | |
326 unknown.append(fn) | |
327 elif c[2] != s.st_size or (c[1] ^ s.st_mode) & 0100: | |
328 changed.append(fn) | |
329 elif c[1] != s.st_mode or c[3] != s.st_mtime: | |
330 lookup.append(fn) | |
331 else: | |
332 if not ignore(fn): unknown.append(fn) | |
333 | |
334 return (lookup, changed, added, dc.keys(), unknown) | |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
335 |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
336 # used to avoid circular references so destructors work |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
337 def opener(base): |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
338 p = base |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
339 def o(path, mode="r"): |
15
6daf7757e92b
Fix network pull of repo files with "%" in their base64 encoding.
mpm@selenic.com
parents:
10
diff
changeset
|
340 if p[:7] == "http://": |
6daf7757e92b
Fix network pull of repo files with "%" in their base64 encoding.
mpm@selenic.com
parents:
10
diff
changeset
|
341 f = os.path.join(p, urllib.quote(path)) |
372 | 342 return httprangereader.httprangereader(f) |
15
6daf7757e92b
Fix network pull of repo files with "%" in their base64 encoding.
mpm@selenic.com
parents:
10
diff
changeset
|
343 |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
344 f = os.path.join(p, path) |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
345 |
292 | 346 mode += "b" # for that other OS |
347 | |
348 if mode[0] != "r": | |
110
c37c7f784ee3
Move hg from storing files in data with base64 encoding to full
mpm@selenic.com
parents:
109
diff
changeset
|
349 try: |
c37c7f784ee3
Move hg from storing files in data with base64 encoding to full
mpm@selenic.com
parents:
109
diff
changeset
|
350 s = os.stat(f) |
c37c7f784ee3
Move hg from storing files in data with base64 encoding to full
mpm@selenic.com
parents:
109
diff
changeset
|
351 except OSError: |
c37c7f784ee3
Move hg from storing files in data with base64 encoding to full
mpm@selenic.com
parents:
109
diff
changeset
|
352 d = os.path.dirname(f) |
c37c7f784ee3
Move hg from storing files in data with base64 encoding to full
mpm@selenic.com
parents:
109
diff
changeset
|
353 if not os.path.isdir(d): |
c37c7f784ee3
Move hg from storing files in data with base64 encoding to full
mpm@selenic.com
parents:
109
diff
changeset
|
354 os.makedirs(d) |
c37c7f784ee3
Move hg from storing files in data with base64 encoding to full
mpm@selenic.com
parents:
109
diff
changeset
|
355 else: |
c37c7f784ee3
Move hg from storing files in data with base64 encoding to full
mpm@selenic.com
parents:
109
diff
changeset
|
356 if s.st_nlink > 1: |
417 | 357 file(f + ".tmp", "wb").write(file(f, "rb").read()) |
421 | 358 util.rename(f+".tmp", f) |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
359 |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
360 return file(f, mode) |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
361 |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
362 return o |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
363 |
499 | 364 class RepoError(Exception): pass |
365 | |
60 | 366 class localrepository: |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
367 def __init__(self, ui, path=None, create=0): |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
368 self.remote = 0 |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
369 if path and path[:7] == "http://": |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
370 self.remote = 1 |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
371 self.path = path |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
372 else: |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
373 if not path: |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
374 p = os.getcwd() |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
375 while not os.path.isdir(os.path.join(p, ".hg")): |
420
dbe86d465e09
[PATCH] Repo locator fix for the other `OS'
mpm@selenic.com
parents:
419
diff
changeset
|
376 oldp = p |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
377 p = os.path.dirname(p) |
499 | 378 if p == oldp: raise RepoError("no repo found") |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
379 path = p |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
380 self.path = os.path.join(path, ".hg") |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
381 |
405 | 382 if not create and not os.path.isdir(self.path): |
499 | 383 raise RepoError("repository %s not found" % self.path) |
405 | 384 |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
385 self.root = path |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
386 self.ui = ui |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
387 |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
388 if create: |
515 | 389 os.mkdir(self.path) |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
390 os.mkdir(self.join("data")) |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
391 |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
392 self.opener = opener(self.path) |
291
2c4f2be05587
Add wopener for opening files in the working directory
mpm@selenic.com
parents:
288
diff
changeset
|
393 self.wopener = opener(self.root) |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
394 self.manifest = manifest(self.opener) |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
395 self.changelog = changelog(self.opener) |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
396 self.ignorelist = None |
343 | 397 self.tagscache = None |
398 self.nodetagscache = None | |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
399 |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
400 if not self.remote: |
244 | 401 self.dirstate = dirstate(self.opener, ui, self.root) |
337 | 402 try: |
403 self.ui.readconfig(self.opener("hgrc")) | |
404 except IOError: pass | |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
405 |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
406 def ignore(self, f): |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
407 if self.ignorelist is None: |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
408 self.ignorelist = [] |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
409 try: |
417 | 410 l = file(self.wjoin(".hgignore")) |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
411 for pat in l: |
9 | 412 if pat != "\n": |
419
28511fc21073
[PATCH] file seperator handling for the other 'OS'
mpm@selenic.com
parents:
418
diff
changeset
|
413 self.ignorelist.append(re.compile(util.pconvert(pat[:-1]))) |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
414 except IOError: pass |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
415 for pat in self.ignorelist: |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
416 if pat.search(f): return True |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
417 return False |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
418 |
487 | 419 def hook(self, name, **args): |
420 s = self.ui.config("hooks", name) | |
421 if s: | |
422 self.ui.note("running hook %s: %s\n" % (name, s)) | |
423 old = {} | |
424 for k, v in args.items(): | |
425 k = k.upper() | |
426 old[k] = os.environ.get(k, None) | |
427 os.environ[k] = v | |
428 | |
429 r = os.system(s) | |
430 | |
431 for k, v in old.items(): | |
432 if v != None: | |
433 os.environ[k] = v | |
434 else: | |
435 del os.environ[k] | |
436 | |
437 if r: | |
438 self.ui.warn("abort: %s hook failed with status %d!\n" % | |
439 (name, r)) | |
440 return False | |
441 return True | |
442 | |
343 | 443 def tags(self): |
444 '''return a mapping of tag to node''' | |
477
520540fd6b64
Handle errors in .hgtags or hgrc [tags] section more gracefully.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
471
diff
changeset
|
445 if not self.tagscache: |
343 | 446 self.tagscache = {} |
67 | 447 try: |
254 | 448 # read each head of the tags file, ending with the tip |
449 # and add each tag found to the map, with "newer" ones | |
450 # taking precedence | |
67 | 451 fl = self.file(".hgtags") |
254 | 452 h = fl.heads() |
453 h.reverse() | |
454 for r in h: | |
455 for l in fl.revision(r).splitlines(): | |
456 if l: | |
385
e9e1efd5291c
Fixed problems with extra spaces around tags in .hgtags
Thomas Arendsen Hein <thomas@intevation.de>
parents:
383
diff
changeset
|
457 n, k = l.split(" ", 1) |
477
520540fd6b64
Handle errors in .hgtags or hgrc [tags] section more gracefully.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
471
diff
changeset
|
458 try: |
520540fd6b64
Handle errors in .hgtags or hgrc [tags] section more gracefully.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
471
diff
changeset
|
459 bin_n = bin(n) |
520540fd6b64
Handle errors in .hgtags or hgrc [tags] section more gracefully.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
471
diff
changeset
|
460 except TypeError: |
520540fd6b64
Handle errors in .hgtags or hgrc [tags] section more gracefully.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
471
diff
changeset
|
461 bin_n = '' |
520540fd6b64
Handle errors in .hgtags or hgrc [tags] section more gracefully.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
471
diff
changeset
|
462 self.tagscache[k.strip()] = bin_n |
520540fd6b64
Handle errors in .hgtags or hgrc [tags] section more gracefully.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
471
diff
changeset
|
463 except KeyError: |
520540fd6b64
Handle errors in .hgtags or hgrc [tags] section more gracefully.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
471
diff
changeset
|
464 pass |
454 | 465 for k, n in self.ui.configitems("tags"): |
477
520540fd6b64
Handle errors in .hgtags or hgrc [tags] section more gracefully.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
471
diff
changeset
|
466 try: |
520540fd6b64
Handle errors in .hgtags or hgrc [tags] section more gracefully.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
471
diff
changeset
|
467 bin_n = bin(n) |
520540fd6b64
Handle errors in .hgtags or hgrc [tags] section more gracefully.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
471
diff
changeset
|
468 except TypeError: |
520540fd6b64
Handle errors in .hgtags or hgrc [tags] section more gracefully.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
471
diff
changeset
|
469 bin_n = '' |
520540fd6b64
Handle errors in .hgtags or hgrc [tags] section more gracefully.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
471
diff
changeset
|
470 self.tagscache[k] = bin_n |
520540fd6b64
Handle errors in .hgtags or hgrc [tags] section more gracefully.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
471
diff
changeset
|
471 |
343 | 472 self.tagscache['tip'] = self.changelog.tip() |
473 | |
474 return self.tagscache | |
475 | |
476 def tagslist(self): | |
477 '''return a list of tags ordered by revision''' | |
478 l = [] | |
477
520540fd6b64
Handle errors in .hgtags or hgrc [tags] section more gracefully.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
471
diff
changeset
|
479 for t, n in self.tags().items(): |
343 | 480 try: |
481 r = self.changelog.rev(n) | |
482 except: | |
483 r = -2 # sort to the beginning of the list if unknown | |
484 l.append((r,t,n)) | |
485 l.sort() | |
486 return [(t,n) for r,t,n in l] | |
487 | |
488 def nodetags(self, node): | |
489 '''return the tags associated with a node''' | |
490 if not self.nodetagscache: | |
491 self.nodetagscache = {} | |
492 for t,n in self.tags().items(): | |
493 self.nodetagscache.setdefault(n,[]).append(t) | |
494 return self.nodetagscache.get(node, []) | |
495 | |
496 def lookup(self, key): | |
67 | 497 try: |
343 | 498 return self.tags()[key] |
67 | 499 except KeyError: |
500 return self.changelog.lookup(key) | |
501 | |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
502 def join(self, f): |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
503 return os.path.join(self.path, f) |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
504 |
244 | 505 def wjoin(self, f): |
506 return os.path.join(self.root, f) | |
507 | |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
508 def file(self, f): |
192 | 509 if f[0] == '/': f = f[1:] |
144
ea9188538222
Fix transaction handling bug by reverting fileopener change
mpm@selenic.com
parents:
140
diff
changeset
|
510 return filelog(self.opener, f) |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
511 |
291
2c4f2be05587
Add wopener for opening files in the working directory
mpm@selenic.com
parents:
288
diff
changeset
|
512 def wfile(self, f, mode='r'): |
2c4f2be05587
Add wopener for opening files in the working directory
mpm@selenic.com
parents:
288
diff
changeset
|
513 return self.wopener(f, mode) |
2c4f2be05587
Add wopener for opening files in the working directory
mpm@selenic.com
parents:
288
diff
changeset
|
514 |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
515 def transaction(self): |
251 | 516 # save dirstate for undo |
263 | 517 try: |
518 ds = self.opener("dirstate").read() | |
519 except IOError: | |
520 ds = "" | |
251 | 521 self.opener("undo.dirstate", "w").write(ds) |
515 | 522 |
262 | 523 return transaction.transaction(self.opener, self.join("journal"), |
524 self.join("undo")) | |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
525 |
210 | 526 def recover(self): |
225 | 527 lock = self.lock() |
557 | 528 if os.path.exists(self.join("journal")): |
501 | 529 self.ui.status("rolling back interrupted transaction\n") |
557 | 530 return transaction.rollback(self.opener, self.join("journal")) |
210 | 531 else: |
532 self.ui.warn("no interrupted transaction available\n") | |
533 | |
534 def undo(self): | |
225 | 535 lock = self.lock() |
210 | 536 if os.path.exists(self.join("undo")): |
501 | 537 self.ui.status("rolling back last transaction\n") |
262 | 538 transaction.rollback(self.opener, self.join("undo")) |
251 | 539 self.dirstate = None |
421 | 540 util.rename(self.join("undo.dirstate"), self.join("dirstate")) |
251 | 541 self.dirstate = dirstate(self.opener, self.ui, self.root) |
163 | 542 else: |
210 | 543 self.ui.warn("no undo information available\n") |
162 | 544 |
161 | 545 def lock(self, wait = 1): |
546 try: | |
547 return lock.lock(self.join("lock"), 0) | |
548 except lock.LockHeld, inst: | |
549 if wait: | |
550 self.ui.warn("waiting for lock held by %s\n" % inst.args[0]) | |
551 return lock.lock(self.join("lock"), wait) | |
552 raise inst | |
553 | |
203 | 554 def rawcommit(self, files, text, user, date, p1=None, p2=None): |
442 | 555 orig_parent = self.dirstate.parents()[0] or nullid |
452
a1e91c24dab5
rawcommit: do lookup of parents at the appropriate layer
mpm@selenic.com
parents:
442
diff
changeset
|
556 p1 = p1 or self.dirstate.parents()[0] or nullid |
a1e91c24dab5
rawcommit: do lookup of parents at the appropriate layer
mpm@selenic.com
parents:
442
diff
changeset
|
557 p2 = p2 or self.dirstate.parents()[1] or nullid |
302 | 558 c1 = self.changelog.read(p1) |
559 c2 = self.changelog.read(p2) | |
560 m1 = self.manifest.read(c1[0]) | |
561 mf1 = self.manifest.readflags(c1[0]) | |
562 m2 = self.manifest.read(c2[0]) | |
563 | |
442 | 564 if orig_parent == p1: |
565 update_dirstate = 1 | |
566 else: | |
567 update_dirstate = 0 | |
568 | |
203 | 569 tr = self.transaction() |
302 | 570 mm = m1.copy() |
571 mfm = mf1.copy() | |
203 | 572 linkrev = self.changelog.count() |
573 for f in files: | |
574 try: | |
302 | 575 t = self.wfile(f).read() |
441 | 576 tm = util.is_exec(self.wjoin(f), mfm.get(f, False)) |
302 | 577 r = self.file(f) |
578 mfm[f] = tm | |
360 | 579 mm[f] = r.add(t, {}, tr, linkrev, |
302 | 580 m1.get(f, nullid), m2.get(f, nullid)) |
442 | 581 if update_dirstate: |
582 self.dirstate.update([f], "n") | |
203 | 583 except IOError: |
314
3402cb9a4c06
More tweaking to rawcommit for repo conversion
mpm@selenic.com
parents:
313
diff
changeset
|
584 try: |
3402cb9a4c06
More tweaking to rawcommit for repo conversion
mpm@selenic.com
parents:
313
diff
changeset
|
585 del mm[f] |
3402cb9a4c06
More tweaking to rawcommit for repo conversion
mpm@selenic.com
parents:
313
diff
changeset
|
586 del mfm[f] |
442 | 587 if update_dirstate: |
588 self.dirstate.forget([f]) | |
314
3402cb9a4c06
More tweaking to rawcommit for repo conversion
mpm@selenic.com
parents:
313
diff
changeset
|
589 except: |
3402cb9a4c06
More tweaking to rawcommit for repo conversion
mpm@selenic.com
parents:
313
diff
changeset
|
590 # deleted from p2? |
3402cb9a4c06
More tweaking to rawcommit for repo conversion
mpm@selenic.com
parents:
313
diff
changeset
|
591 pass |
203 | 592 |
302 | 593 mnode = self.manifest.add(mm, mfm, tr, linkrev, c1[0], c2[0]) |
594 n = self.changelog.add(mnode, files, text, tr, p1, p2, user, date) | |
203 | 595 tr.close() |
442 | 596 if update_dirstate: |
597 self.dirstate.setparents(n, nullid) | |
203 | 598 |
317 | 599 def commit(self, files = None, text = "", user = None, date = None): |
220 | 600 commit = [] |
601 remove = [] | |
602 if files: | |
603 for f in files: | |
604 s = self.dirstate.state(f) | |
244 | 605 if s in 'nmai': |
220 | 606 commit.append(f) |
607 elif s == 'r': | |
608 remove.append(f) | |
609 else: | |
244 | 610 self.ui.warn("%s not tracked!\n" % f) |
220 | 611 else: |
536 | 612 (c, a, d, u) = self.changes(None, None) |
220 | 613 commit = c + a |
614 remove = d | |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
615 |
220 | 616 if not commit and not remove: |
151 | 617 self.ui.status("nothing changed\n") |
618 return | |
619 | |
487 | 620 if not self.hook("precommit"): |
621 return 1 | |
622 | |
229 | 623 p1, p2 = self.dirstate.parents() |
624 c1 = self.changelog.read(p1) | |
625 c2 = self.changelog.read(p2) | |
626 m1 = self.manifest.read(c1[0]) | |
276 | 627 mf1 = self.manifest.readflags(c1[0]) |
229 | 628 m2 = self.manifest.read(c2[0]) |
225 | 629 lock = self.lock() |
151 | 630 tr = self.transaction() |
631 | |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
632 # check in files |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
633 new = {} |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
634 linkrev = self.changelog.count() |
220 | 635 commit.sort() |
636 for f in commit: | |
83 | 637 self.ui.note(f + "\n") |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
638 try: |
441 | 639 mf1[f] = util.is_exec(self.wjoin(f), mf1.get(f, False)) |
418 | 640 t = self.wfile(f).read() |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
641 except IOError: |
220 | 642 self.warn("trouble committing %s!\n" % f) |
643 raise | |
644 | |
363 | 645 meta = {} |
646 cp = self.dirstate.copied(f) | |
647 if cp: | |
648 meta["copy"] = cp | |
649 meta["copyrev"] = hex(m1.get(cp, m2.get(cp, nullid))) | |
575 | 650 self.ui.debug(" %s: copy %s:%s\n" % (f, cp, meta["copyrev"])) |
363 | 651 |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
652 r = self.file(f) |
229 | 653 fp1 = m1.get(f, nullid) |
654 fp2 = m2.get(f, nullid) | |
363 | 655 new[f] = r.add(t, meta, tr, linkrev, fp1, fp2) |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
656 |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
657 # update manifest |
229 | 658 m1.update(new) |
416
5e9e8b8d2629
[PATCH] Removal of a file added by merging branches
mpm@selenic.com
parents:
415
diff
changeset
|
659 for f in remove: |
5e9e8b8d2629
[PATCH] Removal of a file added by merging branches
mpm@selenic.com
parents:
415
diff
changeset
|
660 if f in m1: |
5e9e8b8d2629
[PATCH] Removal of a file added by merging branches
mpm@selenic.com
parents:
415
diff
changeset
|
661 del m1[f] |
276 | 662 mn = self.manifest.add(m1, mf1, tr, linkrev, c1[0], c2[0]) |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
663 |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
664 # add changeset |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
665 new = new.keys() |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
666 new.sort() |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
667 |
288 | 668 if not text: |
669 edittext = "\n" + "HG: manifest hash %s\n" % hex(mn) | |
670 edittext += "".join(["HG: changed %s\n" % f for f in new]) | |
671 edittext += "".join(["HG: removed %s\n" % f for f in remove]) | |
672 edittext = self.ui.edit(edittext) | |
673 if not edittext.rstrip(): | |
674 return 1 | |
675 text = edittext | |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
676 |
317 | 677 n = self.changelog.add(mn, new, text, tr, p1, p2, user, date) |
487 | 678 |
679 if not self.hook("commit", node=hex(n)): | |
680 return 1 | |
681 | |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
682 tr.close() |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
683 |
229 | 684 self.dirstate.setparents(n) |
220 | 685 self.dirstate.update(new, "n") |
686 self.dirstate.forget(remove) | |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
687 |
537 | 688 def changes(self, node1, node2, files=None): |
566 | 689 mf2, u = None, [] |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
690 |
536 | 691 def fcmp(fn, mf): |
291
2c4f2be05587
Add wopener for opening files in the working directory
mpm@selenic.com
parents:
288
diff
changeset
|
692 t1 = self.wfile(fn).read() |
29 | 693 t2 = self.file(fn).revision(mf[fn]) |
694 return cmp(t1, t2) | |
695 | |
536 | 696 # are we comparing the working directory? |
561 | 697 if not node2: |
536 | 698 l, c, a, d, u = self.dirstate.changes(files, self.ignore) |
699 | |
700 # are we comparing working dir against its parent? | |
561 | 701 if not node1: |
536 | 702 if l: |
703 # do a full compare of any files that might have changed | |
704 change = self.changelog.read(self.dirstate.parents()[0]) | |
561 | 705 mf2 = self.manifest.read(change[0]) |
548 | 706 for f in l: |
561 | 707 if fcmp(f, mf2): |
536 | 708 c.append(f) |
561 | 709 |
710 for l in c, a, d, u: | |
711 l.sort() | |
712 | |
536 | 713 return (c, a, d, u) |
515 | 714 |
536 | 715 # are we comparing working dir against non-tip? |
716 # generate a pseudo-manifest for the working dir | |
561 | 717 if not node2: |
718 if not mf2: | |
536 | 719 change = self.changelog.read(self.dirstate.parents()[0]) |
561 | 720 mf2 = self.manifest.read(change[0]).copy() |
536 | 721 for f in a + c + l: |
561 | 722 mf2[f] = "" |
536 | 723 for f in d: |
561 | 724 if f in mf2: del mf2[f] |
536 | 725 else: |
561 | 726 change = self.changelog.read(node2) |
727 mf2 = self.manifest.read(change[0]) | |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
728 |
566 | 729 # flush lists from dirstate before comparing manifests |
730 c, a = [], [] | |
731 | |
561 | 732 change = self.changelog.read(node1) |
733 mf1 = self.manifest.read(change[0]).copy() | |
32 | 734 |
735 for fn in mf2: | |
736 if mf1.has_key(fn): | |
737 if mf1[fn] != mf2[fn]: | |
561 | 738 if mf2[fn] != "" or fcmp(fn, mf1): |
536 | 739 c.append(fn) |
32 | 740 del mf1[fn] |
741 else: | |
536 | 742 a.append(fn) |
515 | 743 |
536 | 744 d = mf1.keys() |
561 | 745 |
746 for l in c, a, d, u: | |
747 l.sort() | |
515 | 748 |
536 | 749 return (c, a, d, u) |
32 | 750 |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
751 def add(self, list): |
220 | 752 for f in list: |
244 | 753 p = self.wjoin(f) |
220 | 754 if not os.path.isfile(p): |
755 self.ui.warn("%s does not exist!\n" % f) | |
756 elif self.dirstate.state(f) == 'n': | |
757 self.ui.warn("%s already tracked!\n" % f) | |
758 else: | |
759 self.dirstate.update([f], "a") | |
760 | |
761 def forget(self, list): | |
762 for f in list: | |
763 if self.dirstate.state(f) not in 'ai': | |
764 self.ui.warn("%s not added!\n" % f) | |
765 else: | |
766 self.dirstate.forget([f]) | |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
767 |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
768 def remove(self, list): |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
769 for f in list: |
244 | 770 p = self.wjoin(f) |
220 | 771 if os.path.isfile(p): |
772 self.ui.warn("%s still exists!\n" % f) | |
402 | 773 elif self.dirstate.state(f) == 'a': |
774 self.ui.warn("%s never committed!\n" % f) | |
775 self.dirstate.forget(f) | |
220 | 776 elif f not in self.dirstate: |
777 self.ui.warn("%s not tracked!\n" % f) | |
778 else: | |
779 self.dirstate.update([f], "r") | |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
780 |
363 | 781 def copy(self, source, dest): |
782 p = self.wjoin(dest) | |
783 if not os.path.isfile(dest): | |
784 self.ui.warn("%s does not exist!\n" % dest) | |
785 else: | |
786 if self.dirstate.state(dest) == '?': | |
787 self.dirstate.update([dest], "a") | |
788 self.dirstate.copy(source, dest) | |
789 | |
222 | 790 def heads(self): |
791 return self.changelog.heads() | |
792 | |
56
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
793 def branches(self, nodes): |
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
794 if not nodes: nodes = [self.changelog.tip()] |
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
795 b = [] |
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
796 for n in nodes: |
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
797 t = n |
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
798 while n: |
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
799 p = self.changelog.parents(n) |
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
800 if p[1] != nullid or p[0] == nullid: |
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
801 b.append((t, n, p[0], p[1])) |
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
802 break |
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
803 n = p[0] |
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
804 return b |
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
805 |
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
806 def between(self, pairs): |
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
807 r = [] |
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
808 |
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
809 for top, bottom in pairs: |
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
810 n, l, i = top, [], 0 |
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
811 f = 1 |
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
812 |
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
813 while n != bottom: |
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
814 p = self.changelog.parents(n)[0] |
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
815 if i == f: |
575 | 816 l.append(n) |
56
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
817 f = f * 2 |
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
818 n = p |
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
819 i += 1 |
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
820 |
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
821 r.append(l) |
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
822 |
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
823 return r |
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
824 |
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
825 def newer(self, nodes): |
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
826 m = {} |
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
827 nl = [] |
94 | 828 pm = {} |
56
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
829 cl = self.changelog |
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
830 t = l = cl.count() |
94 | 831 |
832 # find the lowest numbered node | |
56
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
833 for n in nodes: |
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
834 l = min(l, cl.rev(n)) |
94 | 835 m[n] = 1 |
46 | 836 |
56
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
837 for i in xrange(l, t): |
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
838 n = cl.node(i) |
94 | 839 if n in m: # explicitly listed |
840 pm[n] = 1 | |
841 nl.append(n) | |
842 continue | |
56
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
843 for p in cl.parents(n): |
94 | 844 if p in pm: # parent listed |
845 pm[n] = 1 | |
56
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
846 nl.append(n) |
94 | 847 break |
56
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
848 |
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
849 return nl |
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
850 |
516 | 851 def findincoming(self, remote): |
65
d40cc5aacc31
Fix up a bunch of bugs in the new merge code
mpm@selenic.com
parents:
64
diff
changeset
|
852 m = self.changelog.nodemap |
56
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
853 search = [] |
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
854 fetch = [] |
148
c32286d0a665
Improve pruning of branches in outstanding changeset algorithm
mpm@selenic.com
parents:
146
diff
changeset
|
855 seen = {} |
c32286d0a665
Improve pruning of branches in outstanding changeset algorithm
mpm@selenic.com
parents:
146
diff
changeset
|
856 seenbranch = {} |
192 | 857 |
190
3dd5ce2fddb6
merge: short-circuit search for merge into empty repo
mpm@selenic.com
parents:
187
diff
changeset
|
858 # if we have an empty repo, fetch everything |
3dd5ce2fddb6
merge: short-circuit search for merge into empty repo
mpm@selenic.com
parents:
187
diff
changeset
|
859 if self.changelog.tip() == nullid: |
222 | 860 self.ui.status("requesting all changes\n") |
516 | 861 return [nullid] |
190
3dd5ce2fddb6
merge: short-circuit search for merge into empty repo
mpm@selenic.com
parents:
187
diff
changeset
|
862 |
3dd5ce2fddb6
merge: short-circuit search for merge into empty repo
mpm@selenic.com
parents:
187
diff
changeset
|
863 # otherwise, assume we're closer to the tip than the root |
222 | 864 self.ui.status("searching for changes\n") |
865 heads = remote.heads() | |
866 unknown = [] | |
867 for h in heads: | |
868 if h not in m: | |
869 unknown.append(h) | |
46 | 870 |
222 | 871 if not unknown: |
60 | 872 return None |
324 | 873 |
874 rep = {} | |
875 reqcnt = 0 | |
515 | 876 |
222 | 877 unknown = remote.branches(unknown) |
56
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
878 while unknown: |
324 | 879 r = [] |
880 while unknown: | |
881 n = unknown.pop(0) | |
882 if n[0] in seen: | |
883 continue | |
148
c32286d0a665
Improve pruning of branches in outstanding changeset algorithm
mpm@selenic.com
parents:
146
diff
changeset
|
884 |
324 | 885 self.ui.debug("examining %s:%s\n" % (short(n[0]), short(n[1]))) |
886 if n[0] == nullid: | |
887 break | |
328 | 888 if n in seenbranch: |
324 | 889 self.ui.debug("branch already found\n") |
890 continue | |
891 if n[1] and n[1] in m: # do we know the base? | |
892 self.ui.debug("found incomplete branch %s:%s\n" | |
893 % (short(n[0]), short(n[1]))) | |
894 search.append(n) # schedule branch range for scanning | |
328 | 895 seenbranch[n] = 1 |
324 | 896 else: |
897 if n[1] not in seen and n[1] not in fetch: | |
898 if n[2] in m and n[3] in m: | |
899 self.ui.debug("found new changeset %s\n" % | |
900 short(n[1])) | |
901 fetch.append(n[1]) # earliest unknown | |
902 continue | |
903 | |
904 for a in n[2:4]: | |
905 if a not in rep: | |
906 r.append(a) | |
907 rep[a] = 1 | |
908 | |
328 | 909 seen[n[0]] = 1 |
910 | |
324 | 911 if r: |
912 reqcnt += 1 | |
913 self.ui.debug("request %d: %s\n" % | |
914 (reqcnt, " ".join(map(short, r)))) | |
915 for p in range(0, len(r), 10): | |
916 for b in remote.branches(r[p:p+10]): | |
148
c32286d0a665
Improve pruning of branches in outstanding changeset algorithm
mpm@selenic.com
parents:
146
diff
changeset
|
917 self.ui.debug("received %s:%s\n" % |
c32286d0a665
Improve pruning of branches in outstanding changeset algorithm
mpm@selenic.com
parents:
146
diff
changeset
|
918 (short(b[0]), short(b[1]))) |
c32286d0a665
Improve pruning of branches in outstanding changeset algorithm
mpm@selenic.com
parents:
146
diff
changeset
|
919 if b[0] not in m and b[0] not in seen: |
c32286d0a665
Improve pruning of branches in outstanding changeset algorithm
mpm@selenic.com
parents:
146
diff
changeset
|
920 unknown.append(b) |
515 | 921 |
56
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
922 while search: |
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
923 n = search.pop(0) |
324 | 924 reqcnt += 1 |
56
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
925 l = remote.between([(n[0], n[1])])[0] |
328 | 926 l.append(n[1]) |
56
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
927 p = n[0] |
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
928 f = 1 |
328 | 929 for i in l: |
930 self.ui.debug("narrowing %d:%d %s\n" % (f, len(l), short(i))) | |
65
d40cc5aacc31
Fix up a bunch of bugs in the new merge code
mpm@selenic.com
parents:
64
diff
changeset
|
931 if i in m: |
85 | 932 if f <= 2: |
83 | 933 self.ui.debug("found new branch changeset %s\n" % |
934 short(p)) | |
56
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
935 fetch.append(p) |
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
936 else: |
83 | 937 self.ui.debug("narrowed branch search to %s:%s\n" |
938 % (short(p), short(i))) | |
56
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
939 search.append((p, i)) |
65
d40cc5aacc31
Fix up a bunch of bugs in the new merge code
mpm@selenic.com
parents:
64
diff
changeset
|
940 break |
56
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
941 p, f = i, f * 2 |
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
942 |
65
d40cc5aacc31
Fix up a bunch of bugs in the new merge code
mpm@selenic.com
parents:
64
diff
changeset
|
943 for f in fetch: |
d40cc5aacc31
Fix up a bunch of bugs in the new merge code
mpm@selenic.com
parents:
64
diff
changeset
|
944 if f in m: |
499 | 945 raise RepoError("already have changeset " + short(f[:4])) |
83 | 946 |
511 | 947 if fetch == [nullid]: |
514
874e577e332e
change unrelated repository error to a warning
mpm@selenic.com
parents:
511
diff
changeset
|
948 self.ui.warn("warning: pulling from an unrelated repository!\n") |
511 | 949 |
94 | 950 self.ui.note("adding new changesets starting at " + |
83 | 951 " ".join([short(f) for f in fetch]) + "\n") |
65
d40cc5aacc31
Fix up a bunch of bugs in the new merge code
mpm@selenic.com
parents:
64
diff
changeset
|
952 |
324 | 953 self.ui.debug("%d total queries\n" % reqcnt) |
954 | |
516 | 955 return fetch |
956 | |
56
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
957 def changegroup(self, basenodes): |
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
958 nodes = self.newer(basenodes) |
ad2ea1185f04
Add getchangegroup code to efficiently calculate and request a changegroup
mpm@selenic.com
parents:
55
diff
changeset
|
959 |
46 | 960 # construct the link map |
961 linkmap = {} | |
962 for n in nodes: | |
963 linkmap[self.changelog.rev(n)] = n | |
964 | |
965 # construct a list of all changed files | |
966 changed = {} | |
967 for n in nodes: | |
968 c = self.changelog.read(n) | |
969 for f in c[3]: | |
970 changed[f] = 1 | |
971 changed = changed.keys() | |
972 changed.sort() | |
973 | |
974 # the changegroup is changesets + manifests + all file revs | |
975 revs = [ self.changelog.rev(n) for n in nodes ] | |
976 | |
192 | 977 for y in self.changelog.group(linkmap): yield y |
978 for y in self.manifest.group(linkmap): yield y | |
46 | 979 for f in changed: |
192 | 980 yield struct.pack(">l", len(f) + 4) + f |
46 | 981 g = self.file(f).group(linkmap) |
192 | 982 for y in g: |
983 yield y | |
46 | 984 |
65
d40cc5aacc31
Fix up a bunch of bugs in the new merge code
mpm@selenic.com
parents:
64
diff
changeset
|
985 def addchangegroup(self, generator): |
222 | 986 |
987 class genread: | |
988 def __init__(self, generator): | |
989 self.g = generator | |
990 self.buf = "" | |
991 def read(self, l): | |
992 while l > len(self.buf): | |
993 try: | |
994 self.buf += self.g.next() | |
995 except StopIteration: | |
996 break | |
997 d, self.buf = self.buf[:l], self.buf[l:] | |
998 return d | |
515 | 999 |
222 | 1000 def getchunk(): |
1001 d = source.read(4) | |
1002 if not d: return "" | |
1003 l = struct.unpack(">l", d)[0] | |
1004 if l <= 4: return "" | |
1005 return source.read(l - 4) | |
1006 | |
1007 def getgroup(): | |
1008 while 1: | |
1009 c = getchunk() | |
1010 if not c: break | |
1011 yield c | |
1012 | |
1013 def csmap(x): | |
1014 self.ui.debug("add changeset %s\n" % short(x)) | |
1015 return self.changelog.count() | |
1016 | |
1017 def revmap(x): | |
1018 return self.changelog.rev(x) | |
1019 | |
1020 if not generator: return | |
1021 changesets = files = revisions = 0 | |
225 | 1022 |
222 | 1023 source = genread(generator) |
225 | 1024 lock = self.lock() |
222 | 1025 tr = self.transaction() |
1026 | |
1027 # pull off the changeset group | |
1028 self.ui.status("adding changesets\n") | |
1029 co = self.changelog.tip() | |
224
ccbcc4d76f81
fix bad assumption about uniqueness of file versions
mpm@selenic.com
parents:
223
diff
changeset
|
1030 cn = self.changelog.addgroup(getgroup(), csmap, tr, 1) # unique |
222 | 1031 changesets = self.changelog.rev(cn) - self.changelog.rev(co) |
1032 | |
1033 # pull off the manifest group | |
1034 self.ui.status("adding manifests\n") | |
1035 mm = self.manifest.tip() | |
1036 mo = self.manifest.addgroup(getgroup(), revmap, tr) | |
1037 | |
1038 # process the files | |
1039 self.ui.status("adding file revisions\n") | |
1040 while 1: | |
1041 f = getchunk() | |
1042 if not f: break | |
1043 self.ui.debug("adding %s revisions\n" % f) | |
1044 fl = self.file(f) | |
529
aace5b681fe9
Attempt to fix negative revision count from pull
mpm@selenic.com
parents:
522
diff
changeset
|
1045 o = fl.count() |
222 | 1046 n = fl.addgroup(getgroup(), revmap, tr) |
529
aace5b681fe9
Attempt to fix negative revision count from pull
mpm@selenic.com
parents:
522
diff
changeset
|
1047 revisions += fl.count() - o |
222 | 1048 files += 1 |
1049 | |
1050 self.ui.status(("modified %d files, added %d changesets" + | |
1051 " and %d new revisions\n") | |
1052 % (files, changesets, revisions)) | |
1053 | |
1054 tr.close() | |
1055 return | |
1056 | |
275 | 1057 def update(self, node, allow=False, force=False): |
232
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1058 pl = self.dirstate.parents() |
275 | 1059 if not force and pl[1] != nullid: |
254 | 1060 self.ui.warn("aborting: outstanding uncommitted merges\n") |
46 | 1061 return |
1062 | |
232
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1063 p1, p2 = pl[0], node |
305 | 1064 pa = self.changelog.ancestor(p1, p2) |
232
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1065 m1n = self.changelog.read(p1)[0] |
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1066 m2n = self.changelog.read(p2)[0] |
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1067 man = self.manifest.ancestor(m1n, m2n) |
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1068 m1 = self.manifest.read(m1n) |
276 | 1069 mf1 = self.manifest.readflags(m1n) |
232
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1070 m2 = self.manifest.read(m2n) |
276 | 1071 mf2 = self.manifest.readflags(m2n) |
232
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1072 ma = self.manifest.read(man) |
412 | 1073 mfa = self.manifest.readflags(man) |
232
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1074 |
536 | 1075 (c, a, d, u) = self.changes(None, None) |
232
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1076 |
408
3695fbd2c33b
[PATCH] Merging files that are deleted in both branches
mpm@selenic.com
parents:
407
diff
changeset
|
1077 # is this a jump, or a merge? i.e. is there a linear path |
3695fbd2c33b
[PATCH] Merging files that are deleted in both branches
mpm@selenic.com
parents:
407
diff
changeset
|
1078 # from p1 to p2? |
3695fbd2c33b
[PATCH] Merging files that are deleted in both branches
mpm@selenic.com
parents:
407
diff
changeset
|
1079 linear_path = (pa == p1 or pa == p2) |
3695fbd2c33b
[PATCH] Merging files that are deleted in both branches
mpm@selenic.com
parents:
407
diff
changeset
|
1080 |
232
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1081 # resolve the manifest to determine which files |
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1082 # we care about merging |
254 | 1083 self.ui.note("resolving manifests\n") |
232
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1084 self.ui.debug(" ancestor %s local %s remote %s\n" % |
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1085 (short(man), short(m1n), short(m2n))) |
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1086 |
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1087 merge = {} |
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1088 get = {} |
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1089 remove = [] |
305 | 1090 mark = {} |
46 | 1091 |
232
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1092 # construct a working dir manifest |
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1093 mw = m1.copy() |
276 | 1094 mfw = mf1.copy() |
576 | 1095 umap = dict.fromkeys(u) |
1096 | |
254 | 1097 for f in a + c + u: |
1098 mw[f] = "" | |
441 | 1099 mfw[f] = util.is_exec(self.wjoin(f), mfw.get(f, False)) |
576 | 1100 |
232
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1101 for f in d: |
254 | 1102 if f in mw: del mw[f] |
232
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1103 |
408
3695fbd2c33b
[PATCH] Merging files that are deleted in both branches
mpm@selenic.com
parents:
407
diff
changeset
|
1104 # If we're jumping between revisions (as opposed to merging), |
3695fbd2c33b
[PATCH] Merging files that are deleted in both branches
mpm@selenic.com
parents:
407
diff
changeset
|
1105 # and if neither the working directory nor the target rev has |
3695fbd2c33b
[PATCH] Merging files that are deleted in both branches
mpm@selenic.com
parents:
407
diff
changeset
|
1106 # the file, then we need to remove it from the dirstate, to |
3695fbd2c33b
[PATCH] Merging files that are deleted in both branches
mpm@selenic.com
parents:
407
diff
changeset
|
1107 # prevent the dirstate from listing the file when it is no |
3695fbd2c33b
[PATCH] Merging files that are deleted in both branches
mpm@selenic.com
parents:
407
diff
changeset
|
1108 # longer in the manifest. |
3695fbd2c33b
[PATCH] Merging files that are deleted in both branches
mpm@selenic.com
parents:
407
diff
changeset
|
1109 if linear_path and f not in m2: |
3695fbd2c33b
[PATCH] Merging files that are deleted in both branches
mpm@selenic.com
parents:
407
diff
changeset
|
1110 self.dirstate.forget((f,)) |
3695fbd2c33b
[PATCH] Merging files that are deleted in both branches
mpm@selenic.com
parents:
407
diff
changeset
|
1111 |
576 | 1112 # Compare manifests |
232
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1113 for f, n in mw.iteritems(): |
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1114 if f in m2: |
277
79279550c8ff
merge: update permissions even if file contents didn't change
mpm@selenic.com
parents:
276
diff
changeset
|
1115 s = 0 |
79279550c8ff
merge: update permissions even if file contents didn't change
mpm@selenic.com
parents:
276
diff
changeset
|
1116 |
407
0e0d0670b2bc
[PATCH] Merging identical changes from another branch
mpm@selenic.com
parents:
405
diff
changeset
|
1117 # is the wfile new since m1, and match m2? |
428 | 1118 if f not in m1: |
407
0e0d0670b2bc
[PATCH] Merging identical changes from another branch
mpm@selenic.com
parents:
405
diff
changeset
|
1119 t1 = self.wfile(f).read() |
0e0d0670b2bc
[PATCH] Merging identical changes from another branch
mpm@selenic.com
parents:
405
diff
changeset
|
1120 t2 = self.file(f).revision(m2[f]) |
0e0d0670b2bc
[PATCH] Merging identical changes from another branch
mpm@selenic.com
parents:
405
diff
changeset
|
1121 if cmp(t1, t2) == 0: |
0e0d0670b2bc
[PATCH] Merging identical changes from another branch
mpm@selenic.com
parents:
405
diff
changeset
|
1122 mark[f] = 1 |
0e0d0670b2bc
[PATCH] Merging identical changes from another branch
mpm@selenic.com
parents:
405
diff
changeset
|
1123 n = m2[f] |
0e0d0670b2bc
[PATCH] Merging identical changes from another branch
mpm@selenic.com
parents:
405
diff
changeset
|
1124 del t1, t2 |
0e0d0670b2bc
[PATCH] Merging identical changes from another branch
mpm@selenic.com
parents:
405
diff
changeset
|
1125 |
296
a3d83bf86755
hg update: fix clobbering files when going backwards
mpm@selenic.com
parents:
292
diff
changeset
|
1126 # are files different? |
232
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1127 if n != m2[f]: |
254 | 1128 a = ma.get(f, nullid) |
296
a3d83bf86755
hg update: fix clobbering files when going backwards
mpm@selenic.com
parents:
292
diff
changeset
|
1129 # are both different from the ancestor? |
254 | 1130 if n != a and m2[f] != a: |
273
4f8174389001
merge: Fix bug where we overwrote local when local was newer
mpm@selenic.com
parents:
263
diff
changeset
|
1131 self.ui.debug(" %s versions differ, resolve\n" % f) |
276 | 1132 # merge executable bits |
1133 # "if we changed or they changed, change in merge" | |
1134 a, b, c = mfa.get(f, 0), mfw[f], mf2[f] | |
1135 mode = ((a^b) | (a^c)) ^ a | |
1136 merge[f] = (m1.get(f, nullid), m2[f], mode) | |
277
79279550c8ff
merge: update permissions even if file contents didn't change
mpm@selenic.com
parents:
276
diff
changeset
|
1137 s = 1 |
305 | 1138 # are we clobbering? |
1139 # is remote's version newer? | |
1140 # or are we going back in time? | |
1141 elif force or m2[f] != a or (p2 == pa and mw[f] == m1[f]): | |
273
4f8174389001
merge: Fix bug where we overwrote local when local was newer
mpm@selenic.com
parents:
263
diff
changeset
|
1142 self.ui.debug(" remote %s is newer, get\n" % f) |
254 | 1143 get[f] = m2[f] |
277
79279550c8ff
merge: update permissions even if file contents didn't change
mpm@selenic.com
parents:
276
diff
changeset
|
1144 s = 1 |
305 | 1145 else: |
1146 mark[f] = 1 | |
576 | 1147 elif f in umap: |
1148 # this unknown file is the same as the checkout | |
1149 get[f] = m2[f] | |
277
79279550c8ff
merge: update permissions even if file contents didn't change
mpm@selenic.com
parents:
276
diff
changeset
|
1150 |
79279550c8ff
merge: update permissions even if file contents didn't change
mpm@selenic.com
parents:
276
diff
changeset
|
1151 if not s and mfw[f] != mf2[f]: |
79279550c8ff
merge: update permissions even if file contents didn't change
mpm@selenic.com
parents:
276
diff
changeset
|
1152 if force: |
79279550c8ff
merge: update permissions even if file contents didn't change
mpm@selenic.com
parents:
276
diff
changeset
|
1153 self.ui.debug(" updating permissions for %s\n" % f) |
441 | 1154 util.set_exec(self.wjoin(f), mf2[f]) |
277
79279550c8ff
merge: update permissions even if file contents didn't change
mpm@selenic.com
parents:
276
diff
changeset
|
1155 else: |
79279550c8ff
merge: update permissions even if file contents didn't change
mpm@selenic.com
parents:
276
diff
changeset
|
1156 a, b, c = mfa.get(f, 0), mfw[f], mf2[f] |
79279550c8ff
merge: update permissions even if file contents didn't change
mpm@selenic.com
parents:
276
diff
changeset
|
1157 mode = ((a^b) | (a^c)) ^ a |
79279550c8ff
merge: update permissions even if file contents didn't change
mpm@selenic.com
parents:
276
diff
changeset
|
1158 if mode != b: |
79279550c8ff
merge: update permissions even if file contents didn't change
mpm@selenic.com
parents:
276
diff
changeset
|
1159 self.ui.debug(" updating permissions for %s\n" % f) |
441 | 1160 util.set_exec(self.wjoin(f), mode) |
305 | 1161 mark[f] = 1 |
232
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1162 del m2[f] |
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1163 elif f in ma: |
275 | 1164 if not force and n != ma[f]: |
415
c2b9502a4e96
[PATCH] Don't prompt user for keep-vs-delete when the merge is about to be aborted
mpm@selenic.com
parents:
413
diff
changeset
|
1165 r = "" |
c2b9502a4e96
[PATCH] Don't prompt user for keep-vs-delete when the merge is about to be aborted
mpm@selenic.com
parents:
413
diff
changeset
|
1166 if linear_path or allow: |
c2b9502a4e96
[PATCH] Don't prompt user for keep-vs-delete when the merge is about to be aborted
mpm@selenic.com
parents:
413
diff
changeset
|
1167 r = self.ui.prompt( |
c2b9502a4e96
[PATCH] Don't prompt user for keep-vs-delete when the merge is about to be aborted
mpm@selenic.com
parents:
413
diff
changeset
|
1168 (" local changed %s which remote deleted\n" % f) + |
c2b9502a4e96
[PATCH] Don't prompt user for keep-vs-delete when the merge is about to be aborted
mpm@selenic.com
parents:
413
diff
changeset
|
1169 "(k)eep or (d)elete?", "[kd]", "k") |
232
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1170 if r == "d": |
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1171 remove.append(f) |
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1172 else: |
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1173 self.ui.debug("other deleted %s\n" % f) |
254 | 1174 remove.append(f) # other deleted it |
232
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1175 else: |
254 | 1176 if n == m1.get(f, nullid): # same as parent |
383
4862a134e2c2
hg merge: fix time asymmetry bug with deleting files on update to past
mpm@selenic.com
parents:
377
diff
changeset
|
1177 if p2 == pa: # going backwards? |
4862a134e2c2
hg merge: fix time asymmetry bug with deleting files on update to past
mpm@selenic.com
parents:
377
diff
changeset
|
1178 self.ui.debug("remote deleted %s\n" % f) |
4862a134e2c2
hg merge: fix time asymmetry bug with deleting files on update to past
mpm@selenic.com
parents:
377
diff
changeset
|
1179 remove.append(f) |
4862a134e2c2
hg merge: fix time asymmetry bug with deleting files on update to past
mpm@selenic.com
parents:
377
diff
changeset
|
1180 else: |
4862a134e2c2
hg merge: fix time asymmetry bug with deleting files on update to past
mpm@selenic.com
parents:
377
diff
changeset
|
1181 self.ui.debug("local created %s, keeping\n" % f) |
254 | 1182 else: |
1183 self.ui.debug("working dir created %s, keeping\n" % f) | |
46 | 1184 |
232
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1185 for f, n in m2.iteritems(): |
256 | 1186 if f[0] == "/": continue |
275 | 1187 if not force and f in ma and n != ma[f]: |
415
c2b9502a4e96
[PATCH] Don't prompt user for keep-vs-delete when the merge is about to be aborted
mpm@selenic.com
parents:
413
diff
changeset
|
1188 r = "" |
c2b9502a4e96
[PATCH] Don't prompt user for keep-vs-delete when the merge is about to be aborted
mpm@selenic.com
parents:
413
diff
changeset
|
1189 if linear_path or allow: |
c2b9502a4e96
[PATCH] Don't prompt user for keep-vs-delete when the merge is about to be aborted
mpm@selenic.com
parents:
413
diff
changeset
|
1190 r = self.ui.prompt( |
c2b9502a4e96
[PATCH] Don't prompt user for keep-vs-delete when the merge is about to be aborted
mpm@selenic.com
parents:
413
diff
changeset
|
1191 ("remote changed %s which local deleted\n" % f) + |
c2b9502a4e96
[PATCH] Don't prompt user for keep-vs-delete when the merge is about to be aborted
mpm@selenic.com
parents:
413
diff
changeset
|
1192 "(k)eep or (d)elete?", "[kd]", "k") |
275 | 1193 if r == "d": remove.append(f) |
232
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1194 else: |
254 | 1195 self.ui.debug("remote created %s\n" % f) |
232
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1196 get[f] = n |
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1197 |
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1198 del mw, m1, m2, ma |
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1199 |
275 | 1200 if force: |
1201 for f in merge: | |
1202 get[f] = merge[f][1] | |
1203 merge = {} | |
1204 | |
408
3695fbd2c33b
[PATCH] Merging files that are deleted in both branches
mpm@selenic.com
parents:
407
diff
changeset
|
1205 if linear_path: |
254 | 1206 # we don't need to do any magic, just jump to the new rev |
1207 mode = 'n' | |
1208 p1, p2 = p2, nullid | |
1209 else: | |
275 | 1210 if not allow: |
305 | 1211 self.ui.status("this update spans a branch" + |
1212 " affecting the following files:\n") | |
1213 fl = merge.keys() + get.keys() | |
1214 fl.sort() | |
1215 for f in fl: | |
1216 cf = "" | |
1217 if f in merge: cf = " (resolve)" | |
1218 self.ui.status(" %s%s\n" % (f, cf)) | |
1219 self.ui.warn("aborting update spanning branches!\n") | |
1220 self.ui.status("(use update -m to perform a branch merge)\n") | |
275 | 1221 return 1 |
254 | 1222 # we have to remember what files we needed to get/change |
1223 # because any file that's different from either one of its | |
1224 # parents must be in the changeset | |
1225 mode = 'm' | |
305 | 1226 self.dirstate.update(mark.keys(), "m") |
254 | 1227 |
232
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1228 self.dirstate.setparents(p1, p2) |
191
d7e859cf2f1b
merge: add count of new manifests, files, and revisions
mpm@selenic.com
parents:
190
diff
changeset
|
1229 |
232
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1230 # get the files we don't need to change |
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1231 files = get.keys() |
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1232 files.sort() |
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1233 for f in files: |
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1234 if f[0] == "/": continue |
273
4f8174389001
merge: Fix bug where we overwrote local when local was newer
mpm@selenic.com
parents:
263
diff
changeset
|
1235 self.ui.note("getting %s\n" % f) |
276 | 1236 t = self.file(f).read(get[f]) |
232
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1237 try: |
291
2c4f2be05587
Add wopener for opening files in the working directory
mpm@selenic.com
parents:
288
diff
changeset
|
1238 self.wfile(f, "w").write(t) |
232
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1239 except IOError: |
297
0dbcf3c9ff20
Fixed usage of removed variable 'wp'.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
292
diff
changeset
|
1240 os.makedirs(os.path.dirname(self.wjoin(f))) |
291
2c4f2be05587
Add wopener for opening files in the working directory
mpm@selenic.com
parents:
288
diff
changeset
|
1241 self.wfile(f, "w").write(t) |
441 | 1242 util.set_exec(self.wjoin(f), mf2[f]) |
254 | 1243 self.dirstate.update([f], mode) |
46 | 1244 |
232
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1245 # merge the tricky bits |
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1246 files = merge.keys() |
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1247 files.sort() |
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1248 for f in files: |
256 | 1249 self.ui.status("merging %s\n" % f) |
276 | 1250 m, o, flag = merge[f] |
232
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1251 self.merge3(f, m, o) |
441 | 1252 util.set_exec(self.wjoin(f), flag) |
254 | 1253 self.dirstate.update([f], 'm') |
232
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1254 |
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1255 for f in remove: |
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1256 self.ui.note("removing %s\n" % f) |
254 | 1257 os.unlink(f) |
1258 if mode == 'n': | |
1259 self.dirstate.forget(remove) | |
1260 else: | |
1261 self.dirstate.update(remove, 'r') | |
232
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1262 |
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1263 def merge3(self, fn, my, other): |
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1264 """perform a 3-way merge in the working directory""" |
249 | 1265 |
96 | 1266 def temp(prefix, node): |
1267 pre = "%s~%s." % (os.path.basename(fn), prefix) | |
1268 (fd, name) = tempfile.mkstemp("", pre) | |
417 | 1269 f = os.fdopen(fd, "wb") |
96 | 1270 f.write(fl.revision(node)) |
1271 f.close() | |
1272 return name | |
1273 | |
232
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1274 fl = self.file(fn) |
96 | 1275 base = fl.ancestor(my, other) |
244 | 1276 a = self.wjoin(fn) |
346 | 1277 b = temp("base", base) |
1278 c = temp("other", other) | |
96 | 1279 |
232
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1280 self.ui.note("resolving %s\n" % fn) |
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1281 self.ui.debug("file %s: other %s ancestor %s\n" % |
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1282 (fn, short(other), short(base))) |
96 | 1283 |
240 | 1284 cmd = os.environ.get("HGMERGE", "hgmerge") |
1285 r = os.system("%s %s %s %s" % (cmd, a, b, c)) | |
232
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1286 if r: |
275 | 1287 self.ui.warn("merging %s failed!\n" % fn) |
232
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1288 |
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1289 os.unlink(b) |
fc4a6e5b5812
hg resolve: merge a given node into the working directory
mpm@selenic.com
parents:
231
diff
changeset
|
1290 os.unlink(c) |
96 | 1291 |
247 | 1292 def verify(self): |
1293 filelinkrevs = {} | |
1294 filenodes = {} | |
1295 changesets = revisions = files = 0 | |
1296 errors = 0 | |
1297 | |
302 | 1298 seen = {} |
247 | 1299 self.ui.status("checking changesets\n") |
1300 for i in range(self.changelog.count()): | |
1301 changesets += 1 | |
1302 n = self.changelog.node(i) | |
302 | 1303 if n in seen: |
1304 self.ui.warn("duplicate changeset at revision %d\n" % i) | |
1305 errors += 1 | |
1306 seen[n] = 1 | |
515 | 1307 |
247 | 1308 for p in self.changelog.parents(n): |
1309 if p not in self.changelog.nodemap: | |
1310 self.ui.warn("changeset %s has unknown parent %s\n" % | |
1311 (short(n), short(p))) | |
1312 errors += 1 | |
1313 try: | |
1314 changes = self.changelog.read(n) | |
1315 except Exception, inst: | |
1316 self.ui.warn("unpacking changeset %s: %s\n" % (short(n), inst)) | |
1317 errors += 1 | |
1318 | |
1319 for f in changes[3]: | |
1320 filelinkrevs.setdefault(f, []).append(i) | |
1321 | |
302 | 1322 seen = {} |
247 | 1323 self.ui.status("checking manifests\n") |
1324 for i in range(self.manifest.count()): | |
1325 n = self.manifest.node(i) | |
302 | 1326 if n in seen: |
1327 self.ui.warn("duplicate manifest at revision %d\n" % i) | |
1328 errors += 1 | |
1329 seen[n] = 1 | |
515 | 1330 |
247 | 1331 for p in self.manifest.parents(n): |
1332 if p not in self.manifest.nodemap: | |
1333 self.ui.warn("manifest %s has unknown parent %s\n" % | |
1334 (short(n), short(p))) | |
1335 errors += 1 | |
1336 | |
1337 try: | |
1338 delta = mdiff.patchtext(self.manifest.delta(n)) | |
1339 except KeyboardInterrupt: | |
1340 print "aborted" | |
1341 sys.exit(0) | |
1342 except Exception, inst: | |
1343 self.ui.warn("unpacking manifest %s: %s\n" | |
1344 % (short(n), inst)) | |
1345 errors += 1 | |
1346 | |
1347 ff = [ l.split('\0') for l in delta.splitlines() ] | |
1348 for f, fn in ff: | |
284 | 1349 filenodes.setdefault(f, {})[bin(fn[:40])] = 1 |
247 | 1350 |
1351 self.ui.status("crosschecking files in changesets and manifests\n") | |
1352 for f in filenodes: | |
1353 if f not in filelinkrevs: | |
1354 self.ui.warn("file %s in manifest but not in changesets\n" % f) | |
1355 errors += 1 | |
1356 | |
1357 for f in filelinkrevs: | |
1358 if f not in filenodes: | |
1359 self.ui.warn("file %s in changeset but not in manifest\n" % f) | |
1360 errors += 1 | |
1361 | |
1362 self.ui.status("checking files\n") | |
1363 ff = filenodes.keys() | |
1364 ff.sort() | |
1365 for f in ff: | |
1366 if f == "/dev/null": continue | |
1367 files += 1 | |
1368 fl = self.file(f) | |
1369 nodes = { nullid: 1 } | |
302 | 1370 seen = {} |
247 | 1371 for i in range(fl.count()): |
1372 revisions += 1 | |
1373 n = fl.node(i) | |
1374 | |
302 | 1375 if n in seen: |
1376 self.ui.warn("%s: duplicate revision %d\n" % (f, i)) | |
1377 errors += 1 | |
1378 | |
247 | 1379 if n not in filenodes[f]: |
1380 self.ui.warn("%s: %d:%s not in manifests\n" | |
1381 % (f, i, short(n))) | |
1382 print len(filenodes[f].keys()), fl.count(), f | |
1383 errors += 1 | |
1384 else: | |
1385 del filenodes[f][n] | |
1386 | |
1387 flr = fl.linkrev(n) | |
1388 if flr not in filelinkrevs[f]: | |
1389 self.ui.warn("%s:%s points to unexpected changeset %d\n" | |
1390 % (f, short(n), fl.linkrev(n))) | |
1391 errors += 1 | |
1392 else: | |
1393 filelinkrevs[f].remove(flr) | |
1394 | |
1395 # verify contents | |
1396 try: | |
1397 t = fl.read(n) | |
1398 except Exception, inst: | |
1399 self.ui.warn("unpacking file %s %s: %s\n" | |
1400 % (f, short(n), inst)) | |
1401 errors += 1 | |
1402 | |
1403 # verify parents | |
1404 (p1, p2) = fl.parents(n) | |
1405 if p1 not in nodes: | |
1406 self.ui.warn("file %s:%s unknown parent 1 %s" % | |
1407 (f, short(n), short(p1))) | |
1408 errors += 1 | |
1409 if p2 not in nodes: | |
1410 self.ui.warn("file %s:%s unknown parent 2 %s" % | |
1411 (f, short(n), short(p1))) | |
1412 errors += 1 | |
1413 nodes[n] = 1 | |
1414 | |
1415 # cross-check | |
1416 for node in filenodes[f]: | |
1417 self.ui.warn("node %s in manifests not in %s\n" | |
1418 % (hex(n), f)) | |
1419 errors += 1 | |
1420 | |
1421 self.ui.status("%d files, %d changesets, %d total revisions\n" % | |
1422 (files, changesets, revisions)) | |
1423 | |
1424 if errors: | |
1425 self.ui.warn("%d integrity errors encountered!\n" % errors) | |
1426 return 1 | |
1427 | |
60 | 1428 class remoterepository: |
1429 def __init__(self, ui, path): | |
176
1d8e9637a0a4
Change hg: protocol name to http: and http: to old-http:
mpm@selenic.com
parents:
171
diff
changeset
|
1430 self.url = path |
60 | 1431 self.ui = ui |
321 | 1432 no_list = [ "localhost", "127.0.0.1" ] |
1433 host = ui.config("http_proxy", "host") | |
424
9294dce4b633
Allow override of HTTP_PROXY, http_proxy and no_proxy; make no_proxy work.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
385
diff
changeset
|
1434 if host is None: |
9294dce4b633
Allow override of HTTP_PROXY, http_proxy and no_proxy; make no_proxy work.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
385
diff
changeset
|
1435 host = os.environ.get("http_proxy") |
426
8c90ab5644c9
Allow hgrc's proxy host and $http_proxy env var to start with http://
Thomas Arendsen Hein <thomas@intevation.de>
parents:
424
diff
changeset
|
1436 if host and host.startswith('http://'): |
8c90ab5644c9
Allow hgrc's proxy host and $http_proxy env var to start with http://
Thomas Arendsen Hein <thomas@intevation.de>
parents:
424
diff
changeset
|
1437 host = host[7:] |
321 | 1438 user = ui.config("http_proxy", "user") |
1439 passwd = ui.config("http_proxy", "passwd") | |
1440 no = ui.config("http_proxy", "no") | |
424
9294dce4b633
Allow override of HTTP_PROXY, http_proxy and no_proxy; make no_proxy work.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
385
diff
changeset
|
1441 if no is None: |
9294dce4b633
Allow override of HTTP_PROXY, http_proxy and no_proxy; make no_proxy work.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
385
diff
changeset
|
1442 no = os.environ.get("no_proxy") |
321 | 1443 if no: |
1444 no_list = no_list + no.split(",") | |
515 | 1445 |
321 | 1446 no_proxy = 0 |
1447 for h in no_list: | |
1448 if (path.startswith("http://" + h + "/") or | |
1449 path.startswith("http://" + h + ":") or | |
1450 path == "http://" + h): | |
1451 no_proxy = 1 | |
1452 | |
1453 # Note: urllib2 takes proxy values from the environment and those will | |
1454 # take precedence | |
424
9294dce4b633
Allow override of HTTP_PROXY, http_proxy and no_proxy; make no_proxy work.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
385
diff
changeset
|
1455 for env in ["HTTP_PROXY", "http_proxy", "no_proxy"]: |
9294dce4b633
Allow override of HTTP_PROXY, http_proxy and no_proxy; make no_proxy work.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
385
diff
changeset
|
1456 if os.environ.has_key(env): |
9294dce4b633
Allow override of HTTP_PROXY, http_proxy and no_proxy; make no_proxy work.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
385
diff
changeset
|
1457 del os.environ[env] |
321 | 1458 |
1459 proxy_handler = urllib2.BaseHandler() | |
1460 if host and not no_proxy: | |
1461 proxy_handler = urllib2.ProxyHandler({"http" : "http://" + host}) | |
1462 | |
1463 authinfo = None | |
1464 if user and passwd: | |
1465 passmgr = urllib2.HTTPPasswordMgrWithDefaultRealm() | |
1466 passmgr.add_password(None, host, user, passwd) | |
1467 authinfo = urllib2.ProxyBasicAuthHandler(passmgr) | |
1468 | |
1469 opener = urllib2.build_opener(proxy_handler, authinfo) | |
1470 urllib2.install_opener(opener) | |
60 | 1471 |
1472 def do_cmd(self, cmd, **args): | |
83 | 1473 self.ui.debug("sending %s command\n" % cmd) |
60 | 1474 q = {"cmd": cmd} |
1475 q.update(args) | |
1476 qs = urllib.urlencode(q) | |
1477 cu = "%s?%s" % (self.url, qs) | |
321 | 1478 return urllib2.urlopen(cu) |
60 | 1479 |
222 | 1480 def heads(self): |
1481 d = self.do_cmd("heads").read() | |
1482 try: | |
1483 return map(bin, d[:-1].split(" ")) | |
1484 except: | |
1485 self.ui.warn("unexpected response:\n" + d[:400] + "\n...\n") | |
1486 raise | |
1487 | |
60 | 1488 def branches(self, nodes): |
1489 n = " ".join(map(hex, nodes)) | |
65
d40cc5aacc31
Fix up a bunch of bugs in the new merge code
mpm@selenic.com
parents:
64
diff
changeset
|
1490 d = self.do_cmd("branches", nodes=n).read() |
217 | 1491 try: |
1492 br = [ tuple(map(bin, b.split(" "))) for b in d.splitlines() ] | |
1493 return br | |
1494 except: | |
1495 self.ui.warn("unexpected response:\n" + d[:400] + "\n...\n") | |
1496 raise | |
60 | 1497 |
1498 def between(self, pairs): | |
1499 n = "\n".join(["-".join(map(hex, p)) for p in pairs]) | |
65
d40cc5aacc31
Fix up a bunch of bugs in the new merge code
mpm@selenic.com
parents:
64
diff
changeset
|
1500 d = self.do_cmd("between", pairs=n).read() |
217 | 1501 try: |
1502 p = [ l and map(bin, l.split(" ")) or [] for l in d.splitlines() ] | |
1503 return p | |
1504 except: | |
1505 self.ui.warn("unexpected response:\n" + d[:400] + "\n...\n") | |
1506 raise | |
60 | 1507 |
1508 def changegroup(self, nodes): | |
1509 n = " ".join(map(hex, nodes)) | |
65
d40cc5aacc31
Fix up a bunch of bugs in the new merge code
mpm@selenic.com
parents:
64
diff
changeset
|
1510 zd = zlib.decompressobj() |
d40cc5aacc31
Fix up a bunch of bugs in the new merge code
mpm@selenic.com
parents:
64
diff
changeset
|
1511 f = self.do_cmd("changegroup", roots=n) |
192 | 1512 bytes = 0 |
65
d40cc5aacc31
Fix up a bunch of bugs in the new merge code
mpm@selenic.com
parents:
64
diff
changeset
|
1513 while 1: |
d40cc5aacc31
Fix up a bunch of bugs in the new merge code
mpm@selenic.com
parents:
64
diff
changeset
|
1514 d = f.read(4096) |
192 | 1515 bytes += len(d) |
65
d40cc5aacc31
Fix up a bunch of bugs in the new merge code
mpm@selenic.com
parents:
64
diff
changeset
|
1516 if not d: |
d40cc5aacc31
Fix up a bunch of bugs in the new merge code
mpm@selenic.com
parents:
64
diff
changeset
|
1517 yield zd.flush() |
d40cc5aacc31
Fix up a bunch of bugs in the new merge code
mpm@selenic.com
parents:
64
diff
changeset
|
1518 break |
d40cc5aacc31
Fix up a bunch of bugs in the new merge code
mpm@selenic.com
parents:
64
diff
changeset
|
1519 yield zd.decompress(d) |
192 | 1520 self.ui.note("%d bytes of data transfered\n" % bytes) |
60 | 1521 |
1522 def repository(ui, path=None, create=0): | |
176
1d8e9637a0a4
Change hg: protocol name to http: and http: to old-http:
mpm@selenic.com
parents:
171
diff
changeset
|
1523 if path and path[:7] == "http://": |
1d8e9637a0a4
Change hg: protocol name to http: and http: to old-http:
mpm@selenic.com
parents:
171
diff
changeset
|
1524 return remoterepository(ui, path) |
60 | 1525 if path and path[:5] == "hg://": |
176
1d8e9637a0a4
Change hg: protocol name to http: and http: to old-http:
mpm@selenic.com
parents:
171
diff
changeset
|
1526 return remoterepository(ui, path.replace("hg://", "http://")) |
1d8e9637a0a4
Change hg: protocol name to http: and http: to old-http:
mpm@selenic.com
parents:
171
diff
changeset
|
1527 if path and path[:11] == "old-http://": |
1d8e9637a0a4
Change hg: protocol name to http: and http: to old-http:
mpm@selenic.com
parents:
171
diff
changeset
|
1528 return localrepository(ui, path.replace("old-http://", "http://")) |
60 | 1529 else: |
1530 return localrepository(ui, path, create) | |
1531 |