Github гайд: различия между версиями
(Новая страница: «# Git for the SS14 Developer If you've ever followed a hackily written guide to Git or opened up one of the many incredibly bloated modern git GUIs like GitKraken, you probably recognize that Git can be *really confusing*. The purpose of this guide is to give you just the information you need to develop properly for SS14 and give you the resources to learn more if necessary. Here are some more resources for learning about Git: - [The Git-SCM online book](h...») |
Нет описания правки Метка: отменено |
||
Строка 1: | Строка 1: | ||
<h1 id="git-for-the-ss14-developer">Git for the SS14 Developer</h1> | |||
<p>If you've ever followed a hackily written guide to Git or opened up one of the many incredibly bloated modern git GUIs like GitKraken, you probably recognize that Git can be <em>really confusing</em>. The purpose of this guide is to give you just the information you need to develop properly for SS14 and give you the resources to learn more if necessary.</p> | |||
If you | <p>Here are some more resources for learning about Git:</p> | ||
<ul> | |||
Here are some more resources for learning about Git: | <li><a href="https://git-scm.com/book/en/v2">The Git-SCM online book</a></li> | ||
<li><a href="https://www.atlassian.com/git/tutorials/setting-up-a-repository">Atlassian's git guides</a>. Good guides for some more advanced stuff</li> | |||
<li><a href="https://ohshitgit.com/">Oh shit, Git?!</a>, a list of solutions to common git problems. This one will come in handy.</li> | |||
<li><a href="https://learngitbranching.js.org/">Learn Git Branching</a>. This one is interactive, and very in-depth, but you <strong>will have learned Git by the end of it</strong>. Recommended for intermediate Git users.</li> | |||
</ul> | |||
<h2 id="1-setting-up-git-itself">1. Setting up Git itself</h2> | |||
<p>```admonish danger "DO NOT USE GITKRAKEN" | |||
For the love of god do not install GitKraken or GitHub Desktop. I have felt nothing but endless CBT trying to help people using either of them. I know GitKraken looks all professional and GH Desktop is nice and simple but please do not use either of them unless you know what you are doing.</p> | |||
```admonish danger | <pre><code> | ||
For the love of god do not install GitKraken or GitHub Desktop. I have felt nothing but endless CBT trying to help people using either of them. I know GitKraken looks all professional and GH Desktop is nice and simple but please do not use either of them unless you know what you are doing. | If you were following our <span class="hljs-strong">**"Setting up a Development Environment"**</span> guide, you probably already have Git installed. If not, go to [<span class="hljs-string">their website</span>](<span class="hljs-link">https://git-scm.org</span>) and install it now. This will install the Git backend, as well as Git Bash (if you select that option)--one of the many ways you can actually use Git. | ||
If you were following our **"Setting up a Development Environment"** guide, you probably already have Git installed. If not, go to [their website](https://git-scm.org) and install it now. This will install the Git backend, as well as Git Bash (if you select that option)--one of the many ways you can actually use Git. | |||
If you're on Linux, you'll probably just be using Git through your terminal or whichever IDE you've chosen, and chances are you have it installed already. | If you're on Linux, you'll probably just be using Git through your terminal or whichever IDE you've chosen, and chances are you have it installed already. | ||
Строка 21: | Строка 18: | ||
I highly recommend at least trying Git Bash (as will a lot of our developers), but there are friendlier alternatives many use that I'll be showing steps for here as well: | I highly recommend at least trying Git Bash (as will a lot of our developers), but there are friendlier alternatives many use that I'll be showing steps for here as well: | ||
- [TortoiseGit](https://tortoisegit.org/) -- old but gold Git GUI that shows info in the file explorer menu and makes basic stuff a breeze | <span class="hljs-bullet">- </span>[<span class="hljs-string">TortoiseGit</span>](<span class="hljs-link">https://tortoisegit.org/</span>) -- old but gold Git GUI that shows info in the file explorer menu and makes basic stuff a breeze | ||
- [SmartGit](https://www.syntevo.com/smartgit/) -- fully featured Git GUI that's very customizable and simple to use | <span class="hljs-bullet">- </span>[<span class="hljs-string">SmartGit</span>](<span class="hljs-link">https://www.syntevo.com/smartgit/</span>) -- fully featured Git GUI that's very customizable and simple to use | ||
I won't have steps for these (I'm recommending these after I initially wrote this guide) but after trying some more there are other very, very good options: | I won't have steps for these (I'm recommending these after I initially wrote this guide) but after trying some more there are other very, very good options: | ||
- [Fork](https://git-fork.com/) -- fast and extremely ergonomic GUI, my personal favorite. "Non-free", but it's WinRAR-level non-free, so it's basically free. Has support for partial staging of | <span class="hljs-bullet">- </span>[<span class="hljs-string">Fork</span>](<span class="hljs-link">https://git-fork.com/</span>) -- fast and extremely ergonomic GUI, my personal favorite. "Non-free", but it's WinRAR-level non-free, so it's basically free. Has support for partial staging of | ||
- [Sublime Merge](https://www.sublimemerge.com/) -- very similar to Fork, looks and feels great and I've gotten a lot of recommendations for it, though I haven't used it much. Also has support for partial staging. | <span class="hljs-bullet">- </span>[<span class="hljs-string">Sublime Merge</span>](<span class="hljs-link">https://www.sublimemerge.com/</span>) -- very similar to Fork, looks and feels great and I've gotten a lot of recommendations for it, though I haven't used it much. Also has support for partial staging. | ||
Most IDEs have some form of Git integration as well. [<span class="hljs-string">JetBrains Rider</span>](<span class="hljs-link">https://www.jetbrains.com/rider/</span>)'s Git integration is really good (and I personally recommend Rider for everything SS14-development related). I don't recommend Visual Studio's Git integration, because it's.. not very good. | |||
While you're here, install <span class="hljs-code">`Python 3.7+`</span> as well if you don't have it already. You can do that [<span class="hljs-string">here</span>](<span class="hljs-link">https://www.python.org/</span>) for Windows and Mac, and if you're on Linux you almost certainly have Python installed already. If you don't, figure it out yourself, dork! | |||
<span class="xml"><span class="hljs-tag"><<span class="hljs-name">hr</span>></span></span> | |||
<span class="hljs-code">```admonish danger "Name and Email privacy" | |||
When [setting up your `user.name` and `user.email`](https://git-scm.com/book/en/v2/Getting-Started-First-Time-Git-Setup#_your_identity), know that these are publicly displayed on all commits that you create. If you want to keep your information private, you can set `user.name` to your username instead of your real name, and `user.email` to the one provided by GitHub when the [`Keep my email addresses private`](https://github.com/settings/emails#toggle_visibility) setting is checked in [GitHub Email Settings](https://github.com/settings/emails#primary_email_select_label).</span> | |||
</code></pre><p>Now that you have Git installed, I recommend you read up a bit on the basics of it first and get acquainted with whatever git client you're working with, whether its just command-line (Git Bash) or anything else.</p> | |||
<p>We're going to run through the process of setting up a Git environment for Space Station 14 so that you can <strong>contribute code through pull requests, create your own codebase</strong>, or just <strong>check out the history of the project.</strong></p> | |||
<h3 id="1-1-why-are-we-even-using-git-">1.1 Why are we even using Git?</h3> | |||
<p>Git is <strong>version-control software</strong>--basically, it's an easy way to track changes to the code, and manage those changes without headaches. It's an invaluable tool for software development, because it easily lets you make new changes, view different changes, see who made changes, etc. without having to coordinate and tabulate everything yourself.</p> | |||
<p>GitHub is an online service that hosts Git <strong>repositories</strong> (codebases) for easy collaboration. It's perfect for a codebase like SS14, with lots of contributors and lots of history. It also means that we're <em>open-source</em>--anyone can go to our GitHub and download the code!</p> | |||
<h2 id="2-setting-up-your-repositories">2. Setting up your repositories</h2> | |||
<p>Like I said before, a repository is just a codebase. Repositories contain some <strong>branches</strong>, and those branches contain different <strong>commits</strong>. You might have heard of both of these--I'll talk more about them in depth later.</p> | |||
<p>A <strong>remote</strong> repository is just a repository's that's on GitHub. A <strong>local</strong> repository is one that's actually on your computer.</p> | |||
<h3 id="2-1-creating-your-remote-repository">2.1 Creating your remote repository</h3> | |||
<p>First, let's make our own remote repository fork of Space Station 14. You'll need a GitHub account for this, of course. 'Forking' it like this just means you're copying all of the repository's history and changes into your own remote repository so that you can do stuff freely to the code.</p> | |||
<p>Your remote repository doesn't automatically update with changes from the original SS14 repo--you'll have to do that yourself, which I'll talk about later.</p> | |||
<p>Navigate to the <a href="https://github.com/space-wizards/space-station-14">Space Station 14 repository</a> and click here:</p> | |||
<p><img src="https://i.imgur.com/lAHNHdD.png" alt=""></p> | |||
<p>From there, it'll ask you where to fork it and what to name it--just to your regular account, and name it whatever you please! I'd stick with <code>space-station-14</code> if you just want to help out with development, though.</p> | |||
<h3 id="2-2-creating-your-local-repository">2.2 Creating your local repository</h3> | |||
<p>Now, we'll need to download our remote repository onto our computer (<strong>cloning</strong>) so we can add <del>20 pairs of clown shoes to every locker</del> some changes to it. You <em>can</em> technically change your remote repository (GitHub has some nice tools), but having it on your computer means you use IDEs like Visual Studio or Rider to build the game and run tests, as well as handle Git stuff easily.</p> | |||
<p>For every step, there will be screenshots and instructions for Git Bash, SmartGit, and TortoiseGit on Windows.</p> | |||
<p>Navigate to somewhere on your computer where you want to put the local repository, and:</p> | |||
<details><summary>TortoiseGit</summary> | <details><summary>TortoiseGit</summary> | ||
<p> | <p> | ||
Right click to see TortoiseGit | Right click to see TortoiseGit's context menu stuff: | ||
<img src="https://i.imgur.com/QGmrQmH.png" alt=""> | |||
</p> | </p> | ||
Строка 90: | Строка 67: | ||
Open up SmartGit and navigate to the desired location, then: | Open up SmartGit and navigate to the desired location, then: | ||
<img src="https://i.imgur.com/C3JBYR6.png" alt=""> | |||
</p> | </p> | ||
Строка 100: | Строка 77: | ||
Right click: | Right click: | ||
<img src="https://i.imgur.com/kIYnm16.png" alt=""> | |||
</p> | </p> | ||
Строка 107: | Строка 84: | ||
<hr> | <hr> | ||
Then, we | <p>Then, we'll enter the command for cloning <strong>our</strong> remote repository--not the <code>space-wizards/space-station-14</code> repository.</p> | ||
<details><summary>TortoiseGit</summary> | <details><summary>TortoiseGit</summary> | ||
<p> | <p> | ||
<img src="https://i.imgur.com/3HzCnjm.png" alt=""> | |||
<img src="https://i.imgur.com/a7vhKcC.png" alt=""> | |||
Строка 122: | Строка 98: | ||
<p> | <p> | ||
<img src="https://i.imgur.com/YyJm5fx.png" alt=""> | |||
Строка 131: | Строка 107: | ||
<p> | <p> | ||
<img src="https://i.imgur.com/Xn4AQLf.png" alt=""> | |||
Then | Then <strong>c</strong>hange <strong>d</strong>irectory using: | ||
<code>cd space-station-14</code> | |||
(This may be different if you cloned another fork, it | (This may be different if you cloned another fork, it's almost always being the same as the repository name) | ||
Every Git command will look something like this-- | Every Git command will look something like this--<code>git</code> and then a keyword like <code>add</code>, <code>commit</code>, <code>pull</code>, etc. | ||
</p> | </p> | ||
Строка 145: | Строка 121: | ||
<hr> | <hr> | ||
After this completes, you have a local repository that you can now modify! There | <p>After this completes, you have a local repository that you can now modify! There's still some more setup to go through, though.</p> | ||
<h3 id="2-3-submodule-woes">2.3 Submodule woes</h3> | |||
<p><strong>Pay attention to this!</strong> If you don't do this, you'll get a lot of weird errors about stuff not being available when you actually try to build the game.</p> | |||
<p>Space Station 14 has a <em>lot</em> of submodules--most notably our engine, RobustToolbox. Submodules are just repositories inside a repository, and they need to be updated manually by you. Or do they?</p> | |||
<p>We have an automatic submodule updater so you don’t have to worry about running <code>git submodule update --init --recursive</code> (the command for manually updating submodules) all the time.</p> | |||
<p>Run <code>RUN_THIS.py</code> inside the repo you downloaded with Python. Preferably from a terminal too (<code>python RUN_THIS.py</code> or <code>python3 RUN_THIS.py</code>). This should take a few seconds so if it instantly stops you probably aren’t using Python 3.7+ or something.</p> | |||
Space Station 14 has a | <p>If you are on Windows and get redirected to the Microsoft Store or encounter a message in your terminal claiming that Python is not installed when you attempt to run the above command, you will need to disable the Microsoft shortcut that might be causing this issue. You can do this by searching for <code>Manage App Execution Aliases</code> in the Windows search and then turning off the two Python references.</p> | ||
<p>If you do want to modify the engine directly however, or you want to update the submodule manually (the auto updating can be a pain occasionally), make a file called DISABLE_SUBMODULE_AUTOUPDATE inside the BuildChecker/ directory.</p> | |||
We have an automatic submodule updater so you don’t have to worry about running | <p>If you ever need to manually update RobustToolbox for whatever reason you can use <code>cd RobustToolbox; git checkout v0.4.87</code>(replace <code>v0.4.87</code> with the latest RobustToolbox release) then you can use <code>cd..\</code> to get back into your SS14 repo. This is also an example of using <code>cd</code> to navigate files from the comfort of your command line.</p> | ||
<h2 id="3-setting-up-remotes">3. Setting up remotes</h2> | |||
Run | <p>When you cloned your remote repository, a <strong>remote</strong> was automatically added to your local repository. <strong>Remotes</strong> are just named URLs to remote repositories that Git keeps track of so you can do stuff like download (pull) new changes to the code or upload (push) code to your forked repository. </p> | ||
<p>In this case, the remote automatically added is called<code>origin</code> and it points to <code>https://github.com/[username-here]/space-station-14</code> (or whatever you named the remote repository).</p> | |||
If you are on Windows and get redirected to the Microsoft Store or encounter a message in your terminal claiming that Python is not installed when you attempt to run the above command, you will need to disable the Microsoft shortcut that might be causing this issue. You can do this by searching for | <p>One issue: we don't have a reference to the original <code>space-wizards/space-station-14</code> remote repository anywhere! How are we supposed to update our local repository without it? So let's make sure we've navigated inside our local repo's folder, and we'll add a new remote:</p> | ||
If you do want to modify the engine directly however, or you want to update the submodule manually (the auto updating can be a pain occasionally), make a file called DISABLE_SUBMODULE_AUTOUPDATE inside the BuildChecker/ directory. | |||
If you ever need to manually update RobustToolbox for whatever reason you can use | |||
When you cloned your remote repository, a | |||
In this case, the remote automatically added is called | |||
One issue: we don | |||
<details><summary>TortoiseGit</summary> | <details><summary>TortoiseGit</summary> | ||
<p> | <p> | ||
<img src="https://i.imgur.com/yANaYWI.png" alt=""> | |||
<img src="https://i.imgur.com/cjbhMEN.png" alt=""> | |||
Строка 184: | Строка 147: | ||
<p> | <p> | ||
<img src="https://i.imgur.com/LXCpgVo.png" alt=""> | |||
<img src="https://i.imgur.com/ZHIHPJC.png" alt=""> | |||
Строка 194: | Строка 157: | ||
<p> | <p> | ||
<img src="https://i.imgur.com/00ETpii.png" alt=""> | |||
</p> | </p> | ||
Строка 201: | Строка 164: | ||
<hr> | <hr> | ||
All this does is add a new remote named | <p>All this does is add a new remote named <code>upstream</code> that points to the original <code>space-wizards/space-station-14</code> repository. Now we can receive updates from the main repository whenever we want! (see below on how to do that). </p> | ||
<p>The convention is to call the remote pointing to the original repository <code>upstream</code> but you can technically call it whatever you like. I'll be referring to it as 'the upstream', though, and it's terminology Git guides use as well.</p> | |||
<p><strong>Addendum for fork/downstream developers:</strong> If a downstream repository you wish to contribute to is set up as a direct fork (IE: GitHub shows a "forked from" label underneath the repo's name), then you'll additionally want to add that fork as a remote (but if the fork isn't set up that way, you can ignore this). You can do this in a way similar to how you've added the upstream as a remote (just use the fork's GitHub link as the remote URL), but be sure to substitute the remote name of <code>upstream</code> with any name you deem appropriate. Your own fork does not have to be a fork of the downstream's fork for this; all that matters is that the commit history in the individual branches you push to your own remote line up with the commit history of wherever you're intending to PR your changes to.</p> | |||
<p>```admonish warning title="Before working on your first PR to the space-wizards repo" | |||
Please make sure you read through the <a href="https://github.com/space-wizards/space-station-14/issues/8524">Freezes & Restrictions</a> and ensure your idea does not fall into the freezes or if your PR requires some prerequisite before being made. </p> | |||
<pre><code> | |||
## <span class="hljs-number">4</span>. Branching & Commits | |||
Branches <span class="hljs-keyword">and</span> commits are two <span class="hljs-keyword">of</span> the most important concepts <span class="hljs-keyword">in</span> Git, <span class="hljs-keyword">and</span> most <span class="hljs-keyword">of</span> the work you do will revolve around them. | |||
### <span class="hljs-number">4.1</span> Whats a commit? | |||
Like I mentioned before, **commits** are just packaged up changes <span class="hljs-keyword">to</span> the code. As the developer, you choose which changes go into a commit <span class="hljs-keyword">and</span> <span class="hljs-keyword">when</span> <span class="hljs-keyword">to</span> commit those changes. **Committing** refers <span class="hljs-keyword">to</span> creating a commit, <span class="hljs-keyword">and</span> it essentially makes a save point that you can go back <span class="hljs-keyword">to</span> at any <span class="hljs-built_in">time</span>. | |||
Commits have an author, timestamp, a message, <span class="hljs-keyword">and</span> some code changes attached <span class="hljs-keyword">to</span> them. They also have a really long <span class="hljs-symbol">'commit</span> hash', a unique identifier used <span class="hljs-keyword">to</span> refer <span class="hljs-keyword">to</span> different commits. | |||
Commits are how history <span class="hljs-keyword">is</span> built up<span class="hljs-comment">--you can actually view the history of every single commit made to the SS14 repository from the beginning, which is pretty cool:</span> | |||
Commits are how history is built up--you can actually view the history of every single commit made to the SS14 repository from the beginning, which is pretty cool: | |||
![](https://i.imgur.com/HQDdw6h.png) | ![](https://i.imgur.com/HQDdw6h.png) | ||
(done with `git log --reverse`) | (done <span class="hljs-keyword">with</span> `git log <span class="hljs-comment">--reverse`)</span> | ||
### 4.2 What's a branch? | ### <span class="hljs-number">4.2</span> What<span class="hljs-symbol">'s</span> a branch? | ||
**Branches** are very, very important. They're basically just a list of changes to the code (commits). The default branch is 'master', and all of our servers use that branch to compile the code. | **Branches** are very, very important. They<span class="hljs-symbol">'re</span> basically just a list <span class="hljs-keyword">of</span> changes <span class="hljs-keyword">to</span> the code (commits). The <span class="hljs-keyword">default</span> branch <span class="hljs-keyword">is</span> <span class="hljs-symbol">'master</span>', <span class="hljs-keyword">and</span> <span class="hljs-keyword">all</span> <span class="hljs-keyword">of</span> our servers <span class="hljs-keyword">use</span> that branch <span class="hljs-keyword">to</span> compile the code. | ||
You're pretty much always 'on a branch' when you're working with your code, and you can switch which branch you're working on easily. | You<span class="hljs-symbol">'re</span> pretty much always <span class="hljs-symbol">'on</span> a branch' <span class="hljs-keyword">when</span> you<span class="hljs-symbol">'re</span> working <span class="hljs-keyword">with</span> your code, <span class="hljs-keyword">and</span> you can switch which branch you<span class="hljs-symbol">'re</span> working <span class="hljs-keyword">on</span> easily. | ||
Generally, branches are named for whatever you're going to be working on in them, but it doesn't *really* matter what they're named. | Generally, branches are named <span class="hljs-keyword">for</span> whatever you<span class="hljs-symbol">'re</span> going <span class="hljs-keyword">to</span> be working <span class="hljs-keyword">on</span> <span class="hljs-keyword">in</span> them, but it doesn<span class="hljs-symbol">'t</span> *really* matter what they<span class="hljs-symbol">'re</span> named. | ||
You can make as many branches as you like. When you create a branch, it 'branches out' (no shit, really?) from the current branch you're on and becomes its own independent thing you can add commits to. | You can make as many branches as you like. <span class="hljs-keyword">When</span> you create a branch, it <span class="hljs-symbol">'branches</span> <span class="hljs-keyword">out</span>' (no shit, really?) from the current branch you<span class="hljs-symbol">'re</span> <span class="hljs-keyword">on</span> <span class="hljs-keyword">and</span> becomes its own independent thing you can add commits <span class="hljs-keyword">to</span>. | ||
![](https://i.imgur.com/ByMugxu.png= | ![](https://i.imgur.com/ByMugxu.png=<span class="hljs-number">500</span>x300) | ||
In this diagram, each little node is a different commit, and each color is a different branch. | <span class="hljs-keyword">In</span> this diagram, each little node <span class="hljs-keyword">is</span> a different commit, <span class="hljs-keyword">and</span> each color <span class="hljs-keyword">is</span> a different branch. | ||
#### Branch merging | #### Branch merging | ||
Branches are important because they can be **merged** together. This is how features are integrated into the main `master` branch. A **merge** just means 'take the special commits from this branch, and apply them to another branch'. You can merge any two branches together. | Branches are important because they can be **merged** together. This <span class="hljs-keyword">is</span> how features are integrated into the main `master` branch. A **merge** just means <span class="hljs-symbol">'take</span> the special commits from this branch, <span class="hljs-keyword">and</span> apply them <span class="hljs-keyword">to</span> another branch'. You can merge any two branches together. | ||
Sometimes this doesn't go well, because both branches modify the same part in a file in contradictory ways, in which case you'll get a **merge conflict**--more on that in the addendums. | Sometimes this doesn<span class="hljs-symbol">'t</span> go well, because both branches modify the same part <span class="hljs-keyword">in</span> a <span class="hljs-keyword">file</span> <span class="hljs-keyword">in</span> contradictory ways, <span class="hljs-keyword">in</span> which <span class="hljs-keyword">case</span> you<span class="hljs-symbol">'ll</span> get a **merge conflict**<span class="hljs-comment">--more on that in the addendums.</span> | ||
GitHub pull requests are really a 'merge request'--you're saying that you want to merge the commits on your branch into another branch, usually their `master`. More on that later. | GitHub pull requests are really a <span class="hljs-symbol">'merge</span> request'<span class="hljs-comment">--you're saying that you want to merge the commits on your branch into another branch, usually their `master`. More on that later.</span> | ||
Pull requests show all this info very well: | Pull requests show <span class="hljs-keyword">all</span> this info very well: | ||
![](https://i.imgur.com/YAOWX5R.png) | ![](https://i.imgur.com/YAOWX5R.png) | ||
![](https://i.imgur.com/nWWy3J4.png) | ![](https://i.imgur.com/nWWy3J4.png) | ||
In this pull request, Swept started out by creating a new branch. Since he now had a fresh branch free of interference to work with, he started working on the feature and created commits to 'save his progress' whenever he felt it was necessary. These commits were added to the branch sequentially, and you can see the evolution of the branch as more code was written. We'll talk more about pull requests later. | <span class="hljs-keyword">In</span> this pull request, Swept started <span class="hljs-keyword">out</span> by creating a <span class="hljs-keyword">new</span> branch. Since he now had a fresh branch free <span class="hljs-keyword">of</span> interference <span class="hljs-keyword">to</span> work <span class="hljs-keyword">with</span>, he started working <span class="hljs-keyword">on</span> the feature <span class="hljs-keyword">and</span> created commits <span class="hljs-keyword">to</span> <span class="hljs-symbol">'save</span> his progress' whenever he felt it was necessary. These commits were added <span class="hljs-keyword">to</span> the branch sequentially, <span class="hljs-keyword">and</span> you can see the evolution <span class="hljs-keyword">of</span> the branch as more code was written. We<span class="hljs-symbol">'ll</span> talk more about pull requests later. | ||
#### But whyyy? | #### But whyyy? | ||
Okay, technically, sure, you can just do all of your work on the `master` branch and pull request from there. But, creating different branches makes it easy to understand where you are, how many changes you've made, and it makes it possible to work on multiple features at once. | Okay, technically, sure, you can just do <span class="hljs-keyword">all</span> <span class="hljs-keyword">of</span> your work <span class="hljs-keyword">on</span> the `master` branch <span class="hljs-keyword">and</span> pull request from there. But, creating different branches makes it easy <span class="hljs-keyword">to</span> understand where you are, how many changes you<span class="hljs-symbol">'ve</span> made, <span class="hljs-keyword">and</span> it makes it possible <span class="hljs-keyword">to</span> work <span class="hljs-keyword">on</span> multiple features at once. | ||
Also we'll close your PR if it's from your `master` branch (it can very easily cause issues) so don't do it. | Also we<span class="hljs-symbol">'ll</span> close your PR <span class="hljs-keyword">if</span> it<span class="hljs-symbol">'s</span> from your `master` branch (it can very easily cause issues) so don<span class="hljs-symbol">'t</span> do it. | ||
### 4.3 Making and working with branches | ### <span class="hljs-number">4.3</span> Making <span class="hljs-keyword">and</span> working <span class="hljs-keyword">with</span> branches | ||
Making branches is pretty easy. Let's make a new branch called `funny-feature`: | Making branches <span class="hljs-keyword">is</span> pretty easy. Let<span class="hljs-symbol">'s</span> make a <span class="hljs-keyword">new</span> branch called `funny-feature`: | ||
<details><summary>TortoiseGit</summary> | |||
<p> | |||
![](https://i.imgur.com/OGkblCk.png) | ![](https://i.imgur.com/OGkblCk.png) | ||
![](https://i.imgur.com/ZPfzFcm.png) | ![](https://i.imgur.com/ZPfzFcm.png) | ||
</p> | |||
</details> | |||
<details><summary>SmartGit</summary> | |||
<p> | |||
![](https://i.imgur.com/pK1oyfz.png) | ![](https://i.imgur.com/pK1oyfz.png) | ||
![](https://i.imgur.com/ | ![](https://i.imgur.com/<span class="hljs-number">5</span>MZ6Ocv.png) | ||
</p> | |||
</details> | |||
<details><summary>Git Bash</summary> | |||
<p> | |||
![](https://i.imgur.com/kOc9rfe.png) | ![](https://i.imgur.com/kOc9rfe.png) | ||
You may notice that the bit in parentheses (master) changed to (funny-feature)! Incredible! | You may notice that the <span class="hljs-built_in">bit</span> <span class="hljs-keyword">in</span> parentheses (master) changed <span class="hljs-keyword">to</span> (funny-feature)! Incredible! | ||
The `-b` in `git checkout` here means 'checkout this branch, and create it if it doesn't exist.' | The `-b` <span class="hljs-keyword">in</span> `git checkout` here means <span class="hljs-symbol">'checkout</span> this branch, <span class="hljs-keyword">and</span> create it <span class="hljs-keyword">if</span> it doesn<span class="hljs-symbol">'t</span> exist.' | ||
</p> | |||
</details> | |||
<hr> | |||
Now, you can work freely with this branch as you please without fear of messing up your all-important master branch. | Now, you can work freely <span class="hljs-keyword">with</span> this branch as you please without fear <span class="hljs-keyword">of</span> messing up your <span class="hljs-keyword">all</span>-important master branch. | ||
Switching between branches is pretty easy: it's called **checking out** a branch. When you do this, your files and folders locally will be changed to match the branch, so Git will yell at you if you have local changes and you try to check out. | Switching between branches <span class="hljs-keyword">is</span> pretty easy: it<span class="hljs-symbol">'s</span> called **checking <span class="hljs-keyword">out</span>** a branch. <span class="hljs-keyword">When</span> you do this, your files <span class="hljs-keyword">and</span> folders locally will be changed <span class="hljs-keyword">to</span> match the branch, so Git will yell at you <span class="hljs-keyword">if</span> you have local changes <span class="hljs-keyword">and</span> you try <span class="hljs-keyword">to</span> check <span class="hljs-keyword">out</span>. | ||
Checking out a branch: | Checking <span class="hljs-keyword">out</span> a branch: | ||
<details><summary>TortoiseGit</summary> | |||
<p> | |||
![](https://i.imgur.com/UThKrCK.png) | ![](https://i.imgur.com/UThKrCK.png) | ||
</p> | |||
</details> | |||
<details><summary>SmartGit</summary> | |||
<p> | |||
![](https://i.imgur.com/fzC1pVm.png) | ![](https://i.imgur.com/fzC1pVm.png) | ||
</p> | |||
</details> | |||
<details><summary>Git Bash</summary> | |||
<p> | |||
![](https://i.imgur.com/DqWEdY5.png) | ![](https://i.imgur.com/DqWEdY5.png) | ||
</p> | |||
</details> | |||
<hr> | |||
Then, make whatever local changes you want! It doesn't really matter. Make a new file, delete everything, change one line in a file, etc. It won't affect your `master` branch, because this is`funny-feature` land now! | <span class="hljs-keyword">Then</span>, make whatever local changes you want! It doesn<span class="hljs-symbol">'t</span> really matter. Make a <span class="hljs-keyword">new</span> <span class="hljs-keyword">file</span>, delete everything, change one <span class="hljs-literal">line</span> <span class="hljs-keyword">in</span> a <span class="hljs-keyword">file</span>, etc. It won<span class="hljs-symbol">'t</span> affect your `master` branch, because this <span class="hljs-keyword">is</span>`funny-feature` land now! | ||
### 4.4 Staging and committing changes to your branch | ### <span class="hljs-number">4.4</span> Staging <span class="hljs-keyword">and</span> committing changes <span class="hljs-keyword">to</span> your branch | ||
One more important thing: Before you can `commit` your changes, you have to `add` your changes to the **staging area**. All this means is that you're specifying which files you want to commit. This is helpful, because you *almost never* want to commit submodule changes, so you avoid that by not adding them to the staging area. | One more important thing: Before you can `commit` your changes, you have <span class="hljs-keyword">to</span> `add` your changes <span class="hljs-keyword">to</span> the **staging area**. <span class="hljs-keyword">All</span> this means <span class="hljs-keyword">is</span> that you<span class="hljs-symbol">'re</span> specifying which files you want <span class="hljs-keyword">to</span> commit. This <span class="hljs-keyword">is</span> helpful, because you *almost never* want <span class="hljs-keyword">to</span> commit submodule changes, so you avoid that by <span class="hljs-keyword">not</span> adding them <span class="hljs-keyword">to</span> the staging area. | ||
As mentioned before, commits always come with a message, which is just a short, imperative description of what's being done in that commit. Or you can be a chad and name every commit "changes stuff", up to you. | As mentioned before, commits always come <span class="hljs-keyword">with</span> a message, which <span class="hljs-keyword">is</span> just a short, imperative description <span class="hljs-keyword">of</span> what<span class="hljs-symbol">'s</span> being done <span class="hljs-keyword">in</span> that commit. <span class="hljs-keyword">Or</span> you can be a chad <span class="hljs-keyword">and</span> name every commit <span class="hljs-string">"changes stuff"</span>, up <span class="hljs-keyword">to</span> you. | ||
If you want to see what you've currently changed, and what's in the staging area, it's pretty easy: | <span class="hljs-keyword">If</span> you want <span class="hljs-keyword">to</span> see what you<span class="hljs-symbol">'ve</span> currently changed, <span class="hljs-keyword">and</span> what<span class="hljs-symbol">'s</span> <span class="hljs-keyword">in</span> the staging area, it<span class="hljs-symbol">'s</span> pretty easy: | ||
<details><summary>TortoiseGit</summary> | |||
<p> | |||
![](https://i.imgur.com/xmZKKWJ.png) | ![](https://i.imgur.com/xmZKKWJ.png) | ||
TortoiseGit also shows changed files/folders (a red icon in the bottom right) in the Windows Explorer which is really nice and why I have it installed in the first place. | TortoiseGit also shows changed files/folders (a red icon <span class="hljs-keyword">in</span> the bottom right) <span class="hljs-keyword">in</span> the Windows Explorer which <span class="hljs-keyword">is</span> really nice <span class="hljs-keyword">and</span> why I have it installed <span class="hljs-keyword">in</span> the first place. | ||
</p> | |||
</details> | |||
<details><summary>SmartGit</summary> | |||
<p> | |||
![](https://i.imgur.com/ROsurs1.png) | ![](https://i.imgur.com/ROsurs1.png) | ||
This is assuming you installed SmartGit with the option that the main window shows diffs and status. If you didn't, I don't really know where it is. | This <span class="hljs-keyword">is</span> assuming you installed SmartGit <span class="hljs-keyword">with</span> the option that the main window shows diffs <span class="hljs-keyword">and</span> status. <span class="hljs-keyword">If</span> you didn<span class="hljs-symbol">'t</span>, I don<span class="hljs-symbol">'t</span> really know where it <span class="hljs-keyword">is</span>. | ||
</p> | |||
</details> | |||
<details><summary>Git Bash</summary> | |||
<p> | |||
![](https://i.imgur.com/UeMjAHj.png) | ![](https://i.imgur.com/UeMjAHj.png) | ||
</p> | |||
</details> | |||
<hr> | |||
Now that you've verified that all of these changes look good, we'll add them to the staging area and commit them (some Git GUIs do this in one step) | Now that you<span class="hljs-symbol">'ve</span> verified that <span class="hljs-keyword">all</span> <span class="hljs-keyword">of</span> these changes look good, we<span class="hljs-symbol">'ll</span> add them <span class="hljs-keyword">to</span> the staging area <span class="hljs-keyword">and</span> commit them (some Git GUIs do this <span class="hljs-keyword">in</span> one step) | ||
<details><summary>TortoiseGit</summary> | |||
<p> | |||
![](https://i.imgur.com/ltIASro.png) | ![](https://i.imgur.com/ltIASro.png) | ||
![](https://i.imgur.com/BIa9r6c.png) | ![](https://i.imgur.com/BIa9r6c.png) | ||
</p> | |||
</details> | |||
<details><summary>SmartGit</summary> | |||
<p> | |||
![](https://i.imgur.com/RYUL7u3.png) | ![](https://i.imgur.com/RYUL7u3.png) | ||
![](https://i.imgur.com/Du7HqRV.png) | ![](https://i.imgur.com/Du7HqRV.png) | ||
</p> | |||
</details> | |||
<details><summary>Git Bash</summary> | |||
<p> | |||
![](https://i.imgur.com/mpKk5L1.png) | ![](https://i.imgur.com/mpKk5L1.png) | ||
</p> | |||
</details> | |||
<hr> | |||
Woo, we've committed our changes to a branch! Now that they're committed, they're in the history of the branch forever (sort of). We can do a lot of things now: merge our `funny-feature` into our local `master` branch (if we wanted, for some reason), upload (push) our `funny-feature` branch to our remote repository, or nuke the branch entirely (among other things). We'll opt for pushing the branch and making a pull request now. | Woo, we<span class="hljs-symbol">'ve</span> committed our changes <span class="hljs-keyword">to</span> a branch! Now that they<span class="hljs-symbol">'re</span> committed, they<span class="hljs-symbol">'re</span> <span class="hljs-keyword">in</span> the history <span class="hljs-keyword">of</span> the branch forever (sort <span class="hljs-keyword">of</span>). We can do a lot <span class="hljs-keyword">of</span> things now: merge our `funny-feature` into our local `master` branch (<span class="hljs-keyword">if</span> we wanted, <span class="hljs-keyword">for</span> some reason), upload (push) our `funny-feature` branch <span class="hljs-keyword">to</span> our remote repository, <span class="hljs-keyword">or</span> nuke the branch entirely (among other things). We<span class="hljs-symbol">'ll</span> opt <span class="hljs-keyword">for</span> pushing the branch <span class="hljs-keyword">and</span> making a pull request now. | ||
## 5. Pushing and making a PR | ## <span class="hljs-number">5</span>. Pushing <span class="hljs-keyword">and</span> making a PR | ||
A **pull request** is a GitHub-specific thing. It just means that you want a codebase to merge your changes on one of your branches into one of their branches--usually to their `master` branch. Before we can do this, our remote GitHub repository (origin) needs to know about the beautiful branches and commits we've created locally, so we upload or **push** those changes to the remote. | A **pull request** <span class="hljs-keyword">is</span> a GitHub-specific thing. It just means that you want a codebase <span class="hljs-keyword">to</span> merge your changes <span class="hljs-keyword">on</span> one <span class="hljs-keyword">of</span> your branches into one <span class="hljs-keyword">of</span> their branches<span class="hljs-comment">--usually to their `master` branch. Before we can do this, our remote GitHub repository (origin) needs to know about the beautiful branches and commits we've created locally, so we upload or **push** those changes to the remote.</span> | ||
### 5.1 Pushing commits | ### <span class="hljs-number">5.1</span> Pushing commits | ||
It's pretty easy to push our changes now that we've committed them. Be aware that, when using these commands, Git is probably going to ask for your GitHub credentials so that it can verify that you're allowed to push to that remote. | It<span class="hljs-symbol">'s</span> pretty easy <span class="hljs-keyword">to</span> push our changes now that we<span class="hljs-symbol">'ve</span> committed them. Be aware that, <span class="hljs-keyword">when</span> using these commands, Git <span class="hljs-keyword">is</span> probably going <span class="hljs-keyword">to</span> ask <span class="hljs-keyword">for</span> your GitHub credentials so that it can verify that you<span class="hljs-symbol">'re</span> allowed <span class="hljs-keyword">to</span> push <span class="hljs-keyword">to</span> that remote. | ||
When pushing changes, we specify the *remote* repository that we're pushing to and the *local* branch that we're pushing. Simple enough. | <span class="hljs-keyword">When</span> pushing changes, we specify the *remote* repository that we<span class="hljs-symbol">'re</span> pushing <span class="hljs-keyword">to</span> <span class="hljs-keyword">and</span> the *local* branch that we<span class="hljs-symbol">'re</span> pushing. Simple enough. | ||
Pushing our branch to our remote repository (origin): | Pushing our branch <span class="hljs-keyword">to</span> our remote repository (origin): | ||
<details><summary>TortoiseGit</summary> | |||
<p> | |||
![](https://i.imgur.com/bWS5Kdk.png) | ![](https://i.imgur.com/bWS5Kdk.png) | ||
![](https://i.imgur.com/Irv1e5k.png) | ![](https://i.imgur.com/Irv1e5k.png) | ||
Selecting 'push all branches' does what it says on the tin. Can be useful. | Selecting <span class="hljs-symbol">'push</span> <span class="hljs-keyword">all</span> branches' does what it says <span class="hljs-keyword">on</span> the tin. Can be useful. | ||
</p> | |||
</details> | |||
<details><summary>SmartGit</summary> | |||
<p> | |||
![](https://i.imgur.com/s82VnNn.png) | ![](https://i.imgur.com/s82VnNn.png) | ||
![](https://i.imgur.com/VP8PuCq.png) | ![](https://i.imgur.com/VP8PuCq.png) | ||
</p> | |||
</details> | |||
<details><summary>Git Bash</summary> | |||
<p> | |||
![](https://i.imgur.com/ | ![](https://i.imgur.com/<span class="hljs-number">7</span>FJqzkL.png) | ||
</p> | |||
</details> | |||
### 5.2 Making a pull request | ### <span class="hljs-number">5.2</span> Making a pull request | ||
Now, the fun part. We'll go to GitHub now and make a pull request for our funny feature. | Now, the fun part. We<span class="hljs-symbol">'ll</span> go <span class="hljs-keyword">to</span> GitHub now <span class="hljs-keyword">and</span> make a pull request <span class="hljs-keyword">for</span> our funny feature. | ||
![](https://i.imgur.com/YNmEMtG.png) | ![](https://i.imgur.com/YNmEMtG.png) | ||
Add a description, a nice title, some screenshots, and hopefully it gets merged. | Add a description, a nice title, some screenshots, <span class="hljs-keyword">and</span> hopefully it gets merged. | ||
## 6. Updating our repository | ## <span class="hljs-number">6</span>. Updating our repository | ||
Maybe it's been a while, a week or two, since your last pull request, and you'd like to make another. Before you do anything, you need to download (**pull**) the code changes from the main SS14 repository into your local repository. If you don't, you'll have out-of-date code and your local changes may not be accurate to how the game will actually run--you might even get **merge conflicts** when you try to PR. | Maybe it<span class="hljs-symbol">'s</span> been a <span class="hljs-keyword">while</span>, a week <span class="hljs-keyword">or</span> two, since your last pull request, <span class="hljs-keyword">and</span> you<span class="hljs-symbol">'d</span> like <span class="hljs-keyword">to</span> make another. Before you do anything, you need <span class="hljs-keyword">to</span> download (**pull**) the code changes from the main SS14 repository into your local repository. <span class="hljs-keyword">If</span> you don<span class="hljs-symbol">'t</span>, you<span class="hljs-symbol">'ll</span> have <span class="hljs-keyword">out</span>-<span class="hljs-keyword">of</span>-date code <span class="hljs-keyword">and</span> your local changes may <span class="hljs-keyword">not</span> be accurate <span class="hljs-keyword">to</span> how the game will actually run<span class="hljs-comment">--you might even get **merge conflicts** when you try to PR.</span> | ||
There are two ways to update your repository. Both methods assume you have the `upstream` remote set up properly--if not, go back to earlier in the guide. And of course, if you're developing for a downstream, then you'll want to substitute `upstream` for whatever you named the downstream repo in step 4, to make sure that you're working with that downstream's files instead of upstream's. Make sure you *always* go through the update process when switching between contributing to a fork, and contributing to upstream, otherwise you'll inevitably end up either PRing the entire history of a downstream to upstream, or making PRs to downstream that immediately conflict. | There are two ways <span class="hljs-keyword">to</span> update your repository. Both methods <span class="hljs-keyword">assume</span> you have the `upstream` remote set up properly<span class="hljs-comment">--if not, go back to earlier in the guide. And of course, if you're developing for a downstream, then you'll want to substitute `upstream` for whatever you named the downstream repo in step 4, to make sure that you're working with that downstream's files instead of upstream's. Make sure you *always* go through the update process when switching between contributing to a fork, and contributing to upstream, otherwise you'll inevitably end up either PRing the entire history of a downstream to upstream, or making PRs to downstream that immediately conflict.</span> | ||
The first method, **fetch+merge**, gives you more control but can be confusing. The second method, **pulling**, is simple and easy but doesn't give you much control. However, pulling is usually all you need. | The first method, **fetch+merge**, gives you more control but can be confusing. The second method, **pulling**, <span class="hljs-keyword">is</span> simple <span class="hljs-keyword">and</span> easy but doesn<span class="hljs-symbol">'t</span> give you much control. However, pulling <span class="hljs-keyword">is</span> usually <span class="hljs-keyword">all</span> you need. | ||
### 6.1 Fetch + merge method | ### <span class="hljs-number">6.1</span> Fetch + merge method | ||
**Fetching** refers to downloading the new branches and commits from a remote repository--but not doing anything with them just yet (nothing locally will be changed). After we fetch changes from our `upstream` remote (the main SS14 repository), we'll merge them into our local `master` branch. | **Fetching** refers <span class="hljs-keyword">to</span> downloading the <span class="hljs-keyword">new</span> branches <span class="hljs-keyword">and</span> commits from a remote repository<span class="hljs-comment">--but not doing anything with them just yet (nothing locally will be changed). After we fetch changes from our `upstream` remote (the main SS14 repository), we'll merge them into our local `master` branch.</span> | ||
When you fetch a remote, it downloads those branches to your local repository and prepends them with the remotes name and a slash. So, when you fetch `upstream`, it'll make a branch called `upstream/master`. As a bonus, you can checkout this remote branch directly if you'd like, and even create a local branch based off it, which is especially useful if you're working with more than just upstream. | <span class="hljs-keyword">When</span> you fetch a remote, it downloads those branches <span class="hljs-keyword">to</span> your local repository <span class="hljs-keyword">and</span> prepends them <span class="hljs-keyword">with</span> the remotes name <span class="hljs-keyword">and</span> a slash. So, <span class="hljs-keyword">when</span> you fetch `upstream`, it<span class="hljs-symbol">'ll</span> make a branch called `upstream/master`. As a bonus, you can checkout this remote branch directly <span class="hljs-keyword">if</span> you<span class="hljs-symbol">'d</span> like, <span class="hljs-keyword">and</span> even create a local branch based off it, which <span class="hljs-keyword">is</span> especially useful <span class="hljs-keyword">if</span> you<span class="hljs-symbol">'re</span> working <span class="hljs-keyword">with</span> more than just upstream. | ||
First, let's fetch from our `upstream` remote. It'll take a little bit to complete. | First, let<span class="hljs-symbol">'s</span> fetch from our `upstream` remote. It<span class="hljs-symbol">'ll</span> take a little <span class="hljs-built_in">bit</span> <span class="hljs-keyword">to</span> complete. | ||
<details><summary>TortoiseGit</summary> | |||
<p> | |||
![](https://i.imgur.com/ | ![](https://i.imgur.com/<span class="hljs-number">3</span>cWun8b.png) | ||
![](https://i.imgur.com/XGgXRY0.png) | ![](https://i.imgur.com/XGgXRY0.png) | ||
Make sure you select `upstream` and not origin! | Make sure you <span class="hljs-keyword">select</span> `upstream` <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> origin! | ||
</p> | |||
</details> | |||
<details><summary>SmartGit</summary> | |||
<p> | |||
![](https://i.imgur.com/CNFFJJ8.png) | ![](https://i.imgur.com/CNFFJJ8.png) | ||
I think smartgit fetches from all remotes when you click this????? | I think smartgit fetches from <span class="hljs-keyword">all</span> remotes <span class="hljs-keyword">when</span> you click this????? | ||
If it doesn't and it just fetches from origin, go to the bottom left and do this: | <span class="hljs-keyword">If</span> it doesn<span class="hljs-symbol">'t</span> <span class="hljs-keyword">and</span> it just fetches from origin, go <span class="hljs-keyword">to</span> the bottom left <span class="hljs-keyword">and</span> do this: | ||
![](https://i.imgur.com/ | ![](https://i.imgur.com/<span class="hljs-number">8</span>rF0tz5.png) | ||
</p> | |||
</details> | |||
<details><summary>Git Bash</summary> | |||
<p> | |||
![](https://i.imgur.com/aJvW9PX.png) | ![](https://i.imgur.com/aJvW9PX.png) | ||
Here nothing happened because I just fetched, but it'll take a while. | Here nothing happened because I just fetched, but it<span class="hljs-symbol">'ll</span> take a <span class="hljs-keyword">while</span>. | ||
</p> | |||
</details> | |||
<hr> | |||
Now, we'll merge those changes we just downloaded into our `master` branch. You don't have to merge into master here; you can merge into another branch, too. If you just wanted to 'fast-forward' update one of your branches to make sure your PR is up to date, you can merge into that branch instead. | Now, we<span class="hljs-symbol">'ll</span> merge those changes we just downloaded into our `master` branch. You don<span class="hljs-symbol">'t</span> have <span class="hljs-keyword">to</span> merge into master here; you can merge into another branch, too. <span class="hljs-keyword">If</span> you just wanted <span class="hljs-keyword">to</span> <span class="hljs-symbol">'fast</span>-forward' update one <span class="hljs-keyword">of</span> your branches <span class="hljs-keyword">to</span> make sure your PR <span class="hljs-keyword">is</span> up <span class="hljs-keyword">to</span> date, you can merge into that branch instead. | ||
Check out the branch you want to merge to. Then, | Check <span class="hljs-keyword">out</span> the branch you want <span class="hljs-keyword">to</span> merge <span class="hljs-keyword">to</span>. <span class="hljs-keyword">Then</span>, | ||
<details><summary>TortoiseGit</summary> | |||
<p> | |||
![](https://i.imgur.com/ | ![](https://i.imgur.com/<span class="hljs-number">8</span>lUaEFt.png) | ||
![](https://i.imgur.com/ | ![](https://i.imgur.com/<span class="hljs-number">7</span>BvBPYY.png) | ||
</p> | |||
</details> | |||
<details><summary>SmartGit</summary> | |||
<p> | |||
![](https://i.imgur.com/n8cc2DN.png) | ![](https://i.imgur.com/n8cc2DN.png) | ||
![](https://i.imgur.com/aRSawAo.png) | ![](https://i.imgur.com/aRSawAo.png) | ||
</p> | |||
</details> | |||
<details><summary>Git Bash</summary> | |||
<p> | |||
![](https://i.imgur.com/H2L8pOp.png) | ![](https://i.imgur.com/H2L8pOp.png) | ||
You can also `git merge upstream/master [branch-to-merge-to] | You can also `git merge upstream/master [branch-<span class="hljs-keyword">to</span>-merge-<span class="hljs-keyword">to</span>] | ||
</p> | |||
</details> | |||
### 6.2 Pull method | ### <span class="hljs-number">6.2</span> Pull method | ||
**Pulling** refers to **fetching** (downloading) the new branches and commits from a remote repository, and then merging them into a branch. Pulling is often easier because Git has a nice system for automatically figuring out which remote you want to fetch from (but it doesn't always work cleanly). | **Pulling** refers <span class="hljs-keyword">to</span> **fetching** (downloading) the <span class="hljs-keyword">new</span> branches <span class="hljs-keyword">and</span> commits from a remote repository, <span class="hljs-keyword">and</span> <span class="hljs-keyword">then</span> merging them into a branch. Pulling <span class="hljs-keyword">is</span> often easier because Git has a nice system <span class="hljs-keyword">for</span> automatically figuring <span class="hljs-keyword">out</span> which remote you want <span class="hljs-keyword">to</span> fetch from (but it doesn<span class="hljs-symbol">'t</span> always work cleanly). | ||
Pulling is usually simpler and a lot easier to do. | Pulling <span class="hljs-keyword">is</span> usually simpler <span class="hljs-keyword">and</span> a lot easier <span class="hljs-keyword">to</span> do. | ||
We'll **pull** from our `upstream` remote (the main SS14 repo) and tell it to merge into our local `master` branch. | We<span class="hljs-symbol">'ll</span> **pull** from our `upstream` remote (the main SS14 repo) <span class="hljs-keyword">and</span> tell it <span class="hljs-keyword">to</span> merge into our local `master` branch. | ||
First, checkout your `master` branch. We covered this earlier. Then, | First, checkout your `master` branch. We covered this earlier. <span class="hljs-keyword">Then</span>, | ||
<details><summary>TortoiseGit</summary> | |||
<p> | |||
![](https://i.imgur.com/XMUt6cv.png) | ![](https://i.imgur.com/XMUt6cv.png) | ||
![](https://i.imgur.com/NHVlZ4W.png) | ![](https://i.imgur.com/NHVlZ4W.png) | ||
</p> | |||
</details> | |||
<details><summary>SmartGit</summary> | |||
<p> | |||
![](https://i.imgur.com/ANqpcph.png) | ![](https://i.imgur.com/ANqpcph.png) | ||
Строка 562: | Строка 521: | ||
![](https://i.imgur.com/k0scDB8.png) | ![](https://i.imgur.com/k0scDB8.png) | ||
</p> | |||
</details> | |||
<details><summary>Git Bash</summary> | |||
<p> | |||
![](https://i.imgur.com/OfHut9Y.png) | ![](https://i.imgur.com/OfHut9Y.png) | ||
</p> | |||
</details> | |||
<hr> | |||
If either method went well, you've successfully updated your master branch (or whichever branch you chose to update)! Do this regularly, and always before you start work on a new branch. | <span class="hljs-keyword">If</span> either method went well, you<span class="hljs-symbol">'ve</span> successfully updated your master branch (<span class="hljs-keyword">or</span> whichever branch you chose <span class="hljs-keyword">to</span> update)! Do this regularly, <span class="hljs-keyword">and</span> always before you start work <span class="hljs-keyword">on</span> a <span class="hljs-keyword">new</span> branch. | ||
# Addendums | # Addendums | ||
## 1. Things to keep in mind | ## <span class="hljs-number">1</span>. Things <span class="hljs-keyword">to</span> keep <span class="hljs-keyword">in</span> mind | ||
You've more or less learned the workflow for developing features for SS14 Git-wise, but here's some things I'd really like to hammer into your mind: | You<span class="hljs-symbol">'ve</span> more <span class="hljs-keyword">or</span> less learned the workflow <span class="hljs-keyword">for</span> developing features <span class="hljs-keyword">for</span> SS14 Git-wise, but here<span class="hljs-symbol">'s</span> some things I<span class="hljs-symbol">'d</span> really like <span class="hljs-keyword">to</span> hammer into your mind: | ||
- When creating a new feature, *always always always* create a new branch off of `master` before committing anything. If you accidentally commit your physics changes to your bike horn branch, you're not in for a fun time, but it is fixable (see Oh Shit, Git?! above) | - <span class="hljs-keyword">When</span> creating a <span class="hljs-keyword">new</span> feature, *always always always* create a <span class="hljs-keyword">new</span> branch off <span class="hljs-keyword">of</span> `master` before committing anything. <span class="hljs-keyword">If</span> you accidentally commit your physics changes <span class="hljs-keyword">to</span> your bike horn branch, you<span class="hljs-symbol">'re</span> <span class="hljs-keyword">not</span> <span class="hljs-keyword">in</span> <span class="hljs-keyword">for</span> a fun <span class="hljs-built_in">time</span>, but it <span class="hljs-keyword">is</span> fixable (see Oh Shit, Git?! above) | ||
- **Never, ever commit RobustToolbox or any submodules like Lidgren.Network** unless you know what you're doing. In the top-level local repository, these submodules are considered 'files', so it's easy to accidentally stage and commit them. Do not do this. See below for how to fix your fuckups if it happens. | - **Never, ever commit RobustToolbox <span class="hljs-keyword">or</span> any submodules like Lidgren.Network** unless you know what you<span class="hljs-symbol">'re</span> doing. <span class="hljs-keyword">In</span> the top-level local repository, these submodules are considered <span class="hljs-symbol">'files</span>', so it<span class="hljs-symbol">'s</span> easy <span class="hljs-keyword">to</span> accidentally stage <span class="hljs-keyword">and</span> commit them. Do <span class="hljs-keyword">not</span> do this. See below <span class="hljs-keyword">for</span> how <span class="hljs-keyword">to</span> fix your fuckups <span class="hljs-keyword">if</span> it happens. | ||
- If you need further help with Git, feel free to ask in the SS14 Discord in #howdoicode. | - <span class="hljs-keyword">If</span> you need further help <span class="hljs-keyword">with</span> Git, feel free <span class="hljs-keyword">to</span> ask <span class="hljs-keyword">in</span> the SS14 Discord <span class="hljs-keyword">in</span> #howdoicode. | ||
## 2. A quick example workflow | ## <span class="hljs-number">2</span>. A quick example workflow | ||
To get everything in your head and to summarize it all, here's an example workflow for making several pull requests using Git Bash commands. | <span class="hljs-keyword">To</span> get everything <span class="hljs-keyword">in</span> your head <span class="hljs-keyword">and</span> <span class="hljs-keyword">to</span> summarize it <span class="hljs-keyword">all</span>, here<span class="hljs-symbol">'s</span> an example workflow <span class="hljs-keyword">for</span> making several pull requests using Git Bash commands. | ||
```python | ```python | ||
git checkout master # Before we create a new branch, we should be on master. | git checkout master # Before we create a <span class="hljs-keyword">new</span> branch, we should be <span class="hljs-keyword">on</span> master. | ||
git fetch upstream # We'll fetch any new changes from the SS14 repo.. | git fetch upstream # We<span class="hljs-symbol">'ll</span> fetch any <span class="hljs-keyword">new</span> changes from the SS14 repo.. | ||
git merge upstream/master # ..and merge them into our master branch. | git merge upstream/master # ..<span class="hljs-keyword">and</span> merge them into our master branch. | ||
git checkout -b my-new-feature # Make a new branch for the feature | git checkout -b my-<span class="hljs-keyword">new</span>-feature # Make a <span class="hljs-keyword">new</span> branch <span class="hljs-keyword">for</span> the feature | ||
...local changes later... | ...local changes later... | ||
git add -A # Add all of our local changes to the staging area | git add -A # Add <span class="hljs-keyword">all</span> <span class="hljs-keyword">of</span> our local changes <span class="hljs-keyword">to</span> the staging area | ||
git commit -m "Fix spaghetti explosions" # Commit them | git commit -m <span class="hljs-string">"Fix spaghetti explosions"</span> # Commit them | ||
git push origin my-new-feature # and push them to our remote | git push origin my-<span class="hljs-keyword">new</span>-feature # <span class="hljs-keyword">and</span> push them <span class="hljs-keyword">to</span> our remote | ||
# Now, I want to work on a different pull request. | # Now, I want <span class="hljs-keyword">to</span> work <span class="hljs-keyword">on</span> a different pull request. | ||
git checkout master | git checkout master | ||
# It hasn't been too long, and nothing important was merged, | # It hasn<span class="hljs-symbol">'t</span> been too long, <span class="hljs-keyword">and</span> nothing important was merged, | ||
# so I won't fetch and merge changes again--just a new branch. | # so I won<span class="hljs-symbol">'t</span> fetch <span class="hljs-keyword">and</span> merge changes again<span class="hljs-comment">--just a new branch.</span> | ||
git checkout -b another-feature | git checkout -b another-feature | ||
...local changes later... | ...local changes later... | ||
git add -A | git add -A | ||
git commit -m "Deletes nuclear operatives" | git commit -m <span class="hljs-string">"Deletes nuclear operatives"</span> | ||
# I committed, but then I realized my commit was entirely wrong | # I committed, but <span class="hljs-keyword">then</span> I realized my commit was entirely wrong | ||
# and i'll take it up later. | # <span class="hljs-keyword">and</span> i<span class="hljs-symbol">'ll</span> take it up later. | ||
git revert HEAD | git revert HEAD | ||
Строка 621: | Строка 580: | ||
...a week later... | ...a week later... | ||
# A lot of new stuff was merged, so let's update our branch. | # A lot <span class="hljs-keyword">of</span> <span class="hljs-keyword">new</span> stuff was merged, so let<span class="hljs-symbol">'s</span> update our branch. | ||
git fetch upstream | git fetch upstream | ||
Строка 628: | Строка 587: | ||
git merge master | git merge master | ||
# Now we'll make changes and push again, this time correctly. | # Now we<span class="hljs-symbol">'ll</span> make changes <span class="hljs-keyword">and</span> push again, this <span class="hljs-built_in">time</span> correctly. | ||
...local changes later... | ...local changes later... | ||
git add -A | git add -A | ||
git commit -m "Adds Highlander gamemode" | git commit -m <span class="hljs-string">"Adds Highlander gamemode"</span> | ||
git push origin another-feature | git push origin another-feature | ||
# Made both PRs, both were merged, so we're done here | # Made both PRs, both were merged, so we<span class="hljs-symbol">'re</span> done here | ||
git checkout master | git checkout master | ||
git branch -d my-new-feature # Delete both old branches | git branch -d my-<span class="hljs-keyword">new</span>-feature # Delete both old branches | ||
git branch -d another-feature | git branch -d another-feature | ||
</code></pre><h1 id="glossary-the-inner-machinations-of-git">Glossary: The Inner Machinations of Git</h1> | |||
<p>Just for reference, here's a little glossary of Git concepts and terms explained in a little more detail, all in one place.</p> | |||
<ul> | |||
<li><strong>'Branches'</strong> are self-contained versions of the codebase that you can add commits to. The default branch is <strong>master</strong>, but you can make as many as you like.</li> | |||
<li><strong>'Repositories'</strong> are essentially just folders where you can use Git to make changes and keep track of changes made. Local repositories are repositories you have on your computer, and remote repositories are repositories that live on websites like <a href="https://github.com/space-wizards/space-station-14">GitHub</a>. Repositories are made up of a lot of branches.</li> | |||
Just for reference, here | <li><strong>'Remotes'</strong> are names for and links to remote repositories that your local repository can use.</li> | ||
<li><strong>'Submodules'</strong> are repositories that are located inside another repository.</li> | |||
<li><strong>'Forks'</strong> are repositories that are based on another repository. If you're going to make a pull request to the SS14 repo, you need to fork it first.</li> | |||
<li><strong>'The working tree'</strong> is just every file and folder and what not that's in the repository.</li> | |||
<li><strong>'Staging'</strong> means adding (with <code>git add</code>) changes from your working tree into the 'staging area', where some actions can be performed on it</li> | |||
<li><strong>'Commits'</strong> are snapshots of the repository's working tree at a given time. Basically a save point. A 'commit' is just a list of files that have been changed from the last commit, and the changes that are 'committed' are the changes that you've 'staged'.</li> | |||
<li><strong>'Checking out'</strong> is the act of switching to another branch so you can mess with it or look at its changes locally.</li> | |||
<li><strong>'Merging'</strong> is the act of integrating the changes from one branch into another branch.</li> | |||
<li><strong>'Merge conflicts'</strong> occur when integrating the changes from one branch into another can't be done automatically because they both change the same area in a file, or their changes are mutually exclusive in some other way.</li> | |||
<li><strong>'Fetching'</strong> means getting the branches and commits of a remote repository, but not actually.. doing anything with them yet. You'll just have them updated for if you want to checkout or merge them later.</li> | |||
<li><strong>'Pulling'</strong> is the act of integrating changes from a remote repository's branch into your local branch.</li> | |||
<li><strong>'Pull requests'</strong> are a GitHub-specific action that allow you to request that your local branch and all of its changes is merged into another repository's branch.</li> | |||
<li><strong>'Pushing'</strong> is the act of integrating your local changes into a remote repository.</li> | |||
</ul> | |||
<p>There are way more commands and concepts than this, but this is all you <em>really</em> need to know for basic development work.</p> | |||
<h1 id="appendix-a-helpful-tips-and-tricks">Appendix A: Helpful tips and tricks</h1> | |||
<p>There's some stuff I didn't cover, but you'll almost inevitably have to do at some point. I'll cover these all <strong>exclusively as git commands in Git Bash</strong> quickly, but they're not too hard to figure out in the other programs (same keywords, just look for those). I recommend using their specific guides because I don't know TortoiseGit / SmartGit / GitKraken / Github Desktop well enough to help you with more advanced stuff.</p> | |||
<p>One note since it comes up a lot here: <strong><code>HEAD</code> is a fancy name for the commit that you're currently on</strong>. Nothing more than that. Branches are also technically fancy names for commits, but you don't need to know that yet.</p> | |||
There are way more commands and concepts than this, but this is all you | <p>A lot of these can be found probably more eloquently in Oh Shit, Git?! (see resources above)</p> | ||
<h2 id="resolving-merge-conflicts">Resolving merge conflicts</h2> | |||
<p><em>WIP i'll write a better guide for this later because it's important</em></p> | |||
<p>A nasty little maintainer has told you to 'resolve conflicts' or your PR 'wont be merged'. What an asshole! Thankfully, it's not too hard.</p> | |||
<p>First, you're going to want to update your local <code>master branch</code>. See above for how to do that.</p> | |||
There | <p>When you run <code>git merge master [local branch]</code>, it'll either do it cleanly (woohoo) or tell you you have to resolve conflicts (wahhhh). </p> | ||
<p>All you need to do to resolve conflicts manually is go into the files that are conflicting, remove all the <code>>>>>HEAD</code> and <code>===== <<<<master</code> nonsense (just notates where the changes originated) and then edit the file so that it properly integrates both sets of changes. Sometimes this is easy, sometimes it's hard. If it's hard, you probably know what you're doing. After that, just <code>git commit</code>.</p> | |||
One note since it comes up a lot here: | <p>Atlassian has a really good guide for this <a href="https://www.atlassian.com/git/tutorials/using-branches/merge-conflicts">here</a></p> | ||
<h2 id="checking-history">Checking history</h2> | |||
A lot of these can be found probably more eloquently in Oh Shit, Git?! (see resources above) | <p><code>git log --oneline</code> is your friend. It shows short commit hashes (unique IDs for commits), their messages, and their branches and tags.</p> | ||
<h2 id="getting-rid-of-local-changes">Getting rid of local changes</h2> | |||
<p>You might have accidentally made changes you didn't want to, and you don't want to bother with making an entirely new branch or something--but you haven't committed those changes yet.</p> | |||
<pre><code>git <span class="hljs-keyword">reset</span> <span class="hljs-comment">--hard HEAD</span> | |||
</code></pre><p>This just means 'change the working tree to the current commit, before any local changes. Or else.' <strong>You can't retrieve those local changes if you do this, so be wary.</strong></p> | |||
<h2 id="unstaging-changes">Unstaging changes</h2> | |||
<p>Ah shit, I just staged RobustToolbox by accident. No fear!</p> | |||
A nasty little maintainer has told you to | <pre><code>git <span class="hljs-keyword">reset</span> <span class="hljs-keyword">HEAD</span> [<span class="hljs-keyword">file</span>] | ||
</code></pre><p>Alternatively, to unstage everything:</p> | |||
First, you | <pre><code>git <span class="hljs-keyword">reset</span> <span class="hljs-keyword">HEAD</span> | ||
</code></pre><h2 id="reverting-a-commit-you-made">Reverting a commit you made</h2> | |||
When you run | <p>Oh shit, your xenomorph erotica made its way into a commit/you accidentally committed a submodule! What now? Well, there's two solutions:</p> | ||
<pre><code><span class="hljs-symbol">git</span> <span class="hljs-keyword">revert </span>HEAD | |||
All you need to do to resolve conflicts manually is go into the files that are conflicting, remove all the | </code></pre><p>This makes a new commit undoing the current commit, and then commits it. Hehe commit. </p> | ||
<p>If you want to undo a different commit, you can check its hash in <code>git log --oneline</code> and then call <code>git revert [commit hash]</code>. Git has a more robust system for doing this; you can do <code>git revert HEAD~1</code> to undo the commit before your current one or <code>git revert HEAD~2</code> to revert the one before that. The <code>~1</code> just means '1 commit before HEAD'.</p> | |||
Atlassian has a really good guide for this | <p>Alternatively,</p> | ||
<pre><code>git <span class="hljs-keyword">reset</span> <span class="hljs-comment">--hard HEAD~1</span> | |||
</code></pre><p><strong>I don't recommend doing this unless you're fully aware of what you're doing.</strong></p> | |||
<p>For when you REALLY don't want anyone to know about that xenomorph erotica you just made. This method rewrites history, so it isn't the best for a collaborative environment. If you do this, you'll need to force push (<code>git push origin [branch] --force</code>) or else it won't work. Force pushing can be dangerous, so again, be sure you know what you're doing.</p> | |||
<h2 id="checking-out-a-pr-s-changes-locally">Checking out a PR's changes locally</h2> | |||
<p>Ok, this one is a little difficult. There's a couple ways to do this:</p> | |||
<h3 id="github-cli">Github CLI</h3> | |||
<p>Install github's fancy CLI and do this:</p> | |||
You might have accidentally made changes you didn | <pre><code>gh <span class="hljs-keyword">pr</span> checkout [<span class="hljs-keyword">pr</span> number] | ||
</code></pre><p>Neat.</p> | |||
<h3 id="changing-git-config">Changing .git/config</h3> | |||
git reset --hard HEAD | <p>Go into your .git folder (hidden by default--may need to enable showing hidden folders in Windows), and open up the 'config' file. There should be a bit that looks something like:</p> | ||
<pre><code>[remote <span class="hljs-string">"upstream"</span>] | |||
url = <span class="hljs-symbol">https:</span>/<span class="hljs-regexp">/github.com/space</span>-wizards/space-station-<span class="hljs-number">14</span> | |||
This just means | fetch = +refs/heads/*<span class="hljs-symbol">:refs/remotes/upstream/*</span> | ||
</code></pre><p>Add a line to this that reads <code>fetch = +refs/pull/*/head:refs/remotes/upstream/pr/*</code>, so that section should now look like:</p> | |||
<pre><code>[remote <span class="hljs-string">"upstream"</span>] | |||
url = <span class="hljs-symbol">https:</span>/<span class="hljs-regexp">/github.com/space</span>-wizards/space-station-<span class="hljs-number">14</span> | |||
Ah shit, I just staged RobustToolbox by accident. No fear! | fetch = +refs/heads/*<span class="hljs-symbol">:refs/remotes/upstream/*</span> | ||
fetch = +refs/pull/*<span class="hljs-regexp">/head:refs/remotes</span><span class="hljs-regexp">/upstream/pr</span><span class="hljs-regexp">/*</span> | |||
</code></pre><p>Now, <code>git fetch upstream</code>. This method is great if you're a maintainer, but it also.. fetches every branch that's still up from every PR that's been opened, so not fantastic if you just wanted one thing. From here, you can <code>git checkout upstream/pr/[pr number]</code> to check out their branch. This is basically what GitHub CLI does but less sophisticated.</p> | |||
git reset | <h3 id="adding-a-new-remote">Adding a new remote</h3> | ||
<p>This method kinda sucks because it takes a while but if you want to check out someone else's fork of the game and their branches it's pretty nice.</p> | |||
<p>Not actually that hard but its confusing if you don't know Git very well. Set up a remote to the user's remote repository, fetch their branches, and then checkout their branch:</p> | |||
Alternatively, to unstage everything: | <pre><code>git remote add [username] <span class="hljs-link">https://github.com/</span>[<span class="hljs-string">username</span>]/space-station-14 | ||
git reset HEAD | |||
Oh shit, your xenomorph erotica made its way into a commit/you accidentally committed a submodule! What now? Well, there | |||
This makes a new commit undoing the current commit, and then commits it. Hehe commit. | |||
If you want to undo a different commit, you can check its hash in | |||
Alternatively, | |||
git reset --hard HEAD~1 | |||
For when you REALLY don | |||
Ok, this one is a little difficult. There | |||
Install github | |||
gh pr checkout [pr number] | |||
Neat. | |||
Go into your .git folder (hidden by default--may need to enable showing hidden folders in Windows), and open up the | |||
[remote "upstream"] | |||
Add a line to this that reads | |||
[remote "upstream"] | |||
url = | |||
fetch = +refs/heads/*:refs/remotes/upstream/* | |||
fetch = +refs/pull/*/head:refs/remotes/upstream/pr/* | |||
Now, | |||
This method kinda sucks because it takes a while but if you want to check out someone else | |||
Not actually that hard but its confusing if you don | |||
git remote add [username] https://github.com/[username]/space-station-14 | |||
git fetch [username] | git fetch [username] | ||
git checkout [username]/[branch name] | git checkout [username]/[branch name] | ||
</code></pre><p>This also lets you make PRs to their remote branch, if you so desired.</p> | |||
This also lets you make PRs to their remote branch, if you so desired. |
Версия от 13:46, 26 сентября 2024
Git for the SS14 Developer
If you've ever followed a hackily written guide to Git or opened up one of the many incredibly bloated modern git GUIs like GitKraken, you probably recognize that Git can be really confusing. The purpose of this guide is to give you just the information you need to develop properly for SS14 and give you the resources to learn more if necessary.
Here are some more resources for learning about Git:
- <a href="https://git-scm.com/book/en/v2">The Git-SCM online book</a>
- <a href="https://www.atlassian.com/git/tutorials/setting-up-a-repository">Atlassian's git guides</a>. Good guides for some more advanced stuff
- <a href="https://ohshitgit.com/">Oh shit, Git?!</a>, a list of solutions to common git problems. This one will come in handy.
- <a href="https://learngitbranching.js.org/">Learn Git Branching</a>. This one is interactive, and very in-depth, but you will have learned Git by the end of it. Recommended for intermediate Git users.
1. Setting up Git itself
```admonish danger "DO NOT USE GITKRAKEN" For the love of god do not install GitKraken or GitHub Desktop. I have felt nothing but endless CBT trying to help people using either of them. I know GitKraken looks all professional and GH Desktop is nice and simple but please do not use either of them unless you know what you are doing.
<code> If you were following our <span class="hljs-strong">**"Setting up a Development Environment"**</span> guide, you probably already have Git installed. If not, go to [<span class="hljs-string">their website</span>](<span class="hljs-link">https://git-scm.org</span>) and install it now. This will install the Git backend, as well as Git Bash (if you select that option)--one of the many ways you can actually use Git. If you're on Linux, you'll probably just be using Git through your terminal or whichever IDE you've chosen, and chances are you have it installed already. I highly recommend at least trying Git Bash (as will a lot of our developers), but there are friendlier alternatives many use that I'll be showing steps for here as well: <span class="hljs-bullet">- </span>[<span class="hljs-string">TortoiseGit</span>](<span class="hljs-link">https://tortoisegit.org/</span>) -- old but gold Git GUI that shows info in the file explorer menu and makes basic stuff a breeze <span class="hljs-bullet">- </span>[<span class="hljs-string">SmartGit</span>](<span class="hljs-link">https://www.syntevo.com/smartgit/</span>) -- fully featured Git GUI that's very customizable and simple to use I won't have steps for these (I'm recommending these after I initially wrote this guide) but after trying some more there are other very, very good options: <span class="hljs-bullet">- </span>[<span class="hljs-string">Fork</span>](<span class="hljs-link">https://git-fork.com/</span>) -- fast and extremely ergonomic GUI, my personal favorite. "Non-free", but it's WinRAR-level non-free, so it's basically free. Has support for partial staging of <span class="hljs-bullet">- </span>[<span class="hljs-string">Sublime Merge</span>](<span class="hljs-link">https://www.sublimemerge.com/</span>) -- very similar to Fork, looks and feels great and I've gotten a lot of recommendations for it, though I haven't used it much. Also has support for partial staging. Most IDEs have some form of Git integration as well. [<span class="hljs-string">JetBrains Rider</span>](<span class="hljs-link">https://www.jetbrains.com/rider/</span>)'s Git integration is really good (and I personally recommend Rider for everything SS14-development related). I don't recommend Visual Studio's Git integration, because it's.. not very good. While you're here, install <span class="hljs-code">`Python 3.7+`</span> as well if you don't have it already. You can do that [<span class="hljs-string">here</span>](<span class="hljs-link">https://www.python.org/</span>) for Windows and Mac, and if you're on Linux you almost certainly have Python installed already. If you don't, figure it out yourself, dork! <span class="xml"><span class="hljs-tag"><<span class="hljs-name">hr</span>></span></span> <span class="hljs-code">```admonish danger "Name and Email privacy" When [setting up your `user.name` and `user.email`](https://git-scm.com/book/en/v2/Getting-Started-First-Time-Git-Setup#_your_identity), know that these are publicly displayed on all commits that you create. If you want to keep your information private, you can set `user.name` to your username instead of your real name, and `user.email` to the one provided by GitHub when the [`Keep my email addresses private`](https://github.com/settings/emails#toggle_visibility) setting is checked in [GitHub Email Settings](https://github.com/settings/emails#primary_email_select_label).</span> </code>
Now that you have Git installed, I recommend you read up a bit on the basics of it first and get acquainted with whatever git client you're working with, whether its just command-line (Git Bash) or anything else.
We're going to run through the process of setting up a Git environment for Space Station 14 so that you can contribute code through pull requests, create your own codebase, or just check out the history of the project.
1.1 Why are we even using Git?
Git is version-control software--basically, it's an easy way to track changes to the code, and manage those changes without headaches. It's an invaluable tool for software development, because it easily lets you make new changes, view different changes, see who made changes, etc. without having to coordinate and tabulate everything yourself.
GitHub is an online service that hosts Git repositories (codebases) for easy collaboration. It's perfect for a codebase like SS14, with lots of contributors and lots of history. It also means that we're open-source--anyone can go to our GitHub and download the code!
2. Setting up your repositories
Like I said before, a repository is just a codebase. Repositories contain some branches, and those branches contain different commits. You might have heard of both of these--I'll talk more about them in depth later.
A remote repository is just a repository's that's on GitHub. A local repository is one that's actually on your computer.
2.1 Creating your remote repository
First, let's make our own remote repository fork of Space Station 14. You'll need a GitHub account for this, of course. 'Forking' it like this just means you're copying all of the repository's history and changes into your own remote repository so that you can do stuff freely to the code.
Your remote repository doesn't automatically update with changes from the original SS14 repo--you'll have to do that yourself, which I'll talk about later.
Navigate to the <a href="https://github.com/space-wizards/space-station-14">Space Station 14 repository</a> and click here:
<img src="https://i.imgur.com/lAHNHdD.png" alt="">
From there, it'll ask you where to fork it and what to name it--just to your regular account, and name it whatever you please! I'd stick with space-station-14
if you just want to help out with development, though.
2.2 Creating your local repository
Now, we'll need to download our remote repository onto our computer (cloning) so we can add 20 pairs of clown shoes to every locker some changes to it. You can technically change your remote repository (GitHub has some nice tools), but having it on your computer means you use IDEs like Visual Studio or Rider to build the game and run tests, as well as handle Git stuff easily.
For every step, there will be screenshots and instructions for Git Bash, SmartGit, and TortoiseGit on Windows.
Navigate to somewhere on your computer where you want to put the local repository, and:
<details><summary>TortoiseGit</summary>
Right click to see TortoiseGit's context menu stuff: <img src="https://i.imgur.com/QGmrQmH.png" alt="">
</details>
<details><summary>SmartGit</summary>
Open up SmartGit and navigate to the desired location, then: <img src="https://i.imgur.com/C3JBYR6.png" alt="">
</details>
<details><summary>Git Bash</summary>
Right click: <img src="https://i.imgur.com/kIYnm16.png" alt="">
</details>
Then, we'll enter the command for cloning our remote repository--not the space-wizards/space-station-14
repository.
<details><summary>TortoiseGit</summary>
<img src="https://i.imgur.com/3HzCnjm.png" alt=""> <img src="https://i.imgur.com/a7vhKcC.png" alt="">
</details>
<details><summary>SmartGit</summary>
<img src="https://i.imgur.com/YyJm5fx.png" alt="">
</details>
<details><summary>Git Bash</summary>
<img src="https://i.imgur.com/Xn4AQLf.png" alt="">
Then change directory using:
cd space-station-14
(This may be different if you cloned another fork, it's almost always being the same as the repository name)
Every Git command will look something like this--git
and then a keyword like add
, commit
, pull
, etc.
</details>
After this completes, you have a local repository that you can now modify! There's still some more setup to go through, though.
2.3 Submodule woes
Pay attention to this! If you don't do this, you'll get a lot of weird errors about stuff not being available when you actually try to build the game.
Space Station 14 has a lot of submodules--most notably our engine, RobustToolbox. Submodules are just repositories inside a repository, and they need to be updated manually by you. Or do they?
We have an automatic submodule updater so you don’t have to worry about running git submodule update --init --recursive
(the command for manually updating submodules) all the time.
Run RUN_THIS.py
inside the repo you downloaded with Python. Preferably from a terminal too (python RUN_THIS.py
or python3 RUN_THIS.py
). This should take a few seconds so if it instantly stops you probably aren’t using Python 3.7+ or something.
If you are on Windows and get redirected to the Microsoft Store or encounter a message in your terminal claiming that Python is not installed when you attempt to run the above command, you will need to disable the Microsoft shortcut that might be causing this issue. You can do this by searching for Manage App Execution Aliases
in the Windows search and then turning off the two Python references.
If you do want to modify the engine directly however, or you want to update the submodule manually (the auto updating can be a pain occasionally), make a file called DISABLE_SUBMODULE_AUTOUPDATE inside the BuildChecker/ directory.
If you ever need to manually update RobustToolbox for whatever reason you can use cd RobustToolbox; git checkout v0.4.87
(replace v0.4.87
with the latest RobustToolbox release) then you can use cd..\
to get back into your SS14 repo. This is also an example of using cd
to navigate files from the comfort of your command line.
3. Setting up remotes
When you cloned your remote repository, a remote was automatically added to your local repository. Remotes are just named URLs to remote repositories that Git keeps track of so you can do stuff like download (pull) new changes to the code or upload (push) code to your forked repository.
In this case, the remote automatically added is calledorigin
and it points to https://github.com/[username-here]/space-station-14
(or whatever you named the remote repository).
One issue: we don't have a reference to the original space-wizards/space-station-14
remote repository anywhere! How are we supposed to update our local repository without it? So let's make sure we've navigated inside our local repo's folder, and we'll add a new remote:
<details><summary>TortoiseGit</summary>
<img src="https://i.imgur.com/yANaYWI.png" alt=""> <img src="https://i.imgur.com/cjbhMEN.png" alt="">
</details>
<details><summary>SmartGit</summary>
<img src="https://i.imgur.com/LXCpgVo.png" alt=""> <img src="https://i.imgur.com/ZHIHPJC.png" alt="">
</details>
<details><summary>Git Bash</summary>
<img src="https://i.imgur.com/00ETpii.png" alt="">
</details>
All this does is add a new remote named upstream
that points to the original space-wizards/space-station-14
repository. Now we can receive updates from the main repository whenever we want! (see below on how to do that).
The convention is to call the remote pointing to the original repository upstream
but you can technically call it whatever you like. I'll be referring to it as 'the upstream', though, and it's terminology Git guides use as well.
Addendum for fork/downstream developers: If a downstream repository you wish to contribute to is set up as a direct fork (IE: GitHub shows a "forked from" label underneath the repo's name), then you'll additionally want to add that fork as a remote (but if the fork isn't set up that way, you can ignore this). You can do this in a way similar to how you've added the upstream as a remote (just use the fork's GitHub link as the remote URL), but be sure to substitute the remote name of upstream
with any name you deem appropriate. Your own fork does not have to be a fork of the downstream's fork for this; all that matters is that the commit history in the individual branches you push to your own remote line up with the commit history of wherever you're intending to PR your changes to.
```admonish warning title="Before working on your first PR to the space-wizards repo" Please make sure you read through the <a href="https://github.com/space-wizards/space-station-14/issues/8524">Freezes & Restrictions</a> and ensure your idea does not fall into the freezes or if your PR requires some prerequisite before being made.
<code> ## <span class="hljs-number">4</span>. Branching & Commits Branches <span class="hljs-keyword">and</span> commits are two <span class="hljs-keyword">of</span> the most important concepts <span class="hljs-keyword">in</span> Git, <span class="hljs-keyword">and</span> most <span class="hljs-keyword">of</span> the work you do will revolve around them. ### <span class="hljs-number">4.1</span> Whats a commit? Like I mentioned before, **commits** are just packaged up changes <span class="hljs-keyword">to</span> the code. As the developer, you choose which changes go into a commit <span class="hljs-keyword">and</span> <span class="hljs-keyword">when</span> <span class="hljs-keyword">to</span> commit those changes. **Committing** refers <span class="hljs-keyword">to</span> creating a commit, <span class="hljs-keyword">and</span> it essentially makes a save point that you can go back <span class="hljs-keyword">to</span> at any <span class="hljs-built_in">time</span>. Commits have an author, timestamp, a message, <span class="hljs-keyword">and</span> some code changes attached <span class="hljs-keyword">to</span> them. They also have a really long <span class="hljs-symbol">'commit</span> hash', a unique identifier used <span class="hljs-keyword">to</span> refer <span class="hljs-keyword">to</span> different commits. Commits are how history <span class="hljs-keyword">is</span> built up<span class="hljs-comment">--you can actually view the history of every single commit made to the SS14 repository from the beginning, which is pretty cool:</span> ![](https://i.imgur.com/HQDdw6h.png) (done <span class="hljs-keyword">with</span> `git log <span class="hljs-comment">--reverse`)</span> ### <span class="hljs-number">4.2</span> What<span class="hljs-symbol">'s</span> a branch? **Branches** are very, very important. They<span class="hljs-symbol">'re</span> basically just a list <span class="hljs-keyword">of</span> changes <span class="hljs-keyword">to</span> the code (commits). The <span class="hljs-keyword">default</span> branch <span class="hljs-keyword">is</span> <span class="hljs-symbol">'master</span>', <span class="hljs-keyword">and</span> <span class="hljs-keyword">all</span> <span class="hljs-keyword">of</span> our servers <span class="hljs-keyword">use</span> that branch <span class="hljs-keyword">to</span> compile the code. You<span class="hljs-symbol">'re</span> pretty much always <span class="hljs-symbol">'on</span> a branch' <span class="hljs-keyword">when</span> you<span class="hljs-symbol">'re</span> working <span class="hljs-keyword">with</span> your code, <span class="hljs-keyword">and</span> you can switch which branch you<span class="hljs-symbol">'re</span> working <span class="hljs-keyword">on</span> easily. Generally, branches are named <span class="hljs-keyword">for</span> whatever you<span class="hljs-symbol">'re</span> going <span class="hljs-keyword">to</span> be working <span class="hljs-keyword">on</span> <span class="hljs-keyword">in</span> them, but it doesn<span class="hljs-symbol">'t</span> *really* matter what they<span class="hljs-symbol">'re</span> named. You can make as many branches as you like. <span class="hljs-keyword">When</span> you create a branch, it <span class="hljs-symbol">'branches</span> <span class="hljs-keyword">out</span>' (no shit, really?) from the current branch you<span class="hljs-symbol">'re</span> <span class="hljs-keyword">on</span> <span class="hljs-keyword">and</span> becomes its own independent thing you can add commits <span class="hljs-keyword">to</span>. ![](https://i.imgur.com/ByMugxu.png=<span class="hljs-number">500</span>x300) <span class="hljs-keyword">In</span> this diagram, each little node <span class="hljs-keyword">is</span> a different commit, <span class="hljs-keyword">and</span> each color <span class="hljs-keyword">is</span> a different branch. #### Branch merging Branches are important because they can be **merged** together. This <span class="hljs-keyword">is</span> how features are integrated into the main `master` branch. A **merge** just means <span class="hljs-symbol">'take</span> the special commits from this branch, <span class="hljs-keyword">and</span> apply them <span class="hljs-keyword">to</span> another branch'. You can merge any two branches together. Sometimes this doesn<span class="hljs-symbol">'t</span> go well, because both branches modify the same part <span class="hljs-keyword">in</span> a <span class="hljs-keyword">file</span> <span class="hljs-keyword">in</span> contradictory ways, <span class="hljs-keyword">in</span> which <span class="hljs-keyword">case</span> you<span class="hljs-symbol">'ll</span> get a **merge conflict**<span class="hljs-comment">--more on that in the addendums.</span> GitHub pull requests are really a <span class="hljs-symbol">'merge</span> request'<span class="hljs-comment">--you're saying that you want to merge the commits on your branch into another branch, usually their `master`. More on that later.</span> Pull requests show <span class="hljs-keyword">all</span> this info very well: ![](https://i.imgur.com/YAOWX5R.png) ![](https://i.imgur.com/nWWy3J4.png) <span class="hljs-keyword">In</span> this pull request, Swept started <span class="hljs-keyword">out</span> by creating a <span class="hljs-keyword">new</span> branch. Since he now had a fresh branch free <span class="hljs-keyword">of</span> interference <span class="hljs-keyword">to</span> work <span class="hljs-keyword">with</span>, he started working <span class="hljs-keyword">on</span> the feature <span class="hljs-keyword">and</span> created commits <span class="hljs-keyword">to</span> <span class="hljs-symbol">'save</span> his progress' whenever he felt it was necessary. These commits were added <span class="hljs-keyword">to</span> the branch sequentially, <span class="hljs-keyword">and</span> you can see the evolution <span class="hljs-keyword">of</span> the branch as more code was written. We<span class="hljs-symbol">'ll</span> talk more about pull requests later. #### But whyyy? Okay, technically, sure, you can just do <span class="hljs-keyword">all</span> <span class="hljs-keyword">of</span> your work <span class="hljs-keyword">on</span> the `master` branch <span class="hljs-keyword">and</span> pull request from there. But, creating different branches makes it easy <span class="hljs-keyword">to</span> understand where you are, how many changes you<span class="hljs-symbol">'ve</span> made, <span class="hljs-keyword">and</span> it makes it possible <span class="hljs-keyword">to</span> work <span class="hljs-keyword">on</span> multiple features at once. Also we<span class="hljs-symbol">'ll</span> close your PR <span class="hljs-keyword">if</span> it<span class="hljs-symbol">'s</span> from your `master` branch (it can very easily cause issues) so don<span class="hljs-symbol">'t</span> do it. ### <span class="hljs-number">4.3</span> Making <span class="hljs-keyword">and</span> working <span class="hljs-keyword">with</span> branches Making branches <span class="hljs-keyword">is</span> pretty easy. Let<span class="hljs-symbol">'s</span> make a <span class="hljs-keyword">new</span> branch called `funny-feature`: <details><summary>TortoiseGit</summary> <p> ![](https://i.imgur.com/OGkblCk.png) ![](https://i.imgur.com/ZPfzFcm.png) </p> </details> <details><summary>SmartGit</summary> <p> ![](https://i.imgur.com/pK1oyfz.png) ![](https://i.imgur.com/<span class="hljs-number">5</span>MZ6Ocv.png) </p> </details> <details><summary>Git Bash</summary> <p> ![](https://i.imgur.com/kOc9rfe.png) You may notice that the <span class="hljs-built_in">bit</span> <span class="hljs-keyword">in</span> parentheses (master) changed <span class="hljs-keyword">to</span> (funny-feature)! Incredible! The `-b` <span class="hljs-keyword">in</span> `git checkout` here means <span class="hljs-symbol">'checkout</span> this branch, <span class="hljs-keyword">and</span> create it <span class="hljs-keyword">if</span> it doesn<span class="hljs-symbol">'t</span> exist.' </p> </details> <hr> Now, you can work freely <span class="hljs-keyword">with</span> this branch as you please without fear <span class="hljs-keyword">of</span> messing up your <span class="hljs-keyword">all</span>-important master branch. Switching between branches <span class="hljs-keyword">is</span> pretty easy: it<span class="hljs-symbol">'s</span> called **checking <span class="hljs-keyword">out</span>** a branch. <span class="hljs-keyword">When</span> you do this, your files <span class="hljs-keyword">and</span> folders locally will be changed <span class="hljs-keyword">to</span> match the branch, so Git will yell at you <span class="hljs-keyword">if</span> you have local changes <span class="hljs-keyword">and</span> you try <span class="hljs-keyword">to</span> check <span class="hljs-keyword">out</span>. Checking <span class="hljs-keyword">out</span> a branch: <details><summary>TortoiseGit</summary> <p> ![](https://i.imgur.com/UThKrCK.png) </p> </details> <details><summary>SmartGit</summary> <p> ![](https://i.imgur.com/fzC1pVm.png) </p> </details> <details><summary>Git Bash</summary> <p> ![](https://i.imgur.com/DqWEdY5.png) </p> </details> <hr> <span class="hljs-keyword">Then</span>, make whatever local changes you want! It doesn<span class="hljs-symbol">'t</span> really matter. Make a <span class="hljs-keyword">new</span> <span class="hljs-keyword">file</span>, delete everything, change one <span class="hljs-literal">line</span> <span class="hljs-keyword">in</span> a <span class="hljs-keyword">file</span>, etc. It won<span class="hljs-symbol">'t</span> affect your `master` branch, because this <span class="hljs-keyword">is</span>`funny-feature` land now! ### <span class="hljs-number">4.4</span> Staging <span class="hljs-keyword">and</span> committing changes <span class="hljs-keyword">to</span> your branch One more important thing: Before you can `commit` your changes, you have <span class="hljs-keyword">to</span> `add` your changes <span class="hljs-keyword">to</span> the **staging area**. <span class="hljs-keyword">All</span> this means <span class="hljs-keyword">is</span> that you<span class="hljs-symbol">'re</span> specifying which files you want <span class="hljs-keyword">to</span> commit. This <span class="hljs-keyword">is</span> helpful, because you *almost never* want <span class="hljs-keyword">to</span> commit submodule changes, so you avoid that by <span class="hljs-keyword">not</span> adding them <span class="hljs-keyword">to</span> the staging area. As mentioned before, commits always come <span class="hljs-keyword">with</span> a message, which <span class="hljs-keyword">is</span> just a short, imperative description <span class="hljs-keyword">of</span> what<span class="hljs-symbol">'s</span> being done <span class="hljs-keyword">in</span> that commit. <span class="hljs-keyword">Or</span> you can be a chad <span class="hljs-keyword">and</span> name every commit <span class="hljs-string">"changes stuff"</span>, up <span class="hljs-keyword">to</span> you. <span class="hljs-keyword">If</span> you want <span class="hljs-keyword">to</span> see what you<span class="hljs-symbol">'ve</span> currently changed, <span class="hljs-keyword">and</span> what<span class="hljs-symbol">'s</span> <span class="hljs-keyword">in</span> the staging area, it<span class="hljs-symbol">'s</span> pretty easy: <details><summary>TortoiseGit</summary> <p> ![](https://i.imgur.com/xmZKKWJ.png) TortoiseGit also shows changed files/folders (a red icon <span class="hljs-keyword">in</span> the bottom right) <span class="hljs-keyword">in</span> the Windows Explorer which <span class="hljs-keyword">is</span> really nice <span class="hljs-keyword">and</span> why I have it installed <span class="hljs-keyword">in</span> the first place. </p> </details> <details><summary>SmartGit</summary> <p> ![](https://i.imgur.com/ROsurs1.png) This <span class="hljs-keyword">is</span> assuming you installed SmartGit <span class="hljs-keyword">with</span> the option that the main window shows diffs <span class="hljs-keyword">and</span> status. <span class="hljs-keyword">If</span> you didn<span class="hljs-symbol">'t</span>, I don<span class="hljs-symbol">'t</span> really know where it <span class="hljs-keyword">is</span>. </p> </details> <details><summary>Git Bash</summary> <p> ![](https://i.imgur.com/UeMjAHj.png) </p> </details> <hr> Now that you<span class="hljs-symbol">'ve</span> verified that <span class="hljs-keyword">all</span> <span class="hljs-keyword">of</span> these changes look good, we<span class="hljs-symbol">'ll</span> add them <span class="hljs-keyword">to</span> the staging area <span class="hljs-keyword">and</span> commit them (some Git GUIs do this <span class="hljs-keyword">in</span> one step) <details><summary>TortoiseGit</summary> <p> ![](https://i.imgur.com/ltIASro.png) ![](https://i.imgur.com/BIa9r6c.png) </p> </details> <details><summary>SmartGit</summary> <p> ![](https://i.imgur.com/RYUL7u3.png) ![](https://i.imgur.com/Du7HqRV.png) </p> </details> <details><summary>Git Bash</summary> <p> ![](https://i.imgur.com/mpKk5L1.png) </p> </details> <hr> Woo, we<span class="hljs-symbol">'ve</span> committed our changes <span class="hljs-keyword">to</span> a branch! Now that they<span class="hljs-symbol">'re</span> committed, they<span class="hljs-symbol">'re</span> <span class="hljs-keyword">in</span> the history <span class="hljs-keyword">of</span> the branch forever (sort <span class="hljs-keyword">of</span>). We can do a lot <span class="hljs-keyword">of</span> things now: merge our `funny-feature` into our local `master` branch (<span class="hljs-keyword">if</span> we wanted, <span class="hljs-keyword">for</span> some reason), upload (push) our `funny-feature` branch <span class="hljs-keyword">to</span> our remote repository, <span class="hljs-keyword">or</span> nuke the branch entirely (among other things). We<span class="hljs-symbol">'ll</span> opt <span class="hljs-keyword">for</span> pushing the branch <span class="hljs-keyword">and</span> making a pull request now. ## <span class="hljs-number">5</span>. Pushing <span class="hljs-keyword">and</span> making a PR A **pull request** <span class="hljs-keyword">is</span> a GitHub-specific thing. It just means that you want a codebase <span class="hljs-keyword">to</span> merge your changes <span class="hljs-keyword">on</span> one <span class="hljs-keyword">of</span> your branches into one <span class="hljs-keyword">of</span> their branches<span class="hljs-comment">--usually to their `master` branch. Before we can do this, our remote GitHub repository (origin) needs to know about the beautiful branches and commits we've created locally, so we upload or **push** those changes to the remote.</span> ### <span class="hljs-number">5.1</span> Pushing commits It<span class="hljs-symbol">'s</span> pretty easy <span class="hljs-keyword">to</span> push our changes now that we<span class="hljs-symbol">'ve</span> committed them. Be aware that, <span class="hljs-keyword">when</span> using these commands, Git <span class="hljs-keyword">is</span> probably going <span class="hljs-keyword">to</span> ask <span class="hljs-keyword">for</span> your GitHub credentials so that it can verify that you<span class="hljs-symbol">'re</span> allowed <span class="hljs-keyword">to</span> push <span class="hljs-keyword">to</span> that remote. <span class="hljs-keyword">When</span> pushing changes, we specify the *remote* repository that we<span class="hljs-symbol">'re</span> pushing <span class="hljs-keyword">to</span> <span class="hljs-keyword">and</span> the *local* branch that we<span class="hljs-symbol">'re</span> pushing. Simple enough. Pushing our branch <span class="hljs-keyword">to</span> our remote repository (origin): <details><summary>TortoiseGit</summary> <p> ![](https://i.imgur.com/bWS5Kdk.png) ![](https://i.imgur.com/Irv1e5k.png) Selecting <span class="hljs-symbol">'push</span> <span class="hljs-keyword">all</span> branches' does what it says <span class="hljs-keyword">on</span> the tin. Can be useful. </p> </details> <details><summary>SmartGit</summary> <p> ![](https://i.imgur.com/s82VnNn.png) ![](https://i.imgur.com/VP8PuCq.png) </p> </details> <details><summary>Git Bash</summary> <p> ![](https://i.imgur.com/<span class="hljs-number">7</span>FJqzkL.png) </p> </details> ### <span class="hljs-number">5.2</span> Making a pull request Now, the fun part. We<span class="hljs-symbol">'ll</span> go <span class="hljs-keyword">to</span> GitHub now <span class="hljs-keyword">and</span> make a pull request <span class="hljs-keyword">for</span> our funny feature. ![](https://i.imgur.com/YNmEMtG.png) Add a description, a nice title, some screenshots, <span class="hljs-keyword">and</span> hopefully it gets merged. ## <span class="hljs-number">6</span>. Updating our repository Maybe it<span class="hljs-symbol">'s</span> been a <span class="hljs-keyword">while</span>, a week <span class="hljs-keyword">or</span> two, since your last pull request, <span class="hljs-keyword">and</span> you<span class="hljs-symbol">'d</span> like <span class="hljs-keyword">to</span> make another. Before you do anything, you need <span class="hljs-keyword">to</span> download (**pull**) the code changes from the main SS14 repository into your local repository. <span class="hljs-keyword">If</span> you don<span class="hljs-symbol">'t</span>, you<span class="hljs-symbol">'ll</span> have <span class="hljs-keyword">out</span>-<span class="hljs-keyword">of</span>-date code <span class="hljs-keyword">and</span> your local changes may <span class="hljs-keyword">not</span> be accurate <span class="hljs-keyword">to</span> how the game will actually run<span class="hljs-comment">--you might even get **merge conflicts** when you try to PR.</span> There are two ways <span class="hljs-keyword">to</span> update your repository. Both methods <span class="hljs-keyword">assume</span> you have the `upstream` remote set up properly<span class="hljs-comment">--if not, go back to earlier in the guide. And of course, if you're developing for a downstream, then you'll want to substitute `upstream` for whatever you named the downstream repo in step 4, to make sure that you're working with that downstream's files instead of upstream's. Make sure you *always* go through the update process when switching between contributing to a fork, and contributing to upstream, otherwise you'll inevitably end up either PRing the entire history of a downstream to upstream, or making PRs to downstream that immediately conflict.</span> The first method, **fetch+merge**, gives you more control but can be confusing. The second method, **pulling**, <span class="hljs-keyword">is</span> simple <span class="hljs-keyword">and</span> easy but doesn<span class="hljs-symbol">'t</span> give you much control. However, pulling <span class="hljs-keyword">is</span> usually <span class="hljs-keyword">all</span> you need. ### <span class="hljs-number">6.1</span> Fetch + merge method **Fetching** refers <span class="hljs-keyword">to</span> downloading the <span class="hljs-keyword">new</span> branches <span class="hljs-keyword">and</span> commits from a remote repository<span class="hljs-comment">--but not doing anything with them just yet (nothing locally will be changed). After we fetch changes from our `upstream` remote (the main SS14 repository), we'll merge them into our local `master` branch.</span> <span class="hljs-keyword">When</span> you fetch a remote, it downloads those branches <span class="hljs-keyword">to</span> your local repository <span class="hljs-keyword">and</span> prepends them <span class="hljs-keyword">with</span> the remotes name <span class="hljs-keyword">and</span> a slash. So, <span class="hljs-keyword">when</span> you fetch `upstream`, it<span class="hljs-symbol">'ll</span> make a branch called `upstream/master`. As a bonus, you can checkout this remote branch directly <span class="hljs-keyword">if</span> you<span class="hljs-symbol">'d</span> like, <span class="hljs-keyword">and</span> even create a local branch based off it, which <span class="hljs-keyword">is</span> especially useful <span class="hljs-keyword">if</span> you<span class="hljs-symbol">'re</span> working <span class="hljs-keyword">with</span> more than just upstream. First, let<span class="hljs-symbol">'s</span> fetch from our `upstream` remote. It<span class="hljs-symbol">'ll</span> take a little <span class="hljs-built_in">bit</span> <span class="hljs-keyword">to</span> complete. <details><summary>TortoiseGit</summary> <p> ![](https://i.imgur.com/<span class="hljs-number">3</span>cWun8b.png) ![](https://i.imgur.com/XGgXRY0.png) Make sure you <span class="hljs-keyword">select</span> `upstream` <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> origin! </p> </details> <details><summary>SmartGit</summary> <p> ![](https://i.imgur.com/CNFFJJ8.png) I think smartgit fetches from <span class="hljs-keyword">all</span> remotes <span class="hljs-keyword">when</span> you click this????? <span class="hljs-keyword">If</span> it doesn<span class="hljs-symbol">'t</span> <span class="hljs-keyword">and</span> it just fetches from origin, go <span class="hljs-keyword">to</span> the bottom left <span class="hljs-keyword">and</span> do this: ![](https://i.imgur.com/<span class="hljs-number">8</span>rF0tz5.png) </p> </details> <details><summary>Git Bash</summary> <p> ![](https://i.imgur.com/aJvW9PX.png) Here nothing happened because I just fetched, but it<span class="hljs-symbol">'ll</span> take a <span class="hljs-keyword">while</span>. </p> </details> <hr> Now, we<span class="hljs-symbol">'ll</span> merge those changes we just downloaded into our `master` branch. You don<span class="hljs-symbol">'t</span> have <span class="hljs-keyword">to</span> merge into master here; you can merge into another branch, too. <span class="hljs-keyword">If</span> you just wanted <span class="hljs-keyword">to</span> <span class="hljs-symbol">'fast</span>-forward' update one <span class="hljs-keyword">of</span> your branches <span class="hljs-keyword">to</span> make sure your PR <span class="hljs-keyword">is</span> up <span class="hljs-keyword">to</span> date, you can merge into that branch instead. Check <span class="hljs-keyword">out</span> the branch you want <span class="hljs-keyword">to</span> merge <span class="hljs-keyword">to</span>. <span class="hljs-keyword">Then</span>, <details><summary>TortoiseGit</summary> <p> ![](https://i.imgur.com/<span class="hljs-number">8</span>lUaEFt.png) ![](https://i.imgur.com/<span class="hljs-number">7</span>BvBPYY.png) </p> </details> <details><summary>SmartGit</summary> <p> ![](https://i.imgur.com/n8cc2DN.png) ![](https://i.imgur.com/aRSawAo.png) </p> </details> <details><summary>Git Bash</summary> <p> ![](https://i.imgur.com/H2L8pOp.png) You can also `git merge upstream/master [branch-<span class="hljs-keyword">to</span>-merge-<span class="hljs-keyword">to</span>] </p> </details> ### <span class="hljs-number">6.2</span> Pull method **Pulling** refers <span class="hljs-keyword">to</span> **fetching** (downloading) the <span class="hljs-keyword">new</span> branches <span class="hljs-keyword">and</span> commits from a remote repository, <span class="hljs-keyword">and</span> <span class="hljs-keyword">then</span> merging them into a branch. Pulling <span class="hljs-keyword">is</span> often easier because Git has a nice system <span class="hljs-keyword">for</span> automatically figuring <span class="hljs-keyword">out</span> which remote you want <span class="hljs-keyword">to</span> fetch from (but it doesn<span class="hljs-symbol">'t</span> always work cleanly). Pulling <span class="hljs-keyword">is</span> usually simpler <span class="hljs-keyword">and</span> a lot easier <span class="hljs-keyword">to</span> do. We<span class="hljs-symbol">'ll</span> **pull** from our `upstream` remote (the main SS14 repo) <span class="hljs-keyword">and</span> tell it <span class="hljs-keyword">to</span> merge into our local `master` branch. First, checkout your `master` branch. We covered this earlier. <span class="hljs-keyword">Then</span>, <details><summary>TortoiseGit</summary> <p> ![](https://i.imgur.com/XMUt6cv.png) ![](https://i.imgur.com/NHVlZ4W.png) </p> </details> <details><summary>SmartGit</summary> <p> ![](https://i.imgur.com/ANqpcph.png) ![](https://i.imgur.com/kvv058A.png) ![](https://i.imgur.com/k0scDB8.png) </p> </details> <details><summary>Git Bash</summary> <p> ![](https://i.imgur.com/OfHut9Y.png) </p> </details> <hr> <span class="hljs-keyword">If</span> either method went well, you<span class="hljs-symbol">'ve</span> successfully updated your master branch (<span class="hljs-keyword">or</span> whichever branch you chose <span class="hljs-keyword">to</span> update)! Do this regularly, <span class="hljs-keyword">and</span> always before you start work <span class="hljs-keyword">on</span> a <span class="hljs-keyword">new</span> branch. # Addendums ## <span class="hljs-number">1</span>. Things <span class="hljs-keyword">to</span> keep <span class="hljs-keyword">in</span> mind You<span class="hljs-symbol">'ve</span> more <span class="hljs-keyword">or</span> less learned the workflow <span class="hljs-keyword">for</span> developing features <span class="hljs-keyword">for</span> SS14 Git-wise, but here<span class="hljs-symbol">'s</span> some things I<span class="hljs-symbol">'d</span> really like <span class="hljs-keyword">to</span> hammer into your mind: - <span class="hljs-keyword">When</span> creating a <span class="hljs-keyword">new</span> feature, *always always always* create a <span class="hljs-keyword">new</span> branch off <span class="hljs-keyword">of</span> `master` before committing anything. <span class="hljs-keyword">If</span> you accidentally commit your physics changes <span class="hljs-keyword">to</span> your bike horn branch, you<span class="hljs-symbol">'re</span> <span class="hljs-keyword">not</span> <span class="hljs-keyword">in</span> <span class="hljs-keyword">for</span> a fun <span class="hljs-built_in">time</span>, but it <span class="hljs-keyword">is</span> fixable (see Oh Shit, Git?! above) - **Never, ever commit RobustToolbox <span class="hljs-keyword">or</span> any submodules like Lidgren.Network** unless you know what you<span class="hljs-symbol">'re</span> doing. <span class="hljs-keyword">In</span> the top-level local repository, these submodules are considered <span class="hljs-symbol">'files</span>', so it<span class="hljs-symbol">'s</span> easy <span class="hljs-keyword">to</span> accidentally stage <span class="hljs-keyword">and</span> commit them. Do <span class="hljs-keyword">not</span> do this. See below <span class="hljs-keyword">for</span> how <span class="hljs-keyword">to</span> fix your fuckups <span class="hljs-keyword">if</span> it happens. - <span class="hljs-keyword">If</span> you need further help <span class="hljs-keyword">with</span> Git, feel free <span class="hljs-keyword">to</span> ask <span class="hljs-keyword">in</span> the SS14 Discord <span class="hljs-keyword">in</span> #howdoicode. ## <span class="hljs-number">2</span>. A quick example workflow <span class="hljs-keyword">To</span> get everything <span class="hljs-keyword">in</span> your head <span class="hljs-keyword">and</span> <span class="hljs-keyword">to</span> summarize it <span class="hljs-keyword">all</span>, here<span class="hljs-symbol">'s</span> an example workflow <span class="hljs-keyword">for</span> making several pull requests using Git Bash commands. ```python git checkout master # Before we create a <span class="hljs-keyword">new</span> branch, we should be <span class="hljs-keyword">on</span> master. git fetch upstream # We<span class="hljs-symbol">'ll</span> fetch any <span class="hljs-keyword">new</span> changes from the SS14 repo.. git merge upstream/master # ..<span class="hljs-keyword">and</span> merge them into our master branch. git checkout -b my-<span class="hljs-keyword">new</span>-feature # Make a <span class="hljs-keyword">new</span> branch <span class="hljs-keyword">for</span> the feature ...local changes later... git add -A # Add <span class="hljs-keyword">all</span> <span class="hljs-keyword">of</span> our local changes <span class="hljs-keyword">to</span> the staging area git commit -m <span class="hljs-string">"Fix spaghetti explosions"</span> # Commit them git push origin my-<span class="hljs-keyword">new</span>-feature # <span class="hljs-keyword">and</span> push them <span class="hljs-keyword">to</span> our remote # Now, I want <span class="hljs-keyword">to</span> work <span class="hljs-keyword">on</span> a different pull request. git checkout master # It hasn<span class="hljs-symbol">'t</span> been too long, <span class="hljs-keyword">and</span> nothing important was merged, # so I won<span class="hljs-symbol">'t</span> fetch <span class="hljs-keyword">and</span> merge changes again<span class="hljs-comment">--just a new branch.</span> git checkout -b another-feature ...local changes later... git add -A git commit -m <span class="hljs-string">"Deletes nuclear operatives"</span> # I committed, but <span class="hljs-keyword">then</span> I realized my commit was entirely wrong # <span class="hljs-keyword">and</span> i<span class="hljs-symbol">'ll</span> take it up later. git revert HEAD git checkout master ...a week later... # A lot <span class="hljs-keyword">of</span> <span class="hljs-keyword">new</span> stuff was merged, so let<span class="hljs-symbol">'s</span> update our branch. git fetch upstream git merge upstream/master master git checkout another-feature git merge master # Now we<span class="hljs-symbol">'ll</span> make changes <span class="hljs-keyword">and</span> push again, this <span class="hljs-built_in">time</span> correctly. ...local changes later... git add -A git commit -m <span class="hljs-string">"Adds Highlander gamemode"</span> git push origin another-feature # Made both PRs, both were merged, so we<span class="hljs-symbol">'re</span> done here git checkout master git branch -d my-<span class="hljs-keyword">new</span>-feature # Delete both old branches git branch -d another-feature </code>
Glossary: The Inner Machinations of Git
Just for reference, here's a little glossary of Git concepts and terms explained in a little more detail, all in one place.
- 'Branches' are self-contained versions of the codebase that you can add commits to. The default branch is master, but you can make as many as you like.
- 'Repositories' are essentially just folders where you can use Git to make changes and keep track of changes made. Local repositories are repositories you have on your computer, and remote repositories are repositories that live on websites like <a href="https://github.com/space-wizards/space-station-14">GitHub</a>. Repositories are made up of a lot of branches.
- 'Remotes' are names for and links to remote repositories that your local repository can use.
- 'Submodules' are repositories that are located inside another repository.
- 'Forks' are repositories that are based on another repository. If you're going to make a pull request to the SS14 repo, you need to fork it first.
- 'The working tree' is just every file and folder and what not that's in the repository.
- 'Staging' means adding (with
git add
) changes from your working tree into the 'staging area', where some actions can be performed on it - 'Commits' are snapshots of the repository's working tree at a given time. Basically a save point. A 'commit' is just a list of files that have been changed from the last commit, and the changes that are 'committed' are the changes that you've 'staged'.
- 'Checking out' is the act of switching to another branch so you can mess with it or look at its changes locally.
- 'Merging' is the act of integrating the changes from one branch into another branch.
- 'Merge conflicts' occur when integrating the changes from one branch into another can't be done automatically because they both change the same area in a file, or their changes are mutually exclusive in some other way.
- 'Fetching' means getting the branches and commits of a remote repository, but not actually.. doing anything with them yet. You'll just have them updated for if you want to checkout or merge them later.
- 'Pulling' is the act of integrating changes from a remote repository's branch into your local branch.
- 'Pull requests' are a GitHub-specific action that allow you to request that your local branch and all of its changes is merged into another repository's branch.
- 'Pushing' is the act of integrating your local changes into a remote repository.
There are way more commands and concepts than this, but this is all you really need to know for basic development work.
Appendix A: Helpful tips and tricks
There's some stuff I didn't cover, but you'll almost inevitably have to do at some point. I'll cover these all exclusively as git commands in Git Bash quickly, but they're not too hard to figure out in the other programs (same keywords, just look for those). I recommend using their specific guides because I don't know TortoiseGit / SmartGit / GitKraken / Github Desktop well enough to help you with more advanced stuff.
One note since it comes up a lot here: HEAD
is a fancy name for the commit that you're currently on. Nothing more than that. Branches are also technically fancy names for commits, but you don't need to know that yet.
A lot of these can be found probably more eloquently in Oh Shit, Git?! (see resources above)
Resolving merge conflicts
WIP i'll write a better guide for this later because it's important
A nasty little maintainer has told you to 'resolve conflicts' or your PR 'wont be merged'. What an asshole! Thankfully, it's not too hard.
First, you're going to want to update your local master branch
. See above for how to do that.
When you run git merge master [local branch]
, it'll either do it cleanly (woohoo) or tell you you have to resolve conflicts (wahhhh).
All you need to do to resolve conflicts manually is go into the files that are conflicting, remove all the >>>>HEAD
and ===== <<<<master
nonsense (just notates where the changes originated) and then edit the file so that it properly integrates both sets of changes. Sometimes this is easy, sometimes it's hard. If it's hard, you probably know what you're doing. After that, just git commit
.
Atlassian has a really good guide for this <a href="https://www.atlassian.com/git/tutorials/using-branches/merge-conflicts">here</a>
Checking history
git log --oneline
is your friend. It shows short commit hashes (unique IDs for commits), their messages, and their branches and tags.
Getting rid of local changes
You might have accidentally made changes you didn't want to, and you don't want to bother with making an entirely new branch or something--but you haven't committed those changes yet.
<code>git <span class="hljs-keyword">reset</span> <span class="hljs-comment">--hard HEAD</span> </code>
This just means 'change the working tree to the current commit, before any local changes. Or else.' You can't retrieve those local changes if you do this, so be wary.
Unstaging changes
Ah shit, I just staged RobustToolbox by accident. No fear!
<code>git <span class="hljs-keyword">reset</span> <span class="hljs-keyword">HEAD</span> [<span class="hljs-keyword">file</span>] </code>
Alternatively, to unstage everything:
<code>git <span class="hljs-keyword">reset</span> <span class="hljs-keyword">HEAD</span> </code>
Reverting a commit you made
Oh shit, your xenomorph erotica made its way into a commit/you accidentally committed a submodule! What now? Well, there's two solutions:
<code><span class="hljs-symbol">git</span> <span class="hljs-keyword">revert </span>HEAD </code>
This makes a new commit undoing the current commit, and then commits it. Hehe commit.
If you want to undo a different commit, you can check its hash in git log --oneline
and then call git revert [commit hash]
. Git has a more robust system for doing this; you can do git revert HEAD~1
to undo the commit before your current one or git revert HEAD~2
to revert the one before that. The ~1
just means '1 commit before HEAD'.
Alternatively,
<code>git <span class="hljs-keyword">reset</span> <span class="hljs-comment">--hard HEAD~1</span> </code>
I don't recommend doing this unless you're fully aware of what you're doing.
For when you REALLY don't want anyone to know about that xenomorph erotica you just made. This method rewrites history, so it isn't the best for a collaborative environment. If you do this, you'll need to force push (git push origin [branch] --force
) or else it won't work. Force pushing can be dangerous, so again, be sure you know what you're doing.
Checking out a PR's changes locally
Ok, this one is a little difficult. There's a couple ways to do this:
Github CLI
Install github's fancy CLI and do this:
<code>gh <span class="hljs-keyword">pr</span> checkout [<span class="hljs-keyword">pr</span> number] </code>
Neat.
Changing .git/config
Go into your .git folder (hidden by default--may need to enable showing hidden folders in Windows), and open up the 'config' file. There should be a bit that looks something like:
<code>[remote <span class="hljs-string">"upstream"</span>] url = <span class="hljs-symbol">https:</span>/<span class="hljs-regexp">/github.com/space</span>-wizards/space-station-<span class="hljs-number">14</span> fetch = +refs/heads/*<span class="hljs-symbol">:refs/remotes/upstream/*</span> </code>
Add a line to this that reads fetch = +refs/pull/*/head:refs/remotes/upstream/pr/*
, so that section should now look like:
<code>[remote <span class="hljs-string">"upstream"</span>] url = <span class="hljs-symbol">https:</span>/<span class="hljs-regexp">/github.com/space</span>-wizards/space-station-<span class="hljs-number">14</span> fetch = +refs/heads/*<span class="hljs-symbol">:refs/remotes/upstream/*</span> fetch = +refs/pull/*<span class="hljs-regexp">/head:refs/remotes</span><span class="hljs-regexp">/upstream/pr</span><span class="hljs-regexp">/*</span> </code>
Now, git fetch upstream
. This method is great if you're a maintainer, but it also.. fetches every branch that's still up from every PR that's been opened, so not fantastic if you just wanted one thing. From here, you can git checkout upstream/pr/[pr number]
to check out their branch. This is basically what GitHub CLI does but less sophisticated.
Adding a new remote
This method kinda sucks because it takes a while but if you want to check out someone else's fork of the game and their branches it's pretty nice.
Not actually that hard but its confusing if you don't know Git very well. Set up a remote to the user's remote repository, fetch their branches, and then checkout their branch:
<code>git remote add [username] <span class="hljs-link">https://github.com/</span>[<span class="hljs-string">username</span>]/space-station-14 git fetch [username] git checkout [username]/[branch name] </code>
This also lets you make PRs to their remote branch, if you so desired.