818
}
819
}
820
821
+enum discovery_result {
822
+ GIT_DIR_NONE = 0,
823
+ GIT_DIR_EXPLICIT,
824
+ GIT_DIR_DISCOVERED,
825
+ GIT_DIR_BARE,
826
+ /* these are errors */
827
+ GIT_DIR_HIT_CEILING = -1,
828
+ GIT_DIR_HIT_MOUNT_POINT = -2
829
+};
830
+
831
/*
832
* We cannot decide in this function whether we are in the work tree or
833
* not, since the config can only be read _after_ this function was called.
834
+ *
835
+ * Also, we avoid changing any global state (such as the current working
836
+ * directory) to allow early callers.
837
+ *
838
+ * The directory where the search should start needs to be passed in via the
839
+ * `dir` parameter; upon return, the `dir` buffer will contain the path of
840
+ * the directory where the search ended, and `gitdir` will contain the path of
841
+ * the discovered .git/ directory, if any. If `gitdir` is not absolute, it
842
+ * is relative to `dir` (i.e. *not* necessarily the cwd).
843
*/
825
-static const char *setup_git_directory_gently_1(int *nongit_ok)
844
+static enum discovery_result setup_git_directory_gently_1(struct strbuf *dir,
845
+ struct strbuf *gitdir)
846
{
847
const char *env_ceiling_dirs = getenv(CEILING_DIRECTORIES_ENVIRONMENT);
848
struct string_list ceiling_dirs = STRING_LIST_INIT_DUP;
829
- static struct strbuf cwd = STRBUF_INIT;
830
- const char *gitdirenv, *ret;
831
- char *gitfile;
832
- int offset, offset_parent, ceil_offset = -1;
849
+ const char *gitdirenv;
850
+ int ceil_offset = -1, min_offset = has_dos_drive_prefix(dir->buf) ? 3 : 1;
851
dev_t current_device = 0;
852
int one_filesystem = 1;
853
836
- /*
837
- * We may have read an incomplete configuration before
838
- * setting-up the git directory. If so, clear the cache so
839
- * that the next queries to the configuration reload complete
840
- * configuration (including the per-repo config file that we
841
- * ignored previously).
842
- */
843
- git_config_clear();
844
-
845
- /*
846
- * Let's assume that we are in a git repository.
847
- * If it turns out later that we are somewhere else, the value will be
848
- * updated accordingly.
849
- */
850
- if (nongit_ok)
851
- *nongit_ok = 0;
852
-
853
- if (strbuf_getcwd(&cwd))
854
- die_errno(_("Unable to read current working directory"));
855
- offset = cwd.len;
856
-
854
/*
855
* If GIT_DIR is set explicitly, we're not going
856
* to do any discovery, but we still do repository
857
* validation.
858
*/
859
gitdirenv = getenv(GIT_DIR_ENVIRONMENT);
863
- if (gitdirenv)
864
- return setup_explicit_git_dir(gitdirenv, &cwd, nongit_ok);
860
+ if (gitdirenv) {
861
+ strbuf_addstr(gitdir, gitdirenv);
862
+ return GIT_DIR_EXPLICIT;
863
+ }
864
865
if (env_ceiling_dirs) {
866
int empty_entry_found = 0;
868
string_list_split(&ceiling_dirs, env_ceiling_dirs, PATH_SEP, -1);
869
filter_string_list(&ceiling_dirs, 0,
870
canonicalize_ceiling_entry, &empty_entry_found);
872
- ceil_offset = longest_ancestor_length(cwd.buf, &ceiling_dirs);
871
+ ceil_offset = longest_ancestor_length(dir->buf, &ceiling_dirs);
872
string_list_clear(&ceiling_dirs, 0);
873
}
874
876
- if (ceil_offset < 0 && has_dos_drive_prefix(cwd.buf))
877
- ceil_offset = 1;
875
+ if (ceil_offset < 0)
876
+ ceil_offset = min_offset - 2;
877
878
/*
880
- * Test in the following order (relative to the cwd):
879
+ * Test in the following order (relative to the dir):
880
* - .git (file containing "gitdir: <path>")
881
* - .git/
882
* - ./ (bare)
888
*/
889
one_filesystem = !git_env_bool("GIT_DISCOVERY_ACROSS_FILESYSTEM", 0);
890
if (one_filesystem)
892
- current_device = get_device_or_die(".", NULL, 0);
891
+ current_device = get_device_or_die(dir->buf, NULL, 0);
892
for (;;) {
894
- gitfile = (char*)read_gitfile(DEFAULT_GIT_DIR_ENVIRONMENT);
895
- if (gitfile)
896
- gitdirenv = gitfile = xstrdup(gitfile);
897
- else {
898
- if (is_git_directory(DEFAULT_GIT_DIR_ENVIRONMENT))
899
- gitdirenv = DEFAULT_GIT_DIR_ENVIRONMENT;
893
+ int offset = dir->len;
894
+
895
+ if (offset > min_offset)
896
+ strbuf_addch(dir, '/');
897
+ strbuf_addstr(dir, DEFAULT_GIT_DIR_ENVIRONMENT);
898
+ gitdirenv = read_gitfile(dir->buf);
899
+ if (!gitdirenv && is_git_directory(dir->buf))
900
+ gitdirenv = DEFAULT_GIT_DIR_ENVIRONMENT;
901
+ strbuf_setlen(dir, offset);
902
+ if (gitdirenv) {
903
+ strbuf_addstr(gitdir, gitdirenv);
904
+ return GIT_DIR_DISCOVERED;
905
}
906
902
- if (gitdirenv) {
903
- ret = setup_discovered_git_dir(gitdirenv,
904
- &cwd, offset,
905
- nongit_ok);
906
- free(gitfile);
907
- return ret;
907
+ if (is_git_directory(dir->buf)) {
908
+ strbuf_addstr(gitdir, ".");
909
+ return GIT_DIR_BARE;
910
}
909
- free(gitfile);
911
911
- if (is_git_directory("."))
912
- return setup_bare_git_dir(&cwd, offset, nongit_ok);
912
+ if (offset <= min_offset)
913
+ return GIT_DIR_HIT_CEILING;
914
914
- offset_parent = offset;
915
- while (--offset_parent > ceil_offset &&
916
- !is_dir_sep(cwd.buf[offset_parent]))
915
+ while (--offset > ceil_offset && !is_dir_sep(dir->buf[offset]))
916
; /* continue */
918
- if (offset_parent <= ceil_offset)
919
- return setup_nongit(cwd.buf, nongit_ok);
920
- if (one_filesystem) {
921
- dev_t parent_device = get_device_or_die("..", cwd.buf,
922
- offset);
923
- if (parent_device != current_device) {
924
- if (nongit_ok) {
925
- if (chdir(cwd.buf))
926
- die_errno(_("Cannot come back to cwd"));
927
- *nongit_ok = 1;
928
- return NULL;
929
- }
930
- strbuf_setlen(&cwd, offset);
931
- die(_("Not a git repository (or any parent up to mount point %s)\n"
932
- "Stopping at filesystem boundary (GIT_DISCOVERY_ACROSS_FILESYSTEM not set)."),
933
- cwd.buf);
934
- }
935
- }
936
- if (chdir("..")) {
937
- strbuf_setlen(&cwd, offset);
938
- die_errno(_("Cannot change to '%s/..'"), cwd.buf);
939
- }
940
- offset = offset_parent;
917
+ if (offset <= ceil_offset)
918
+ return GIT_DIR_HIT_CEILING;
919
+
920
+ strbuf_setlen(dir, offset > min_offset ? offset : min_offset);
921
+ if (one_filesystem &&
922
+ current_device != get_device_or_die(dir->buf, NULL, offset))
923
+ return GIT_DIR_HIT_MOUNT_POINT;
924
}
925
}
926
927
const char *setup_git_directory_gently(int *nongit_ok)
928
{
929
+ static struct strbuf cwd = STRBUF_INIT;
930
+ struct strbuf dir = STRBUF_INIT, gitdir = STRBUF_INIT;
931
const char *prefix;
932
948
- prefix = setup_git_directory_gently_1(nongit_ok);
933
+ /*
934
+ * We may have read an incomplete configuration before
935
+ * setting-up the git directory. If so, clear the cache so
936
+ * that the next queries to the configuration reload complete
937
+ * configuration (including the per-repo config file that we
938
+ * ignored previously).
939
+ */
940
+ git_config_clear();
941
+
942
+ /*
943
+ * Let's assume that we are in a git repository.
944
+ * If it turns out later that we are somewhere else, the value will be
945
+ * updated accordingly.
946
+ */
947
+ if (nongit_ok)
948
+ *nongit_ok = 0;
949
+
950
+ if (strbuf_getcwd(&cwd))
951
+ die_errno(_("Unable to read current working directory"));
952
+ strbuf_addbuf(&dir, &cwd);
953
+
954
+ switch (setup_git_directory_gently_1(&dir, &gitdir)) {
955
+ case GIT_DIR_NONE:
956
+ prefix = NULL;
957
+ break;
958
+ case GIT_DIR_EXPLICIT:
959
+ prefix = setup_explicit_git_dir(gitdir.buf, &cwd, nongit_ok);
960
+ break;
961
+ case GIT_DIR_DISCOVERED:
962
+ if (dir.len < cwd.len && chdir(dir.buf))
963
+ die(_("Cannot change to '%s'"), dir.buf);
964
+ prefix = setup_discovered_git_dir(gitdir.buf, &cwd, dir.len,
965
+ nongit_ok);
966
+ break;
967
+ case GIT_DIR_BARE:
968
+ if (dir.len < cwd.len && chdir(dir.buf))
969
+ die(_("Cannot change to '%s'"), dir.buf);
970
+ prefix = setup_bare_git_dir(&cwd, dir.len, nongit_ok);
971
+ break;
972
+ case GIT_DIR_HIT_CEILING:
973
+ prefix = setup_nongit(cwd.buf, nongit_ok);
974
+ break;
975
+ case GIT_DIR_HIT_MOUNT_POINT:
976
+ if (nongit_ok) {
977
+ *nongit_ok = 1;
978
+ strbuf_release(&cwd);
979
+ strbuf_release(&dir);
980
+ return NULL;
981
+ }
982
+ die(_("Not a git repository (or any parent up to mount point %s)\n"
983
+ "Stopping at filesystem boundary (GIT_DISCOVERY_ACROSS_FILESYSTEM not set)."),
984
+ dir.buf);
985
+ default:
986
+ die("BUG: unhandled setup_git_directory_1() result");
987
+ }
988
+
989
if (prefix)
990
setenv(GIT_PREFIX_ENVIRONMENT, prefix, 1);
991
else
994
startup_info->have_repository = !nongit_ok || !*nongit_ok;
995
startup_info->prefix = prefix;
996
997
+ strbuf_release(&dir);
998
+ strbuf_release(&gitdir);
999
+
1000
return prefix;
1001
}
1002