Plastic SCM - GitSync guide
As you likely know by now, Plastic SCM is a full featured DVCS (Distributed Version Control Software). And, Plastic SCM also speaks the Git network protocol.
Plastic SCM is able to push and pull changes directly to any remote Git server. This is because Plastic supports the https:// and git:// protocols for both pushing and pulling changesets.
This feature immediately turns Plastic SCM into a DVCS fully compatible with Git. The advantages of this means that you can use Plastic or Git on your workstation, and still participate on Git projects (GitHub, CodePlex and many more).
What is GitSync?
This can be a first approach: GitSync is a native Windows DVCS connected to GitHub. So, it virtually turns Plastic SCM into a full-fledged Windows client for Git.
Note: GitSync is not technically a new Git client: You would be using Plastic SCM on the client side but being able to push/pull to Git servers (using https or Git protocols).
Imagine that you're a developer using GitHub (or Bitbucket, or maybe CodePlex). In any case, there are things you like: using a cloud-based repository for your code, and Windows to develop. And things you don't like: being forced to use the CLI, and lack of really awesome GUI tools.
So, you wish you had everything: Cloud repositories, the DVCS power, and awesome tools for Windows.
That's what you get with GitSync.
The capabilities of GitSync are:
- Direct push/pull - Including all commits, comments, branches, merge tracking and tags.
- Adding/deleting or moving files - No limits at any of the two sides.
- Full merge tracking - You can merge at Git side and Plastic will recognize the merge tracking. And, the same is true in the Plastic-to-Git direction. That's the benefit of Plastic SCM and Git being full DVCS!
- Conflict management - It is possible to make changes on the same branch on the Git and Plastic sides concurrently and Plastic will handle the data exchange, pull the changes, request the user to run a merge, then push the solved conflict (as you'd do if you just were using a full Git setup).
How it works?
Since an image is worth a thousand words, let's go, step by step, through an entire push and pull process.
You've a Git repo and then you pull it on Plastic. As a result, you get an exact clone with the branches and commits you had in Git now converted to Plastic, and what's best about this, is the ability to be rendered in the Branch Explorer:
Creating new commit on the Git side
The next image shows what happens when a new commit is created on the Git side, and how the pull from Plastic SCM retrieves it.
Instead of just performing a simple change, the figure shows a merge from big_feature branch into master. The result in Plastic SCM mimics what happened at the Git side, adding the merge link (which is rendered as a green line) on the Plastic Branch Explorer:
Creating new changeset on the Plastic side
The next step is performing a change in Plastic SCM and pushing the change to Git. To create a more complete example, instead of just creating a new changeset, we will also perform a merge.
The changesets 6 and 7 are created on the Plastic side, then they're pushed to Git. As you can see in the figure below, the merge information (multiple parents on the Git repo) is also sent from Plastic to Git.
So far, the changes were done at one side or the other, but not at the two sides concurrently.
Performing changes concurrently: conflicts
The following picture shows what happens when developers work on the same branch at the same time. One new commit is created in Git (on green) and a new one in Plastic (orange):
If the Plastic developer tries to push to Git, an error will show up since there are conflicting changes (the same that would happen on a similar scenario on a pure Plastic or pure Git setup). The steps to follow are:
- First pull the changes from Git
- A new "subbranch" will be created placing the 88ffa changeset correctly.
- The next steps will be resolving the merge conflict at the Plastic SCM side, and then completing the push:
At the end of the interaction, both repositories will look the same, and will let developers work together at both sides.
Note: Since Plastic SCM is a full DVCS (like Git) it can clone a Git repository and later push changes to it... entirely! We do not restrict to a single branch. You can create branches on Plastic and push them to Git. You can create branches on Git and pull them to Plastic.
The gitsync.conf file
The GitSync configuration file (
gitsync.conf) lets you include information that will be automatically used during the GitSync operations.
This information is related to the mapping between two Plastic SCM and Git objects:
- User accounts
- Xlinks/Submodules information
file must be located in:
- In the Plastic SCM client folder.
- In the
plastic4 directory (under
$HOME/.plastic4 on Linux/Mac systems or
C:\Users\user\AppData\Local\plastic4 on Windows).
Mapping user accounts
gitsync.conf file, we can define a mapping between Plastic and Git (emails). This information will be used as author and committer when committing to Git.
This info is added on the
email-mapping section with the following format:
plastic_user = git_email_address
This is an example of
asalim = firstname.lastname@example.org
ubuntu = email@example.com
Mapping Plastic SCM Xlinks and Git submodules
A Git submodule is just a pointer to a commit in a different repository. It doesn't propagate operations between submodules or handle the branching between the repositories, so this very basic information is enough for the submodules work.
A Plastic Xlink object is more complex than the Git submodule: the Xlinks allow the user to set relative servers, set rules for the branch expansion, and define whether the Xlink is writable or not.
In general terms, we can say that Git submodules and Plastic Xlinks have the same mission: pointing to a commit in a different repository. So a direct mapping can be established between:
- A Git commit ↔ A Plastic changeset
- A Git repository url ↔ A Plastic repository specification
GitSync lets the user create Plastic Xlinks from Git submodules and vice versa. The Git submodules and the Plastic Xlinks can be synchronized using GitSync:
- The Git submodules are converted into Plastic Xlinks during the pull operation.
- The Plastic Xlinks are converted into Git submodules during the push operation.
Please note that before synchronizing a repository with Xlinks/Submodules, the target repositories must be synchronized.
To synchronize a repository with Xlinks/Submodules, the mapping information must be added on the
gitsync.conf file. This info is added on the submodules section with the following format:
git_repository_url -> plastic_repository_spec [writable:true|false] [relativeserver:true|false]
- If the Git submodule has to be converted on a writable Plastic Xlink, then the
writable field must be included as
writable:true. If the
writable field is omitted or it's set to false, the Xlink is created as readonly.
- If the Git submodule must be converted on a Plastic Xlink with a relative server, the field
relativeserver must be included as
relativeserver:true. If the
relativeserver field is omitted or it is set to false, then the Xlink is created against the Plastic repository server (as non-relative Xlink).
This would be a valid configuration example:
git://localhost/code -> code@localhost:8084 writable:true relativeserver:true
git://localhost/doc -> doc@localhost:8084 writable:false relativeserver:true
There are two Git operations that are restricted when using GitSync:
merge (fast-forward) command
These Git commands don't take into account the history of your changes. Although the user can work in a parallel way, Git talks about history like something linear. But Plastic prioritizes keeping the changes history.
Plastic SCM takes into account the whole history of the changes you make. This means that Plastic doesn't rewrite history. It is not that we're against it, it was a design decision, a philosophy.
The changes history is reflected when working on branches and merging. Because Plastic SCM is able to solve and show how the history is, we recommend you to avoid using those Git commands when working with GitSync.
Plastic has the Branch Explorer which simply lets you understand what is going on, graphically. This way you are not distracted and you don't miss rebasing.
When you diff a branch with several merges, it is hard to see what you really changed on the branch and what comes from the merge... this is also solved in Plastic:
We recommend that you not to use the Git rebase and merge (fast-forward) command to avoid unexpected results when synchronizing your Plastic-Git repositories.
As we've seen previously, Plastic can push and pull directly to remote Git servers using both native Git and https protocols, which includes well-known sites such as GitHub, BitKeeper, CodePlex and many others.
When we started developing the Git-bidirectional synchronization with Plastic SCM, we had the following scenarios in mind:
- Developers already using Plastic SCM who want to contribute to projects in sites like GitHub, CodePlex, BitKeeper and others.
- Developers working on teams using Git as primary server who prefer to use Plastic SCM but need to contribute changes back to the main server.
- Teams gradually adopting Plastic SCM who need to contribute to other teams on Git.
We went the hard way for a solution: we didn't come up with some sort of intermediate script to convert changes from one system to the other, or doing fast-import/export, imposing a ton of limitations. But we actually implemented was the Git network protocols in Plastic as a layer able to directly pull and push to Git.
Plastic starts a negotiation phase with the remote Git server, as a Git command would do, speaking the Git protocol. It is a core feature, not an add-on script.
As we've said, GitSync implements the smart-protocol and:
- It can negotiate with a remote Git receive-pack to upload data (negotiating which changesets/commits are needed and generating the correct pack file from Plastic repository data to be sent to Git).
- It can also negotiate with a remote upload-pack to decide which commits need to be packaged, download the pack and import it into Plastic.
The first pull
Let's start by connecting to a GitHub repository.
If you go to GitHub and browse the repos, you'll probably find something like a list of "trendy" repos. In the example figure, I've selected one of them which turned out to be the corefx repository:
Now, to pull it to Plastic I've created a repo to "host it" (called corefx too) and went to the initially empty Branch Explorer, then to the context menu option to launch the Sync with Git:
Then you launch the Sync dialog (which is very similar to the replication dialog to push/pull changes between Plastic servers) and enter the URL of the Git repo:
No need for credentials now since we're just pulling (cloning) from a public repo. You'll need to specify them in case you need to push and then the server requires you to be an authenticated user.
Just press Sync and the process (pull) will start up as follows:
This operation can be done by using the command line in the following way:
cm sync corefx git https://github.com/corefx/corefx.git
Assuming the local corefx repo is empty, it will calculate the changesets and branches it needs to pull from the remote GitHub repo, and will pull them:
In order to pull new changes done at the GitHub side, you'll simply re-run the same command:
cm sync corefx git https://github.com/corefx/corefx.git
And it will now calculate and pull only the new changes made at the Git side, if any.
You're currently pulling Git changesets and branches directly to your local Plastic SCM repository:
Once the replication is complete, we'll go back to the workspace explorer, and we'll update our workspace to download the source files.
Refresh the Branch Explorer too. And you'll be able to render the just imported Git changesets in a typical Plastic SCM way:
And now, right-clicking any changeset (commit in Git jargon), you'll be able to check differences with our built-in diff system:
Now you're ready to do more changes in Plastic whether branches, merges, anything. Then repeat the same process to sync to Git (which will in turn push or pull changes and even ask you to solve merges before pushing back to Git, if concurrent changes were done on the same branches).
Pushing to Git
We're going to push one of our Plastic repositories to GitHub. You'll see that this process is similar to the previous one.
Ok! Let's start!
I created a new GitHub repository in order to export my Plastic repository to GitHub:
I've chose my dokancode Plastic repo. In the Branch Explorer view, right-click one of its branches and, as we did in the previous chapter, select the Sync with Git menu option:
The Sync dialog will be launched.
Then, enter the GitHub repository URL and the credentials if needed:
Then, click the Sync button to start the synchronization. In this case, we're going to push (or export) our Plastic repository:
We're currently pushing Plastic SCM changesets and branches directly to my GitHub repository.
This operation can be done by using the command line in the following way:
cm sync dokancode git https://github.com/mbctesting/dokancode.git
Assuming the GitHub dokancode repo is empty, GitSync will calculate the changesets and branches it needs to push from the Plastic repo, and will push them:
Once the push operation is finished, we can see a summary with the objects that have been exporting:
If we go back to GitHub and refresh the dokancode repository, we'll see the exported objects from Plastic:
Now we're ready to work with the repository in both sides: Plastic SCM and GitHub. We'll be able to create branches, do changes... and synchronize again by pulling/pushing.
Working on the both sides
In this chapter we're going to show you how to work with the dokancode repo, both in the GitHub and Plastic sides, applying some basic operations.
This is the recommended step - Before performing any changes at either of the sides, you must synchronize your repo (using the Sync with Git action) to avoid conflicts.
Changes at the Git side
Now I'm going to run some operations on the master branch:
Delete the license.txt file:
Edit the dokan-net-0.6.0\readme_dokan.txt file:
And move it to dokan-net-0.6.0\DokanNet folder:
And then, I'm going to create a new branch (scm007).
Add two new files:
And edit one of those files:
The commits are done and now we're ready to see them in the Plastic side.
As we've learned during this guide, we've seen that GitSync is capable of calculating what's new at the other side, negotiate with the remote server and push the changes.
So let's go to synchronize the Plastic repo with the GitHub one by running a Sync with Git action:
By clicking Sync, the synchronization will begin and will pull to the Plastic repo the changes we performed on the GitHub side:
Once the synchronization finished:
We can see a summary with the imported objects:
If we go back to the Branch Explorer and refresh the view, we'll see the changes done in the GitHub side that have been imported to Plastic:
We can open the Changesets view to see these GitHub changes:
And, if we want to go deeper, we can confirm the changes done with the readme_dokan.txt file in the GitHub side. We can see the history of that file to check that those changes have been applied with the synchronization:
Now we can continue performing changes at the Plastic side.
Changes at the Plastic side
I'm going to perform some changes on the scm005 branch. At this point, both the Git and Plastic sides have the same content. We can check it on both sides:
In this branch I'm going to:
Add a new file:
Edit the DokanOperation.cs file:
These are the new changes:
Once the changes are done, I'm going to synchronize the GitHub repository by running a Sync with Git operation:
Once the synchronization is done, we can see the summary:
The summary tells us that the synchronization has sent two changesets involved in one branch:
If we go to the GitHub side, we can see these new changes that were done in the Plastic side:
Plastic and Git branches conversion
If you noticed, the Plastic main branch is mapped to Git master branch. This mapping is also considered for the children branches of main on Plastic. This means that the Plastic branches are converted into Git branches by removing the hierarchy and replacing the / with -. And this rule is also valid when a Git branch is converted into a Plastic branch: the - character is used to recreate the hierarchy in Plastic.
In the examples before, the Plastic branch /main/scm005 is converted to master-scm005. And the Git branch scm007 under master, is converted to /main/scm007:
The - character is also allowed as part of the branch name like the following examples:
|Branch - Git side
||Branch - Plastic side
Full merge tracking
Since Plastic SCM handles the same concepts as Git (DAG, commits, merge links, and so on), it is rather easy to share the merge tracking. You do a merge in Git, fine, you can get it back to Plastic. If you do a merge in Plastic, fine, you can push even the merge link back to Git.
The most difficult feature for us to handle is related to the "precise item tracking"; we do (and Git doesn't). Plastic has an internal id associated to each file and directory. It means we can easily handle tons of merge conflicts that are hard to track for Git (like a divergent move, something trivial for Plastic).
In the following examples we'll see how the merge tracking works when using GitSync.
Merge on the Plastic side
We're going to create two branches:
Branch scm008 - I'll edit the DokanResetTimeout method in the DokanNet.cs file, move it inside the file, and add a new field:
Branch scm009 - I'll move the DokanNet.cs file to another folder, then I'll move the method DokanResetTimeout to another class and edit it:
Once the changes are done on different branches, I'm going to merge them to the main branch, and I get this result:
Now I'm going to synchronize my repositories on both sides, as you know, using the Sync with Git operation. This way, I will push these merges on the Git side.
The new branches have been pushed and the merge tracking looks like this on the Git side:
Merge on the Git side
Now we're going to see a merge in the Git side is tracked on the Plastic one.
I'm going to create a new branch and I'll create a new file and edited another one:
Once the commits are done, I'm going to perform a merge from the scm010 branch to the master one:
Note that the merge is done using the --no-ff
option as we've seen in the GitSync restrictions
The merge is done and now we're going to pull these changes to the remote Git repo:
Once the local Git changes have been pulled to the remote Git repo, let's go to synchronize our repos. This means that the latest changes will be pulled to the Plastic repo. If we run a Sync with Git operation:
...and refresh the Branch Explorer once the synchronization is finished, we'll see how the changes and merge done in the Git side have been pulled into the Plastic one:
As we've seen in the How it works chapter, we can make changes concurrently both in the Plastic and Git side. This means that you can work on the same branch on the two systems and reconcile changes (as you do when you use a pure Plastic environment or a pure Git one).
We're going to see how you can manage that situation with GitSync and Plastic.
Let's start by using one of the previous examples. In the Changes at the Git side section we made some changes at the GitHub side. This is the what I did:
- In the master branch - I deleted the license.txt file, edited the dokan-net-0.6.0\readme_dokan.txt file, and moved it to the dokan-net-0.6.0\DokanNet folder.
- Then I created a new branch (scm007) where - I added two new files (ArrayIndex.cs and ArrayInitialization.cs) and edited one of them (ArrayIndex.cs).
And now, I'm going to perform some changes in the Plastic side:
In the main branch, I'm going to edit the DokanNet.cs file:
And add 3 new files:
Once the changes are done, I decided to synchronize both repos using the Sync with Git operation:
When the synchronization is finished, a message will tell us that a merge is needed!
And this is because we made some changes in the same branch on both the Git and Plastic sides.
In the summary, will see that the main (or master) branch is the one that requires a merge operation:
And it's true: We applied some changes in the master branch on the Git side, and some other changes in the main branch on the Plastic side. Remember, that main and master is the same branch but using different names (see the Git-Plastic Dictionary for further information).
As we've seen in the How it works section, we have to resolve the merge conflict at the Plastic side. So let's do it!
If we update the Branch Explorer, we'll see that:
- First, the main branch has multiple "heads" that must be merged. This is because these conflicts are handled as a subbranch in Plastic SCM.
- Second, the scm007 branch has been synchronized (pulled from GitHub to Plastic SCM).
To solve this conflict, we're going to run a merge from the "GitHub" head (the head of the subbranch):
We'll see the changes that are going to be merged:
By clicking the Process all merges button, then the items have been automatically merged.
The last step (as you know) is to checkin (confirm) the changes in the Pending changes view:
Once you clicked the Checkin button, you'll see that the two "heads" are merged into only one head, the one from the main branch:
The merge conflict is now solved. But we need to complete the synchronization by pushing in the Git side the changes done in the Plastic one. And, as you may already know, this is done by using the Sync with Git action.
Once this operation is finished, both repos are fully synchronized. This means that we have the same content on both sides.
June 16, 2017
Read how the branches conversion between Plastic and Git, and vice versa, works. We also updated the related screenshots.
April 12, 2016