Xlinks guide


What is an Xlink

Projects often need to reuse existing components that have been developed and are actively used as part of other projects. Plastic SCM encourages using separate repositories for different projects, and components and access shared components by "mounting" them in the project repository through Xlinks. This section will introduce Xlinks and how to use this powerful feature to share components among projects that evolve in parallel.

An Xlink is pretty similar to a symbolic link, like those found in Unix operating systems. It is a directory entry in your repository tree that points to another directory in a different repository. An Xlink, however, will also contain information about the specific version of the target directory to which it is pointing.

Sample Xlink

Xlinks can point to repositories with other Xlinks inside them, so Xlink component mounting can address really complex development scenarios.

Several Xlinked repositories

Xlinks pointing to a given version of the target directory let the user specify, for instance, that project X on version 1.1 is using version 2.1 of library Y. When a new version of the library is labeled, say 2.2, the code of the project can be updated to use it and maybe version 1.2 of project X uses library Y 2.2.

Since Xlinks are versioned, the Xlink in old project X version 1.1 still points to library Y 2.1 and the original configuration can be completely rebuilt without any issue. The following figure depicts how it looks like:

Xlink evolution

Creating and Modifying Xlinks

An Xlink is defined with the following arguments:

  1. The directory entry to create in the current repository. This is a directory that will be used.
  2. The target repository.
  3. The directory to mount in the target repository. You can Xlink to the root of another repository and any directory path inside by mounting a "subtree" on the parent repo as partial Xlinks.

    Partial Xlinks are available on Read-only Xlinks (see below). "Writable partial Xlinks" are not supported yet because they would overly complicate the merge (what if you have conflicts on parts you are not mounting?).

    Note: At this point, you need to use the command line to create partial Xlinks. GUI support will come soon.

    Important: Do not use partial read-only Xlinks with Gluon workspaces. Plastic Gluon doesn't handle partial read-only Xlinks. If you use this feature with Gluon workspaces, you'll get an inconsistent workspace.

  4. The version of the directory to mount. This is specified using either a changeset specification or a label specification.

These are some examples of Xlinks definitions:

Xlink definition syntax sample
  • Read-only Xlinks - Recommended for situations where you are the user of an existing component, but you don't influence its development. In the example above, the user Xlinks an existing library only calling it from their project but not making any changes to it.
  • Writable Xlinks - Lets you make changes inside the Xlinked repository.

In the Workspace Explorer of the GUI client, you'll notice that the Type column contains wXlink where it used to be Xlink for read-only Xlinks.

Read-only vs. writable-Xlinks in the Workspace Explorer

Creating an Xlink using the command line


Creating an Xlink using the GUI


Updating an Xlink


Modifying an Xlink using the command line


Modifying an Xlink using the GUI


Exploring the Xlinked repository

The Plastic SCM GUI views display the information of the top-level repository loaded in the workspace. But, what if you want to see the Branch Explorer or the Changesets views of an Xlinked repository?

The Workspace Explorer makes this easy through the Repository submenu. When you right-click an item inside an Xlinked repository, the Repository submenu lets you open the most important views for the repository where the item is located: i.e. the Xlinked repository. For your convenience, the first entry in the menu contains the repository name of the item:

Repository menu for an item in an Xlinked repository

Xlink Expansion Rules

The Xlink Expansion Rules define how branches are created on the Xlinked repositories and how the branches in the parent repository relate to the branches in the Xlinked repository.


Xlink created in top level branch


Adding an Xlink on a second level branch


Creating asymmetric Xlink hierarchies

So far, the created wXlinks have been symmetric: main linked to main, main/task001 to main/task001, and so on.

Expansion rules are especially helpful when asymmetric links are required. Suppose you need to link the branch main@quake to branch main/fix@zlib. The initial expansion rule will be set this way, and it will enable a parallel asymmetric evolution as the following picture shows:

Asymmetric links

The initial versions of Plastic SCM with Xlink support didn't include Xlink expansion rules. The expansion was controlled by matching branch names, so while simple asymmetric hierarchies were supported, complex cases were not. Consider the following example:

Complex case without expansion rules

That will be handled in the following way now:

Complex case with expansion rules

Advanced expansion cases

Some projects need to set more than one Xlink to the same repository, maybe because they depend on two different versions of the same component.

Consider the following example:

Complex case with multiple xlinks in the same repository

The erp repo Xlinks twice to the zlib: one for the server code that uses the most up-to-date 1.9 version of zlib, and one for the iphone code that uses the older version 1.7.

Note: The erp project could be structured differently, maybe dividing the server and client on different repositories, but this is not the goal of this explanation.

Once the Xlinks are setup, let's inspect /server/zlib:

Complex xlink in main server

Please note how the Is defined by user is set to true. In Plastic internals jargon, this rule is a traveling rule which means: it doesn't apply to the current branch and has to travel to the final one (like when you create a rule in /main/task001 for main@quake -> main@xlinked , it has to travel to main during the merge) or it hasn't been applied yet. Consider now the situation where you make a change inside /server/zlib. The situation will be:

Complex case with multiple xlinks in the same repository - Change

Where the /server/zlib wXlink has been updated to point to the newly expanded branch main/server@zlib while the other wXlink hasn't been modified yet.

At this point, if you edit the wXlink /server/zlib, you'll see the rule has been modified, and it is now as follows:

Complex xlink in main server after expansion

The rule now applies to the branch association, so it is no longer considered as a traveling rule (or defined by the user).

This is a complex scenario, and understanding how it works helps to understand Xlink branch expansion rules.

Initially, an Xlink is created from main@erp to main@zlib with a rule main -> main/server (main/server branch is still empty):

Xlink Branch Expansion in action in a complex scenario - step one

Then the developer creates main/task001@erp and makes a change inside wXlink.

Please note how the branch expansion doesn't happen as initially expected only because main/server is empty and it doesn't contain changesets to start /main/server/task001 from, so main/task001@zlib is created instead:

Xlink Branch Expansion in action in a complex scenario - step two

The developer merges main/task001@erp back to main, and the following happens (now the rule is used as expected). The rule defined by the user is finally used when the correct conditions are met:

Xlink Branch Expansion in action in a complex scenario - step three

Merging links

Merging a branch also affects the auto-expanded branches in the wXlinked repositories. The merge operation is done on the top-level repository (the repository to which the workspace is pointing). It will then evaluate any new versions of wXlinks that have been created and consider the changes in the linked repositories in the merge process.

In this sample scenario, we have the same 2 repositories used in previous sections: ProjectX and MyLibrary. ProjectX is the top-level repository and contains a wXlink component1 pointing to MyLibrary. In ProjectX, we have created two child branches: task0127 and task0243.

We then made changes in the file events.h, located in the Xlinked MyLibrary repository in both branches. This, indeed, expanded branches task0127 and task0243 to the MyLibrary repository:

Sample conflict: same file modified on two branches on Xlinked repositories

Now, what happens when you merge from branch task0127 to branch task0243, as depicted in the figure below?

Branch task0127 is merged to task0243

The merge operation will consider the changes made to the wXlink in both branches and then evaluate the changes in the wXlinked repositories themselves to include them in the merge. So, as a user, you'll have to resolve any possible conflicts as you would with a normal "single repository" merge.

Merging changes in Xlinked repositories

Now the merging of Form1.cs is resolved but, what about the wXlink? The answer is that the merge operation will also update the WXlink to point to the result of the merge in the MyLibrary repository. That is, as a result of the merge operation, there is a new version of Form1.cs with the merged changes, and the WXlink in the ProjectX repository will point to this new changeset. For this reason, the Pending Changes view shows a pending merge link for the ProjectX repository, as depicted in the next figure:

Merged branches in top-level and wXlinked repositories

The overall result is that you only need to tell Plastic SCM "I want to merge this branch" in your workspace, and the merge operation will handle the changes made in wXlinked repositories.


Relative Xlinks

When Xlinks are replicated, the target they point to is still the original one. So, say that you are replicating a repository with an xlink component1 pointing to changeset number 6 on repository MyLibrary on server mainserver.location1.com:8087. The destination of your replica is on another Plastic SCM server at otherserver.location2.com:8087. When you replicate the top-level repository, the Xlink in your replicated repository will still point to mainserver. If it is reachable from the location2.com network, the data for MyLibrary repository will be downloaded from location1.com.

Most of the time, you'll want to replicate the MyLibrary repository to location2.com as well and perform any changes in the local replica.

To tell the Xlink that you want to use the MyLibrary repository found in your default server (that of the top-level repository), you need to create the Xlink with a relative server.

This is achieved with the -rs modifier when the Xlink is created, as in the following example:

cm xlink -rs component1 / 6@mylibrary

When this link is replicated, it'll try to locate MyLibrary repository in the local server rather than mainserver.location1.com.

Changeset number 6 may no longer have number 6 in the replicated repository (changesets are internally identified by their GUID, not their number) since replicas may have different numbering.

The Xlink will be pointing to the right changeset even if the number changes because it uses the changeset GUID rather than the changeset number to locate it.

Read the Plastic SCM book to learn how replication works.


Updates

January 21, 2019
  • We updated the screenshots related to the Xlink dialogs to show how they look like now.
  • We also included some notes to remark that you can only manage expansion rules when you are creating or editing writable links.
April 10, 2019
December 17, 2016