I have a theoretical question about possible VCS merging.
I know that many VCS use 3 revision merge, which is common ancestor, "mine" and "your" revision. I know how they works.
I've thought about another alternative, recursive revision merge, haven't found this in Google.
"You found America!" you might think. I know Git use recursive merge.
But the reason Git is using recursive merge is for criss-cross merge
I'm talking about a normal case, non criss-cross merge.
For example, we have a common ancestor, A, and to branches, 1 and 2.
branch 1: B, C, D, E, F, G
branch 2: B', C', D', E', F', G'
As said before, A is the common ancestor so it's the parent of B and B'.
We want to merge G and G' into branch 1. The common way that Git and Mercurial use is the diff3:
diff3(ancestor = A, mine = G, yours = G')
This will compute merge by computing 3 version only, which is O(1).
The alternative algorithm I thought about is O(n):
merge the closest revisions to ancestor first.
merge the result with the next closest revision from branch 1
merge the result with the next closest revision from branch 2 (if remain)
repeat (in loop) to step 2 if there any revision in branch 1 remain.
In the above example it looks like:
merge B and B'
merge the result with C
merge the result with C'
merge the result with D
and so on...
The question I couldn't resolve is - Is there any case that my way is safer and more accurate (in non criss-cross merge) than the traditional 3 revision merge?
Can my way avoid conflicts that the traditional way cause?
Can my way create new conflicts that the tradition way doesn't cause?
Does my way conflicts are not "real" conflicts? (which the tradition way doesn't cause)
We want to merge G and G' into branch 1.
Why we want merge G into branch1? G is already in branch1. In best case we give nothing from this merge, in worst - conflict. Same for all other revisions without '
So only B' - G' need to be merged to branch1. And this is the 3-way merge.
BTW. third component of 3-way merge not 'common ancestor', but 'base'. Common ancestor can be base but not always.
Related
I would like to support the following situation:
development happens on two branches - they are both a bit like "default" (actual development happens on feature branches, but they are branched of and merged to one of these two branches)
I would like to merge changes from one branch to another in both directions without grafting individual commits
branches have a diff (on big merge of a feature branch) that I would like to always keep and support
I tried to do a dummy merge as described here, first in one direction, then after several successful merges, in another direction (dummy merge of dummy merge). Now I need to do a merge again in another direction, and here another dummy merge (of dummy merge of dummy merge) does not help me any more (and I hoped that one dummy merge would be enough anyway).
Is it possible to do development in this fashion, or is it better to do most of development in one branch? (well, I know it is better for hg, but I have reasons)
Preface
If both branches share the same functionality (unstable common DEVEL), I can't see any reasons in such splitting, except added headache
Face
You can avoid merging unwanted changeset from one branch into another and use ordinary merge if you'll convert this mergeset into MQ-patch ( or maybe shelveset) and always merge from|to (read "Merging patches with new upstream revisions" for merging to branch hint) branch with unapplied patch
I have a branch named A. I create another branch from A named as B. I work on the new branch B and push it. Later on I work on branch A and push it. Now, I switch back to branch B but I want it to update with the latest changes of branch A.
so should I merge from branch A to branch B, or branch B to branch A
In a normal case, the result of the merge is usually unique, whether you go to one direction or the other. The branch destination, however, depends only on your interpretation of the branches.
For example, you should merge the development branches in the stable branch only when they are deemed ready, but the stable can go in development more often.
Let's consider following two Mercurial scenarios:
Scenario A:
I have linear history from rev 1 to rev 5, I create branch foobar and commit revisions 5-11 to it. Then I switch to master and commit rev 12 to master. I have two branches (master and foobar), with one head each. Nice.
Scenario B:
I have a linear history from revision 1 to rev 10 (only one branch - master). I'd like to put revisions 6-10 to a new branch and continue my master from 5 onward, effectively putting myself into scenario A. I see that mercurial does not support retroactive naming of branches, so there's no way for me to transition to scenario A, but I'm thinking about hack like this one:
I create a new branch (and name it foobar), and commit rev 11 to it
I switch to master and do hg update -5, and then commit rev 12 to master
Do I now have two branches with one head each? If I understand correctly, the only difference between scenario A and scenario B is that in scenario B revs 5-10 are not labeled with "branch foobar", which in practice doesn't mean much, and all future behavior for scenario A and scenario B is equal. Am I right?
You are correct. When you do a hg update the earlier revision you will see the files as they were at that point and be able to isolate the differences from the revisions that you wanted on a branch.
In CVS I have a branch (b) off another branch (a) which is off the trunk/head.
Some bug fixes were made in branch (a) that I'd like to go ahead and use in branch (b). How can I pull those fixes into my branch in Eclipse?
head
|
v
a (with bug fixes)
|
v
b (needs bug fixes)
Ideally what you need is to have two tags on a for every feature you want to merge, and then merge the difference between those two tags into b. However, you would also need to remember which ones you have already merged, because CVS doesn't remember that.
When I was working in a company that used CVS and branches, our policy was that bugfixes from branches (a in this case) that ought to be used by other branches need to get merged into the trunk first, and all the other branches merge them from there.
However, it was still very painful if you wanted to cherry-pick individual bugfixes. Essentially, you'd have to remember every fix you've merged (by two tags, marking the beginning and the end of the changes making up that fix).
Generally, in CVS it's much better to remember (in a tag) up to which revision you have merged, and merge everything from there to the head (and then move the tag to the head). In CVS, cherry-picking is painful and requires you to store the merge history somewhere.
This question is rather agnostic than related to a certain version control program.
Assume there is a source code tree under certain distributed version control. Let's call it A.
At some point somebody else clones it and gets its own copy. Let's call it B.
I'll call A and B branches, even if some version control tools have different definitions for branches (some might call A and B repositories).
Let's assume that branch A is the "main" branch. In the context of distributed version control this only means that branch A is modified much more actively and the owner of branch B periodically syncs (pulls) new updates from branch A.
Let's consider that a certain source file in branch B contains a class (again, it's also language agnostic). The owner of branch B considers that some class methods are more appropriate and groups them together by moving them inside the class body. Functionally nothing has changed - this is a very trivial refactoring of the code. But the change gets reflected in diffs. Now, assuming that this change from branch B will never get merged into branch A, the owner of branch B will always get this difference when pulling from branch A and merging into his own workspace. Even if there's only one such trivial change, the owner of branch B needs to resolve conflicts every time when pulling from branch A. As long as branches A and B are modified independently, more and more conflicts like this appear. What is the workaround for this situation? Which workflow should the owner of branch B follow to minimize the effort for periodically syncing with branch A?
The owner of branch B should have discussed the change with the owner of branch A. They should have decided that either the change was worth making, in which case it should have been committed to the trunk (A) or it wasn't, in which case it should have never been made. VCS is not a substitute for communication between developers.
Dev B should ask Dev A to pull from him.
The situation is not avoidable if two branches diverge and never converge. Its similar to a fork in a project - Its very difficult to merge two different forks.
Dev B should either un-refactor, or else add some meaningful functionality that has enough momentum to warrant merging back into A. Otherwise tell him "Them's the breaks".
To go to an extreme example, he could decide that he doesn't like C and decide to re-write everything as Pascal, line by line, using the same variable names, class names, etc.. To the point that the only difference is the language. So what would you tell him then, when he insists that there aren't any changes, so there should be no diff?
One workaround is to have a fancy diff wrapper around code comparison that will intelligently ignore certain very specific diffs.
On a simple level it's usually implemented via gdiff, on fancier, with custom diff code.
However, I must say that such a situation is really a bad thing and it's much better to merge the changes back into A; by for example submitting a patch to A's maintainers owners