Show More
@@ -0,0 +1,83 | |||||
|
1 | # automv.py | |||
|
2 | # | |||
|
3 | # Copyright 2013-2016 Facebook, Inc. | |||
|
4 | # | |||
|
5 | # This software may be used and distributed according to the terms of the | |||
|
6 | # GNU General Public License version 2 or any later version. | |||
|
7 | """Check for unrecorded moves at commit time (EXPERIMENTAL) | |||
|
8 | ||||
|
9 | This extension checks at commit/amend time if any of the committed files | |||
|
10 | comes from an unrecorded mv. | |||
|
11 | ||||
|
12 | The threshold at which a file is considered a move can be set with the | |||
|
13 | ``automv.similarity`` config option; the default value is 1.00. | |||
|
14 | ||||
|
15 | """ | |||
|
16 | from __future__ import absolute_import | |||
|
17 | ||||
|
18 | from mercurial import ( | |||
|
19 | commands, | |||
|
20 | copies, | |||
|
21 | extensions, | |||
|
22 | scmutil, | |||
|
23 | similar | |||
|
24 | ) | |||
|
25 | from mercurial.i18n import _ | |||
|
26 | ||||
|
27 | def extsetup(ui): | |||
|
28 | entry = extensions.wrapcommand( | |||
|
29 | commands.table, 'commit', mvcheck) | |||
|
30 | entry[1].append( | |||
|
31 | ('', 'no-automv', None, | |||
|
32 | _('disable automatic file move detection'))) | |||
|
33 | ||||
|
34 | def mvcheck(orig, ui, repo, *pats, **opts): | |||
|
35 | disabled = opts.pop('no_automv', False) | |||
|
36 | if not disabled: | |||
|
37 | threshold = float(ui.config('automv', 'similarity', '1.00')) | |||
|
38 | if threshold > 0: | |||
|
39 | match = scmutil.match(repo[None], pats, opts) | |||
|
40 | added, removed = _interestingfiles(repo, match) | |||
|
41 | renames = _findrenames(repo, match, added, removed, threshold) | |||
|
42 | _markchanges(repo, renames) | |||
|
43 | ||||
|
44 | # developer config: automv.testmode | |||
|
45 | if not ui.configbool('automv', 'testmode'): | |||
|
46 | return orig(ui, repo, *pats, **opts) | |||
|
47 | ||||
|
48 | def _interestingfiles(repo, matcher): | |||
|
49 | stat = repo.status(repo['.'], repo[None], matcher) | |||
|
50 | added = stat[1] | |||
|
51 | removed = stat[2] | |||
|
52 | ||||
|
53 | copy = copies._forwardcopies(repo['.'], repo[None], matcher) | |||
|
54 | # remove the copy files for which we already have copy info | |||
|
55 | added = [f for f in added if f not in copy] | |||
|
56 | ||||
|
57 | return added, removed | |||
|
58 | ||||
|
59 | def _findrenames(repo, matcher, added, removed, similarity): | |||
|
60 | """Find renames from removed files of the current commit/amend files | |||
|
61 | to the added ones""" | |||
|
62 | renames = {} | |||
|
63 | if similarity > 0: | |||
|
64 | for src, dst, score in similar.findrenames( | |||
|
65 | repo, added, removed, similarity): | |||
|
66 | if repo.ui.verbose: | |||
|
67 | repo.ui.status( | |||
|
68 | _('detected move of %s as %s (%d%% similar)\n') % ( | |||
|
69 | matcher.rel(src), matcher.rel(dst), score * 100)) | |||
|
70 | renames[dst] = src | |||
|
71 | if renames: | |||
|
72 | repo.ui.status(_('detected move of %d files\n') % len(renames)) | |||
|
73 | return renames | |||
|
74 | ||||
|
75 | def _markchanges(repo, renames): | |||
|
76 | """Marks the files in renames as copied.""" | |||
|
77 | wctx = repo[None] | |||
|
78 | wlock = repo.wlock() | |||
|
79 | try: | |||
|
80 | for dst, src in renames.iteritems(): | |||
|
81 | wctx.copy(src, dst) | |||
|
82 | finally: | |||
|
83 | wlock.release() |
@@ -0,0 +1,285 | |||||
|
1 | $ cat >> $HGRCPATH << EOF | |||
|
2 | > [extensions] | |||
|
3 | > automv= | |||
|
4 | > rebase= | |||
|
5 | > EOF | |||
|
6 | ||||
|
7 | Setup repo | |||
|
8 | ||||
|
9 | $ hg init repo | |||
|
10 | $ cd repo | |||
|
11 | ||||
|
12 | Test automv command for commit | |||
|
13 | ||||
|
14 | $ echo 'foo' > a.txt | |||
|
15 | $ hg add a.txt | |||
|
16 | $ hg commit -m 'init repo with a' | |||
|
17 | ||||
|
18 | mv/rm/add | |||
|
19 | $ mv a.txt b.txt | |||
|
20 | $ hg rm a.txt | |||
|
21 | $ hg add b.txt | |||
|
22 | $ hg status -C | |||
|
23 | A b.txt | |||
|
24 | R a.txt | |||
|
25 | $ hg commit -m 'msg' | |||
|
26 | detected move of 1 files | |||
|
27 | $ hg status --change . -C | |||
|
28 | A b.txt | |||
|
29 | a.txt | |||
|
30 | R a.txt | |||
|
31 | $ hg up -r 0 | |||
|
32 | 1 files updated, 0 files merged, 1 files removed, 0 files unresolved | |||
|
33 | ||||
|
34 | mv/rm/add/modif | |||
|
35 | $ mv a.txt b.txt | |||
|
36 | $ hg rm a.txt | |||
|
37 | $ hg add b.txt | |||
|
38 | $ printf '\nfoo\n' >> b.txt | |||
|
39 | $ hg status -C | |||
|
40 | A b.txt | |||
|
41 | R a.txt | |||
|
42 | $ hg commit -m 'msg' | |||
|
43 | created new head | |||
|
44 | $ hg status --change . -C | |||
|
45 | A b.txt | |||
|
46 | R a.txt | |||
|
47 | $ hg up -r 0 | |||
|
48 | 1 files updated, 0 files merged, 1 files removed, 0 files unresolved | |||
|
49 | ||||
|
50 | mv/rm/add/modif/changethreshold | |||
|
51 | $ mv a.txt b.txt | |||
|
52 | $ hg rm a.txt | |||
|
53 | $ hg add b.txt | |||
|
54 | $ printf '\nfoo\n' >> b.txt | |||
|
55 | $ hg status -C | |||
|
56 | A b.txt | |||
|
57 | R a.txt | |||
|
58 | $ hg commit --config automv.similarity='0.6' -m 'msg' | |||
|
59 | detected move of 1 files | |||
|
60 | created new head | |||
|
61 | $ hg status --change . -C | |||
|
62 | A b.txt | |||
|
63 | a.txt | |||
|
64 | R a.txt | |||
|
65 | $ hg up -r 0 | |||
|
66 | 1 files updated, 0 files merged, 1 files removed, 0 files unresolved | |||
|
67 | ||||
|
68 | mv | |||
|
69 | $ mv a.txt b.txt | |||
|
70 | $ hg status -C | |||
|
71 | ! a.txt | |||
|
72 | ? b.txt | |||
|
73 | $ hg commit -m 'msg' | |||
|
74 | nothing changed (1 missing files, see 'hg status') | |||
|
75 | [1] | |||
|
76 | $ hg status -C | |||
|
77 | ! a.txt | |||
|
78 | ? b.txt | |||
|
79 | $ hg revert -aqC | |||
|
80 | $ rm b.txt | |||
|
81 | ||||
|
82 | mv/rm/add/notincommitfiles | |||
|
83 | $ mv a.txt b.txt | |||
|
84 | $ hg rm a.txt | |||
|
85 | $ hg add b.txt | |||
|
86 | $ echo 'bar' > c.txt | |||
|
87 | $ hg add c.txt | |||
|
88 | $ hg status -C | |||
|
89 | A b.txt | |||
|
90 | A c.txt | |||
|
91 | R a.txt | |||
|
92 | $ hg commit c.txt -m 'msg' | |||
|
93 | created new head | |||
|
94 | $ hg status --change . -C | |||
|
95 | A c.txt | |||
|
96 | $ hg status -C | |||
|
97 | A b.txt | |||
|
98 | R a.txt | |||
|
99 | $ hg up -r 0 | |||
|
100 | 0 files updated, 0 files merged, 1 files removed, 0 files unresolved | |||
|
101 | $ hg rm a.txt | |||
|
102 | $ echo 'bar' > c.txt | |||
|
103 | $ hg add c.txt | |||
|
104 | $ hg commit -m 'msg' | |||
|
105 | detected move of 1 files | |||
|
106 | created new head | |||
|
107 | $ hg status --change . -C | |||
|
108 | A b.txt | |||
|
109 | a.txt | |||
|
110 | A c.txt | |||
|
111 | R a.txt | |||
|
112 | $ hg up -r 0 | |||
|
113 | 1 files updated, 0 files merged, 2 files removed, 0 files unresolved | |||
|
114 | ||||
|
115 | mv/rm/add/--no-automv | |||
|
116 | $ mv a.txt b.txt | |||
|
117 | $ hg rm a.txt | |||
|
118 | $ hg add b.txt | |||
|
119 | $ hg status -C | |||
|
120 | A b.txt | |||
|
121 | R a.txt | |||
|
122 | $ hg commit --no-automv -m 'msg' | |||
|
123 | created new head | |||
|
124 | $ hg status --change . -C | |||
|
125 | A b.txt | |||
|
126 | R a.txt | |||
|
127 | $ hg up -r 0 | |||
|
128 | 1 files updated, 0 files merged, 1 files removed, 0 files unresolved | |||
|
129 | ||||
|
130 | Test automv command for commit --amend | |||
|
131 | ||||
|
132 | mv/rm/add | |||
|
133 | $ echo 'c' > c.txt | |||
|
134 | $ hg add c.txt | |||
|
135 | $ hg commit -m 'revision to amend to' | |||
|
136 | created new head | |||
|
137 | $ mv a.txt b.txt | |||
|
138 | $ hg rm a.txt | |||
|
139 | $ hg add b.txt | |||
|
140 | $ hg status -C | |||
|
141 | A b.txt | |||
|
142 | R a.txt | |||
|
143 | $ hg commit --amend -m 'amended' | |||
|
144 | detected move of 1 files | |||
|
145 | saved backup bundle to $TESTTMP/repo/.hg/strip-backup/*-amend-backup.hg (glob) | |||
|
146 | $ hg status --change . -C | |||
|
147 | A b.txt | |||
|
148 | a.txt | |||
|
149 | A c.txt | |||
|
150 | R a.txt | |||
|
151 | $ hg up -r 0 | |||
|
152 | 1 files updated, 0 files merged, 2 files removed, 0 files unresolved | |||
|
153 | ||||
|
154 | mv/rm/add/modif | |||
|
155 | $ echo 'c' > c.txt | |||
|
156 | $ hg add c.txt | |||
|
157 | $ hg commit -m 'revision to amend to' | |||
|
158 | created new head | |||
|
159 | $ mv a.txt b.txt | |||
|
160 | $ hg rm a.txt | |||
|
161 | $ hg add b.txt | |||
|
162 | $ printf '\nfoo\n' >> b.txt | |||
|
163 | $ hg status -C | |||
|
164 | A b.txt | |||
|
165 | R a.txt | |||
|
166 | $ hg commit --amend -m 'amended' | |||
|
167 | saved backup bundle to $TESTTMP/repo/.hg/strip-backup/*-amend-backup.hg (glob) | |||
|
168 | $ hg status --change . -C | |||
|
169 | A b.txt | |||
|
170 | A c.txt | |||
|
171 | R a.txt | |||
|
172 | $ hg up -r 0 | |||
|
173 | 1 files updated, 0 files merged, 2 files removed, 0 files unresolved | |||
|
174 | ||||
|
175 | mv/rm/add/modif/changethreshold | |||
|
176 | $ echo 'c' > c.txt | |||
|
177 | $ hg add c.txt | |||
|
178 | $ hg commit -m 'revision to amend to' | |||
|
179 | created new head | |||
|
180 | $ mv a.txt b.txt | |||
|
181 | $ hg rm a.txt | |||
|
182 | $ hg add b.txt | |||
|
183 | $ printf '\nfoo\n' >> b.txt | |||
|
184 | $ hg status -C | |||
|
185 | A b.txt | |||
|
186 | R a.txt | |||
|
187 | $ hg commit --amend --config automv.similarity='0.6' -m 'amended' | |||
|
188 | detected move of 1 files | |||
|
189 | saved backup bundle to $TESTTMP/repo/.hg/strip-backup/*-amend-backup.hg (glob) | |||
|
190 | $ hg status --change . -C | |||
|
191 | A b.txt | |||
|
192 | a.txt | |||
|
193 | A c.txt | |||
|
194 | R a.txt | |||
|
195 | $ hg up -r 0 | |||
|
196 | 1 files updated, 0 files merged, 2 files removed, 0 files unresolved | |||
|
197 | ||||
|
198 | mv | |||
|
199 | $ echo 'c' > c.txt | |||
|
200 | $ hg add c.txt | |||
|
201 | $ hg commit -m 'revision to amend to' | |||
|
202 | created new head | |||
|
203 | $ mv a.txt b.txt | |||
|
204 | $ hg status -C | |||
|
205 | ! a.txt | |||
|
206 | ? b.txt | |||
|
207 | $ hg commit --amend -m 'amended' | |||
|
208 | saved backup bundle to $TESTTMP/repo/.hg/strip-backup/*-amend-backup.hg (glob) | |||
|
209 | $ hg status -C | |||
|
210 | ! a.txt | |||
|
211 | ? b.txt | |||
|
212 | $ hg up -Cr 0 | |||
|
213 | 1 files updated, 0 files merged, 1 files removed, 0 files unresolved | |||
|
214 | ||||
|
215 | mv/rm/add/notincommitfiles | |||
|
216 | $ echo 'c' > c.txt | |||
|
217 | $ hg add c.txt | |||
|
218 | $ hg commit -m 'revision to amend to' | |||
|
219 | created new head | |||
|
220 | $ mv a.txt b.txt | |||
|
221 | $ hg rm a.txt | |||
|
222 | $ hg add b.txt | |||
|
223 | $ echo 'bar' > d.txt | |||
|
224 | $ hg add d.txt | |||
|
225 | $ hg status -C | |||
|
226 | A b.txt | |||
|
227 | A d.txt | |||
|
228 | R a.txt | |||
|
229 | $ hg commit --amend -m 'amended' d.txt | |||
|
230 | saved backup bundle to $TESTTMP/repo/.hg/strip-backup/*-amend-backup.hg (glob) | |||
|
231 | $ hg status --change . -C | |||
|
232 | A c.txt | |||
|
233 | A d.txt | |||
|
234 | $ hg status -C | |||
|
235 | A b.txt | |||
|
236 | R a.txt | |||
|
237 | $ hg commit --amend -m 'amended' | |||
|
238 | detected move of 1 files | |||
|
239 | saved backup bundle to $TESTTMP/repo/.hg/strip-backup/*-amend-backup.hg (glob) | |||
|
240 | $ hg status --change . -C | |||
|
241 | A b.txt | |||
|
242 | a.txt | |||
|
243 | A c.txt | |||
|
244 | A d.txt | |||
|
245 | R a.txt | |||
|
246 | $ hg up -r 0 | |||
|
247 | 1 files updated, 0 files merged, 3 files removed, 0 files unresolved | |||
|
248 | ||||
|
249 | mv/rm/add/--no-automv | |||
|
250 | $ echo 'c' > c.txt | |||
|
251 | $ hg add c.txt | |||
|
252 | $ hg commit -m 'revision to amend to' | |||
|
253 | created new head | |||
|
254 | $ mv a.txt b.txt | |||
|
255 | $ hg rm a.txt | |||
|
256 | $ hg add b.txt | |||
|
257 | $ hg status -C | |||
|
258 | A b.txt | |||
|
259 | R a.txt | |||
|
260 | $ hg commit --amend -m 'amended' --no-automv | |||
|
261 | saved backup bundle to $TESTTMP/repo/.hg/strip-backup/*-amend-backup.hg (glob) | |||
|
262 | $ hg status --change . -C | |||
|
263 | A b.txt | |||
|
264 | A c.txt | |||
|
265 | R a.txt | |||
|
266 | $ hg up -r 0 | |||
|
267 | 1 files updated, 0 files merged, 2 files removed, 0 files unresolved | |||
|
268 | ||||
|
269 | mv/rm/commit/add/amend | |||
|
270 | $ echo 'c' > c.txt | |||
|
271 | $ hg add c.txt | |||
|
272 | $ hg commit -m 'revision to amend to' | |||
|
273 | created new head | |||
|
274 | $ mv a.txt b.txt | |||
|
275 | $ hg rm a.txt | |||
|
276 | $ hg status -C | |||
|
277 | R a.txt | |||
|
278 | ? b.txt | |||
|
279 | $ hg commit -m "removed a" | |||
|
280 | $ hg add b.txt | |||
|
281 | $ hg commit --amend -m 'amended' | |||
|
282 | saved backup bundle to $TESTTMP/repo/.hg/strip-backup/*-amend-backup.hg (glob) | |||
|
283 | $ hg status --change . -C | |||
|
284 | A b.txt | |||
|
285 | R a.txt |
General Comments 0
You need to be logged in to leave comments.
Login now