2005-08-17 09:06:34 +08:00
|
|
|
#include "cache.h"
|
2017-06-23 02:43:33 +08:00
|
|
|
#include "repository.h"
|
2017-06-15 02:07:36 +08:00
|
|
|
#include "config.h"
|
Clean up work-tree handling
The old version of work-tree support was an unholy mess, barely readable,
and not to the point.
For example, why do you have to provide a worktree, when it is not used?
As in "git status". Now it works.
Another riddle was: if you can have work trees inside the git dir, why
are some programs complaining that they need a work tree?
IOW it is allowed to call
$ git --git-dir=../ --work-tree=. bla
when you really want to. In this case, you are both in the git directory
and in the working tree. So, programs have to actually test for the right
thing, namely if they are inside a working tree, and not if they are
inside a git directory.
Also, GIT_DIR=../.git should behave the same as if no GIT_DIR was
specified, unless there is a repository in the current working directory.
It does now.
The logic to determine if a repository is bare, or has a work tree
(tertium non datur), is this:
--work-tree=bla overrides GIT_WORK_TREE, which overrides core.bare = true,
which overrides core.worktree, which overrides GIT_DIR/.. when GIT_DIR
ends in /.git, which overrides the directory in which .git/ was found.
In related news, a long standing bug was fixed: when in .git/bla/x.git/,
which is a bare repository, git formerly assumed ../.. to be the
appropriate git dir. This problem was reported by Shawn Pearce to have
caused much pain, where a colleague mistakenly ran "git init" in "/" a
long time ago, and bare repositories just would not work.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-08-01 08:30:14 +08:00
|
|
|
#include "dir.h"
|
2012-10-29 00:16:24 +08:00
|
|
|
#include "string-list.h"
|
Clean up work-tree handling
The old version of work-tree support was an unholy mess, barely readable,
and not to the point.
For example, why do you have to provide a worktree, when it is not used?
As in "git status". Now it works.
Another riddle was: if you can have work trees inside the git dir, why
are some programs complaining that they need a work tree?
IOW it is allowed to call
$ git --git-dir=../ --work-tree=. bla
when you really want to. In this case, you are both in the git directory
and in the working tree. So, programs have to actually test for the right
thing, namely if they are inside a working tree, and not if they are
inside a git directory.
Also, GIT_DIR=../.git should behave the same as if no GIT_DIR was
specified, unless there is a repository in the current working directory.
It does now.
The logic to determine if a repository is bare, or has a work tree
(tertium non datur), is this:
--work-tree=bla overrides GIT_WORK_TREE, which overrides core.bare = true,
which overrides core.worktree, which overrides GIT_DIR/.. when GIT_DIR
ends in /.git, which overrides the directory in which .git/ was found.
In related news, a long standing bug was fixed: when in .git/bla/x.git/,
which is a bare repository, git formerly assumed ../.. to be the
appropriate git dir. This problem was reported by Shawn Pearce to have
caused much pain, where a colleague mistakenly ran "git init" in "/" a
long time ago, and bare repositories just would not work.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-08-01 08:30:14 +08:00
|
|
|
|
|
|
|
static int inside_git_dir = -1;
|
|
|
|
static int inside_work_tree = -1;
|
setup_git_directory: delay core.bare/core.worktree errors
If both core.bare and core.worktree are set, we complain
about the bogus config and die. Dying is good, because it
avoids commands running and doing damage in a potentially
incorrect setup. But dying _there_ is bad, because it means
that commands which do not even care about the work tree
cannot run. This can make repairing the situation harder:
[setup]
$ git config core.bare true
$ git config core.worktree /some/path
[OK, expected.]
$ git status
fatal: core.bare and core.worktree do not make sense
[Hrm...]
$ git config --unset core.worktree
fatal: core.bare and core.worktree do not make sense
[Nope...]
$ git config --edit
fatal: core.bare and core.worktree do not make sense
[Gaaah.]
$ git help config
fatal: core.bare and core.worktree do not make sense
Instead, let's issue a warning about the bogus config when
we notice it (i.e., for all commands), but only die when the
command tries to use the work tree (by calling setup_work_tree).
So we now get:
$ git status
warning: core.bare and core.worktree do not make sense
fatal: unable to set up work tree using invalid config
$ git config --unset core.worktree
warning: core.bare and core.worktree do not make sense
We have to update t1510 to accomodate this; it uses
symbolic-ref to check whether the configuration works or
not, but of course that command does not use the working
tree. Instead, we switch it to use `git status`, as it
requires a work-tree, does not need any special setup, and
is read-only (so a failure will not adversely affect further
tests).
In addition, we add a new test that checks the desired
behavior (i.e., that running "git config" with the bogus
config does in fact work).
Reported-by: SZEDER Gábor <szeder@ira.uka.de>
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-05-29 14:49:10 +08:00
|
|
|
static int work_tree_config_is_bogus;
|
2005-08-17 09:06:34 +08:00
|
|
|
|
setup: make startup_info available everywhere
Commit a60645f (setup: remember whether repository was
found, 2010-08-05) introduced the startup_info structure,
which records some parts of the setup_git_directory()
process (notably, whether we actually found a repository or
not).
One of the uses of this data is for functions to behave
appropriately based on whether we are in a repo. But the
startup_info struct is just a pointer to storage provided by
the main program, and the only program that sets it up is
the git.c wrapper. Thus builtins have access to
startup_info, but externally linked programs do not.
Worse, library code which is accessible from both has to be
careful about accessing startup_info. This can be used to
trigger a die("BUG") via get_sha1():
$ git fast-import <<-\EOF
tag foo
from HEAD:./whatever
EOF
fatal: BUG: startup_info struct is not initialized.
Obviously that's fairly nonsensical input to feed to
fast-import, but we should never hit a die("BUG"). And there
may be other ways to trigger it if other non-builtins
resolve sha1s.
So let's point the storage for startup_info to a static
variable in setup.c, making it available to all users of the
library code. We _could_ turn startup_info into a regular
extern struct, but doing so would mean tweaking all of the
existing use sites. So let's leave the pointer indirection
in place. We can, however, drop any checks for NULL, as
they will always be false (and likewise, we can drop the
test covering this case, which was a rather artificial
situation using one of the test-* programs).
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-03-06 06:10:27 +08:00
|
|
|
static struct startup_info the_startup_info;
|
|
|
|
struct startup_info *startup_info = &the_startup_info;
|
|
|
|
|
2014-02-04 22:25:19 +08:00
|
|
|
/*
|
|
|
|
* The input parameter must contain an absolute path, and it must already be
|
|
|
|
* normalized.
|
|
|
|
*
|
|
|
|
* Find the part of an absolute path that lies inside the work tree by
|
|
|
|
* dereferencing symlinks outside the work tree, for example:
|
|
|
|
* /dir1/repo/dir2/file (work tree is /dir1/repo) -> dir2/file
|
|
|
|
* /dir/file (work tree is /) -> dir/file
|
|
|
|
* /dir/symlink1/symlink2 (symlink1 points to work tree) -> symlink2
|
|
|
|
* /dir/repolink/file (repolink points to /dir/repo) -> file
|
|
|
|
* /dir/repo (exactly equal to work tree) -> (empty string)
|
|
|
|
*/
|
|
|
|
static int abspath_part_inside_repo(char *path)
|
|
|
|
{
|
|
|
|
size_t len;
|
|
|
|
size_t wtlen;
|
|
|
|
char *path0;
|
|
|
|
int off;
|
|
|
|
const char *work_tree = get_git_work_tree();
|
|
|
|
|
|
|
|
if (!work_tree)
|
|
|
|
return -1;
|
|
|
|
wtlen = strlen(work_tree);
|
|
|
|
len = strlen(path);
|
2014-04-24 21:06:09 +08:00
|
|
|
off = offset_1st_component(path);
|
2014-02-04 22:25:19 +08:00
|
|
|
|
|
|
|
/* check if work tree is already the prefix */
|
|
|
|
if (wtlen <= len && !strncmp(path, work_tree, wtlen)) {
|
|
|
|
if (path[wtlen] == '/') {
|
|
|
|
memmove(path, path + wtlen + 1, len - wtlen);
|
|
|
|
return 0;
|
|
|
|
} else if (path[wtlen - 1] == '/' || path[wtlen] == '\0') {
|
|
|
|
/* work tree is the root, or the whole path */
|
|
|
|
memmove(path, path + wtlen, len - wtlen + 1);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
/* work tree might match beginning of a symlink to work tree */
|
|
|
|
off = wtlen;
|
|
|
|
}
|
|
|
|
path0 = path;
|
2014-04-24 21:06:09 +08:00
|
|
|
path += off;
|
2014-02-04 22:25:19 +08:00
|
|
|
|
|
|
|
/* check each '/'-terminated level */
|
|
|
|
while (*path) {
|
|
|
|
path++;
|
|
|
|
if (*path == '/') {
|
|
|
|
*path = '\0';
|
|
|
|
if (strcmp(real_path(path0), work_tree) == 0) {
|
|
|
|
memmove(path0, path + 1, len - (path - path0));
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
*path = '/';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* check whole path */
|
|
|
|
if (strcmp(real_path(path0), work_tree) == 0) {
|
|
|
|
*path0 = '\0';
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2013-07-14 16:36:03 +08:00
|
|
|
/*
|
|
|
|
* Normalize "path", prepending the "prefix" for relative paths. If
|
|
|
|
* remaining_prefix is not NULL, return the actual prefix still
|
|
|
|
* remains in the path. For example, prefix = sub1/sub2/ and path is
|
|
|
|
*
|
|
|
|
* foo -> sub1/sub2/foo (full prefix)
|
|
|
|
* ../foo -> sub1/foo (remaining prefix is sub1/)
|
|
|
|
* ../../bar -> bar (no remaining prefix)
|
|
|
|
* ../../sub1/sub2/foo -> sub1/sub2/foo (but no remaining prefix)
|
|
|
|
* `pwd`/../bar -> sub1/bar (no remaining prefix)
|
|
|
|
*/
|
|
|
|
char *prefix_path_gently(const char *prefix, int len,
|
|
|
|
int *remaining_prefix, const char *path)
|
setup: sanitize absolute and funny paths in get_pathspec()
The prefix_path() function called from get_pathspec() is
responsible for translating list of user-supplied pathspecs to
list of pathspecs that is relative to the root of the work
tree. When working inside a subdirectory, the user-supplied
pathspecs are taken to be relative to the current subdirectory.
Among special path components in pathspecs, we used to accept
and interpret only "." ("the directory", meaning a no-op) and
".." ("up one level") at the beginning. Everything else was
passed through as-is.
For example, if you are in Documentation/ directory of the
project, you can name Documentation/howto/maintain-git.txt as:
howto/maintain-git.txt
../Documentation/howto/maitain-git.txt
../././Documentation/howto/maitain-git.txt
but not as:
howto/./maintain-git.txt
$(pwd)/howto/maintain-git.txt
This patch updates prefix_path() in several ways:
- If the pathspec is not absolute, prefix (i.e. the current
subdirectory relative to the root of the work tree, with
terminating slash, if not empty) and the pathspec is
concatenated first and used in the next step. Otherwise,
that absolute pathspec is used in the next step.
- Then special path components "." (no-op) and ".." (up one
level) are interpreted to simplify the path. It is an error
to have too many ".." to cause the intermediate result to
step outside of the input to this step.
- If the original pathspec was not absolute, the result from
the previous step is the resulting "sanitized" pathspec.
Otherwise, the result from the previous step is still
absolute, and it is an error if it does not begin with the
directory that corresponds to the root of the work tree. The
directory is stripped away from the result and is returned.
- In any case, the resulting pathspec in the array
get_pathspec() returns omit the ones that caused errors.
With this patch, the last two examples also behave as expected.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-01-29 14:44:27 +08:00
|
|
|
{
|
|
|
|
const char *orig = path;
|
2010-12-27 18:54:37 +08:00
|
|
|
char *sanitized;
|
|
|
|
if (is_absolute_path(orig)) {
|
2016-02-23 06:44:28 +08:00
|
|
|
sanitized = xmallocz(strlen(path));
|
2013-07-14 16:36:03 +08:00
|
|
|
if (remaining_prefix)
|
|
|
|
*remaining_prefix = 0;
|
2014-02-04 22:25:20 +08:00
|
|
|
if (normalize_path_copy_len(sanitized, path, remaining_prefix)) {
|
|
|
|
free(sanitized);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
if (abspath_part_inside_repo(sanitized)) {
|
|
|
|
free(sanitized);
|
|
|
|
return NULL;
|
|
|
|
}
|
2010-12-27 18:54:37 +08:00
|
|
|
} else {
|
setup.c: do not feed NULL to "%.*s" even with precision 0
A recent update 75faa45a (replace trivial malloc + sprintf / strcpy
calls with xstrfmt, 2015-09-24) rewrote
prepare an empty buffer
if (len)
append the first len bytes of "prefix" to the buffer
append "path" to the buffer
that computed "path", optionally prefixed by "prefix", into
xstrfmt("%.*s%s", len, prefix, path);
However, passing a NULL pointer to the printf(3) family of functions
to format it with %s conversion, even with the precision set to 0,
i.e.
xstrfmt("%.*s", 0, NULL)
yields undefined results, at least on some platforms.
Avoid this problem by substituting prefix with "" when len==0, as
prefix can legally be NULL in that case. This would mimick the
intent of the original code better.
Reported-by: Tom G. Christensen <tgc@jupiterrise.com>
Helped-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-04-08 03:38:18 +08:00
|
|
|
sanitized = xstrfmt("%.*s%s", len, len ? prefix : "", path);
|
2013-07-14 16:36:03 +08:00
|
|
|
if (remaining_prefix)
|
|
|
|
*remaining_prefix = len;
|
2014-02-04 22:25:20 +08:00
|
|
|
if (normalize_path_copy_len(sanitized, sanitized, remaining_prefix)) {
|
2012-06-22 02:09:50 +08:00
|
|
|
free(sanitized);
|
|
|
|
return NULL;
|
setup: sanitize absolute and funny paths in get_pathspec()
The prefix_path() function called from get_pathspec() is
responsible for translating list of user-supplied pathspecs to
list of pathspecs that is relative to the root of the work
tree. When working inside a subdirectory, the user-supplied
pathspecs are taken to be relative to the current subdirectory.
Among special path components in pathspecs, we used to accept
and interpret only "." ("the directory", meaning a no-op) and
".." ("up one level") at the beginning. Everything else was
passed through as-is.
For example, if you are in Documentation/ directory of the
project, you can name Documentation/howto/maintain-git.txt as:
howto/maintain-git.txt
../Documentation/howto/maitain-git.txt
../././Documentation/howto/maitain-git.txt
but not as:
howto/./maintain-git.txt
$(pwd)/howto/maintain-git.txt
This patch updates prefix_path() in several ways:
- If the pathspec is not absolute, prefix (i.e. the current
subdirectory relative to the root of the work tree, with
terminating slash, if not empty) and the pathspec is
concatenated first and used in the next step. Otherwise,
that absolute pathspec is used in the next step.
- Then special path components "." (no-op) and ".." (up one
level) are interpreted to simplify the path. It is an error
to have too many ".." to cause the intermediate result to
step outside of the input to this step.
- If the original pathspec was not absolute, the result from
the previous step is the resulting "sanitized" pathspec.
Otherwise, the result from the previous step is still
absolute, and it is an error if it does not begin with the
directory that corresponds to the root of the work tree. The
directory is stripped away from the result and is returned.
- In any case, the resulting pathspec in the array
get_pathspec() returns omit the ones that caused errors.
With this patch, the last two examples also behave as expected.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-01-29 14:44:27 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return sanitized;
|
2005-08-17 11:44:32 +08:00
|
|
|
}
|
|
|
|
|
2012-06-22 02:09:50 +08:00
|
|
|
char *prefix_path(const char *prefix, int len, const char *path)
|
|
|
|
{
|
2013-07-14 16:36:03 +08:00
|
|
|
char *r = prefix_path_gently(prefix, len, NULL, path);
|
2012-06-22 02:09:50 +08:00
|
|
|
if (!r)
|
|
|
|
die("'%s' is outside repository", path);
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
int path_inside_repo(const char *prefix, const char *path)
|
|
|
|
{
|
|
|
|
int len = prefix ? strlen(prefix) : 0;
|
2013-07-14 16:36:03 +08:00
|
|
|
char *r = prefix_path_gently(prefix, len, NULL, path);
|
2012-06-22 02:09:50 +08:00
|
|
|
if (r) {
|
|
|
|
free(r);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-10-18 15:27:24 +08:00
|
|
|
int check_filename(const char *prefix, const char *arg)
|
|
|
|
{
|
2017-03-21 09:28:49 +08:00
|
|
|
char *to_free = NULL;
|
2009-10-18 15:27:24 +08:00
|
|
|
struct stat st;
|
|
|
|
|
2017-05-27 03:07:42 +08:00
|
|
|
if (skip_prefix(arg, ":/", &arg)) {
|
|
|
|
if (!*arg) /* ":/" is root dir, always exists */
|
2013-01-21 21:00:48 +08:00
|
|
|
return 1;
|
2017-05-27 03:07:31 +08:00
|
|
|
prefix = NULL;
|
2017-05-27 03:08:39 +08:00
|
|
|
} else if (skip_prefix(arg, ":!", &arg) ||
|
|
|
|
skip_prefix(arg, ":^", &arg)) {
|
|
|
|
if (!*arg) /* excluding everything is silly, but allowed */
|
|
|
|
return 1;
|
2017-05-27 03:07:31 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (prefix)
|
|
|
|
arg = to_free = prefix_filename(prefix, arg);
|
|
|
|
|
|
|
|
if (!lstat(arg, &st)) {
|
2017-03-21 09:28:49 +08:00
|
|
|
free(to_free);
|
2009-10-18 15:27:24 +08:00
|
|
|
return 1; /* file exists */
|
2017-03-21 09:28:49 +08:00
|
|
|
}
|
2017-06-14 04:47:06 +08:00
|
|
|
if (is_missing_file_error(errno)) {
|
2017-03-21 09:28:49 +08:00
|
|
|
free(to_free);
|
2009-10-18 15:27:24 +08:00
|
|
|
return 0; /* file does not exist */
|
2017-03-21 09:28:49 +08:00
|
|
|
}
|
2009-10-18 15:27:24 +08:00
|
|
|
die_errno("failed to stat '%s'", arg);
|
|
|
|
}
|
|
|
|
|
2012-06-19 02:18:21 +08:00
|
|
|
static void NORETURN die_verify_filename(const char *prefix,
|
|
|
|
const char *arg,
|
|
|
|
int diagnose_misspelt_rev)
|
2009-12-07 18:10:50 +08:00
|
|
|
{
|
2012-06-19 02:18:21 +08:00
|
|
|
if (!diagnose_misspelt_rev)
|
2016-06-18 04:21:06 +08:00
|
|
|
die(_("%s: no such path in the working tree.\n"
|
|
|
|
"Use 'git <command> -- <path>...' to specify paths that do not exist locally."),
|
2012-06-19 02:18:21 +08:00
|
|
|
arg);
|
2011-05-11 03:05:01 +08:00
|
|
|
/*
|
|
|
|
* Saying "'(icase)foo' does not exist in the index" when the
|
|
|
|
* user gave us ":(icase)foo" is just stupid. A magic pathspec
|
|
|
|
* begins with a colon and is followed by a non-alnum; do not
|
2012-07-03 02:01:25 +08:00
|
|
|
* let maybe_die_on_misspelt_object_name() even trigger.
|
2011-05-11 03:05:01 +08:00
|
|
|
*/
|
|
|
|
if (!(arg[0] == ':' && !isalnum(arg[1])))
|
2012-07-03 02:01:25 +08:00
|
|
|
maybe_die_on_misspelt_object_name(arg, prefix);
|
2011-05-11 03:05:01 +08:00
|
|
|
|
2009-12-07 18:10:50 +08:00
|
|
|
/* ... or fall back the most general message. */
|
2016-06-18 04:21:06 +08:00
|
|
|
die(_("ambiguous argument '%s': unknown revision or path not in the working tree.\n"
|
|
|
|
"Use '--' to separate paths from revisions, like this:\n"
|
|
|
|
"'git <command> [<revision>...] -- [<file>...]'"), arg);
|
2009-12-07 18:10:50 +08:00
|
|
|
|
|
|
|
}
|
|
|
|
|
verify_filename(): treat ":(magic)" as a pathspec
For commands that take revisions and pathspecs, magic
pathspecs like ":(exclude)foo" require the user to specify
a disambiguating "--", since they do not match a file in the
filesystem, like:
git grep foo -- :(exclude)bar
This makes them more annoying to use than they need to be.
We loosened the rules for wildcards in 28fcc0b71 (pathspec:
avoid the need of "--" when wildcard is used, 2015-05-02).
Let's do the same for pathspecs with long-form magic.
We already handle the short-forms ":/" and ":^" specially in
check_filename(), so we don't need to handle them here. And
in fact, we could do the same with long-form magic, parsing
out the actual filename and making sure it exists. But there
are a few reasons not to do it that way:
- the parsing gets much more complicated, and we'd want to
hand it off to the pathspec code. But that code isn't
ready to do this kind of speculative parsing (it's happy
to die() when it sees a syntactically invalid pathspec).
- not all pathspec magic maps to a filesystem path. E.g.,
:(attr) should be treated as a pathspec regardless of
what is in the filesystem
- we can be a bit looser with ":(" than with the
short-form ":/", because it is much less likely to have
a false positive. Whereas ":/" also means "search for a
commit with this regex".
Note that because the change is in verify_filename() and not
in its helper check_filename(), this doesn't affect the
verify_non_filename() case. I.e., if an item that matches
our new rule doesn't resolve as an object, we may fallback
to treating it as a pathspec (rather than complaining it
doesn't exist). But if it does resolve (e.g., as a file in
the index that starts with an open-paren), we won't then
complain that it's also a valid pathspec. This matches the
wildcard-exception behavior.
And of course in either case, one can always insert the "--"
to get more precise results.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-05-27 03:10:31 +08:00
|
|
|
/*
|
|
|
|
* Check for arguments that don't resolve as actual files,
|
|
|
|
* but which look sufficiently like pathspecs that we'll consider
|
|
|
|
* them such for the purposes of rev/pathspec DWIM parsing.
|
|
|
|
*/
|
|
|
|
static int looks_like_pathspec(const char *arg)
|
|
|
|
{
|
|
|
|
/* anything with a wildcard character */
|
|
|
|
if (!no_wildcard(arg))
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
/* long-form pathspec magic */
|
|
|
|
if (starts_with(arg, ":("))
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-04-27 01:15:54 +08:00
|
|
|
/*
|
|
|
|
* Verify a filename that we got as an argument for a pathspec
|
|
|
|
* entry. Note that a filename that begins with "-" never verifies
|
|
|
|
* as true, because even if such a filename were to exist, we want
|
|
|
|
* it to be preceded by the "--" marker (or we want the user to
|
|
|
|
* use a format like "./-filename")
|
2012-06-19 02:18:21 +08:00
|
|
|
*
|
|
|
|
* The "diagnose_misspelt_rev" is used to provide a user-friendly
|
|
|
|
* diagnosis when dying upon finding that "name" is not a pathname.
|
|
|
|
* If set to 1, the diagnosis will try to diagnose "name" as an
|
|
|
|
* invalid object name (e.g. HEAD:foo). If set to 0, the diagnosis
|
|
|
|
* will only complain about an inexisting file.
|
|
|
|
*
|
|
|
|
* This function is typically called to check that a "file or rev"
|
|
|
|
* argument is unambiguous. In this case, the caller will want
|
|
|
|
* diagnose_misspelt_rev == 1 when verifying the first non-rev
|
|
|
|
* argument (which could have been a revision), and
|
|
|
|
* diagnose_misspelt_rev == 0 for the next ones (because we already
|
|
|
|
* saw a filename, there's not ambiguity anymore).
|
2006-04-27 01:15:54 +08:00
|
|
|
*/
|
2012-06-19 02:18:21 +08:00
|
|
|
void verify_filename(const char *prefix,
|
|
|
|
const char *arg,
|
|
|
|
int diagnose_misspelt_rev)
|
2006-04-27 01:15:54 +08:00
|
|
|
{
|
|
|
|
if (*arg == '-')
|
2017-10-03 01:30:02 +08:00
|
|
|
die("option '%s' must come before non-option arguments", arg);
|
2017-05-27 03:10:53 +08:00
|
|
|
if (looks_like_pathspec(arg) || check_filename(prefix, arg))
|
2006-04-27 01:15:54 +08:00
|
|
|
return;
|
2012-06-19 02:18:21 +08:00
|
|
|
die_verify_filename(prefix, arg, diagnose_misspelt_rev);
|
2006-04-27 01:15:54 +08:00
|
|
|
}
|
|
|
|
|
2006-04-27 06:09:27 +08:00
|
|
|
/*
|
|
|
|
* Opposite of the above: the command line did not have -- marker
|
|
|
|
* and we parsed the arg as a refname. It should not be interpretable
|
|
|
|
* as a filename.
|
|
|
|
*/
|
|
|
|
void verify_non_filename(const char *prefix, const char *arg)
|
|
|
|
{
|
2007-06-03 22:48:16 +08:00
|
|
|
if (!is_inside_work_tree() || is_inside_git_dir())
|
2007-01-20 10:09:34 +08:00
|
|
|
return;
|
2006-04-27 06:09:27 +08:00
|
|
|
if (*arg == '-')
|
|
|
|
return; /* flag */
|
2009-10-18 15:27:24 +08:00
|
|
|
if (!check_filename(prefix, arg))
|
|
|
|
return;
|
2016-06-18 04:21:06 +08:00
|
|
|
die(_("ambiguous argument '%s': both revision and filename\n"
|
|
|
|
"Use '--' to separate paths from revisions, like this:\n"
|
|
|
|
"'git <command> [<revision>...] -- [<file>...]'"), arg);
|
2006-04-27 06:09:27 +08:00
|
|
|
}
|
|
|
|
|
2014-11-30 16:24:44 +08:00
|
|
|
int get_common_dir(struct strbuf *sb, const char *gitdir)
|
2015-09-14 06:17:42 +08:00
|
|
|
{
|
|
|
|
const char *git_env_common_dir = getenv(GIT_COMMON_DIR_ENVIRONMENT);
|
|
|
|
if (git_env_common_dir) {
|
|
|
|
strbuf_addstr(sb, git_env_common_dir);
|
|
|
|
return 1;
|
|
|
|
} else {
|
|
|
|
return get_common_dir_noenv(sb, gitdir);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int get_common_dir_noenv(struct strbuf *sb, const char *gitdir)
|
2014-11-30 16:24:41 +08:00
|
|
|
{
|
|
|
|
struct strbuf data = STRBUF_INIT;
|
|
|
|
struct strbuf path = STRBUF_INIT;
|
2014-11-30 16:24:44 +08:00
|
|
|
int ret = 0;
|
2015-09-14 06:17:42 +08:00
|
|
|
|
2014-11-30 16:24:41 +08:00
|
|
|
strbuf_addf(&path, "%s/commondir", gitdir);
|
|
|
|
if (file_exists(path.buf)) {
|
|
|
|
if (strbuf_read_file(&data, path.buf, 0) <= 0)
|
|
|
|
die_errno(_("failed to read %s"), path.buf);
|
|
|
|
while (data.len && (data.buf[data.len - 1] == '\n' ||
|
|
|
|
data.buf[data.len - 1] == '\r'))
|
|
|
|
data.len--;
|
|
|
|
data.buf[data.len] = '\0';
|
|
|
|
strbuf_reset(&path);
|
|
|
|
if (!is_absolute_path(data.buf))
|
|
|
|
strbuf_addf(&path, "%s/", gitdir);
|
|
|
|
strbuf_addbuf(&path, &data);
|
2017-02-26 00:00:33 +08:00
|
|
|
strbuf_add_real_path(sb, path.buf);
|
2014-11-30 16:24:44 +08:00
|
|
|
ret = 1;
|
2016-12-13 02:16:55 +08:00
|
|
|
} else {
|
2014-11-30 16:24:41 +08:00
|
|
|
strbuf_addstr(sb, gitdir);
|
2016-12-13 02:16:55 +08:00
|
|
|
}
|
|
|
|
|
2014-11-30 16:24:41 +08:00
|
|
|
strbuf_release(&data);
|
|
|
|
strbuf_release(&path);
|
2014-11-30 16:24:44 +08:00
|
|
|
return ret;
|
2014-11-30 16:24:41 +08:00
|
|
|
}
|
2005-08-17 09:06:34 +08:00
|
|
|
|
[PATCH] Make .git directory validation code test HEAD
Inspired by a report by Kalle Valo, this changes git-sh-setup-script and
the "setup_git_directory()" function to test that $GIT_DIR/HEAD is a
symlink, since a number of core git features depend on that these days.
We used to allow a regular file there, but git-fsck-cache has been
complaining about that for a while, and anything that uses branches
depends on the HEAD file being a symlink, so let's just encode that as a
fundamental requirement.
Before, a non-symlink HEAD file would appear to work, but have subtle bugs
like not having the HEAD show up as a valid reference (because it wasn't
under "refs"). Now, we will complain loudly, and the user can fix it up
trivially instead of getting strange behaviour.
This also removes the tests for "$GIT_DIR" and "$GIT_OBJECT_DIRECTORY"
being directories, since the other tests will implicitly test for that
anyway (ie the tests for HEAD, refs and 00 would fail).
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-08-28 04:54:42 +08:00
|
|
|
/*
|
2006-12-31 12:30:19 +08:00
|
|
|
* Test if it looks like we're at a git directory.
|
2005-11-26 07:43:41 +08:00
|
|
|
* We want to see:
|
[PATCH] Make .git directory validation code test HEAD
Inspired by a report by Kalle Valo, this changes git-sh-setup-script and
the "setup_git_directory()" function to test that $GIT_DIR/HEAD is a
symlink, since a number of core git features depend on that these days.
We used to allow a regular file there, but git-fsck-cache has been
complaining about that for a while, and anything that uses branches
depends on the HEAD file being a symlink, so let's just encode that as a
fundamental requirement.
Before, a non-symlink HEAD file would appear to work, but have subtle bugs
like not having the HEAD show up as a valid reference (because it wasn't
under "refs"). Now, we will complain loudly, and the user can fix it up
trivially instead of getting strange behaviour.
This also removes the tests for "$GIT_DIR" and "$GIT_OBJECT_DIRECTORY"
being directories, since the other tests will implicitly test for that
anyway (ie the tests for HEAD, refs and 00 would fail).
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-08-28 04:54:42 +08:00
|
|
|
*
|
2008-01-03 22:18:07 +08:00
|
|
|
* - either an objects/ directory _or_ the proper
|
[PATCH] Make .git directory validation code test HEAD
Inspired by a report by Kalle Valo, this changes git-sh-setup-script and
the "setup_git_directory()" function to test that $GIT_DIR/HEAD is a
symlink, since a number of core git features depend on that these days.
We used to allow a regular file there, but git-fsck-cache has been
complaining about that for a while, and anything that uses branches
depends on the HEAD file being a symlink, so let's just encode that as a
fundamental requirement.
Before, a non-symlink HEAD file would appear to work, but have subtle bugs
like not having the HEAD show up as a valid reference (because it wasn't
under "refs"). Now, we will complain loudly, and the user can fix it up
trivially instead of getting strange behaviour.
This also removes the tests for "$GIT_DIR" and "$GIT_OBJECT_DIRECTORY"
being directories, since the other tests will implicitly test for that
anyway (ie the tests for HEAD, refs and 00 would fail).
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-08-28 04:54:42 +08:00
|
|
|
* GIT_OBJECT_DIRECTORY environment variable
|
2006-12-31 12:30:19 +08:00
|
|
|
* - a refs/ directory
|
2005-10-01 05:26:57 +08:00
|
|
|
* - either a HEAD symlink or a HEAD file that is formatted as
|
2007-01-02 15:31:08 +08:00
|
|
|
* a proper "ref:", or a regular file HEAD that has a properly
|
|
|
|
* formatted sha1 object name.
|
[PATCH] Make .git directory validation code test HEAD
Inspired by a report by Kalle Valo, this changes git-sh-setup-script and
the "setup_git_directory()" function to test that $GIT_DIR/HEAD is a
symlink, since a number of core git features depend on that these days.
We used to allow a regular file there, but git-fsck-cache has been
complaining about that for a while, and anything that uses branches
depends on the HEAD file being a symlink, so let's just encode that as a
fundamental requirement.
Before, a non-symlink HEAD file would appear to work, but have subtle bugs
like not having the HEAD show up as a valid reference (because it wasn't
under "refs"). Now, we will complain loudly, and the user can fix it up
trivially instead of getting strange behaviour.
This also removes the tests for "$GIT_DIR" and "$GIT_OBJECT_DIRECTORY"
being directories, since the other tests will implicitly test for that
anyway (ie the tests for HEAD, refs and 00 would fail).
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-08-28 04:54:42 +08:00
|
|
|
*/
|
standardize and improve lookup rules for external local repos
When you specify a local repository on the command line of
clone, ls-remote, upload-pack, receive-pack, or upload-archive,
or in a request to git-daemon, we perform a little bit of
lookup magic, doing things like looking in working trees for
.git directories and appending ".git" for bare repos.
For clone, this magic happens in get_repo_path. For
everything else, it happens in enter_repo. In both cases,
there are some ambiguous or confusing cases that aren't
handled well, and there is one case that is not handled the
same by both methods.
This patch tries to provide (and test!) standard, sensible
lookup rules for both code paths. The intended changes are:
1. When looking up "foo", we have always preferred
a working tree "foo" (containing "foo/.git" over the
bare "foo.git". But we did not prefer a bare "foo" over
"foo.git". With this patch, we do so.
2. We would select directories that existed but didn't
actually look like git repositories. With this patch,
we make sure a selected directory looks like a git
repo. Not only is this more sensible in general, but it
will help anybody who is negatively affected by change
(1) negatively (e.g., if they had "foo.git" next to its
separate work tree "foo", and expect to keep finding
"foo.git" when they reference "foo").
3. The enter_repo code path would, given "foo", look for
"foo.git/.git" (i.e., do the ".git" append magic even
for a repo with working tree). The clone code path did
not; with this patch, they now behave the same.
In the unlikely case of a working tree overlaying a bare
repo (i.e., a ".git" directory _inside_ a bare repo), we
continue to treat it as a working tree (prefering the
"inner" .git over the bare repo). This is mainly because the
combination seems nonsensical, and I'd rather stick with
existing behavior on the off chance that somebody is relying
on it.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-02-03 05:59:13 +08:00
|
|
|
int is_git_directory(const char *suspect)
|
[PATCH] Make .git directory validation code test HEAD
Inspired by a report by Kalle Valo, this changes git-sh-setup-script and
the "setup_git_directory()" function to test that $GIT_DIR/HEAD is a
symlink, since a number of core git features depend on that these days.
We used to allow a regular file there, but git-fsck-cache has been
complaining about that for a while, and anything that uses branches
depends on the HEAD file being a symlink, so let's just encode that as a
fundamental requirement.
Before, a non-symlink HEAD file would appear to work, but have subtle bugs
like not having the HEAD show up as a valid reference (because it wasn't
under "refs"). Now, we will complain loudly, and the user can fix it up
trivially instead of getting strange behaviour.
This also removes the tests for "$GIT_DIR" and "$GIT_OBJECT_DIRECTORY"
being directories, since the other tests will implicitly test for that
anyway (ie the tests for HEAD, refs and 00 would fail).
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-08-28 04:54:42 +08:00
|
|
|
{
|
2014-11-30 16:24:40 +08:00
|
|
|
struct strbuf path = STRBUF_INIT;
|
|
|
|
int ret = 0;
|
|
|
|
size_t len;
|
2006-12-31 12:30:19 +08:00
|
|
|
|
2014-11-30 16:24:41 +08:00
|
|
|
/* Check worktree-related signatures */
|
|
|
|
strbuf_addf(&path, "%s/HEAD", suspect);
|
|
|
|
if (validate_headref(path.buf))
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
strbuf_reset(&path);
|
|
|
|
get_common_dir(&path, suspect);
|
2014-11-30 16:24:40 +08:00
|
|
|
len = path.len;
|
2014-11-30 16:24:41 +08:00
|
|
|
|
|
|
|
/* Check non-worktree-related signatures */
|
2006-12-31 12:30:19 +08:00
|
|
|
if (getenv(DB_ENVIRONMENT)) {
|
|
|
|
if (access(getenv(DB_ENVIRONMENT), X_OK))
|
2014-11-30 16:24:40 +08:00
|
|
|
goto done;
|
2006-12-31 12:30:19 +08:00
|
|
|
}
|
|
|
|
else {
|
2014-11-30 16:24:41 +08:00
|
|
|
strbuf_setlen(&path, len);
|
2014-11-30 16:24:40 +08:00
|
|
|
strbuf_addstr(&path, "/objects");
|
|
|
|
if (access(path.buf, X_OK))
|
|
|
|
goto done;
|
2006-12-31 12:30:19 +08:00
|
|
|
}
|
|
|
|
|
2014-11-30 16:24:40 +08:00
|
|
|
strbuf_setlen(&path, len);
|
|
|
|
strbuf_addstr(&path, "/refs");
|
|
|
|
if (access(path.buf, X_OK))
|
|
|
|
goto done;
|
2006-12-31 12:30:19 +08:00
|
|
|
|
2014-11-30 16:24:40 +08:00
|
|
|
ret = 1;
|
|
|
|
done:
|
|
|
|
strbuf_release(&path);
|
|
|
|
return ret;
|
[PATCH] Make .git directory validation code test HEAD
Inspired by a report by Kalle Valo, this changes git-sh-setup-script and
the "setup_git_directory()" function to test that $GIT_DIR/HEAD is a
symlink, since a number of core git features depend on that these days.
We used to allow a regular file there, but git-fsck-cache has been
complaining about that for a while, and anything that uses branches
depends on the HEAD file being a symlink, so let's just encode that as a
fundamental requirement.
Before, a non-symlink HEAD file would appear to work, but have subtle bugs
like not having the HEAD show up as a valid reference (because it wasn't
under "refs"). Now, we will complain loudly, and the user can fix it up
trivially instead of getting strange behaviour.
This also removes the tests for "$GIT_DIR" and "$GIT_OBJECT_DIRECTORY"
being directories, since the other tests will implicitly test for that
anyway (ie the tests for HEAD, refs and 00 would fail).
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-08-28 04:54:42 +08:00
|
|
|
}
|
|
|
|
|
2016-01-23 06:27:33 +08:00
|
|
|
int is_nonbare_repository_dir(struct strbuf *path)
|
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
int gitfile_error;
|
|
|
|
size_t orig_path_len = path->len;
|
|
|
|
assert(orig_path_len != 0);
|
|
|
|
strbuf_complete(path, '/');
|
|
|
|
strbuf_addstr(path, ".git");
|
|
|
|
if (read_gitfile_gently(path->buf, &gitfile_error) || is_git_directory(path->buf))
|
|
|
|
ret = 1;
|
|
|
|
if (gitfile_error == READ_GITFILE_ERR_OPEN_FAILED ||
|
|
|
|
gitfile_error == READ_GITFILE_ERR_READ_FAILED)
|
|
|
|
ret = 1;
|
|
|
|
strbuf_setlen(path, orig_path_len);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2007-01-20 10:09:34 +08:00
|
|
|
int is_inside_git_dir(void)
|
|
|
|
{
|
Clean up work-tree handling
The old version of work-tree support was an unholy mess, barely readable,
and not to the point.
For example, why do you have to provide a worktree, when it is not used?
As in "git status". Now it works.
Another riddle was: if you can have work trees inside the git dir, why
are some programs complaining that they need a work tree?
IOW it is allowed to call
$ git --git-dir=../ --work-tree=. bla
when you really want to. In this case, you are both in the git directory
and in the working tree. So, programs have to actually test for the right
thing, namely if they are inside a working tree, and not if they are
inside a git directory.
Also, GIT_DIR=../.git should behave the same as if no GIT_DIR was
specified, unless there is a repository in the current working directory.
It does now.
The logic to determine if a repository is bare, or has a work tree
(tertium non datur), is this:
--work-tree=bla overrides GIT_WORK_TREE, which overrides core.bare = true,
which overrides core.worktree, which overrides GIT_DIR/.. when GIT_DIR
ends in /.git, which overrides the directory in which .git/ was found.
In related news, a long standing bug was fixed: when in .git/bla/x.git/,
which is a bare repository, git formerly assumed ../.. to be the
appropriate git dir. This problem was reported by Shawn Pearce to have
caused much pain, where a colleague mistakenly ran "git init" in "/" a
long time ago, and bare repositories just would not work.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-08-01 08:30:14 +08:00
|
|
|
if (inside_git_dir < 0)
|
|
|
|
inside_git_dir = is_inside_dir(get_git_dir());
|
|
|
|
return inside_git_dir;
|
2007-06-06 15:10:42 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
int is_inside_work_tree(void)
|
|
|
|
{
|
Clean up work-tree handling
The old version of work-tree support was an unholy mess, barely readable,
and not to the point.
For example, why do you have to provide a worktree, when it is not used?
As in "git status". Now it works.
Another riddle was: if you can have work trees inside the git dir, why
are some programs complaining that they need a work tree?
IOW it is allowed to call
$ git --git-dir=../ --work-tree=. bla
when you really want to. In this case, you are both in the git directory
and in the working tree. So, programs have to actually test for the right
thing, namely if they are inside a working tree, and not if they are
inside a git directory.
Also, GIT_DIR=../.git should behave the same as if no GIT_DIR was
specified, unless there is a repository in the current working directory.
It does now.
The logic to determine if a repository is bare, or has a work tree
(tertium non datur), is this:
--work-tree=bla overrides GIT_WORK_TREE, which overrides core.bare = true,
which overrides core.worktree, which overrides GIT_DIR/.. when GIT_DIR
ends in /.git, which overrides the directory in which .git/ was found.
In related news, a long standing bug was fixed: when in .git/bla/x.git/,
which is a bare repository, git formerly assumed ../.. to be the
appropriate git dir. This problem was reported by Shawn Pearce to have
caused much pain, where a colleague mistakenly ran "git init" in "/" a
long time ago, and bare repositories just would not work.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-08-01 08:30:14 +08:00
|
|
|
if (inside_work_tree < 0)
|
|
|
|
inside_work_tree = is_inside_dir(get_git_work_tree());
|
|
|
|
return inside_work_tree;
|
2007-06-06 15:10:42 +08:00
|
|
|
}
|
|
|
|
|
2007-11-09 07:35:32 +08:00
|
|
|
void setup_work_tree(void)
|
|
|
|
{
|
2007-11-09 19:34:07 +08:00
|
|
|
const char *work_tree, *git_dir;
|
|
|
|
static int initialized = 0;
|
|
|
|
|
|
|
|
if (initialized)
|
|
|
|
return;
|
setup_git_directory: delay core.bare/core.worktree errors
If both core.bare and core.worktree are set, we complain
about the bogus config and die. Dying is good, because it
avoids commands running and doing damage in a potentially
incorrect setup. But dying _there_ is bad, because it means
that commands which do not even care about the work tree
cannot run. This can make repairing the situation harder:
[setup]
$ git config core.bare true
$ git config core.worktree /some/path
[OK, expected.]
$ git status
fatal: core.bare and core.worktree do not make sense
[Hrm...]
$ git config --unset core.worktree
fatal: core.bare and core.worktree do not make sense
[Nope...]
$ git config --edit
fatal: core.bare and core.worktree do not make sense
[Gaaah.]
$ git help config
fatal: core.bare and core.worktree do not make sense
Instead, let's issue a warning about the bogus config when
we notice it (i.e., for all commands), but only die when the
command tries to use the work tree (by calling setup_work_tree).
So we now get:
$ git status
warning: core.bare and core.worktree do not make sense
fatal: unable to set up work tree using invalid config
$ git config --unset core.worktree
warning: core.bare and core.worktree do not make sense
We have to update t1510 to accomodate this; it uses
symbolic-ref to check whether the configuration works or
not, but of course that command does not use the working
tree. Instead, we switch it to use `git status`, as it
requires a work-tree, does not need any special setup, and
is read-only (so a failure will not adversely affect further
tests).
In addition, we add a new test that checks the desired
behavior (i.e., that running "git config" with the bogus
config does in fact work).
Reported-by: SZEDER Gábor <szeder@ira.uka.de>
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-05-29 14:49:10 +08:00
|
|
|
|
|
|
|
if (work_tree_config_is_bogus)
|
|
|
|
die("unable to set up work tree using invalid config");
|
|
|
|
|
2007-11-09 19:34:07 +08:00
|
|
|
work_tree = get_git_work_tree();
|
|
|
|
git_dir = get_git_dir();
|
2007-11-03 19:23:11 +08:00
|
|
|
if (!is_absolute_path(git_dir))
|
2011-03-17 19:26:46 +08:00
|
|
|
git_dir = real_path(get_git_dir());
|
2007-11-03 19:23:11 +08:00
|
|
|
if (!work_tree || chdir(work_tree))
|
|
|
|
die("This operation must be run in a work tree");
|
2010-12-27 09:26:04 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Make sure subsequent git processes find correct worktree
|
|
|
|
* if $GIT_WORK_TREE is set relative
|
|
|
|
*/
|
|
|
|
if (getenv(GIT_WORK_TREE_ENVIRONMENT))
|
|
|
|
setenv(GIT_WORK_TREE_ENVIRONMENT, ".", 1);
|
|
|
|
|
2013-10-14 10:29:40 +08:00
|
|
|
set_git_dir(remove_leading_path(git_dir, work_tree));
|
2007-11-09 19:34:07 +08:00
|
|
|
initialized = 1;
|
2007-11-03 19:23:11 +08:00
|
|
|
}
|
|
|
|
|
2016-03-12 06:37:07 +08:00
|
|
|
static int check_repo_format(const char *var, const char *value, void *vdata)
|
2014-11-30 16:24:44 +08:00
|
|
|
{
|
2016-03-12 06:37:07 +08:00
|
|
|
struct repository_format *data = vdata;
|
introduce "extensions" form of core.repositoryformatversion
Normally we try to avoid bumps of the whole-repository
core.repositoryformatversion field. However, it is
unavoidable if we want to safely change certain aspects of
git in a backwards-incompatible way (e.g., modifying the set
of ref tips that we must traverse to generate a list of
unreachable, safe-to-prune objects).
If we were to bump the repository version for every such
change, then any implementation understanding version `X`
would also have to understand `X-1`, `X-2`, and so forth,
even though the incompatibilities may be in orthogonal parts
of the system, and there is otherwise no reason we cannot
implement one without the other (or more importantly, that
the user cannot choose to use one feature without the other,
weighing the tradeoff in compatibility only for that
particular feature).
This patch documents the existing repositoryformatversion
strategy and introduces a new format, "1", which lets a
repository specify that it must run with an arbitrary set of
extensions. This can be used, for example:
- to inform git that the objects should not be pruned based
only on the reachability of the ref tips (e.g, because it
has "clone --shared" children)
- that the refs are stored in a format besides the usual
"refs" and "packed-refs" directories
Because we bump to format "1", and because format "1"
requires that a running git knows about any extensions
mentioned, we know that older versions of the code will not
do something dangerous when confronted with these new
formats.
For example, if the user chooses to use database storage for
refs, they may set the "extensions.refbackend" config to
"db". Older versions of git will not understand format "1"
and bail. Versions of git which understand "1" but do not
know about "refbackend", or which know about "refbackend"
but not about the "db" backend, will refuse to run. This is
annoying, of course, but much better than the alternative of
claiming that there are no refs in the repository, or
writing to a location that other implementations will not
read.
Note that we are only defining the rules for format 1 here.
We do not ever write format 1 ourselves; it is a tool that
is meant to be used by users and future extensions to
provide safety with older implementations.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-06-23 18:53:58 +08:00
|
|
|
const char *ext;
|
|
|
|
|
2014-11-30 16:24:44 +08:00
|
|
|
if (strcmp(var, "core.repositoryformatversion") == 0)
|
2016-03-12 06:37:07 +08:00
|
|
|
data->version = git_config_int(var, value);
|
introduce "extensions" form of core.repositoryformatversion
Normally we try to avoid bumps of the whole-repository
core.repositoryformatversion field. However, it is
unavoidable if we want to safely change certain aspects of
git in a backwards-incompatible way (e.g., modifying the set
of ref tips that we must traverse to generate a list of
unreachable, safe-to-prune objects).
If we were to bump the repository version for every such
change, then any implementation understanding version `X`
would also have to understand `X-1`, `X-2`, and so forth,
even though the incompatibilities may be in orthogonal parts
of the system, and there is otherwise no reason we cannot
implement one without the other (or more importantly, that
the user cannot choose to use one feature without the other,
weighing the tradeoff in compatibility only for that
particular feature).
This patch documents the existing repositoryformatversion
strategy and introduces a new format, "1", which lets a
repository specify that it must run with an arbitrary set of
extensions. This can be used, for example:
- to inform git that the objects should not be pruned based
only on the reachability of the ref tips (e.g, because it
has "clone --shared" children)
- that the refs are stored in a format besides the usual
"refs" and "packed-refs" directories
Because we bump to format "1", and because format "1"
requires that a running git knows about any extensions
mentioned, we know that older versions of the code will not
do something dangerous when confronted with these new
formats.
For example, if the user chooses to use database storage for
refs, they may set the "extensions.refbackend" config to
"db". Older versions of git will not understand format "1"
and bail. Versions of git which understand "1" but do not
know about "refbackend", or which know about "refbackend"
but not about the "db" backend, will refuse to run. This is
annoying, of course, but much better than the alternative of
claiming that there are no refs in the repository, or
writing to a location that other implementations will not
read.
Note that we are only defining the rules for format 1 here.
We do not ever write format 1 ourselves; it is a tool that
is meant to be used by users and future extensions to
provide safety with older implementations.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-06-23 18:53:58 +08:00
|
|
|
else if (skip_prefix(var, "extensions.", &ext)) {
|
|
|
|
/*
|
|
|
|
* record any known extensions here; otherwise,
|
|
|
|
* we fall through to recording it as unknown, and
|
|
|
|
* check_repository_format will complain
|
|
|
|
*/
|
|
|
|
if (!strcmp(ext, "noop"))
|
|
|
|
;
|
2015-06-23 18:54:11 +08:00
|
|
|
else if (!strcmp(ext, "preciousobjects"))
|
2016-03-12 06:37:07 +08:00
|
|
|
data->precious_objects = git_config_bool(var, value);
|
introduce "extensions" form of core.repositoryformatversion
Normally we try to avoid bumps of the whole-repository
core.repositoryformatversion field. However, it is
unavoidable if we want to safely change certain aspects of
git in a backwards-incompatible way (e.g., modifying the set
of ref tips that we must traverse to generate a list of
unreachable, safe-to-prune objects).
If we were to bump the repository version for every such
change, then any implementation understanding version `X`
would also have to understand `X-1`, `X-2`, and so forth,
even though the incompatibilities may be in orthogonal parts
of the system, and there is otherwise no reason we cannot
implement one without the other (or more importantly, that
the user cannot choose to use one feature without the other,
weighing the tradeoff in compatibility only for that
particular feature).
This patch documents the existing repositoryformatversion
strategy and introduces a new format, "1", which lets a
repository specify that it must run with an arbitrary set of
extensions. This can be used, for example:
- to inform git that the objects should not be pruned based
only on the reachability of the ref tips (e.g, because it
has "clone --shared" children)
- that the refs are stored in a format besides the usual
"refs" and "packed-refs" directories
Because we bump to format "1", and because format "1"
requires that a running git knows about any extensions
mentioned, we know that older versions of the code will not
do something dangerous when confronted with these new
formats.
For example, if the user chooses to use database storage for
refs, they may set the "extensions.refbackend" config to
"db". Older versions of git will not understand format "1"
and bail. Versions of git which understand "1" but do not
know about "refbackend", or which know about "refbackend"
but not about the "db" backend, will refuse to run. This is
annoying, of course, but much better than the alternative of
claiming that there are no refs in the repository, or
writing to a location that other implementations will not
read.
Note that we are only defining the rules for format 1 here.
We do not ever write format 1 ourselves; it is a tool that
is meant to be used by users and future extensions to
provide safety with older implementations.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-06-23 18:53:58 +08:00
|
|
|
else
|
2016-03-12 06:37:07 +08:00
|
|
|
string_list_append(&data->unknown_extensions, ext);
|
2016-03-12 06:37:14 +08:00
|
|
|
} else if (strcmp(var, "core.bare") == 0) {
|
|
|
|
data->is_bare = git_config_bool(var, value);
|
|
|
|
} else if (strcmp(var, "core.worktree") == 0) {
|
|
|
|
if (!value)
|
|
|
|
return config_error_nonbool(var);
|
|
|
|
data->work_tree = xstrdup(value);
|
introduce "extensions" form of core.repositoryformatversion
Normally we try to avoid bumps of the whole-repository
core.repositoryformatversion field. However, it is
unavoidable if we want to safely change certain aspects of
git in a backwards-incompatible way (e.g., modifying the set
of ref tips that we must traverse to generate a list of
unreachable, safe-to-prune objects).
If we were to bump the repository version for every such
change, then any implementation understanding version `X`
would also have to understand `X-1`, `X-2`, and so forth,
even though the incompatibilities may be in orthogonal parts
of the system, and there is otherwise no reason we cannot
implement one without the other (or more importantly, that
the user cannot choose to use one feature without the other,
weighing the tradeoff in compatibility only for that
particular feature).
This patch documents the existing repositoryformatversion
strategy and introduces a new format, "1", which lets a
repository specify that it must run with an arbitrary set of
extensions. This can be used, for example:
- to inform git that the objects should not be pruned based
only on the reachability of the ref tips (e.g, because it
has "clone --shared" children)
- that the refs are stored in a format besides the usual
"refs" and "packed-refs" directories
Because we bump to format "1", and because format "1"
requires that a running git knows about any extensions
mentioned, we know that older versions of the code will not
do something dangerous when confronted with these new
formats.
For example, if the user chooses to use database storage for
refs, they may set the "extensions.refbackend" config to
"db". Older versions of git will not understand format "1"
and bail. Versions of git which understand "1" but do not
know about "refbackend", or which know about "refbackend"
but not about the "db" backend, will refuse to run. This is
annoying, of course, but much better than the alternative of
claiming that there are no refs in the repository, or
writing to a location that other implementations will not
read.
Note that we are only defining the rules for format 1 here.
We do not ever write format 1 ourselves; it is a tool that
is meant to be used by users and future extensions to
provide safety with older implementations.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-06-23 18:53:58 +08:00
|
|
|
}
|
2014-11-30 16:24:44 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-11-26 23:32:34 +08:00
|
|
|
static int check_repository_format_gently(const char *gitdir, int *nongit_ok)
|
2007-12-05 21:33:32 +08:00
|
|
|
{
|
2014-11-30 16:24:42 +08:00
|
|
|
struct strbuf sb = STRBUF_INIT;
|
2016-03-12 06:37:07 +08:00
|
|
|
struct strbuf err = STRBUF_INIT;
|
|
|
|
struct repository_format candidate;
|
2016-03-12 06:37:14 +08:00
|
|
|
int has_common;
|
introduce "extensions" form of core.repositoryformatversion
Normally we try to avoid bumps of the whole-repository
core.repositoryformatversion field. However, it is
unavoidable if we want to safely change certain aspects of
git in a backwards-incompatible way (e.g., modifying the set
of ref tips that we must traverse to generate a list of
unreachable, safe-to-prune objects).
If we were to bump the repository version for every such
change, then any implementation understanding version `X`
would also have to understand `X-1`, `X-2`, and so forth,
even though the incompatibilities may be in orthogonal parts
of the system, and there is otherwise no reason we cannot
implement one without the other (or more importantly, that
the user cannot choose to use one feature without the other,
weighing the tradeoff in compatibility only for that
particular feature).
This patch documents the existing repositoryformatversion
strategy and introduces a new format, "1", which lets a
repository specify that it must run with an arbitrary set of
extensions. This can be used, for example:
- to inform git that the objects should not be pruned based
only on the reachability of the ref tips (e.g, because it
has "clone --shared" children)
- that the refs are stored in a format besides the usual
"refs" and "packed-refs" directories
Because we bump to format "1", and because format "1"
requires that a running git knows about any extensions
mentioned, we know that older versions of the code will not
do something dangerous when confronted with these new
formats.
For example, if the user chooses to use database storage for
refs, they may set the "extensions.refbackend" config to
"db". Older versions of git will not understand format "1"
and bail. Versions of git which understand "1" but do not
know about "refbackend", or which know about "refbackend"
but not about the "db" backend, will refuse to run. This is
annoying, of course, but much better than the alternative of
claiming that there are no refs in the repository, or
writing to a location that other implementations will not
read.
Note that we are only defining the rules for format 1 here.
We do not ever write format 1 ourselves; it is a tool that
is meant to be used by users and future extensions to
provide safety with older implementations.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-06-23 18:53:58 +08:00
|
|
|
|
2016-03-12 06:37:14 +08:00
|
|
|
has_common = get_common_dir(&sb, gitdir);
|
2014-11-30 16:24:43 +08:00
|
|
|
strbuf_addstr(&sb, "/config");
|
2016-03-12 06:37:14 +08:00
|
|
|
read_repository_format(&candidate, sb.buf);
|
2016-03-12 06:37:07 +08:00
|
|
|
strbuf_release(&sb);
|
2014-11-30 16:24:43 +08:00
|
|
|
|
2010-11-26 23:32:34 +08:00
|
|
|
/*
|
2016-03-12 06:37:07 +08:00
|
|
|
* For historical use of check_repository_format() in git-init,
|
|
|
|
* we treat a missing config as a silent "ok", even when nongit_ok
|
|
|
|
* is unset.
|
2010-11-26 23:32:34 +08:00
|
|
|
*/
|
2016-03-12 06:37:07 +08:00
|
|
|
if (candidate.version < 0)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (verify_repository_format(&candidate, &err) < 0) {
|
|
|
|
if (nongit_ok) {
|
|
|
|
warning("%s", err.buf);
|
|
|
|
strbuf_release(&err);
|
|
|
|
*nongit_ok = -1;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
die("%s", err.buf);
|
|
|
|
}
|
|
|
|
|
|
|
|
repository_format_precious_objects = candidate.precious_objects;
|
|
|
|
string_list_clear(&candidate.unknown_extensions, 0);
|
2016-03-12 06:37:14 +08:00
|
|
|
if (!has_common) {
|
|
|
|
if (candidate.is_bare != -1) {
|
|
|
|
is_bare_repository_cfg = candidate.is_bare;
|
|
|
|
if (is_bare_repository_cfg == 1)
|
|
|
|
inside_work_tree = -1;
|
|
|
|
}
|
|
|
|
if (candidate.work_tree) {
|
|
|
|
free(git_work_tree_cfg);
|
|
|
|
git_work_tree_cfg = candidate.work_tree;
|
2016-03-12 06:37:07 +08:00
|
|
|
inside_work_tree = -1;
|
2016-03-12 06:37:14 +08:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
free(candidate.work_tree);
|
2016-03-12 06:37:07 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-03-12 06:37:14 +08:00
|
|
|
int read_repository_format(struct repository_format *format, const char *path)
|
2016-03-12 06:37:07 +08:00
|
|
|
{
|
|
|
|
memset(format, 0, sizeof(*format));
|
|
|
|
format->version = -1;
|
|
|
|
format->is_bare = -1;
|
|
|
|
string_list_init(&format->unknown_extensions, 1);
|
2016-03-12 06:37:14 +08:00
|
|
|
git_config_from_file(check_repo_format, path, format);
|
2016-03-12 06:37:07 +08:00
|
|
|
return format->version;
|
|
|
|
}
|
|
|
|
|
|
|
|
int verify_repository_format(const struct repository_format *format,
|
|
|
|
struct strbuf *err)
|
|
|
|
{
|
|
|
|
if (GIT_REPO_VERSION_READ < format->version) {
|
2016-03-12 06:37:22 +08:00
|
|
|
strbuf_addf(err, _("Expected git repo version <= %d, found %d"),
|
2016-03-12 06:37:07 +08:00
|
|
|
GIT_REPO_VERSION_READ, format->version);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (format->version >= 1 && format->unknown_extensions.nr) {
|
introduce "extensions" form of core.repositoryformatversion
Normally we try to avoid bumps of the whole-repository
core.repositoryformatversion field. However, it is
unavoidable if we want to safely change certain aspects of
git in a backwards-incompatible way (e.g., modifying the set
of ref tips that we must traverse to generate a list of
unreachable, safe-to-prune objects).
If we were to bump the repository version for every such
change, then any implementation understanding version `X`
would also have to understand `X-1`, `X-2`, and so forth,
even though the incompatibilities may be in orthogonal parts
of the system, and there is otherwise no reason we cannot
implement one without the other (or more importantly, that
the user cannot choose to use one feature without the other,
weighing the tradeoff in compatibility only for that
particular feature).
This patch documents the existing repositoryformatversion
strategy and introduces a new format, "1", which lets a
repository specify that it must run with an arbitrary set of
extensions. This can be used, for example:
- to inform git that the objects should not be pruned based
only on the reachability of the ref tips (e.g, because it
has "clone --shared" children)
- that the refs are stored in a format besides the usual
"refs" and "packed-refs" directories
Because we bump to format "1", and because format "1"
requires that a running git knows about any extensions
mentioned, we know that older versions of the code will not
do something dangerous when confronted with these new
formats.
For example, if the user chooses to use database storage for
refs, they may set the "extensions.refbackend" config to
"db". Older versions of git will not understand format "1"
and bail. Versions of git which understand "1" but do not
know about "refbackend", or which know about "refbackend"
but not about the "db" backend, will refuse to run. This is
annoying, of course, but much better than the alternative of
claiming that there are no refs in the repository, or
writing to a location that other implementations will not
read.
Note that we are only defining the rules for format 1 here.
We do not ever write format 1 ourselves; it is a tool that
is meant to be used by users and future extensions to
provide safety with older implementations.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-06-23 18:53:58 +08:00
|
|
|
int i;
|
|
|
|
|
2016-03-12 06:37:22 +08:00
|
|
|
strbuf_addstr(err, _("unknown repository extensions found:"));
|
introduce "extensions" form of core.repositoryformatversion
Normally we try to avoid bumps of the whole-repository
core.repositoryformatversion field. However, it is
unavoidable if we want to safely change certain aspects of
git in a backwards-incompatible way (e.g., modifying the set
of ref tips that we must traverse to generate a list of
unreachable, safe-to-prune objects).
If we were to bump the repository version for every such
change, then any implementation understanding version `X`
would also have to understand `X-1`, `X-2`, and so forth,
even though the incompatibilities may be in orthogonal parts
of the system, and there is otherwise no reason we cannot
implement one without the other (or more importantly, that
the user cannot choose to use one feature without the other,
weighing the tradeoff in compatibility only for that
particular feature).
This patch documents the existing repositoryformatversion
strategy and introduces a new format, "1", which lets a
repository specify that it must run with an arbitrary set of
extensions. This can be used, for example:
- to inform git that the objects should not be pruned based
only on the reachability of the ref tips (e.g, because it
has "clone --shared" children)
- that the refs are stored in a format besides the usual
"refs" and "packed-refs" directories
Because we bump to format "1", and because format "1"
requires that a running git knows about any extensions
mentioned, we know that older versions of the code will not
do something dangerous when confronted with these new
formats.
For example, if the user chooses to use database storage for
refs, they may set the "extensions.refbackend" config to
"db". Older versions of git will not understand format "1"
and bail. Versions of git which understand "1" but do not
know about "refbackend", or which know about "refbackend"
but not about the "db" backend, will refuse to run. This is
annoying, of course, but much better than the alternative of
claiming that there are no refs in the repository, or
writing to a location that other implementations will not
read.
Note that we are only defining the rules for format 1 here.
We do not ever write format 1 ourselves; it is a tool that
is meant to be used by users and future extensions to
provide safety with older implementations.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-06-23 18:53:58 +08:00
|
|
|
|
2016-03-12 06:37:07 +08:00
|
|
|
for (i = 0; i < format->unknown_extensions.nr; i++)
|
|
|
|
strbuf_addf(err, "\n\t%s",
|
|
|
|
format->unknown_extensions.items[i].string);
|
|
|
|
return -1;
|
introduce "extensions" form of core.repositoryformatversion
Normally we try to avoid bumps of the whole-repository
core.repositoryformatversion field. However, it is
unavoidable if we want to safely change certain aspects of
git in a backwards-incompatible way (e.g., modifying the set
of ref tips that we must traverse to generate a list of
unreachable, safe-to-prune objects).
If we were to bump the repository version for every such
change, then any implementation understanding version `X`
would also have to understand `X-1`, `X-2`, and so forth,
even though the incompatibilities may be in orthogonal parts
of the system, and there is otherwise no reason we cannot
implement one without the other (or more importantly, that
the user cannot choose to use one feature without the other,
weighing the tradeoff in compatibility only for that
particular feature).
This patch documents the existing repositoryformatversion
strategy and introduces a new format, "1", which lets a
repository specify that it must run with an arbitrary set of
extensions. This can be used, for example:
- to inform git that the objects should not be pruned based
only on the reachability of the ref tips (e.g, because it
has "clone --shared" children)
- that the refs are stored in a format besides the usual
"refs" and "packed-refs" directories
Because we bump to format "1", and because format "1"
requires that a running git knows about any extensions
mentioned, we know that older versions of the code will not
do something dangerous when confronted with these new
formats.
For example, if the user chooses to use database storage for
refs, they may set the "extensions.refbackend" config to
"db". Older versions of git will not understand format "1"
and bail. Versions of git which understand "1" but do not
know about "refbackend", or which know about "refbackend"
but not about the "db" backend, will refuse to run. This is
annoying, of course, but much better than the alternative of
claiming that there are no refs in the repository, or
writing to a location that other implementations will not
read.
Note that we are only defining the rules for format 1 here.
We do not ever write format 1 ourselves; it is a tool that
is meant to be used by users and future extensions to
provide safety with older implementations.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-06-23 18:53:58 +08:00
|
|
|
}
|
|
|
|
|
2016-03-12 06:37:07 +08:00
|
|
|
return 0;
|
2007-12-05 21:33:32 +08:00
|
|
|
}
|
|
|
|
|
2017-01-25 07:56:50 +08:00
|
|
|
void read_gitfile_error_die(int error_code, const char *path, const char *dir)
|
|
|
|
{
|
|
|
|
switch (error_code) {
|
|
|
|
case READ_GITFILE_ERR_STAT_FAILED:
|
|
|
|
case READ_GITFILE_ERR_NOT_A_FILE:
|
|
|
|
/* non-fatal; follow return path */
|
|
|
|
break;
|
|
|
|
case READ_GITFILE_ERR_OPEN_FAILED:
|
|
|
|
die_errno("Error opening '%s'", path);
|
|
|
|
case READ_GITFILE_ERR_TOO_LARGE:
|
|
|
|
die("Too large to be a .git file: '%s'", path);
|
|
|
|
case READ_GITFILE_ERR_READ_FAILED:
|
|
|
|
die("Error reading %s", path);
|
|
|
|
case READ_GITFILE_ERR_INVALID_FORMAT:
|
|
|
|
die("Invalid gitfile format: %s", path);
|
|
|
|
case READ_GITFILE_ERR_NO_PATH:
|
|
|
|
die("No path in gitfile: %s", path);
|
|
|
|
case READ_GITFILE_ERR_NOT_A_REPO:
|
|
|
|
die("Not a git repository: %s", dir);
|
|
|
|
default:
|
|
|
|
die("BUG: unknown error code");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-02-21 06:13:13 +08:00
|
|
|
/*
|
|
|
|
* Try to read the location of the git directory from the .git file,
|
2017-09-26 19:21:49 +08:00
|
|
|
* return path to git directory if found. The return value comes from
|
|
|
|
* a shared buffer.
|
2015-06-10 02:24:35 +08:00
|
|
|
*
|
|
|
|
* On failure, if return_error_code is not NULL, return_error_code
|
|
|
|
* will be set to an error code and NULL will be returned. If
|
|
|
|
* return_error_code is NULL the function will die instead (for most
|
|
|
|
* cases).
|
2008-02-21 06:13:13 +08:00
|
|
|
*/
|
2015-06-10 02:24:35 +08:00
|
|
|
const char *read_gitfile_gently(const char *path, int *return_error_code)
|
2008-02-21 06:13:13 +08:00
|
|
|
{
|
2015-06-16 03:39:52 +08:00
|
|
|
const int max_file_size = 1 << 20; /* 1MB */
|
2015-06-10 02:24:35 +08:00
|
|
|
int error_code = 0;
|
|
|
|
char *buf = NULL;
|
|
|
|
char *dir = NULL;
|
2010-01-09 11:36:41 +08:00
|
|
|
const char *slash;
|
2008-02-21 06:13:13 +08:00
|
|
|
struct stat st;
|
|
|
|
int fd;
|
2011-05-27 00:28:44 +08:00
|
|
|
ssize_t len;
|
2008-02-21 06:13:13 +08:00
|
|
|
|
2015-06-10 02:24:35 +08:00
|
|
|
if (stat(path, &st)) {
|
2017-03-14 04:12:18 +08:00
|
|
|
/* NEEDSWORK: discern between ENOENT vs other errors */
|
2015-06-10 02:24:35 +08:00
|
|
|
error_code = READ_GITFILE_ERR_STAT_FAILED;
|
|
|
|
goto cleanup_return;
|
|
|
|
}
|
|
|
|
if (!S_ISREG(st.st_mode)) {
|
|
|
|
error_code = READ_GITFILE_ERR_NOT_A_FILE;
|
|
|
|
goto cleanup_return;
|
|
|
|
}
|
2015-06-16 03:39:52 +08:00
|
|
|
if (st.st_size > max_file_size) {
|
|
|
|
error_code = READ_GITFILE_ERR_TOO_LARGE;
|
|
|
|
goto cleanup_return;
|
|
|
|
}
|
2008-02-21 06:13:13 +08:00
|
|
|
fd = open(path, O_RDONLY);
|
2015-06-10 02:24:35 +08:00
|
|
|
if (fd < 0) {
|
|
|
|
error_code = READ_GITFILE_ERR_OPEN_FAILED;
|
|
|
|
goto cleanup_return;
|
|
|
|
}
|
2016-02-23 06:44:28 +08:00
|
|
|
buf = xmallocz(st.st_size);
|
2008-02-21 06:13:13 +08:00
|
|
|
len = read_in_full(fd, buf, st.st_size);
|
|
|
|
close(fd);
|
2015-06-10 02:24:35 +08:00
|
|
|
if (len != st.st_size) {
|
|
|
|
error_code = READ_GITFILE_ERR_READ_FAILED;
|
|
|
|
goto cleanup_return;
|
|
|
|
}
|
|
|
|
if (!starts_with(buf, "gitdir: ")) {
|
|
|
|
error_code = READ_GITFILE_ERR_INVALID_FORMAT;
|
|
|
|
goto cleanup_return;
|
|
|
|
}
|
2008-02-21 06:13:13 +08:00
|
|
|
while (buf[len - 1] == '\n' || buf[len - 1] == '\r')
|
|
|
|
len--;
|
2015-06-10 02:24:35 +08:00
|
|
|
if (len < 9) {
|
|
|
|
error_code = READ_GITFILE_ERR_NO_PATH;
|
|
|
|
goto cleanup_return;
|
|
|
|
}
|
2008-02-21 06:13:13 +08:00
|
|
|
buf[len] = '\0';
|
2010-01-09 11:36:41 +08:00
|
|
|
dir = buf + 8;
|
|
|
|
|
|
|
|
if (!is_absolute_path(dir) && (slash = strrchr(path, '/'))) {
|
|
|
|
size_t pathlen = slash+1 - path;
|
2015-09-25 05:07:03 +08:00
|
|
|
dir = xstrfmt("%.*s%.*s", (int)pathlen, path,
|
|
|
|
(int)(len - 8), buf + 8);
|
2010-01-09 11:36:41 +08:00
|
|
|
free(buf);
|
|
|
|
buf = dir;
|
|
|
|
}
|
2015-06-10 02:24:35 +08:00
|
|
|
if (!is_git_directory(dir)) {
|
|
|
|
error_code = READ_GITFILE_ERR_NOT_A_REPO;
|
|
|
|
goto cleanup_return;
|
|
|
|
}
|
2011-03-17 19:26:46 +08:00
|
|
|
path = real_path(dir);
|
2010-01-09 11:36:41 +08:00
|
|
|
|
2015-06-10 02:24:35 +08:00
|
|
|
cleanup_return:
|
|
|
|
if (return_error_code)
|
|
|
|
*return_error_code = error_code;
|
2017-01-25 07:56:50 +08:00
|
|
|
else if (error_code)
|
|
|
|
read_gitfile_error_die(error_code, path, dir);
|
2015-06-10 02:24:35 +08:00
|
|
|
|
2008-02-21 06:13:13 +08:00
|
|
|
free(buf);
|
2015-06-26 17:03:31 +08:00
|
|
|
return error_code ? NULL : path;
|
2008-02-21 06:13:13 +08:00
|
|
|
}
|
|
|
|
|
2010-07-24 19:19:44 +08:00
|
|
|
static const char *setup_explicit_git_dir(const char *gitdirenv,
|
2014-07-29 02:26:40 +08:00
|
|
|
struct strbuf *cwd,
|
2010-11-26 23:32:39 +08:00
|
|
|
int *nongit_ok)
|
2010-07-24 19:19:44 +08:00
|
|
|
{
|
2010-11-26 23:32:39 +08:00
|
|
|
const char *work_tree_env = getenv(GIT_WORK_TREE_ENVIRONMENT);
|
|
|
|
const char *worktree;
|
|
|
|
char *gitfile;
|
2011-03-26 17:04:24 +08:00
|
|
|
int offset;
|
2010-07-24 19:19:44 +08:00
|
|
|
|
|
|
|
if (PATH_MAX - 40 < strlen(gitdirenv))
|
|
|
|
die("'$%s' too big", GIT_DIR_ENVIRONMENT);
|
2010-11-26 23:32:39 +08:00
|
|
|
|
2011-08-23 05:04:56 +08:00
|
|
|
gitfile = (char*)read_gitfile(gitdirenv);
|
2010-11-26 23:32:39 +08:00
|
|
|
if (gitfile) {
|
|
|
|
gitfile = xstrdup(gitfile);
|
|
|
|
gitdirenv = gitfile;
|
|
|
|
}
|
|
|
|
|
2010-07-24 19:19:44 +08:00
|
|
|
if (!is_git_directory(gitdirenv)) {
|
|
|
|
if (nongit_ok) {
|
|
|
|
*nongit_ok = 1;
|
2010-11-26 23:32:39 +08:00
|
|
|
free(gitfile);
|
2010-07-24 19:19:44 +08:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
die("Not a git repository: '%s'", gitdirenv);
|
|
|
|
}
|
2010-11-26 23:32:39 +08:00
|
|
|
|
|
|
|
if (check_repository_format_gently(gitdirenv, nongit_ok)) {
|
|
|
|
free(gitfile);
|
|
|
|
return NULL;
|
2010-07-24 19:19:44 +08:00
|
|
|
}
|
2010-11-26 23:32:39 +08:00
|
|
|
|
|
|
|
/* #3, #7, #11, #15, #19, #23, #27, #31 (see t1510) */
|
|
|
|
if (work_tree_env)
|
|
|
|
set_git_work_tree(work_tree_env);
|
|
|
|
else if (is_bare_repository_cfg > 0) {
|
setup_git_directory: delay core.bare/core.worktree errors
If both core.bare and core.worktree are set, we complain
about the bogus config and die. Dying is good, because it
avoids commands running and doing damage in a potentially
incorrect setup. But dying _there_ is bad, because it means
that commands which do not even care about the work tree
cannot run. This can make repairing the situation harder:
[setup]
$ git config core.bare true
$ git config core.worktree /some/path
[OK, expected.]
$ git status
fatal: core.bare and core.worktree do not make sense
[Hrm...]
$ git config --unset core.worktree
fatal: core.bare and core.worktree do not make sense
[Nope...]
$ git config --edit
fatal: core.bare and core.worktree do not make sense
[Gaaah.]
$ git help config
fatal: core.bare and core.worktree do not make sense
Instead, let's issue a warning about the bogus config when
we notice it (i.e., for all commands), but only die when the
command tries to use the work tree (by calling setup_work_tree).
So we now get:
$ git status
warning: core.bare and core.worktree do not make sense
fatal: unable to set up work tree using invalid config
$ git config --unset core.worktree
warning: core.bare and core.worktree do not make sense
We have to update t1510 to accomodate this; it uses
symbolic-ref to check whether the configuration works or
not, but of course that command does not use the working
tree. Instead, we switch it to use `git status`, as it
requires a work-tree, does not need any special setup, and
is read-only (so a failure will not adversely affect further
tests).
In addition, we add a new test that checks the desired
behavior (i.e., that running "git config" with the bogus
config does in fact work).
Reported-by: SZEDER Gábor <szeder@ira.uka.de>
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-05-29 14:49:10 +08:00
|
|
|
if (git_work_tree_cfg) {
|
|
|
|
/* #22.2, #30 */
|
|
|
|
warning("core.bare and core.worktree do not make sense");
|
|
|
|
work_tree_config_is_bogus = 1;
|
|
|
|
}
|
2010-11-26 23:32:39 +08:00
|
|
|
|
|
|
|
/* #18, #26 */
|
|
|
|
set_git_dir(gitdirenv);
|
|
|
|
free(gitfile);
|
2010-07-24 19:19:44 +08:00
|
|
|
return NULL;
|
2010-11-26 23:32:39 +08:00
|
|
|
}
|
|
|
|
else if (git_work_tree_cfg) { /* #6, #14 */
|
|
|
|
if (is_absolute_path(git_work_tree_cfg))
|
|
|
|
set_git_work_tree(git_work_tree_cfg);
|
|
|
|
else {
|
2014-07-29 02:30:39 +08:00
|
|
|
char *core_worktree;
|
2010-11-26 23:32:39 +08:00
|
|
|
if (chdir(gitdirenv))
|
|
|
|
die_errno("Could not chdir to '%s'", gitdirenv);
|
|
|
|
if (chdir(git_work_tree_cfg))
|
|
|
|
die_errno("Could not chdir to '%s'", git_work_tree_cfg);
|
2014-07-29 02:30:39 +08:00
|
|
|
core_worktree = xgetcwd();
|
2014-07-29 02:26:40 +08:00
|
|
|
if (chdir(cwd->buf))
|
2010-11-26 23:32:39 +08:00
|
|
|
die_errno("Could not come back to cwd");
|
|
|
|
set_git_work_tree(core_worktree);
|
2014-07-29 02:30:39 +08:00
|
|
|
free(core_worktree);
|
2010-11-26 23:32:39 +08:00
|
|
|
}
|
|
|
|
}
|
setup: suppress implicit "." work-tree for bare repos
If an explicit GIT_DIR is given without a working tree, we
implicitly assume that the current working directory should
be used as the working tree. E.g.,:
GIT_DIR=/some/repo.git git status
would compare against the cwd.
Unfortunately, we fool this rule for sub-invocations of git
by setting GIT_DIR internally ourselves. For example:
git init foo
cd foo/.git
git status ;# fails, as we expect
git config alias.st status
git status ;# does not fail, but should
What happens is that we run setup_git_directory when doing
alias lookup (since we need to see the config), set GIT_DIR
as a result, and then leave GIT_WORK_TREE blank (because we
do not have one). Then when we actually run the status
command, we do setup_git_directory again, which sees our
explicit GIT_DIR and uses the cwd as an implicit worktree.
It's tempting to argue that we should be suppressing that
second invocation of setup_git_directory, as it could use
the values we already found in memory. However, the problem
still exists for sub-processes (e.g., if "git status" were
an external command).
You can see another example with the "--bare" option, which
sets GIT_DIR explicitly. For example:
git init foo
cd foo/.git
git status ;# fails
git --bare status ;# does NOT fail
We need some way of telling sub-processes "even though
GIT_DIR is set, do not use cwd as an implicit working tree".
We could do it by putting a special token into
GIT_WORK_TREE, but the obvious choice (an empty string) has
some portability problems.
Instead, we add a new boolean variable, GIT_IMPLICIT_WORK_TREE,
which suppresses the use of cwd as a working tree when
GIT_DIR is set. We trigger the new variable when we know we
are in a bare setting.
The variable is left intentionally undocumented, as this is
an internal detail (for now, anyway). If somebody comes up
with a good alternate use for it, and once we are confident
we have shaken any bugs out of it, we can consider promoting
it further.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-03-08 17:32:22 +08:00
|
|
|
else if (!git_env_bool(GIT_IMPLICIT_WORK_TREE_ENVIRONMENT, 1)) {
|
|
|
|
/* #16d */
|
|
|
|
set_git_dir(gitdirenv);
|
|
|
|
free(gitfile);
|
|
|
|
return NULL;
|
|
|
|
}
|
2010-11-26 23:32:39 +08:00
|
|
|
else /* #2, #10 */
|
|
|
|
set_git_work_tree(".");
|
|
|
|
|
|
|
|
/* set_git_work_tree() must have been called by now */
|
|
|
|
worktree = get_git_work_tree();
|
|
|
|
|
|
|
|
/* both get_git_work_tree() and cwd are already normalized */
|
2014-07-29 02:26:40 +08:00
|
|
|
if (!strcmp(cwd->buf, worktree)) { /* cwd == worktree */
|
2010-11-26 23:32:39 +08:00
|
|
|
set_git_dir(gitdirenv);
|
|
|
|
free(gitfile);
|
2010-07-24 19:19:44 +08:00
|
|
|
return NULL;
|
2010-11-26 23:32:39 +08:00
|
|
|
}
|
2010-07-24 19:19:44 +08:00
|
|
|
|
2014-07-29 02:26:40 +08:00
|
|
|
offset = dir_inside_of(cwd->buf, worktree);
|
2011-03-26 17:04:24 +08:00
|
|
|
if (offset >= 0) { /* cwd inside worktree? */
|
2011-03-17 19:26:46 +08:00
|
|
|
set_git_dir(real_path(gitdirenv));
|
2010-11-26 23:32:39 +08:00
|
|
|
if (chdir(worktree))
|
|
|
|
die_errno("Could not chdir to '%s'", worktree);
|
2014-07-29 02:26:40 +08:00
|
|
|
strbuf_addch(cwd, '/');
|
2010-11-26 23:32:39 +08:00
|
|
|
free(gitfile);
|
2014-07-29 02:26:40 +08:00
|
|
|
return cwd->buf + offset;
|
2010-07-24 19:20:15 +08:00
|
|
|
}
|
2010-11-26 23:32:39 +08:00
|
|
|
|
|
|
|
/* cwd outside worktree */
|
|
|
|
set_git_dir(gitdirenv);
|
|
|
|
free(gitfile);
|
|
|
|
return NULL;
|
2010-07-24 19:20:15 +08:00
|
|
|
}
|
|
|
|
|
2010-11-26 23:32:38 +08:00
|
|
|
static const char *setup_discovered_git_dir(const char *gitdir,
|
2014-07-29 02:26:40 +08:00
|
|
|
struct strbuf *cwd, int offset,
|
2010-11-26 23:32:38 +08:00
|
|
|
int *nongit_ok)
|
2010-07-24 20:11:58 +08:00
|
|
|
{
|
2010-11-26 23:32:38 +08:00
|
|
|
if (check_repository_format_gently(gitdir, nongit_ok))
|
|
|
|
return NULL;
|
2010-07-24 20:11:58 +08:00
|
|
|
|
2011-01-19 20:42:30 +08:00
|
|
|
/* --work-tree is set without --git-dir; use discovered one */
|
|
|
|
if (getenv(GIT_WORK_TREE_ENVIRONMENT) || git_work_tree_cfg) {
|
2017-05-04 21:56:51 +08:00
|
|
|
char *to_free = NULL;
|
|
|
|
const char *ret;
|
|
|
|
|
2014-07-29 02:26:40 +08:00
|
|
|
if (offset != cwd->len && !is_absolute_path(gitdir))
|
2017-05-04 21:56:51 +08:00
|
|
|
gitdir = to_free = real_pathdup(gitdir, 1);
|
2014-07-29 02:26:40 +08:00
|
|
|
if (chdir(cwd->buf))
|
2011-01-19 20:42:30 +08:00
|
|
|
die_errno("Could not come back to cwd");
|
2017-05-04 21:56:51 +08:00
|
|
|
ret = setup_explicit_git_dir(gitdir, cwd, nongit_ok);
|
|
|
|
free(to_free);
|
|
|
|
return ret;
|
2011-01-19 20:42:30 +08:00
|
|
|
}
|
|
|
|
|
2010-11-26 23:32:38 +08:00
|
|
|
/* #16.2, #17.2, #20.2, #21.2, #24, #25, #28, #29 (see t1510) */
|
|
|
|
if (is_bare_repository_cfg > 0) {
|
2014-07-29 02:26:40 +08:00
|
|
|
set_git_dir(offset == cwd->len ? gitdir : real_path(gitdir));
|
|
|
|
if (chdir(cwd->buf))
|
2010-11-26 23:32:38 +08:00
|
|
|
die_errno("Could not come back to cwd");
|
2010-07-24 20:11:58 +08:00
|
|
|
return NULL;
|
2010-11-26 23:32:38 +08:00
|
|
|
}
|
2010-07-24 20:11:58 +08:00
|
|
|
|
2010-11-26 23:32:38 +08:00
|
|
|
/* #0, #1, #5, #8, #9, #12, #13 */
|
|
|
|
set_git_work_tree(".");
|
|
|
|
if (strcmp(gitdir, DEFAULT_GIT_DIR_ENVIRONMENT))
|
|
|
|
set_git_dir(gitdir);
|
2010-07-24 20:11:58 +08:00
|
|
|
inside_git_dir = 0;
|
2010-11-26 23:32:38 +08:00
|
|
|
inside_work_tree = 1;
|
2014-07-29 02:26:40 +08:00
|
|
|
if (offset == cwd->len)
|
2010-07-24 20:11:58 +08:00
|
|
|
return NULL;
|
|
|
|
|
2017-03-14 04:09:44 +08:00
|
|
|
/* Make "offset" point past the '/' (already the case for root dirs) */
|
|
|
|
if (offset != offset_1st_component(cwd->buf))
|
|
|
|
offset++;
|
|
|
|
/* Add a '/' at the end */
|
2014-07-29 02:26:40 +08:00
|
|
|
strbuf_addch(cwd, '/');
|
|
|
|
return cwd->buf + offset;
|
2010-07-24 20:11:58 +08:00
|
|
|
}
|
|
|
|
|
2010-11-26 23:32:36 +08:00
|
|
|
/* #16.1, #17.1, #20.1, #21.1, #22.1 (see t1510) */
|
2014-07-29 02:26:40 +08:00
|
|
|
static const char *setup_bare_git_dir(struct strbuf *cwd, int offset,
|
|
|
|
int *nongit_ok)
|
2010-07-24 19:25:32 +08:00
|
|
|
{
|
|
|
|
int root_len;
|
|
|
|
|
2010-11-26 23:32:36 +08:00
|
|
|
if (check_repository_format_gently(".", nongit_ok))
|
|
|
|
return NULL;
|
|
|
|
|
setup: suppress implicit "." work-tree for bare repos
If an explicit GIT_DIR is given without a working tree, we
implicitly assume that the current working directory should
be used as the working tree. E.g.,:
GIT_DIR=/some/repo.git git status
would compare against the cwd.
Unfortunately, we fool this rule for sub-invocations of git
by setting GIT_DIR internally ourselves. For example:
git init foo
cd foo/.git
git status ;# fails, as we expect
git config alias.st status
git status ;# does not fail, but should
What happens is that we run setup_git_directory when doing
alias lookup (since we need to see the config), set GIT_DIR
as a result, and then leave GIT_WORK_TREE blank (because we
do not have one). Then when we actually run the status
command, we do setup_git_directory again, which sees our
explicit GIT_DIR and uses the cwd as an implicit worktree.
It's tempting to argue that we should be suppressing that
second invocation of setup_git_directory, as it could use
the values we already found in memory. However, the problem
still exists for sub-processes (e.g., if "git status" were
an external command).
You can see another example with the "--bare" option, which
sets GIT_DIR explicitly. For example:
git init foo
cd foo/.git
git status ;# fails
git --bare status ;# does NOT fail
We need some way of telling sub-processes "even though
GIT_DIR is set, do not use cwd as an implicit working tree".
We could do it by putting a special token into
GIT_WORK_TREE, but the obvious choice (an empty string) has
some portability problems.
Instead, we add a new boolean variable, GIT_IMPLICIT_WORK_TREE,
which suppresses the use of cwd as a working tree when
GIT_DIR is set. We trigger the new variable when we know we
are in a bare setting.
The variable is left intentionally undocumented, as this is
an internal detail (for now, anyway). If somebody comes up
with a good alternate use for it, and once we are confident
we have shaken any bugs out of it, we can consider promoting
it further.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-03-08 17:32:22 +08:00
|
|
|
setenv(GIT_IMPLICIT_WORK_TREE_ENVIRONMENT, "0", 1);
|
|
|
|
|
2011-01-19 20:42:30 +08:00
|
|
|
/* --work-tree is set without --git-dir; use discovered one */
|
|
|
|
if (getenv(GIT_WORK_TREE_ENVIRONMENT) || git_work_tree_cfg) {
|
2017-05-04 21:56:47 +08:00
|
|
|
static const char *gitdir;
|
2011-01-19 20:42:30 +08:00
|
|
|
|
2014-07-29 02:26:40 +08:00
|
|
|
gitdir = offset == cwd->len ? "." : xmemdupz(cwd->buf, offset);
|
|
|
|
if (chdir(cwd->buf))
|
2011-01-19 20:42:30 +08:00
|
|
|
die_errno("Could not come back to cwd");
|
2014-07-29 02:26:40 +08:00
|
|
|
return setup_explicit_git_dir(gitdir, cwd, nongit_ok);
|
2011-01-19 20:42:30 +08:00
|
|
|
}
|
|
|
|
|
2010-07-24 19:25:32 +08:00
|
|
|
inside_git_dir = 1;
|
2010-11-26 23:32:36 +08:00
|
|
|
inside_work_tree = 0;
|
2014-07-29 02:26:40 +08:00
|
|
|
if (offset != cwd->len) {
|
|
|
|
if (chdir(cwd->buf))
|
2010-07-24 19:29:41 +08:00
|
|
|
die_errno("Cannot come back to cwd");
|
2014-07-29 02:26:40 +08:00
|
|
|
root_len = offset_1st_component(cwd->buf);
|
|
|
|
strbuf_setlen(cwd, offset > root_len ? offset : root_len);
|
|
|
|
set_git_dir(cwd->buf);
|
2010-11-26 23:32:34 +08:00
|
|
|
}
|
2010-11-26 23:32:36 +08:00
|
|
|
else
|
2010-07-24 19:25:32 +08:00
|
|
|
set_git_dir(".");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2010-07-24 19:26:41 +08:00
|
|
|
static const char *setup_nongit(const char *cwd, int *nongit_ok)
|
|
|
|
{
|
|
|
|
if (!nongit_ok)
|
2016-08-08 19:15:59 +08:00
|
|
|
die(_("Not a git repository (or any of the parent directories): %s"), DEFAULT_GIT_DIR_ENVIRONMENT);
|
2010-07-24 19:26:41 +08:00
|
|
|
if (chdir(cwd))
|
2016-08-08 19:15:59 +08:00
|
|
|
die_errno(_("Cannot come back to cwd"));
|
2010-07-24 19:26:41 +08:00
|
|
|
*nongit_ok = 1;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2012-04-13 07:11:36 +08:00
|
|
|
static dev_t get_device_or_die(const char *path, const char *prefix, int prefix_len)
|
2010-07-24 19:27:58 +08:00
|
|
|
{
|
|
|
|
struct stat buf;
|
2012-04-13 07:11:36 +08:00
|
|
|
if (stat(path, &buf)) {
|
|
|
|
die_errno("failed to stat '%*s%s%s'",
|
|
|
|
prefix_len,
|
2010-07-24 19:27:58 +08:00
|
|
|
prefix ? prefix : "",
|
|
|
|
prefix ? "/" : "", path);
|
2012-04-13 07:11:36 +08:00
|
|
|
}
|
2010-07-24 19:27:58 +08:00
|
|
|
return buf.st_dev;
|
|
|
|
}
|
|
|
|
|
2012-10-29 00:16:25 +08:00
|
|
|
/*
|
2012-10-29 00:16:26 +08:00
|
|
|
* A "string_list_each_func_t" function that canonicalizes an entry
|
|
|
|
* from GIT_CEILING_DIRECTORIES using real_path_if_valid(), or
|
Provide a mechanism to turn off symlink resolution in ceiling paths
Commit 1b77d83cab 'setup_git_directory_gently_1(): resolve symlinks
in ceiling paths' changed the setup code to resolve symlinks in the
entries in GIT_CEILING_DIRECTORIES. Because those entries are
compared textually to the symlink-resolved current directory, an
entry in GIT_CEILING_DIRECTORIES that contained a symlink would have
no effect. It was known that this could cause performance problems
if the symlink resolution *itself* touched slow filesystems, but it
was thought that such use cases would be unlikely. The intention of
the earlier change was to deal with a case when the user has this:
GIT_CEILING_DIRECTORIES=/home/gitster
but in reality, /home/gitster is a symbolic link to somewhere else,
e.g. /net/machine/home4/gitster. A textual comparison between the
specified value /home/gitster and the location getcwd(3) returns
would not help us, but readlink("/home/gitster") would still be
fast.
After this change was released, Anders Kaseorg <andersk@mit.edu>
reported:
> [...] my computer has been acting so slow when I’m not connected to
> the network. I put various network filesystem paths in
> $GIT_CEILING_DIRECTORIES, such as
> /afs/athena.mit.edu/user/a/n/andersk (to avoid hitting its parents
> /afs/athena.mit.edu, /afs/athena.mit.edu/user/a, and
> /afs/athena.mit.edu/user/a/n which all live in different AFS
> volumes). Now when I’m not connected to the network, every
> invocation of Git, including the __git_ps1 in my shell prompt, waits
> for AFS to timeout.
To allow users to work around this problem, give them a mechanism to
turn off symlink resolution in GIT_CEILING_DIRECTORIES entries. All
the entries that follow an empty entry will not be checked for symbolic
links and used literally in comparison. E.g. with these:
GIT_CEILING_DIRECTORIES=:/foo/bar:/xyzzy or
GIT_CEILING_DIRECTORIES=/foo/bar::/xyzzy
we will not readlink("/xyzzy") because it comes after an empty entry.
With the former (but not with the latter), "/foo/bar" comes after an
empty entry, and we will not readlink it, either.
Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-02-20 17:09:24 +08:00
|
|
|
* discards it if unusable. The presence of an empty entry in
|
|
|
|
* GIT_CEILING_DIRECTORIES turns off canonicalization for all
|
|
|
|
* subsequent entries.
|
2012-10-29 00:16:25 +08:00
|
|
|
*/
|
2012-10-29 00:16:26 +08:00
|
|
|
static int canonicalize_ceiling_entry(struct string_list_item *item,
|
Provide a mechanism to turn off symlink resolution in ceiling paths
Commit 1b77d83cab 'setup_git_directory_gently_1(): resolve symlinks
in ceiling paths' changed the setup code to resolve symlinks in the
entries in GIT_CEILING_DIRECTORIES. Because those entries are
compared textually to the symlink-resolved current directory, an
entry in GIT_CEILING_DIRECTORIES that contained a symlink would have
no effect. It was known that this could cause performance problems
if the symlink resolution *itself* touched slow filesystems, but it
was thought that such use cases would be unlikely. The intention of
the earlier change was to deal with a case when the user has this:
GIT_CEILING_DIRECTORIES=/home/gitster
but in reality, /home/gitster is a symbolic link to somewhere else,
e.g. /net/machine/home4/gitster. A textual comparison between the
specified value /home/gitster and the location getcwd(3) returns
would not help us, but readlink("/home/gitster") would still be
fast.
After this change was released, Anders Kaseorg <andersk@mit.edu>
reported:
> [...] my computer has been acting so slow when I’m not connected to
> the network. I put various network filesystem paths in
> $GIT_CEILING_DIRECTORIES, such as
> /afs/athena.mit.edu/user/a/n/andersk (to avoid hitting its parents
> /afs/athena.mit.edu, /afs/athena.mit.edu/user/a, and
> /afs/athena.mit.edu/user/a/n which all live in different AFS
> volumes). Now when I’m not connected to the network, every
> invocation of Git, including the __git_ps1 in my shell prompt, waits
> for AFS to timeout.
To allow users to work around this problem, give them a mechanism to
turn off symlink resolution in GIT_CEILING_DIRECTORIES entries. All
the entries that follow an empty entry will not be checked for symbolic
links and used literally in comparison. E.g. with these:
GIT_CEILING_DIRECTORIES=:/foo/bar:/xyzzy or
GIT_CEILING_DIRECTORIES=/foo/bar::/xyzzy
we will not readlink("/xyzzy") because it comes after an empty entry.
With the former (but not with the latter), "/foo/bar" comes after an
empty entry, and we will not readlink it, either.
Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-02-20 17:09:24 +08:00
|
|
|
void *cb_data)
|
2012-10-29 00:16:25 +08:00
|
|
|
{
|
Provide a mechanism to turn off symlink resolution in ceiling paths
Commit 1b77d83cab 'setup_git_directory_gently_1(): resolve symlinks
in ceiling paths' changed the setup code to resolve symlinks in the
entries in GIT_CEILING_DIRECTORIES. Because those entries are
compared textually to the symlink-resolved current directory, an
entry in GIT_CEILING_DIRECTORIES that contained a symlink would have
no effect. It was known that this could cause performance problems
if the symlink resolution *itself* touched slow filesystems, but it
was thought that such use cases would be unlikely. The intention of
the earlier change was to deal with a case when the user has this:
GIT_CEILING_DIRECTORIES=/home/gitster
but in reality, /home/gitster is a symbolic link to somewhere else,
e.g. /net/machine/home4/gitster. A textual comparison between the
specified value /home/gitster and the location getcwd(3) returns
would not help us, but readlink("/home/gitster") would still be
fast.
After this change was released, Anders Kaseorg <andersk@mit.edu>
reported:
> [...] my computer has been acting so slow when I’m not connected to
> the network. I put various network filesystem paths in
> $GIT_CEILING_DIRECTORIES, such as
> /afs/athena.mit.edu/user/a/n/andersk (to avoid hitting its parents
> /afs/athena.mit.edu, /afs/athena.mit.edu/user/a, and
> /afs/athena.mit.edu/user/a/n which all live in different AFS
> volumes). Now when I’m not connected to the network, every
> invocation of Git, including the __git_ps1 in my shell prompt, waits
> for AFS to timeout.
To allow users to work around this problem, give them a mechanism to
turn off symlink resolution in GIT_CEILING_DIRECTORIES entries. All
the entries that follow an empty entry will not be checked for symbolic
links and used literally in comparison. E.g. with these:
GIT_CEILING_DIRECTORIES=:/foo/bar:/xyzzy or
GIT_CEILING_DIRECTORIES=/foo/bar::/xyzzy
we will not readlink("/xyzzy") because it comes after an empty entry.
With the former (but not with the latter), "/foo/bar" comes after an
empty entry, and we will not readlink it, either.
Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-02-20 17:09:24 +08:00
|
|
|
int *empty_entry_found = cb_data;
|
2012-10-29 00:16:26 +08:00
|
|
|
char *ceil = item->string;
|
2012-10-29 00:16:25 +08:00
|
|
|
|
Provide a mechanism to turn off symlink resolution in ceiling paths
Commit 1b77d83cab 'setup_git_directory_gently_1(): resolve symlinks
in ceiling paths' changed the setup code to resolve symlinks in the
entries in GIT_CEILING_DIRECTORIES. Because those entries are
compared textually to the symlink-resolved current directory, an
entry in GIT_CEILING_DIRECTORIES that contained a symlink would have
no effect. It was known that this could cause performance problems
if the symlink resolution *itself* touched slow filesystems, but it
was thought that such use cases would be unlikely. The intention of
the earlier change was to deal with a case when the user has this:
GIT_CEILING_DIRECTORIES=/home/gitster
but in reality, /home/gitster is a symbolic link to somewhere else,
e.g. /net/machine/home4/gitster. A textual comparison between the
specified value /home/gitster and the location getcwd(3) returns
would not help us, but readlink("/home/gitster") would still be
fast.
After this change was released, Anders Kaseorg <andersk@mit.edu>
reported:
> [...] my computer has been acting so slow when I’m not connected to
> the network. I put various network filesystem paths in
> $GIT_CEILING_DIRECTORIES, such as
> /afs/athena.mit.edu/user/a/n/andersk (to avoid hitting its parents
> /afs/athena.mit.edu, /afs/athena.mit.edu/user/a, and
> /afs/athena.mit.edu/user/a/n which all live in different AFS
> volumes). Now when I’m not connected to the network, every
> invocation of Git, including the __git_ps1 in my shell prompt, waits
> for AFS to timeout.
To allow users to work around this problem, give them a mechanism to
turn off symlink resolution in GIT_CEILING_DIRECTORIES entries. All
the entries that follow an empty entry will not be checked for symbolic
links and used literally in comparison. E.g. with these:
GIT_CEILING_DIRECTORIES=:/foo/bar:/xyzzy or
GIT_CEILING_DIRECTORIES=/foo/bar::/xyzzy
we will not readlink("/xyzzy") because it comes after an empty entry.
With the former (but not with the latter), "/foo/bar" comes after an
empty entry, and we will not readlink it, either.
Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-02-20 17:09:24 +08:00
|
|
|
if (!*ceil) {
|
|
|
|
*empty_entry_found = 1;
|
2012-10-29 00:16:25 +08:00
|
|
|
return 0;
|
Provide a mechanism to turn off symlink resolution in ceiling paths
Commit 1b77d83cab 'setup_git_directory_gently_1(): resolve symlinks
in ceiling paths' changed the setup code to resolve symlinks in the
entries in GIT_CEILING_DIRECTORIES. Because those entries are
compared textually to the symlink-resolved current directory, an
entry in GIT_CEILING_DIRECTORIES that contained a symlink would have
no effect. It was known that this could cause performance problems
if the symlink resolution *itself* touched slow filesystems, but it
was thought that such use cases would be unlikely. The intention of
the earlier change was to deal with a case when the user has this:
GIT_CEILING_DIRECTORIES=/home/gitster
but in reality, /home/gitster is a symbolic link to somewhere else,
e.g. /net/machine/home4/gitster. A textual comparison between the
specified value /home/gitster and the location getcwd(3) returns
would not help us, but readlink("/home/gitster") would still be
fast.
After this change was released, Anders Kaseorg <andersk@mit.edu>
reported:
> [...] my computer has been acting so slow when I’m not connected to
> the network. I put various network filesystem paths in
> $GIT_CEILING_DIRECTORIES, such as
> /afs/athena.mit.edu/user/a/n/andersk (to avoid hitting its parents
> /afs/athena.mit.edu, /afs/athena.mit.edu/user/a, and
> /afs/athena.mit.edu/user/a/n which all live in different AFS
> volumes). Now when I’m not connected to the network, every
> invocation of Git, including the __git_ps1 in my shell prompt, waits
> for AFS to timeout.
To allow users to work around this problem, give them a mechanism to
turn off symlink resolution in GIT_CEILING_DIRECTORIES entries. All
the entries that follow an empty entry will not be checked for symbolic
links and used literally in comparison. E.g. with these:
GIT_CEILING_DIRECTORIES=:/foo/bar:/xyzzy or
GIT_CEILING_DIRECTORIES=/foo/bar::/xyzzy
we will not readlink("/xyzzy") because it comes after an empty entry.
With the former (but not with the latter), "/foo/bar" comes after an
empty entry, and we will not readlink it, either.
Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-02-20 17:09:24 +08:00
|
|
|
} else if (!is_absolute_path(ceil)) {
|
2012-10-29 00:16:25 +08:00
|
|
|
return 0;
|
Provide a mechanism to turn off symlink resolution in ceiling paths
Commit 1b77d83cab 'setup_git_directory_gently_1(): resolve symlinks
in ceiling paths' changed the setup code to resolve symlinks in the
entries in GIT_CEILING_DIRECTORIES. Because those entries are
compared textually to the symlink-resolved current directory, an
entry in GIT_CEILING_DIRECTORIES that contained a symlink would have
no effect. It was known that this could cause performance problems
if the symlink resolution *itself* touched slow filesystems, but it
was thought that such use cases would be unlikely. The intention of
the earlier change was to deal with a case when the user has this:
GIT_CEILING_DIRECTORIES=/home/gitster
but in reality, /home/gitster is a symbolic link to somewhere else,
e.g. /net/machine/home4/gitster. A textual comparison between the
specified value /home/gitster and the location getcwd(3) returns
would not help us, but readlink("/home/gitster") would still be
fast.
After this change was released, Anders Kaseorg <andersk@mit.edu>
reported:
> [...] my computer has been acting so slow when I’m not connected to
> the network. I put various network filesystem paths in
> $GIT_CEILING_DIRECTORIES, such as
> /afs/athena.mit.edu/user/a/n/andersk (to avoid hitting its parents
> /afs/athena.mit.edu, /afs/athena.mit.edu/user/a, and
> /afs/athena.mit.edu/user/a/n which all live in different AFS
> volumes). Now when I’m not connected to the network, every
> invocation of Git, including the __git_ps1 in my shell prompt, waits
> for AFS to timeout.
To allow users to work around this problem, give them a mechanism to
turn off symlink resolution in GIT_CEILING_DIRECTORIES entries. All
the entries that follow an empty entry will not be checked for symbolic
links and used literally in comparison. E.g. with these:
GIT_CEILING_DIRECTORIES=:/foo/bar:/xyzzy or
GIT_CEILING_DIRECTORIES=/foo/bar::/xyzzy
we will not readlink("/xyzzy") because it comes after an empty entry.
With the former (but not with the latter), "/foo/bar" comes after an
empty entry, and we will not readlink it, either.
Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-02-20 17:09:24 +08:00
|
|
|
} else if (*empty_entry_found) {
|
|
|
|
/* Keep entry but do not canonicalize it */
|
|
|
|
return 1;
|
|
|
|
} else {
|
2017-03-08 23:43:40 +08:00
|
|
|
char *real_path = real_pathdup(ceil, 0);
|
2016-12-13 02:16:55 +08:00
|
|
|
if (!real_path) {
|
Provide a mechanism to turn off symlink resolution in ceiling paths
Commit 1b77d83cab 'setup_git_directory_gently_1(): resolve symlinks
in ceiling paths' changed the setup code to resolve symlinks in the
entries in GIT_CEILING_DIRECTORIES. Because those entries are
compared textually to the symlink-resolved current directory, an
entry in GIT_CEILING_DIRECTORIES that contained a symlink would have
no effect. It was known that this could cause performance problems
if the symlink resolution *itself* touched slow filesystems, but it
was thought that such use cases would be unlikely. The intention of
the earlier change was to deal with a case when the user has this:
GIT_CEILING_DIRECTORIES=/home/gitster
but in reality, /home/gitster is a symbolic link to somewhere else,
e.g. /net/machine/home4/gitster. A textual comparison between the
specified value /home/gitster and the location getcwd(3) returns
would not help us, but readlink("/home/gitster") would still be
fast.
After this change was released, Anders Kaseorg <andersk@mit.edu>
reported:
> [...] my computer has been acting so slow when I’m not connected to
> the network. I put various network filesystem paths in
> $GIT_CEILING_DIRECTORIES, such as
> /afs/athena.mit.edu/user/a/n/andersk (to avoid hitting its parents
> /afs/athena.mit.edu, /afs/athena.mit.edu/user/a, and
> /afs/athena.mit.edu/user/a/n which all live in different AFS
> volumes). Now when I’m not connected to the network, every
> invocation of Git, including the __git_ps1 in my shell prompt, waits
> for AFS to timeout.
To allow users to work around this problem, give them a mechanism to
turn off symlink resolution in GIT_CEILING_DIRECTORIES entries. All
the entries that follow an empty entry will not be checked for symbolic
links and used literally in comparison. E.g. with these:
GIT_CEILING_DIRECTORIES=:/foo/bar:/xyzzy or
GIT_CEILING_DIRECTORIES=/foo/bar::/xyzzy
we will not readlink("/xyzzy") because it comes after an empty entry.
With the former (but not with the latter), "/foo/bar" comes after an
empty entry, and we will not readlink it, either.
Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-02-20 17:09:24 +08:00
|
|
|
return 0;
|
2016-12-13 02:16:55 +08:00
|
|
|
}
|
Provide a mechanism to turn off symlink resolution in ceiling paths
Commit 1b77d83cab 'setup_git_directory_gently_1(): resolve symlinks
in ceiling paths' changed the setup code to resolve symlinks in the
entries in GIT_CEILING_DIRECTORIES. Because those entries are
compared textually to the symlink-resolved current directory, an
entry in GIT_CEILING_DIRECTORIES that contained a symlink would have
no effect. It was known that this could cause performance problems
if the symlink resolution *itself* touched slow filesystems, but it
was thought that such use cases would be unlikely. The intention of
the earlier change was to deal with a case when the user has this:
GIT_CEILING_DIRECTORIES=/home/gitster
but in reality, /home/gitster is a symbolic link to somewhere else,
e.g. /net/machine/home4/gitster. A textual comparison between the
specified value /home/gitster and the location getcwd(3) returns
would not help us, but readlink("/home/gitster") would still be
fast.
After this change was released, Anders Kaseorg <andersk@mit.edu>
reported:
> [...] my computer has been acting so slow when I’m not connected to
> the network. I put various network filesystem paths in
> $GIT_CEILING_DIRECTORIES, such as
> /afs/athena.mit.edu/user/a/n/andersk (to avoid hitting its parents
> /afs/athena.mit.edu, /afs/athena.mit.edu/user/a, and
> /afs/athena.mit.edu/user/a/n which all live in different AFS
> volumes). Now when I’m not connected to the network, every
> invocation of Git, including the __git_ps1 in my shell prompt, waits
> for AFS to timeout.
To allow users to work around this problem, give them a mechanism to
turn off symlink resolution in GIT_CEILING_DIRECTORIES entries. All
the entries that follow an empty entry will not be checked for symbolic
links and used literally in comparison. E.g. with these:
GIT_CEILING_DIRECTORIES=:/foo/bar:/xyzzy or
GIT_CEILING_DIRECTORIES=/foo/bar::/xyzzy
we will not readlink("/xyzzy") because it comes after an empty entry.
With the former (but not with the latter), "/foo/bar" comes after an
empty entry, and we will not readlink it, either.
Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-02-20 17:09:24 +08:00
|
|
|
free(item->string);
|
2016-12-13 02:16:55 +08:00
|
|
|
item->string = real_path;
|
Provide a mechanism to turn off symlink resolution in ceiling paths
Commit 1b77d83cab 'setup_git_directory_gently_1(): resolve symlinks
in ceiling paths' changed the setup code to resolve symlinks in the
entries in GIT_CEILING_DIRECTORIES. Because those entries are
compared textually to the symlink-resolved current directory, an
entry in GIT_CEILING_DIRECTORIES that contained a symlink would have
no effect. It was known that this could cause performance problems
if the symlink resolution *itself* touched slow filesystems, but it
was thought that such use cases would be unlikely. The intention of
the earlier change was to deal with a case when the user has this:
GIT_CEILING_DIRECTORIES=/home/gitster
but in reality, /home/gitster is a symbolic link to somewhere else,
e.g. /net/machine/home4/gitster. A textual comparison between the
specified value /home/gitster and the location getcwd(3) returns
would not help us, but readlink("/home/gitster") would still be
fast.
After this change was released, Anders Kaseorg <andersk@mit.edu>
reported:
> [...] my computer has been acting so slow when I’m not connected to
> the network. I put various network filesystem paths in
> $GIT_CEILING_DIRECTORIES, such as
> /afs/athena.mit.edu/user/a/n/andersk (to avoid hitting its parents
> /afs/athena.mit.edu, /afs/athena.mit.edu/user/a, and
> /afs/athena.mit.edu/user/a/n which all live in different AFS
> volumes). Now when I’m not connected to the network, every
> invocation of Git, including the __git_ps1 in my shell prompt, waits
> for AFS to timeout.
To allow users to work around this problem, give them a mechanism to
turn off symlink resolution in GIT_CEILING_DIRECTORIES entries. All
the entries that follow an empty entry will not be checked for symbolic
links and used literally in comparison. E.g. with these:
GIT_CEILING_DIRECTORIES=:/foo/bar:/xyzzy or
GIT_CEILING_DIRECTORIES=/foo/bar::/xyzzy
we will not readlink("/xyzzy") because it comes after an empty entry.
With the former (but not with the latter), "/foo/bar" comes after an
empty entry, and we will not readlink it, either.
Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-02-20 17:09:24 +08:00
|
|
|
return 1;
|
|
|
|
}
|
2012-10-29 00:16:25 +08:00
|
|
|
}
|
|
|
|
|
setup_git_directory_1(): avoid changing global state
For historical reasons, Git searches for the .git/ directory (or the
.git file) by changing the working directory successively to the parent
directory of the current directory, until either anything was found or
until a ceiling or a mount point is hit.
Further global state may be changed in case a .git/ directory was found.
We do have a use case, though, where we would like to find the .git/
directory without having any global state touched, though: when we read
the early config e.g. for the pager or for alias expansion.
Let's just move all of code that changes any global state out of the
function `setup_git_directory_gently_1()` into
`setup_git_directory_gently()`.
In subsequent patches, we will use the _1() function in a new
`discover_git_directory()` function that we will then use for the early
config code.
Note: the new loop is a *little* tricky, as we have to handle the root
directory specially: we cannot simply strip away the last component
including the slash, as the root directory only has that slash. To remedy
that, we introduce the `min_offset` variable that holds the minimal length
of an absolute path, and using that to special-case the root directory,
including an early exit before trying to find the parent of the root
directory.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-14 04:10:42 +08:00
|
|
|
enum discovery_result {
|
|
|
|
GIT_DIR_NONE = 0,
|
|
|
|
GIT_DIR_EXPLICIT,
|
|
|
|
GIT_DIR_DISCOVERED,
|
|
|
|
GIT_DIR_BARE,
|
|
|
|
/* these are errors */
|
|
|
|
GIT_DIR_HIT_CEILING = -1,
|
2017-03-14 04:11:22 +08:00
|
|
|
GIT_DIR_HIT_MOUNT_POINT = -2,
|
|
|
|
GIT_DIR_INVALID_GITFILE = -3
|
setup_git_directory_1(): avoid changing global state
For historical reasons, Git searches for the .git/ directory (or the
.git file) by changing the working directory successively to the parent
directory of the current directory, until either anything was found or
until a ceiling or a mount point is hit.
Further global state may be changed in case a .git/ directory was found.
We do have a use case, though, where we would like to find the .git/
directory without having any global state touched, though: when we read
the early config e.g. for the pager or for alias expansion.
Let's just move all of code that changes any global state out of the
function `setup_git_directory_gently_1()` into
`setup_git_directory_gently()`.
In subsequent patches, we will use the _1() function in a new
`discover_git_directory()` function that we will then use for the early
config code.
Note: the new loop is a *little* tricky, as we have to handle the root
directory specially: we cannot simply strip away the last component
including the slash, as the root directory only has that slash. To remedy
that, we introduce the `min_offset` variable that holds the minimal length
of an absolute path, and using that to special-case the root directory,
including an early exit before trying to find the parent of the root
directory.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-14 04:10:42 +08:00
|
|
|
};
|
|
|
|
|
Clean up work-tree handling
The old version of work-tree support was an unholy mess, barely readable,
and not to the point.
For example, why do you have to provide a worktree, when it is not used?
As in "git status". Now it works.
Another riddle was: if you can have work trees inside the git dir, why
are some programs complaining that they need a work tree?
IOW it is allowed to call
$ git --git-dir=../ --work-tree=. bla
when you really want to. In this case, you are both in the git directory
and in the working tree. So, programs have to actually test for the right
thing, namely if they are inside a working tree, and not if they are
inside a git directory.
Also, GIT_DIR=../.git should behave the same as if no GIT_DIR was
specified, unless there is a repository in the current working directory.
It does now.
The logic to determine if a repository is bare, or has a work tree
(tertium non datur), is this:
--work-tree=bla overrides GIT_WORK_TREE, which overrides core.bare = true,
which overrides core.worktree, which overrides GIT_DIR/.. when GIT_DIR
ends in /.git, which overrides the directory in which .git/ was found.
In related news, a long standing bug was fixed: when in .git/bla/x.git/,
which is a bare repository, git formerly assumed ../.. to be the
appropriate git dir. This problem was reported by Shawn Pearce to have
caused much pain, where a colleague mistakenly ran "git init" in "/" a
long time ago, and bare repositories just would not work.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-08-01 08:30:14 +08:00
|
|
|
/*
|
|
|
|
* We cannot decide in this function whether we are in the work tree or
|
|
|
|
* not, since the config can only be read _after_ this function was called.
|
setup_git_directory_1(): avoid changing global state
For historical reasons, Git searches for the .git/ directory (or the
.git file) by changing the working directory successively to the parent
directory of the current directory, until either anything was found or
until a ceiling or a mount point is hit.
Further global state may be changed in case a .git/ directory was found.
We do have a use case, though, where we would like to find the .git/
directory without having any global state touched, though: when we read
the early config e.g. for the pager or for alias expansion.
Let's just move all of code that changes any global state out of the
function `setup_git_directory_gently_1()` into
`setup_git_directory_gently()`.
In subsequent patches, we will use the _1() function in a new
`discover_git_directory()` function that we will then use for the early
config code.
Note: the new loop is a *little* tricky, as we have to handle the root
directory specially: we cannot simply strip away the last component
including the slash, as the root directory only has that slash. To remedy
that, we introduce the `min_offset` variable that holds the minimal length
of an absolute path, and using that to special-case the root directory,
including an early exit before trying to find the parent of the root
directory.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-14 04:10:42 +08:00
|
|
|
*
|
|
|
|
* Also, we avoid changing any global state (such as the current working
|
|
|
|
* directory) to allow early callers.
|
|
|
|
*
|
|
|
|
* The directory where the search should start needs to be passed in via the
|
|
|
|
* `dir` parameter; upon return, the `dir` buffer will contain the path of
|
|
|
|
* the directory where the search ended, and `gitdir` will contain the path of
|
|
|
|
* the discovered .git/ directory, if any. If `gitdir` is not absolute, it
|
|
|
|
* is relative to `dir` (i.e. *not* necessarily the cwd).
|
Clean up work-tree handling
The old version of work-tree support was an unholy mess, barely readable,
and not to the point.
For example, why do you have to provide a worktree, when it is not used?
As in "git status". Now it works.
Another riddle was: if you can have work trees inside the git dir, why
are some programs complaining that they need a work tree?
IOW it is allowed to call
$ git --git-dir=../ --work-tree=. bla
when you really want to. In this case, you are both in the git directory
and in the working tree. So, programs have to actually test for the right
thing, namely if they are inside a working tree, and not if they are
inside a git directory.
Also, GIT_DIR=../.git should behave the same as if no GIT_DIR was
specified, unless there is a repository in the current working directory.
It does now.
The logic to determine if a repository is bare, or has a work tree
(tertium non datur), is this:
--work-tree=bla overrides GIT_WORK_TREE, which overrides core.bare = true,
which overrides core.worktree, which overrides GIT_DIR/.. when GIT_DIR
ends in /.git, which overrides the directory in which .git/ was found.
In related news, a long standing bug was fixed: when in .git/bla/x.git/,
which is a bare repository, git formerly assumed ../.. to be the
appropriate git dir. This problem was reported by Shawn Pearce to have
caused much pain, where a colleague mistakenly ran "git init" in "/" a
long time ago, and bare repositories just would not work.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-08-01 08:30:14 +08:00
|
|
|
*/
|
setup_git_directory_1(): avoid changing global state
For historical reasons, Git searches for the .git/ directory (or the
.git file) by changing the working directory successively to the parent
directory of the current directory, until either anything was found or
until a ceiling or a mount point is hit.
Further global state may be changed in case a .git/ directory was found.
We do have a use case, though, where we would like to find the .git/
directory without having any global state touched, though: when we read
the early config e.g. for the pager or for alias expansion.
Let's just move all of code that changes any global state out of the
function `setup_git_directory_gently_1()` into
`setup_git_directory_gently()`.
In subsequent patches, we will use the _1() function in a new
`discover_git_directory()` function that we will then use for the early
config code.
Note: the new loop is a *little* tricky, as we have to handle the root
directory specially: we cannot simply strip away the last component
including the slash, as the root directory only has that slash. To remedy
that, we introduce the `min_offset` variable that holds the minimal length
of an absolute path, and using that to special-case the root directory,
including an early exit before trying to find the parent of the root
directory.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-14 04:10:42 +08:00
|
|
|
static enum discovery_result setup_git_directory_gently_1(struct strbuf *dir,
|
2017-03-14 04:11:22 +08:00
|
|
|
struct strbuf *gitdir,
|
|
|
|
int die_on_error)
|
2005-08-17 09:06:34 +08:00
|
|
|
{
|
2008-05-20 14:49:26 +08:00
|
|
|
const char *env_ceiling_dirs = getenv(CEILING_DIRECTORIES_ENVIRONMENT);
|
2012-10-29 00:16:24 +08:00
|
|
|
struct string_list ceiling_dirs = STRING_LIST_INIT_DUP;
|
setup_git_directory_1(): avoid changing global state
For historical reasons, Git searches for the .git/ directory (or the
.git file) by changing the working directory successively to the parent
directory of the current directory, until either anything was found or
until a ceiling or a mount point is hit.
Further global state may be changed in case a .git/ directory was found.
We do have a use case, though, where we would like to find the .git/
directory without having any global state touched, though: when we read
the early config e.g. for the pager or for alias expansion.
Let's just move all of code that changes any global state out of the
function `setup_git_directory_gently_1()` into
`setup_git_directory_gently()`.
In subsequent patches, we will use the _1() function in a new
`discover_git_directory()` function that we will then use for the early
config code.
Note: the new loop is a *little* tricky, as we have to handle the root
directory specially: we cannot simply strip away the last component
including the slash, as the root directory only has that slash. To remedy
that, we introduce the `min_offset` variable that holds the minimal length
of an absolute path, and using that to special-case the root directory,
including an early exit before trying to find the parent of the root
directory.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-14 04:10:42 +08:00
|
|
|
const char *gitdirenv;
|
|
|
|
int ceil_offset = -1, min_offset = has_dos_drive_prefix(dir->buf) ? 3 : 1;
|
2010-07-13 17:02:00 +08:00
|
|
|
dev_t current_device = 0;
|
|
|
|
int one_filesystem = 1;
|
2005-08-17 09:06:34 +08:00
|
|
|
|
Clean up work-tree handling
The old version of work-tree support was an unholy mess, barely readable,
and not to the point.
For example, why do you have to provide a worktree, when it is not used?
As in "git status". Now it works.
Another riddle was: if you can have work trees inside the git dir, why
are some programs complaining that they need a work tree?
IOW it is allowed to call
$ git --git-dir=../ --work-tree=. bla
when you really want to. In this case, you are both in the git directory
and in the working tree. So, programs have to actually test for the right
thing, namely if they are inside a working tree, and not if they are
inside a git directory.
Also, GIT_DIR=../.git should behave the same as if no GIT_DIR was
specified, unless there is a repository in the current working directory.
It does now.
The logic to determine if a repository is bare, or has a work tree
(tertium non datur), is this:
--work-tree=bla overrides GIT_WORK_TREE, which overrides core.bare = true,
which overrides core.worktree, which overrides GIT_DIR/.. when GIT_DIR
ends in /.git, which overrides the directory in which .git/ was found.
In related news, a long standing bug was fixed: when in .git/bla/x.git/,
which is a bare repository, git formerly assumed ../.. to be the
appropriate git dir. This problem was reported by Shawn Pearce to have
caused much pain, where a colleague mistakenly ran "git init" in "/" a
long time ago, and bare repositories just would not work.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-08-01 08:30:14 +08:00
|
|
|
/*
|
|
|
|
* If GIT_DIR is set explicitly, we're not going
|
|
|
|
* to do any discovery, but we still do repository
|
|
|
|
* validation.
|
|
|
|
*/
|
2006-12-31 12:30:19 +08:00
|
|
|
gitdirenv = getenv(GIT_DIR_ENVIRONMENT);
|
setup_git_directory_1(): avoid changing global state
For historical reasons, Git searches for the .git/ directory (or the
.git file) by changing the working directory successively to the parent
directory of the current directory, until either anything was found or
until a ceiling or a mount point is hit.
Further global state may be changed in case a .git/ directory was found.
We do have a use case, though, where we would like to find the .git/
directory without having any global state touched, though: when we read
the early config e.g. for the pager or for alias expansion.
Let's just move all of code that changes any global state out of the
function `setup_git_directory_gently_1()` into
`setup_git_directory_gently()`.
In subsequent patches, we will use the _1() function in a new
`discover_git_directory()` function that we will then use for the early
config code.
Note: the new loop is a *little* tricky, as we have to handle the root
directory specially: we cannot simply strip away the last component
including the slash, as the root directory only has that slash. To remedy
that, we introduce the `min_offset` variable that holds the minimal length
of an absolute path, and using that to special-case the root directory,
including an early exit before trying to find the parent of the root
directory.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-14 04:10:42 +08:00
|
|
|
if (gitdirenv) {
|
|
|
|
strbuf_addstr(gitdir, gitdirenv);
|
|
|
|
return GIT_DIR_EXPLICIT;
|
|
|
|
}
|
2005-08-17 09:06:34 +08:00
|
|
|
|
2012-10-29 00:16:24 +08:00
|
|
|
if (env_ceiling_dirs) {
|
Provide a mechanism to turn off symlink resolution in ceiling paths
Commit 1b77d83cab 'setup_git_directory_gently_1(): resolve symlinks
in ceiling paths' changed the setup code to resolve symlinks in the
entries in GIT_CEILING_DIRECTORIES. Because those entries are
compared textually to the symlink-resolved current directory, an
entry in GIT_CEILING_DIRECTORIES that contained a symlink would have
no effect. It was known that this could cause performance problems
if the symlink resolution *itself* touched slow filesystems, but it
was thought that such use cases would be unlikely. The intention of
the earlier change was to deal with a case when the user has this:
GIT_CEILING_DIRECTORIES=/home/gitster
but in reality, /home/gitster is a symbolic link to somewhere else,
e.g. /net/machine/home4/gitster. A textual comparison between the
specified value /home/gitster and the location getcwd(3) returns
would not help us, but readlink("/home/gitster") would still be
fast.
After this change was released, Anders Kaseorg <andersk@mit.edu>
reported:
> [...] my computer has been acting so slow when I’m not connected to
> the network. I put various network filesystem paths in
> $GIT_CEILING_DIRECTORIES, such as
> /afs/athena.mit.edu/user/a/n/andersk (to avoid hitting its parents
> /afs/athena.mit.edu, /afs/athena.mit.edu/user/a, and
> /afs/athena.mit.edu/user/a/n which all live in different AFS
> volumes). Now when I’m not connected to the network, every
> invocation of Git, including the __git_ps1 in my shell prompt, waits
> for AFS to timeout.
To allow users to work around this problem, give them a mechanism to
turn off symlink resolution in GIT_CEILING_DIRECTORIES entries. All
the entries that follow an empty entry will not be checked for symbolic
links and used literally in comparison. E.g. with these:
GIT_CEILING_DIRECTORIES=:/foo/bar:/xyzzy or
GIT_CEILING_DIRECTORIES=/foo/bar::/xyzzy
we will not readlink("/xyzzy") because it comes after an empty entry.
With the former (but not with the latter), "/foo/bar" comes after an
empty entry, and we will not readlink it, either.
Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-02-20 17:09:24 +08:00
|
|
|
int empty_entry_found = 0;
|
|
|
|
|
2012-10-29 00:16:24 +08:00
|
|
|
string_list_split(&ceiling_dirs, env_ceiling_dirs, PATH_SEP, -1);
|
2012-10-29 00:16:26 +08:00
|
|
|
filter_string_list(&ceiling_dirs, 0,
|
Provide a mechanism to turn off symlink resolution in ceiling paths
Commit 1b77d83cab 'setup_git_directory_gently_1(): resolve symlinks
in ceiling paths' changed the setup code to resolve symlinks in the
entries in GIT_CEILING_DIRECTORIES. Because those entries are
compared textually to the symlink-resolved current directory, an
entry in GIT_CEILING_DIRECTORIES that contained a symlink would have
no effect. It was known that this could cause performance problems
if the symlink resolution *itself* touched slow filesystems, but it
was thought that such use cases would be unlikely. The intention of
the earlier change was to deal with a case when the user has this:
GIT_CEILING_DIRECTORIES=/home/gitster
but in reality, /home/gitster is a symbolic link to somewhere else,
e.g. /net/machine/home4/gitster. A textual comparison between the
specified value /home/gitster and the location getcwd(3) returns
would not help us, but readlink("/home/gitster") would still be
fast.
After this change was released, Anders Kaseorg <andersk@mit.edu>
reported:
> [...] my computer has been acting so slow when I’m not connected to
> the network. I put various network filesystem paths in
> $GIT_CEILING_DIRECTORIES, such as
> /afs/athena.mit.edu/user/a/n/andersk (to avoid hitting its parents
> /afs/athena.mit.edu, /afs/athena.mit.edu/user/a, and
> /afs/athena.mit.edu/user/a/n which all live in different AFS
> volumes). Now when I’m not connected to the network, every
> invocation of Git, including the __git_ps1 in my shell prompt, waits
> for AFS to timeout.
To allow users to work around this problem, give them a mechanism to
turn off symlink resolution in GIT_CEILING_DIRECTORIES entries. All
the entries that follow an empty entry will not be checked for symbolic
links and used literally in comparison. E.g. with these:
GIT_CEILING_DIRECTORIES=:/foo/bar:/xyzzy or
GIT_CEILING_DIRECTORIES=/foo/bar::/xyzzy
we will not readlink("/xyzzy") because it comes after an empty entry.
With the former (but not with the latter), "/foo/bar" comes after an
empty entry, and we will not readlink it, either.
Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-02-20 17:09:24 +08:00
|
|
|
canonicalize_ceiling_entry, &empty_entry_found);
|
setup_git_directory_1(): avoid changing global state
For historical reasons, Git searches for the .git/ directory (or the
.git file) by changing the working directory successively to the parent
directory of the current directory, until either anything was found or
until a ceiling or a mount point is hit.
Further global state may be changed in case a .git/ directory was found.
We do have a use case, though, where we would like to find the .git/
directory without having any global state touched, though: when we read
the early config e.g. for the pager or for alias expansion.
Let's just move all of code that changes any global state out of the
function `setup_git_directory_gently_1()` into
`setup_git_directory_gently()`.
In subsequent patches, we will use the _1() function in a new
`discover_git_directory()` function that we will then use for the early
config code.
Note: the new loop is a *little* tricky, as we have to handle the root
directory specially: we cannot simply strip away the last component
including the slash, as the root directory only has that slash. To remedy
that, we introduce the `min_offset` variable that holds the minimal length
of an absolute path, and using that to special-case the root directory,
including an early exit before trying to find the parent of the root
directory.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-14 04:10:42 +08:00
|
|
|
ceil_offset = longest_ancestor_length(dir->buf, &ceiling_dirs);
|
2012-10-29 00:16:24 +08:00
|
|
|
string_list_clear(&ceiling_dirs, 0);
|
|
|
|
}
|
|
|
|
|
setup_git_directory_1(): avoid changing global state
For historical reasons, Git searches for the .git/ directory (or the
.git file) by changing the working directory successively to the parent
directory of the current directory, until either anything was found or
until a ceiling or a mount point is hit.
Further global state may be changed in case a .git/ directory was found.
We do have a use case, though, where we would like to find the .git/
directory without having any global state touched, though: when we read
the early config e.g. for the pager or for alias expansion.
Let's just move all of code that changes any global state out of the
function `setup_git_directory_gently_1()` into
`setup_git_directory_gently()`.
In subsequent patches, we will use the _1() function in a new
`discover_git_directory()` function that we will then use for the early
config code.
Note: the new loop is a *little* tricky, as we have to handle the root
directory specially: we cannot simply strip away the last component
including the slash, as the root directory only has that slash. To remedy
that, we introduce the `min_offset` variable that holds the minimal length
of an absolute path, and using that to special-case the root directory,
including an early exit before trying to find the parent of the root
directory.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-14 04:10:42 +08:00
|
|
|
if (ceil_offset < 0)
|
|
|
|
ceil_offset = min_offset - 2;
|
2005-08-17 09:06:34 +08:00
|
|
|
|
2007-06-06 15:10:42 +08:00
|
|
|
/*
|
setup_git_directory_1(): avoid changing global state
For historical reasons, Git searches for the .git/ directory (or the
.git file) by changing the working directory successively to the parent
directory of the current directory, until either anything was found or
until a ceiling or a mount point is hit.
Further global state may be changed in case a .git/ directory was found.
We do have a use case, though, where we would like to find the .git/
directory without having any global state touched, though: when we read
the early config e.g. for the pager or for alias expansion.
Let's just move all of code that changes any global state out of the
function `setup_git_directory_gently_1()` into
`setup_git_directory_gently()`.
In subsequent patches, we will use the _1() function in a new
`discover_git_directory()` function that we will then use for the early
config code.
Note: the new loop is a *little* tricky, as we have to handle the root
directory specially: we cannot simply strip away the last component
including the slash, as the root directory only has that slash. To remedy
that, we introduce the `min_offset` variable that holds the minimal length
of an absolute path, and using that to special-case the root directory,
including an early exit before trying to find the parent of the root
directory.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-14 04:10:42 +08:00
|
|
|
* Test in the following order (relative to the dir):
|
2008-02-21 06:13:13 +08:00
|
|
|
* - .git (file containing "gitdir: <path>")
|
Clean up work-tree handling
The old version of work-tree support was an unholy mess, barely readable,
and not to the point.
For example, why do you have to provide a worktree, when it is not used?
As in "git status". Now it works.
Another riddle was: if you can have work trees inside the git dir, why
are some programs complaining that they need a work tree?
IOW it is allowed to call
$ git --git-dir=../ --work-tree=. bla
when you really want to. In this case, you are both in the git directory
and in the working tree. So, programs have to actually test for the right
thing, namely if they are inside a working tree, and not if they are
inside a git directory.
Also, GIT_DIR=../.git should behave the same as if no GIT_DIR was
specified, unless there is a repository in the current working directory.
It does now.
The logic to determine if a repository is bare, or has a work tree
(tertium non datur), is this:
--work-tree=bla overrides GIT_WORK_TREE, which overrides core.bare = true,
which overrides core.worktree, which overrides GIT_DIR/.. when GIT_DIR
ends in /.git, which overrides the directory in which .git/ was found.
In related news, a long standing bug was fixed: when in .git/bla/x.git/,
which is a bare repository, git formerly assumed ../.. to be the
appropriate git dir. This problem was reported by Shawn Pearce to have
caused much pain, where a colleague mistakenly ran "git init" in "/" a
long time ago, and bare repositories just would not work.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-08-01 08:30:14 +08:00
|
|
|
* - .git/
|
|
|
|
* - ./ (bare)
|
2008-02-21 06:13:13 +08:00
|
|
|
* - ../.git
|
Clean up work-tree handling
The old version of work-tree support was an unholy mess, barely readable,
and not to the point.
For example, why do you have to provide a worktree, when it is not used?
As in "git status". Now it works.
Another riddle was: if you can have work trees inside the git dir, why
are some programs complaining that they need a work tree?
IOW it is allowed to call
$ git --git-dir=../ --work-tree=. bla
when you really want to. In this case, you are both in the git directory
and in the working tree. So, programs have to actually test for the right
thing, namely if they are inside a working tree, and not if they are
inside a git directory.
Also, GIT_DIR=../.git should behave the same as if no GIT_DIR was
specified, unless there is a repository in the current working directory.
It does now.
The logic to determine if a repository is bare, or has a work tree
(tertium non datur), is this:
--work-tree=bla overrides GIT_WORK_TREE, which overrides core.bare = true,
which overrides core.worktree, which overrides GIT_DIR/.. when GIT_DIR
ends in /.git, which overrides the directory in which .git/ was found.
In related news, a long standing bug was fixed: when in .git/bla/x.git/,
which is a bare repository, git formerly assumed ../.. to be the
appropriate git dir. This problem was reported by Shawn Pearce to have
caused much pain, where a colleague mistakenly ran "git init" in "/" a
long time ago, and bare repositories just would not work.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-08-01 08:30:14 +08:00
|
|
|
* - ../.git/
|
|
|
|
* - ../ (bare)
|
|
|
|
* - ../../.git/
|
|
|
|
* etc.
|
2007-06-06 15:10:42 +08:00
|
|
|
*/
|
2010-04-05 05:49:31 +08:00
|
|
|
one_filesystem = !git_env_bool("GIT_DISCOVERY_ACROSS_FILESYSTEM", 0);
|
2010-07-24 19:27:58 +08:00
|
|
|
if (one_filesystem)
|
setup_git_directory_1(): avoid changing global state
For historical reasons, Git searches for the .git/ directory (or the
.git file) by changing the working directory successively to the parent
directory of the current directory, until either anything was found or
until a ceiling or a mount point is hit.
Further global state may be changed in case a .git/ directory was found.
We do have a use case, though, where we would like to find the .git/
directory without having any global state touched, though: when we read
the early config e.g. for the pager or for alias expansion.
Let's just move all of code that changes any global state out of the
function `setup_git_directory_gently_1()` into
`setup_git_directory_gently()`.
In subsequent patches, we will use the _1() function in a new
`discover_git_directory()` function that we will then use for the early
config code.
Note: the new loop is a *little* tricky, as we have to handle the root
directory specially: we cannot simply strip away the last component
including the slash, as the root directory only has that slash. To remedy
that, we introduce the `min_offset` variable that holds the minimal length
of an absolute path, and using that to special-case the root directory,
including an early exit before trying to find the parent of the root
directory.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-14 04:10:42 +08:00
|
|
|
current_device = get_device_or_die(dir->buf, NULL, 0);
|
Clean up work-tree handling
The old version of work-tree support was an unholy mess, barely readable,
and not to the point.
For example, why do you have to provide a worktree, when it is not used?
As in "git status". Now it works.
Another riddle was: if you can have work trees inside the git dir, why
are some programs complaining that they need a work tree?
IOW it is allowed to call
$ git --git-dir=../ --work-tree=. bla
when you really want to. In this case, you are both in the git directory
and in the working tree. So, programs have to actually test for the right
thing, namely if they are inside a working tree, and not if they are
inside a git directory.
Also, GIT_DIR=../.git should behave the same as if no GIT_DIR was
specified, unless there is a repository in the current working directory.
It does now.
The logic to determine if a repository is bare, or has a work tree
(tertium non datur), is this:
--work-tree=bla overrides GIT_WORK_TREE, which overrides core.bare = true,
which overrides core.worktree, which overrides GIT_DIR/.. when GIT_DIR
ends in /.git, which overrides the directory in which .git/ was found.
In related news, a long standing bug was fixed: when in .git/bla/x.git/,
which is a bare repository, git formerly assumed ../.. to be the
appropriate git dir. This problem was reported by Shawn Pearce to have
caused much pain, where a colleague mistakenly ran "git init" in "/" a
long time ago, and bare repositories just would not work.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-08-01 08:30:14 +08:00
|
|
|
for (;;) {
|
2017-03-14 04:11:22 +08:00
|
|
|
int offset = dir->len, error_code = 0;
|
setup_git_directory_1(): avoid changing global state
For historical reasons, Git searches for the .git/ directory (or the
.git file) by changing the working directory successively to the parent
directory of the current directory, until either anything was found or
until a ceiling or a mount point is hit.
Further global state may be changed in case a .git/ directory was found.
We do have a use case, though, where we would like to find the .git/
directory without having any global state touched, though: when we read
the early config e.g. for the pager or for alias expansion.
Let's just move all of code that changes any global state out of the
function `setup_git_directory_gently_1()` into
`setup_git_directory_gently()`.
In subsequent patches, we will use the _1() function in a new
`discover_git_directory()` function that we will then use for the early
config code.
Note: the new loop is a *little* tricky, as we have to handle the root
directory specially: we cannot simply strip away the last component
including the slash, as the root directory only has that slash. To remedy
that, we introduce the `min_offset` variable that holds the minimal length
of an absolute path, and using that to special-case the root directory,
including an early exit before trying to find the parent of the root
directory.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-14 04:10:42 +08:00
|
|
|
|
|
|
|
if (offset > min_offset)
|
|
|
|
strbuf_addch(dir, '/');
|
|
|
|
strbuf_addstr(dir, DEFAULT_GIT_DIR_ENVIRONMENT);
|
2017-03-14 04:11:22 +08:00
|
|
|
gitdirenv = read_gitfile_gently(dir->buf, die_on_error ?
|
|
|
|
NULL : &error_code);
|
|
|
|
if (!gitdirenv) {
|
|
|
|
if (die_on_error ||
|
|
|
|
error_code == READ_GITFILE_ERR_NOT_A_FILE) {
|
2017-03-14 04:12:18 +08:00
|
|
|
/* NEEDSWORK: fail if .git is not file nor dir */
|
2017-03-14 04:11:22 +08:00
|
|
|
if (is_git_directory(dir->buf))
|
|
|
|
gitdirenv = DEFAULT_GIT_DIR_ENVIRONMENT;
|
|
|
|
} else if (error_code != READ_GITFILE_ERR_STAT_FAILED)
|
|
|
|
return GIT_DIR_INVALID_GITFILE;
|
2010-11-26 23:32:38 +08:00
|
|
|
}
|
setup_git_directory_1(): avoid changing global state
For historical reasons, Git searches for the .git/ directory (or the
.git file) by changing the working directory successively to the parent
directory of the current directory, until either anything was found or
until a ceiling or a mount point is hit.
Further global state may be changed in case a .git/ directory was found.
We do have a use case, though, where we would like to find the .git/
directory without having any global state touched, though: when we read
the early config e.g. for the pager or for alias expansion.
Let's just move all of code that changes any global state out of the
function `setup_git_directory_gently_1()` into
`setup_git_directory_gently()`.
In subsequent patches, we will use the _1() function in a new
`discover_git_directory()` function that we will then use for the early
config code.
Note: the new loop is a *little* tricky, as we have to handle the root
directory specially: we cannot simply strip away the last component
including the slash, as the root directory only has that slash. To remedy
that, we introduce the `min_offset` variable that holds the minimal length
of an absolute path, and using that to special-case the root directory,
including an early exit before trying to find the parent of the root
directory.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-14 04:10:42 +08:00
|
|
|
strbuf_setlen(dir, offset);
|
2010-11-26 23:32:38 +08:00
|
|
|
if (gitdirenv) {
|
setup_git_directory_1(): avoid changing global state
For historical reasons, Git searches for the .git/ directory (or the
.git file) by changing the working directory successively to the parent
directory of the current directory, until either anything was found or
until a ceiling or a mount point is hit.
Further global state may be changed in case a .git/ directory was found.
We do have a use case, though, where we would like to find the .git/
directory without having any global state touched, though: when we read
the early config e.g. for the pager or for alias expansion.
Let's just move all of code that changes any global state out of the
function `setup_git_directory_gently_1()` into
`setup_git_directory_gently()`.
In subsequent patches, we will use the _1() function in a new
`discover_git_directory()` function that we will then use for the early
config code.
Note: the new loop is a *little* tricky, as we have to handle the root
directory specially: we cannot simply strip away the last component
including the slash, as the root directory only has that slash. To remedy
that, we introduce the `min_offset` variable that holds the minimal length
of an absolute path, and using that to special-case the root directory,
including an early exit before trying to find the parent of the root
directory.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-14 04:10:42 +08:00
|
|
|
strbuf_addstr(gitdir, gitdirenv);
|
|
|
|
return GIT_DIR_DISCOVERED;
|
2010-11-26 23:32:38 +08:00
|
|
|
}
|
|
|
|
|
setup_git_directory_1(): avoid changing global state
For historical reasons, Git searches for the .git/ directory (or the
.git file) by changing the working directory successively to the parent
directory of the current directory, until either anything was found or
until a ceiling or a mount point is hit.
Further global state may be changed in case a .git/ directory was found.
We do have a use case, though, where we would like to find the .git/
directory without having any global state touched, though: when we read
the early config e.g. for the pager or for alias expansion.
Let's just move all of code that changes any global state out of the
function `setup_git_directory_gently_1()` into
`setup_git_directory_gently()`.
In subsequent patches, we will use the _1() function in a new
`discover_git_directory()` function that we will then use for the early
config code.
Note: the new loop is a *little* tricky, as we have to handle the root
directory specially: we cannot simply strip away the last component
including the slash, as the root directory only has that slash. To remedy
that, we introduce the `min_offset` variable that holds the minimal length
of an absolute path, and using that to special-case the root directory,
including an early exit before trying to find the parent of the root
directory.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-14 04:10:42 +08:00
|
|
|
if (is_git_directory(dir->buf)) {
|
|
|
|
strbuf_addstr(gitdir, ".");
|
|
|
|
return GIT_DIR_BARE;
|
2010-03-18 03:55:52 +08:00
|
|
|
}
|
2010-11-26 23:32:38 +08:00
|
|
|
|
setup_git_directory_1(): avoid changing global state
For historical reasons, Git searches for the .git/ directory (or the
.git file) by changing the working directory successively to the parent
directory of the current directory, until either anything was found or
until a ceiling or a mount point is hit.
Further global state may be changed in case a .git/ directory was found.
We do have a use case, though, where we would like to find the .git/
directory without having any global state touched, though: when we read
the early config e.g. for the pager or for alias expansion.
Let's just move all of code that changes any global state out of the
function `setup_git_directory_gently_1()` into
`setup_git_directory_gently()`.
In subsequent patches, we will use the _1() function in a new
`discover_git_directory()` function that we will then use for the early
config code.
Note: the new loop is a *little* tricky, as we have to handle the root
directory specially: we cannot simply strip away the last component
including the slash, as the root directory only has that slash. To remedy
that, we introduce the `min_offset` variable that holds the minimal length
of an absolute path, and using that to special-case the root directory,
including an early exit before trying to find the parent of the root
directory.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-14 04:10:42 +08:00
|
|
|
if (offset <= min_offset)
|
|
|
|
return GIT_DIR_HIT_CEILING;
|
2010-11-26 23:32:36 +08:00
|
|
|
|
setup_git_directory_1(): avoid changing global state
For historical reasons, Git searches for the .git/ directory (or the
.git file) by changing the working directory successively to the parent
directory of the current directory, until either anything was found or
until a ceiling or a mount point is hit.
Further global state may be changed in case a .git/ directory was found.
We do have a use case, though, where we would like to find the .git/
directory without having any global state touched, though: when we read
the early config e.g. for the pager or for alias expansion.
Let's just move all of code that changes any global state out of the
function `setup_git_directory_gently_1()` into
`setup_git_directory_gently()`.
In subsequent patches, we will use the _1() function in a new
`discover_git_directory()` function that we will then use for the early
config code.
Note: the new loop is a *little* tricky, as we have to handle the root
directory specially: we cannot simply strip away the last component
including the slash, as the root directory only has that slash. To remedy
that, we introduce the `min_offset` variable that holds the minimal length
of an absolute path, and using that to special-case the root directory,
including an early exit before trying to find the parent of the root
directory.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-14 04:10:42 +08:00
|
|
|
while (--offset > ceil_offset && !is_dir_sep(dir->buf[offset]))
|
2017-03-07 22:32:32 +08:00
|
|
|
; /* continue */
|
setup_git_directory_1(): avoid changing global state
For historical reasons, Git searches for the .git/ directory (or the
.git file) by changing the working directory successively to the parent
directory of the current directory, until either anything was found or
until a ceiling or a mount point is hit.
Further global state may be changed in case a .git/ directory was found.
We do have a use case, though, where we would like to find the .git/
directory without having any global state touched, though: when we read
the early config e.g. for the pager or for alias expansion.
Let's just move all of code that changes any global state out of the
function `setup_git_directory_gently_1()` into
`setup_git_directory_gently()`.
In subsequent patches, we will use the _1() function in a new
`discover_git_directory()` function that we will then use for the early
config code.
Note: the new loop is a *little* tricky, as we have to handle the root
directory specially: we cannot simply strip away the last component
including the slash, as the root directory only has that slash. To remedy
that, we introduce the `min_offset` variable that holds the minimal length
of an absolute path, and using that to special-case the root directory,
including an early exit before trying to find the parent of the root
directory.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-14 04:10:42 +08:00
|
|
|
if (offset <= ceil_offset)
|
|
|
|
return GIT_DIR_HIT_CEILING;
|
|
|
|
|
|
|
|
strbuf_setlen(dir, offset > min_offset ? offset : min_offset);
|
|
|
|
if (one_filesystem &&
|
|
|
|
current_device != get_device_or_die(dir->buf, NULL, offset))
|
|
|
|
return GIT_DIR_HIT_MOUNT_POINT;
|
2007-06-06 15:10:42 +08:00
|
|
|
}
|
2005-08-17 09:06:34 +08:00
|
|
|
}
|
2005-11-26 07:43:41 +08:00
|
|
|
|
2017-06-15 02:07:37 +08:00
|
|
|
int discover_git_directory(struct strbuf *commondir,
|
|
|
|
struct strbuf *gitdir)
|
2017-03-14 04:10:45 +08:00
|
|
|
{
|
|
|
|
struct strbuf dir = STRBUF_INIT, err = STRBUF_INIT;
|
|
|
|
size_t gitdir_offset = gitdir->len, cwd_len;
|
2017-06-15 02:07:37 +08:00
|
|
|
size_t commondir_offset = commondir->len;
|
2017-03-14 04:10:45 +08:00
|
|
|
struct repository_format candidate;
|
|
|
|
|
|
|
|
if (strbuf_getcwd(&dir))
|
2017-06-15 02:07:37 +08:00
|
|
|
return -1;
|
2017-03-14 04:10:45 +08:00
|
|
|
|
|
|
|
cwd_len = dir.len;
|
2017-03-14 04:11:22 +08:00
|
|
|
if (setup_git_directory_gently_1(&dir, gitdir, 0) <= 0) {
|
2017-03-14 04:10:45 +08:00
|
|
|
strbuf_release(&dir);
|
2017-06-15 02:07:37 +08:00
|
|
|
return -1;
|
2017-03-14 04:10:45 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The returned gitdir is relative to dir, and if dir does not reflect
|
|
|
|
* the current working directory, we simply make the gitdir absolute.
|
|
|
|
*/
|
|
|
|
if (dir.len < cwd_len && !is_absolute_path(gitdir->buf + gitdir_offset)) {
|
|
|
|
/* Avoid a trailing "/." */
|
|
|
|
if (!strcmp(".", gitdir->buf + gitdir_offset))
|
|
|
|
strbuf_setlen(gitdir, gitdir_offset);
|
|
|
|
else
|
|
|
|
strbuf_addch(&dir, '/');
|
|
|
|
strbuf_insert(gitdir, gitdir_offset, dir.buf, dir.len);
|
|
|
|
}
|
|
|
|
|
2017-06-15 02:07:37 +08:00
|
|
|
get_common_dir(commondir, gitdir->buf + gitdir_offset);
|
|
|
|
|
2017-03-14 04:10:45 +08:00
|
|
|
strbuf_reset(&dir);
|
2017-06-15 02:07:37 +08:00
|
|
|
strbuf_addf(&dir, "%s/config", commondir->buf + commondir_offset);
|
2017-03-14 04:10:45 +08:00
|
|
|
read_repository_format(&candidate, dir.buf);
|
|
|
|
strbuf_release(&dir);
|
|
|
|
|
|
|
|
if (verify_repository_format(&candidate, &err) < 0) {
|
|
|
|
warning("ignoring git dir '%s': %s",
|
|
|
|
gitdir->buf + gitdir_offset, err.buf);
|
|
|
|
strbuf_release(&err);
|
2017-06-15 02:07:37 +08:00
|
|
|
strbuf_setlen(commondir, commondir_offset);
|
2017-06-14 19:35:26 +08:00
|
|
|
strbuf_setlen(gitdir, gitdir_offset);
|
2017-06-15 02:07:37 +08:00
|
|
|
return -1;
|
2017-03-14 04:10:45 +08:00
|
|
|
}
|
|
|
|
|
2017-06-15 02:07:37 +08:00
|
|
|
return 0;
|
2017-03-14 04:10:45 +08:00
|
|
|
}
|
|
|
|
|
2010-08-06 10:46:33 +08:00
|
|
|
const char *setup_git_directory_gently(int *nongit_ok)
|
|
|
|
{
|
setup_git_directory_1(): avoid changing global state
For historical reasons, Git searches for the .git/ directory (or the
.git file) by changing the working directory successively to the parent
directory of the current directory, until either anything was found or
until a ceiling or a mount point is hit.
Further global state may be changed in case a .git/ directory was found.
We do have a use case, though, where we would like to find the .git/
directory without having any global state touched, though: when we read
the early config e.g. for the pager or for alias expansion.
Let's just move all of code that changes any global state out of the
function `setup_git_directory_gently_1()` into
`setup_git_directory_gently()`.
In subsequent patches, we will use the _1() function in a new
`discover_git_directory()` function that we will then use for the early
config code.
Note: the new loop is a *little* tricky, as we have to handle the root
directory specially: we cannot simply strip away the last component
including the slash, as the root directory only has that slash. To remedy
that, we introduce the `min_offset` variable that holds the minimal length
of an absolute path, and using that to special-case the root directory,
including an early exit before trying to find the parent of the root
directory.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-14 04:10:42 +08:00
|
|
|
static struct strbuf cwd = STRBUF_INIT;
|
|
|
|
struct strbuf dir = STRBUF_INIT, gitdir = STRBUF_INIT;
|
2017-08-03 03:49:23 +08:00
|
|
|
const char *prefix;
|
2010-08-06 10:46:33 +08:00
|
|
|
|
setup_git_directory_1(): avoid changing global state
For historical reasons, Git searches for the .git/ directory (or the
.git file) by changing the working directory successively to the parent
directory of the current directory, until either anything was found or
until a ceiling or a mount point is hit.
Further global state may be changed in case a .git/ directory was found.
We do have a use case, though, where we would like to find the .git/
directory without having any global state touched, though: when we read
the early config e.g. for the pager or for alias expansion.
Let's just move all of code that changes any global state out of the
function `setup_git_directory_gently_1()` into
`setup_git_directory_gently()`.
In subsequent patches, we will use the _1() function in a new
`discover_git_directory()` function that we will then use for the early
config code.
Note: the new loop is a *little* tricky, as we have to handle the root
directory specially: we cannot simply strip away the last component
including the slash, as the root directory only has that slash. To remedy
that, we introduce the `min_offset` variable that holds the minimal length
of an absolute path, and using that to special-case the root directory,
including an early exit before trying to find the parent of the root
directory.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-14 04:10:42 +08:00
|
|
|
/*
|
|
|
|
* We may have read an incomplete configuration before
|
|
|
|
* setting-up the git directory. If so, clear the cache so
|
|
|
|
* that the next queries to the configuration reload complete
|
|
|
|
* configuration (including the per-repo config file that we
|
|
|
|
* ignored previously).
|
|
|
|
*/
|
|
|
|
git_config_clear();
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Let's assume that we are in a git repository.
|
|
|
|
* If it turns out later that we are somewhere else, the value will be
|
|
|
|
* updated accordingly.
|
|
|
|
*/
|
|
|
|
if (nongit_ok)
|
|
|
|
*nongit_ok = 0;
|
|
|
|
|
|
|
|
if (strbuf_getcwd(&cwd))
|
|
|
|
die_errno(_("Unable to read current working directory"));
|
|
|
|
strbuf_addbuf(&dir, &cwd);
|
|
|
|
|
2017-03-14 04:11:22 +08:00
|
|
|
switch (setup_git_directory_gently_1(&dir, &gitdir, 1)) {
|
setup_git_directory_1(): avoid changing global state
For historical reasons, Git searches for the .git/ directory (or the
.git file) by changing the working directory successively to the parent
directory of the current directory, until either anything was found or
until a ceiling or a mount point is hit.
Further global state may be changed in case a .git/ directory was found.
We do have a use case, though, where we would like to find the .git/
directory without having any global state touched, though: when we read
the early config e.g. for the pager or for alias expansion.
Let's just move all of code that changes any global state out of the
function `setup_git_directory_gently_1()` into
`setup_git_directory_gently()`.
In subsequent patches, we will use the _1() function in a new
`discover_git_directory()` function that we will then use for the early
config code.
Note: the new loop is a *little* tricky, as we have to handle the root
directory specially: we cannot simply strip away the last component
including the slash, as the root directory only has that slash. To remedy
that, we introduce the `min_offset` variable that holds the minimal length
of an absolute path, and using that to special-case the root directory,
including an early exit before trying to find the parent of the root
directory.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-14 04:10:42 +08:00
|
|
|
case GIT_DIR_NONE:
|
|
|
|
prefix = NULL;
|
|
|
|
break;
|
|
|
|
case GIT_DIR_EXPLICIT:
|
|
|
|
prefix = setup_explicit_git_dir(gitdir.buf, &cwd, nongit_ok);
|
|
|
|
break;
|
|
|
|
case GIT_DIR_DISCOVERED:
|
|
|
|
if (dir.len < cwd.len && chdir(dir.buf))
|
|
|
|
die(_("Cannot change to '%s'"), dir.buf);
|
|
|
|
prefix = setup_discovered_git_dir(gitdir.buf, &cwd, dir.len,
|
|
|
|
nongit_ok);
|
|
|
|
break;
|
|
|
|
case GIT_DIR_BARE:
|
|
|
|
if (dir.len < cwd.len && chdir(dir.buf))
|
|
|
|
die(_("Cannot change to '%s'"), dir.buf);
|
|
|
|
prefix = setup_bare_git_dir(&cwd, dir.len, nongit_ok);
|
|
|
|
break;
|
|
|
|
case GIT_DIR_HIT_CEILING:
|
|
|
|
prefix = setup_nongit(cwd.buf, nongit_ok);
|
|
|
|
break;
|
|
|
|
case GIT_DIR_HIT_MOUNT_POINT:
|
|
|
|
if (nongit_ok) {
|
|
|
|
*nongit_ok = 1;
|
|
|
|
strbuf_release(&cwd);
|
|
|
|
strbuf_release(&dir);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
die(_("Not a git repository (or any parent up to mount point %s)\n"
|
|
|
|
"Stopping at filesystem boundary (GIT_DISCOVERY_ACROSS_FILESYSTEM not set)."),
|
|
|
|
dir.buf);
|
|
|
|
default:
|
|
|
|
die("BUG: unhandled setup_git_directory_1() result");
|
|
|
|
}
|
|
|
|
|
2011-05-26 11:37:12 +08:00
|
|
|
if (prefix)
|
2013-03-08 17:30:25 +08:00
|
|
|
setenv(GIT_PREFIX_ENVIRONMENT, prefix, 1);
|
2011-05-26 11:37:12 +08:00
|
|
|
else
|
2013-03-08 17:30:25 +08:00
|
|
|
setenv(GIT_PREFIX_ENVIRONMENT, "", 1);
|
2011-05-26 11:37:12 +08:00
|
|
|
|
setup: make startup_info available everywhere
Commit a60645f (setup: remember whether repository was
found, 2010-08-05) introduced the startup_info structure,
which records some parts of the setup_git_directory()
process (notably, whether we actually found a repository or
not).
One of the uses of this data is for functions to behave
appropriately based on whether we are in a repo. But the
startup_info struct is just a pointer to storage provided by
the main program, and the only program that sets it up is
the git.c wrapper. Thus builtins have access to
startup_info, but externally linked programs do not.
Worse, library code which is accessible from both has to be
careful about accessing startup_info. This can be used to
trigger a die("BUG") via get_sha1():
$ git fast-import <<-\EOF
tag foo
from HEAD:./whatever
EOF
fatal: BUG: startup_info struct is not initialized.
Obviously that's fairly nonsensical input to feed to
fast-import, but we should never hit a die("BUG"). And there
may be other ways to trigger it if other non-builtins
resolve sha1s.
So let's point the storage for startup_info to a static
variable in setup.c, making it available to all users of the
library code. We _could_ turn startup_info into a regular
extern struct, but doing so would mean tweaking all of the
existing use sites. So let's leave the pointer indirection
in place. We can, however, drop any checks for NULL, as
they will always be false (and likewise, we can drop the
test covering this case, which was a rather artificial
situation using one of the test-* programs).
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-03-06 06:10:27 +08:00
|
|
|
startup_info->have_repository = !nongit_ok || !*nongit_ok;
|
|
|
|
startup_info->prefix = prefix;
|
|
|
|
|
2017-06-21 03:19:32 +08:00
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*/
|
2017-06-23 02:43:33 +08:00
|
|
|
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();
|
|
|
|
}
|
|
|
|
}
|
2017-06-21 03:19:32 +08:00
|
|
|
|
setup_git_directory_1(): avoid changing global state
For historical reasons, Git searches for the .git/ directory (or the
.git file) by changing the working directory successively to the parent
directory of the current directory, until either anything was found or
until a ceiling or a mount point is hit.
Further global state may be changed in case a .git/ directory was found.
We do have a use case, though, where we would like to find the .git/
directory without having any global state touched, though: when we read
the early config e.g. for the pager or for alias expansion.
Let's just move all of code that changes any global state out of the
function `setup_git_directory_gently_1()` into
`setup_git_directory_gently()`.
In subsequent patches, we will use the _1() function in a new
`discover_git_directory()` function that we will then use for the early
config code.
Note: the new loop is a *little* tricky, as we have to handle the root
directory specially: we cannot simply strip away the last component
including the slash, as the root directory only has that slash. To remedy
that, we introduce the `min_offset` variable that holds the minimal length
of an absolute path, and using that to special-case the root directory,
including an early exit before trying to find the parent of the root
directory.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-14 04:10:42 +08:00
|
|
|
strbuf_release(&dir);
|
|
|
|
strbuf_release(&gitdir);
|
|
|
|
|
2010-08-06 10:46:33 +08:00
|
|
|
return prefix;
|
|
|
|
}
|
|
|
|
|
2006-06-10 14:09:49 +08:00
|
|
|
int git_config_perm(const char *var, const char *value)
|
|
|
|
{
|
2008-04-16 16:34:24 +08:00
|
|
|
int i;
|
|
|
|
char *endptr;
|
|
|
|
|
|
|
|
if (value == NULL)
|
|
|
|
return PERM_GROUP;
|
|
|
|
|
|
|
|
if (!strcmp(value, "umask"))
|
|
|
|
return PERM_UMASK;
|
|
|
|
if (!strcmp(value, "group"))
|
|
|
|
return PERM_GROUP;
|
|
|
|
if (!strcmp(value, "all") ||
|
|
|
|
!strcmp(value, "world") ||
|
|
|
|
!strcmp(value, "everybody"))
|
|
|
|
return PERM_EVERYBODY;
|
|
|
|
|
|
|
|
/* Parse octal numbers */
|
|
|
|
i = strtol(value, &endptr, 8);
|
|
|
|
|
|
|
|
/* If not an octal number, maybe true/false? */
|
|
|
|
if (*endptr != 0)
|
|
|
|
return git_config_bool(var, value) ? PERM_GROUP : PERM_UMASK;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Treat values 0, 1 and 2 as compatibility cases, otherwise it is
|
2009-03-26 07:19:36 +08:00
|
|
|
* a chmod value to restrict to.
|
2008-04-16 16:34:24 +08:00
|
|
|
*/
|
|
|
|
switch (i) {
|
|
|
|
case PERM_UMASK: /* 0 */
|
|
|
|
return PERM_UMASK;
|
|
|
|
case OLD_PERM_GROUP: /* 1 */
|
|
|
|
return PERM_GROUP;
|
|
|
|
case OLD_PERM_EVERYBODY: /* 2 */
|
|
|
|
return PERM_EVERYBODY;
|
2006-06-10 14:09:49 +08:00
|
|
|
}
|
2008-04-16 16:34:24 +08:00
|
|
|
|
|
|
|
/* A filemode value was given: 0xxx */
|
|
|
|
|
|
|
|
if ((i & 0600) != 0600)
|
2016-08-08 19:15:59 +08:00
|
|
|
die(_("Problem with core.sharedRepository filemode value "
|
2008-04-16 16:34:24 +08:00
|
|
|
"(0%.3o).\nThe owner of files must always have "
|
2016-08-08 19:15:59 +08:00
|
|
|
"read and write permissions."), i);
|
2008-04-16 16:34:24 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Mask filemode value. Others can not get write permission.
|
|
|
|
* x flags for directories are handled separately.
|
|
|
|
*/
|
2009-03-26 07:19:36 +08:00
|
|
|
return -(i & 0666);
|
2006-06-10 14:09:49 +08:00
|
|
|
}
|
|
|
|
|
2016-03-12 06:36:45 +08:00
|
|
|
void check_repository_format(void)
|
2005-11-26 07:59:09 +08:00
|
|
|
{
|
2016-03-06 06:11:34 +08:00
|
|
|
check_repository_format_gently(get_git_dir(), NULL);
|
|
|
|
startup_info->have_repository = 1;
|
2005-11-26 07:59:09 +08:00
|
|
|
}
|
|
|
|
|
2010-06-05 16:04:20 +08:00
|
|
|
/*
|
|
|
|
* Returns the "prefix", a path to the current working directory
|
|
|
|
* relative to the work tree root, or NULL, if the current working
|
|
|
|
* directory is not a strict subdirectory of the work tree root. The
|
|
|
|
* prefix always ends with a '/' character.
|
|
|
|
*/
|
2005-11-26 07:43:41 +08:00
|
|
|
const char *setup_git_directory(void)
|
|
|
|
{
|
2010-11-26 23:32:39 +08:00
|
|
|
return setup_git_directory_gently(NULL);
|
2005-11-26 07:43:41 +08:00
|
|
|
}
|
2011-08-16 05:17:46 +08:00
|
|
|
|
2017-01-25 07:56:49 +08:00
|
|
|
const char *resolve_gitdir_gently(const char *suspect, int *return_error_code)
|
2011-08-16 05:17:46 +08:00
|
|
|
{
|
|
|
|
if (is_git_directory(suspect))
|
|
|
|
return suspect;
|
2017-01-25 07:56:49 +08:00
|
|
|
return read_gitfile_gently(suspect, return_error_code);
|
2011-08-16 05:17:46 +08:00
|
|
|
}
|
2013-07-16 17:27:36 +08:00
|
|
|
|
|
|
|
/* if any standard file descriptor is missing open it to /dev/null */
|
|
|
|
void sanitize_stdfds(void)
|
|
|
|
{
|
|
|
|
int fd = open("/dev/null", O_RDWR, 0);
|
|
|
|
while (fd != -1 && fd < 2)
|
|
|
|
fd = dup(fd);
|
|
|
|
if (fd == -1)
|
|
|
|
die_errno("open /dev/null or dup failed");
|
|
|
|
if (fd > 2)
|
|
|
|
close(fd);
|
|
|
|
}
|
2014-02-08 15:08:51 +08:00
|
|
|
|
|
|
|
int daemonize(void)
|
|
|
|
{
|
|
|
|
#ifdef NO_POSIX_GOODIES
|
|
|
|
errno = ENOSYS;
|
|
|
|
return -1;
|
|
|
|
#else
|
|
|
|
switch (fork()) {
|
|
|
|
case 0:
|
|
|
|
break;
|
|
|
|
case -1:
|
|
|
|
die_errno("fork failed");
|
|
|
|
default:
|
|
|
|
exit(0);
|
|
|
|
}
|
|
|
|
if (setsid() == -1)
|
|
|
|
die_errno("setsid failed");
|
|
|
|
close(0);
|
|
|
|
close(1);
|
|
|
|
close(2);
|
|
|
|
sanitize_stdfds();
|
|
|
|
return 0;
|
|
|
|
#endif
|
|
|
|
}
|