Guide to working with tgstation as an upstream repository
The information in this article will provide you with the knowledge you need to run and maintain your own "flavor" of /tg/station while retaining the ability to remain up-to-date with the latest
bugs that the /tg/station developers have to offer.
The most important take-away from using multiple Git repositories is this: Watch your commit log. When merging from upstream you don't want to add new commit lines, because these will be added on every pull request you create. The result is that the commit log becomes flooded with "empty commits" (commits which contain no modifications). This also means that you shouldn't use Github to perform pull requests automatically -- only use this feature to create a pull request to another repository, not to get updates for yourself.
Accepting your fate
The first step is accepting your fate, namely that you will never be able to make changes to the main /tg/station source-code without getting merge conflicts, and therefore headaches. If you want to do this you'll have to change your attitude.
When you first check out your repository create a folder for your version. For example, I named mine "nullstation". Note that your folder should be alphabetically AFTER the code folder, or you're gonna have a bad time.
All code and icons you don't share with /tg/ go in that folder. You shouldn't do anything outside that folder (apart from some exceptions listed below) to prevent conflicts between files. You DON'T want want to end up thousands of commits behind and unable to update without spending weeks sorting through all the changes. And since they tend to commit stuff all the time you WILL get out-of-date. My advice is to merge with upstream often to ensure you have the latest changes and don't suddenly have to rewrite all of your custom changes because the entire API's changed. Remember, the people you're dealing with go through UI managers on a bi-quarterly basis. If they're that uncertain about a freaking browser encapsulation problem then expect any and all API's to change at any time.
Contribute as much as possible
I'm not an official member of the /tg/station development team but it's safe to say that if they've accepted my pull requests that they're pretty lenient on what's added so long as it doesn't break things or introduce a bad habit to the codebase. So far they've been willing to play ball and discuss things, though don't expect your pull request to be accepted even if you do everything right because the people in charge _will_ nitpick your changes and _will_ have conflicting opinions about how things need to be done.
I know. Why bother with this at all, right? Well, they are keen to fix bugs and improve the overall game, and unless you've got as much of a backing as they do you're not going to stand a chance.
A brief primer on Git terminology
The main difference between Git and other version control systems is that Git stores the repository on your local computer where other repositories would have them on a central server.
You *commit* your changes to your *local* repository. You then *push* those changes to a *remote* repository.
- Local* is your own computer. *Remote* is a remote server. *Origin* refers to the repository you're likely to push to (your original repository, before you made a local one). *Upstream* refers to your lord and masters, the parent repository which you inherit from.
In the examples below the local repository resides in a folder on your computer, the origin repository is a forked repository on Github that you own, and the upstream repository is the main /tg/station repository.
A *fork* is a copy of another project, potentially with changes. A fork starts off as a duplicate of another project, but may change over time. There are some "forks" of SS13 that have changed so heavily that they're no longer part of the project they forked from, though (for licensing purposes) keep in mind that they did initially start out as a duplicate of the original project.
Now we move on to the tree analogy. A Git repository is like a tree. A tree has branches. A *branch* is a single copy of the source-code. Different branches may have different changes. One may be an entire rewrite of the atmospherics system. Another may be the same game but with only minor map modifications. The *master branch* is your default branch, your initial position within the tree.
Setting up your project in a few easy steps
- If you're not comfortable with Git and running on Windows then I advise to get the TortoiseGit program. It encapsulates a lot of commands in easy-to-use buttons and wizards. When in doubt, bug oranges, tkdrg, Mloc, neersighted or nullquery on IRC (in that order). This guide assumes you're using TortoiseGit.
- Fork from the main /tg/station Github repository. Go to https://github.com/tgstation/-tg-station and hit the "Fork" button.
- You can now check out the repository. To clone a repository:
- Copy the Git URL from your repository
- Create a new folder on your system for your projects (e.x., "My Documents\Projects")
- Right-click your new folder. Then click "Git Clone..."
- The URL should already be visible on a textbox near the top. Just click 'ok' to continue.
- A new folder will have been created, e.x. "My Documents\Projects\-tg-station"
- Rename the "-tg-station" folder to "tgstation". If you don't, running the .dmb directly will run it in ultrasafe mode which will prevent it from reading/writing its own files.
- This next step is very important. Create a new branch for your version. Do this by right-clicking the "tgstation" folder and under the menu option "TortoiseGit" click "Create Branch..."
- You will now have to provide a name for your branch. In my case I named it "ns-master" (shorthand for "nullstation-master"). It doesn't matter what the name is, so long as you're comfortable with it. Note that the standard is to have "master" in the name if it's your main branch. Make sure to tick "Switch to new branch".
- If you forgot to tick "Switch to new branch": right-click the folder, under the "TortoiseGit" menu option search for "Switch/Checkout..." to change to a different branch.
- We'll now push the repository to Github, which will create your branch online. Right-click the folder and click "Git Sync...".
- Set the remote branch to the same name as your branch (you can manually type in the name) and click "Push...". You will now have to provide your login credentials for Github.
- Head over to your repository on Github and confirm that the branch is listed under the list of branches. (The list of branches is the dropdown that says "Branch: master").
- Click the "Branches" tab. Click "Change default branch" and specify your own "master" branch as the default.
You now have the basics set up. In order to commit and push your changes to Github:
- Make changes to the project. I.e., add a new file, modify a file, delete files.
- Right-click the main project folder (the "tgstation" folder) and click "Git Commit..." (the actual name will vary as it will contain the name of the local branch you're committing to)
- Be sure to tick any files that you do want to include and untick any files you don't want to include.
- Type in a message explaining what you changed. This is important if you intend to push your changes to the main /tg/station repository as they'll want a short description of what you did. It's also helpful for you to know, and for the commit logs.
- Click "OK" to commit.
Note that this will only commit changes to your local computer. To push your changes to Github:
- Right-click the main project folder and click "Git Sync..."
- Click "Pull" to ensure you're up-to-date with any changes from the remote server.
- Click "Push" to push your changes. It will ask for your credentials to authorize this action.
Contributing to /tg/station
While plenty of articles offer more detail into this process, note that Github handles this part, so there's virtually no knowledge of Git required to create a pull request.
One thing to note is what is called "topic branches". I've previously explained what a branch is in the Git terminology section. From a technical point-of-view a "topic branch" is no different than a regular branch. The reason they're called "topic branches" is because the branch is intended to handle a particular topic, such as a bug fix or implementing a feature.
The point of splitting everything you do up into branches is to make it easy to submit multiple pull requests to other repositories for each change. If you made all of your changes under the default branch then there is no way to differentiate between your changes when you submit your pull request. Pull requests always submit every change in an entire branch, there's no way to exclude specific commits.
Rebase, or: how to update from /tg/station without losing your modifications
Rebase in a nutshell: start over from the current state of the /tg/station repository, then reapply all of your changes one-by-one. Except instead of doing it manually and losing a lot of time, the process is automated.
In order to perform a rebase for the first time do the following:
- Make sure you have no modifications that you still have to commit, because you'll lose them.
- Right-click your main project folder and click "Git Bash". This will give you a command prompt where you can type Git commands directly.
- Type "git remote -v" and check if you have an "upstream" remote listed.
- If you don't: Type "git remote add upstream https://github.com/tgstation/-tg-station.git". This will add a new remote called "upstream" set to the main /tg/station repository.
Assuming you have done so, use the following commands every time you want to update:
- Type "git fetch upstream" to fetch all the changes from /tg/station.
- Type "git rebase upstream/master" to re-apply your modifications. This will fail if there are conflicts. In that case, type "git rebase upstream/master --continue" after you've resolved the conflict.
Git's "blame" feature
Ok. So you've found a bug in the code. But why is that line there? Who added it, and why? The best way to find out is to use the Git Blame feature. This allows you to point to any line of code and get a commit log for that line of code.
The easiest way to access this view is from Github. Go to the file you want to check, then click the "Blame" button in the top-right corner. Unlike the name suggests, you're not immediately accusing someone of writing something bad, but instead the view will change and split up each block of code with the commit that last changed it. This way, you can determine who is to blame.
Frequency asked questions
I'm leaving this section open for anyone who has any questions. Feel free to add them, and maybe when someone knowledgeable looks at this page they'll update this section with an answer.
- Why don't you use submodules?
- Submodules work by storing the hash of a particular commit in the repository you're working on. This will work. It'll work great, and it'll never fail... assuming you work alone. If you don't, someone else will invariably commit the submodule with the wrong hash and cause it to point to either an outdated or newer version. Then you'll have to undo those changes again.
- Another reason is that while they remove a lot of ballast it becomes impossible to make changes to any files within the submodule without committing those. The only way out is to fork the /tg/station repository, but if you're going to do that then you may as well use the rebase method to remain up-to-date.