Getting Started with Git and SourceTree
If you are new to version/source control then please read the "beginners" documents in the Source Control Guide, so you can understand the terminology (also check out the Source Control Acronyms Page). This guide does however assume you have never used Git/SourceTree before, so starts right from the beginning!
Note that this guide will use source and version control interchangeably. They both refer to the same thing for the purposes of this guide.
Jump to step:
- Install SourceTree
- Join Bitbucket
- Complete SourceTree Setup
- Enter User Information
- Creating a New Repository
- Example Project Creation
- Ignoring Files and Directories
- Staging Files
- Initial Commit
- Committing Changes
- Creating a Branch
- Example New Development Feature
- Committing Changes to the Development Branch
- Merging Branches (No Conflicts)
- Example Conflict Creation
- Merging Branches (With Conflicts)
- Tagging Commits
There are a number of clients you can use for working with Git, and in fact you can do everything from the command line, but the one we recommend is SourceTree, which is free, comes with Git, and works well: https://www.sourcetreeapp.com/
Download and install SourceTree, and ensure “Launch SourceTree” is ticked once it is installed, then click Finish.
We will now move to Bitbucket, but keep SourceTree open as we will complete the set up within it shortly.
If you have not done so already, visit https://bitbucket.org/account/signup/ and create an account. An example is shown below:
You will be sent an email to verify your account email address. Click on the link in the email, which will take you back to Bitbucket to choose a username. Choose something professional, and click submit.
You are now part of Bitbucket!
To fully install SourceTree, we will need to connect it to your Bitbucket account, which doubles as an Atlassian account, as well as install Git. Complete the following steps:
- License Agreement: Read and Agree.
- Atlassian Account: Connect your Atlassian (Bitbucket) account by entering your username and password from the previous step into the existing account option.
- Remotes: Connect your remote account by entering your Bitbucket username and password from the previous step and click Continue.
- Install Tools: Ensure “Configure Automatic Line Ending by default” is ticked, and click Continue.
- A pop up will ask you whether you want a Global Ignore File. This is a good idea, unless you are commonly changing computers. Typically click Yes (this guide assumes you clicked Yes).
- Starting Repository: Click Skip Setup, or continue without creating a new Repo, or cloning an existing one.
- Load SSH Key: Cancel
In order to make commits, you will need to tell SourceTree who you are. Click Tools->Options, and under the general tab, enter your name and email address as per your Atlassian Account, and click OK.
Creating a New Repository
Click the “Clone / New” button on the SourceTree menu:
Select “Create New Repository”, select the destination path (use the … button), ensure the name is correct (short, specific, avoid the word Repo), and click Create:
When starting a new project, this folder should be empty (typical workflow).
For the purpose of this guide, we will create an example Win32 C application using Visual Studio. You can create a new project in whichever environment you are most comfortable with.
1) Create a project :
2) Create a new source file (e.g. main.c), and create a default program, compile it and ensure it runs correctly:
At this point we now have a functioning program that has been tested, and we can commit it to source control.
Once you have some source files of a functioning program to commit, we can begin to think about our initial commit. This step is the first stage in every new repository. Back in SourceTree, under the new repository you will see a number of files listed with “?” within unstaged files, as shown in the figure below. This means these are new files Git has not seen before, and is asking what should be done with them.
Before we blindly add all these files to our repository, it is worth checking what exactly these files are. Remember we do not want to add binary or intermediate files to source control, and noting many of the files (at least from Visual Studio) are intermediate or diagnostic files, we definitely do not want to add them to source control.
As a general rule of thumb, any files which are in a Debug or Release folder we do not want to add to source control, nor any binary file (unless it is past of software testing). You can identify a binary file by when you left click on it within SourceTree, it is not displayed in the file viewer on the right.
The list below shows the files SourceTree + Git has identified are different from the repository history. For this project, only the bottom four we want to add to source control (source + project files), but we will set up a couple rules now to stop the remainder of the files always being flagged as new.
Directory Ignore: For this repository we are going to “ignore” all files within the Debug directory, meaning we want Git to forget about them and not monitor any changes to them. This is a fairly all-encompassing operation, so ensure you apply it carefully.
Right click on a file in the directory we want to ignore in the Unstaged area, and click “Ignore”:
Within the pop-up window, select the option “Ignore everything beneath:”, and select the Debug folder:
You may choose to ignore for all repositories, although this is definitely not recommended for directories. Generally, it is better to change specific ignore parameters per repository, especially when working across multiple computers or multiple team members.
Click OK and all files under Debug/ will be removed from the unstaged list, and a new “.gitignore” file will be added. This file contains a list of files, folders, and extensions that Git should ignore for this repository only. Do not delete this file ever, you need it.
File Extension Ignore: The remaining two files we do not want are the .opensdf and .sdf files, which are intermediate debug databases generated by Visual Studio. Right click on each one, click ignore, and select the option “Ignore all files with this extension”:
The final list of unstaged files should look like the below:
Git provides a staging area where you can collect multiple files and “hunks” (parts of files) that you want to group together into a single commit. This is a very useful feature when a single commit involves changes across multiple files.
For this example, we are going to stage all the new files from our project (that are not ignored), thus click “Stage All” in the Unstaged files window. All the files will move from the Unstaged to Staged files window, with “+” next to them to indicate they will be added to source control, as below:
When committing files in the future, it is less likely you will Stage All, rather you will Stage Selected files and hunks.
With files/changes within the Staged area, you can now type your commit message (description of what changes have been made) in the text box at the bottom. For this example, we will use the standard description when doing an initial code submission: “Initial Commit”:
Once you have completed your commit message, click “Commit” to submit the changes to Git. The whole process is very quick, so you may not see anything! Once complete, click on “master” under “BRANCHES” to see your commit:
This window lists all the commits to your repository, timestamped, and by who. Any commit can be clicked on, and the files changed viewed to see what changes were made:
“+” indicates a line added, while “-“ indicates a line removed.
Return to Visual Studio, and make a couple small changes to your main function, such as the below:
Save the file, compile it, make sure it works, then return to SourceTree and click on “Working Copy” under File Status:
Above we see SourceTree (actually Git, but displayed by SourceTree) has identified we have made changes to our main file, and clicking on the file provides a preview of what changes were identified. Note Git does not monitor individual word changes, rather it will add and remove lines that have changed.
Creating a Branch
At any point you are free to create a “branch” of your current project/source, so that you can start, for example, developing new features, fixing a bug, or begin refactoring, without fear of breaking your working (and hopefully tested) program.
The branch effectively takes a copy of your project at a specified point in time (relative to a commit), and provides a “parallel” set of source files for you to work on. At any point you can switch back to your original branch, or any branch for that matter, thus you can have several experimental features in development at the same time without worrying about breaking the main code base.
Each branch allows its own commits, can be branched further, and when it is eventually finished (working and tested), can be “merged” back into the master branch, allowing the newly developed code to become part of the main project that everyone uses.
You can branch from any commit, but generally it makes sense to branch from the most recent commit (also called the “Working Copy Parent”). It is generally recommended to branch before you start developing a new feature/intend to branch, but it can be done later if need be.
Within SourceTree, ensure the example repository is open and the master branch is highlighted, and click Branch:
Enter the name of your new Branch, ensure “Checkout New Branch” is ticked, and click Create Branch:
Viewable below is the result of this operation, a new branch. The dot and bold indicates this is the currently “checked out” branch, meaning the one any commits you make will be assigned to. As we created this branch before we made any changes, the “head” (latest commit) of both the master and development branch are at the same place.
Back within Visual Studio, implement a new feature into the software. An example is shown below for illustration purposes:
As before, compile and test the new feature to ensure it works correctly.
Back within SourceTree, it will have picked up the new feature you implemented in the previous step. Stage the source file you modified, and enter a commit message, but before you commit, ensure you have checked out the development branch, as shown below:
With the correct branch selected and a message entered, click commit:
Return to the development branch summary by clicking on it, and you will see the development branch is now at a different point from the master branch.
At this point you now have two versions of your software, one contained within the master branch (excluding the new feature), and the other within the development branch (including the new feature). Remember you have not modified the master branch, and all the development changes are easily reversible.
For example, if you wanted to swap back to the master branch, simply right click on “Master” under “BRANCHES”, and click “Checkout master”, as per the below figure.
SourceTree will now show the master branch highlighted:
And Visual Studio will indicate changes to your source file(s) have been detected (changed by Git). Always click “Yes to All” when asked to reload the files, unless you have unsaved work.
Merging Branches (No Conflicts)
Once the development within a branch is complete and tested, it should be merged back into the master branch, so it becomes part of the main project. For projects you manage yourself, you decide when this should happen. For projects within IPL’s Bitbucket Project group, please check with your supervisor before doing this.
Merging two branches is easy, provided there are no conflicts. This step will show the process when there are no conflicts (changes made to the same part of a program in two or more different branches), which should be the typical workflow.
To begin, checkout the master branch again (if it is not already checked out):
Next, click Merge on the menu bar:
SourceTree will now ask you which commit you wish to merge into the current branch. Normally this will be the most recent commit within the branch you are merging:
Ensure “Commit merge immediately (if no conflicts)” is ticked, and click OK. Provided there are no conflicts, your repository should now look like the below:
Noting the head of the master and development branch is now on the same commit, indicating they contain the same version of the code.
You should always aim to merge code back into the master branch once you have finished development. If you leave it too long, then the chances increase rapidly that there will be conflicts which you will need to manually address (a pain, covered next).
Example Conflict Creation
What we will do now is intentionally create a conflict between two branches to show the process of resolving it. You should never aim to do this during your development!
A conflict occurs when the same line of code has been changed and committed differently to two different branches. When you attempt to merge this, Git will not decide for you which change is correct, thus you must do it manually.
Master Branch Change:
- Check out the master branch.
- Change a line within the source, e.g.
- Compile & test the change.
- Commit the change to the master branch.
Development Branch Change:
- Check out the development branch.
- Change the same line as above, but to something different, e.g.
- Compile & test the change.
- Commit the change to the development branch.
Your commit summary in SourceTree should now look something like this:
Noting the split in the graph column, indicating changes between committed versions of the code.
The least fun part of source control is merging when there are conflicts. To illustrate:
- Checkout the master branch (if not already checked out)
- Click on the merge button
- Highlight the most recent commit in the development branch, and click OK:
You will now receive an error from Git, indicating the merge operation could not be completed:
The error states a conflict exists in main.c, the automatic merge failed, thus we must fix the conflict then commit the source again.
NOTE: Never try to delete commits or branches (or even repositories!) to fix a conflict. You can reverse a commit, but this can be problematic. You are better off following the next steps.
If you close the error window, and return to Visual Studio, you will see the source has been modified to include both modifications, surrounded by arrows, and separated by “
To resolve the conflict, remove one of the offending options, and delete the markup added by Git:
Returning to SourceTree, you will see the source files with conflicts highlighted with exclamation marks:
To tell Git the conflict is now resolved, stage the source file(s) you have fixed, then commit the pre-generated commit message.
Inspecting the master branch again shows the merge operation has been completed:
Note the head of the development branch is not at the same location as the master branch, as the development branch still contains the original “Hello, Development”. What we have done is taken all other changes from the development branch (if there were any), merged them into the master branch, and told Git which part of the conflict we want to keep.
To align the development and master branches, so the development branch contains the latest master code, repeat the merge, but this time check out the development branch, and merge the master branch in:
As you can see, merging with conflicts is a pain, so avoid it if possible!
A useful feature for tracking code releases is the “Tag” feature, which allows you to tag a commit with a specific message. This could be “released for review”, or “version 1.xx released”, or some other milestone in the project. It basically creates an easy way to checkout an older version of the project, without having to scan through all the commits to locate it.
To Tag a repository, it must be associated with a branch and commit. For this example, check out the master branch again, and click Tag on the menu:
Enter a tag name (something short and descriptive), and click Add Tag:
The new tag will appear under the tag list, as well as on the commit:
Complete the Bitbucket Setup Guide to configure a remote repository.