Skip to main content

Multiple developers on a project

Many TouchGFX projects involve multiple developers. Two or more developers that access and modify the same resources can be a problem, but if you follow a few best practices, these problems can be reduced and handled.

Before TouchGFX version 4.18, an Excel file was used to hold all text resources (translations). This was a problem in projects with multiple developers since the Excel file cannot be merged, if two users both added or changed a text. Texts had to be manually copied between various Excel sheets.

From TouchGFX version 4.18, an XML document is used to hold the texts. This XML file can in most cases be merged using standard text tools.

Conflicts can also arise in the .touchgfx file where the TouchGFX Designer saves the UI design. This file is in JSON format and can also be merged using standard tools.

In this section we will see some examples of conflicts in the TouchGFX files and how to solve them.

Other sources of conflicts are the IAR or Keil project files, which we will not discuss here.

Conflicts

Conflicts can arise when two developers modify or add to the same resource. When merging the two changes most tools are not able to tell which of the modifications that shall be kept (if some are to be deleted) or the correct order of the two (if they both are kept).

The general situation is illustrated in the figure below:

Working with two branches

In this example two branches are created from the main branch. The Feature2 branch is merged first in to the main branch. This can give a merge conflict if work is also done on the main branch. Later the Feature1 branch is merged in to the main branch. This can give a conflict if the two feature branches made changes to the same files.

There are four major points of conflicts in a TouchGFX project:

  • TouchGFX UI file (the .touchgfx file)
  • TouchGFX Text Database (the texts.xml file)
  • Ordinary C++ code in the UI and other modules
  • Project files for IDEs

In the next sections we will see how to handle and reduce the problems with conflicts in the TouchGFX files.

The TouchGFX file

The .touchgfx file is where the TouchGFX Designer saves the definition of the UI created in the Designer. This means that if two developers in a project both work with the TouchGFX Designer, they will both make changes to this file, and conflicts can occur.

The .touchgfx file basically consists of two arrays. The first array contains the list of Screens. The second array is the list of Containers.

Here is a very simple project created using the TouchGFX Designer. It consists of one Screen with one Box widget named "box1":

A one screen project

The Screens section of the .touchgfx file is as follows:

    "Screens": [
{
"Name": "Screen1",
"Components": [
{
"Type": "Box",
"Name": "box1",
"Width": 800,
"Height": 480,
"Color": {
"Red": 51,
"Green": 255
}
}
],
"Interactions": []
}
],

The Screens are saved under "Screens", which in this case contains only one Screen definition named Screen1. The Widgets added to Screen1 are found under "Components" inside the Screen. So far we have only added one Widget of type Box named Box1. Various attributes are set on Box1, e.g., Width, Height, and Color. Note that default values are not written to the .touchgfx file, so the "Blue" component of the Color attribute of box1 which is zero is not explicit stated.

Conflict when adding Screens

We will now see in detail why we can get a conflict, when more Screens are added, and how to resolve the conflict.

We take the above project as a starting point for development. Let's make a couple of feature branches:

git checkout -b feature1
git checkout -b feature2

Assume now that developer1 checks out the branch feature1 and adds Screen2. The .touchgfx file now also contains a Screen definition for Screen2, after Screen1.:

    "Screens": [
{
"Name": "Screen1",
...
},
{
"Name": "Screen2",
"Components": [
{
"Type": "Box",
"Name": "box1",
"Width": 800,
"Height": 480,
"Color": {
"Red": 255,
"Green": 255,
"Blue": 255
}
}
],
"Interactions": []
}
],

Assume now that developer2 checks out feature2 and also adds a new Screen (Screen3). His .touchgfx file will look very much like the file above.

The next thing the team wants to do is to merge the two feature branches (assuming they finished their tasks). Let's first merge feature1:

Merging feature1

This merge operation went well. The resulting .touchgfx file is identical to the one in feature1. But when we try to merge in feature2, we are not so lucky:

Merging feature2

Both the feature2 branch and the main branch changed the .touchgfx file, and git was not able to merge the changes. This is because both branches were adding a screen just after Screen1:

Merge conflict in .touchgfx file

The merge conflict shown in WinMerge

There are two problems in this merge. The worst problem is that git tries to merge the two screen definitions (Screen2 and Screen3) into one. We want two whole screen definitions. One after the other. The second problem is that git (and any other version control system) cannot know which Screen you want to have first in main, Screen2 or Screen3. That is up to the developer.

We therefore need to manually merge the changes in the .touchgfx file. Be sure to insert the whole definition of Screen3 (from '{' to '}') after Screen2.

You can use this command to get the Multiple.touchgfx file back to the state before starting the merge:

git checkout --ours Multiple.touchgfx

You can use this command to get the .touchgfx file from feature2:

git show feature2:Multiple1.touchgfx > feature2.touchgfx

Now open feature2.touchgfx and Multiple1.touchgfx in you favorite editor and copy the whole Screen3 definition from feature2.touchgfx to Multiple1.touchgfx. We now have this (remember the commas between the screens):

    "Screens": [
{
"Name": "Screen1",
...
},
{
"Name": "Screen2",
...
},
{
"Name": "Screen3",
...
}
],

After correcting the conflict, we can commit the merge:

git commit -m 'Merged feature2'

Avoid having the project opened in the TouchGFX Designer while merging. If you Save or Generate code (F4) from the Designer it will overwrite the .touchgfx file on the disk (and remove your conflict)!

After merging, you can open the .touchgfx project in TouchGFX Designer and Generate code.

Conflict when adding changing attributes

Conflicts can also arise when two developers change the same property of a widget. Imagine that we create two new feature branches feature3 and feature4 and in both branches change the color of the box in Screen1 to respectively yellow and blue.

Merging feature3 to main is again without problems, but when merging the other feature branch we get a conflict becuase the same lines in the .touchgfx file have been modified:

Merging feature4

Merge conflict in .touchgfx file

The solution here is to decide (by talking to the developers) if you want the property (i.e. the color) from feature3 or feature4. Of course it cannot be both. And it should probably not be mixed (giving a white color). So open the .touchgfx file in your editor or favorite git merge tool and select the lines you want. Here we select the properties from feature3 and get:

        "Name": "Screen1",
"Components": [
{
"Type": "Box",
"Name": "box1",
"Width": 800,
"Height": 480,
"Color": {
"Red": 255,
"Green": 255
}
}
...
Note
The TouchGFX Designer does not include attributes in the JSON file that have the default value. This means that in the above example Blue is not mentioned under "Color" as it has the value "0".

The TouchGFX Text Database file

The TouchGFX Text Database (texts.xml file) can get conflicts that are very similar to what we saw above. Let us take a look at an example. We start by creating a couple of feature branches:

git checkout -b feature5
git checkout -b feature6

We will use feature5 to add a TextArea widget and a text to Screen2, and feature6 to add a TextArea to Screen3. This simulates two developers working on separate Screens.

Assume now that developer1 checks out feature5 and adds a TextArea.

1

Adding a TextArea to Screen2

The TextArea is given a resource ID (1) by the Designer, Screen2Headline, and the text content "Screen 2". When the developer saves the project in the TouchGFX Designer, two files are modified on disk:

Modifications to .touchgfx and .xml files

The developer adds both files and commits. The diff for the texts.xml (see below) shows that we have added a Text XML element with the ID Screen2Headline and a Translation element with the English text. The Text element is inside a new TextGroup element. This element was created by the Designer because we did not put our new text in a specific group:

Modification to assets/texts/texts.xml

The other developer performs similar changes although his text is called Screen3Headline and the text is "My Headline":

Modification to assets/texts/texts.xml in feature6

Again when the features are done they must be merged to main. This is painless for the first branch, feature5, but again we get a conflict when merging feature6. This time in tests.xml:

Conflict in assets/texts/texts.xml when merging in feature6

The .touchgfx file was also changed on main and feature6 since the branch was created, but git was able to merge the change sets, as these changes are in separate places in the file (not in the same Screen). The conflict arises because both changed the first (or last) text in the "Unsorted" TextGroup element:

Conflict in assets/texts/texts.xml when merging in feature6

For this conflict, the order of the texts has no importance, but it is of course mandatory to produce correct XML, so we manually merge the text file to get two full Text elements:

Text conflict resolved

Avoiding conflicts

Some of the conflicts we have seen above can be avoided by following a few simple rules.

  • Always Create new Screens on the main branch. When Screens are created on the main branch it is impossible for two features branches to insert a new Screen in the same place in the .touchgfx file. Don't call the Screens Screen1, Screen2, etc. A common way used by many groups is to create all the Screens (empty in most cases) very early in the project. This is possible if you are given a graphical design for most of the application at project start. If you later need to add a screen consider adding it next to a Screen with a logical connection and not necessarily as the last Screen. This is done by adding the Screen in the Designer and then drag the new screen upwards to its final location.

  • Custom Containers exhibits the same conflicts as the Screens. As the need for a custom container arises during development of a Screen, it is maybe not practical to create the container on main branch in advance. Consider creating the custom container on the main branch, rebase the feature branch to main, and continue development. Another way is to finish the feature branch and rebase to main. A conflict can arise here which can be solved by taking the whole container block as of last commit in the feature branch and manually put that in .touchgfx file while leaving the containers from main unchanged. Now merge to main. The main branch will not see any conflicts.

  • Text conflicts can be reduced by using multiple TextGroups instead of putting all texts in the "Unsorted" group. Here we have created a TextGroup for Screen3 and moved the old text to this group and added a new text (SecondHeadline):

Separate Group for Screen3 texts

Version control systems

When multiple developers are working on a project it is beneficial to use a version control system. For example git, as we used above. This rises the question of which files to save in the version control system in a TouchGFX project?

Tip
General rule: Do not save any file in your version control system that is regenerated by the tools. One way to do this, is by adding those file names to a .gitignore file.

The reason is to avoid confusion when e.g., the .touchgfx file and the files generated from it are changed. Which modification do you keep, if they do not agree. If you get a conflict in the .touchgfx file, you will also get the conflict in the generated files. This means more work to resolve any conflict.

Typical layout of the project root in a TouchGFX Designer project

FolderContentSave in VCS
Coremain.c and other files for initialization. These are regenerated by CubeMX, but it is fine to add code to the marked "User Sections"Yes
DriversThe STM32 HAL and BSP softwareYes
EWARMIAR EWARM project files. The compiler will create subdirectories for compiled files and other output files. These should not be saved.(Yes)
gccARM gcc makefile and linker scriptYes
LIBJPEGGenerated by CubeMX if the LibJPEG middleware is enabledYes
MDK-ARMKeil project files. Do not save any subdirectory(Yes)
MiddlewaresSource code or header files and libraries for any enabled middleware. Including TouchGFXYes
STM32CubeIDECubeIDE project filesYes
TouchGFXSee below

Typical layout of the TouchGFX folder in a project

FolderContentSave in VCS
AppGenerated by CubeMX. Functions to start TouchGFX from main.cYes
assetsFonts, images, and texts for TouchGFXYes
buildCompiler output for ARM and windows gccNo
configConfiguration files for gcc and MSVSYes
generatedFiles generated by TouchGFX tools and Designer. The user.config file contains the path to the TouchGFX installation. These files often results in conflicts if added.No
guiUser code for the Screens. These are generated by the TouchGFX Designer if they are missing.Yes
simulatorSimulator specific codeYes
targetTarget specific code generated by CubeMXYes
application.configConfiguration of image and text formats. Used by the TouchGFX Designer and other tools.Yes
ApplicationTemplate.touchgfx.partVarious information about the project. Generated by CubeMX and read by TouchGFX Designer.Yes
F746TextureMapper.touchgfxThe UI definition created with TouchGFX Designer.Yes

The standard advice is to save all files generated by CubeMX in your version control system. The files generated by the TouchGFX Designer in contrast should not be saved. The reason for this is that in many projects CubeMX is used mainly in the beginning to create a hardware configuration. It is therefore preferable, that you do not need to open CubeMX and generate code after each update from the version control system. A lot more changes are made in the TouchGFX Designer, so many developers will need that application open anyway. So it is no burden to regenerate code from within the TouchGFX Designer.

The validity of this advice depends on your project group. If you have some developers that does not work with the UI, it may be preferable to also commit the TouchGFX/generated folder so they have a more full project directly in the VCS.

Generating TouchGFX code from the command-line

It is possible to regenerate the TouchGFX code from a command-line. A typical use case is a build server or any other CI setup.

A command-line interface is provided by the tgfx.exe tool located in the TouchGFX installation. To regenerate code for the above project, run this command:

d:/TouchGFX/4.20.0/designer/tgfx.exe generate -p TouchGFX/F746TextureMapper.touchgfx

Running this command corresponds to generating code (F4) within the TouchGFX Designer. If you use this command on your build server you can avoid checking in the generated files.

Ignoring specific files

Many version control systems can be configured to ignore specific filenames and folders.

Here is a typical .gitignore for a TouchGFX project:

TouchGFX/build/
TouchGFX/generated/
EWARM/settings/
EWARM/STM32F746/

This ignore list makes git ignore the generated TouchGFX files and any compiled files. We also ignore any user settings files and build output for IAR.