Achtung-Achtung! You have been warned – A geeky article on Git and strange behaviour in the Java Swing API ahead!
First Step – Migration to new Git Repositories
Until recently I have used SVN for versioning of my game software, but the other day I talked to one of my colleagues about migrating my repository from SVN to Git. It seemed a natural choice, since Git its the versioning control system of this age and in my new job we work and code on a Linux platform using Git extensively on the command line.
I had some vague hints that I could use Git by calling git svn to clone my old SVN repository. Later that evening I had some time on my hands and started migrating. I don not use the cloud for backup I have several USB devices where I backup my stuff. My original repository is file based of the same reason and has this file based url:
file:///home/username/Android/AndroidRepository
So away to the terminal I went, created a GitOrigins folder for my new Git repositories. My Goal was to split my apps into individual Git repositories. I called git svn just to see what options I had before going ahead, but that didi not go well git: ‘svn’ is not a git command. See ‘git –help’ the terminal responded in its silent clinical way. No problem git-svn is part of the Git core system and can be installed on Ubuntu by calling:
sudo apt-get install git-core git-svn
Just to prepare I titled myself Sir GoogleALot for a period to find some recommendations on how to best procede after my web adventure I was ready to go. Starting with A Dungeon Horror Deed which was implemented with a trunk a folder called ADungeonHorrorDeedPilot/trunk in SVN I invoked my first magic Git conversion command in my GitOrigins folder:
git svn clone file:///home/usernam/Android/AndroidRepository/ADungeonHorrorDeedPilot/trunk
After a lot of conversion output in the terminal, I ended up getting a trunk folder. So now I needed to convince myself that it indeed was a valid Git repository so I installed some nifty Git tools for interactive meddling and started gitk which is a graphical viewer by calling these commands:
sudo apt-get install gitk
sudo apt-get install git-cola
sudo apt-get install git-gui
cd trunk
gitk
gitk is for browsing branches, commits and changes, git-gui as a helper for gitk and git-cola to work with commits and other git activities. Starting gitk showed med that I was in a valid Git repository.
But I wanted to extract the repository with the specific name ADHD, not trunk. I deleted the new trunk folder and invoked git-svn to extract to that specific name:
git svn clone file:///home/username/Android/AndroidRepository/ADungeonHorrorDeedPilot/trunk ADHD
And it went as expected, you can name the repository by adding the name you want at the end of the command as can be seen from the last calls. After this I went ahead and converted the rest of the repositories I had and checked all repositories with gitk for validity and they where ok. So far so good, at this stage I decided to make a zip of GitOrigins and saved it as a backup.
WTF! My origin must be bare!
After cloning all my projects to independent repositories, next i wanted to try out working with the code. As the first thing I made a Work folder and cloned the ADHD repository there by calling:
mkdir Work
cd Work
git clone file:///home/username/GitOrigins/ADHD
cd ADHD
Git has to know who the user is to do its operations this was done with these commands:
git config –global user.name “username”
git config –global user.email “username@gmail.com”
git config –global color.ui ‘auto’
Now for the funny stuff, importing the ADHD project to Eclipse, building it and running it in a virtual Android device. It worked like a charm. However calling git status showed me that i had both a bin and a gen folder containing untracked files. These folders are generated but not needed to be put under version control, so in the best Git style i made a .gitignore file containing:
/bin/*
/gen/*
Now my git status command showed me that only the .gitignore was untracked so I tracked it and comitted it:
git add .gitignore
git commit -a -m “Initial version of ignore file”
No problem, so now to push this local change to the origin in the GitOrigins folder:
git push
But to my horror this failed to begin with. There are two types of Git repositories, bare and non-bare. Bare repositories are a working copies with out the actual files, but contains the Git version of the files in the form of structured changes and hashes, and these are the ones you per default can push your changes to.
To convert an existing working copy to a bare use these commands, for a working copy in a repository called myrepo:
cd myrepo
mv .git ../myrepo.git # renaming just for clarity
cd ..
rm -fr myrepo
cd myrepo.git
git config –bool core.bare true
I made a script containing these commands, that takes the name of the directory as the one argument to do this:
cd ${1}
mv .git ../${1}.git
cd ..
rm -fr ${1}
cd ${1}.git
git config –bool core.bare true
This was used to convert all the folders in my repository directory called
GitOrigins like this:
./make_bare.sh ACurrencyCalculator
./make_bare.sh ADHD
…
Then I could Push 😉
The Sultan of Swing – Aka Weird Bug Solving
After this initial effort I also imported my ADHDEditor project. It all ran smoothly and I only had to ignore a bin directory since the editor is a Java Swing application. So i tried it out and to my horror discovered an undetected bug in my editor. As it turns out I have been a lazy bastard when I made the editor using JOptionPane to create most of my entity editing dialogs. Some of them uses JComboBox to select an entity icon and dynamically show it when a new selection is made in the JComboBox through a cunning listener implementation:
In the code that prepares the JOptionPane I did this to set the JComboBox:
But due to something weird in the Swing API for this listener implementation the icon is not updated when I try to edit a Quest where the first entry in the type ComboBox is selected. Strangely enough I also have a JOptionPane setup for editing monsters but that does not have the same problem. After messing around I ended replacing the setSelectedItem call with this fix:
I solves the problem but is not really a satisfactory fix since I can not can find the core reason for the bug imidiately, but it will have to do for now.
Final Elimination of the Franken Bug
As an aside it just occurred to me that the editor code for different entities can be put into separate classes, making the code even more maintainable. I have started this process with the QuestEditor class. I it will also give me a chance to dig deeper into the problem, because it is easier to test a single class like this.
And testing this way have also enabled me to find the problem. You can not invoke a change listener by selecting and item that already is selected. So I have made a method that updates the Icon that can be called in the listener and be called during the creation of the editing dialog and this solved the problem.
As a follow up here a small week after I wrote this post I can tell that the Editors has been moved to separate class removing some 500 lines from the main class file and at the same time giving a much better overview, making it much easier to maintain.
Leaving stuff better than when I entered always makes me happy 😉