add support for git references
diff --git a/lib/pub_cache.dart b/lib/pub_cache.dart
index f478d6d..83755af 100644
--- a/lib/pub_cache.dart
+++ b/lib/pub_cache.dart
@@ -10,6 +10,8 @@
 import 'package:pub_semver/pub_semver.dart';
 import 'package:yaml/yaml.dart' as yaml;
 
+import 'src/impl.dart';
+
 /// A programmatic API for reflecting on Pub's cache directory.
 class PubCache {
 
@@ -106,13 +108,19 @@
     if (dartlangDir.existsSync()) {
       _packageRefs = dartlangDir.listSync()
           .where((dir) => dir is Directory)
-          .map((dir) => new _DirectoryPackageRef('hosted', dir))
+          .map((dir) => new DirectoryPackageRef('hosted', dir))
           .toList();
     }
 
-    // TODO: Scan for git packages (ignore the git/cache directory).
+    // Scan for git packages (ignore the git/cache directory).
     // ace-a1a140cc933e7d44d2955a6d6033308754bb9235
-
+    Directory gitDir = new Directory(path.join(location.path, 'git'));
+    if (gitDir.existsSync()) {
+      Iterable gitRefs = gitDir.listSync()
+          .where((dir) => dir is Directory && path.basename(dir.path) != 'cache')
+          .map((dir) => new GitDirectoryPackageRef(dir));
+      _packageRefs.addAll(gitRefs);
+    }
   }
 
   Directory _getSubDir(Directory dir, String name) =>
@@ -162,7 +170,24 @@
     Map packages = doc['packages'];
     _packageRefs = packages.keys.map((key) {
       Map m = packages[key];
-      return new _AppPackageRef(_cache, m['source'], key, m['version']);
+      String source = m['source'];
+      if (source == 'git') {
+        return new PackageRefImpl.git(key, m['version'], m['description'], (curRef) {
+          for (PackageRef ref in _cache.getPackageRefs()) {
+            if (ref == curRef) return ref.resolve();
+          }
+          return null;
+        });
+      } else if (source == 'hosted') {
+        return new PackageRefImpl.hosted(key, m['version'], (curRef) {
+          for (PackageRef ref in _cache.getPackageRefs()) {
+            if (ref == curRef) return ref.resolve();
+          }
+          return null;
+        });
+      } else {
+        return new PackageRefImpl(source, key, m['version']);
+      }
     }).toList();
   }
 }
@@ -190,47 +215,6 @@
   String toString() => '${name} ${version}';
 }
 
-class _AppPackageRef extends PackageRef {
-  final PubCache cache;
-  final String sourceType;
-  final String name;
-  final Version version;
-
-  _AppPackageRef(this.cache, this.sourceType, this.name, String ver) :
-      version = new Version.parse(ver);
-
-  Package resolve() {
-    for (PackageRef ref in cache.getPackageRefs()) {
-      if (ref == this) return ref.resolve();
-    }
-
-    return null;
-  }
-}
-
-class _DirectoryPackageRef extends PackageRef {
-  final String sourceType;
-  final Directory directory;
-
-  String _name;
-  Version _version;
-
-  _DirectoryPackageRef(this.sourceType, this.directory) {
-    _name = path.basename(this.directory.path);
-
-    int index = _name.indexOf('-');
-    if (index != -1) {
-      _version = new Version.parse(_name.substring(index + 1));
-      _name = _name.substring(0, index);
-    }
-  }
-
-  String get name => _name;
-  Version get version => _version;
-
-  Package resolve() => new Package(directory, name, version);
-}
-
 /// A representation of a package, including the name, version, and location on
 /// disk.
 class Package {
diff --git a/lib/src/impl.dart b/lib/src/impl.dart
new file mode 100644
index 0000000..fe6dfcb
--- /dev/null
+++ b/lib/src/impl.dart
@@ -0,0 +1,105 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library pub_cache.impl;
+
+import 'dart:io';
+
+import 'package:path/path.dart' as path;
+import 'package:pub_semver/pub_semver.dart';
+import 'package:yaml/yaml.dart' as yaml;
+
+import '../pub_cache.dart';
+
+class PackageRefImpl extends PackageRef {
+  final String sourceType;
+  final String name;
+  final Version version;
+
+  Function _resolver;
+
+  PackageRefImpl(this.sourceType, this.name, String ver) :
+      version = new Version.parse(ver);
+
+  PackageRefImpl.hosted(this.name, String ver, this._resolver) :
+    sourceType = 'hosted', version = new Version.parse(ver);
+
+  factory PackageRefImpl.git(String name, String ver, Map description, Function resolver) {
+    return new GitPackageRefImpl(name, ver, description, resolver);
+  }
+
+  Package resolve() => _resolver == null ? null : _resolver(this);
+}
+
+class GitPackageRefImpl extends PackageRefImpl {
+  final Map _description;
+
+  GitPackageRefImpl(String name, String ver, this._description, Function resolver) :
+      super('git', name, ver) {
+    _resolver = resolver;
+  }
+
+  /// The git commit.
+  String get resolvedRef => _description['resolved-ref'];
+
+  /// The git url.
+  String get url => _description['url'];
+}
+
+class DirectoryPackageRef extends PackageRef {
+  final String sourceType;
+  final Directory directory;
+
+  String _name;
+  Version _version;
+
+  DirectoryPackageRef(this.sourceType, this.directory) {
+    _name = path.basename(this.directory.path);
+
+    int index = _name.indexOf('-');
+    if (index != -1) {
+      _version = new Version.parse(_name.substring(index + 1));
+      _name = _name.substring(0, index);
+    }
+  }
+
+  String get name => _name;
+  Version get version => _version;
+
+  Package resolve() => new Package(directory, name, version);
+}
+
+class GitDirectoryPackageRef extends PackageRef {
+  final String sourceType;
+  final Directory directory;
+
+  String _name;
+  Version _version;
+  String _resolvedRef;
+
+  GitDirectoryPackageRef(this.directory) : sourceType = 'git' {
+    _name = path.basename(this.directory.path);
+
+    int index = _name.indexOf('-');
+    if (index != -1) {
+      _resolvedRef = _name.substring(index + 1);
+      _name = _name.substring(0, index);
+    }
+
+    // Parse the version.
+    File f = new File(path.join(directory.path, 'pubspec.yaml'));
+    if (f.existsSync()) {
+      Map pubspec = yaml.loadYaml(f.readAsStringSync());
+      _version = new Version.parse(pubspec['version']);
+    }
+  }
+
+  String get name => _name;
+  Version get version => _version;
+
+  /// The git commit.
+  String get resolvedRef => _resolvedRef;
+
+  Package resolve() => new Package(directory, name, version);
+}
diff --git a/test/pub_cache_test.dart b/test/pub_cache_test.dart
index 4a5f8a2..b93c0ca 100644
--- a/test/pub_cache_test.dart
+++ b/test/pub_cache_test.dart
@@ -133,4 +133,20 @@
       expect(p.toString(), isNotEmpty);
     });
   });
+
+  group('integration', () {
+    test('list', () {
+      PubCache cache = new PubCache();
+      var apps = cache.getGlobalApplications();
+      print('${apps.length} activated applications:');
+      apps.forEach((app) => print('  ${app}'));
+
+      var packages = cache.getCachedPackages();
+      print('\n${packages.length} packages in cache:');
+      packages.forEach((pkg) {
+        List versions = cache.getAllPackageVersions(pkg);
+        print('  ${pkg} [${versions.map((p) => p.version.toString()).join(', ')}]');
+      });
+    });
+  });
 }