I wrote in the past about importing a Codename One demo from github but I left the whole working with git as an open subject. Mostly because I considered it a bit out of scope for the discussion. I have a section in the free online course about the anatomy of a Codename One application which I completely forgot to upload until I wrote this!
If you want to understand more, I strongly suggest watching that as it explains a lot of the “why” and “how” logic of Codename One project structures. It explains the purpose of every file you see in the project…
The Right Gitignore
We spent yesterday migrating our internal SVN repository (yes we still used SVN internally) to git. The reason we didn’t do it before was historic. We have a 15gb repository for Codename One that includes a lot of history and junk. Git doesn’t work well with large repositories and splitting up the whole thing effectively means discarding history.
We made some attempts at migrating in the past but the scripts would generally fail after 2-3 days of continuous work… So we split up the repositories to smaller ones and made a clean break. While doing that we wrote a lot of gitignore files and this made me think a bit about the whole thing. I think there is a lot of nuance in setting up the right gitignore file and there are a few interesting tradeoffs we should consider.
When we first started committing to git we used something like this for netbeans projects:
*.jar nbproject/private/ build/ dist/ lib/CodenameOne_SRC.zip
Removing the jars, build, private folder etc. makes a lot of sense but there are a few nuances that are missing here…
You will notice we excluded the jars which are stored under lib and we exclude the Codename One source zip. But I didn’t exclude cn1libs… That was an omission since the original project we committed didn’t have cn1libs. But should we commit a binary file to git?
I don’t know. Generally git isn’t very good with binaries but cn1libs make sense. In another project that did have a cn1lib I did this:
*.jar nbproject/private/ build/ dist/ lib/CodenameOne_SRC.zip lib/impl/ native/internal_tmp/
The important lines are
native/internal_tmp/. Technically cn1libs are just zips. When you do a refresh libs they unzip into the right directories under
native/internal_tmp. By excluding these directories we can remove duplicates that can result in conflicts.
I’m not sure if committing the cn1libs is a good choice. It’s something i’m still conflicted about.
I’m generally in favor of committing the res file and it’s committed in the git ignore files above. The res file is at risk of corruption and in that case having a history we can refer to matters a lot.
But the resource file is a bit of a problematic file. As a binary file if we have a team working with it the conflicts can be a major blocker. This was far worse with the old GUI builder, that was one of the big motivations of moving into the new GUI builder which works better for teams.
Still, if you want to keep an eye of every change in the resource file you can switch on the File → XML Team Mode which should be on by default. This mode creates a file hierarchy under the
res directory to match the res file you opened. E.g. if you have a file named
src/theme.res it will create a matching
res/theme.xml and also nest all the images and resources you use in the res directory.
That’s very useful as you can edit the files directly and keep track of every file in git. However, this has two big drawbacks:
It’s flaky – while this mode works it never reached the stability of the regular res file mode
It conflicts – the simulator/device are oblivious to this mode. So if you fetch an update you also need to update the res file and you might still have conflicts related to that file
Ultimately both of these issues shouldn’t be a deal breaker. Even though this mode is a bit flaky it’s better than the alternative as you can literally “see” the content of the resource file. You can easily revert and reapply your changes to the res file when merging from git, it’s tedious but again not a deal breaker.
Building on the gitignore we have for NetBeans the eclipse version should look like this:
.DS_Store *.jar build/ dist/ lib/impl/ native/internal_tmp/ .metadata bin/ tmp/ *.tmp *.bak *.swp *.zip *~.nib local.properties .settings/ .loadpath .recommenders .externalToolBuilders/ *.launch *.pydevproject .cproject .factorypath .buildpath .project .classpath
.DS_Store *.jar build/ dist/ lib/impl/ native/internal_tmp/ *.zip .idea/**/workspace.xml .idea/**/tasks.xml .idea/dictionaries .idea/**/dataSources/ .idea/**/dataSources.ids .idea/**/dataSources.xml .idea/**/dataSources.local.xml .idea/**/sqlDataSources.xml .idea/**/dynamic.xml .idea/**/uiDesigner.xml .idea/**/gradle.xml .idea/**/libraries *.iws /out/ atlassian-ide-plugin.xml
This is by no means the final version of this. These sort of files tend to change over time as more functionality (e.g. Kotlin support) makes its way into Codename One or the respective IDE’s. This can also be impacted by your OS or IDE plugin. Notice I excluded
.DS_Store which is a file Mac OS sometimes creates but I didn’t exclude
Thumbs.db because I don’t use Windows as much.