Dependency Management Using Git Submodules

In this Dependency Management tutorial you’ll learn how to use Git Submodules to manage both internal and external dependencies for your project. By Andy Obusek.

Leave a rating/review
Save for later
Share
You are currently viewing page 2 of 3 of this article. Click here to view the first page.

Pulling Changes From A Private Dependency

When sharing code between projects, you’ll often find you need to make changes to the shared code, and also make those changes available to other projects. Git Submodules make this easy.

You’ll add some code to ImaggaRouter, commit those changes, then use those changes from PhotoTagger.

Add a new Swift file to the ImaggaRouter project and name it ImaggaRouter.swift. Replace its contents with:

import Foundation

public enum ImaggaRouter {
  static let baseURLPath = "http://api.imagga.com/v1"
  static let authenticationToken = "Basic xxx"

  case content
  case tags(String)
  case colors(String)

  var path: String {
    switch self {
    case .content:
      return "/content"
    case .tags:
      return "/tagging"
    case .colors:
      return "/colors"
    }
  }
}

This code begins to flesh out a routing enum for interacting with the Imagga API.

Now add and commit these changes to the ImaggaRouter repository. From the root of the ImaggaRouter project, execute git commit -am "Add initial ImaggaRouter path":

ImaggaRouter|master⚡ ⇒ git commit -am "Add initial ImaggaRouter path"
[master 1523f10] Add initial ImaggaRouter path
 3 files changed, 33 insertions(+)
 rewrite ImaggaRouter.xcodeproj/project.xcworkspace/xcuserdata/andyo.xcuserdatad/UserInterfaceState.xcuserstate (80%)
 create mode 100644 ImaggaRouter/ImaggaRouter.swift
ImaggaRouter|master ⇒ 

This adds the most recent changes (adding an initial implementation of ImaggaRouter.swift) to the local Git repository.

Note: This time you used the Git -am switch on git commit instead of using git add X; git commit -m "Message". The -am will add all untracked files and any files with changes to the commit. So in this case you had multiple files with changes instead of doing multiple git add X you managed to perform the functionality in one line.

Now the private dependency has been updated with changes, it’s time to pull those into PhotoTagger.

From the root of the PhotoTagger project, navigate into the submodule folder for ImaggaRouter, and execute git pull:

ImaggaRouter|master ⇒ pwd
/Users/andyo/Documents/AndyRW/PhotoTagger/Frameworks/Internal/ImaggaRouter
ImaggaRouter|master ⇒ git pull
Updating 1523f10..4d9e71a
Fast-forward
 .gitignore                                                                                             |  66 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 ImaggaRouter.xcodeproj/project.xcworkspace/xcuserdata/andyo.xcuserdatad/UserInterfaceState.xcuserstate | Bin 9652 -> 9771 bytes
 2 files changed, 66 insertions(+)
ImaggaRouter|master ⇒ 

This retrieves the latest changes from the submodule. You can verify this by opening ImaggaRouter.swift and taking a peek through for the changes you just made.

The submodule is maintained as a a separate Git repository within the main project’s folder hierarchy. This is useful to know because all the same Git commands can be used to inspect that repository as well.

For example, from the submodule folder Frameworks/Internal/ImaggaRouter, execute git log to look at the commits for the submodule. Since you just updated it, the latest commit should be as you would expect:

commit 1523f10dda29649d5ee281e7f1a6dedff5a8779f
Author: Andy Obusek <andyo@xyz.com>
Date:   Mon Feb 13 20:08:29 2017 -0500

    Add initial ImaggaRouter path

... cut ...

And just to observe the differences, that this really is a separate repository, navigate back to the root folder of PhotoTagger and execute git log:

ImaggaRouter|master ⇒ cd ../../..
PhotoTagger|master⚡ ⇒ pwd
/Users/andyo/Documents/AndyRW/PhotoTagger
PhotoTagger|master⚡ ⇒ git log
commit 7303c65cc0f18174cb4846f6abe5cbfb57e17607
Author: Andy Obusek <andyo@aweber.com>
Date:   Mon Feb 13 20:24:13 2017 -0500

    Add ImaggaRouter project to Xcode

Notice how the latest commit message is different? That’s one indication you’re in a different Git repository.

While you’re in the root folder of PhotoTagger, execute git status:

PhotoTagger|master⚡ ⇒ git status
On branch master
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

	modified:   Frameworks/Internal/ImaggaRouter (new commits)

Submodules changed but not updated:

* Frameworks/Internal/ImaggaRouter 1523f10...4d9e71a (1):
  > Add initial ImaggaRouter path

no changes added to commit (use "git add" and/or "git commit -a")
PhotoTagger|master⚡ ⇒ 

This status message tells you three important pieces of information:

  1. There are local changes that haven’t been committed.
  2. There have been updates to the ImaggaRouter submodule.
  3. There are specific commits that are new in the ImaggaRouter submodule.

To finally integrate the latest changes to ImaggaRouter, execute git add . followed by git commit -m "Update ImaggaRouter":

PhotoTagger|master⚡ ⇒ git add .
PhotoTagger|master⚡ ⇒ git commit -m "Update ImaggaRouter
dquote> "
[master ad3b7f8] Update ImaggaRouter
 1 file changed, 1 insertion(+), 1 deletion(-)
PhotoTagger|master ⇒ 

You’ve now made changes to the private dependency and pulled those changes back into the main project. You’re getting pretty good at this! :]

Working With A 3rd Party Dependency

Now you’ll add Alamofire as a dependency to your project as a Git Submodule. Alamofire is a popular networking library for iOS.

Adding Alamofire

Adding an external dependency is very similar to a private dependency. The only difference from what you’ve done so far is you’ll add Alamofire via its public github.com repository.

From the root folder of PhotoTagger, create a new folder under Frameworks named “External” by executing the following:

mkdir Frameworks/External

Then execute git submodule add https://github.com/Alamofire/Alamofire.git Frameworks/External/Alamofire:

PhotoTagger|master ⇒ mkdir Frameworks/External
PhotoTagger|master ⇒ git submodule add https://github.com/Alamofire/Alamofire.git Frameworks/External/Alamofire 
Cloning into '/Users/andyo/Documents/AndyRW/PhotoTagger/Frameworks/External/Alamofire'...
remote: Counting objects: 5924, done.
remote: Total 5924 (delta 0), reused 0 (delta 0), pack-reused 5924
Receiving objects: 100% (5924/5924), 2.51 MiB | 4.86 MiB/s, done.
Resolving deltas: 100% (3937/3937), done.
PhotoTagger|master⚡ ⇒ 

This adds Alamofire as a Git Submodule into a new sub-folder named Frameworks/External/Alamofire.

Execute git status to reveal the local repository’s knowledge of Alamofire needs to be committed.

To do this, execute git add . followed by git commit -m 'Add Alamofire':

PhotoTagger|master⚡ ⇒ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

	modified:   .gitmodules
	new file:   Frameworks/External/Alamofire

Submodule changes to be committed:

* Frameworks/External/Alamofire 0000000...fa3c6d0 (660):
  > [PR #1927] Fixed bug in README example code around default headers.

PhotoTagger|master⚡ ⇒ git add .
PhotoTagger|master⚡ ⇒ git commit -m "Add Alamofire"
[master 1b3e30b] Add Alamofire
 2 files changed, 4 insertions(+)
 create mode 160000 Frameworks/External/Alamofire
PhotoTagger|master ⇒ 

Now you can add Alamofire.xcodeproj to your project.

Just as before with ImaggaRouter.xcodeproj, drag Alamofire.xcodeproj into your project.

To use Alamofire, you need to add the framework as a Linked Framework to the main PhotoTagger target’s General settings.

Adding an external dependency was as simple as that!

Sometimes you come across the need to remove a dependency. Maybe it’s an old library you’re ready to stop using. Or maybe you just wanted to try out that latest and greatest new hot framework. Either way, it’s good to know how to remove dependencies that have been added as Git Submodules.