Merging in the new dependency resolver
diff --git a/.travis.yml b/.travis.yml
index b66cd48..3d5193d 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -17,7 +17,7 @@
 # in the vendor directory. We don't need to test all dependent packages.
 # Only testing this project.
 script:
-  - GO15VENDOREXPERIMENT=1 go test -v . ./cmd ./gb ./util ./yaml
+  - GO15VENDOREXPERIMENT=1 go test -v . ./cmd ./gb ./util ./cfg
 
 notifications:
   irc: "irc.freenode.net#masterminds"
diff --git a/cfg/cfg.go b/cfg/cfg.go
new file mode 100644
index 0000000..52874d2
--- /dev/null
+++ b/cfg/cfg.go
@@ -0,0 +1,2 @@
+// Package cfg handles working with the Glide configuration files.
+package cfg
diff --git a/yaml/yaml.go b/cfg/config.go
similarity index 60%
rename from yaml/yaml.go
rename to cfg/config.go
index 5648e22..0daa26f 100644
--- a/yaml/yaml.go
+++ b/cfg/config.go
@@ -1,7 +1,7 @@
-// Package yaml provides the ability to work with glide.yaml files.
-package yaml
+package cfg
 
 import (
+	"crypto/sha256"
 	"fmt"
 	"reflect"
 	"strings"
@@ -11,76 +11,73 @@
 	"gopkg.in/yaml.v2"
 )
 
-// FromYaml takes a yaml string and converts it to a Config instance.
-func FromYaml(yml string) (*Config, error) {
-	c := &Config{}
-	err := yaml.Unmarshal([]byte(yml), &c)
-	if err != nil {
-		return nil, err
-	}
-
-	// The ref property is for the legacy yaml file structure.
-	// This sets the currect version to the ref if a version isn't
-	// already set.
-	for _, v := range c.Imports {
-		if v.Reference == "" && v.Ref != "" {
-			v.Reference = v.Ref
-		}
-		v.Ref = ""
-
-		// Make sure only legitimate VCS are listed.
-		v.VcsType = filterVcsType(v.VcsType)
-
-		// Get the root name for the package
-		o := v.Name
-		v.Name = util.GetRootFromPackage(v.Name)
-		subpkg := strings.TrimPrefix(o, v.Name)
-		if len(subpkg) > 0 && subpkg != o {
-			v.Subpackages = append(v.Subpackages, strings.TrimPrefix(subpkg, "/"))
-		}
-	}
-	for _, v := range c.DevImports {
-		if v.Reference == "" && v.Ref != "" {
-			v.Reference = v.Ref
-		}
-		v.Ref = ""
-
-		v.VcsType = filterVcsType(v.VcsType)
-
-		// Get the root name for the package
-		o := v.Name
-		v.Name = util.GetRootFromPackage(v.Name)
-		subpkg := strings.TrimPrefix(o, v.Name)
-		if len(subpkg) > 0 && subpkg != o {
-			v.Subpackages = append(v.Subpackages, subpkg)
-		}
-	}
-
-	c.DeDupe()
-	if err != nil {
-		return c, err
-	}
-
-	return c, nil
-}
-
-// ToYaml takes a *Config instance and converts it into a yaml string.
-func ToYaml(cfg *Config) (string, error) {
-	yml, err := yaml.Marshal(&cfg)
-	if err != nil {
-		return "", err
-	}
-	return string(yml), nil
-}
-
 // Config is the top-level configuration object.
 type Config struct {
-	Parent     *Config      `yaml:"-"`
 	Name       string       `yaml:"package"`
 	Imports    Dependencies `yaml:"import"`
 	DevImports Dependencies `yaml:"devimport,omitempty"`
 }
 
+// A transitive representation of a dependency for importing and exploting to yaml.
+type cf struct {
+	Name       string       `yaml:"package"`
+	Imports    Dependencies `yaml:"import"`
+	DevImports Dependencies `yaml:"devimport,omitempty"`
+}
+
+// ConfigFromYaml returns an instance of Config from YAML
+func ConfigFromYaml(yml []byte) (*Config, error) {
+	cfg := &Config{}
+	err := yaml.Unmarshal([]byte(yml), &cfg)
+	return cfg, err
+}
+
+// Marshal converts a Config instance to YAML
+func (c *Config) Marshal() ([]byte, error) {
+	yml, err := yaml.Marshal(&c)
+	if err != nil {
+		return []byte{}, err
+	}
+	return yml, nil
+}
+
+// UnmarshalYAML is a hook for gopkg.in/yaml.v2 in the unmarshalling process
+func (c *Config) UnmarshalYAML(unmarshal func(interface{}) error) error {
+	newConfig := &cf{}
+	if err := unmarshal(&newConfig); err != nil {
+		return err
+	}
+	c.Name = newConfig.Name
+	c.Imports = newConfig.Imports
+	c.DevImports = newConfig.DevImports
+
+	// Cleanup the Config object now that we have it.
+	err := c.DeDupe()
+
+	return err
+}
+
+// MarshalYAML is a hook for gopkg.in/yaml.v2 in the marshaling process
+func (c *Config) MarshalYAML() (interface{}, error) {
+	newConfig := &cf{
+		Name: c.Name,
+	}
+	i, err := c.Imports.Clone().DeDupe()
+	if err != nil {
+		return newConfig, err
+	}
+
+	di, err := c.DevImports.Clone().DeDupe()
+	if err != nil {
+		return newConfig, err
+	}
+
+	newConfig.Imports = i
+	newConfig.DevImports = di
+
+	return newConfig, nil
+}
+
 // HasDependency returns true if the given name is listed as an import or dev import.
 func (c *Config) HasDependency(name string) bool {
 	for _, d := range c.Imports {
@@ -96,16 +93,16 @@
 	return false
 }
 
-// HasRecursiveDependency returns true if this config or one of it's parents has this dependency
-func (c *Config) HasRecursiveDependency(name string) bool {
-	if c.HasDependency(name) == true {
-		return true
-	} else if c.Parent != nil {
-		return c.Parent.HasRecursiveDependency(name)
-	}
-	return false
+// Clone performs a deep clone of the Config instance
+func (c *Config) Clone() *Config {
+	n := &Config{}
+	n.Name = c.Name
+	n.Imports = c.Imports.Clone()
+	n.DevImports = c.DevImports.Clone()
+	return n
 }
 
+// DeDupe consolidates duplicate dependencies on a Config instance
 func (c *Config) DeDupe() error {
 
 	// Remove duplicates in the imports
@@ -143,87 +140,21 @@
 	return nil
 }
 
-// GetRoot follows the Parent down to the top node
-func (c *Config) GetRoot() *Config {
-	if c.Parent != nil {
-		return c.Parent.GetRoot()
+// Hash generates a sha256 hash for a given Config
+func (c *Config) Hash() (string, error) {
+	yml, err := c.Marshal()
+	if err != nil {
+		return "", err
 	}
-	return c
-}
 
-// Clone performs a deep clone of the Config instance
-func (c *Config) Clone() *Config {
-	n := &Config{}
-	n.Name = c.Name
-	n.Imports = c.Imports.Clone()
-	n.DevImports = c.DevImports.Clone()
-	return n
+	hash := sha256.New()
+	hash.Sum(yml)
+	return fmt.Sprintf("%x", hash.Sum(nil)), nil
 }
 
 // Dependencies is a collection of Dependency
 type Dependencies []*Dependency
 
-// Dependency describes a package that the present package depends upon.
-type Dependency struct {
-	Name             string   `yaml:"package"`
-	Reference        string   `yaml:"version,omitempty"`
-	Ref              string   `yaml:"ref,omitempty"`
-	Pin              string   `yaml:"pin,omitempty"`
-	Repository       string   `yaml:"repo,omitempty"`
-	VcsType          string   `yaml:"vcs,omitempty"`
-	Subpackages      []string `yaml:"subpackages,omitempty"`
-	Arch             []string `yaml:"arch,omitempty"`
-	Os               []string `yaml:"os,omitempty"`
-	UpdateAsVendored bool     `yaml:"-"`
-}
-
-// GetRepo retrieves a Masterminds/vcs repo object configured for the root
-// of the package being retrieved.
-func (d *Dependency) GetRepo(dest string) (vcs.Repo, error) {
-
-	// The remote location is either the configured repo or the package
-	// name as an https url.
-	var remote string
-	if len(d.Repository) > 0 {
-		remote = d.Repository
-	} else {
-		remote = "https://" + d.Name
-	}
-
-	// If the VCS type has a value we try that first.
-	if len(d.VcsType) > 0 && d.VcsType != "None" {
-		switch vcs.Type(d.VcsType) {
-		case vcs.Git:
-			return vcs.NewGitRepo(remote, dest)
-		case vcs.Svn:
-			return vcs.NewSvnRepo(remote, dest)
-		case vcs.Hg:
-			return vcs.NewHgRepo(remote, dest)
-		case vcs.Bzr:
-			return vcs.NewBzrRepo(remote, dest)
-		default:
-			return nil, fmt.Errorf("Unknown VCS type %s set for %s", d.VcsType, d.Name)
-		}
-	}
-
-	// When no type set we try to autodetect.
-	return vcs.NewRepo(remote, dest)
-}
-
-func (d *Dependency) Clone() *Dependency {
-	return &Dependency{
-		Name:             d.Name,
-		Reference:        d.Reference,
-		Pin:              d.Pin,
-		Repository:       d.Repository,
-		VcsType:          d.VcsType,
-		Subpackages:      d.Subpackages,
-		Arch:             d.Arch,
-		Os:               d.Os,
-		UpdateAsVendored: d.UpdateAsVendored,
-	}
-}
-
 // Get a dependency by name
 func (d Dependencies) Get(name string) *Dependency {
 	for _, dep := range d {
@@ -234,6 +165,7 @@
 	return nil
 }
 
+// Clone performs a deep clone of Dependencies
 func (d Dependencies) Clone() Dependencies {
 	n := make(Dependencies, 0, 1)
 	for _, v := range d {
@@ -273,6 +205,130 @@
 	return imports, nil
 }
 
+// Dependency describes a package that the present package depends upon.
+type Dependency struct {
+	Name             string   `yaml:"package"`
+	Reference        string   `yaml:"version,omitempty"`
+	Pin              string   `yaml:"-"`
+	Repository       string   `yaml:"repo,omitempty"`
+	VcsType          string   `yaml:"vcs,omitempty"`
+	Subpackages      []string `yaml:"subpackages,omitempty"`
+	Arch             []string `yaml:"arch,omitempty"`
+	Os               []string `yaml:"os,omitempty"`
+	UpdateAsVendored bool     `yaml:"-"`
+}
+
+// A transitive representation of a dependency for importing and exploting to yaml.
+type dep struct {
+	Name        string   `yaml:"package"`
+	Reference   string   `yaml:"version,omitempty"`
+	Ref         string   `yaml:"ref,omitempty"`
+	Repository  string   `yaml:"repo,omitempty"`
+	VcsType     string   `yaml:"vcs,omitempty"`
+	Subpackages []string `yaml:"subpackages,omitempty"`
+	Arch        []string `yaml:"arch,omitempty"`
+	Os          []string `yaml:"os,omitempty"`
+}
+
+// UnmarshalYAML is a hook for gopkg.in/yaml.v2 in the unmarshaling process
+func (d *Dependency) UnmarshalYAML(unmarshal func(interface{}) error) error {
+	newDep := &dep{}
+	err := unmarshal(&newDep)
+	if err != nil {
+		return err
+	}
+	d.Name = newDep.Name
+	d.Reference = newDep.Reference
+	d.Repository = newDep.Repository
+	d.VcsType = newDep.VcsType
+	d.Subpackages = newDep.Subpackages
+	d.Arch = newDep.Arch
+	d.Os = newDep.Os
+
+	if d.Reference == "" && newDep.Ref != "" {
+		d.Reference = newDep.Ref
+	}
+
+	// Make sure only legitimate VCS are listed.
+	d.VcsType = filterVcsType(d.VcsType)
+
+	// Get the root name for the package
+	o := d.Name
+	d.Name = util.GetRootFromPackage(d.Name)
+	subpkg := strings.TrimPrefix(o, d.Name)
+	if len(subpkg) > 0 && subpkg != o {
+		d.Subpackages = append(d.Subpackages, strings.TrimPrefix(subpkg, "/"))
+	}
+
+	return nil
+}
+
+// MarshalYAML is a hook for gopkg.in/yaml.v2 in the marshaling process
+func (d *Dependency) MarshalYAML() (interface{}, error) {
+
+	// Make sure we only write the correct vcs type to file
+	t := filterVcsType(d.VcsType)
+	newDep := &dep{
+		Name:        d.Name,
+		Reference:   d.Reference,
+		Repository:  d.Repository,
+		VcsType:     t,
+		Subpackages: d.Subpackages,
+		Arch:        d.Arch,
+		Os:          d.Os,
+	}
+
+	return newDep, nil
+}
+
+// GetRepo retrieves a Masterminds/vcs repo object configured for the root
+// of the package being retrieved.
+func (d *Dependency) GetRepo(dest string) (vcs.Repo, error) {
+
+	// The remote location is either the configured repo or the package
+	// name as an https url.
+	var remote string
+	if len(d.Repository) > 0 {
+		remote = d.Repository
+	} else {
+		remote = "https://" + d.Name
+	}
+
+	// If the VCS type has a value we try that first.
+	if len(d.VcsType) > 0 && d.VcsType != "None" {
+		switch vcs.Type(d.VcsType) {
+		case vcs.Git:
+			return vcs.NewGitRepo(remote, dest)
+		case vcs.Svn:
+			return vcs.NewSvnRepo(remote, dest)
+		case vcs.Hg:
+			return vcs.NewHgRepo(remote, dest)
+		case vcs.Bzr:
+			return vcs.NewBzrRepo(remote, dest)
+		default:
+			return nil, fmt.Errorf("Unknown VCS type %s set for %s", d.VcsType, d.Name)
+		}
+	}
+
+	// When no type set we try to autodetect.
+	return vcs.NewRepo(remote, dest)
+}
+
+// Clone creates a clone of a Dependency
+func (d *Dependency) Clone() *Dependency {
+	return &Dependency{
+		Name:             d.Name,
+		Reference:        d.Reference,
+		Pin:              d.Pin,
+		Repository:       d.Repository,
+		VcsType:          d.VcsType,
+		Subpackages:      d.Subpackages,
+		Arch:             d.Arch,
+		Os:               d.Os,
+		UpdateAsVendored: d.UpdateAsVendored,
+	}
+}
+
 func stringArrayDeDupe(s []string, items ...string) []string {
 	for _, item := range items {
 		exists := false
diff --git a/cfg/config_test.go b/cfg/config_test.go
new file mode 100644
index 0000000..03ba08e
--- /dev/null
+++ b/cfg/config_test.go
@@ -0,0 +1,116 @@
+package cfg
+
+import (
+	"testing"
+
+	"gopkg.in/yaml.v2"
+)
+
+var yml = `
+package: fake/testing
+import:
+  - package: github.com/kylelemons/go-gypsy
+    subpackages:
+      - yaml
+  # Intentionally left spaces at end of next line.
+  - package: github.com/Masterminds/convert
+    repo: git@github.com:Masterminds/convert.git
+    vcs: git
+    ref: a9949121a2e2192ca92fa6dddfeaaa4a4412d955
+    subpackages:
+      - color
+      - nautical
+      - radial
+    os:
+      - linux
+    arch:
+      - i386
+      - arm
+  - package: github.com/Masterminds/structable
+  - package: github.com/Masterminds/cookoo/color
+  - package: github.com/Masterminds/cookoo/convert
+
+devimport:
+  - package: github.com/kylelemons/go-gypsy
+`
+
+func TestManualConfigFromYaml(t *testing.T) {
+	cfg := &Config{}
+	err := yaml.Unmarshal([]byte(yml), &cfg)
+	if err != nil {
+		t.Errorf("Unable to Unmarshal config yaml")
+	}
+
+	if cfg.Name != "fake/testing" {
+		t.Errorf("Inaccurate name found %s", cfg.Name)
+	}
+
+	found := false
+	found2 := false
+	for _, i := range cfg.Imports {
+		if i.Name == "github.com/Masterminds/convert" {
+			found = true
+			ref := "a9949121a2e2192ca92fa6dddfeaaa4a4412d955"
+			if i.Reference != ref {
+				t.Errorf("Config reference for cookoo is inaccurate. Expected '%s' found '%s'", ref, i.Reference)
+			}
+		}
+
+		if i.Name == "github.com/Masterminds/cookoo" {
+			found2 = true
+			if i.Subpackages[0] != "color" {
+				t.Error("Dependency separating package and subpackage not working")
+			}
+		}
+	}
+	if !found {
+		t.Error("Unable to find github.com/Masterminds/convert")
+	}
+	if !found2 {
+		t.Error("Unable to find github.com/Masterminds/cookoo")
+	}
+}
+
+func TestClone(t *testing.T) {
+	cfg := &Config{}
+	err := yaml.Unmarshal([]byte(yml), &cfg)
+	if err != nil {
+		t.Errorf("Unable to Unmarshal config yaml")
+	}
+
+	cfg2 := cfg.Clone()
+	if cfg2.Name != "fake/testing" {
+		t.Error("Config cloning failed")
+	}
+	cfg.Name = "foo"
+
+	if cfg.Name == cfg2.Name {
+		t.Error("Cloning Config name failed")
+	}
+}
+
+func TestConfigFromYaml(t *testing.T) {
+	c, err := ConfigFromYaml([]byte(yml))
+	if err != nil {
+		t.Error("ConfigFromYaml failed to parse yaml")
+	}
+
+	if c.Name != "fake/testing" {
+		t.Error("ConfigFromYaml failed to properly parse yaml")
+	}
+}
+
+func TestHasDependency(t *testing.T) {
+	c, err := ConfigFromYaml([]byte(yml))
+	if err != nil {
+		t.Error("ConfigFromYaml failed to parse yaml for HasDependency")
+	}
+
+	if c.HasDependency("github.com/Masterminds/convert") != true {
+		t.Error("HasDependency failing to pickup depenency")
+	}
+
+	if c.HasDependency("foo/bar/bar") != false {
+		t.Error("HasDependency picking up dependency it shouldn't")
+	}
+}
diff --git a/cfg/lock.go b/cfg/lock.go
new file mode 100644
index 0000000..921fe33
--- /dev/null
+++ b/cfg/lock.go
@@ -0,0 +1,117 @@
+package cfg
+
+import (
+	"sort"
+	"strings"
+	"time"
+
+	"gopkg.in/yaml.v2"
+)
+
+// Lockfile represents a glide.lock file.
+type Lockfile struct {
+	Hash       string    `yaml:"hash"`
+	Updated    time.Time `yaml:"updated"`
+	Imports    Locks     `yaml:"imports"`
+	DevImports Locks     `yaml:"devImports"`
+}
+
+// LockfileFromYaml returns an instance of Lockfile from YAML
+func LockfileFromYaml(yml []byte) (*Lockfile, error) {
+	lock := &Lockfile{}
+	err := yaml.Unmarshal([]byte(yml), &lock)
+	return lock, err
+}
+
+// Marshal converts a Config instance to YAML
+func (lf *Lockfile) Marshal() ([]byte, error) {
+	yml, err := yaml.Marshal(&lf)
+	if err != nil {
+		return []byte{}, err
+	}
+	return yml, nil
+}
+
+type Locks []*Lock
+
+// Len returns the length of the Locks. This is needed for sorting with
+// the sort package.
+func (l Locks) Len() int {
+	return len(l)
+}
+
+// Less is needed for the sort interface. It compares two locks based on
+// their name.
+func (l Locks) Less(i, j int) bool {
+
+	// Names are normalized to lowercase because case affects sorting order. For
+	// example, Masterminds comes before kylelemons. Making them lowercase
+	// causes kylelemons to come first which is what is expected.
+	return strings.ToLower(l[i].Name) < strings.ToLower(l[j].Name)
+}
+
+// Swap is needed for the sort interface. It swaps the position of two
+// locks.
+func (l Locks) Swap(i, j int) {
+	l[i], l[j] = l[j], l[i]
+}
+
+type Lock struct {
+	Name        string   `yaml:"name"`
+	Version     string   `yaml:"version"`
+	Repository  string   `yaml:"repo,omitempty"`
+	VcsType     string   `yaml:"vcs,omitempty"`
+	Subpackages []string `yaml:"subpackages,omitempty"`
+	Arch        []string `yaml:"arch,omitempty"`
+	Os          []string `yaml:"os,omitempty"`
+}
+
+func NewLockfile(ds Dependencies, hash string) *Lockfile {
+	lf := &Lockfile{
+		Hash:    hash,
+		Updated: time.Now(),
+		Imports: make([]*Lock, len(ds)),
+	}
+
+	for i := 0; i < len(ds); i++ {
+		lf.Imports[i] = &Lock{
+			Name:        ds[i].Name,
+			Version:     ds[i].Pin,
+			Repository:  ds[i].Repository,
+			VcsType:     ds[i].VcsType,
+			Subpackages: ds[i].Subpackages,
+			Arch:        ds[i].Arch,
+			Os:          ds[i].Os,
+		}
+	}
+
+	sort.Sort(lf.Imports)
+
+	return lf
+}
+
+func LockfileFromMap(ds map[string]*Dependency, hash string) *Lockfile {
+	lf := &Lockfile{
+		Hash:    hash,
+		Updated: time.Now(),
+		Imports: make([]*Lock, len(ds)),
+	}
+
+	i := 0
+	for name, dep := range ds {
+		lf.Imports[i] = &Lock{
+			Name:        name,
+			Version:     dep.Pin,
+			Repository:  dep.Repository,
+			VcsType:     dep.VcsType,
+			Subpackages: dep.Subpackages,
+			Arch:        dep.Arch,
+			Os:          dep.Os,
+		}
+		i++
+	}
+
+	sort.Sort(lf.Imports)
+
+	return lf
+}
diff --git a/cfg/lock_test.go b/cfg/lock_test.go
new file mode 100644
index 0000000..78dcee3
--- /dev/null
+++ b/cfg/lock_test.go
@@ -0,0 +1,34 @@
+package cfg
+
+import (
+	"sort"
+	"testing"
+)
+
+func TestSortLocks(t *testing.T) {
+	c, err := ConfigFromYaml([]byte(yml))
+	if err != nil {
+		t.Error("ConfigFromYaml failed to parse yaml for TestSortDependencies")
+	}
+
+	ls := make(Locks, len(c.Imports))
+	for i := 0; i < len(c.Imports); i++ {
+		ls[i] = &Lock{
+			Name:    c.Imports[i].Name,
+			Version: c.Imports[i].Reference,
+		}
+	}
+
+	if ls[2].Name != "github.com/Masterminds/structable" {
+		t.Error("Initial dependencies are out of order prior to sort")
+	}
+
+	sort.Sort(ls)
+
+	if ls[0].Name != "github.com/kylelemons/go-gypsy" ||
+		ls[1].Name != "github.com/Masterminds/convert" ||
+		ls[2].Name != "github.com/Masterminds/cookoo" ||
+		ls[3].Name != "github.com/Masterminds/structable" {
+		t.Error("Sorting of dependencies failed")
+	}
+}
diff --git a/cmd/delete.go b/cmd/delete.go
index 3752c9b..709dafd 100644
--- a/cmd/delete.go
+++ b/cmd/delete.go
@@ -7,7 +7,7 @@
 	"strings"
 
 	"github.com/Masterminds/cookoo"
-	"github.com/Masterminds/glide/yaml"
+	"github.com/Masterminds/glide/cfg"
 )
 
 // DeleteUnusedPackages removes packages from vendor/ that are no longer used.
@@ -27,7 +27,7 @@
 	}
 
 	// Build directory tree of what to keep.
-	cfg := p.Get("conf", nil).(*yaml.Config)
+	cfg := p.Get("conf", nil).(*cfg.Config)
 	var pkgList []string
 	for _, dep := range cfg.Imports {
 		pkgList = append(pkgList, dep.Name)
diff --git a/cmd/exec.go b/cmd/exec.go
deleted file mode 100644
index 3cc0720..0000000
--- a/cmd/exec.go
+++ /dev/null
@@ -1,41 +0,0 @@
-package cmd
-
-import (
-	"fmt"
-	"github.com/Masterminds/cookoo"
-	"github.com/codegangsta/cli"
-	"os"
-	"os/exec"
-)
-
-// ExecCmd executes a system command  inside vendor
-func ExecCmd(c cookoo.Context, p *cookoo.Params) (interface{}, cookoo.Interrupt) {
-	args := p.Get("args", nil).(cli.Args)
-
-	if len(args) == 0 {
-		return nil, fmt.Errorf("No command to execute")
-	}
-
-	gopath, err := VendorPath(c)
-	if err != nil {
-		return false, err
-	}
-
-	err = os.Setenv("GOPATH", gopath)
-	if err != nil {
-		return false, err
-	}
-
-	path := os.Getenv("PATH")
-	err = os.Setenv("PATH", gopath+"/bin:"+path)
-	if err != nil {
-		return false, err
-	}
-
-	cmd := exec.Command(args[0], args[1:]...)
-	cmd.Stdout = os.Stdout
-	cmd.Stderr = os.Stderr
-	err = cmd.Run()
-
-	return true, nil
-}
diff --git a/cmd/flatten.go b/cmd/flatten.go
index d24fd54..cfff217 100644
--- a/cmd/flatten.go
+++ b/cmd/flatten.go
@@ -7,8 +7,8 @@
 	"strings"
 
 	"github.com/Masterminds/cookoo"
+	"github.com/Masterminds/glide/cfg"
 	"github.com/Masterminds/glide/util"
-	"github.com/Masterminds/glide/yaml"
 	"github.com/Masterminds/semver"
 )
 
@@ -21,12 +21,12 @@
 //	- packages ([]string): The packages to read. If this is empty, it reads all
 //		packages.
 //	- force (bool): force vcs updates.
-//	- conf (*yaml.Config): The configuration.
+//	- conf (*cfg.Config): The configuration.
 //
 // Returns:
 //
 func Flatten(c cookoo.Context, p *cookoo.Params) (interface{}, cookoo.Interrupt) {
-	conf := p.Get("conf", &yaml.Config{}).(*yaml.Config)
+	conf := p.Get("conf", &cfg.Config{}).(*cfg.Config)
 	skip := p.Get("skip", false).(bool)
 	home := p.Get("home", "").(string)
 	cache := p.Get("cache", false).(bool)
@@ -49,7 +49,7 @@
 	}
 
 	// Build an initial dependency map.
-	deps := make(map[string]*yaml.Dependency, len(conf.Imports))
+	deps := make(map[string]*cfg.Dependency, len(conf.Imports))
 	for _, imp := range conf.Imports {
 		deps[imp.Name] = imp
 	}
@@ -70,6 +70,12 @@
 	flattenSetRefs(f)
 	Info("Project relies on %d dependencies.", len(deps))
 
+	hash, err := conf.Hash()
+	if err != nil {
+		return conf, err
+	}
+	c.Put("Lockfile", cfg.LockfileFromMap(deps, hash))
+
 	// A shallow copy should be all that's needed.
 	confcopy := conf.Clone()
 	exportFlattenedDeps(confcopy, deps)
@@ -77,8 +83,8 @@
 	return confcopy, err
 }
 
-func exportFlattenedDeps(conf *yaml.Config, in map[string]*yaml.Dependency) {
-	out := make([]*yaml.Dependency, len(in))
+func exportFlattenedDeps(conf *cfg.Config, in map[string]*cfg.Dependency) {
+	out := make([]*cfg.Dependency, len(in))
 	i := 0
 	for _, v := range in {
 		out[i] = v
@@ -88,13 +94,13 @@
 }
 
 type flattening struct {
-	conf *yaml.Config
+	conf *cfg.Config
 	// Top vendor path, e.g. project/vendor
 	top string
 	// Current path
 	curr string
 	// Built list of dependencies
-	deps map[string]*yaml.Dependency
+	deps map[string]*cfg.Dependency
 	// Dependencies that need to be scanned.
 	scan []string
 }
@@ -120,8 +126,6 @@
 		} else if m, ok = mergeGuess(base, imp, f.deps, f.top, scanned); ok {
 			mod = m
 		}
-		//mod, _ = mergeGuess(base, imp, f.deps, f.top, scanned)
-		//Info("Scanned: %v", scanned)
 
 		if len(mod) > 0 {
 			Debug("----> Updating all dependencies for %q (%d)", imp, len(mod))
@@ -193,7 +197,7 @@
 	}
 }
 
-func mergeGlide(dir, name string, deps map[string]*yaml.Dependency, vend string) ([]string, bool) {
+func mergeGlide(dir, name string, deps map[string]*cfg.Dependency, vend string) ([]string, bool) {
 	gp := path.Join(dir, "glide.yaml")
 	if _, err := os.Stat(gp); err != nil {
 		return []string{}, false
@@ -205,7 +209,7 @@
 		return []string{}, false
 	}
 
-	conf, err := yaml.FromYaml(string(yml))
+	conf, err := cfg.ConfigFromYaml(yml)
 	if err != nil {
 		Warn("Found glide file %q, but can't use it: %s", gp, err)
 		return []string{}, false
@@ -220,7 +224,7 @@
 //
 // It returns true if any dependencies were found (even if not added because
 // they are duplicates).
-func mergeGodep(dir, name string, deps map[string]*yaml.Dependency, vend string) ([]string, bool) {
+func mergeGodep(dir, name string, deps map[string]*cfg.Dependency, vend string) ([]string, bool) {
 	Debug("Looking in %s/Godeps/ for a Godeps.json file.\n", dir)
 	d, err := parseGodepGodeps(dir)
 	if err != nil {
@@ -235,7 +239,7 @@
 }
 
 // listGb merges GB dependencies into the deps.
-func mergeGb(dir, pkg string, deps map[string]*yaml.Dependency, vend string) ([]string, bool) {
+func mergeGb(dir, pkg string, deps map[string]*cfg.Dependency, vend string) ([]string, bool) {
 	Debug("Looking in %s/vendor/ for a manifest file.\n", dir)
 	d, err := parseGbManifest(dir)
 	if err != nil || len(d) == 0 {
@@ -246,7 +250,7 @@
 }
 
 // mergeGPM merges GPM Godeps files into deps.
-func mergeGPM(dir, pkg string, deps map[string]*yaml.Dependency, vend string) ([]string, bool) {
+func mergeGPM(dir, pkg string, deps map[string]*cfg.Dependency, vend string) ([]string, bool) {
 	d, err := parseGPMGodeps(dir)
 	if err != nil || len(d) == 0 {
 		return []string{}, false
@@ -260,7 +264,7 @@
 // This always returns true because it always handles the job of searching
 // for dependencies. So generally it should be the last merge strategy
 // that you try.
-func mergeGuess(dir, pkg string, deps map[string]*yaml.Dependency, vend string, scanned map[string]bool) ([]string, bool) {
+func mergeGuess(dir, pkg string, deps map[string]*cfg.Dependency, vend string, scanned map[string]bool) ([]string, bool) {
 	Info("Scanning %s for dependencies.", pkg)
 	buildContext, err := GetBuildContext()
 	if err != nil {
@@ -295,7 +299,7 @@
 		case ptypeUnknown:
 			Info("==> Unknown %s (%s)", name, oname)
 			Debug("✨☆ Undownloaded dependency: %s", name)
-			nd := &yaml.Dependency{
+			nd := &cfg.Dependency{
 				Name:       name,
 				Repository: "https://" + repo,
 			}
@@ -310,7 +314,7 @@
 			// but not be on vendor. We add any that are on $GOPATH.
 			if _, ok := deps[name]; !ok {
 				Debug("✨☆ GOPATH dependency: %s", name)
-				nd := &yaml.Dependency{Name: name}
+				nd := &cfg.Dependency{Name: name}
 				deps[name] = nd
 				res = append(res, name)
 			}
@@ -319,12 +323,10 @@
 	}
 
 	return res, true
-	//Info("Package %s manages its own dependencies", pkg)
-	//return []string{}, true
 }
 
 // mergeDeps merges any dependency array into deps.
-func mergeDeps(orig map[string]*yaml.Dependency, add []*yaml.Dependency, vend string) []string {
+func mergeDeps(orig map[string]*cfg.Dependency, add []*cfg.Dependency, vend string) []string {
 	mod := []string{}
 	for _, dd := range add {
 		// Add it unless it's already there.
diff --git a/cmd/gb.go b/cmd/gb.go
index ac66aeb..35245d3 100644
--- a/cmd/gb.go
+++ b/cmd/gb.go
@@ -6,8 +6,8 @@
 	"path/filepath"
 
 	"github.com/Masterminds/cookoo"
+	"github.com/Masterminds/glide/cfg"
 	"github.com/Masterminds/glide/gb"
-	"github.com/Masterminds/glide/yaml"
 )
 
 func HasGbManifest(c cookoo.Context, p *cookoo.Params) (interface{}, cookoo.Interrupt) {
@@ -28,14 +28,14 @@
 	return parseGbManifest(dir)
 }
 
-func parseGbManifest(dir string) ([]*yaml.Dependency, error) {
+func parseGbManifest(dir string) ([]*cfg.Dependency, error) {
 	path := filepath.Join(dir, "vendor/manifest")
 	if fi, err := os.Stat(path); err != nil || fi.IsDir() {
-		return []*yaml.Dependency{}, nil
+		return []*cfg.Dependency{}, nil
 	}
 
 	Info("Found GB manifest file.\n")
-	buf := []*yaml.Dependency{}
+	buf := []*cfg.Dependency{}
 	file, err := os.Open(path)
 	if err != nil {
 		return buf, err
@@ -64,7 +64,7 @@
 			}
 		} else {
 			seen[pkg] = true
-			dep := &yaml.Dependency{
+			dep := &cfg.Dependency{
 				Name:       pkg,
 				Reference:  d.Revision,
 				Repository: d.Repository,
diff --git a/cmd/get_imports.go b/cmd/get_imports.go
index 35baee6..feae223 100644
--- a/cmd/get_imports.go
+++ b/cmd/get_imports.go
@@ -17,8 +17,8 @@
 	"strings"
 
 	"github.com/Masterminds/cookoo"
+	"github.com/Masterminds/glide/cfg"
 	"github.com/Masterminds/glide/util"
-	"github.com/Masterminds/glide/yaml"
 	"github.com/Masterminds/semver"
 	v "github.com/Masterminds/vcs"
 )
@@ -42,7 +42,7 @@
 // 	- []*Dependency: A list of constructed dependencies.
 func GetAll(c cookoo.Context, p *cookoo.Params) (interface{}, cookoo.Interrupt) {
 	names := p.Get("packages", []string{}).([]string)
-	cfg := p.Get("conf", nil).(*yaml.Config)
+	conf := p.Get("conf", nil).(*cfg.Config)
 	insecure := p.Get("insecure", false).(bool)
 	home := p.Get("home", "").(string)
 	cache := p.Get("cache", false).(bool)
@@ -51,7 +51,7 @@
 
 	Info("Preparing to install %d package.", len(names))
 
-	deps := []*yaml.Dependency{}
+	deps := []*cfg.Dependency{}
 	for _, name := range names {
 		cwd, err := VendorPath(c)
 		if err != nil {
@@ -63,7 +63,7 @@
 			return nil, fmt.Errorf("Package name is required for %q.", name)
 		}
 
-		if cfg.HasDependency(root) {
+		if conf.HasDependency(root) {
 			Warn("Package %q is already in glide.yaml. Skipping", root)
 			continue
 		}
@@ -75,7 +75,7 @@
 			return false, err
 		}
 
-		dep := &yaml.Dependency{
+		dep := &cfg.Dependency{
 			Name: root,
 		}
 
@@ -93,7 +93,7 @@
 			return dep, err
 		}
 
-		cfg.Imports = append(cfg.Imports, dep)
+		conf.Imports = append(conf.Imports, dep)
 
 		deps = append(deps, dep)
 
@@ -106,10 +106,10 @@
 // Params:
 //
 // 	- force (bool): force packages to update (default false)
-//	- conf (*yaml.Config): The configuration
+//	- conf (*cfg.Config): The configuration
 // 	- packages([]string): The packages to update. Default is all.
 func UpdateImports(c cookoo.Context, p *cookoo.Params) (interface{}, cookoo.Interrupt) {
-	cfg := p.Get("conf", nil).(*yaml.Config)
+	cfg := p.Get("conf", nil).(*cfg.Config)
 	force := p.Get("force", true).(bool)
 	plist := p.Get("packages", []string{}).([]string)
 	home := p.Get("home", "").(string)
@@ -152,7 +152,7 @@
 // SetReference is a command to set the VCS reference (commit id, tag, etc) for
 // a project.
 func SetReference(c cookoo.Context, p *cookoo.Params) (interface{}, cookoo.Interrupt) {
-	cfg := p.Get("conf", nil).(*yaml.Config)
+	cfg := p.Get("conf", nil).(*cfg.Config)
 	cwd, err := VendorPath(c)
 	if err != nil {
 		return false, err
@@ -174,7 +174,7 @@
 
 // filterArchOs indicates a dependency should be filtered out because it is
 // the wrong GOOS or GOARCH.
-func filterArchOs(dep *yaml.Dependency) bool {
+func filterArchOs(dep *cfg.Dependency) bool {
 	found := false
 	if len(dep.Arch) > 0 {
 		for _, a := range dep.Arch {
@@ -205,7 +205,7 @@
 }
 
 // VcsExists checks if the directory has a local VCS checkout.
-func VcsExists(dep *yaml.Dependency, dest string) bool {
+func VcsExists(dep *cfg.Dependency, dest string) bool {
 	repo, err := dep.GetRepo(dest)
 	if err != nil {
 		return false
@@ -217,7 +217,7 @@
 // VcsGet figures out how to fetch a dependency, and then gets it.
 //
 // VcsGet installs into the dest.
-func VcsGet(dep *yaml.Dependency, dest, home string, cache, cacheGopath, skipGopath bool) error {
+func VcsGet(dep *cfg.Dependency, dest, home string, cache, cacheGopath, skipGopath bool) error {
 
 	// When not skipping the $GOPATH look in it for a copy of the package
 	if !skipGopath {
@@ -423,7 +423,7 @@
 }
 
 // VcsUpdate updates to a particular checkout based on the VCS setting.
-func VcsUpdate(dep *yaml.Dependency, vend, home string, force, cache, cacheGopath, skipGopath bool) error {
+func VcsUpdate(dep *cfg.Dependency, vend, home string, force, cache, cacheGopath, skipGopath bool) error {
 	Info("Fetching updates for %s.\n", dep.Name)
 
 	if filterArchOs(dep) {
@@ -513,14 +513,23 @@
 }
 
 // VcsVersion set the VCS version for a checkout.
-func VcsVersion(dep *yaml.Dependency, vend string) error {
+func VcsVersion(dep *cfg.Dependency, vend string) error {
+	cwd := path.Join(vend, dep.Name)
+
 	// If there is no refernece configured there is nothing to set.
 	if dep.Reference == "" {
+		// Before exiting update the pinned version
+		repo, err := dep.GetRepo(cwd)
+		if err != nil {
+			return err
+		}
+		dep.Pin, err = repo.Version()
+		if err != nil {
+			return err
+		}
 		return nil
 	}
 
-	cwd := path.Join(vend, dep.Name)
-
 	// When the directory is not empty and has no VCS directory it's
 	// a vendored files situation.
 	empty, err := isDirectoryEmpty(cwd)
@@ -585,13 +594,17 @@
 			Error("Failed to set version to %s: %s\n", dep.Reference, err)
 			return err
 		}
+		dep.Pin, err = repo.Version()
+		if err != nil {
+			return err
+		}
 	}
 
 	return nil
 }
 
 // VcsLastCommit gets the last commit ID from the given dependency.
-func VcsLastCommit(dep *yaml.Dependency, vend string) (string, error) {
+func VcsLastCommit(dep *cfg.Dependency, vend string) (string, error) {
 	cwd := path.Join(vend, dep.Name)
 	repo, err := dep.GetRepo(cwd)
 	if err != nil {
diff --git a/cmd/godeps.go b/cmd/godeps.go
index 72c6d27..fc62dd7 100644
--- a/cmd/godeps.go
+++ b/cmd/godeps.go
@@ -7,8 +7,8 @@
 	"strings"
 
 	"github.com/Masterminds/cookoo"
+	"github.com/Masterminds/glide/cfg"
 	"github.com/Masterminds/glide/util"
-	"github.com/Masterminds/glide/yaml"
 )
 
 // This file contains commands for working with Godep.
@@ -48,19 +48,19 @@
 // Params:
 // - dir (string): the project's directory
 //
-// Returns an []*yaml.Dependency
+// Returns an []*cfg.Dependency
 func ParseGodepGodeps(c cookoo.Context, p *cookoo.Params) (interface{}, cookoo.Interrupt) {
 	dir := cookoo.GetString("dir", "", p)
 	return parseGodepGodeps(dir)
 }
-func parseGodepGodeps(dir string) ([]*yaml.Dependency, error) {
+func parseGodepGodeps(dir string) ([]*cfg.Dependency, error) {
 	path := filepath.Join(dir, "Godeps/Godeps.json")
 	if _, err := os.Stat(path); err != nil {
-		return []*yaml.Dependency{}, nil
+		return []*cfg.Dependency{}, nil
 	}
 	Info("Found Godeps.json file.\n")
 
-	buf := []*yaml.Dependency{}
+	buf := []*cfg.Dependency{}
 
 	godeps := new(Godeps)
 
@@ -96,7 +96,7 @@
 			}
 		} else {
 			seen[pkg] = true
-			dep := &yaml.Dependency{Name: pkg, Reference: d.Rev}
+			dep := &cfg.Dependency{Name: pkg, Reference: d.Rev}
 			if len(sub) > 0 {
 				dep.Subpackages = []string{sub}
 			}
diff --git a/cmd/gpm.go b/cmd/gpm.go
index 82ed89d..eef097f 100644
--- a/cmd/gpm.go
+++ b/cmd/gpm.go
@@ -7,7 +7,7 @@
 	"strings"
 
 	"github.com/Masterminds/cookoo"
-	"github.com/Masterminds/glide/yaml"
+	"github.com/Masterminds/glide/cfg"
 )
 
 // This file contains commands for working with GPM/GVP.
@@ -25,22 +25,22 @@
 // Params
 // 	- dir (string): Directory root.
 //
-// Returns an []*yaml.Dependency
+// Returns an []*cfg.Dependency
 func GPMGodeps(c cookoo.Context, p *cookoo.Params) (interface{}, cookoo.Interrupt) {
 	dir := cookoo.GetString("dir", "", p)
 	return parseGPMGodeps(dir)
 }
-func parseGPMGodeps(dir string) ([]*yaml.Dependency, error) {
+func parseGPMGodeps(dir string) ([]*cfg.Dependency, error) {
 	path := filepath.Join(dir, "Godeps")
 	if i, err := os.Stat(path); err != nil {
-		return []*yaml.Dependency{}, nil
+		return []*cfg.Dependency{}, nil
 	} else if i.IsDir() {
 		Info("Godeps is a directory. This is probably a Godep project.\n")
-		return []*yaml.Dependency{}, nil
+		return []*cfg.Dependency{}, nil
 	}
 	Info("Found Godeps file.\n")
 
-	buf := []*yaml.Dependency{}
+	buf := []*cfg.Dependency{}
 
 	file, err := os.Open(path)
 	if err != nil {
@@ -50,7 +50,7 @@
 	for scanner.Scan() {
 		parts, ok := parseGodepsLine(scanner.Text())
 		if ok {
-			dep := &yaml.Dependency{Name: parts[0]}
+			dep := &cfg.Dependency{Name: parts[0]}
 			if len(parts) > 1 {
 				dep.Reference = parts[1]
 			}
@@ -70,11 +70,11 @@
 	dir := cookoo.GetString("dir", "", p)
 	path := filepath.Join(dir, "Godeps-Git")
 	if _, err := os.Stat(path); err != nil {
-		return []*yaml.Dependency{}, nil
+		return []*cfg.Dependency{}, nil
 	}
 	Info("Found Godeps-Git file.\n")
 
-	buf := []*yaml.Dependency{}
+	buf := []*cfg.Dependency{}
 
 	file, err := os.Open(path)
 	if err != nil {
@@ -84,7 +84,7 @@
 	for scanner.Scan() {
 		parts, ok := parseGodepsLine(scanner.Text())
 		if ok {
-			dep := &yaml.Dependency{Name: parts[1], Repository: parts[0]}
+			dep := &cfg.Dependency{Name: parts[1], Repository: parts[0]}
 			if len(parts) > 2 {
 				dep.Reference = parts[2]
 			}
diff --git a/cmd/guess_deps.go b/cmd/guess_deps.go
index 871dc6c..7ced3c6 100644
--- a/cmd/guess_deps.go
+++ b/cmd/guess_deps.go
@@ -1,11 +1,13 @@
 package cmd
 
 import (
+	"go/build"
 	"os"
+	"path/filepath"
 	"strings"
 
 	"github.com/Masterminds/cookoo"
-	"github.com/Masterminds/glide/yaml"
+	"github.com/Masterminds/glide/cfg"
 )
 
 // GuessDeps tries to get the dependencies for the current directory.
@@ -20,21 +22,69 @@
 	base := p.Get("dirname", ".").(string)
 	deps := make(map[string]bool)
 	err = findDeps(buildContext, deps, base, "")
-	deps = compactDeps(deps)
-	delete(deps, base)
-	if err != nil {
-		return nil, err
+	name := guessPackageName(buildContext, base)
+
+	// If there error is that no go source files were found try looking one
+	// level deeper. Some Go projects don't have go source files at the top
+	// level.
+	switch err.(type) {
+	case *build.NoGoError:
+		filepath.Walk(base, func(path string, fi os.FileInfo, err error) error {
+			if excludeSubtree(path, fi) {
+				top := filepath.Base(path)
+				if fi.IsDir() && (top == "vendor" || top == "testdata") {
+					return filepath.SkipDir
+				}
+				return nil
+			}
+
+			pkg, err := buildContext.ImportDir(path, 0)
+			if err != nil {
+				// When there is an error we skip it and keep going.
+				return nil
+			}
+
+			if pkg.Goroot {
+				return nil
+			}
+
+			for _, imp := range pkg.Imports {
+
+				// Skip subpackages of the project we're in.
+				if strings.HasPrefix(imp, name) {
+					continue
+				}
+				if imp == name {
+					continue
+				}
+
+				found := findPkg(buildContext, imp, base)
+				switch found.PType {
+				case ptypeGoroot, ptypeCgo:
+					break
+				default:
+					deps[imp] = true
+				}
+			}
+
+			return nil
+		})
 	}
 
-	config := new(yaml.Config)
+	deps = compactDeps(deps)
+	delete(deps, base)
+
+	Info("Generating a YAML configuration file and guessing the dependencies")
+
+	config := new(cfg.Config)
 
 	// Get the name of the top level package
-	config.Name = guessPackageName(buildContext, base)
-	config.Imports = make([]*yaml.Dependency, len(deps))
+	config.Name = name
+	config.Imports = make([]*cfg.Dependency, len(deps))
 	i := 0
 	for pa := range deps {
 		Info("Found reference to %s\n", pa)
-		d := &yaml.Dependency{
+		d := &cfg.Dependency{
 			Name: pa,
 		}
 		config.Imports[i] = d
@@ -124,7 +174,12 @@
 
 	pkg, err := b.Import(base, cwd, 0)
 	if err != nil {
-		return "main"
+		// There may not be any top level Go source files but the project may
+		// still be within the GOPATH.
+		if strings.HasPrefix(base, b.GOPATH) {
+			p := strings.TrimPrefix(base, b.GOPATH)
+			return strings.Trim(p, string(os.PathSeparator))
+		}
 	}
 
 	return pkg.ImportPath
diff --git a/cmd/init_glide.go b/cmd/init_glide.go
deleted file mode 100644
index 4d26008..0000000
--- a/cmd/init_glide.go
+++ /dev/null
@@ -1,59 +0,0 @@
-package cmd
-
-import (
-	"fmt"
-	"os"
-
-	"github.com/Masterminds/cookoo"
-)
-
-var yamlTpl = `# Glide YAML configuration file
-# Set this to your fully qualified package name, e.g.
-# github.com/Masterminds/foo. This should be the
-# top level package.
-package: %s
-
-# Declare your project's dependencies.
-import:
-  # Fetch package similar to 'go get':
-  #- package: github.com/Masterminds/cookoo
-  # Get and manage a package with Git:
-  #- package: github.com/Masterminds/cookoo
-  #  # The repository URL
-  #  repo: git@github.com:Masterminds/cookoo.git
-  #  # A tag, branch, or SHA
-  #  ref: 1.1.0
-  #  # the VCS type (compare to bzr, hg, svn). You should
-  #  # set this if you know it.
-  #  vcs: git
-`
-
-// InitGlide initializes a new Glide project.
-//
-// Among other things, it creates a default glide.yaml.
-//
-// Params:
-// 	- filename (string): The name of the glide YAML file. Default is glide.yaml.
-// 	- project (string): The name of the project. Default is 'main'.
-func InitGlide(c cookoo.Context, p *cookoo.Params) (interface{}, cookoo.Interrupt) {
-	fname := p.Get("filename", "glide.yaml").(string)
-	pname := p.Get("project", "main").(string)
-	vdir := c.Get("VendorDir", "vendor").(string)
-
-	if _, err := os.Stat(fname); err == nil {
-		cwd, _ := os.Getwd()
-		return false, fmt.Errorf("Cowardly refusing to overwrite %s in %s", fname, cwd)
-	}
-	f, err := os.Create(fname)
-	if err != nil {
-		return false, err
-	}
-
-	fmt.Fprintf(f, yamlTpl, pname)
-	f.Close()
-
-	os.MkdirAll(vdir, 0755)
-
-	Info("Initialized. You can now edit '%s'\n", fname)
-	return true, nil
-}
diff --git a/cmd/install.go b/cmd/install.go
new file mode 100644
index 0000000..c58babd
--- /dev/null
+++ b/cmd/install.go
@@ -0,0 +1,111 @@
+package cmd
+
+import (
+	"errors"
+	"io/ioutil"
+	"os"
+
+	"github.com/Masterminds/cookoo"
+	"github.com/Masterminds/glide/cfg"
+)
+
+// LockFileExists checks if a lock file exists. If not it jumps to the update
+// command.
+func LockFileExists(c cookoo.Context, p *cookoo.Params) (interface{}, cookoo.Interrupt) {
+	fname := p.Get("filename", "glide.lock").(string)
+	if _, err := os.Stat(fname); err != nil {
+		Info("Lock file (glide.lock) does not exist. Performing update.")
+		return false, &cookoo.Reroute{"update"}
+	}
+
+	return true, nil
+}
+
+// LoadLockFile loads the lock file to the context and checks if it is correct
+// for the loaded cfg file.
+func LoadLockFile(c cookoo.Context, p *cookoo.Params) (interface{}, cookoo.Interrupt) {
+	fname := p.Get("filename", "glide.lock").(string)
+	conf := p.Get("conf", nil).(*cfg.Config)
+
+	yml, err := ioutil.ReadFile(fname)
+	if err != nil {
+		return nil, err
+	}
+	lock, err := cfg.LockfileFromYaml(yml)
+	if err != nil {
+		return nil, err
+	}
+
+	hash, err := conf.Hash()
+	if err != nil {
+		return nil, err
+	}
+
+	if hash != lock.Hash {
+		return nil, errors.New("Lock file does not match YAML configuration. Consider running 'update'")
+	}
+
+	return lock, nil
+}
+
+// Install installs the dependencies from a Lockfile.
+func Install(c cookoo.Context, p *cookoo.Params) (interface{}, cookoo.Interrupt) {
+	lock := p.Get("lock", nil).(*cfg.Lockfile)
+	conf := p.Get("conf", nil).(*cfg.Config)
+	force := p.Get("force", true).(bool)
+	home := p.Get("home", "").(string)
+	cache := p.Get("cache", false).(bool)
+	cacheGopath := p.Get("cacheGopath", false).(bool)
+	skipGopath := p.Get("skipGopath", false).(bool)
+
+	cwd, err := VendorPath(c)
+	if err != nil {
+		return false, err
+	}
+
+	// Create a config setup based on the Lockfile data to process with
+	// existing commands.
+	newConf := &cfg.Config{}
+	newConf.Name = conf.Name
+
+	newConf.Imports = make(cfg.Dependencies, len(lock.Imports))
+	for k, v := range lock.Imports {
+		newConf.Imports[k] = &cfg.Dependency{
+			Name:        v.Name,
+			Reference:   v.Version,
+			Repository:  v.Repository,
+			VcsType:     v.VcsType,
+			Subpackages: v.Subpackages,
+			Arch:        v.Arch,
+			Os:          v.Os,
+		}
+	}
+
+	newConf.DevImports = make(cfg.Dependencies, len(lock.DevImports))
+	for k, v := range lock.DevImports {
+		newConf.DevImports[k] = &cfg.Dependency{
+			Name:        v.Name,
+			Reference:   v.Version,
+			Repository:  v.Repository,
+			VcsType:     v.VcsType,
+			Subpackages: v.Subpackages,
+			Arch:        v.Arch,
+			Os:          v.Os,
+		}
+	}
+
+	newConf.DeDupe()
+
+	if len(newConf.Imports) == 0 {
+		Info("No dependencies found. Nothing installed.\n")
+		return false, nil
+	}
+
+	for _, dep := range newConf.Imports {
+		if err := VcsUpdate(dep, cwd, home, force, cache, cacheGopath, skipGopath); err != nil {
+			Warn("Update failed for %s: %s\n", dep.Name, err)
+		}
+	}
+
+	return newConf, nil
+}
diff --git a/cmd/link_package.go b/cmd/link_package.go
index 71d1dd4..214b094 100644
--- a/cmd/link_package.go
+++ b/cmd/link_package.go
@@ -7,13 +7,13 @@
 	"strings"
 
 	"github.com/Masterminds/cookoo"
-	"github.com/Masterminds/glide/yaml"
+	"github.com/Masterminds/glide/cfg"
 )
 
 // LinkPackage creates a symlink to the project within the GOPATH.
 func LinkPackage(c cookoo.Context, p *cookoo.Params) (interface{}, cookoo.Interrupt) {
-	cfg := c.Get("cfg", "").(*yaml.Config)
-	pname := p.Get("path", cfg.Name).(string)
+	conf := c.Get("cfg", "").(*cfg.Config)
+	pname := p.Get("path", conf.Name).(string)
 
 	// Per issue #10, this may be nicer to work with in cases where repos are
 	// moved.
diff --git a/cmd/print_name.go b/cmd/print_name.go
index 7245f1d..6a6d26d 100644
--- a/cmd/print_name.go
+++ b/cmd/print_name.go
@@ -4,14 +4,14 @@
 	"fmt"
 
 	"github.com/Masterminds/cookoo"
-	"github.com/Masterminds/glide/yaml"
+	"github.com/Masterminds/glide/cfg"
 )
 
 // PrintName prints the name of the project.
 //
 // This comes from Config.Name.
 func PrintName(c cookoo.Context, p *cookoo.Params) (interface{}, cookoo.Interrupt) {
-	cfg := p.Get("conf", nil).(*yaml.Config)
-	fmt.Println(cfg.Name)
+	conf := p.Get("conf", nil).(*cfg.Config)
+	fmt.Println(conf.Name)
 	return nil, nil
 }
diff --git a/cmd/rebuild.go b/cmd/rebuild.go
index d13c414..a781503 100644
--- a/cmd/rebuild.go
+++ b/cmd/rebuild.go
@@ -8,16 +8,16 @@
 	"strings"
 
 	"github.com/Masterminds/cookoo"
-	"github.com/Masterminds/glide/yaml"
+	"github.com/Masterminds/glide/cfg"
 )
 
 // Rebuild runs 'go build' in a directory.
 //
 // Params:
-// 	- conf: the *yaml.Config.
+// 	- conf: the *cfg.Config.
 //
 func Rebuild(c cookoo.Context, p *cookoo.Params) (interface{}, cookoo.Interrupt) {
-	cfg := p.Get("conf", nil).(*yaml.Config)
+	conf := p.Get("conf", nil).(*cfg.Config)
 	vpath, err := VendorPath(c)
 	if err != nil {
 		return nil, err
@@ -25,12 +25,12 @@
 
 	Info("Building dependencies.\n")
 
-	if len(cfg.Imports) == 0 {
+	if len(conf.Imports) == 0 {
 		Info("No dependencies found. Nothing built.\n")
 		return true, nil
 	}
 
-	for _, dep := range cfg.Imports {
+	for _, dep := range conf.Imports {
 		if err := buildDep(c, dep, vpath); err != nil {
 			Warn("Failed to build %s: %s\n", dep.Name, err)
 		}
@@ -39,7 +39,7 @@
 	return true, nil
 }
 
-func buildDep(c cookoo.Context, dep *yaml.Dependency, vpath string) error {
+func buildDep(c cookoo.Context, dep *cfg.Dependency, vpath string) error {
 	if len(dep.Subpackages) == 0 {
 		buildPath(c, dep.Name)
 	}
diff --git a/cmd/tree.go b/cmd/tree.go
index 681be94..60181ec 100644
--- a/cmd/tree.go
+++ b/cmd/tree.go
@@ -187,13 +187,21 @@
 	}
 
 	// Recurse backward to scan other vendor/ directories
-	for wd := cwd; wd != "/"; wd = filepath.Dir(wd) {
-		p = filepath.Join(wd, "vendor", name)
-		if fi, err = os.Stat(p); err == nil && (fi.IsDir() || isLink(fi)) {
-			info.Path = p
-			info.PType = ptypeVendor
-			info.Vendored = true
-			return info
+	// If the cwd isn't an absolute path walking upwards looking for vendor/
+	// folders can get into an infinate loop.
+	abs, err := filepath.Abs(cwd)
+	if err != nil {
+		abs = cwd
+	}
+	if abs != "." {
+		for wd := abs; wd != "/"; wd = filepath.Dir(wd) {
+			p = filepath.Join(wd, "vendor", name)
+			if fi, err = os.Stat(p); err == nil && (fi.IsDir() || isLink(fi)) {
+				info.Path = p
+				info.PType = ptypeVendor
+				info.Vendored = true
+				return info
+			}
 		}
 	}
 	// Check $GOPATH
diff --git a/cmd/update_references.go b/cmd/update_references.go
index 3e602fa..92fe235 100644
--- a/cmd/update_references.go
+++ b/cmd/update_references.go
@@ -4,7 +4,7 @@
 	"path"
 
 	"github.com/Masterminds/cookoo"
-	"github.com/Masterminds/glide/yaml"
+	"github.com/Masterminds/glide/cfg"
 )
 
 // UpdateReferences updates the revision numbers on all of the imports.
@@ -13,10 +13,10 @@
 // be updated.
 //
 // Params:
-// 	- conf (*yaml.Config): Configuration
+// 	- conf (*cfg.Config): Configuration
 // 	- packages ([]string): A list of packages to update. Default is all packages.
 func UpdateReferences(c cookoo.Context, p *cookoo.Params) (interface{}, cookoo.Interrupt) {
-	cfg := p.Get("conf", &yaml.Config{}).(*yaml.Config)
+	conf := p.Get("conf", &cfg.Config{}).(*cfg.Config)
 	plist := p.Get("packages", []string{}).([]string)
 	vend, _ := VendorPath(c)
 	pkgs := list2map(plist)
@@ -27,33 +27,33 @@
 		return false, err
 	}
 
-	if len(cfg.Imports) == 0 {
-		return cfg, nil
+	if len(conf.Imports) == 0 {
+		return conf, nil
 	}
 
 	// Walk the dependency tree to discover all the packages to pin.
-	packages := make([]string, len(cfg.Imports))
-	for i, v := range cfg.Imports {
+	packages := make([]string, len(conf.Imports))
+	for i, v := range conf.Imports {
 		packages[i] = v.Name
 	}
-	deps := make(map[string]*yaml.Dependency, len(cfg.Imports))
-	for _, imp := range cfg.Imports {
+	deps := make(map[string]*cfg.Dependency, len(conf.Imports))
+	for _, imp := range conf.Imports {
 		deps[imp.Name] = imp
 	}
-	f := &flattening{cfg, vend, vend, deps, packages}
+	f := &flattening{conf, vend, vend, deps, packages}
 	err = discoverDependencyTree(f)
 	if err != nil {
-		return cfg, err
+		return conf, err
 	}
 
-	exportFlattenedDeps(cfg, deps)
+	exportFlattenedDeps(conf, deps)
 
-	err = cfg.DeDupe()
+	err = conf.DeDupe()
 	if err != nil {
-		return cfg, err
+		return conf, err
 	}
 
-	for _, imp := range cfg.Imports {
+	for _, imp := range conf.Imports {
 		if restrict && !pkgs[imp.Name] {
 			Debug("===> Skipping %q", imp.Name)
 			continue
@@ -65,7 +65,7 @@
 		imp.Reference = commit
 	}
 
-	return cfg, nil
+	return conf, nil
 }
 
 func discoverDependencyTree(f *flattening) error {
diff --git a/cmd/vendored.go b/cmd/vendored.go
index 8eb1b8f..b0e3f64 100644
--- a/cmd/vendored.go
+++ b/cmd/vendored.go
@@ -5,7 +5,7 @@
 	"path"
 
 	"github.com/Masterminds/cookoo"
-	"github.com/Masterminds/glide/yaml"
+	"github.com/Masterminds/glide/cfg"
 	"github.com/Masterminds/vcs"
 )
 
@@ -15,17 +15,17 @@
 // VendoredCleanUp should be a suffix to UpdateImports.
 func VendoredSetup(c cookoo.Context, p *cookoo.Params) (interface{}, cookoo.Interrupt) {
 	update := p.Get("update", true).(bool)
-	cfg := p.Get("conf", nil).(*yaml.Config)
+	conf := p.Get("conf", nil).(*cfg.Config)
 	if update != true {
-		return cfg, nil
+		return conf, nil
 	}
 
 	vend, err := VendorPath(c)
 	if err != nil {
-		return cfg, err
+		return conf, err
 	}
 
-	for _, dep := range cfg.Imports {
+	for _, dep := range conf.Imports {
 		cwd := path.Join(vend, dep.Name)
 
 		// When the directory is not empty and has no VCS directory it's
@@ -50,11 +50,11 @@
 		}
 	}
 
-	return cfg, nil
+	return conf, nil
 }
 
 // VendoredCleanUp is a command that cleans up vendored codebases after an update.
-// If enabled (via update) it removed the VCS info from updated vendored
+// If enabled (via update) it removes the VCS info from updated vendored
 // packages. This should be a suffix to UpdateImports and  VendoredSetup should
 // be a prefix to UpdateImports.
 func VendoredCleanUp(c cookoo.Context, p *cookoo.Params) (interface{}, cookoo.Interrupt) {
@@ -62,14 +62,14 @@
 	if update != true {
 		return false, nil
 	}
-	cfg := p.Get("conf", nil).(*yaml.Config)
+	conf := p.Get("conf", nil).(*cfg.Config)
 
 	vend, err := VendorPath(c)
 	if err != nil {
 		return false, err
 	}
 
-	for _, dep := range cfg.Imports {
+	for _, dep := range conf.Imports {
 		if dep.UpdateAsVendored == true {
 			Info("Cleaning up vendored package %s\n", dep.Name)
 
diff --git a/cmd/yaml.go b/cmd/yaml.go
index fe302d6..1042244 100644
--- a/cmd/yaml.go
+++ b/cmd/yaml.go
@@ -8,7 +8,7 @@
 	"strings"
 
 	"github.com/Masterminds/cookoo"
-	"github.com/Masterminds/glide/yaml"
+	"github.com/Masterminds/glide/cfg"
 )
 
 // ParseYaml parses the glide.yaml format and returns a Configuration object.
@@ -17,7 +17,7 @@
 //	- filename (string): YAML filename as a string
 //
 // Returns:
-//	- *yaml.Config: The configuration.
+//	- *cfg.Config: The configuration.
 func ParseYaml(c cookoo.Context, p *cookoo.Params) (interface{}, cookoo.Interrupt) {
 	fname := p.Get("filename", "glide.yaml").(string)
 	//conf := new(Config)
@@ -25,12 +25,12 @@
 	if err != nil {
 		return nil, err
 	}
-	cfg, err := yaml.FromYaml(string(yml))
+	conf, err := cfg.ConfigFromYaml(yml)
 	if err != nil {
 		return nil, err
 	}
 
-	return cfg, nil
+	return conf, nil
 }
 
 // ParseYamlString parses a YAML string. This is similar but different to
@@ -40,32 +40,44 @@
 //	- yaml (string): YAML as a string.
 //
 // Returns:
-//	- *yaml.Config: The configuration.
+//	- *cfg.Config: The configuration.
 func ParseYamlString(c cookoo.Context, p *cookoo.Params) (interface{}, cookoo.Interrupt) {
 	yamlString := p.Get("yaml", "").(string)
 
-	cfg, err := yaml.FromYaml(string(yamlString))
+	conf, err := cfg.ConfigFromYaml([]byte(yamlString))
 	if err != nil {
 		return nil, err
 	}
 
-	return cfg, nil
+	return conf, nil
 }
 
-// WriteYaml writes a yaml.Node to the console as a string.
+// GuardYaml protects the glide yaml file from being overwritten.
+func GuardYaml(c cookoo.Context, p *cookoo.Params) (interface{}, cookoo.Interrupt) {
+	fname := p.Get("filename", "glide.yaml").(string)
+	if _, err := os.Stat(fname); err == nil {
+		cwd, _ := os.Getwd()
+		return false, fmt.Errorf("Cowardly refusing to overwrite %s in %s", fname, cwd)
+	}
+
+	return true, nil
+}
+
+// WriteYaml writes the config as YAML.
 //
 // Params:
-//	- conf: A *yaml.Config to render.
+//	- conf: A *cfg.Config to render.
 // 	- out (io.Writer): An output stream to write to. Default is os.Stdout.
 // 	- filename (string): If set, the file will be opened and the content will be written to it.
 func WriteYaml(c cookoo.Context, p *cookoo.Params) (interface{}, cookoo.Interrupt) {
-	cfg := p.Get("conf", nil).(*yaml.Config)
+	conf := p.Get("conf", nil).(*cfg.Config)
 	toStdout := p.Get("toStdout", true).(bool)
 
-	yml, err := yaml.ToYaml(cfg)
+	data, err := conf.Marshal()
 	if err != nil {
 		return nil, err
 	}
+
 	var out io.Writer
 	if nn, ok := p.Has("filename"); ok && len(nn.(string)) > 0 {
 		file, err := os.Create(nn.(string))
@@ -73,22 +85,51 @@
 		}
 		defer file.Close()
 		out = io.Writer(file)
-		fmt.Fprint(out, yml)
+		//fmt.Fprint(out, yml)
+		out.Write(data)
 	} else if toStdout {
 		out = p.Get("out", os.Stdout).(io.Writer)
-		fmt.Fprint(out, yml)
+		//fmt.Fprint(out, yml)
+		out.Write(data)
 	}
 
 	// Otherwise we supress output.
 	return true, nil
 }
 
-// AddDependencies adds a list of *Dependency objects to the given *yaml.Config.
+// WriteLock writes the lock as YAML.
+//
+// Params:
+//	- lockfile: A *cfg.Lockfile to render.
+// 	- out (io.Writer): An output stream to write to. Default is os.Stdout.
+func WriteLock(c cookoo.Context, p *cookoo.Params) (interface{}, cookoo.Interrupt) {
+	lockfile := p.Get("lockfile", nil).(*cfg.Lockfile)
+
+	Info("Writing glide.lock file")
+
+	data, err := lockfile.Marshal()
+	if err != nil {
+		return nil, err
+	}
+
+	var out io.Writer
+	file, err := os.Create("glide.lock")
+	if err != nil {
+		return false, err
+	}
+	defer file.Close()
+	out = io.Writer(file)
+	out.Write(data)
+
+	return true, nil
+}
+
+// AddDependencies adds a list of *Dependency objects to the given *cfg.Config.
 //
 // This is used to merge in packages from other sources or config files.
 func AddDependencies(c cookoo.Context, p *cookoo.Params) (interface{}, cookoo.Interrupt) {
-	deps := p.Get("dependencies", []*yaml.Dependency{}).([]*yaml.Dependency)
-	config := p.Get("conf", nil).(*yaml.Config)
+	deps := p.Get("dependencies", []*cfg.Dependency{}).([]*cfg.Dependency)
+	config := p.Get("conf", nil).(*cfg.Config)
 
 	// Make a set of existing package names for quick comparison.
 	pkgSet := make(map[string]bool, len(config.Imports))
diff --git a/cmd/yaml_test.go b/cmd/yaml_test.go
index 460d1ae..b466297 100644
--- a/cmd/yaml_test.go
+++ b/cmd/yaml_test.go
@@ -4,7 +4,7 @@
 	"testing"
 
 	"github.com/Masterminds/cookoo"
-	"github.com/Masterminds/glide/yaml"
+	"github.com/Masterminds/glide/cfg"
 )
 
 var yamlFile = `
@@ -32,55 +32,36 @@
   - package: github.com/kylelemons/go-gypsy
 `
 
-var childYamlFile = `
-package: fake/testing/more
-import:
-  - package: github.com/kylelemons/go-gypsy
-    subpackages:
-      - yaml
-`
-
 func TestFromYaml(t *testing.T) {
 	reg, router, cxt := cookoo.Cookoo()
 
 	reg.Route("t", "Testing").
-		Does(ParseYamlString, "cfg").Using("yaml").WithDefault(yamlFile).
-		Does(ParseYamlString, "childCfg").Using("yaml").WithDefault(childYamlFile)
+		Does(ParseYamlString, "cfg").Using("yaml").WithDefault(yamlFile)
 
 	if err := router.HandleRequest("t", cxt, false); err != nil {
 		t.Errorf("Failed to parse YAML: %s", err)
 	}
 
-	cfg := cxt.Get("cfg", nil).(*yaml.Config)
-	cfgChild := cxt.Get("childCfg", nil).(*yaml.Config)
-	cfgChild.Parent = cfg
+	conf := cxt.Get("cfg", nil).(*cfg.Config)
 
-	if cfg.Name != "fake/testing" {
-		t.Errorf("Expected name to be 'fake/teting', not '%s'", cfg.Name)
+	if conf.Name != "fake/testing" {
+		t.Errorf("Expected name to be 'fake/teting', not '%s'", conf.Name)
 	}
 
-	if len(cfg.Imports) != 3 {
-		t.Errorf("Expected 3 imports, got %d", len(cfg.Imports))
+	if len(conf.Imports) != 3 {
+		t.Errorf("Expected 3 imports, got %d", len(conf.Imports))
 	}
 
-	if cfg.Parent != nil {
-		t.Error("Expected root glide Parent to be nil")
-	}
-
-	if cfg.Imports.Get("github.com/Masterminds/convert") == nil {
+	if conf.Imports.Get("github.com/Masterminds/convert") == nil {
 		t.Error("Expected Imports.Get to return Dependency")
 	}
 
-	if cfg.Imports.Get("github.com/doesnot/exist") != nil {
+	if conf.Imports.Get("github.com/doesnot/exist") != nil {
 		t.Error("Execpted Imports.Get to return nil")
 	}
 
-	if cfgChild.HasRecursiveDependency("github.com/Masterminds/convert") == false {
-		t.Errorf("Expected to find a recursive dependency")
-	}
-
-	var imp *yaml.Dependency
-	for _, d := range cfg.Imports {
+	var imp *cfg.Dependency
+	for _, d := range conf.Imports {
 		if d.Name == "github.com/Masterminds/convert" {
 			imp = d
 		}
@@ -119,7 +100,7 @@
 		t.Errorf("Got wrong reference.")
 	}
 
-	if len(cfg.DevImports) != 1 {
+	if len(conf.DevImports) != 1 {
 		t.Errorf("Expected one dev import.")
 	}
 
diff --git a/dependency/resolver.go b/dependency/resolver.go
index 21ac93a..943c3aa 100644
--- a/dependency/resolver.go
+++ b/dependency/resolver.go
@@ -7,8 +7,8 @@
 	"path/filepath"
 	"strings"
 
+	"github.com/Masterminds/glide/cfg"
 	"github.com/Masterminds/glide/msg"
-	"github.com/Masterminds/glide/yaml"
 )
 
 // MissingPackageHandler handles the case where a package is missing during scanning.
@@ -230,7 +230,7 @@
 //
 // If one of the passed in packages does not exist in the vendor directory,
 // an error is returned.
-func (r *Resolver) ResolveAll(deps []*yaml.Dependency) ([]string, error) {
+func (r *Resolver) ResolveAll(deps []*cfg.Dependency) ([]string, error) {
 	queue := sliceToQueue(deps, r.VendorDir)
 	return r.resolveList(queue)
 }
@@ -389,7 +389,7 @@
 
 // sliceToQueue is a special-purpose function for unwrapping a slice of
 // dependencies into a queue of fully qualified paths.
-func sliceToQueue(deps []*yaml.Dependency, basepath string) *list.List {
+func sliceToQueue(deps []*cfg.Dependency, basepath string) *list.List {
 	l := list.New()
 	for _, e := range deps {
 		l.PushBack(filepath.Join(basepath, e.Name))
diff --git a/dependency/resolver_test.go b/dependency/resolver_test.go
index bed414d..46268f2 100644
--- a/dependency/resolver_test.go
+++ b/dependency/resolver_test.go
@@ -6,7 +6,7 @@
 	"strings"
 	"testing"
 
-	"github.com/Masterminds/glide/yaml"
+	"github.com/Masterminds/glide/cfg"
 )
 
 func TestResolveLocalShallow(t *testing.T) {
@@ -77,11 +77,11 @@
 
 func TestResolveAll(t *testing.T) {
 	// These are build dependencies of Glide, so we know they are here.
-	deps := []*yaml.Dependency{
-		&yaml.Dependency{Name: "github.com/codegangsta/cli"},
-		&yaml.Dependency{Name: "github.com/Masterminds/cookoo"},
-		&yaml.Dependency{Name: "github.com/Masterminds/semver"},
-		&yaml.Dependency{Name: "gopkg.in/yaml.v2"},
+	deps := []*cfg.Dependency{
+		&cfg.Dependency{Name: "github.com/codegangsta/cli"},
+		&cfg.Dependency{Name: "github.com/Masterminds/cookoo"},
+		&cfg.Dependency{Name: "github.com/Masterminds/semver"},
+		&cfg.Dependency{Name: "gopkg.in/yaml.v2"},
 	}
 
 	r, err := NewResolver("../")
diff --git a/glide.go b/glide.go
index 565a80a..f8d1995 100644
--- a/glide.go
+++ b/glide.go
@@ -124,22 +124,15 @@
 		{
 			Name:      "create",
 			ShortName: "init",
-			Usage:     "Initialize a new project, creating a template glide.yaml",
+			Usage:     "Initialize a new project, creating a glide.yaml file",
 			Description: `This command starts from a project without Glide and
-	sets it up. Once this step is done, you may edit the glide.yaml file and then
-	you may run 'glide install' to fetch your initial dependencies.
+	sets it up. It generates a glide.yaml file, parsing your codebase to guess
+	the dependencies to include. Once this step is done you may edit the
+	glide.yaml file to update imported dependency properties such as the version
+	or version range to include.
 
-	By default, the project name is 'main'. You can specify an alternative on
-	the commandline:
-
-		$ glide create github.com/Masterminds/foo
-
-	For a project that already has a glide.yaml file, you may skip 'glide create'
-	and instead run 'glide up'.`,
+	To fetch the dependencies you may run 'glide install'.`,
 			Action: func(c *cli.Context) {
-				if len(c.Args()) >= 1 {
-					cxt.Put("project", c.Args()[0])
-				}
 				setupHandler(c, "create", cxt, router)
 			},
 		},
@@ -317,10 +310,75 @@
 			},
 		},
 		{
+			Name:      "install",
+			ShortName: "i",
+			Usage:     "Install a project's dependencies",
+			Description: `This uses the native VCS of each packages to install
+		the appropriate version. There are two ways a projects dependencies can
+	be installed. When there is a glide.yaml file defining the dependencies but
+	no lock file (glide.lock) the dependencies are installed using the "update"
+	command and a glide.lock file is generated pinning all dependencies. If a
+	glide.lock file is already present the dependencies are installed or updated
+	from the lock file.`,
+			Flags: []cli.Flag{
+				cli.BoolFlag{
+					Name:  "delete",
+					Usage: "Delete vendor packages not specified in config.",
+				},
+				cli.BoolFlag{
+					Name:  "no-recursive, quick",
+					Usage: "Disable updating dependencies' dependencies. Only update things in glide.yaml.",
+				},
+				cli.BoolFlag{
+					Name:  "force",
+					Usage: "If there was a change in the repo or VCS switch to new one. Warning, changes will be lost.",
+				},
+				cli.BoolFlag{
+					Name:  "update-vendored, u",
+					Usage: "Update vendored packages (without local VCS repo). Warning, changes will be lost.",
+				},
+				cli.StringFlag{
+					Name:  "file, f",
+					Usage: "Save all of the discovered dependencies to a Glide YAML file.",
+				},
+				cli.BoolFlag{
+					Name:  "cache",
+					Usage: "When downloading dependencies attempt to cache them.",
+				},
+				cli.BoolFlag{
+					Name:  "cache-gopath",
+					Usage: "When downloading dependencies attempt to put them in the GOPATH, too.",
+				},
+				cli.BoolFlag{
+					Name:  "skip-gopath",
+					Usage: "Skip attempting to copy a dependency from the GOPATH.",
+				},
+			},
+			Action: func(c *cli.Context) {
+				cxt.Put("deleteOptIn", c.Bool("delete"))
+				cxt.Put("forceUpdate", c.Bool("force"))
+				cxt.Put("skipFlatten", c.Bool("no-recursive"))
+				cxt.Put("deleteFlatten", c.Bool("delete-flatten"))
+				cxt.Put("toPath", c.String("file"))
+				cxt.Put("toStdout", false)
+				cxt.Put("useCache", c.Bool("cache"))
+				cxt.Put("cacheGopath", c.Bool("cache-gopath"))
+				cxt.Put("skipGopath", c.Bool("skip-gopath"))
+				if c.Bool("import") {
+					cxt.Put("importGodeps", true)
+					cxt.Put("importGPM", true)
+					cxt.Put("importGb", true)
+				}
+				cxt.Put("updateVendoredDeps", c.Bool("update-vendored"))
+
+				cxt.Put("packages", []string(c.Args()))
+				setupHandler(c, "install", cxt, router)
+			},
+		},
+		{
 			Name:      "update",
 			ShortName: "up",
-			Aliases:   []string{"install"},
-			Usage:     "Update or install a project's dependencies",
+			Usage:     "Update a project's dependencies",
 			Description: `This uses the native VCS of each package to try to
 	pull the most applicable updates. Packages with fixed refs (Versions or
 	tags) will not be updated. Packages with no ref or with a branch ref will
@@ -429,27 +487,6 @@
 			},
 		},
 		{
-			Name:  "guess",
-			Usage: "Guess dependencies for existing source.",
-			Description: `This looks through existing source and dependencies,
-	and tries to guess all of the dependent packages.
-
-	By default, 'glide guess' writes to standard output. But if a filename
-	is supplied, the results are written to the file:
-
-		$ glide guess glide.yaml
-
-	The above will overwrite the glide.yaml file.`,
-			Action: func(c *cli.Context) {
-				outfile := ""
-				if len(c.Args()) == 1 {
-					outfile = c.Args()[0]
-				}
-				cxt.Put("toPath", outfile)
-				setupHandler(c, "guess", cxt, router)
-			},
-		},
-		{
 			Name:  "about",
 			Usage: "Learn about Glide",
 			Action: func(c *cli.Context) {
@@ -510,12 +547,27 @@
 		Using("conf").From("cxt:cfg").
 		Using("filename").WithDefault("glide.yaml").From("cxt:yaml")
 
-	reg.Route("exec", "Execute command with GOPATH set.").
+	reg.Route("install", "Install dependencies.").
 		Includes("@startup").
 		Includes("@ready").
-		Does(cmd.ExecCmd, "cmd").
-		Using("args").From("cxt:cliArgs").
-		Using("filename").From("cxt:yaml")
+		Does(cmd.CowardMode, "_").
+		Does(cmd.LockFileExists, "_").
+		Does(cmd.LoadLockFile, "lock").
+		Using("conf").From("cxt:cfg").
+		Does(cmd.Mkdir, "dir").Using("dir").WithDefault(VendorDir).
+		Does(cmd.DeleteUnusedPackages, "deleted").
+		Using("conf").From("cxt:cfg").
+		Using("optIn").From("cxt:deleteOptIn").
+		Does(cmd.VendoredSetup, "cfg").
+		Using("conf").From("cxt:cfg").
+		Using("update").From("cxt:updateVendoredDeps").
+		Does(cmd.Install, "icfg").
+		Using("conf").From("cxt:cfg").
+		Using("lock").From("cxt:lock").
+		Does(cmd.SetReference, "version").Using("conf").From("cxt:icfg").
+		Does(cmd.VendoredCleanUp, "_").
+		Using("conf").From("cxt:icfg").
+		Using("update").From("cxt:updateVendoredDeps")
 
 	reg.Route("update", "Update dependencies.").
 		Includes("@startup").
@@ -551,7 +603,9 @@
 		Does(cmd.WriteYaml, "out").
 		Using("conf").From("cxt:cfg").
 		Using("filename").From("cxt:toPath").
-		Using("toStdout").From("cxt:toStdout")
+		Using("toStdout").From("cxt:toStdout").
+		Does(cmd.WriteLock, "lock").
+		Using("lockfile").From("cxt:Lockfile")
 
 	//Does(cmd.Rebuild, "rebuild").Using("conf").From("cxt:cfg")
 
@@ -564,10 +618,22 @@
 	reg.Route("pin", "Print a YAML file with all of the packages pinned to the current version.").
 		Includes("@startup").
 		Includes("@ready").
-		Does(cmd.UpdateReferences, "refs").Using("conf").From("cxt:cfg").
+		Does(cmd.Flatten, "flattened").Using("conf").From("cxt:cfg").
+		Using("packages").From("cxt:packages").
+		Using("force").From("cxt:forceUpdate").
+		Using("skip").From("cxt:skipFlatten").
+		Using("home").From("cxt:home").
+		Using("cache").From("cxt:useCache").
+		Using("cacheGopath").From("cxt:cacheGopath").
+		Using("skipGopath").From("cxt:skipGopath").
+		//Does(cmd.VendoredCleanUp, "_").
+		//Using("conf").From("cxt:flattened").
+		//Using("update").From("cxt:updateVendoredDeps").
+		// Write the Lockfile
 		Does(cmd.WriteYaml, "out").
-		Using("conf").From("cxt:cfg").
-		Using("filename").From("cxt:toPath")
+		Using("conf").From("cxt:Lockfile").
+		Using("filename").From("cxt:toPath").
+		Using("toStdout").From("cxt:toStdout")
 
 	reg.Route("import gpm", "Read a Godeps file").
 		Includes("@startup").
@@ -605,18 +671,14 @@
 		Does(cmd.WriteYaml, "out").Using("conf").From("cxt:cfg").
 		Using("filename").From("cxt:toPath")
 
-	reg.Route("guess", "Guess dependencies").
-		Includes("@ready").
+	reg.Route("create", "Guess dependencies").
+		Includes("@startup").
+		Does(cmd.GuardYaml, "_").
+		Using("filename").From("cxt:yaml").
 		Does(cmd.GuessDeps, "cfg").
 		Does(cmd.WriteYaml, "out").
 		Using("conf").From("cxt:cfg").
-		Using("filename").From("cxt:toPath")
-
-	reg.Route("create", "Initialize Glide").
-		Includes("@startup").
-		Does(cmd.InitGlide, "init").
-		Using("filename").From("cxt:yaml").
-		Using("project").From("cxt:project").WithDefault("main")
+		Using("filename").From("cxt:yaml")
 
 	reg.Route("name", "Print environment").
 		Includes("@startup").
diff --git a/glide.lock b/glide.lock
new file mode 100644
index 0000000..24f77ad
--- /dev/null
+++ b/glide.lock
@@ -0,0 +1,18 @@
+hash: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
+updated: 2015-11-30T11:48:49.050533501-05:00
+imports:
+- name: github.com/codegangsta/cli
+  version: 0302d3914d2a6ad61404584cdae6e6dbc9c03599
+- name: github.com/Masterminds/cookoo
+  version: 78aa11ce75e257c51be7ea945edb84cf19c4a6de
+  repo: git@github.com:Masterminds/cookoo.git
+  vcs: git
+  subpackages:
+  - .
+- name: github.com/Masterminds/semver
+  version: 6333b7bd29aad1d79898ff568fd90a8aa533ae82
+- name: github.com/Masterminds/vcs
+  version: eaee272c8fa4514e1572e182faecff5be20e792a
+- name: gopkg.in/yaml.v2
+  version: 53feefa2559fb8dfa8d81baad31be332c97d6c77
+devImports: []
diff --git a/yaml/yaml_test.go b/yaml/yaml_test.go
deleted file mode 100644
index 94d160d..0000000
--- a/yaml/yaml_test.go
+++ /dev/null
@@ -1,66 +0,0 @@
-package yaml
-
-import "testing"
-
-var yml = `
-package: fake/testing
-import:
-  - package: github.com/kylelemons/go-gypsy
-    subpackages:
-      - yaml
-  # Intentionally left spaces at end of next line.
-  - package: github.com/Masterminds/convert
-    repo: git@github.com:Masterminds/convert.git
-    ref: a9949121a2e2192ca92fa6dddfeaaa4a4412d955
-    subpackages:
-      - color
-      - nautical
-      - radial
-    os:
-      - linux
-    arch:
-      - i386
-      - arm
-  - package: github.com/Masterminds/structable
-  - package: github.com/Masterminds/cookoo/color
-
-devimport:
-  - package: github.com/kylelemons/go-gypsy
-`
-
-func TestFromYaml(t *testing.T) {
-	cfg, err := FromYaml(yml)
-	if err != nil {
-		t.Errorf("Unexpected error parsing yaml %s", err)
-	}
-
-	if cfg.Name != "fake/testing" {
-		t.Errorf("Inaccurate name found %s", cfg.Name)
-	}
-
-	found := false
-	for _, i := range cfg.Imports {
-		if i.Name == "github.com/Masterminds/cookoo" {
-			found = true
-		}
-	}
-	if !found {
-		t.Error("Unable to find github.com/Masterminds/cookoo")
-	}
-}
-
-func TestToYaml(t *testing.T) {
-	cfg, err := FromYaml(yml)
-	if err != nil {
-		t.Errorf("Unexpected error parsing yaml %s", err)
-	}
-
-	o, err := ToYaml(cfg)
-	if err != nil {
-		t.Errorf("Unexpected error converting cfg to yaml %s", err)
-	}
-
-	if o == "" {
-		t.Error("Yaml output not generated when expected")
-	}
-}