Source control is an essential part of game development and one that every developer should use. Setting up a repository can be quite a hassle if you don't know what you are doing. Even after it's set up, dealing with merge conflicts, branching, and pulling can be daunting. In this 2 part blog series, I will show you everything you need to work with source control, specifically in GameMaker Studio 2 (GMS2), including:
- Benefits of using source control and how to take advantage of it
- Types of source control
- Useful definitions when working with source control
- Setting up a repository
- Adding team members to repository
- Integration and first commit
- Pull, commit, merge, and push changes
Disclaimer about screenshots: I am using a custom skin in GMS2. The windows and colors may look different from yours, but the options are all the same.
What is source control?
Source control is a tool used to manage changes and versions in software development, hence why it is also referred to as "version control". When working with source control, team members submit their changes and compare them to the changes of others, eventually merging it all together and ending up with a version of the software that includes all the latest information. Doing this by hand is very complicated and prone to error, which is why we have computers help us with this process. It is an essential tool when working with multiple people sharing a codebase, letting everyone work at any time without interfering with anyone else's work.
Benefits of using source control
- Project backup on a server: Whether you are using an online service, or your own server, this will ensure that you will not lose your project if you experience hardware malfunction. Better safe than sorry!
- Team collaboration: Using source control when multiple people are working on the same project is invaluable. Everyone can change any part of the project without the fear or deleting someone else's project. Team Members will have access to the most up-to-date version of the program at all times.
- Finding the origin of a bug: Sometimes we come across bugs we have no idea where to look for them. A good way to narrow down the search for a bug is to revert to an older revision and test if the bug is present. You'll reach a version in which the bug is not there so, helping you pinpoint when the bug was introduced. If you and your team are committing their changes often, you should have a small list of files changed between the version with and without the bug. It is likely that the bug has something to do with the files that were changed in that commit, so now you have a smaller set of files to debug, as opposed to the entire project.
- Reverting to a "Last Good Known Build": You should always have a "Last Good Known Build" of your project. This is especially important to do before events where you will show a DEMO of your game. Either because you are working on some features which are not done yet, or you made last minute changes that ended up introducing bugs, there is nothing worse than trying to show off your project and running into a roadblock. If this happens, revert to your Last Good Known Build and show that one. After the event is over, you can revert to the latest version and keep working, no problem.
Types of source control
There are different source control types, the most common being: Git, Mercurial (HG), Perforce, and SVN. These are subdivided into: distributed (Git and HG) and centralized (Perforce and SVN).
Centralized source controls are great for big projects because the repository storage is at a server. It allows everyone to pull and push changes at will. The downside is that they are slower rely on Internet speed.
Also, you need to check out or lock files before working on them, to prevent other people from modifying the same file. Again, these are great for larger projects, since you don't need to keep a local copy of the repository.
For smaller projects though, the ones we are interested in are the distributed source controls. For these, everyone keeps a local copy of the repository on their computer. This allows members to work on any part of the project. Once they are done with their changes, they can commit and push it (more on these terms later). However, you can run into issues when trying to push or pull changes on the same file as someone else. We call these "merge conflicts" but there are ways to solve them, which we will discuss later.
In this series, we will be working with Git, since it is integrated with GameMaker Studio 2 by default. If you want to use an external tool to work on your repository, Mercurial works too (I used Mercurial while working on INK and HackyZack).
Useful definitions when working with source control
A few concepts that will be used when working with repositories are:
- Commit: Think of this as creating a local "savepoint" for your project. You can revert to any of your commits (revisions) later on.
- Pull: This is when you grab the latest version of the repository from the server and compare it to your local one, meaning your latest commit.
- Conflict: When two people change the same file, and there is no easy solution, the program marks it as a conflict. The developer needs to resolve all conflicts before moving forward.
- Merge: This is the process of fixing all your conflicts. It can be done either by picking your local file, the one on the server, or a mix of both that includes all changes.
- Push: After you fix all the conflicts and merge the files, you send it back to the server by pushing it. This way, others can pull the changes afterward.
Setting up a repository
The two most common websites that allow you to set a repository are Github and Bitbucket. Github is the most popular for open-source projects, but it does not allow you to create private repositories with a free account, and it only works with Git. Bitbucket allows you create unlimited private repositories using Git or Mercurial, for up to 5 members. If your team is larger than 5 members, this may be a slight problem. Bitbucket's pricing model is still cheaper than Github's, so it is still the better choice and the one I use in all my projects.
First, go to http://bitbucket.org and Sign Up or Log In, if you already have an account.
Once you log in and are on your Dashboard, the "Create" button:
From there, you can create a new Repository or a new team. Creating a team is simple, and it is useful if you have many members. Let's go over the menu to create a repository.
The owner can be your own account, or you can choose a team as the owner. Here, I'm making a personal repository, so I'll choose my account. Next, pick a name for your repository. Make sure you select "This is a private repository" and "Git" as the type (Mercurial works too if you plan on using an external tool). Don't worry too much about the advanced settings for now. Afterwards, click on "Create Repository".
Adding team members to a repository
Another thing you may want to do if working with a team is to add users to your Repository. Everyone in your team first needs to create a Bitbucket account. Then, the administrator can click on the Settings > User and group access.
Type the username or email address of each team member and set their privileges to Write or Admin. This allows them to push changes. You can also add them to a group, include that group, and set its access level to Write/Admin. Either option works.
Now let's integrate the repository we created with GameMaker Studio 2.
Integration and first commit
Open GameMaker Studio 2. You don't need to open any projects for now. Go to Files > Preferences. Next, you are going to click on Plugins > Source Control (Git).
You should end up with a screen like this one. Enter your Identity details. Choose a username that your team members will recognize. It doesn't have to be the same one you used in Bitbucket/Github. The email is also irrelevant, but it's good practice to use the same one as the one you use in your account. Next, set your Authentication details by clicking on "Add new User/Pass Authentication".
The Username and Password are the ones you use to log into the repository website. The Repository URL is in a box at the top of your Overview page that says "SSH" and has a text box next to it:
Switch it to HTTPS mode and copy the link inside. If the repository already has content in it, then your URL will include the "git clone" part. Remove it. Your URL should be: https://firstname.lastname@example.org/group/repoName.
At this point, you are in one of two situations:
- You created the repository, but need to push the Initial Commit.
- The repository is already populated and you need to clone it on your computer.
I will explain what to do in both cases.
Case 1: creating the initial commit
Open your project, or make a new one, if you are starting from scratch. Go to your Main Options under your Resources tab. In General > Settings, check the box that says "Enable Source Control".
This will set the source control panel visible on the top bar which shows these options:
The first option creates a local Repository you can use. This is useful if you are working on a personal, solo project, and have a bad Internet connection. A safer way is to have your repository backed up on a server, in case anything happens to your hard drive. The second option, Import Project into Repository, is the one we will use. A prompt asking you to enter the Repository URL will show when you click it. If your identity and authentication information is correct, GameMaker will create an initial commit and push it to the repository. Else, you will get this warning message:
If this happens, go back to the previous step and try again. When everything is working, go to your Bitbucket page and click on Commits:
You should see something like this:
And you are done! Now, what happens when you want to set the repository for another team member or on another computer? This time, the process is simpler.
Case 2: cloning the repository
Open GameMaker Studio 2. On the welcome screen, go to Source Control > Clone Repository. You will get this dialog box:
Go to Bitbucket, copy the HTTPS link and put it in the top box. On the second one, select a local folder to clone your project into. After you do this, it will clone the repository and it will ask you to choose the YYP file for your project to open it. That's all!
Pull, commit, merge, and push changes
Let's explain the standard workflow when using repositories. The most basic loop is:
Make Changes --> Save --> Commit --> Pull --> Merge --> Commit Merge --> Push
The first three are self-explanatory. Work until you reach a good stopping point. Then, save and commit your changes. I try to commit once I finish working on an object or a feature. I recommend committing often so that each version's changes are easier to keep track of. At least, commit once a day. This way, you will always have your work backed up and up to date. When you are ready to commit your build, save and go to Source Control > Commit Changes. You will see a window that looks like this one when committing changes:
The window has 3 sections. Staged changes are the ones you want to commit. Unstaged ones are the files you changed, but may not want to keep those changes. Usually, you will want to click on "Stage All" to make sure all the changes go through though. Last, you can add a Commit Message. This is optional, but I encourage you to add a detailed description. It doesn't have to be long. Detail what you did since your last commit as this will make it easier to find a specific revision.
After you commit your local copy, the next thing you need to do is Pull from the server. This will check for any un-synced changes. If there aren't any changes, you are free to skip the Merge and Commit Merge steps and Push. Yet, if there are changes, a few different things can happen. The easiest scenario to fix is when there are no common changes. In this case, the program will use the recent version of each file. Afterwards, commit again the new version with all the changes in it, and push it. The complications start when you change a file that has already been changed on the server, creating Merge Conflicts. When this happens, a window will pop up with all the conflicting files and 3 options:
- Use Theirs: This option replaces the local file with the one on the repository.
- Use Mine: Same as above, but you pick your local file as the one to keep, which will replace the one on the repository.
- Merge: Selecting this option opens both files using your merge tool. Sometimes the solution is trivial, other times you need to do a lot more work. I can't explain how to solve every merge conflict situation in this post, but I will go through a few in the next section.
After you resolve all the merge conflicts, you are free to commit and push.
TIP: When you pull, you may get a message alerting you that some files changed, and ask you if you want to reload them. This can get annoying. There's a setting in File > Preferences > General Settings called "Automatically reload changed files". Turn it on if you want to skip this dialog box in the future.
To be continued...
This concludes part 1 of the series. I hope you found it useful. In the next section, I will go over the most common merge conflicts and how to solve them (read part 2 of this series here).
I am always willing to help out if you run into any issues with the material covered in the article, or something else related to GMS2. You can contact me by email or on Twitter.
Alejandro Hitti is a videogame Programmer and Designer from Venezuela. Although his background is in C++ and working using custom-made game engines, his two commercial games, INK and HackyZack, were made using GameMaker Studio 1.4. With the release of GameMaker Studio 2, that became his engine of choice. The novelty of GMS2, paired with his knowledge of the previous version, ignited his interest to create tutorials that focus on this new engine.