Fixing renames in a Mercurial repository after committing
Asked Answered
C

3

9

Many files in our Mercurial repository were moved in a single commit, but these files were not marked as renamed. To make matters worse, some of the files were also modified in the same commit.

How can I backout the changeset and detect renames properly, while keeping the changes and the file moves?

Crashland answered 30/7, 2013 at 11:32 Comment(0)
F
13

There's an alternative to history editing (aka mucking around in MQ) for fixing renames. The manual procedure is outlined here as the logic that the fixrenames extension uses.

The manual process is as follows. For each revision N for which there are renames not marked:

$ hg update n-1
$ hg revert --all --rev n
$ hg addremove -s 70
$ hg commit -m "Fix renames from n"
$ hg merge n

Note that the similarity flag sometimes requires fiddling. The reason is that renames almost never are pure renames. For example, renaming a class requires a change in the file as well as a change in the filename. Thus they aren't 100% the same. You'll have to review what addremove does and make sure that the added files are marked as "X (renamed from Y)".

In this fashion you can recover full history without a bunch of manual work. I had to do this today (without using the fixrenames extension) and it took me about 5 minutes to fix.

You can even apply this procedure where there are stacked changesets you need to fix.

The changeset graph would look like this. Consider changesets A, B, C & D. B and D had incorrect renames:

D
|
C
|
B
|
A

First we update to A, do an inplace revert to B, do the addremove and commit as E. Then we merge C into E as F since C didn't have anything wrong with it. You should see something like this:

F D
|\|
| C
| |
E B
|/
A

Now apply the same for D. We update to F, revert from D, addremove and commit to G. Now we just merge to close the extra head. You should see something like this:

H
|\
G |
| |
F D
|\|
| C
| |
E B
|/
A

If you want to convince your self that this worked you can always

hg diff -r D -r H

Depending on your tool, you'll see either no difference or renamed files listed but with no differences between them.

Fermentation answered 19/12, 2013 at 16:46 Comment(1)
The command line says hg merge n but the graph indicates a merge with n+1?Klystron
E
3

Automated version of MrFox's answer

  1. Export changes of "bad" changeset into patch-file (git-format, maybe) or save to bundle or convert it into MQ-patch
  2. Update working dir to the parent of bad changeset
  3. Apply patch|import bundle
  4. Use hg addremove -s NN in modified working dir in order to detect renames (NN must be found by hand, all renames have to be detected in result), check results of guessing with hg status -C, repeat adremove until correct result will not received
  5. Commit new good changeset
Electrotherapy answered 30/7, 2013 at 12:18 Comment(0)
R
0
  1. Make a list of all modifications made to the files.
  2. Update back to a version where the files had not been moved.
  3. Rename the files.
  4. Modify the file internals, where needed.
  5. Commit.
Reversioner answered 30/7, 2013 at 11:36 Comment(2)
Making a list of all modifications, reverting to pre-changes, then manually updating every file seems like the most manual way of doing this. I was hoping for a more automated, fool-proof way.Crashland
Mercurial doesn't know how your changes need to be different. There's no 'replace deleted and added files whose names are similar with renaming those files'. Git would be better here, it looks at content and would probably suggest you change the file names or something, rather than deleting and adding the files.Reversioner

© 2022 - 2024 — McMap. All rights reserved.