I often work with Mercurial by keeping a local store of my upstream clones, and then just cloning again locally for my actual working environment:
$ cd /clones
$ hg clone ssh://external-repo.example.com/some/repo/path/foo
$ cd ~/Development
$ hg clone /clones/foo
This is particularly useful for me because I often want to make new clones on airplanes, etc., where I have no internet access. However, this doesn't work when the original clone contains subrepos - the presence of the .hgsubstate file means that hg will always go out to the internet instead of grabbing the local cloned revision (even if they are the same). Is there any way to make a local clone copy the files without going out to the internet?
This question has an answer which would probably work, but seems very unfortunate for long-term management (deleting the .hgsubstate file in the clone in /clones/, and then making local clones from that).
You can use a "trivial" subrepository path in your .hgsub file like this:
foo = foo
bar = bar
This is the recommended setup. The advantage of setup a layout is that a clone has the same structure as the repository you clone from. You can thus clone your clones when on a plane.
Alternatively, you can use the [subpaths] setting to re-map the URLs to local paths. This lets you add
[subpaths]
http://server/(.*) = /clones/libs/\1
to your ~/.hgrc file and then you'll see that paths are remapped to /clones/libs when you clone.
You can achieve this by cloning the subrepositories yourself. Supposing that foo has a single subrepo called bar:
$ cd ~/Development
$ hg clone -U /clones/foo
$ hg clone -U /clones/foo/bar foo/bar
$ hg update -R foo
The update does not need to access the internet since the subrepository exists and contains the necessary changeset for the update on the master.
Related
I have read only permission to an hg repo and am trying to develop and test changes to it locally. The problem is that I am in the middle of changing dev machines and am caught in a weird/akward state across the two machines.
On my old machine I made lots of changes to the repo, locslly. I just cloned the repo on my new machine, but obviously that doesn't contain the changes from my old machine. I need a way to createe a patch/diff from my local working copy on my old machine, and then apply them to my local working copy on my new machine. The problem is that I already commited (hg commit -m "Blah") the changes on my old machine to the distributed repo on it.
What set of specific commands can I use to create a patch/diff of my old machine and then apply it to the repo on my new one?
Update
I commited all changes on my old machine and then ran hg serve, exposing http://mymachine.example.com:8000.
On my new machine, where I had made some different changes (locally) than the changes from my old machine, I ran hg pull http://mymachine.example.com:8000 and got:
myuser#mymachine:~/sandbox/eclipse/workspace/myapp$ hg pull http://mymachine.example.com:8000
pulling from http://mymachine.example.com:8000/
searching for changes
adding changesets
adding manifests
adding file changes
added 2 changesets with 16 changes to 10 files (+1 heads)
(run 'hg heads' to see heads, 'hg merge' to merge)
So I run hg merge:
myuser#mymachine:~/sandbox/eclipse/workspace/myapp$ hg merge
abort: uncommitted changes
(use 'hg status' to list changes)
What do I do now?!?
You can use:
$ hg diff > changes.patch
To create a patch file, then:
$ patch -p1 < changes.patch
To apply that patch file on your new machine.
Well, that's actually fantastic, mercurial is a distributed version control system and you do not need to go via any patch file at all: simply pull the changes from your old machine to your new machine:
hg pull URL
where URL can be any network URL or also ssh-login, e.g.
hg pull ssh://mylogin#old.maschine.box or hg pull path/to/old/repository/on/nfs/mount
`
Alternatively you can also use bundle and unbundle. They create bundles which can be imported in the new mercurial easily and keep all meta-information.
hg bundle -r XXX --base YYY > FILENAME
where YYY is a revision you know you have in your new repository. You import it into your new repo with hg unbundle FILENAME. Of course you can bundle several changesets at once by repeating the -r argument or giving a changeset range like -r X:Y.
The least comfortable method is a via diff or export:
hg export -r XXX > FILENAME or equivalent hg diff -c XXX > FILENAME where you need to import the result with patch -p1 < FILENAME or hg import FILENAME.
The easiest way is to do this is to ensure that all work on your old machine is committed. Then use this command on it from the base of your repo:
hg serve
which creates a simple http server on this repo. The monitor should state the name of the http URL it is serving.
On your new machine, just pull from that URL.
Once you've pulled your old changes you can stop the hg serve process with ^C.
The advantages of this method are that it is very quick, and that it works on just about any system. The ssh method is also quick, but it won't work unless your system is configured to use ssh.
Answer to Update
The OPs update is asking an orthogonal question about how to merge changes pulled from a server with local changes. If you haven't already done so, try to digest the information in this merge doc and this one.
Merging is for merging changesets. The error is happening because you have local changes that haven't been committed which mercurial can't merge. So the first thing to do is to commit your local changes, then you will be able to merge.
But before you merge, I strongly recommend that you are merging what you think you are merging. Either ensure there are only 2 heads, or specify which head you are merging with. When merging, you have to be at one of the heads you wish to merge; it's usually better to be at the head with the most changes since the common ancestor because the diffs are simpler.
After you've merged, don't forget to commit the merge. :-)
We want to create several hg repos
1. /var - big one which is supposed to include files of all nested repos
2. subrepos like /var/repo1 /var/repo2
But the problem is that main hg repo in (/var folder) cannot see new or modified files of subrepos in /var/repo1 /var/repo2. Is there any way to configure main repository so that it can see file modifications of subrepos?
You can use the -S flag to recurse into subrepositories, but it doesn't work for all commands. This is by design, nested repositories should be operated separately, eg. commit in the main repo with the -S switch will actually make separate commit for each nested repository but with same message.
hg status -S displays all changes including subrepos.
hg commit -S commits all changes in this and all nested repositories that have changes.
We have two repositories: myapp and myapp-1.1. We merge myapp-1.1 into myapp.
To see if there are changes in 1.1 that need to be merged I do this:
cd c:\myapp (local clone)
hg fetch (fetch from remote myapp repo)
hg in ssh://hg/myapp-1.1 (see what needs to be merged in from remote 1.1 repo)
This works - but is there a better way? Is there a way to do this without requiring the local myapp clone?
Mercurial can't do much with remote repositories except for some variant of pushing to, or pulling from them.
As such, anything you want to ask Mercurial to do has to be done with a local clone.
So no, there is no way to have Mercurial check if two remote repositories needs to be merged.
What's the problem with having local clone, exactly?
If you want to isolate all operations on machine the repo is located, you could do the following:
$ ssh $hg_box
$ cd myapp; hg in /myapp-1.1
This may seem like the obvious response, but since Mercurial is a completely distributed source control system, and each repo is stand alone, is it possible for you to actually go to the box that has myapp and fetch directly from myapp-1.1? I know most dev teams keep some kind of centralized repository, but that doesn't preclude the use of Mercurial directly from the box that you have as your 'central' repository. It's all still local and remote repositories.
This assumes that you want to fully merge myapp and myapp1.1. Otherwise, pretty much by definition of what you're doing, you have to clone myapp to another full repository, then merge it with myapp-1.1.
Assuming neither the remote repo nor the local repo allows multiple heads per branch, this command should tell if the local repo has the head of the remote repo at a given branch:
hg log -r $( hg in -b branch_name -n -l1 -q --template "{node}\n" )
If local repo doesn't have that changeset, but has outgoing changesets at "branch_name", then typically it should be an indicator that merge is needed.
For a while I had just my code under source control, but I decided it would be cool to put things like my stuff in my .vim folder among other things in a repo. (I'm obviously not going to store everything in my repo, just various config files, my src directory, and maybe a few other things as well)
I was able to set up a repo fine, then push it to my server where I can access it from my other computers, but I can't clone it to my other computers. When I try to clone it it fails because the home directory isn't empty. Is there a way to do what I want here?
Since the versioned files between my computers are the same, what I did was:
~$ hg clone ssh://myserver/hg/dotfiles mydotfiles
~$ mv mydotfiles/.hg .
~$ rm -rf mydotfiles
and that's it, now your home folder is under version control, but of course if your dot files are not identical between computers you will have to do something about it.
Since I only want to version some files and not everything under my home folder, I have this simple rule in ~/.hgignore
# This .hgignore is for the dotfiles repository only,
# the rest of my HG repositories use the file
# .hgignore_global as referenced by [ui]'s ignore setting.
syntax:glob
*
This way I don't get an ocean of files when I do hg status and only see those files that I have under version control that have been modified.
But since I want to see unversioned files when working within another hg repository, I have this in my ~/.hgrc file
[ui]
ignore=/home/gajon/.hgignore_global
And ~/.hgignore_global contains some filters for common transient files:
syntax: glob
*.pyc
*~
.*.swp
.svn*
*.svn*
*.fasl
syntax: regexp
^\.pc/
Suppose you have proj1 and proj2. proj1 is a mercurial repo you want to clone to proj2, but proj2 already has files in it.
Try this:
hg clone proj1 proj3
mv proj3/.hg proj2
rmdir proj3
cd proj2
hg update -C -r tip
In the other directories that already exist, you could hg init, hg add what you want, hg commit that, hg pull from the central repo, and deal with the resulting merge.
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.
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.
The following steps can be performed with a standard Mercurial install:
Commit the changes in your local repository. Note the revision number.
Use "hg export -r REV >patch.diff" to create a patch.
Clone the new repository.
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
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.
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
If the layout is the same, you can just copy all the files over (excluding .hg) and then use hg addrem.
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.
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.