annotate mercurial/repair.py @ 5483:0c43f87baba3 default tip

Fix file-changed-to-dir and dir-to-file commits (issue660). Allow adding to dirstate files that clash with previously existing but marked for removal. Protect from reintroducing clashes by revert. This change doesn't address related issues with update. Current workaround is to do "clean" update by manually removing conflicting files/dirs from working directory.
author Maxim Dounin <mdounin@mdounin.ru>
date Sat, 27 Oct 2007 16:27:55 +0400
parents 18e91c9def0c
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
4702
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
1 # repair.py - functions for repository repair for mercurial
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
2 #
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
3 # Copyright 2005, 2006 Chris Mason <mason@suse.com>
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
4 # Copyright 2007 Matt Mackall
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
5 #
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
6 # This software may be used and distributed according to the terms
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
7 # of the GNU General Public License, incorporated herein by reference.
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
8
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
9 import changegroup, revlog, os, commands
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
10
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
11 def strip(ui, repo, rev, backup="all"):
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
12 def limitheads(chlog, stop):
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
13 """return the list of all nodes that have no children"""
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
14 p = {}
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
15 h = []
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
16 stoprev = 0
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
17 if stop in chlog.nodemap:
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
18 stoprev = chlog.rev(stop)
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
19
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
20 for r in xrange(chlog.count() - 1, -1, -1):
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
21 n = chlog.node(r)
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
22 if n not in p:
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
23 h.append(n)
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
24 if n == stop:
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
25 break
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
26 if r < stoprev:
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
27 break
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
28 for pn in chlog.parents(n):
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
29 p[pn] = 1
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
30 return h
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
31
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
32 def bundle(repo, bases, heads, rev, suffix):
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
33 cg = repo.changegroupsubset(bases, heads, 'strip')
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
34 backupdir = repo.join("strip-backup")
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
35 if not os.path.isdir(backupdir):
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
36 os.mkdir(backupdir)
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
37 name = os.path.join(backupdir, "%s-%s" % (revlog.short(rev), suffix))
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
38 ui.warn("saving bundle to %s\n" % name)
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
39 return changegroup.writebundle(cg, name, "HG10BZ")
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
40
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
41 def stripall(revnum):
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
42 mm = repo.changectx(rev).manifest()
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
43 seen = {}
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
44
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
45 for x in xrange(revnum, repo.changelog.count()):
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
46 for f in repo.changectx(x).files():
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
47 if f in seen:
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
48 continue
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
49 seen[f] = 1
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
50 if f in mm:
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
51 filerev = mm[f]
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
52 else:
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
53 filerev = 0
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
54 seen[f] = filerev
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
55 # we go in two steps here so the strip loop happens in a
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
56 # sensible order. When stripping many files, this helps keep
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
57 # our disk access patterns under control.
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
58 seen_list = seen.keys()
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
59 seen_list.sort()
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
60 for f in seen_list:
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
61 ff = repo.file(f)
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
62 filerev = seen[f]
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
63 if filerev != 0:
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
64 if filerev in ff.nodemap:
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
65 filerev = ff.rev(filerev)
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
66 else:
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
67 filerev = 0
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
68 ff.strip(filerev, revnum)
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
69
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
70 chlog = repo.changelog
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
71 # TODO delete the undo files, and handle undo of merge sets
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
72 pp = chlog.parents(rev)
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
73 revnum = chlog.rev(rev)
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
74
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
75 # save is a list of all the branches we are truncating away
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
76 # that we actually want to keep. changegroup will be used
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
77 # to preserve them and add them back after the truncate
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
78 saveheads = []
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
79 savebases = {}
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
80
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
81 heads = limitheads(chlog, rev)
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
82 seen = {}
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
83
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
84 # search through all the heads, finding those where the revision
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
85 # we want to strip away is an ancestor. Also look for merges
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
86 # that might be turned into new heads by the strip.
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
87 while heads:
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
88 h = heads.pop()
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
89 n = h
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
90 while True:
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
91 seen[n] = 1
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
92 pp = chlog.parents(n)
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
93 if pp[1] != revlog.nullid:
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
94 for p in pp:
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
95 if chlog.rev(p) > revnum and p not in seen:
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
96 heads.append(p)
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
97 if pp[0] == revlog.nullid:
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
98 break
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
99 if chlog.rev(pp[0]) < revnum:
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
100 break
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
101 n = pp[0]
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
102 if n == rev:
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
103 break
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
104 r = chlog.reachable(h, rev)
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
105 if rev not in r:
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
106 saveheads.append(h)
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
107 for x in r:
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
108 if chlog.rev(x) > revnum:
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
109 savebases[x] = 1
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
110
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
111 # create a changegroup for all the branches we need to keep
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
112 if backup == "all":
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
113 bundle(repo, [rev], chlog.heads(), rev, 'backup')
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
114 if saveheads:
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
115 chgrpfile = bundle(repo, savebases.keys(), saveheads, rev, 'temp')
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
116
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
117 stripall(revnum)
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
118
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
119 change = chlog.read(rev)
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
120 chlog.strip(revnum, revnum)
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
121 repo.manifest.strip(repo.manifest.rev(change[0]), revnum)
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
122 if saveheads:
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
123 ui.status("adding branch\n")
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
124 commands.unbundle(ui, repo, "file:%s" % chgrpfile, update=False)
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
125 if backup != "strip":
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
126 os.unlink(chgrpfile)
18e91c9def0c strip: move strip code to a new repair module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
127