Git submodules

I think I’m ready to discuss Git submodules. My chronic problem with submodules is that I don’t use them often enough to understand how they work. From what I gather, you can do a lot more than what I’ll cover, but I’m only interested in just placing a repo in a repo.

The benefit of submodules is that you can reduce duplicate code. Instead of copying files from one repo into another, Git can manage this for you. nclud.com v3 currently has 6 submodules. These are helpful for pulling changes to external repos — in our case jquery-smartresize and jquery.form.js.

I’ve been breaking out re-useable bits of code into smaller repos and gists. So I’ve got this requestAnimationFrame polyfill, and I want to include it in another project, Inflickity. This can be done with two git submodule commands:

git submodule add git://gist.github.com/1866474.git request-animation-frame
git submodule update --init

This will add the submodule, then pull in the appropriate commit. I’ll be able to use request-animation-frame/requestanimationframe.js in the Inflickity demo.

Both those commands trigger a change in the repo, changing .gitmodules and reference to the submodule repository. This change will require a commit.

If anyone else clones the repo, they’ll have to update and init the submodules as well.

git clone https://github.com/nclud/inflickity.git
cd inflickity
git submodule update --init

EDIT Or better yet, clone the repo and pull in submodules with git clone --recursive (thx Mathias):

git clone --recursive https://github.com/nclud/inflickity.git

Now, the crazy-pants part. Per the Git reference, git submodule update

will make the submodules HEAD be detached

I think this is where I usually lose control of what was happening with my submodules. The submodule’s repository has checked out the specific commit, and is not on the master branch as I would have expected. For example, let’s try cloning the Inflickity repo and getting that submodule working.

~/projects $ git clone https://github.com/nclud/inflickity.git
Cloning into inflickity...
...
Unpacking objects: 100% (87/87), done.
~/projects $ cd inflickity
~/projects/inflickity $ git submodule update --init
Submodule 'request-animation-frame' (git://gist.github.com/1866474.git) registered for path 'request-animation-frame'
Cloning into request-animation-frame...
...
Submodule path 'request-animation-frame': checked out 'db50266cd98d2d46277fd54d24cfd37766476a00'
~/projects/inflickity $ ls request-animation-frame/
requestanimationframe.js

Great, so the contents of the submodule are there. But what happens if we check the status of that submodule repository:

~/projects/inflickity $ cd request-animation-frame/
~/projects/inflickity/request-animation-frame $ git status
# Not currently on any branch.
nothing to commit (working directory clean)

Not on any branch. Darnit. This will prevent the basic git pull from working, so you’ll have to specify remote and branch.

~/projects/inflickity/request-animation-frame $ git pull origin master
From git://gist.github.com/1866474
 * branch            master     -> FETCH_HEAD
Already up-to-date.

git submodule foreach allows you to run a shell command for each submodule, which is ideal for pulling all submodules.

~/projects/inflickity $ git submodule foreach 'git pull origin master'
Entering 'request-animation-frame'
From git://gist.github.com/1866474
 * branch            master     -> FETCH_HEAD
Already up-to-date.

Just like when adding submodules, if there are any new commits that were pulled for a submodule, you’ll need to track that change in a commit for the parent repository.

In review, my three go-to git submodule commands are:

# starts it off
git submodule update --init
# for anyone else cloning
git clone --recursive my-repo.git
# pull in any fresh commits
git submodule foreach 'git pull origin master'

This keeps me in the parent repo, and I don’t get confused popping in and out of submodules repo.

GitHub message commit link

Quickly link to a commit in a GitHub message. SHA: followed by the first 7 or so of the commit SHA for that project will be converted into a link. For example, I just dropped:

SHA: 49b5c3a6eb509

which became - SHA: 49b5c3a

More goodies in GitHub Flavored Markdown. You can also quickly reference other projects and branches.

git config —get remote.origin.url

Here’s a faster way to get the URL of a remote git repo, using git config:

git config --get remote.origin.url
# >> git@github.com:desandro/dropshado.ws.git

Or to get list all the options of local .git/config:

git config --local -l
# >> core.repositoryformatversion=0
# >> core.filemode=true
# >> core.bare=false
# >> core.logallrefupdates=true
# >> core.ignorecase=true
# >> remote.origin.url=git@github.com:desandro/dropshado.ws.git
# >> remote.origin.fetch=+refs/heads/*:refs/remotes/origin/*
# >> branch.gh-pages.remote=origin
# >> branch.gh-pages.merge=refs/heads/gh-pages

See previous method git remote show origin.

.gitconfig colors

Aw yeah, another command-line coloring post!

John Schulz pointed me to this git cheat sheat (via Rebecca Murphey). Right up front it provides the settings in ~/.gitconfig to color git command output like git diff, git status, and git branch. Here’s what I’m rocking:

[core]
  quotepath = false
  whitespace=fix,-indent-with-non-tab,trailing-space,cr-at-eol
[color]
  ui = true
[color "branch"]
  current = yellow black
  local = yellow
  remote = magenta
[color "diff"]
  meta = yellow bold
  frag = magenta bold
  old = red reverse
  new = green reverse
  whitespace = white reverse
[color "status"]
  added = yellow
  changed = green
  untracked = cyan reverse
  branch = magenta

Which looks like:

color git commands

Git create and checkout new branch

Use the -b flag with git checkout to create and checkout a new branch in one command.

# old way
git branch newbranch
git checkout newbranch

# new way
git checkout -b newbranch

git remote show origin

git remote show origin displays info for your remote origin repo. I typically use this when I want to get the URL or the remote repo. Here’s what I get in my HTML5 Boilerplate repo:

$ git remote show origin
warning: more than one branch.master.remote
* remote origin
  Fetch URL: git://github.com/paulirish/html5-boilerplate.git
  Push  URL: git://github.com/paulirish/html5-boilerplate.git
  HEAD branch: master
  Remote branches:
    master   tracked
    mobile   tracked
    stripped tracked
  Local branch configured for 'git pull':
    master merges with remote master
              and with remote master
  Local ref configured for 'git push':
    master pushes to master (local out of date)

Gollum wiki downers

I’ve been fiddling with a Gollum wiki and found a couple disappointments running locally.

  • Changes must be committed in the git repo before they are seen in the wiki.
  • Gollum only runs from master branch. Issue 94. Coupled with the previous issue, this prevents any way to preview changes. If you wish to view changes, you must commit to the master branch.
  • If the Home page is missing, no table of contents will be automatically generated (as they are on GitHub). Issue 74
  • Sidebars are not added to pages (as they are on GitHub). Issue 97

These issues are all bummers considering how slick Jekyll is.