14

I have come across a problem that I "think" can only be resolved using patches.

I cloned a project from our main repository, made quite a few changes (updates, deletion of files & directory and additions) to it. These changes are not even committed. The problem is, project from the main repository has been deleted/removed and recreated as a new project (name is same, all the directory structures everything is same as before). I cloned that project again from the main repository and would like to transfer all my uncommitted changes to it.

I am still exploring the hg patch to resolve that. It would be helpful if someone could confirm that creating and adding a patch IS the right approach to this, any resources explaining the process would be of great help.

Martin Geisler
  • 72,968
  • 25
  • 171
  • 229
Abidi
  • 7,846
  • 14
  • 43
  • 65
  • 1
    Why was the repo re-created? Doing this will invalidate all clones, make sure nobody on your team think this is a safe operation to do so this will happen on a regular basis. – Lasse V. Karlsen Dec 28 '10 at 20:19

7 Answers7

26

You're correct — a patch is what you need to transfer the information from one repository to another (unrelated) repository. This will work since the files are the same, as you note.

So, to transfer your uncommitted changes from your old clone, you do

$ hg diff -g > uncommited.patch
$ cd ../new
$ hg import --no-commit ../old/uncomitted.patch

That will restore the information saved in the patch. This includes information about files that are added or renamed in the old clone.

Community
  • 1
  • 1
Martin Geisler
  • 72,968
  • 25
  • 171
  • 229
8

The following steps can be performed with a standard Mercurial install:

  1. Commit the changes in your local repository. Note the revision number.
  2. Use "hg export -r REV >patch.diff" to create a patch.
  3. Clone the new repository.
  4. Use "hg import patch.diff" to apply the patch to the new repository.

Example

C:\>hg init example
C:\>cd example
C:\example>echo >file1
C:\example>hg ci -Am file1
adding file1

C:\example>hg clone . ..\example2
updating to branch default
1 files updated, 0 files merged, 0 files removed, 0 files unresolved

C:\example>rd /s/q .hg
C:\example>hg init
C:\example>hg ci -Am same-but-different
adding file1

At this point example and example2 have identical contents, but the repositories are unrelated to each other due to deleting and reinitializing the .hg folder.

Now make some changes and commit them in one of the repositories, then export them as a patch:

C:\example>echo >>file1
C:\example>echo >file2
C:\example>hg ci -Am changes
adding file2

C:\example>hg export -r 1 >patch.diff

Below shows that the other repository can't pull the changes, because of the reinitialization. It can, however, apply the patch successfully:

C:\example>cd ..\example2
C:\example2>hg pull
pulling from c:\example
searching for changes
abort: repository is unrelated

C:\example2>hg import ..\example\patch.diff
applying ..\example\patch.diff
Community
  • 1
  • 1
Mark Tolonen
  • 166,664
  • 26
  • 169
  • 251
3

I would first make copies of everything so you have a way of backtracking.

Then, in the working copy with the changes, I would first delete the .hg directory, then copy in the .hg directory from the new repo. This basically transfers all of the changed files into the new repo without the need to delete any files and directories.

You will still need to tell the repo about whether to remove any files marked as missing. You will also have to handle renames manually. If this is a small number of operations, it's easier than trying to use the patch method.

Once this is done, commit your changes and push, if necessary.

Binary Phile
  • 2,538
  • 16
  • 16
  • hmm, sounds interesting, I was just wondering why do I have to handle renames manually, is it because new .hg directory has no knowledge of the changes? If that's the case then new .hg will not have any knowledge about any files? Whenever I rename a file, Mercurial status shows ! and ? against old and new files, which is expected. – Abidi Dec 27 '10 at 15:40
  • You should use "hg rename" when renaming files so history is tracked across a rename of a file. – Mark Tolonen Dec 27 '10 at 17:11
  • Because renames have to be done through an explicit command in hg in order to maintain the file history, and we've circumvented that by effectively renaming any changed filenames at the filesystem level. TortoiseHg has a _Guess Renames_ function which can automate this, but if it's just a few files you may as well name them to their old name then use hg's rename function to get back to the new name. – Binary Phile Dec 27 '10 at 18:55
  • 1
    Guess renames from the command line is done as `hg addremove --similarity 90` – Ry4an Brase Dec 27 '10 at 19:24
  • This one worked, replacing .hg directory does the trick. I am yet to try the solution suggested by Mark Tolonen, will get back after experimenting that shortly. Thank you guys. – Abidi Dec 28 '10 at 14:25
  • 1
    I'm sorry, but the `.hg` directory should not be deleted — doing so will delete the "dirstate" too, which is where things like `hg rename a b` and `hg add c` are tracked before they are committed. – Martin Geisler Dec 14 '11 at 10:45
2

seems like what you want is patch queues. In that you have uncommitted changes, and you want to pull from the new repo before committing them....

$ hg qinit -c # initialize mq for your repo containing the uncommitted changes 
$ hg qnew name_of_patch # create patch that contains your uncommitted changes
$ hg qpop # resets your working dir back to the parent changeset

no worries though, your changes are safe and sound in .hg/patches/name_of_patch to see for yourself.....

$ cat .hg/patches/name_of_patch

now pull in the new repo

$ hg pull -u http://location.of.new/repo # pull in changes from new repo update working dir

$ hg qpush # apply your uncommitted changes to new repo

If you are lucky you will have no merge conflicts and you can go ahead and commit the patch by....

$ hg qfinish -a # change all applied patches to changeset

And then if you want....

$ hg push http://location.of.new/repo

If the repos are unrelated, just init a patch repo on your new repo. and manually copy the patch in and add it to .hg/patches/series file.

assuming patch was created. clone new repo

$ hg clone http://location.of.new/repo ./new_repo

init patch repo

$ cd ./new_repo && hg qinit -c

copy patch

$ cp ../old_repo/.hg/patches/name_of_patch .hg/patches/

edit series file using an editor of some sort

$ your_favorite_editor .hg/patches/series

name_of_patch   # <---put this in the series file

apply your patch to new repo

$ hg qpush

if no merge conflicts and you are convinced it works

$ hg qfinish -a
Tom Willis
  • 5,250
  • 23
  • 34
0

If the layout is the same, you can just copy all the files over (excluding .hg) and then use hg addrem.

Ringding
  • 2,856
  • 17
  • 10
  • I think its a manual and incomplete solution, first I have make sure I copy all the files and then remove files and directories from the new one. – Abidi Dec 27 '10 at 12:55
0

Try to look into the MQ plugin, it does exactly this if I recall. I've never had a use for that though, so I can't say.

atx
  • 4,831
  • 3
  • 26
  • 40
0

If the old repository was simply moved/cloned to a new URL then you could simply change the remote repository you talk to the new one.

If, however, it was recreated from the ground up (even with the same structure) then I don't believe Mercurial has any built-in functionality to help you here. Mercurial patches reference specific changesets which won't exist in your new repository.

You could use a merge tool to perform the diff and bring across any changes you made.

Edited To answer the question in the comment: When you clone the repository you are taking a complete snapshot of the entire change history - along with the associated change-set IDs, etc.

Mercurial tracks changes by change-sets to the repository, rather than at the file level like Subversion.

If you clone, then you can easily push/merge into another repository that was also cloned from the same source.

If you recreated the repository then the change IDs won't match, and can't be merged in Hg. The only option in this scenario would be to use a Merge tool which will let you see mismatches in files/folder structure.

Also: Worth pointing out http://hginit.com/ because it explains (indirectly) some of this.

  • Hey Will, The URL is exactly the same but project was deleted and then recreated. What is it that distinguishes between moved/cloned and recreated from ground up? – Abidi Dec 27 '10 at 15:44
  • Hey, Added my response to the answer (bit too long to fit in a comment). –  Dec 27 '10 at 16:01