I need to merge the all new changesets of a mercurial repository (lets call it A) into a subdirectory of another mercurial repository (lets call it B) on a regular basis. This means, just copying all files is not an option, as the files in B may also be changed and a proper merge must be done.
The only thing I've found to far is http://hgtip.com/tips/advanced/2009-11-17-combining-repositories/, which is about combining repositories, and not really merging over and over again including changesets.
Any ideas? Thanks in advance.
This sounds like a case where you want to make use of sub-repositories: Including repository A as a sub-repository into the parent repository B.
Let's assume, that everything of A is found in the path B/A.
That way, you would have locally your repository B and inside it another repository. You can then go to repository A, pull from the other repository A' and do the merge however you see fit. Then go back to parent level, to repository B. Update the tracked status of A and that's it. If you want to make any local changes which affect both, A and B, use the recursive hg commit --subrepos. See https://www.mercurial-scm.org/wiki/Subrepository for a more verbose description.
Mind however, that sub-repositories are a feature of last resort; that means it has some rough edges. One of them is that it's virtually impossible to undo the entanglement of the two repositories.
Maybe similar features like Guest Repositories, HG Nested or Forest Extensions are better suited for your actual use case.
Related
This question is not only technical. I want to get into the concept itself, too.
There is a foreign project on BitBucket (e.g. ObjectListView). And I need to work on two problems at the same time. In git I would just create to branches in my local repository after clonening.
But how would I does this with Mercurial?
When I create branches there I am not able to push my local commits back to the remote repository because of the missing '--allow-new-branch' option.
So it doesn't want me to branch.
In my current understanding I would just create a clone for each new feauter (branch). So this means I have to create two forks on BitBucket for one project when I want to work on two different problems.
How would you solve this?
There is some missing information here, so I'm not sure I know what your problem is. I'll try to take some educated guesses and cover a number of possibilities. Feel free to ask back if I failed to address your problem adequately.
First, you can definitely just create new branches if you wish to do that. You'll need to use hg push -f or hg push --new-branch (if you used a named rather than an anonymous branch) to make the remote server accept them (that's to prevent you from pushing new branches by accident). You will, of course, need write access to the repository (or fork the repository and work on that fork).
Second, if you just want to push the current revision/branch (and any associated revisions of a feature branch) and not sync the entire repository, then hg push -r . will do that (here, . denotes the current revision, you can also specify others). If you use that frequently, you may want to create an alias, e.g. submit = push -r ..
Third, if you actually need separate workspaces, it's probably more convenient to use hg share instead of cloning the repository. (Note that you'll first have to enable the share "extension" for that; the word "extension" is in quotes because it's actually a part of core Mercurial and not really an extension in the traditional sense.) hg share creates a separate directory that is still linked to the same repository, but has a separate checkout with separate files.
It is also important to understand that branches in Git and Mercurial are completely different things. Branches in Git, aside from naming specific commits, exist to keep revisions alive (so they don't get garbage-collected). In Mercurial, nothing ever gets garbage-collected, so you don't need Git-like branches for that purpose; instead, Mercurial has anonymous branches (which are sort of like detached HEADs in Git -- sort of) and named branches (which are used to label sets of revisions with a permanent name). Bookmarks can be used to put temporary labels on either type of branch (or specific revisions). Bookmarks + anonymous branches can be made to feel fairly Git-like if you desire that.
So, if you want a Git-like approach, you'd just create anonymous branches (and optionally put a bookmark on them for ease of reference, though having them as branch heads in two directories created with hg share can be the better choice if you wish to work on both concurrently without having to switch. You'd then use hg push -r . to push that specific branch to the remote repository (you may also need -f if you're creating a new head).
However, if it is not your repository, you may want to check with the owner what structure they prefer; for example, plenty of Mercurial users prefer named branches in order to be able to tell later which revisions belong together (sort of like a tag that spans multiple revisions).
I have two repositories with tho different mercurual named branches, say V1 and V2. The branches are divergent since about one-two years. I'd like to graft some changesets from one repo into the other, without pulling the changes.
I don't want to pull the changes for multiple reasons.
I don't want to conflict developers with history of multiple branches, because there will be enough local branches to care about.
I want to have single branch central repos and developers could accidently push the second branch. The central branches would interact with SVN and should have only one branch per repo. I know I could use central hooks, to prevent such a push, but I don't want questions like, can't push, or how can I do that.
The size of the repo would grow to multiple gigabytes (before pull about 700MB). As I understand, it's because of deficites of current mercurial storage format.
I know, the transplant extension can do the work. I tried it, but I can't force other developers to handle rejects instead of simply use a merge tool. Is there an other way?
In fact there are more then two repos with each a branch, but for the example simplicity two should be enough.
You might be able to do the work in an intermediate repo:
Pull in the changes
Do whatever grafting/rebasing/transplanting you need
Strip out the things you pulled in step 1. or if that doesn't work:
Pull only the changes from the branch you want into the actual repo
You'd end up with a repository that includes your desired change sets, but not all the history from the unwanted branch.
Follow-up to #DanMan
Pull needed branch into intermediate repo
Strip unwanted changesets in clone
hg pull CLONE in real target
Write a tool, a hg-extension or extend the graft command so it can graft from a second repository, similar to the transplant extension.
Yes, the implementation is not so easy as adding the second-repo-functionality in the transplant command. The transplant extension simply uses a patch from an other repo instead of one from own repo. But I think also for graft there is no technical reason, not to do that.
If I understand right, grafting of a single file change is not more than calling the merge tool with the files:
(base) the parent of the to-graft changeset
(my changes) the target revision, on which to graft
(theirs) the to-graft refision
So in order to graft a file change from an other repo, the whole file from other repo is needed before the to-graft changeset was applied (base) and after it was applied (theirs). Technically it should be no problem.
Additionally the implementation
need to determine, which files are affected by the changeset to graft
need to handle deletions correctly
need to handle file renamings (not sure, how complicated it is)
All that should be possible, I see no real technical problems.
Is this possible?
To give a simplified explanation of what I want to do:
I have a repository "A" with a subrepository "B". I have two copies of the pair.
In one copy (let's call it the small copy), "A" has changesets A1-A5, and "B" has changesets B1-B20.
In the other (big) copy, "A" has changesets A1-A10, and "B" has changesets B1-B30.
What I want to do is have take all the files from the big repo and commit them to the small one as changesets A6 and B21. Then I will push that to the server. (The big repo does not exist on the server, so this should not create any conflicts.).
Tools in this area do seem to exist -- see here, for example. The problem is I don't know whether any of the suggested methods play nice with subrepositories.
It sounds like you want to use something like the collapse extension.
Alternately, next time you could use mercurial queues so that your A6-A10 are commits on a patch in a patch repo, which you can then qfinish and push as A6. The suprepo existing shouldn't change either of those suggestions in any fundamental way.
What is a good workflow for using mercurial with two long-running branches that are slightly divergent (i.e. I never intend to entirely merge them back
together)?
In my case, this is CMS software that has been customized differently for two
different web sites. I started with projectA, and once that was working cloned it to projectB and make further tweaks to both A and B to customize them. Now I want to develop some features that show up in both A and B, without merging the site-specific customizations. How?
hg push will push everything, so that won't work
Transplant appears to give me different changeset hashes, which worries me
I feel like maybe the repositories should be set up differently, but I'm not
sure how.
As Thilo comments, the common part would be best developed (and published in A and B) as a third repo declared as a SubRepo.
That way, you respect the first two repos which are independent (one evolution on A doesn't always mean an evolution on B), and you can develop the common part in subrepo C.
A solution for Mercurial might be if you can put the different areas in files that can be in .hgignore, but then they won't be versioned, so that may not be so good.
Another way is to just use 1 repo, and set a global flag, and use template A or B depending on the flag, and / or include different code source file depending on the flag. If the difference is small, then can use if-then-else inside the same file.
You can use hg push to push the changes back together, but you don't necessarily have to merge all the changesets into the trunk. Just take the ones you want.
As stated above, a subrepo is probably the best option. Another alternative would be to have a third branch with the common work, and merge from that branch to projectA and projectB (but never back to the common branch).
This alternative is more likely to have accidents (merging the wrong way) but you might find that it is easier to set up and get working quickly.
...so I've gotten used to the simple stuff with Mercurial (add, commit, diff) and found out about the .hgignore file (yay!) and have gotten the hang of creating and switching between branches (branch, update -C).
I have two major questions though:
If I'm in branch "Branch1" and I want to pull in some but not all of the changes from branch "Branch2", how would I do that? Particularly if all the changes are in one subdirectory. (I guess I could just clone the whole repository, then use a directory-merge tool like Beyond Compare to pick&choose my edits. Seems like there ought to be a way to just isolate the changes in one file or one directory, though.)
Switching between branches with update -C seems so easy, I'm wondering why I would bother using clone. I can only think of a few reasons (see below) -- are there some other reasons I'm missing?
a. if I need to act on two versions/branches at once (e.g. do a performance-metric diff)
b. for a backup (clone the repository to a network drive in a physically different location)
c. to do the pick&choose merge like I've mentioned above.
I use clone for:
Short-lived local branches
Cloning to different development machines and servers
The former use is pretty rare for me - mainly when I'm trying an idea I might want to totally abandon. If I want to merge, I'll want to merge ALL the changes. This sort of branching is mainly for tracking different developers' branches so they don't disturb each other. Just to clarify this last point:
I keep working on my changes and pull my fellow devs changes and they pull mine.
When it's convenient for me I'll merge ALL of the changes from one (or all) of these branches into mine.
For feature branches, or longer lived branches, I use named branches which are more comfortably shared between repositories without merging. It also "feels" better when you want to selectively merge.
Basically I look at it this way:
Named branches are for developing different branches or versions of the app
Clones are for managing different contributions to the same version of the app.
That's my take, though really it's a matter of policy.
For question 1, you need to be a little clearer about what you mean by "changes". Which of these do you mean:
"I want to pull some, but not all, of the changesets in a different branch into this one."
"I want to pull the latest version of some, but not all, of the files in a different branch into this one."
If you mean item 1, you should look into the Transplant extension, specifically the idea of cherrypicking a couple of changesets.
If you mean item 2, you would do the following:
Update to the branch you want to pull the changes into.
Use hg revert -r <branch you want to merge> --include <files to update> to change the contents of those files to the way they are on the other branch.
Use hg commit to commit those changes to the branch as a new changeset.
As for question 2, I never use repository clones for branching myself, so I don't know. I use named branches or anonymous branches (sometimes with bookmarks).
I have another option for you to look into: mercurial queues.
The idea is, to have a stack of patches (no commits, "real" patches) ontop of your current working directory. Then, you can add or remove the applied patches, add one, remove it, add another other one, etc. One single patch or a subset of them ends up to be a new "feature" as you probably want to do with branches. After that, you can apply the patch as usual (since it is a change). Branches are probably more useful if you work with somebody else... ?