Using Migrations with branching
Using migrations with branching
To nicely support language evolution, migrations automatically upgrade client code to use the latest version of a language or multiple languages. The Migrations documentation describes the process of creating and running migrations in MPS. Briefly, in order to change models to comply with the language changes, language authors can provide migrations. MPS automatically tracks language versions used in projects and asks the end-user to apply needed migrations.
While there are hardly any surprises when using a single branch of development, typical team setup involves multiple branches for features as well as bug fixes. With multiple branches teams will inevitably face situations like having different versions of languages in different branches, which makes the merge procedure much more challenging.
The main rule of painless merge
To merge two branches smoothly, all languages used in those branches should be of the same versions. The following describes a simple workflow that allows you to easily synchronise language versions in two branches.
No migrations were created in any of the merged branches
To sync language versions, just update languages in the outdated branch and run required migrations. Now both branches have the same versions of used languages and can be easily merged.
Some migrations were created
All considered cases have the same idea behind them: never merge branches that differ in versions of used languages. Thus we need to propagate all the migrations into both branches before merging them.
1. One migration was developed in one of the branches
The only special thing that should be done when you write a migration is that there should be a commit (name it C) containing the migration itself, but no code should be migrated in the same commit. The migrated files can be committed later, e.g. in the following commit.
The main idea here is to give other branches a possibility to get the new migration without having to merge different versions of used languages.
Now, your history looks like this:
|--- C --- [branch 1]
|------------ [branch 2]
To merge branches b1 and b2
Merge b2 with commit C. Now you have the new migration in b2.
Run the migration on b2
Merge with b1's HEAD
Quite simple, isn't it?
2. Two or more migrations in one of the branches
The principle remains the same, it is just repeated two or more times
|----- C1 — C2 – [branch 1]
|------------ [branch 2]
merge b2 with C1
run C1's migration on b2
merge with C2
run the migration on b2
merge with b1
3. Migrations were created in both branches
In general, we recommend you to avoid this situation as it's harder to resolve. This scenario can best be avoided by having all migrations created in only one agreed-upon branch (e.g. master).
But if you got into this situation, here's a way to resolve it gracefully:
|--- C1 ----- [branch 1]
|--- C2 ----- [branch 2]
Merge b2 and C1, b1 and C2
Run C1's migration on b2, C2's migration on b1
merge the branches
If at some point you end up with migrated and unmigrated code in a single branch, do not worry, we have your back. The Pre-Update Check action (Main Menu | Migration | Run Pre-Update Check) triggers an action that asks all available migrations to check whether the code is fully migrated. If nodes written using the old language versions have been merged into an already migrated branch from an un-migrated branch, these nodes will be detected and the user is offer the possibility to re-run the corresponding migrations.
Possible problems with Node IDs
If a migration sets new IDs to the migrated nodes then running migrations in two branches in parallel and then merging the two branches will result in conflicts of the migrated code.
If a migration creates new nodes and sets their IDs to values that are random, then separate migration of two branches and then merging them will end up with conflicts again.