| To do|
Is this completely up-to-date? Officially the development team don't even use SVN anymore, for instance.
GitHub is a source control management site predominately made for hosting open source projects in Git repositories. GitHub hosts several major names in open source software.
SRB2's source code is publicly available on GitHub, and contributions in the form of Pull Requests are reviewed and accepted through there. It is a public outlet for the internal Subversion repository for code in development.
This guide is meant to help existing programmers understand the workflow surrounding Git and GitHub and how to contribute their changes to SRB2 itself.
What is Git, a summary of the workflow
Git is a Distributed version control system that manages software's changes over time. It is used by the vast majority of new open source projects and is extremely flexible as a system, allowing parallel development by many workers and easy merging of changes through that. Distributed means that, unlike Subversion, there is no "central" repository model, and indeed every clone of a repository is a 1:1 copy of its parent, and can also act independently. The benefits of this include retaining the ability to commit without having permissions to push those commits to the origin, which is a useful model for keeping track of the changes an individual programmer makes over time.
In a Git Repo, there are one or more branches which are simply pointers to different commit HEADs. For example, the master branch (default) in a fresh clone of SRB2 will point to the very latest commit, or origin/master's HEAD. You might make an appropriately named branch and checkout it after cloning, such as
fix-netcode using the
git checkout -b fix-netcode.
For most git repo clones, you will have a working directory which pairs with the staging area. In your working directory, you will make changes in the code for your next commit. When a file is ready, you will stage it, using
git add path/to/file.c, which will put the current version of
file.c into staging. Once you've made sure everything is ready, you can commit by using the appropriately named command and a concise message,
git commit -m "Make player behavior consistent across all compilers. Fixes #75". (Without -m, git will prompt you to enter a message, using whatever text editor is defined as default, and that's usually vim which is a whole different beast from this.) This will create a commit object named some SHA1 hex string like 0f2a8b3e8c..., and then set your current branch's HEAD,
fix-netcode, to the new commit. The new commit will have a parent of the old HEAD of
fix-netcode, which defines the family history of the entire codebase – for any commit except the initial commit, there is ancestry leading all the way back.
Once you're happy with the changes you've made and you've ensured it's clean and (mostly) bug-free, you might publish this branch to the public. If you have write access to the repo you cloned from, you would do something like
git push origin fix-netcode, which will automatically create the
fix-netcode branch on the "upstream" or "origin" repo, upload the necessary commit objects, and set
origin/fix-netcode's HEAD to your local branch's HEAD.
Since your code is now published, you may consider creating a pull request on GitHub to the main project. This is done on the GitHub website – you would visit STJr/SRB2, go to the Pull Requests page, create a pull request, and select your branch for merging. This opens discussion for the maintainers of STJr/SRB2 to request changes and analyze whether or not the code is suitable for a merge into master. Suppose that you're the maintainer: you say the commits are clean, so you will do a merge of that branch into master. This will create a new commit object that has two parents, the old HEAD of master, and the HEAD of the merging branch, and likely you will have to correct any conflicting changes in
file.c that other people have made. This is a fairly easy process if you're familiar with the code, but I won't detail it here. Once the merge is made, you'll push that new commit to the origin branch, and GitHub will notice the commits from
fix-netcode had been merged, and automatically mark the pull request as merged and closed. Success! Your code is now part of the game!
Here is some important terminology that you should have a decent understanding of before diving into Git. In parentheses the word's linguistic uses are identified (v – verb, n – noun, etc).
- Clone (v, n). A copy of a repository with all or some history intact. You can freely traverse all commits without an Internet connection with a clone.
- Branch (v, n). A lightweight pointer to a commit, which acts as a divergence from a parent branch. Two different branches can receive commits separately, which means code history is not linear!
- Commit (v, n). The act of, or the object, that defines a set of changes a programmer has made. These usually have one parent commit, but in the case of merge commits, they will have 2 or more. Git internally uses the HEAD commit of a branch to populate your working directory by traversing up the commit history and picking out the newest versions of files available, so that the working directory exactly represents the commit that is its HEAD.
- Reset (v). The act of setting the current branch's HEAD to another commit. You'll usually do a reset if your local master branch is a number of commits behind the upstream master. This can be potentially destructive: if you have commits added to your branch that aren't in the commit you are resetting to, they WILL disappear – there are other tools meant to resolve that situation!
- Merge (v). The act of creating a new commit that "merges" all the changes of one history of commits with another. In some cases, you'll be able to do a "fast-forward" merge, if the current branch is exactly behind the target branch, which does exactly the same as a Reset. Under most circumstances, only a project maintainer should be using this.
- Rebase (v). Taking the commits that you have made on your branch, "rewinding" their changes back to a common parent on the target branch, Resetting to the HEAD of the target branch, and "replaying" your commits on top. This is a special kind of merge that forces a linear history, and because it actively creates new commits to represent the original ones, you should not use this if you have already published code.
- Working directory (n). The directory that represents all the files of the current commit or branch. You'll make your changes here.
- Staging (n). The area where copies of files from the working directory are stored until they are made into a commit object.
- Remote (n). An object which stores a push and pull address. When you use
git clone, git automatically creates a remote called
origin. You'll create a few remotes to point to other people's forks, such as
MonsterIestynpointing to MonsterIestyn's fork.
- Remote branch (n). A special kind of local branch that reflects the state of a remote branch. These are not normally shown to the user but they are useful to know. They follow the name scheme
remote/branch-name, such as
origin/master, within your local repository.
- Fetch (v). Fetching downloads the commits from a remote and stores them in your repo, setting new HEADs to your Remote Branches. You can then merge or rebase on those Remote Branches using the normal commands. Fetching also sets an alias commit name
FETCH_HEADthat you can type in place of the name
origin/master, for example.
- Pull (v). A combination of Fetch and Merge. Because of the merge property, it's usually recommended to Fetch first, to make sure that you will not accidentally create a new merge commit or have to deal with merge conflicts locally.
- Push (v). Pushes commits to the target, setting their new branch HEADs as necessary.
Here are some GitHub-specific terms that you should know:
- Fork (v, n). A GitHub-side clone of a GitHub repo.
- Pull Request (v, n). A request to merge in some changes from a target fork to the receiver fork. Usually you would create this to merge your branch to the master branch. Each fork has their own Pull Requests.
- Issue (n). A bug report, or feature request, along with all associated discussion surrounding it. These are given a unique number. If a commit message says something along the lines of Fixes, Resolves, or Closes #XXX, GitHub will automatically close that issue when the commit is merged into
master! Each fork has their own Issues repo.
Cloning and using the code
The code is hosted at STJr/SRB2. In order to get a useful copy of it, you will have to clone it using a Git client. Here are a few packages that provide a git distribution, and a visual client:
- GitHub for Windows. The official GitHub client for Windows, automatically downloads and manages a Git installation for you, and provides a simple but moderately useful graphical interface for managing clones, branches and creating commits. You will have to use the command line to make the most of this, however.
- GitHub for MacOSX. The equivalent (and better maintained) MacOSX version of the above. Has a fair amount more features, including automatic pull request generation and checking out of other forks.
- Hub. Some additional commands for command line git for GitHub specific functionality, you need git installed separately.
Before cloning the code, you'll want to create your own fork on GitHub of it. Create an account on GitHub, go to the STJr/SRB2 GitHub project page, and click the Fork button in the top right. You'll have a copy of the repo made on your GitHub account, which you will have write access to. That is the fork you'll want to clone from! Otherwise you will not be able to publish your changes.
Use your client to clone the repo. On git command line, it's this:
$ git clone https://Username@github.com/Username/SRB2.git
The GitHub clients will automatically associate a new SSH key with your GitHub account and will instead use ssh://Username@github.com/Username/SRB2.git as the push URL for the
origin remote. But using https, you will be prompted for your GitHub password from the command prompt or terminal instead. Use whatever your GUI client prefers.
At this point, you may also want to create a new remote to point to STJr/SRB2:
$ git remote add STJr git://github.com/STJr/SRB2.git
Or maybe even another person's fork:
$ git remote add MonsterIestyn git://github.com/MonsterIestyn/SRB2.git
You can now fetch changes from them using:
$ git fetch STJr master
and you might consider rebasing on their branch, or merging, or what have you:
$ git rebase STJr/master
Below are some common workflows that you may reference to when you need a little reminder on how things work.
Contributing your in STJr/SRB2
- Get an idea for what you want to fix or improve. Have a plan ready. Know fairly well what you want to do with the code!
- Create fork and pull it (if needed)
- Add a remote to STJr to rebase or reset in case STJr changes (if needed)
- Create branch.
git checkout -b simple-name-describing-topic
- Checkout your new branch (using checkout -b instead of branch does this automatically. useful tip!)
- Code and commit
- When ready to publish, push to origin branch.
git push origin simple-name-describing-topic
- When ready to submit, create a pull request. (Do this on GitHub)
- Name concise, then give a good description about the changes. "Topic to add new functions for Lua"
- Indicate which Issues this fixes ("fixes #36")
- Discussion opens on your changes
- Continue committing and pushing as adjustments are requested/you find other relevant changes
- Pull request is merged? Delete your branch locally and remotely to clean things up.
git checkout master; git branch -d simple-name-describing-topic
- Reset master to upstream/master to get things up to date.
git fetch STJr master; git reset STJr/master