I’m a big fan of Git versioning software, having received rudimentary training at work and getting into using it at home. It not only allows me the great benefit of being able to roll back unwanted changes or branch off into strange experiments, but thanks to GitHub I have backups of all my (recent) code in a format which makes it available to share with other geeks.
In my short history of using Git I have crafted a few guidelines that I follow to make my personal development experience just a little bit better. These guidelines aren’t complicated rules, but more of a description of the mindset I am in when using Git for my personal projects. These reflect a methodology which has evolved over a period of working on my own and I find them useful in keeping myself on track and having some quality control over my own work even when there is nobody else there to scrutinize it.
A small byword before we begin: I’m not sure about the true definition of iterative development, but in my mind it means that you start off with a small project and slowly but surely add components and features, each time ensuring that your modifications don’t break what you are working on. This could mean that you start off with a tech demo and work towards fulfilling a specification or it could just be adding to an existing product to create new and better versions of it. The topic is broad and my personal interpretation is vague and undefined, but in lieu of wasting everybody’s time explaining everything I’ll just leave it as: cutting a big project into smaller tasks that are done one after another.
There is But One Master Branch
What is the master branch anyway? Is it just the branch named “master”? Is it the single branch which all branches merge into before deployment? Is it the single branch that all branches are based on? Sure, it can be all of that, but in my mind it represents the final product. I don’t have a habit of working on multiple branches, especially because I am working by myself, but the master branch is the only one that I push to GitHub and the only one I can really depend on when it comes to showing what I’m working on to others.
In most projects all work is done to reach a single goal, the final product, which should be reflected in the way that Git branches are treated. Working on a separate branch should be done with the intent to merge it into the master branch at some point and you should never have multiple branches that reflect different versions of your program or different final projects that are part of a single ecosystem. When I migrated my Endless YouTube Player from PHP to Javascript there was a temptation to create different branches to hold the different versions, but in the end I understood that the move from PHP to JS was a part of the evolution of the project, and holding on to a stunted PHP version in its own separate branch would just create the illusion of an unfinished new feature being left to die. This is a task that is best left to tags, which are great for keeping track of previous versions of the project for whatever reason.
Push/Merge Only When You are Finished
This makes sense, right? You only merge back into the master branch or push your changes to the central repository once you are finished with what you’re working on. It’s of course up to you to decide what “finished” means, but for me it was when I was working on a specific feature which took me a few hours to complete, spanning over multiple commits.
I use GitHub’s Issues tracker to keep tabs on what fancy features I want to add to the various projects I’m tinkering with and it makes sense to leave any changes I have done in concordance with one of the issues on my local computer and wait until I’ve completed the task before I push it up to GitHub. This only really makes sense when the tasks are small enough to not span over several weeks, because losing my laptop or having the harddisk spontaneously burst into flames would be devastating if I had a month’s worth of work without a backup. However, if you’re breaking up your project into month-long chunks then I can’t really help you.
Every Commit is a Finished Product
This is probably the one which will either incite ire or have you cheering on my pedantic view on iteration; commits, no matter how big or small, result in a finished product that could be deployed and released into the world. This might be a little hard to explain, but it ties in with the previous guideline in the sense that whatever changes you’ve made to your code will not result in any unfinished function or pending changes left for subsequent commits.
If you’ve added a new feature then the feature is ready to be used, even if there is no way to trigger it. If you’re fixing a bug which requires you to change two parts of the program, then one part is changed and made to work with the rest of the program before the other change is implemented. Let me try with an example:
One of the features I was trying to implement in my upcoming puzzle game was the addition of collectibles scattered around the puzzle boards. A part of this feature was to change how the game keeps a player’s score, allowing it to keep track of the amount of moves the player had used to reach the goal as well as the amount of collectibles the user had picked up in that particular level. First I changed the scorekeeping to allow for multiple variables associated with a level, making sure every piece of the game which referenced the scoreboard was aware of this change. This was then committed (with an appropriately descriptive comment) and I moved on to adding the collectibles counter to the scoreboard which was then added to a separate commit.
This may seem like overkill, especially on such a small feature where the difference between the two commits was about 10 minutes of work, but it encapsulates the primary mentality I have when it comes to iterative development. Every task can, and should, be broken down into smaller sub-tasks which are completed sequentially and without affecting the rest of the project. Commits are just a simple way to create a symbolic separation between the sub-tasks and having the commits never break existing functionality or leave an unfinished gap to be filled in later is just good form. Good form results in better code and happier coders. That’s a scientific fact, look it up.
Tagging = Deployment
Depending on what type of project you’re working on, the concept of “deployment” can have many different meanings, but a good rule of thumb is to define it as any time where the project can be seen by people who aren’t directly involved in its creation, whether that be showing it to a client or putting together a demo to post on a social game development website.
The idea behind this guideline is to define the points where the project is production-ready and create a tag on only those instances, as those are the points in time which is it interesting to look back on. You can always go back to any commit you’ve created, such is the beauty of versioning, but, much like the previous guideline, this is a symbolic gesture of “it’s done” that ties in with the iterativeness of the project.
Those are the guidelines I follow, at least so far, and they have served me well, crafting a neat and logical Git history for me to follow. That said, these are based on my experiences with working by myself, so I won’t guarantee that they’d work in large teams that have to deal with bug fixing alongside feature development or some other crazy stuff that geeks get stuck doing when they’d rather be micro-managing their commit messages.