Merging 3 related repos together using hg - merge

I'm trying to merge 3 repos into one using mercurial. Repo A is the one I'd like to merge Repo B and C into. These are AS3 projects and A relies on files from B and C.
I tried following the steps from this post:
Merging two different repositories
However, I think this depends on the fact that the repos don't share anything. In my case since the project have the same file structure, it seems like it just overwrites the previous one (example: both have /images folder).
Any suggetions?

Let's make sure we fully understand our goal here:
We want to keep all the files from all three projects. If the same file name appears in multiple repositories, we want to do what?
Keep the version from A (or B, or C): We can perform the merge using --tool internal:local or internal:other as appropriate. Local keeps the version we currently have, other keeps the version we're merging in.
Merge them together using Mercurial's standard three-way merging logic (which won't work very well since we don't have common ancestry): --tool internal:merge or just don't specify the option at all. This will likely produce ugly merge conflicts which we will have to resolve.
This can't (shouldn't) happen in the first place: --tool internal:fail will throw an error in this case and won't try to merge the files.
So, here's the modified procedure:
$ hg init combined
$ cd combined
$ hg pull ../A
$ hg update
$ hg pull ../B --force
$ hg merge --tool something # see above
$ # Manually fix up any files that throw merge conflicts
$ hg resolve --all -m # Mark all files as resolved, only if there were conflicts
$ hg commit -m "Merge A and B"
$ hg pull ../C --force
$ hg merge --tool something # see above
$ # Fix conflicts
$ hg resolve --all -m # Only if there were conflicts
$ hg commit -m "Merge A+B and C"

Related

hg: commit a changeset as a merge

Suppose I have two branches A and B. These two branches have been merged together outside of hg (manually I suppose). The merge itself is correct and the files exactly reflect the merge between branch A and B.
Is there a way to commit those files as a merge? I mean to make them appear in hg as if they were merged using hg and make the new commit have both branches as a parent?
One option is to do the merge, but tell hg that you really want that merge to fail. Then reset the files to the version you want and manually mark them as resolved.
hg -y merge --tool=internal:fail otherBranch
hg revert --all --rev thisBranch
hg resolve -a -m
Once you commit and you should be on your way.
See more details here

Move a specific branch to new repository

I have a mercurial repository in which I had created a branch 7-8 months back. And now this branch is the one in which I do most of the development and I don't have anything fruitful in default branch and other branches that I have.
I want to create a new repository that represent only this branch. i.e. I want to move this branch to a new repository with history.
I tried to use HG convert tool with following syntax:
hg convert --filemap ~filemap.txt --branchmap branchmap.txt --source-type hg --dest-type hg "E:\MyStuff\Dev\MyOldRepo" "E:\NewRepo"
File map I have defined all my file that I want to include. In branchmap file i had defined
MyOldNamedBranch default
Convert tool do rename MyOldNamedBranch to default but it also brings the changesets from other branch that I don't need.
I also tried to set the following in setting file but no results:
[convert]
hg.usebranchnames=0
hg.startrev=5262
Please suggest how I can move a branch to new repository with history and leaving other branches behind.
I have set the start revision number in command only and it worked.
hg convert --config convert.hg.startrev=5262 --branchmap branchmap.txt "E:\MyStuff\Dev\MyOldRepo" "E:\NewRepo"
And it worked like a charm.
Try this:
Clone only the branch you need:
hg clone E:\MyStuff\Dev\MyOldRepo -b MyOldNamedBranch .\NewRepo
Then inside the NewRepo, convert all the changesets to the draft phase:
hg phase -r 0 -d -f
Then update to the patent of MyOldBranch (I assume, that the parent is in the default branch)
hg update -r "parents(min(branch(MyOldBranch)))"
Then rebase MyOldBranch on the exactly the same changeset.
hg rebase -s "min(branch(MyOldBranch))" -d .
Do exactly the same with the rest of the branches.
To be honest I'm not sure if this is the best method but it worked for me.

Subclipse tree conflicts

I'm trying to merge a trunk to a branch, but ending up with a lot of tree conflicts, leaving no files merged. To resolve the conflicts, I'm just opening the file and copying contents by hand which just defeats the purpose of a merge operation.
What is the right way to merge a trunk to a branch (in subclipse) ?
How was that branch created? Was it created by using svn cp, or were those files manually copied into that branch?
Let's look at the following:
$ svn mkdir trunk
$ vi trunk/foo trunk/bar
$ svn add trunk/foo trunk/bar
$ svn commit -m"Added foo and bar to trunk"
You now have two files on trunk.
$ svn mkdir --parents branches/1.0
$ cp trunk/* branches/1.0/
$ svn add branches/1.0/*
$ svn commit -m"Duplicated files onto branch"
What I have done is create two entirely different foo and bar on the 1.0 branch. These two files, according to Subversion have absolutely nothing to do with each other. If you make a change on the 1.0 branch, and attempt to merge these changes back to trunk, you will get a lot of conflicts with messages like "local add, incoming add".
What the above user should have done is this:
$ svn cp --parents trunk branches/1.0
$ svn commit -m"Branched trunk and not merely duplicate files"
Now, there's a relationship that Subversion understands between the files on trunk and on the 1.0 branch. Merging will go smoothly.
Here's another way to break a merge:
$ svn delete trunk/foo
$ svn commit -"deleted foo"
$ svn cat -rPREV trunk/foo#PREV > foo
$ svn add foo
$ svn commit -m"Added foo back in. Shouldn't have deleted it.
According to Subversion, there are now two completely different files named foo in the trunk. There's the file you deleted, and there's the file you added. These two files have nothing to do with each other. Imagine if I branched (the correct way using svn cp) to the 1.0 branch, then did my delete and copy of foo. The merge of the 1.0 branch back to trunk will have a conflict because the foo on the branch has no relationship with the foo on trunk.
To restore a file, you need to copy the revision that was deleted (or use svn merge -c).
$ svn cp -rPREV http://svn.repo/svn/trunk/foo#PREV .
$ svn commit -m"Actually old foo now has been restored! Merges will work"
If you branched incorrectly, or deleted and re-added files back to trunk, you will get conflicts. You can try using the --ignore-ancestory parameter, and you can use --dry-run to test your merge before running the actual merge.
If you manually merge, you can use svn merge --record-only to just record the fact you did a merge without actually doing one. This might help the next time you do a merge since you're at least recoding what you've manually done.

In hg, how can I drop the branch name when rebasing and/or transplanting from another repo?

Basically, what I want to try is pulling hg revisions from a branch of an experimental repo into a clone of mainline. But I want to discard the branch name so I can push directly into the server-side mainline repo. It's probably best to give a simple example:
hg init hg_mainline
pushd hg_mainline
touch foo
hg add foo
hg commit -m 'foo'
popd
hg clone hg_mainline hg_experimental
pushd hg_experimental
hg branch bar_branch
touch bar
hg add bar
hg commit -m 'bar'
popd
pushd hg_mainline
hg pull ../hg_experimental
hg log
As you can see, the mainline now includes a rev with "branch: bar_branch." I don't want this revision to have a branch (i.e. it should be default).
It is okay if this requires rewriting history with rebase, transplant, or another tool. I have tried both of these, but couldn't get it working. The most recent revision hash may end up different between the two repos.
So I want the topmost revision of hg_mainline to look like:
changeset: 1:xxxxxxxxxxxx
tag: tip
user: ...
date: ...
summary: ...
with no named branch.
Again, it's okay if the hash isn't preserved from hg_experimental.
I am currently using hg 1.6.2+55-18e1e7520b67 from an Ubuntu PPA.
EDIT:
I also used 1.3.1. I tested the below on both, and the results here are the same.
I got it working with transplant, but only with the grep -v kludge.
hg transplant -s ../hg_experimental 1 --filter "grep -v '^branch:'"
With:
hg transplant -s ../hg_experimental 1
hg export didn't work either, with or without an appropriate grep.
The changeset patch looks like:
# HG changeset patch
# User Matthew Flaschen <EMAIL>
# Date 1282942390 14400
# Branch bar_branch
# Node ID b8e36efea72642f0a0194301489d5c48f619a921
# Parent 85d9b9773d4ec09676dfcc4af89c142c46279444
bar
I exported from experimental with:
hg export 1 -o '/tmp/%b_%H_%R'
and tried to import to mainline with:
hg import /tmp/hg_experimental_b8e36efea72642f0a0194301489d5c48f619a921_1
It fails with:
abort: no diffs found
EDIT 2:
As noted, the export method failed only because the files were empty. It works correctly with --git or with non-empty files.
The simplest solution is use hg export from the experimental repo, and hg import into the main repo. By default, hg import won't apply any branch information in the patch. The downside is that they'll show up as different changesets in the two repos -- hg incoming in the experimental repo will show the changes you just exported/imported -- so after you do this, you may be better off deleting and recreating the experimental repo if you plan on doing any more experimentation.
EDIT: From the hg_mainline repository:
hg export -r 1 -R ../hg_experimental | hg import -
EDIT2: From hg help diffs:
Mercurial's default format for showing changes between two versions of a file
is compatible with the unified format of GNU diff, which can be used by GNU
patch and many other standard tools.
While this standard format is often enough, it does not encode the following information: (snip)
creation or deletion of empty files
The test files are empty in your test script, so you need to either enter something into them, or use the --git option to hg export.
The transplant extension already scraps the branch name:
cd hg_mainline
hg transplant -s ../hg_experimental 1
should do it for you. If you're finding that's not the case you can always use the --filter modify the changesets (perhaps just using grep -v) on the way in.
I will note that if you can come up with a work flow that avoids transplant and retains hashes you're better off. Avoiding named branches entirely makes this easier -- anonymous branches perhaps with bookmarks work as well or better.

Mercurial: Merging one file between branches in one repo

When I have two branches in Hg repo, how to merge only one file with another branch, without having all other files from changeset merged?
Is it possible to merge only certain files, instead of whole changeset?
WARNING: a "dummy merge", as is recommended by #Martin_Geisler, can really mess you up, if later you want to do a true merge of the two branches. The dummy merge will be recorded, and say that you merge into the branch you did the dummy merge to -- you will not see the changes. Or if you merge into the other branch, the changes on that other branch will be undone.
If all you want is to copy an entire file from one branch to another, you can simply do:
hg update -r to-branch
hg revert -r from-branch file
hg ci -m 'copied single file from from-branch to to-branch
If you want to select different parts of that file, then "hg record" is useful.
I just did this on my home directory .hgignore.
If both branches have made changes to a file that you want to keep, a dirty trick would be to create a merge of the two branches using hg merge, possibly/probably on still another branch, check that in, and then copy a single file between the merge and the to-branch:
hg update -r to-branch
branch merge-branch
hg merge -r from-branch
hg ci -m 'temp merge to be discarded"
hg update -r to-branch
hg revert -r merge-branch single-file
hg ci -m 'merged single-file from from-branch to to-branch"
hg strip merge-branch
It is worth mentioning: the way to "copy a single file between branches" (or revisions, or from revision to merge, or....) is "hg revert". I.e.
hg update -r Where-you-want-to-copy-to
hg revert -r Where-you-want-to-copy-from file-you-want-to-copy
...
hg ci
For some reason I, and some of my coworkers, find this VERY confusing. "revert"=="copy" ... makes sense for some usage patterns, but not all.
Nope. Mercurial works on a changeset basis.
But you can do a "dummy merge" where you ignore the incoming changes from one of the branches. Before you commit you could then revert selected files to whatever state you want:
% HGMERGE=internal:local hg merge # keep my files
% hg revert --rev other-branch a.txt # update a.txt to other branch
% hg commit -m 'Dummy merge to pick a.txt from other-branch.'
Maybe that will help you a bit.
One fairly clean way of getting the desired result is to do it in two steps: first use graft, then second use histedit.
Say this is the starting point and you need to select some portions of C and D to "merge" after E:
A---B---C---D
\
-E
Then you would graft C and D on top of E:
A---B---C---D
\
-E--C'--D'
Then use hg histedit to edit C' and D'. During the edit you can make any changes you want, but in this case you would just revert any unwanted files, (or even portions of them).
(Note that histedit edit works by temporarily updating your working folder to match the content of the given changeset as though it were not committed yet. So you can easily revert unwanted files and then hg histedit --continue which will effectively replace the edited changeset.)
So the final result would be:
A---B---C---D
\
-E--C''--D''
Where the '' revisions were modified as required.
I would say this approach is more beneficial when you have large changesets that probably should have been multiple smaller commits in the first place; this approach allows you to "disentangle" only the parts that you need. Using this for just a single file would be fine but could be overkill.
I would just use an external tool like vimdiff to diff the two files that I want to merge and then merge them. The advantage of this is that you can do selective editing on parts of the file. E.g:
hg update -r branch-merging-to
hg extdiff -p vimdiff -r branch-merging-from file-I-am-merging
To do this you need to enable the external tools in your .hgrc, which just means adding these lines:
[extensions]
hgext.extdiff =
If you are using an IDE:
Merge the old branch with new branch
Go inside the the IDE and remove the unwanted changes
Generate the diff file
Update and clean the new branch
Apply the diff in the new branch