Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Recovering history in hg when move not done properly

So somebody on our team moved an entire folder into a subdirectory without using hg's rename feature. The directory structure is like we need it, but the history is now gone prior to the move. It shows it as a new file when the move occurred. Numerous large merges have happened since then, and so it is not really practical to go back in time and do it right.

I have tried hg log --follow and it does not help, since hg does not know about the rename. Is there any way to manually link the files to the old removed versions after the fact, or is there some facility like the way git can infer moves and renames based on hueristics? It would be nice if there was some way to explicitly say, "this file is a continuation of this old deleted file.", even though that would still take some time to fix it all up right.

We have all but given up on ever getting that history back, but it would be really nice to have it.

like image 903
captncraig Avatar asked Oct 18 '11 23:10

captncraig


3 Answers

You need to redo the move correctly by explicitly telling Mercurial what files were moved, then merge the broken changesets. This way you will restore the history path to the original files.

Steps, assuming <x> is the move revision, and <y> is the current head revision.

  1. Update to the revision before the move: hg update <x-1>
  2. Redo the move, but now correctly using hg rename or hg rename --after
  3. Commit
  4. Merge with the original move revision (hg merge <x>), this should have no conflicts but if there are discard all changes.
  5. Commit
  6. Merge with the remaining changesets after the move (if any) (hg merge <y>)
  7. Commit

Here is the basic process shown on the command line:

$ mkdir move-merge-test
$ cd move-merge-test
$ hg init
$ echo "x" > a
$ hg add a
$ hg commit -m "initial revision"

Move incorrectly:

$ mv a b
$ hg remove a
$ hg add b
$ hg status --copies
A b
R a
$ hg commit -m "incorrect move"
$ hg log --follow b
changeset:   1:b22f3e94133b
tag:         tip
user:        Laurens Holst <...>
date:        Wed Oct 19 14:41:37 2011 +0200
summary:     incorrect move

Correct the move:

$ hg update 0
1 files updated, 0 files merged, 1 files removed, 0 files unresolved
$ hg rename a b
$ hg status --copies
A b
  a
R a
$ hg commit -m "correct move"
created new head
$ hg log --follow b
changeset:   2:5deabbcb5480
tag:         tip
parent:      0:b82f89f0c7d9
user:        Laurens Holst <...>
date:        Wed Oct 19 14:46:35 2011 +0200
summary:     correct move

changeset:   0:b82f89f0c7d9
user:        Laurens Holst <...>
date:        Wed Oct 19 14:36:35 2011 +0200
summary:     initial revision

Merge it with the broken move:

$ hg merge 1
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
(branch merge, don't forget to commit)
$ hg commit -m "merge with broken move"
$ hg log --follow b
changeset:   3:ce65fc7b35e4
tag:         tip
parent:      2:5deabbcb5480
parent:      1:b22f3e94133b
user:        Laurens Holst <...>
date:        Wed Oct 19 14:47:13 2011 +0200
summary:     merge broken branch

changeset:   2:5deabbcb5480
parent:      0:b82f89f0c7d9
user:        Laurens Holst <...>
date:        Wed Oct 19 14:46:35 2011 +0200
summary:     correct move

changeset:   1:b22f3e94133b
user:        Laurens Holst <...>
date:        Wed Oct 19 14:41:37 2011 +0200
summary:     incorrect move

changeset:   0:b82f89f0c7d9
user:        Laurens Holst <...>
date:        Wed Oct 19 14:36:35 2011 +0200
summary:     initial revision

As you can see, the history now correctly shows all affected changesets. If the files are moved in several commits, the basic principle stays the same just merge across more than just 1 commit. If you have any commits made after the move, I recommend to merge them in separately (step 6 in the steps above) in order to avoid spurious conflicts.

like image 136
Laurens Holst Avatar answered Nov 01 '22 22:11

Laurens Holst


I had good luck with this kind of thing by deleting the new (the "moved") file, then going back to a revision when the file was still in place, doing the move properly (including commit) and merging the two heads.

like image 27
Ringding Avatar answered Nov 01 '22 23:11

Ringding


There's a --after option to hg rename which lets you tell Mercurial about a rename after the fact, but it has to be done before you commit the rename.

You could try doing hg convert on the repository and specify the --filemap parameter, which will let you rename a files and directories.

https://www.mercurial-scm.org/wiki/ConvertExtension#A--filemap

like image 29
Rob Sobers Avatar answered Nov 01 '22 21:11

Rob Sobers