This is part two of a three part guide to using Git with Unity. Part one deals with setting up Git and Unity to work together, while part three will detail a workflow that works well with Unity projects in particular. This part is a guide to the essential Git functions you need to know to use it. It will most help those new to Git, but anyone can use this part as a Git cheat-sheet, or as an intro to SourceTree or the command line.
So…what can you actually do with this Git thing?
First, a quick overview of how Git works. Better guides have been written for this, so if you’re brand new to version control, have a look there. Essentially though, Git is a collection of snapshots, or ‘commits’ of your project. When you make a new commit, Git remembers how each file has changed since the last, so you can always revert your project to how it was at each stage. Each commit is added to the end of a ‘branch’, which is just a separate line of changes. If you want to work on a new feature, or a complicated bug fix you’d make a new branch for it, so you don’t have to worry about your changes messing everything else up, and merge it in later. Git is also a distributed version control system, this means that each user has a copy of the Git repository/repo on their own computer. To back everything up and coordinate between users, you can connect to a ‘remote’, ‘push’ changes from your computer to the remote, and ‘pull’ other users’ changes from the remote back to your computer.
OK, crash course done. Now:
My First Commit
A ‘commit’ in Git is a record of the current state of your project files. To commit, you ‘stage’ any changed files you want to save the state of, write a message summing up what changes were made, and add it to the repo. At any point you can ‘revert’ to a commit, and all your files will look as they did when the commit was made. Again, I’m not writing a complete guide to Git, and there are other fancy things you can do, but here are the steps for making 99% of all commits you’ll have to do.
By default SourceTree is split into two panels. The bottom shows all the files that have changed since the last commit (so, all of them at the moment), and the top shows all the staged files that will be included in the next commit (empty right now). In most cases, you want to add all current changes to every commit, to do this, click Add/Remove on the top bar. This will move everything from the bottom pane to the top.
Now click Commit, and the commit pane will slide down. This has a box at the top where you can (and should) enter a commit message, as well as panels showing the staged/unstaged files for any last minute changes. Click the Commit button to make your mark on history.
On the command line, you can see what files have changed with git status, changed files are listed under “Untracked files“. To stage all changes for the next commit, use git add -A. Checking the status will now list all files under “Changes to be committed”
To commit these files, use git commit -m ‘my commit message‘. It will print a summary pf the changes committed. If you check the status right afterwards, it will show the working directory as clean, since nothing has changed since the last commit yet. (Your files have not changed, just the repo)
Rolling back changes
At this stage, you have a working version control system, congratulations! You can mess with stuff, commit a batch of changes, and rest knowing that the changes are safe in the repo. Of course none of this is useful if you can’t access these changes. In Git, you do this by ‘checking out’ a commit or file (or branch). If you checkout a file at a specific commit, the file will revert to how it was at the time of the commit. You can then edit it further and commit just as though you had reverted the changes by hand.
If you want to look at the state of the whole project as it was at a point in time, you can checkout an entire commit. This doesn’t affect your working directory at all, so you can easily look back in time, then switch back to the present. However, when you checkout an entire commit you’ll put your repo into a ‘detached HEAD’ state, which just means that you’re no longer at the end of a branch and can no longer make a new commit. If you want to save changes, you can always start a new branch, or go back to the end of current branch and checkout each desired file individually.
Right click on any file in the ‘File Status’ view (choose Show All from the dropdown near the toolbar to see all unchanged files), and choose Reset to Commit… The window that slides down will list all the commits you’ve made. Click one to see the state of your chosen file at this commit, and click OK to revert the file. In SourceTree’s ‘Log’ view, you can see a list of all commits in your repo, across all branches (colour coded!). If you click on one, the bottom pane will show the changes that were made in that commit. Right click any of these files and choose Reset to Commit to revert the file back to how it was at the time of this commit.
If you double click a commit in the log view, you can to revert all your files to the state they were at that time. SourceTree will warn you if you try to do this as it will put your repo into a ‘detached HEAD’ state (you will no longer be at the end of a branch). You’ll need to either go back to your most recent commit and pick files to reset to manually, or start a new branch at this commit. This can be handy for quickly seeing how a game ran at a certain point in time.
You can use the command git checkout commitID filename to revert a file to its state at a given commit, and git checkout commitID to revert all files to a commit, putting your branch in a ‘detached HEAD’ state. Again, you’ll need to go back to the latest commit in the branch (git checkout branchName), or start a new branch, if you want to make and save changes. To get the commit ID’s, you’ll probably need to list your commits. The simplest way to do this is using git log –oneline, the commit ID is the 7 character code at the beginning of each line.
Adding a Remote
You can now commit to your hearts desire. However, with everything stored only on your computer, it isn’t so safe. A remote is the Git name for a backup server. You and your team “push” commits to the same remote, and you “pull” other commits down to your computer. (It’s a little more complex than that when working as a team, but I’ll go over that in the next part). So how do you add a remote?
Go to Repository > Repository Settings, then click the Add button. Enter a name for your remote (usually origin), then enter the URL of your remote if it’s already set up (it should be of the form https://domain.com/remoteRepoName.git). Otherwise, if you have a Github or Bitbucket account, you can click the globe button to the right, and add a new remote from there.
So this is the kind of stuff that makes people stick to the command line. To add a remote you just use git remote add https://domain.com/remoteRepoName.git remoteName. To see a list of remotes and their URLs at any time, use git remote -v.
Pushing to a remote
A git remote won’t sync automatically with your local repo, so to keep your project backed up, you need to push your commits to the remote regularly. These instructions are assuming you’re pushing to a branch that only you are using. So if you’re working alone from a single computer, or committing to your own branch, push away.
Press the Push button in the top toolbar. A pane will slide down, listing the branches that are able to be pushed. The first time you push to a new remote, you’ll need to tick the master branch to have it set up and tracked on the remote. Otherwise, just click OK to push changes on the selected branches to the remote.
On the command line, you just need the command git push remoteName branchName. Git will add the branch to the remote and set up tracking for you if needed. Use git remote show remoteName to see details about the given remote.
Cloning is when you want to pull an entire project down to your computer. You’d do this when joining someone else’s Git repo, or if you lose your local project. If you do this, the repo and Unity project will already be set up properly, so you won’t have to do any additional setup before committing yourself, which can be a huge timesaver.
This is pretty similar to starting a new project. Click on the Add Repository icon from the Bookmarks window, or File > New. This time though, click on the Clone Repository tab, and enter the URL of the remote you want to clone. Then enter a local path and name for the new repo, and click OK to start pulling it down. Again, you can click the globe icon for a window showing all repos on your linked accounts. Note : my URL starts with eddiecameron@, this just means that SourceTree will always try to log in as me when I connect to the repo. If you don’t have this part, it will probably just prompt you when you try to connect, so don’t worry.
Use the command git clone RepoURL to clone the given repo into the current directory. You can easily get the correct URL from the Bitbucket site for your repo, on the right of the screen. Depending on how you set up your Git install, it may ask you for a username and/or password, this is the login to your Bitbucket(or other host) account.
So, that’s it for the Git basics. This by no means covers everything, but it does go over the stuff you need to use it respectably. Check back in Part 3 for an explanation of my Git + Unity workflow and how Git will take a lot of pain and time out of Unity development.