#include "cache.h"
+#include "repository.h"
+#include "config.h"
 #include "dir.h"
 #include "string-list.h"
 
        if (getenv(GIT_WORK_TREE_ENVIRONMENT))
                setenv(GIT_WORK_TREE_ENVIRONMENT, ".", 1);
 
+       /*
+        * NEEDSWORK: this call can essentially be set_git_dir(get_git_dir())
+        * which can cause some problems when trying to free the old value of
+        * gitdir.
+        */
        set_git_dir(remove_leading_path(git_dir, work_tree));
        initialized = 1;
 }
        }
 }
 
-const char *discover_git_directory(struct strbuf *gitdir)
+int discover_git_directory(struct strbuf *commondir,
+                          struct strbuf *gitdir)
 {
        struct strbuf dir = STRBUF_INIT, err = STRBUF_INIT;
        size_t gitdir_offset = gitdir->len, cwd_len;
+       size_t commondir_offset = commondir->len;
        struct repository_format candidate;
 
        if (strbuf_getcwd(&dir))
-               return NULL;
+               return -1;
 
        cwd_len = dir.len;
        if (setup_git_directory_gently_1(&dir, gitdir, 0) <= 0) {
                strbuf_release(&dir);
-               return NULL;
+               return -1;
        }
 
        /*
                strbuf_insert(gitdir, gitdir_offset, dir.buf, dir.len);
        }
 
+       get_common_dir(commondir, gitdir->buf + gitdir_offset);
+
        strbuf_reset(&dir);
-       strbuf_addf(&dir, "%s/config", gitdir->buf + gitdir_offset);
+       strbuf_addf(&dir, "%s/config", commondir->buf + commondir_offset);
        read_repository_format(&candidate, dir.buf);
        strbuf_release(&dir);
 
                warning("ignoring git dir '%s': %s",
                        gitdir->buf + gitdir_offset, err.buf);
                strbuf_release(&err);
-               return NULL;
+               strbuf_setlen(commondir, commondir_offset);
+               strbuf_setlen(gitdir, gitdir_offset);
+               return -1;
        }
 
-       return gitdir->buf + gitdir_offset;
+       return 0;
 }
 
 const char *setup_git_directory_gently(int *nongit_ok)
                die("BUG: unhandled setup_git_directory_1() result");
        }
 
+       /*
+        * NEEDSWORK: This was a hack in order to get ls-files and grep to have
+        * properly formated output when recursing submodules.  Once ls-files
+        * and grep have been changed to perform this recursing in-process this
+        * needs to be removed.
+        */
        env_prefix = getenv(GIT_TOPLEVEL_PREFIX_ENVIRONMENT);
        if (env_prefix)
                prefix = env_prefix;
        startup_info->have_repository = !nongit_ok || !*nongit_ok;
        startup_info->prefix = prefix;
 
+       /*
+        * Not all paths through the setup code will call 'set_git_dir()' (which
+        * directly sets up the environment) so in order to guarantee that the
+        * environment is in a consistent state after setup, explicitly setup
+        * the environment if we have a repository.
+        *
+        * NEEDSWORK: currently we allow bogus GIT_DIR values to be set in some
+        * code paths so we also need to explicitly setup the environment if
+        * the user has set GIT_DIR.  It may be beneficial to disallow bogus
+        * GIT_DIR values at some point in the future.
+        */
+       if (startup_info->have_repository || getenv(GIT_DIR_ENVIRONMENT)) {
+               if (!the_repository->gitdir) {
+                       const char *gitdir = getenv(GIT_DIR_ENVIRONMENT);
+                       if (!gitdir)
+                               gitdir = DEFAULT_GIT_DIR_ENVIRONMENT;
+                       repo_set_gitdir(the_repository, gitdir);
+                       setup_git_env();
+               }
+       }
+
        strbuf_release(&dir);
        strbuf_release(&gitdir);