How To Use Git Source Control with Xcode in iOS 7

Felipe Laso Marsetti

How to use Git source control with Xcode

Note from Ray: Tutorial Team member Felipe Laso Marsetti has ported this tutorial to iOS 7 as part of the iOS 7 feast. We hope you enjoy!

Whether you’re a solo developer or working on a team, if you’re not using source control for your projects, you should be.

Source control is amazing because it helps you more easily revert to older version of your code, see how your code has changed over time, and work as a team. And one of the best source control systems is built right into Xcode – Git!

Git is a distributed version control system initially developed by Linus Torvalds, the principal force behind the development of the Linux kernel. The nice thing about Git is there doesn’t have to be any central repository – everyone can have their own view of the code, and pull in changes from other sources.

In this tutorial, you’ll get hands on experience with Git and learn how to use it directly inside Xcode. This tutorial is fully updated for iOS 7 and covers Git using Xcode 5.

So without further ado, let’s Git going!

Gitting Started

Rather than ramble on about the theory of Git, you’re going to dive right in and try it out. You’ll create a new Xcode project and try out some typical tasks you will typically do on a day-to-day basis with Git source control.

So fire up Xcode and create a new Single View Application from the available templates.

Single View Application Template

Now, fill in the template options as follows:

GitUseExample Project Creation

  • Product Name : GitUseExample
  • Company identifier : As the name indicates, it’s your company identifier, if you have one. Otherwise, type whatever.
  • Class prefix : Leave this empty.
  • Device family : iPhone

Now click Next. The following dialog allows you to choose where to save your project. Choose the location and make sure “Create git repository on My Mac” is selected before you click the create button. Once you do that, click the “Create” button.

GitUseExample Saving

By checking that, Xcode will create an empty Git repository and use the basis of your new project as your first commit. Well, that’s exactly what you want!

versions database

All source control systems, including Git, store their data into a repository so that they can manage your project versions and keep track of changes throughout the development cycle. So think of a repository as a database for versions.

In the course of working on your project, you’ll add files, modify code, and change your project many times.

After you make a big set of changes and are in a “known good” state (typically one or more times per day), it’s a good idea to check in your changes back into the repository. This way, you have a record of “known good” states that you can always revert back to.

But what about the code that’s in your project already, that was created by the project template? Take a look at the following screen.

GitUseExample Project Navigator

Your project is still blank, and since you didn’t make changes yet, you don’t need to commit. But, basically, Xcode has added and committed several files when you created your project. That commit is the initial commit performed automatically by Xcode :]

To check that, click the Source Control menu item and select History….

Source Control Menu History

In the drop down window, notice there’s a commit along with some information about it like the commit hash, date and time, person who made the commit, files change, and commit message.

GitUseExample History

If you click on the text that says “Show 18 modified files” a new pane will drop down containing information about all of the files that were committed, as well as what was changed in each one.

Commit Modified Files

Now, try to make some changes within your files. For example, open up AppDelegate.m and change application:didFinishLaunchingWithOptions: to the following:

- (BOOL)application:(UIApplication *)application 
        didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    // Override point for customization after application launch.
    NSLog(@"application did finish launching");
 
    return YES;
}

After you save the file, you will note that AppDelegate.m now has a “M” badge next to the filename:

Modified AppDelegate.m File

The “M” badge stands for “modified.” Specifically, it means you have modified a file but not yet checked in the changes to your local Git repository.

Before committing, quickly add a simple UIButton to the View Controller file and a method that you link to the button. This is just to illustrate the different status indicators you will get for source control.

Select Main.storyboard and drag a button to the screen from the Object Library. Change the button’s displayed text to whatever you want as shown in the screenshot below.

Modified View Controller

Now, switch to ViewController.h and replace it with the following:

@interface ViewController : UIViewController
 
- (IBAction)clickTheButton:(id)sender;
 
@end

Switch to ViewController.m and add the following code:

#import "ViewController.h"
 
@implementation ViewController
 
#pragma mark - IBActions
 
- (IBAction)clickTheButton:(id)sender
{
    NSLog(@"This is a Git tutorial");
}
 
@end

The last thing to do is to link the method to the button. Switch back to Main.storyboard, click the View Controller in the View Controller scene, and from the Connections Inspector (last tab on the right sidebar) click on clickTheButton: on the Received Actions panel and drag it to the button in the Storyboard Editor. Then choose “Touch Up Inside” from the list that pops up.

Connecting Button Action

If you check the project navigator, you will notice that the status of three files, ViewController.h, ViewController.m and MainStoryboard.storyboard, has changed to display an M badge too. That’s because you just made changes to those files.

Modified Project Navigator Files

Build and run to make sure the project works, and that when you click the button you see the “This is a Git tutorial” message logged to the console.

Button Action Console Log

w00t – you now have a set of code in a “known good” state, it’s time to commit!

Making Some Commit-ments

Committing files is simple – simply go to FileSource ControlCommit.

commit

A new window will show, similar to the following:

Commit Pane

As you can see, the screen is split in to two. The left pane shows the file in its current state with all changes made since the last commit. Since this is your first commit, you will see all changes made since the creation of the project.

The right pane shows the file before you made your changes.

Before And After

Note the blue selections in the code panes. Those indicate the code you added. Even if you add a blank line or white space, Xcode assumes it’s a change and will indicate it with those blue selections.

Try it for yourself: tap the “Cancel” button, go back to ViewController.h, press the Return key to make a new line (or several). Then go to the Source Control menu and select Commit one more time. You should result similar to the following:

Git Modifications

This might be a bit obvious, but Git does carefully track every single change you make throughout your development cycle.

Let’s take a deeper look on that screen to see what Xcode has prepared for you.

Commit Pane Layout

The left pane shows your project files, you can notice these files with the M status which you just modified. Xcode, by default, checks all the files with the M status and assumes that you want to commit all of them.

If you want to eliminate one or more files from being committed, you simply need to uncheck it. You can also decide what to commit within the file and discard individual changes made.

This is called “cherry picking” changes. Let’s try it out!

In the version editor, all your changes are enumerated by Xcode. If you scroll the editor, you will see change 1,2, etc., as shown in the screenshot above.

Each change is checked by default. To eliminate a specific change from being committed just uncheck it.

For example, change 1 is not important since it’s a class extension and that could be useful later on. So uncheck that one so that change isn’t committed.

Cherry Picking

Notice the indicator has turned to gray, to make it clear that change is now excluded from the commit process.

Another way to exclude an individual change in the same file, is to click on the arrow next the change number. Two options will appear: “Commit” (or “Don’t Commit” in case the change is checked) and “Discard Change”. In this case, you just need to select “Don’t Commit”.

Screen Shot 2013-09-24 at 8.14.19 PM

Now let’s commit the rest of the changes. Before you do, be sure to enter a commit message in the bottom part of the screen. This helps you better understand at a glance what each set of changes contain.

Commit Message

Then click commit. Congrats, you have made your first commit! If you go back to the History pane you should see your new commit in the log:

Commit History

This simple process (making changes, and then committing them) is what you’ll be doing 90% of the time. Pretty easy, eh – so you have no excuse not to do it! :]

Branching Off

Another feature in Xcode is committing your changes to a specific branch.

But wait a minute – what’s a branch?

Actually, believe it or not you’re already using a branch. When it’s first created, your project is associated to a branch called “master”. This branch is created automatically by Xcode and, as its name indicates, is the main branch of your project.

“But what is a main branch?”, you may ask. Hmm, ok. Take a look at the following picture:

Basically, the master branch should always keep the main copy of your project. So, when you are working on a project, master should usually refer to the release version.

But you can have other branches as well. One good use for branches is to keep track of experimental new features that aren’t quite ready for the release version.

For example, let’s say you’re adding a new map feature into your app, but it isn’t quite ready for production. To simulate this, create a new class derived from NSObject and name it MapForItenerary. At this point your project might look like this:

Adding New File

Notice the status “A” for the two new files MapForItinerary.h and MapForItinerary.m. This indicates there is a new file that has not yet been committed to the repository.

Now, go to the Commit option in the Source Control menu.

Commit Menu For New File

If you select one of the files with the A status, you may notice that Xcode didn’t provide any earlier version to compare to. This is because the file hasn’t been committed to the repository yet, so there is nothing to compare it with.

Ok, so you added 2 files (MapForItinerary.h, MapForItinerary.m) to the project – Xcode detected that and is ready to commit. However, you may want to commit these new changes to another specific branch. That will help to isolate the risk in case there are some problems with your new map code, as you’ll see later.

Instead of clicking the “Commit 4 Files” button, click the “Cancel” button instead and go to Source Control, select the current branch under “Working Copies” and then select “New Branch…”.

Source Control Menu New Branch

The following dialog will appear to give you the option to name your new branch:

New Branch Name Pane

Name the branch “map_feature” and click the “Create” button. You are automatically switched to the new branch so go ahead and commit these changes and give them a descriptive message:

Commit Message

Once you finish, click the commit button again.

You will see the status letters next to your map files has been cleared. That’s because Xcode has added those files when you committed.

Project Navigator After Commit

You can now see your branches in the Source Control menu by selecting “Configure GitUseExample” under “Working Copies”:

Configuring Git Project

And then, inside the configuration pane, select the “Branches” tab:

Branches Tab

Backing Out

Let’s say you’re working on the latest revision of your project, adding code, and so on. But it appears that you’ve taken a wrong turn somewhere and the project isn’t compiling properly. At this point, you may want to recover the last revision from source control and start fresh.

badstableversion

Git provides this kind of project backup :]

Let’s try it. Go to MapForItinerary.h and make the following changes:

@interface MapForItinerary : NSObject
 
// This is a fake method just to make the discard action clear for you
-(void)fakeMethod;
 
@end

And replace MapForItinerary.m to look like this:

#import "MapForItinerary.h"
 
@implementation MapForItinerary
 
- (void)fakeMethod
{
    // This is a fake method just to make the discard action clear for you
    NSLog(@" Discarding changes allow you to get the latest revision you have worked on it.");
}
 
@end

You’ll notice that the status of the modified files has changed to M, meaning that the files are locally modified and are waiting to be committed.

At this point, you can selectively discard the changes you’ve made to the file. Select MapForItinerary.h in the project navigator and then select Discard Changes in “MapItinerary.h” from the Source Control menu.

Discarding File Change

A prompt will show up, asking you whether you really want to discard the changes you made to that file.

Discard Prompt

Click the “Discard Changes” button. You should see the code you just added vanish! This can be extremely useful when you’ve added some changes but they aren’t working, and you want to get back to the last known good state.

In addition to discarding an entire file’s worth of changes, you can discard individual changes as well.

As this point, MapForItinerary.m should still have the “M” change on it. Select the commit option from the Source Control menu, and find the change to MapForIternerary.m. Click the badge in the middle and choose Discard Change:

Selective Discard

A prompt window will appear, click OK and the change should disappear. If you want to cancel your action, press Command + Z. Boom – the change is gone! Go ahead and enter a log message and finish the commit.

Now that you’ve tried out “Discard Change”, you might wonder what the difference is between that and the “Don’t Commit” option you chose earlier.

It’s true that both of these options result in the change not being pushed to the repository, but there is a difference:

  • Don’t Commit lets you skip the change so that it won’t be committed with other changes, but it will remain in the local source code.
  • Discard Changes not only skips the change, but also deletes it from the local source code.

Time Travel

Discarding changes is a good way to revert back to working code and save you time. However, it can be a little limiting in some cases.

Let’s go back to the commit action for a moment. Commit allows you to save multiple revisions for your project where each revision has specific changes. These are all stored into a repository managed for you by Git.

If you choose to discard changes made to a file, this will give you the last committed version of the file and only the last. And that’s actually where the limitation lies.

Let’s say your project repository contains several revisions over time and that you want to get the first one for a particular file or the second version, but not necessarily the last. Discarding changes doesn’t get you that. But there’s a way this can be done easily with Xcode and Git.

Select the file that you want to revert back to from a previous revision from the Project Navigator. Let’s say ViewController.m, then go to View > Version Editor > Show Version Editor. (Alternatively, you can tap the third button under the Editor section on the toolbar at the top right of the Xcode window.)

The version editor is split into two panes as shown below:

Version Editor

This allows you to compare two revisions of the selected file. In your case, two revisions of ViewController.m. The comparison is based on the time line, so click the timeline viewer icon (marked on the screenshot below) to show it up.

Version Editor Icon

Now, you can move up and down the timeline using your mouse cursor to select the version you want to get back to.

Version Editor Rollback

For example, the oldest version of the ViewController.m file, as shown in the image above, was committed on September the 24th. If that is the version that you are looking for then simply tap the indicator for the revision to open that specific version in the right editing pane :]

Comparing File Versions

Now, to revert to that file version, just click the middle section of a change in the comparison pane and select “Discard Change”. It’s that easy! :]

Another useful feature which is good to know about is the Blame view. This view allows you to catch every commit on your file easily, in real time, so that you can distinguish which commit deals with each revision.

Let’s switch to the blame view. Click and hold down the left mouse button on the version editor button, then select “Blame”.

Screen Shot 2013-09-26 at 10.05.13 PM

You will get something like this:

Screen Shot 2013-09-26 at 10.06.44 PM

Choose the file you want to view its commits from the project navigator pane, for example, ViewController.m.

In the right sidebar, you may notice all the commits you did for this file. Actually, blame view is the best way to see all the commits from different revisions related to a specific file, all merged together in one place.

To see more details around a committed change press the info button next to the date, you will see the revision ID that belongs to the change, who did that change, and other eventual files changed in the same revision. That’s better than going to your project repository in the organizer and searching for such changes, isn’t it? :]

Commit Info

Branching : Isolating the risk

Git allows you to work on multiple streams of revisions and these different streams are known as branches. The main code you work on for a project is called the main branch. So, as you work on a project, you might branch off a development stream from the main branch to a secondary branch – sort of like a tree.

Typically, it’s good coding practice to always work on a copy of your project – the development branch, if you will. And once you complete a development milestone, you normally merge the development branch back to master.

trunk

Let’s practice working with branches!

Go to the Source Control menu item and, under Working Copies, select “Switch to Branch…”.

Switching Branches

From the list of available branches select master and click Done.

Switching to master

When you create a new branch you start off from the state of the current branch you are working on. In this case you are switching to master so you start with the work from that branch. You don’t want to use map_feature for now as it’s still not finished and it’s related to another feature that may not make it into the app any time soon.

Go to the Source Control menu and, also under Working copies, select “New Branch…”.

Screen Shot 2013-09-26 at 10.23.47 PM

Name the branch “New-Branch” and click Create.

New Branch Name

To switch between branches using Xcode, first make sure that the project directory is selected and then click the “Switch Branch” icon on the bottom right corner.

switch branch

You can verify that you are working on “New-Branch” by clicking in the Source Control menu item and looking at the name of the branch under Working Copies.

Verifying Branch

Now, let’s see how changes performed on a branch will be applied to master when merging.

What you are going to do is add a simple UILabel to the user interface in the new branch you created. Then, you will merge the new branch back to master and verify it works.

Switch back to the standard editor view, select Main.storyboard, bring up the object library, and drag a UILabel on to the main view.

My New Label

Save and run to make sure that all is OK and then commit changes to the repository. Be sure to add a commit message.

Now switch to the master branch and run the app again. You’ll notice that the new UILabel you added in the branch is not there. Obviously, that’s because you changed the working branch. The final job is to merge the new branch back to master, or, in other words, apply the changes performed in New-Branch to master.

Go to Source Control > Working Copies > Merge from Branch….

Merge From Branch

From the list of available options select New-Branch and click Merge.

Branch Selection

A new window will show up where you can use the left and right buttons on the bottom menu to specify the direction of the merge. In your case, you want to merge the new branch into the master branch which is the current one. Since the current branch is on the left and the new branch is on the right, you can leave the switch at the bottom of the pane as is (shown in the image).

Merging your branch

Finally, click the “Merge” button to start the process :] You might be prompted at this point to enable automatic snapshots. Since you have your changes going to a Git repository, the snapshot feature is not necessary, so select “Disable.”

If all goes well, you should see the changes (the UILabel) from the new branch appear in the user interface when you click on Main.storyboard or when you run your application. Now your changes are in the master branch because of the merge!

iOS Simulator Screen shot Sep 26, 2013 10.37.56 PM

Where To Go From Here?

Congratulations, you now know how to use Git source control from Xcode, use branches, merge branches, and more!

At this point you have most of the tools you’ll need on a day-to-day basis to work with Git source control in Xcode. If you’d like to learn more, check out our new book iOS 7 by Tutorials, which includes two complete chapters that go into much more detail into Xcode and Git integration.

I hope you enjoyed this tutorial, and I am looking forward for your comments! :]

Felipe Laso Marsetti

Felipe Laso is an iOS developer working at Lextech Global Services. He’s also an aspiring game designer/programmer. You can follow him on Twitter as @airjordan12345 or on his blog.

User Comments

32 Comments

[ 1 , 2 , 3 ]
  • Felipe, Thank's for this great tutorial! Really helped me allot !
    yosihashamen
  • Great tutorial! Helped out a lot. There are a few things I would like to have seen.

    1.) How to add Source Control to an existing project. I've got lots of projects I'd like to get on this system and it isn't clearly explained how to do that.

    2.) How to deal with annoying messages you can run into when trying to do merges. I don't know what stashing is, but I had to do that in order to merge a branch. It required a git command not available in Xcode. I also had a problem because I added a test case target to the master branch that wasn't the same as the one added in the feature branch. Xcode went ballistic.

    3.) How to have Xcode avoid merging stuff that's not really important, things like where breakpoints were placed in the code and other user settings that somehow change when you do little more than look at a file.

    I'm obviously a fan of source control, but it's definitely not as easy to execute as it might seem from reading the articles currently available.
    Theo
[ 1 , 2 , 3 ]

Other Items of Interest

Ray's Monthly Newsletter

Sign up to receive a monthly newsletter with my favorite dev links, and receive a free epic-length tutorial as a bonus!

Advertise with Us!

Vote for Our Next Tutorial!

Every week, we alternate between Gaming and Non-Gaming tutorial votes. This week: Non-Gaming!

    Loading ... Loading ...

Last week's winner: How To Make a Tower Defense Game with Swift.

Suggest a Tutorial - Past Results

Hang Out With Us!

Every month, we have a free live Tech Talk - come hang out with us!


Coming up in December: The Great CALayer Tour

Sign Up - December

Our Books

Our Team

Tutorial Team

  • Ron Kliffer

... 59 total!

Update Team

... 14 total!

Editorial Team

... 22 total!

Code Team

  • Orta Therox

... 3 total!

Subject Matter Experts

  • Richard Casey

... 4 total!