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.
Related
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"
I am using Xcode's integrated Source Control with Git and I have the following problem:
I have a perfectly working master branch and I want to work on two new features. So I create two new branches, where I add one new file at each branch.
Now when I switch back to the master branch or the other branch, after committing the changes and without merging (I don't want to merge yet), the files from ALL the branches appear in the project navigator (the ones that don't belong to the current branch are in red colour) and prevent my code from compiling as the compiler complains that these files don't exist.
My master at least should compile regardless of what I've done in other branches right?
Am I missing something trivial here?
Untracked files and unstaged changes do not belong to any branch. They only live in your working tree. When you switch branches, those files/changes are left untouched. If you want them to exist only in a certain branch, you have to add and commit all of them.
This should help understanding:
$ git status
On branch master
nothing to commit, working directory clean
$ >>file echo 'added line'
$ touch new_file
$ git status
On branch master
Changes not staged for commit:
modified: file
Untracked files:
new_file
$ git checkout -b new_branch
M file
Switch to a new branch 'new_branch'
$ git status
On branch new_branch
Changes not staged for commit:
modified: file
Untracked files:
new_file
So, as you see, unstaged changes are carried over when switching branches (this is by design). When checking out another branch, Git tells you which files contain changes (the line starting with Modified). This also holds for untracked files (Git cannot delete them, since you might need them), but their names are not explicitely output when checking out a branch.
To have Git delete files when switching a branch, you have to add (and commit!) them to a branch first.
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.
How can I resolve this merging issue ?
My project has 1 branch which I used for production and head. 2 times it worked merging production branch into head. Each time I created a tagged head after merging to have a start point for the next merge. Its important to note that I do not create a new branch after each merge, I reuse the branch.
The problem is, if I try to merge my branch to head. eclipse cvs acts like it is comparing and listing all files as "to update", even if file head version is greater than the file branch version.
ex: head file version is 1.8 and branch file version is 1.6. This file was already merged in last merge. When trying to merge I specifiy as "common base version" the head tag that I created after the last merge. Still, eclipse cvs suggests to override head modifications and use the branch version. This behaviour applies to all files.
I dont know what to do. I dont want to manually merge hundreds of files.
thanks for any help
Look at the example:
|tag_h1 |tag_h2
-----------------------------------------> trunk
\ ^ ^
\ / /
\----------------------------------> my_branch
|tag_b1 |tag_b2
On branch there are tags tag_b1 and tag_b2 before each merge, and in trunk, tags tag_h1 and tag_h2.
For a next merge from branch to trunk, the "common base version" of Eclipse will be the one tagged with tag_b2. With CVS update, if you specify two parameters, you will get modifications between these two merged in your working directory. Giving Branch or version to be merged (end tag)=my_branch and Common base version (start tag)=tag_b2 will merge changes from tag_b2 until my_branch end, like calling CVS from command line:
$ cvs up -j tag_b2 -j my_branch
I always tag from where I will merge, and before and after the merge, like this:
|tag_before |tag_after
--------------------------------->
^
/
------------------------------>
|tag_from
Giving the tags a name I can recognize.
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