Combining Changes and Conflict Resolution

Last modified: September 9, 2024

Introduction

While working on your changes you may find that your local copy of the app model doesn’t have all the changes that other team members have committed to the server (the Mendix Team Server, or an on-premises server). In Git terminology this is called ‘being behind’.

When this happens, Mendix Studio Pro offers two ways to combine your changes with changes from the server: Rebase and Merge commit.

Both options support the following features when it comes to resolving the conflicts:

  • Fine-grained conflict resolution – When there are conflicting changes in a document, you do not have to choose between whole documents, resolving a conflict using your change or using their change. Instead, you can resolve conflicts at the level of individual elements, such as widgets, entities, attributes, or microflow actions. All non-conflicting changes from both sides are accepted automatically.
  • No conflicts on changes to lists of widgets – When two developers make changes to widgets in the same document there is no conflict, the changes are combined. However, if the changes are made too close to the same place in the document, a list order conflict is reported that reminds the developer who is merging the changes to decide on the final order of the widgets in the list.
  • Can be aborted at any time. Studio Pro will continue from your latest local commit.

The differences between the two approaches are as follows:

  • Rebase (default):
    • Treats changes from the server as leading, by first retrieving the server state and then reapplying your work to it.
    • Results in a simple commit history.
    • Resolves conflicts when reapplying your local commits. If you have 3 local commits, this could trigger conflict resolution 3 times.
  • Merge commit:
    • Treats local and remote changes equally, and combines them in a separate ‘merge commit’.
    • Results in a more complicated commit history with extra merge commits.
    • Resolves conflicts once, regardless of the number of local and remote commits being merged.

Both processes are guided by notification controls showing the actual state and possible next steps.

Scenario

The clearest way to explain and illustrate the differences between Rebase and Merge commit when combining changes, is to examine an example scenario. The sections Rebase and Merge commit show how the two approaches work.

Starting Point

There are two entities User and Game which you have added to the domain model of your project.

The User entity includes string attributes E_mail and Second_E_mail.

Local Changes, Your Work

During your work you make two changes, each one in separate commit.

In the first commit you rename E_mail to Email

In the next commit you rename Second_E_mail to Second_Email to be consistent with previous change.

Server Changes

In the meantime, your colleague also decided to make some changes to both email fields. They have renamed E_mail to EmailAddress and removed Second_E_mail entirely. These changes have been pushed to the server.

Summary

The current situation could be represent as shown below.

Team Server with three commits (1, 2, and 4), while in Studio Pro there are also three commits (1, 3, and 5)

Combining Changes

This section goes through the example scenario with the two different approaches: Rebase and Merge commit.

Every time changes can be combined, for example when pulling changes from the server, you can choose the approach. The default can be changed by adjusting the user preference.

Rebase

Rebasing is the default way to integrate your work with the server changes. It moves your changes to the tip of the changes pulled from the server.

The rebase process is described below, starting with the state described in the example scenario, above.

Rebase Started

After starting the rebase, your two commits (#3 and #5) are temporarily put aside, and Studio Pro shows the latest changes which were pulled from the server (which includes commits #2 and #4).

Resolving the First Conflict

Git tries to apply your first commit (#3) to the tip of the rebasing branch (‘Mine’). The commit will come after commit #4.

If there were no conflicts when comparing your commit (#3) with the latest state from the server (#4), Studio Pro automatically continues. A new commit would be created from your commit, shown as commit #3' in the image below. The process would then continue with the next commit (#5).

In our example, however, there is a conflict as the E_mail attribute was renamed both on the server, and in your local work.

In the Changes pane you can see your change in the ‘Theirs’ column while your colleague’s work is shown in the ‘Mine’ column.

You need to resolve the conflict to proceed with the rebasing process. After resolving the conflict you can amend the current commit message and commit #3' is created.

Now Studio Pro will continue with rebasing the next local commit (#5).

Resolving the Second Conflict

While Rebasing the next commit (#5) another conflict is detected. You can choose to resolve this conflict using either ‘Theirs’ or ‘Mine’ or reverting to the original.

You can also make additional changes which are added to the same commit. For example you can add another attribute Login, to the User entity. These changes will be represented as ‘Mine’, together with changes that were taken from the server.

Once the conflict is resolved and you continue the rebase, a new commit (#5') is created from your commit (#5), and you can optionally amend the commit message.

As this was the last local commit to reapply, the rebasing can now be completed.

Test Changes

Once the rebase process is completed, the original commits (#3 and #5) that were put aside are now removed. The final state of the branch has the commits #1, #2, #4, #3', and #5', while the server still only has commits #1, #2, and #4.

Your work is still on your local machine and you should test whether the combined state works as expected.

Push Changes

After testing the merged changes, push your work to the server to set the server state to the same as your local state.

Merge Commit

Merge commit is an alternative way to integrate your work with remote changes. The combined state is committed using a separate special merge commit.

The merge commit process is described below, starting with the state described in the example scenario, above.

Merge Started

After starting the merge process Studio Pro will combine your local work (#3 and #5) with the state of the server (#2 and #4).

In the end you’ll be creating a merge commit that merges commits #2 and #4 into your work. The changes already in your local work (#3 and #5) are kept.

Conflict Resolution: Resolving the Two Conflicts

If conflicts arise between any local and remote commits, you must resolve them before creating the merge commit for the combined state. Unlike rebasing, which requires conflict resolution for each local commit with conflicts, here you have only one round of conflict resolution.

Renaming of E_mail attribute

As the E_mail attribute was renamed on both the server and in your local work, you need to decide which changes to retain, or make yet another version. In the Changes pane you can see your change in the ‘Mine’ column while your colleagues’ work is shown in the ‘Theirs’ column.

Removal of Second_E_mail attribute on server

Because the Second_E_mail attribute was removed on the server, while renaming it in your local work, there is another conflict which needs to be resolved.

You can also make additional changes which are added to the same commit. For example you can add another attribute Login, to the User entity.

After resolving all conflicts you can proceed with testing the app.

Test and Push Changes

When the combined state is tested, you can commit the current state of the app. This is a new commit (#6) which will always show that it merged commits #3 and #5.

By default Studio Pro will also push your work to the server when making a commit.

Summary

You have merged your local work with the latest state from the server and resolved all conflicts. For rebasing this meant two rounds of conflict resolution, while for a merge commit you had a single round with all of the conflicts being resolved at the same time.

In the end the history on the server will look like this:

  • After a Rebase:
    All commits in the order #1, #2, #4, #3', and #5'
  • After a Merge commit:
    Commits #1, #2, #4, and #6, with commit #6 including commits #3 and #5

So rebasing results in a simpler commit history, while a merge commit results in an additional commit that will always show as containing another commit or set of commits.

Resolving Conflicts

When you need to resolve conflicts, Studio Pro enables this in two ways:

  • Interactive merge
  • Using whole documents

While explaining resolving of conflicts we will be using merge commit flow. You can resolve conflicts during a rebase in the same way except that ‘Mine’ and ‘Theirs’ are reversed.

Using Interactive Merge

For the conflict, you can inspect the changes and decide which version to apply. Select the line that represents the conflict and choose Resolve using Mine or Resolve using Theirs.

You will see the document update immediately after you click the button. If you are not satisfied with your choice, you can use undo to go back and try another option.

There is a third option to deal with a conflict: Mark as Resolved. This means that you do not choose either side to resolve the conflict and keep things the way they were in the original. Neither of the new text changes will be applied.

Once you have chosen one of the three options to resolve the conflict, green check marks will appear to indicate that this conflict has been dealt with.

Once all conflicts have been resolved, click the Accept and Exit button to finalize the results. The document will be saved and the conflict for that document will be gone. The result is the document that contains changes from both sides and possibly some manual edits.

At any time, you can also choose to abort conflict resolution by clicking the Cancel button. The conflict will remain, and you can resolve it later.

Using Whole Documents

You can resolve conflicted documents too. There are two cause for document conflicts:

  1. One person deletes a document and the other makes a change inside that document.
  2. Both people move a document but to different places in the app tree.

The involved document is marked as conflicted and you can see the reason in the details column of the Changes pane. You can resolve the conflict by one of the following:

  • using my whole document - while merging it will resolve all conflicts in this document using your work
  • using theirs whole document - while merging it will resolve all conflicts in this document using server changes

Notification Controls

While combining changes using either rebase or merge commit, you are shown a notification bar which displays the current status of the process and next available steps.

Shared Controls

The following controls are displayed for both rebases and merge commits.

Abort

The Abort button is visible for almost all steps. It will indicate whether you are aborting a rebase or a merge commit.

Click and confirm this button to stop the combining process and undo all of the changes up to this point. In other words, the status is reset to the point before starting this process.

This has no effect on changes committed to the server, only your local work.

Show Conflicts

The Show conflicts button is only visible when there are conflicts in your application, for example conflicting changes to domain models or microflows.

Click this button to bring the Changes pane into the view, as this is the place where you can resolve this type of conflict.

Show File Conflicts

the Show file conflicts button, in comparison with the Show conflicts button, is shown when there are conflicts in files which are not directly linked to your application.

When clicked, it will open up a pop-up window with a list of all the files that are affected by the update process, with conflicted ones at the top of the list.

You can also use the Show Changes on Disk menu item.

Rebase-Specific Controls

There are some buttons which are only shown when conflicts are found when doing a rebase.

Continue

The Continue button is visible when there are no more conflicts to resolve but there are still other changes to rebase. Click it to resume the rebase process.

Push

The Push button is visible after the rebase has finished successfully and your changes are ready to be pushed to the server. Click it to trigger a push operation.

Examples

Some examples of the rebase notification bar are shown below.

Conflict Detected

Rebase notification bar while there are still conflicts to be resolved.

Rebase notification bar showing one conflict and the Show conflicts, Show file conflicts, and Abort rebase buttons.
Current Step Resolved

Rebase notification bar when conflicts for current step resolved.

Rebase notification bar showing current step is resolved and the Continue and Abort rebase buttons.
Rebase Concluded

Rebase notification bar when whole rebase concluded.

Rebase notification bar showing rebase is complete and the Push button.

Merge-Specific Controls

Commit

The Commit button is visible when there are no more conflicts to resolve, and the merge process is finished.

Click it to opens up the commit dialog with a predefined message indicating that this is a merge commit.

Examples

Some examples of the merge notification bar are shown below.

Conflicts Detected

Merge notification bar while in conflicts phase.

Merge notification bar showing conflicts detected and the Show conflicts, Show file conflicts, and Abort merge buttons.
Merging Complete

Merge notification bar when merge is complete.

Merge notification bar showing merge is complete and the Commit and Abort merge buttons.