Getting to grips with git – the stash, working directory, index, local repo, remote repo

When starting git it’s really helpful to know there are a bunch of locations your source can exist. These are the:

  •  stash
  • working directory
  • index
  • local repo
  • remote repo

I don’t know if this cheat sheet helps or just overwhelms but some may find it useful:


git stash

The docs say:

git-stash - Stash the changes in a dirty working directory away

but there are plenty of ambiguities here.


What exactly does stash mean?

And what’s a dirty working directory?

Say you’ve got this:

On branch master
Changes not staged for commit:
  (use "git add ..." to update what will be committed)
  (use "git checkout -- ..." to discard changes in working directory)

	modified:   A

Untracked files:
  (use "git add ..." to include in what will be committed)


in your current directory your gut reaction might be that it will store your changes to both A and B. After all you’ve changed both and they’re both in your working directory.

That’s not the case:

git stash
Saved working directory and index state WIP on master: 2236ca9 with A
On branch master
Untracked files:
  (use "git add ..." to include in what will be committed)


nothing added to commit but untracked files present (use "git add" to track)

B is ignored. You need to add it to the repo to stash it.

To stash B, use git stash -u


Note: a dirty working directory would seem to indicate a changed file in the current working directory. It isn’t.

dirty state means modified tracked files and staged changes

working directory is a repository created with the git init command.


Useful discussions:


View stash

List stashes with:

git stash list

View contents of stash with:

git stash show -p stash@{0}


Apply stash

Apply stash with:

git stash apply stash@{0}

Note that this won’t remove the stash from the list.


If you attempt to stash it again, you’ll just add another identical entry into your stash list.

To remove it from the list use:

git stash drop stash@{0}


git log –all

Despite git’s power, it can be very un-intuitive.

E.g. you run git log expecting to see all log messages. Not true. You have to run git log –all to see all of them (* see Note 1 below).

And the output is not obvious. e.g.

commit c751111
Merge: fc07fdf 4059fc6
Author: <author>
Date:   Mon Apr 20 14:42:08 2015 -0400

WIP on dev/app/admin/categories: fc07fdf with auto categories

commit 4059fc6
Author: <author>
Date:   Mon Apr 20 14:42:08 2015 -0400

index on dev/app/admin/categories: fc07fdf with auto categories

commit fc07fdf
Author: <author>
Date:   Mon Apr 20 14:39:01 2015 -0400

with auto categories

Let’s go through each line:

1: shows the SHA-1 reference of that commit

2: it seems to have been a merge between 2 other commits

3: author details

4: date

5: this is an auto-generated stash message. <WIP => work in progress> on <name of branch>: <commit SHA-1 reference> <commit message>

The next line of interest is

index on dev/app/admin

Presumably this was auto-generated by git. I don’t have a clue there.


Note 1: another example of the unintuitiveness of git. It turns out that git log –all does NOT show all the log messages. Here’s what it actually does:

warning: push.default is unset; its implicit value has changed in Git 2.0 from ‘matching’ to ‘simple’.

I recently tried pushing a new branch and got this:

$ git push usb
warning: push.default is unset; its implicit value has changed in
Git 2.0 from 'matching' to 'simple'. To squelch this message
and maintain the traditional behavior, use:

git config --global push.default matching

To squelch this message and adopt the new behavior now, use:

git config --global push.default simple
When push.default is set to 'matching', git will push local branches to the remote branches that already exist with the same name.

Since Git 2.0, Git defaults to the more conservative 'simple'
behavior, which only pushes the current branch to the corresponding
remote branch that 'git pull' uses to update the current branch.

See 'git help config' and search for 'push.default' for further information. (the 'simple' mode was introduced in Git 1.7.11. Use the similar mode 'current' instead of 'simple' if you sometimes use older versions of Git)

fatal: The current branch dev/dspd/hero has no upstream branch.
To push the current branch and set the remote as upstream, use

    git push --set-upstream usb my/branch

Just enter this to change the setting:

git config --global push.default simple

More here:

Mac as a Development platform

I sometimes feel as if I spend half my time making fixes caused by Apple upgrades.

This morning I found my previously hand-crafted php.ini had been removed.

So, each time Apple does an upgrade I have to go back in and update php.ini with various customizations (like max post size, etc).

This also happened to Apache. Apple did an upgrade and I lost my virtualhosts.

And other things change too – like I now have to use mysql.server start rather than using mysqld. I can understand that things need to change but why not provide a graphic tool and just change things under the hood.

Now I try restarting MySQL and I get:

Starting MySQL
. ERROR! The server quit without updating PID file (/usr/local/var/mysql/

So clearly another update has happened that I’ll need to fix.

My experience on Linux has always been much smoother. I’m starting to wonder if I should try using it again as a development platform.

How does WordPress load templates?

The short answer:

– go see

However, here’s a worked-out example.

I have a page called News with the slug “news”.  Here’s how WordPress loads the necessary page:

1. Apache runs your root /index.php file

2. This require’s


3. wp-blog-header then:

require_once’s wp-load.php

runs wp() and

require_once’s template-loader.php

4. template-loader.php does a few checks and then runs a huge if, elseif:

if ( defined('WP_USE_THEMES') && WP_USE_THEMES ) :
   $template = false;
   if     ( is_404()            && $template = get_404_template()            ) :
   elseif ( is_search()         && $template = get_search_template()         ) :
   elseif ( is_front_page()     && $template = get_front_page_template()     ) :
   elseif ( is_home()           && $template = get_home_template()           ) :
   elseif ( is_post_type_archive() && $template = get_post_type_archive_template() ) :
   elseif ( is_tax()            && $template = get_taxonomy_template()       ) :
   elseif ( is_attachment()     && $template = get_attachment_template()     ) :
      remove_filter('the_content', 'prepend_attachment');
   elseif ( is_single()         && $template = get_single_template()         ) :
   elseif ( is_page()           && $template = get_page_template()           ) :
   elseif ( is_category()       && $template = get_category_template()       ) :
   elseif ( is_tag()            && $template = get_tag_template()            ) :
   elseif ( is_author()         && $template = get_author_template()         ) :
   elseif ( is_date()           && $template = get_date_template()           ) :
   elseif ( is_archive()        && $template = get_archive_template()        ) :
   elseif ( is_comments_popup() && $template = get_comments_popup_template() ) :
   elseif ( is_paged()          && $template = get_paged_template()          ) :
   else :
      $template = get_index_template();


It turns out that the example given sets $template to ‘wp-content/themes/<theme name>/page-news.php’.

How does it do that? Well, if we search for the function get_page_templates() it turns out there are 3 occurrences in the WordPress code (in wp-admin/includes/theme.php and in various wp-includes files – class-wp-theme.php, template.php).

So, which one is it using?

The answer:

wp-includes/template.php which returns the value here:

$template = get_page_template_slug();

Where is get_page_template_slug() defined?

In wp-includes/post-template.php. This works out the post using the post_id.

$post = get_post( $post_id );

Then it works out the template using get_post_meta() (which is defined in post.php).

get_post_meta simply returns the result of another function get_metadata which is defined in meta.php.

The full code:

$post = get_post( $post_id );
if ( ! $post || 'page' != $post->post_type )
   return false;
$template = get_post_meta( $post->ID, '_wp_page_template', true );
if ( ! $template || 'default' == $template )
   return '';
return $template;

In meta.php > get_metadata it checks $meta_key. It cycles through a bunch of values in $meta_cache until it gets to $meta_key = ‘_wp_mf_page_template’.

The code:

if ( isset($meta_cache[$meta_key]) ) {
   if ( $single )
      return maybe_unserialize( $meta_cache[$meta_key][0] );

cycles through the $meta_cache values just to decide the template! I had 343 values!

I literally gave up here as, whilst I spotted a $meta_key = “_wp_page_template” it continued to cycle through the $meta_cache values. Without wasting more time on this I can only assume it found the value here.





Google Contacts – I can’t find any of my Contacts any more

I have all my contacts in Google Contacts.

If I want to find someone I usually type their name in the Google Contacts search box and I can find them in seconds.

This has all changed now.

The latest version of Google Contacts now searches Google+. E.g. take a look at this:

Google Contacts 588w, 622w" sizes="(max-width: 300px) 100vw, 300px" />

Here’s a search I did recently for someone called Mark.

Why does Google think it makes any sense whatsoever to search all the Marks in the entire world?

I’ve tried clicking all the menu options at the top and on the left such as “Frequently contacted”, etc.

I have literally no idea how to search my Contacts any more. Fortunately, I have my contacts synced with my iPhone and now do all my searches using the Contact app there.