Are you confined in perforce? Do you want to escape from it?







Well, some were simply about the “rendering style” of plastic’s branch explorer (which is what I used to drive the examples), and others about the explanation itself.
Mercurial’s programmer admits that recursive merge is better although argues that it is only worth in some cases and that its costs to implement is bigger than its benefits. Implementing a recursive merge isn’t cheap, as we known down here at Codice, but you know, the big difference between a great product and an exceptional one normally relies on the upper 2% of features that makes it rock.
Today we'll be covering (I'm writing this with the help of Borja, our merge master) "advantages of recursive merge - Case 1: Only one ancestor is the right option".
I’d like to go back to the original example and explain it now in bigger detail:
We’re going to merge from changeset 5 to changeset 6. In this diagram (another explanation using code will come later) we simply say the “content” of the file is A or B or C, but it applies to lines of code (containing important changes, bug fixes and so on).In this case the “src” and “dst” are clear but the problem is the “common ancestor” because there’s more than one candidate.
If you look carefully you’ll see that both changesets “2” and “3” can be taken as common ancestors.
A non-recursive merge algorithm will only use one of them, and depending on the “choice”, the result can be quite different.
This time, the result matches the expected result, but sometimes it simply leads to an incorrect automatic choice, which is the real problem and the real reason why “recursive” is implemented by git and plastic.
Real world has the answer: try a "real" merge involving several hundreds of files and then the answer is clear: usable if you don't have to solve the conflicts vs not usable.
Sample: cat foo.c@main@4
Would be captured by the CC fs driver and instead of issuing a "file not found" it would be able to get the right version of the file to be dumped by "cat".
Likewise it was able to intercept "move" operations so you didn't need to run "cleartool mv" command. What does it mean? You don't need to tell the SCM that you modified a file or that you moved it: it is intercepting all your IO actions, and making the right ops at the FS level!
So, definitely, we always wanted to have some sort "move interception" to avoid having to "tell" plastic a file or dir was moved... it would simply know.
Glass was able to use some underlying FS layer (third party FS driver code to simplify FS creation) to intercept all ops and:
Well, writing your own FS is always a cool thing, but there were caveats:
So, while we used glass internally, we never moved it to production mode.
Xdiff opened up a new door to make Plastic transparent.
And we applied the Xdiff technology. How?
This way the "pending changes view" is now able to figure out what you did on your workspace, including modified and moved files, and directories (remember dvcs like git or mercurial are not able to track directory renames or moves).
During this old period developers were forced to manually specify how the checkout process was going to happen. Look at the following selector:
repository “coolcode”
path “/”
branch “/task001” checkout “/task001”
path “/”
branch “/main” checkout “/task001”
Read through it in detail. What does it mean? There are two rules: the first one says: try to load the item from “/task001” and if you’ve loaded the item with this rule and you need to checkout, checkout to “/task001”.
Then there’s a second rule, which is the one performing the branching. This rule will only load items that were not loaded with the first rule (the selector rules are executed in priority order, top to bottom). So, at the beginning items will be on the “/main” branch only, so all will go through this rule.
If you check carefully you’ll see the second rule loads from “/main” but checkouts on “/task001”! This is how branching happened! On checkout, new revisions are placed on the new branch, then the first rule will be able to load them.
Then child branches were born and the following selector:
repository “coolcode”
path “/”
branch “/main/task001” checkout “/main/task001”
Was equivalent to the previous one. So, only one rule was needed to specify the “branching behavior” defined before.
A branch like “/main/task001” means: “get the content from task001 but if it doesn’t exist take it from main and place all checkouts in main”. It was an important step ahead back in the day.
repository “coolcode”
path “/”
branch “/main/task001”
label “BL130”
checkout “/main/task001”
Otherwise “task001” would “inherit” from LAST on “main” which was the basis of the powerful “dynamic inheritance feature”.
Smart branches made things simpler because you were able to “set a base to a branch” and then your selector turned out to be something like the following:
repository “coolcode”
path “/”
smartbranch “/main/task001”
No need to specify the “label” nor the “checkout branch”.
Basically, in 4.0 a branch that starts from changest 1024 (on “main”) can be named “main/importantfix” if you want to highlight it is a “child” of the “main” branch, but you can easily create “importantfix” directly from cset 1024 too and they’ll behave exactly the same.
We kept the “child branch” concept in 4.0 because we think it introduces a “branching namespace” which is very good for existing Plastic SCM users (used to it for years) and also good to organize development for newcomers.
But remember that now all branches are equal, independently of whether they’re children or “first level” branches, unlike what happened in Plastic prior to 4.0.
You know we listen to you and here’s a blog post focused on explaining what’s new in our latest BL237.7 build (4.0.237.7 version) and where does it came from.Remember we’re using “user voice” and we’re more than happy to receive your feedback there.
Well… we fixed it! New 237.7 is able to deal with files moved between projects!! Cool, isn’t it!
These core changes didn’t have a huge impact on the underlying database structure (if you look carefully you’ll note that the only difference is about the usage of the old “childrenitem” table, which entries were modified (visible on beta) and now have disappeared completely.
This important change made direct database upgrade (as we always did so far: just run the server and during start-up it upgrades the database) no longer feasible.
On the other hand, we have changed our “import strategy” and instead of developing specific “importers” (Subversion, CVS, Visual Source Safe) we’ve now standardized on the “fast-import / fast-export command suite”. This new “fast-export/import” allows us to provide import capabilities from a wider set of SCMs and also enable an easier “way out” for teams who need to feel they’ve a “way back” in case something fails during the move to a new SCM. It also allows us to provide a much better git interop.
We implemented the “fast-export” support for Plastic SCM 3.0 too (available on the latest releases) and then we’ve just decided to stick to this migration path to enable the move to 4.0.
In short:
$ cm fast-export repo@localhost:8084 repo.fast-export
$ cm fast-import repo@localhost:8087 repo.fast-export
There are some important changes between 3.0 and 4.0 underlying structure which will force the 3.0 fast-export command to “discard” some branches.
The reason is tightly related to the way in which 3.0 dynamic branch inheritance worked. In 4.0 each branch points to a changeset “head”, the latest changeset on the branch. So, switching to a branch is always equivalent to switching to the last changeset on the branch. Each changeset is statically resolved which means it simply points to a given source code tree, starting on the root directory of your repository and then to all its content (it doesn’t mean each changeset contains an entire copy of the repo!! Don’t worry about storage!).
Things were a little bit different with 3.0, where the selector rules were necessary in order to resolve a given tree. Remember you could have branches pointing to “last” which means switching to it would load your content on the branch and “combine it” (not merge, just combine the non-overlapping entries) with the latest on the parent branch.
There is a big difference between the changesets in 3.0 and 4.0. In 4.0, each changeset points to an entire, statically resolved tree. It wasn’t true in 3.0 for the changesets on branches inheriting from “last” since “last” would dynamically move.
What does it mean? Basically: branches inheriting from “last” won’t be exported by the 3.0 fast-export command and hence won’t be imported in 4.0. If this is a problem for you and prevents you to migrate to 4.0, please let us know.
This important structural changes (tree + merge tracking) are the reasons why a “direct” migration wasn’t feasible so far, and also the reason why we decided to go through a “export-import” path.
The main risk migrating from 3.0 to 4.0 (and we’re currently working on it) is when a “partial merge link” is wrongly migrated as a full merge link (the only ones supported in 4.0) leading to potential merge calculation errors later on.
The merge from /main/task001 to /main/task002 will only propose /src/foo.c to be merged, because it was the only item modified in the branch. It means that “/doc/plan.pdf” won’t be proposed to be merged to “task002”. This was an important limitation on 3.0 and has been fixed in 4.0. But, if the merge was performed in 3.0, the merge link will be there but “task002” won’t contain the modified “plan.pdf”.
Now you migrate from 3.0 to 4.0 and decide to merge “task002” to “main”. The new merge system will check the differences between the source changeset and the base changeset and it will find that “plan.pdf” was modified (because “task002”, despite of the 3.0 merge, will still contain the “old plan.pdf”, and 4.0 doesn’t have (so far) a good way to know whether it was incorrectly merged on 3.0 or really modified.
At the end of the day, merging task002 will put the old “plan.pdf” on “main”, incorrectly, because the merge link between task001 and task002 is set by 3.0, and 4.0 can’t handles merge differently.
(The case is a little bit dense so feel free to contact us if you need further info). This is not a problem with the following type of merges: