Show More
@@ -1427,14 +1427,33 b' def copy(ui, repo, pats, opts, rename=Fa' | |||||
1427 | uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True) |
|
1427 | uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True) | |
1428 |
|
1428 | |||
1429 | if forget: |
|
1429 | if forget: | |
1430 | match = scmutil.match(wctx, pats, opts) |
|
1430 | rev = opts[b'at_rev'] | |
1431 |
|
1431 | if rev: | ||
1432 | current_copies = wctx.p1copies() |
|
1432 | ctx = scmutil.revsingle(repo, rev) | |
1433 | current_copies.update(wctx.p2copies()) |
|
1433 | else: | |
1434 |
|
1434 | ctx = repo[None] | ||
1435 | for f in wctx.walk(match): |
|
1435 | if ctx.rev() is None: | |
|
1436 | new_ctx = ctx | |||
|
1437 | else: | |||
|
1438 | if len(ctx.parents()) > 1: | |||
|
1439 | raise error.Abort(_(b'cannot unmark copy in merge commit')) | |||
|
1440 | # avoid cycle context -> subrepo -> cmdutil | |||
|
1441 | from . import context | |||
|
1442 | ||||
|
1443 | rewriteutil.precheck(repo, [ctx.rev()], b'uncopy') | |||
|
1444 | new_ctx = context.overlayworkingctx(repo) | |||
|
1445 | new_ctx.setbase(ctx.p1()) | |||
|
1446 | mergemod.graft(repo, ctx, wctx=new_ctx) | |||
|
1447 | ||||
|
1448 | match = scmutil.match(ctx, pats, opts) | |||
|
1449 | ||||
|
1450 | current_copies = ctx.p1copies() | |||
|
1451 | current_copies.update(ctx.p2copies()) | |||
|
1452 | ||||
|
1453 | uipathfn = scmutil.getuipathfn(repo) | |||
|
1454 | for f in ctx.walk(match): | |||
1436 | if f in current_copies: |
|
1455 | if f in current_copies: | |
1437 | wctx[f].markcopied(None) |
|
1456 | new_ctx[f].markcopied(None) | |
1438 | elif match.exact(f): |
|
1457 | elif match.exact(f): | |
1439 | ui.warn( |
|
1458 | ui.warn( | |
1440 | _( |
|
1459 | _( | |
@@ -1442,8 +1461,25 b' def copy(ui, repo, pats, opts, rename=Fa' | |||||
1442 | ) |
|
1461 | ) | |
1443 | % uipathfn(f) |
|
1462 | % uipathfn(f) | |
1444 | ) |
|
1463 | ) | |
|
1464 | ||||
|
1465 | if ctx.rev() is not None: | |||
|
1466 | with repo.lock(): | |||
|
1467 | mem_ctx = new_ctx.tomemctx_for_amend(ctx) | |||
|
1468 | new_node = mem_ctx.commit() | |||
|
1469 | ||||
|
1470 | if repo.dirstate.p1() == ctx.node(): | |||
|
1471 | with repo.dirstate.parentchange(): | |||
|
1472 | scmutil.movedirstate(repo, repo[new_node]) | |||
|
1473 | replacements = {ctx.node(): [new_node]} | |||
|
1474 | scmutil.cleanupnodes( | |||
|
1475 | repo, replacements, b'uncopy', fixphase=True | |||
|
1476 | ) | |||
|
1477 | ||||
1445 | return |
|
1478 | return | |
1446 |
|
1479 | |||
|
1480 | if opts.get(b'at_rev'): | |||
|
1481 | raise error.Abort(_("--at-rev is only supported with --forget")) | |||
|
1482 | ||||
1447 | def walkpat(pat): |
|
1483 | def walkpat(pat): | |
1448 | srcs = [] |
|
1484 | srcs = [] | |
1449 | m = scmutil.match(ctx, [pat], opts, globbed=True) |
|
1485 | m = scmutil.match(ctx, [pat], opts, globbed=True) |
@@ -2312,6 +2312,13 b' def continuecmd(ui, repo, **opts):' | |||||
2312 | (b'', b'forget', None, _(b'unmark a file as copied')), |
|
2312 | (b'', b'forget', None, _(b'unmark a file as copied')), | |
2313 | (b'A', b'after', None, _(b'record a copy that has already occurred')), |
|
2313 | (b'A', b'after', None, _(b'record a copy that has already occurred')), | |
2314 | ( |
|
2314 | ( | |
|
2315 | b'', | |||
|
2316 | b'at-rev', | |||
|
2317 | b'', | |||
|
2318 | _(b'unmark copies in the given revision (EXPERIMENTAL)'), | |||
|
2319 | _(b'REV'), | |||
|
2320 | ), | |||
|
2321 | ( | |||
2315 | b'f', |
|
2322 | b'f', | |
2316 | b'force', |
|
2323 | b'force', | |
2317 | None, |
|
2324 | None, |
@@ -2487,6 +2487,17 b' class overlayworkingctx(committablectx):' | |||||
2487 | editor=editor, |
|
2487 | editor=editor, | |
2488 | ) |
|
2488 | ) | |
2489 |
|
2489 | |||
|
2490 | def tomemctx_for_amend(self, precursor): | |||
|
2491 | extra = precursor.extra().copy() | |||
|
2492 | extra[b'amend_source'] = precursor.hex() | |||
|
2493 | return self.tomemctx( | |||
|
2494 | text=precursor.description(), | |||
|
2495 | branch=precursor.branch(), | |||
|
2496 | extra=extra, | |||
|
2497 | date=precursor.date(), | |||
|
2498 | user=precursor.user(), | |||
|
2499 | ) | |||
|
2500 | ||||
2490 | def isdirty(self, path): |
|
2501 | def isdirty(self, path): | |
2491 | return path in self._cache |
|
2502 | return path in self._cache | |
2492 |
|
2503 |
@@ -17,6 +17,9 b'' | |||||
17 |
|
17 | |||
18 | == New Experimental Features == |
|
18 | == New Experimental Features == | |
19 |
|
19 | |||
|
20 | * Use `hg copy --forget --at-rev REV` to unmark already committed | |||
|
21 | copies. | |||
|
22 | ||||
20 |
|
23 | |||
21 | == Bug Fixes == |
|
24 | == Bug Fixes == | |
22 |
|
25 |
@@ -257,7 +257,7 b' Show all commands + options' | |||||
257 | commit: addremove, close-branch, amend, secret, edit, force-close-branch, interactive, include, exclude, message, logfile, date, user, subrepos |
|
257 | commit: addremove, close-branch, amend, secret, edit, force-close-branch, interactive, include, exclude, message, logfile, date, user, subrepos | |
258 | config: untrusted, edit, local, global, template |
|
258 | config: untrusted, edit, local, global, template | |
259 | continue: dry-run |
|
259 | continue: dry-run | |
260 | copy: forget, after, force, include, exclude, dry-run |
|
260 | copy: forget, after, at-rev, force, include, exclude, dry-run | |
261 | debugancestor: |
|
261 | debugancestor: | |
262 | debugapplystreamclonebundle: |
|
262 | debugapplystreamclonebundle: | |
263 | debugbuilddag: mergeable-file, overwritten-file, new-file |
|
263 | debugbuilddag: mergeable-file, overwritten-file, new-file |
@@ -319,5 +319,56 b' Test unmarking copy of a directory' | |||||
319 | A dir2/bar |
|
319 | A dir2/bar | |
320 | A dir2/foo |
|
320 | A dir2/foo | |
321 | ? dir2/untracked |
|
321 | ? dir2/untracked | |
|
322 | # Clean up for next test | |||
|
323 | $ hg forget dir2 | |||
|
324 | removing dir2/bar | |||
|
325 | removing dir2/foo | |||
|
326 | $ rm -r dir2 | |||
|
327 | ||||
|
328 | Test uncopy on committed copies | |||
|
329 | ||||
|
330 | # Commit some copies | |||
|
331 | $ hg cp bar baz | |||
|
332 | $ hg cp bar qux | |||
|
333 | $ hg ci -m copies | |||
|
334 | $ hg st -C --change . | |||
|
335 | A baz | |||
|
336 | bar | |||
|
337 | A qux | |||
|
338 | bar | |||
|
339 | $ base=$(hg log -r '.^' -T '{rev}') | |||
|
340 | $ hg log -G -T '{rev}:{node|short} {desc}\n' -r $base: | |||
|
341 | @ 5:a612dc2edfda copies | |||
|
342 | | | |||
|
343 | o 4:4800b1f1f38e add dir/ | |||
|
344 | | | |||
|
345 | ~ | |||
|
346 | # Add a dirty change on top to show that it's unaffected | |||
|
347 | $ echo dirty >> baz | |||
|
348 | $ hg st | |||
|
349 | M baz | |||
|
350 | $ cat baz | |||
|
351 | bleah | |||
|
352 | dirty | |||
|
353 | $ hg copy --forget --at-rev . baz | |||
|
354 | saved backup bundle to $TESTTMP/part2/.hg/strip-backup/a612dc2edfda-e36b4448-uncopy.hg | |||
|
355 | # The unwanted copy is no longer recorded, but the unrelated one is | |||
|
356 | $ hg st -C --change . | |||
|
357 | A baz | |||
|
358 | A qux | |||
|
359 | bar | |||
|
360 | # The old commit is gone and we have updated to the new commit | |||
|
361 | $ hg log -G -T '{rev}:{node|short} {desc}\n' -r $base: | |||
|
362 | @ 5:c45090e5effe copies | |||
|
363 | | | |||
|
364 | o 4:4800b1f1f38e add dir/ | |||
|
365 | | | |||
|
366 | ~ | |||
|
367 | # Working copy still has the uncommitted change | |||
|
368 | $ hg st | |||
|
369 | M baz | |||
|
370 | $ cat baz | |||
|
371 | bleah | |||
|
372 | dirty | |||
322 |
|
373 | |||
323 | $ cd .. |
|
374 | $ cd .. |
@@ -120,4 +120,10 b' Commit issue 1476 with a rename on the o' | |||||
120 | $ hg log -r tip -C -v | grep copies |
|
120 | $ hg log -r tip -C -v | grep copies | |
121 | copies: b2 (b1) |
|
121 | copies: b2 (b1) | |
122 |
|
122 | |||
|
123 | Test unmarking copies in merge commit | |||
|
124 | ||||
|
125 | $ hg copy --forget --at-rev . b2 | |||
|
126 | abort: cannot unmark copy in merge commit | |||
|
127 | [255] | |||
|
128 | ||||
123 | $ cd .. |
|
129 | $ cd .. |
General Comments 0
You need to be logged in to leave comments.
Login now