Using a Skeleton in Mercurial for multiple similar projects - mercurial

I have multiple modules, each in their own repository.
Then there's a skeleton, which has some basic code that's common for all clients, with subrepos of some modules that are always included.
What is the best way to use this set-up on a new client?
The problem I'm currently experiencing is:
- if I clone the skeleton and then add something in the skeleton and push it to the server, the skeleton gets updated.
If I have a repository per project for the client in which I clone the skeleton, the same thing happens: the changes in the skeleton are pushed to the skeleton.
Now, I can probably fix this by cloning the skeleton and then immediately creating a new branch for the client in the skeleton, but I prefer if it has its own repository for the delivery to the server, instead of being a branch of the skeleton (which I want to use for skeleton versions, not projects).
What are your suggestions?

If I understand you correctly, the missing bit of information is that you can change the default push path after making a clone. When you run
$ hg clone http://hg.server/repos/skeleton client-a
to get a client-a clone from the skeleton repo, then Mercurial creates client-a/.hg/hgrc with
[paths]
default = http://hg.server/repos/skeleton
So hg push will now send changesets to that repository. You should instead make a new clone on the server:
$ hg clone skeleton client-a
and then make a clone of that on your machine:
$ hg clone http://hg.server/repos/client-a
Changes to the skeleton code will then no longer automatically propagate to the skeleton repo on the server.
An important down-side of this is that all your client repositories will be "compatible" This means that you can do this by accident:
$ cd client-a
$ hg pull http://hg.server/repos/client-b
This works since client-a and client-b share a common ancestor in the skeleton repository. For that reason, I would simply copy the skeleton files and adds them anew to each client repository:
$ unzip skeleton.zip
$ rm skeleton.zip
$ hg add
$ hg commit -m "Initialized repository for client-a"
Since the date and commit message will be different for each client, the repositories will become unrelated and hg push and hg pull will then error out if you try to mix changesets from different clients.

Related

Mercurial diff/patch by example

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. :-)

Mq on a subrepo without write access

I have a dependancy as a subrepository (without write access to) in my project.
I'd like to add a few personal customizations to that subrepository - possibly using mq.
I also would love to be able to just clone the main repo to build it. Currently I have to:
clone the repo - with subrepositories getting cloned automagically
manually clone all the patchqueues for subrepositories
How do I get rid of step 2? Is it even possible without an outside script? (I'm using bitbucket if it makes any difference).
One notion is to make the subrepo not the repo to which you have no write access, but a clone of your own based on their repo.
cd myclones
hg clone http://notmydomain.com/their-repo my-clone-of-their-repo
and in your project's .hg/hgrc you use a [subpaths] section to map their URL to your local clone:
[subpaths]
http://notmydomain.com/their-repo = ../my-clone-of-their-repo
Then you end up with your repo using your local (read-write) clone of their repo to which you otherwise have read-only access. This has a few benefits:
faster -- you're only checking local repositories for all actions
writeable -- you can edit directoy in myproject/their-repo and commit and push (to your local clone)
And when you want to merge in their upstream changes you just go into ../my-clone-of-their-repo and hg pull and hg merge their updates into your customizations.

Embedding a github repository inside a mercurial (kiln) repository - how integrated is it?

Summarised Question:
Are github-hosted sub repositories within a mercurial/kiln repository possible, and if so are they automatically updated/cloned when the parent mercurial repository is operated on by a hg clone or hg commit command?
Detailed Question:
Following on from my question that was answered so excellently here , some of my third party code is in folders I downloaded a while ago from opensource efforts on github. Since at that stage I was not using version control, those folders where just standard folders that now been incorporated as sub repositories in mercurial.
This is obviously not ideal, as for one thing, new versions of the libraries may have bug fixes, or new features I wish to use in the future. I also may need to locally customise some of the libraries.
I can see from reading this link that it possible to have mercurial "know" about those git server urls (and revisions), so I can then have mercurial clone the github hosted libraries direct from their parent repos.
Am I right in saying that when I clone the parent (mercurial) repos, those files will be pulled from github, without having to separately manage this using git?
What is also not clear is, if I were to do this, and it transpired that code might need to be customized from within that github-cloned repository, would I need to use git to manage revisions of the local files, or would mercurial do that by proxy? eg id I were to hg commit -S would mercurial invoke git on my behalf to handle that?
Am I right in saying that when I clone the parent (mercurial) repos, those files will be pulled from github, without having to separately manage this using git?
Yes, clone of a Mercurial repository that contain subrepositories will trigger a clone of the subrepos too. It really happens on update. Mercurial notices the .hgsub file and issues the needed hg clone and git clone commands for you. It uses the information in .hgsubstate to know exactly what revision to checkout.
The subrepositories can be hosted anywhere. For a Git subrepository declared like
foo = [git]https://github.com/user/repo.git
Mercurial will simply issue the corresponding clone command:
git clone https://github.com/user/repo.git foo
It's then your reponsibility to later go into the foo repo and use Git to fetch new commits as necessary. After you fetch/pull new commits, you can make a top-level commit to record the new state of the subrepo in the .hgsubstate file. Use hg summary to see if a subrepo is dirty in this sense.
[...] would I need to use git to manage revisions of the local files, or would mercurial do that by proxy? eg id I were to hg commit -S would mercurial invoke git on my behalf to handle that?
When you edit files and make a top-level hg commit, Mercurial will make sure to commit the subrepo first (if you use hg commit -S or if ui.commitsubrepos=True). If you make a top-level push, then Mercurial will always push the subrepos first so that you always have a consistent set of changes on your server.

Mercurial - determining if a merge is required from remote repo

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.

Mercurial Patch Creation and Usage

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.