Search code examples
mercurial

Amending a commit with the effects of hg cp --after


I have a file before.txt, which I want to split into two smaller files. What I should have done was

$ hg cp before.txt part1.txt # Then edit part1.txt
$ hg mv before.txt part2.txt # Then edit part2.txt
$ hg commit

Then, both part1.txt and part2.txt will have before.txt as part of their history, so the diff will show as deleting parts of a larger file, rather than deleting one file and creating a new one with some of its contents.

However, what I actually did was

$ cp before.txt part1.txt # Then edit part1.txt
$ hg mv before.txt part2.txt # Then edit part2.txt
$ hg commit

So before.txt is only present in the history of one of my two files. If I hadn't run hg commit, it seems clear to me that I could solve my problem with

$ hg cp --after before.txt part1.txt

or something similar to that. And I haven't pushed this commit upstream, so I should be able to edit it however I like. But I can't figure out how to do it. When I run that hg cp, I see:

$ hg cp --after before.txt part1.txt
before.txt: No such file or directory
before.txt: No such file or directory
abort: no files to copy

This makes sense: it can't record that edit as part of a new commit, because the source file doesn't exist. I want to record it as part of the previous commit, but I don't know how to do that except by recording it as part of a new commit and then amending it into the previous commit.


Solution

  • Here's one way to fix that situation:

    $ hg shelve       # get any miscellaneous, unrelated changes out of the way
    $ hg up <parent of revision with the mistake in it>
    
    $ hg cp before.txt part1.txt 
    $ hg mv before.txt part2.txt 
    
    $ hg revert -r <revision with the mistake in it> --all
    $ hg commit
    $ hg strip <revision with the mistake in it>
    

    (I didn't actually try all these commands, hopefully no typos!)

    The first step is optional depending on the state of your working directories.

    Now part1.txt and part2.txt should have the correct contents. The use of revert was just to save having to manually re-edit the file changes. But you could also just redo it manually if that seems easier.

    The use of revert to pull into the working folder the effects of another changeset is a trick I use a lot. Its like a manual way of amending which gives you total flexibility. But it only works well when the revision you are reverting your working copy to is closely related to the revision which is the parent of the working copy. Otherwise it will create numerous nuisance changes.