Merging from master
diff --git a/action/create.go b/action/create.go
index b66257c..fa72e6b 100644
--- a/action/create.go
+++ b/action/create.go
@@ -2,20 +2,31 @@
 
 import (
 	"os"
+	"os/exec"
 	"path/filepath"
+	"regexp"
 	"sort"
 	"strings"
+	"sync"
 
+	"github.com/Masterminds/glide/cache"
 	"github.com/Masterminds/glide/cfg"
 	"github.com/Masterminds/glide/dependency"
 	"github.com/Masterminds/glide/gb"
 	"github.com/Masterminds/glide/godep"
+	"github.com/Masterminds/glide/gom"
 	"github.com/Masterminds/glide/gpm"
 	"github.com/Masterminds/glide/msg"
 	gpath "github.com/Masterminds/glide/path"
 	"github.com/Masterminds/glide/util"
+	"github.com/Masterminds/semver"
+	"github.com/Masterminds/vcs"
 )
 
+// TODO(mattfarina): This file could really use to be cleaned up. It's functional
+// but not all that elegant. This mess of code really needs someone to come
+// along and clean it up. Pretty please.
+
 // Create creates/initializes a new Glide repository.
 //
 // This will fail if a glide.yaml already exists.
@@ -25,17 +36,21 @@
 // If skipImport is set to true, this will not attempt to import from an existing
 // GPM, Godep, or GB project if one should exist. However, it will still attempt
 // to read the local source to determine required packages.
-func Create(base string, skipImport bool) {
+func Create(base string, skipImport, noInteract, skipVerSug bool) {
 	glidefile := gpath.GlideFile
 	// Guard against overwrites.
 	guardYAML(glidefile)
 
 	// Guess deps
-	conf := guessDeps(base, skipImport)
+	conf := guessDeps(base, skipImport, noInteract, skipVerSug)
 	// Write YAML
+	msg.Info("Writing glide.yaml file")
 	if err := conf.WriteFile(glidefile); err != nil {
 		msg.Die("Could not save %s: %s", glidefile, err)
 	}
+	msg.Info("You can now edit the glide.yaml file. Consider:")
+	msg.Info("--> Using versions and ranges. See https://glide.sh/docs/versions/")
+	msg.Info("--> Adding additional metadata. See https://glide.sh/docs/glide.yaml/")
 }
 
 // guardYAML fails if the given file already exists.
@@ -54,7 +69,7 @@
 //
 // FIXME: This function is likely a one-off that has a more standard alternative.
 // It's also long and could use a refactor.
-func guessDeps(base string, skipImport bool) *cfg.Config {
+func guessDeps(base string, skipImport, noInteract, skipVerSug bool) *cfg.Config {
 	buildContext, err := util.GetBuildContext()
 	if err != nil {
 		msg.Die("Failed to build an import context: %s", err)
@@ -70,12 +85,18 @@
 
 	// Import by looking at other package managers and looking over the
 	// entire directory structure.
+	var deps cfg.Dependencies
 
 	// Attempt to import from other package managers.
 	if !skipImport {
-		guessImportDeps(base, config)
+		deps = guessImportDeps(base)
+		if len(deps) == 0 {
+			msg.Info("No dependencies found to import")
+		}
 	}
 
+	msg.Info("Scanning code to look for dependencies")
+
 	// Resolve dependencies by looking at the tree.
 	r, err := dependency.NewResolver(base)
 	if err != nil {
@@ -97,27 +118,76 @@
 		vpath = vpath + string(os.PathSeparator)
 	}
 
+	var count int
+	var all string
+	var allOnce bool
 	for _, pa := range sortable {
 		n := strings.TrimPrefix(pa, vpath)
 		root, subpkg := util.NormalizeName(n)
 
 		if !config.HasDependency(root) && root != config.Name {
-			msg.Info("Found reference to %s\n", n)
-			d := &cfg.Dependency{
-				Name: root,
+			count++
+			d := deps.Get(root)
+			if d == nil {
+				d = &cfg.Dependency{
+					Name: root,
+				}
+				msg.Info("--> Found reference to %s", n)
+			} else {
+				msg.Info("--> Found imported reference to %s", n)
 			}
-			if len(subpkg) > 0 {
-				d.Subpackages = []string{subpkg}
+
+			all, allOnce = guessAskVersion(noInteract, all, allOnce, skipVerSug, d)
+
+			if subpkg != "" {
+				if !d.HasSubpackage(subpkg) {
+					d.Subpackages = append(d.Subpackages, subpkg)
+				}
+				msg.Verbose("--> Noting sub-package %s to %s", subpkg, root)
 			}
+
 			config.Imports = append(config.Imports, d)
 		} else if config.HasDependency(root) {
 			if len(subpkg) > 0 {
 				subpkg = strings.TrimPrefix(subpkg, "/")
 				d := config.Imports.Get(root)
 				if !d.HasSubpackage(subpkg) {
-					msg.Info("Adding sub-package %s to %s\n", subpkg, root)
 					d.Subpackages = append(d.Subpackages, subpkg)
 				}
+				msg.Verbose("--> Noting sub-package %s to %s", subpkg, root)
+			}
+		}
+	}
+
+	if !skipImport && len(deps) > count {
+		var res string
+		if noInteract {
+			res = "y"
+		} else {
+			msg.Info("%d unused imported dependencies found. These are likely transitive dependencies ", len(deps)-count)
+			msg.Info("(dependencies of your dependencies). Would you like to track them in your")
+			msg.Info("glide.yaml file? Note, Glide will automatically scan your codebase to detect")
+			msg.Info("the complete dependency tree and import the complete tree. If your dependencies")
+			msg.Info("do not track dependency version information some version information may be lost.")
+			msg.Info("Yes (Y) or No (N)?")
+			res, err = msg.PromptUntil([]string{"y", "yes", "n", "no"})
+			if err != nil {
+				msg.Die("Error processing response: %s", err)
+			}
+		}
+		if res == "y" || res == "yes" {
+			msg.Info("Including additional imports in the glide.yaml file")
+			for _, dep := range deps {
+				found := config.Imports.Get(dep.Name)
+				if found == nil {
+					config.Imports = append(config.Imports, dep)
+					if dep.Reference != "" {
+						all, allOnce = guessAskVersion(noInteract, all, allOnce, skipVerSug, dep)
+						msg.Info("--> Adding %s at version %s", dep.Name, dep.Reference)
+					} else {
+						msg.Info("--> Adding %s", dep.Name)
+					}
+				}
 			}
 		}
 	}
@@ -125,7 +195,117 @@
 	return config
 }
 
-func guessImportDeps(base string, config *cfg.Config) {
+func guessAskVersion(noInteract bool, all string, allonce, skipVerSug bool, d *cfg.Dependency) (string, bool) {
+	if !noInteract && !skipVerSug && d.Reference == "" {
+		// If scanning has not happened already, for example this isn't an
+		// import, try it now.
+		var loc string
+		if d.Repository != "" {
+			loc = d.Repository
+		} else {
+			loc = "https://" + d.Name
+		}
+		if !guessVersionCache.checked(loc) {
+			createGuessVersion(loc, d.Reference)
+		}
+
+		semv := guessVersionCache.get(loc)
+		if semv != "" {
+			msg.Info("The package %s appears to have Semantic Version releases. The latest", d.Name)
+			msg.Info("release is %s. Would you like to use this release? Yes (Y) or No (N)", semv)
+			res, err2 := msg.PromptUntil([]string{"y", "yes", "n", "no"})
+			if err2 != nil {
+				msg.Die("Error processing response: %s", err2)
+			}
+
+			if res == "y" || res == "yes" {
+				d.Reference = semv
+			}
+		}
+
+	}
+
+	if !noInteract && d.Reference != "" {
+		var changedVer bool
+		ver, err := semver.NewVersion(d.Reference)
+		if err != nil && !skipVerSug {
+			var loc string
+			if d.Repository != "" {
+				loc = d.Repository
+			} else {
+				loc = "https://" + d.Name
+			}
+
+			semv := guessVersionCache.get(loc)
+			if semv != "" {
+				msg.Info("The package %s appears to have Semantic Version releases but the imported data", d.Name)
+				msg.Info("is not using them. The latest release is %s but the imported data is using %s.", semv, d.Reference)
+				msg.Info("Would you like to use the latest release version instead? Yes (Y) or No (N)")
+				res, err2 := msg.PromptUntil([]string{"y", "yes", "n", "no"})
+				if err2 != nil {
+					msg.Die("Error processing response: %s", err2)
+				}
+
+				if res == "y" || res == "yes" {
+					d.Reference = semv
+					changedVer = true
+				}
+			}
+		}
+
+		if changedVer {
+			ver, err = semver.NewVersion(d.Reference)
+		}
+		if err == nil {
+			if all == "" {
+				vstr := ver.String()
+				msg.Info("Imported dependency %s (%s) appears to use semantic versions (http://semver.org).", d.Name, d.Reference)
+				msg.Info("Would you like Glide to track the latest minor or patch releases (major.minor.path)?")
+				msg.Info("Tracking minor version releases would use '>= %s, < %d.0.0' ('^%s'). Tracking patch version", vstr, ver.Major()+1, vstr)
+				msg.Info("releases would use '>= %s, < %d.%d.0' ('~%s'). For more information on Glide versions", vstr, ver.Major(), ver.Minor()+1, vstr)
+				msg.Info("and ranges see https://glide.sh/docs/versions")
+				msg.Info("Minor (M), Patch (P), or Skip Ranges (S)?")
+				res, err := msg.PromptUntil([]string{"minor", "m", "patch", "p", "skip ranges", "s"})
+				if err != nil {
+					msg.Die("Error processing response: %s", err)
+				}
+				if res == "m" || res == "minor" {
+					d.Reference = "^" + vstr
+				} else if res == "p" || res == "patch" {
+					d.Reference = "~" + vstr
+				}
+
+				if !allonce {
+					msg.Info("Would you like to same response (%s) for future dependencies? Yes (Y) or No (N)", res)
+					res2, err := msg.PromptUntil([]string{"y", "yes", "n", "no"})
+					if err != nil {
+						msg.Die("Error processing response: %s", err)
+					}
+					if res2 == "yes" || res2 == "y" {
+						return res, true
+					}
+
+					return "", true
+				}
+
+			} else {
+				if all == "m" || all == "minor" {
+					d.Reference = "^" + ver.String()
+				} else if all == "p" || all == "patch" {
+					d.Reference = "~" + ver.String()
+				}
+			}
+
+			return all, allonce
+		}
+
+		return all, allonce
+	}
+
+	return all, allonce
+}
+
+func guessImportDeps(base string) cfg.Dependencies {
 	msg.Info("Attempting to import from other package managers (use --skip-import to skip)")
 	deps := []*cfg.Dependency{}
 	absBase, err := filepath.Abs(base)
@@ -135,7 +315,7 @@
 
 	if d, ok := guessImportGodep(absBase); ok {
 		msg.Info("Importing Godep configuration")
-		msg.Warn("Godep uses commit id versions. Consider using Semantic Versions with Glide")
+		msg.Warn("--> Godep uses commit id versions. Consider using Semantic Versions with Glide")
 		deps = d
 	} else if d, ok := guessImportGPM(absBase); ok {
 		msg.Info("Importing GPM configuration")
@@ -143,12 +323,41 @@
 	} else if d, ok := guessImportGB(absBase); ok {
 		msg.Info("Importing GB configuration")
 		deps = d
+	} else if d, ok := guessImportGom(absBase); ok {
+		msg.Info("Importing GB configuration")
+		deps = d
 	}
 
-	for _, i := range deps {
-		msg.Info("Found imported reference to %s\n", i.Name)
-		config.Imports = append(config.Imports, i)
+	if len(deps) > 0 {
+		msg.Info("--> Attempting to detect versions from imported commit ids")
 	}
+
+	var wg sync.WaitGroup
+
+	for _, i := range deps {
+		wg.Add(1)
+		go func(dep *cfg.Dependency) {
+			var remote string
+			if dep.Repository != "" {
+				remote = dep.Repository
+			} else {
+				remote = "https://" + dep.Name
+			}
+			ver := createGuessVersion(remote, dep.Reference)
+			if ver != dep.Reference {
+				msg.Verbose("--> Found imported reference to %s at version %s", dep.Name, ver)
+				dep.Reference = ver
+			}
+
+			msg.Debug("--> Found imported reference to %s at revision %s", dep.Name, dep.Reference)
+
+			wg.Done()
+		}(i)
+	}
+
+	wg.Wait()
+
+	return deps
 }
 
 func guessImportGodep(dir string) ([]*cfg.Dependency, bool) {
@@ -177,3 +386,165 @@
 
 	return d, true
 }
+
+func guessImportGom(dir string) ([]*cfg.Dependency, bool) {
+	d, err := gom.Parse(dir)
+	if err != nil || len(d) == 0 {
+		return []*cfg.Dependency{}, false
+	}
+
+	return d, true
+}
+
+// Note, this really needs a simpler name.
+var createGitParseVersion = regexp.MustCompile(`(?m-s)(?:tags)/(\S+)$`)
+
+var guessVersionCache = newVersionCache()
+
+func createGuessVersion(remote, id string) string {
+	err := cache.Setup()
+	if err != nil {
+		msg.Debug("Problem setting up cache: %s", err)
+	}
+	l, err := cache.Location()
+	if err != nil {
+		msg.Debug("Problem detecting cache location: %s", err)
+	}
+	key, err := cache.Key(remote)
+	if err != nil {
+		msg.Debug("Problem generating cache key for %s: %s", remote, err)
+	}
+
+	local := filepath.Join(l, "src", key)
+	repo, err := vcs.NewRepo(remote, local)
+	if err != nil {
+		msg.Debug("Problem getting repo instance: %s", err)
+	}
+
+	// Git endpoints allow for querying without fetching the codebase locally.
+	// We try that first to avoid fetching right away. Is this premature
+	// optimization?
+	cc := true
+	if repo.Vcs() == vcs.Git {
+		out, err := exec.Command("git", "ls-remote", remote).CombinedOutput()
+		if err == nil {
+			guessVersionCache.touchChecked(remote)
+			cc = false
+			lines := strings.Split(string(out), "\n")
+			res := ""
+
+			// TODO(mattfarina): Detect if the found version is semver and use
+			// that one instead of the first found.
+			for _, i := range lines {
+				ti := strings.TrimSpace(i)
+				if found := createGitParseVersion.FindString(ti); found != "" {
+					tg := strings.TrimPrefix(strings.TrimSuffix(found, "^{}"), "tags/")
+					if strings.HasPrefix(ti, id) {
+						res = tg
+					}
+
+					ver, err := semver.NewVersion(tg)
+					if err == nil {
+						if guessVersionCache.get(remote) == "" {
+							guessVersionCache.put(remote, tg)
+						} else {
+							ver2, err := semver.NewVersion(guessVersionCache.get(remote))
+							if err == nil {
+								if ver.GreaterThan(ver2) {
+									guessVersionCache.put(remote, tg)
+								}
+							}
+						}
+					}
+				}
+			}
+
+			if res != "" {
+				return res
+			}
+		}
+	}
+
+	if cc {
+		cache.Lock(key)
+		if _, err = os.Stat(local); os.IsNotExist(err) {
+			repo.Get()
+			branch := findCurrentBranch(repo)
+			c := cache.RepoInfo{DefaultBranch: branch}
+			err = cache.SaveRepoData(key, c)
+			if err != nil {
+				msg.Debug("Error saving cache repo details: %s", err)
+			}
+		} else {
+			repo.Update()
+		}
+
+		tgs, err := repo.TagsFromCommit(id)
+		if err != nil {
+			msg.Debug("Problem getting tags for commit: %s", err)
+		}
+		cache.Unlock(key)
+		if len(tgs) > 0 {
+			return tgs[0]
+		}
+	}
+
+	return id
+}
+
+func findCurrentBranch(repo vcs.Repo) string {
+	msg.Debug("Attempting to find current branch for %s", repo.Remote())
+	// Svn and Bzr don't have default branches.
+	if repo.Vcs() == vcs.Svn || repo.Vcs() == vcs.Bzr {
+		return ""
+	}
+
+	if repo.Vcs() == vcs.Git || repo.Vcs() == vcs.Hg {
+		ver, err := repo.Current()
+		if err != nil {
+			msg.Debug("Unable to find current branch for %s, error: %s", repo.Remote(), err)
+			return ""
+		}
+		return ver
+	}
+
+	return ""
+}
+
+type versionCache struct {
+	sync.RWMutex
+	cache map[string]string
+	cd    map[string]bool
+}
+
+func newVersionCache() *versionCache {
+	return &versionCache{
+		cache: make(map[string]string),
+		cd:    make(map[string]bool),
+	}
+}
+
+func (v *versionCache) put(name, version string) {
+	v.Lock()
+	defer v.Unlock()
+	v.cache[name] = version
+	v.cd[name] = true
+}
+
+func (v *versionCache) checked(name string) bool {
+	v.RLock()
+	defer v.RUnlock()
+	return v.cd[name]
+}
+
+func (v *versionCache) touchChecked(name string) {
+	v.Lock()
+	defer v.Unlock()
+	v.cd[name] = true
+}
+
+func (v *versionCache) get(name string) string {
+	v.RLock()
+	defer v.RUnlock()
+	return v.cache[name]
+}
diff --git a/action/debug.go b/action/debug.go
index 7b8eea6..6af9d26 100644
--- a/action/debug.go
+++ b/action/debug.go
@@ -7,6 +7,15 @@
 // Debug sets the debugging flags across components.
 func Debug(on bool) {
 	msg.Default.IsDebugging = on
+
+	if on == true {
+		msg.Default.IsVerbose = on
+	}
+}
+
+// Verbose sets the verbose flags across components.
+func Verbose(on bool) {
+	msg.Default.IsVerbose = on
 }
 
 // Quiet sets the quiet flags across components.
diff --git a/gb/gb.go b/gb/gb.go
index 1f3b208..7837a42 100644
--- a/gb/gb.go
+++ b/gb/gb.go
@@ -26,6 +26,7 @@
 	}
 
 	msg.Info("Found GB manifest file in %s", gpath.StripBasepath(dir))
+	msg.Info("--> Parsing GB metadata...")
 	buf := []*cfg.Dependency{}
 	file, err := os.Open(path)
 	if err != nil {
diff --git a/glide.go b/glide.go
index 0e1e355..2e01e1c 100644
--- a/glide.go
+++ b/glide.go
@@ -92,8 +92,12 @@
 			Usage: "Quiet (no info or debug messages)",
 		},
 		cli.BoolFlag{
+			Name:  "verbose",
+			Usage: "Print detailed informational messages",
+		},
+		cli.BoolFlag{
 			Name:  "debug",
-			Usage: "Print Debug messages (verbose)",
+			Usage: "Print debug verbose informational messages",
 		},
 		cli.StringFlag{
 			Name:   "home",
@@ -146,9 +150,17 @@
 					Name:  "skip-import",
 					Usage: "When initializing skip importing from other package managers.",
 				},
+				cli.BoolFlag{
+					Name:  "non-interactive",
+					Usage: "Disable interactive prompts.",
+				},
+				cli.BoolFlag{
+					Name:  "skip-version-suggestions",
+					Usage: "When imported commit ids are found that don't map to versions skip suggesting a version.",
+				},
 			},
 			Action: func(c *cli.Context) {
-				action.Create(".", c.Bool("skip-import"))
+				action.Create(".", c.Bool("skip-import"), c.Bool("non-interactive"), c.Bool("skip-version-suggestions"))
 			},
 		},
 		{
@@ -664,6 +676,7 @@
 // so it can be used by any Glide command.
 func startup(c *cli.Context) error {
 	action.Debug(c.Bool("debug"))
+	action.Verbose(c.Bool("verbose"))
 	action.NoColor(c.Bool("no-color"))
 	action.Quiet(c.Bool("quiet"))
 	action.Init(c.String("yaml"), c.String("home"))
diff --git a/godep/godep.go b/godep/godep.go
index a7d0525..71291b3 100644
--- a/godep/godep.go
+++ b/godep/godep.go
@@ -55,6 +55,7 @@
 		return []*cfg.Dependency{}, nil
 	}
 	msg.Info("Found Godeps.json file in %s", gpath.StripBasepath(dir))
+	msg.Info("--> Parsing Godeps metadata...")
 
 	buf := []*cfg.Dependency{}
 
diff --git a/gom/gom.go b/gom/gom.go
index 76305e4..51910b0 100644
--- a/gom/gom.go
+++ b/gom/gom.go
@@ -26,6 +26,7 @@
 	}
 
 	msg.Info("Found Gomfile in %s", gpath.StripBasepath(dir))
+	msg.Info("--> Parsing Gomfile metadata...")
 	buf := []*cfg.Dependency{}
 
 	goms, err := parseGomfile(path)
diff --git a/gpm/gpm.go b/gpm/gpm.go
index 45e316f..e58a81d 100644
--- a/gpm/gpm.go
+++ b/gpm/gpm.go
@@ -31,6 +31,7 @@
 		return []*cfg.Dependency{}, nil
 	}
 	msg.Info("Found Godeps file in %s", gpath.StripBasepath(dir))
+	msg.Info("--> Parsing GPM metadata...")
 
 	buf := []*cfg.Dependency{}
 
diff --git a/msg/msg.go b/msg/msg.go
index af49ecf..bb8b919 100644
--- a/msg/msg.go
+++ b/msg/msg.go
@@ -1,6 +1,7 @@
 package msg
 
 import (
+	"bufio"
 	"fmt"
 	"io"
 	"os"
@@ -16,9 +17,12 @@
 	// Quiet, if true, suppresses chatty levels, like Info.
 	Quiet bool
 
-	// IsDebugging, if true, shows verbose levels, like Debug.
+	// IsDebugging, if true, shows Debug.
 	IsDebugging bool
 
+	// IsVerbose, if true, shows detailed informational messages.
+	IsVerbose bool
+
 	// NoColor, if true, will not use color in the output.
 	NoColor bool
 
@@ -28,6 +32,9 @@
 	// Stderr is the location where this prints logs.
 	Stderr io.Writer
 
+	// Stdin is the location where input is read.
+	Stdin io.Reader
+
 	// PanicOnDie if true Die() will panic instead of exiting.
 	PanicOnDie bool
 
@@ -43,9 +50,11 @@
 	m := &Messenger{
 		Quiet:       false,
 		IsDebugging: false,
+		IsVerbose:   false,
 		NoColor:     false,
 		Stdout:      os.Stdout,
 		Stderr:      os.Stderr,
+		Stdin:       os.Stdin,
 		PanicOnDie:  false,
 		ecode:       1,
 	}
@@ -76,7 +85,7 @@
 		return
 	}
 	prefix := "[DEBUG]\t"
-	Msg(prefix+msg, args...)
+	m.Msg(prefix+msg, args...)
 }
 
 // Debug logs debug information using the Default Messenger
@@ -84,6 +93,19 @@
 	Default.Debug(msg, args...)
 }
 
+// Verbose logs detailed information
+func (m *Messenger) Verbose(msg string, args ...interface{}) {
+	if m.Quiet || !m.IsVerbose {
+		return
+	}
+	m.Info(msg, args...)
+}
+
+// Verbose detailed information using the Default Messenger
+func Verbose(msg string, args ...interface{}) {
+	Default.Verbose(msg, args...)
+}
+
 // Warn logs a warning
 func (m *Messenger) Warn(msg string, args ...interface{}) {
 	prefix := m.Color(Yellow, "[WARN]\t")
@@ -238,3 +260,30 @@
 func Color(code, msg string) string {
 	return Default.Color(code, msg)
 }
+
+// PromptUntil provides a prompt until one of the passed in strings has been
+// entered and return is hit. Note, the comparisons are case insensitive meaning
+// Y == y. The returned value is the one from the passed in options (same case).
+func (m *Messenger) PromptUntil(opts []string) (string, error) {
+	reader := bufio.NewReader(os.Stdin)
+	for {
+		text, err := reader.ReadString('\n')
+		if err != nil {
+			return "", err
+		}
+
+		for _, c := range opts {
+			if strings.EqualFold(c, strings.TrimSpace(text)) {
+				return c, nil
+			}
+		}
+	}
+}
+
+// PromptUntil provides a prompt until one of the passed in strings has been
+// entered and return is hit. Note, the comparisons are case insensitive meaning
+// Y == y. The returned value is the one from the passed in options (same case).
+// Uses the default setup.
+func PromptUntil(opts []string) (string, error) {
+	return Default.PromptUntil(opts)
+}