summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: dace6e4)
raw | patch | inline | side by side (parent: dace6e4)
author | Matthias Lederhofer <matled@gmx.net> | |
Wed, 6 Jun 2007 07:10:42 +0000 (09:10 +0200) | ||
committer | Junio C Hamano <gitster@pobox.com> | |
Wed, 6 Jun 2007 23:07:53 +0000 (16:07 -0700) |
setup_gdg is used as abbreviation for setup_git_directory_gently.
The work tree can be specified using the environment variable
GIT_WORK_TREE and the config option core.worktree (the environment
variable has precendence over the config option). Additionally
there is a command line option --work-tree which sets the
environment variable.
setup_gdg does the following now:
GIT_DIR unspecified
repository in .git directory
parent directory of the .git directory is used as work tree,
GIT_WORK_TREE is ignored
GIT_DIR unspecified
repository in cwd
GIT_DIR is set to cwd
see the cases with GIT_DIR specified what happens next and
also see the note below
GIT_DIR specified
GIT_WORK_TREE/core.worktree unspecified
cwd is used as work tree
GIT_DIR specified
GIT_WORK_TREE/core.worktree specified
the specified work tree is used
Note on the case where GIT_DIR is unspecified and repository is in cwd:
GIT_WORK_TREE is used but is_inside_git_dir is always true.
I did it this way because setup_gdg might be called multiple
times (e.g. when doing alias expansion) and in successive calls
setup_gdg should do the same thing every time.
Meaning of is_bare/is_inside_work_tree/is_inside_git_dir:
(1) is_bare_repository
A repository is bare if core.bare is true or core.bare is
unspecified and the name suggests it is bare (directory not
named .git). The bare option disables a few protective
checks which are useful with a working tree. Currently
this changes if a repository is bare:
updates of HEAD are allowed
git gc packs the refs
the reflog is disabled by default
(2) is_inside_work_tree
True if the cwd is inside the associated working tree (if there
is one), false otherwise.
(3) is_inside_git_dir
True if the cwd is inside the git directory, false otherwise.
Before this patch is_inside_git_dir was always true for bare
repositories.
When setup_gdg finds a repository git_config(git_default_config) is
always called. This ensure that is_bare_repository makes use of
core.bare and does not guess even though core.bare is specified.
inside_work_tree and inside_git_dir are set if setup_gdg finds a
repository. The is_inside_work_tree and is_inside_git_dir functions
will die if they are called before a successful call to setup_gdg.
Signed-off-by: Matthias Lederhofer <matled@gmx.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
The work tree can be specified using the environment variable
GIT_WORK_TREE and the config option core.worktree (the environment
variable has precendence over the config option). Additionally
there is a command line option --work-tree which sets the
environment variable.
setup_gdg does the following now:
GIT_DIR unspecified
repository in .git directory
parent directory of the .git directory is used as work tree,
GIT_WORK_TREE is ignored
GIT_DIR unspecified
repository in cwd
GIT_DIR is set to cwd
see the cases with GIT_DIR specified what happens next and
also see the note below
GIT_DIR specified
GIT_WORK_TREE/core.worktree unspecified
cwd is used as work tree
GIT_DIR specified
GIT_WORK_TREE/core.worktree specified
the specified work tree is used
Note on the case where GIT_DIR is unspecified and repository is in cwd:
GIT_WORK_TREE is used but is_inside_git_dir is always true.
I did it this way because setup_gdg might be called multiple
times (e.g. when doing alias expansion) and in successive calls
setup_gdg should do the same thing every time.
Meaning of is_bare/is_inside_work_tree/is_inside_git_dir:
(1) is_bare_repository
A repository is bare if core.bare is true or core.bare is
unspecified and the name suggests it is bare (directory not
named .git). The bare option disables a few protective
checks which are useful with a working tree. Currently
this changes if a repository is bare:
updates of HEAD are allowed
git gc packs the refs
the reflog is disabled by default
(2) is_inside_work_tree
True if the cwd is inside the associated working tree (if there
is one), false otherwise.
(3) is_inside_git_dir
True if the cwd is inside the git directory, false otherwise.
Before this patch is_inside_git_dir was always true for bare
repositories.
When setup_gdg finds a repository git_config(git_default_config) is
always called. This ensure that is_bare_repository makes use of
core.bare and does not guess even though core.bare is specified.
inside_work_tree and inside_git_dir are set if setup_gdg finds a
repository. The is_inside_work_tree and is_inside_git_dir functions
will die if they are called before a successful call to setup_gdg.
Signed-off-by: Matthias Lederhofer <matled@gmx.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Documentation/config.txt | patch | blob | history | |
Documentation/git-rev-parse.txt | patch | blob | history | |
Documentation/git.txt | patch | blob | history | |
builtin-rev-parse.c | patch | blob | history | |
cache.h | patch | blob | history | |
connect.c | patch | blob | history | |
git.c | patch | blob | history | |
setup.c | patch | blob | history | |
t/test-lib.sh | patch | blob | history |
index 5868d587a905e0aaa55194c7716f9e258a030474..4d0bd37af9c74403b25e1d6bc1ae944791c3e179 100644 (file)
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
false), while all other repositories are assumed to be bare (bare
= true).
+core.worktree::
+ Set the path to the working tree. The value will not be
+ used in combination with repositories found automatically in
+ a .git directory (i.e. $GIT_DIR is not set).
+ This can be overriden by the GIT_WORK_TREE environment
+ variable and the '--work-tree' command line option.
+
core.logAllRefUpdates::
Updates to a ref <ref> is logged to the file
"$GIT_DIR/logs/<ref>", by appending the new and old
index c817d1614af01a11d60e50ab73f41ed2575f3d4a..6e4d15829d4607b9f5b1bafdbd616643266a2538 100644 (file)
When the current working directory is below the repository
directory print "true", otherwise "false".
+--is-inside-work-tree::
+ When the current working directory is inside the work tree of the
+ repository print "true", otherwise "false".
+
--is-bare-repository::
When the repository is bare print "true", otherwise "false".
diff --git a/Documentation/git.txt b/Documentation/git.txt
index 98860af0455ebb5290e7225e6ac677dc7ab3268c..4b567d8028ba78c3182e5416394786b5cded6b45 100644 (file)
--- a/Documentation/git.txt
+++ b/Documentation/git.txt
--------
[verse]
'git' [--version] [--exec-path[=GIT_EXEC_PATH]] [-p|--paginate]
- [--bare] [--git-dir=GIT_DIR] [--help] COMMAND [ARGS]
+ [--bare] [--git-dir=GIT_DIR] [--work-tree=GIT_WORK_TREE]
+ [--help] COMMAND [ARGS]
DESCRIPTION
-----------
Set the path to the repository. This can also be controlled by
setting the GIT_DIR environment variable.
+--work-tree=<path>::
+ Set the path to the working tree. The value will not be
+ used in combination with repositories found automatically in
+ a .git directory (i.e. $GIT_DIR is not set).
+ This can also be controlled by setting the GIT_WORK_TREE
+ environment variable and the core.worktree configuration
+ variable.
+
--bare::
Same as --git-dir=`pwd`.
specifies a path to use instead of the default `.git`
for the base of the repository.
+'GIT_WORK_TREE'::
+ Set the path to the working tree. The value will not be
+ used in combination with repositories found automatically in
+ a .git directory (i.e. $GIT_DIR is not set).
+ This can also be controlled by the '--work-tree' command line
+ option and the core.worktree configuration variable.
+
git Commits
~~~~~~~~~~~
'GIT_AUTHOR_NAME'::
diff --git a/builtin-rev-parse.c b/builtin-rev-parse.c
index 71d51625957ac7851be9a528ed561158ae9f7f93..497903a85a69288afc291ff49e32f7c80140beae 100644 (file)
--- a/builtin-rev-parse.c
+++ b/builtin-rev-parse.c
: "false");
continue;
}
+ if (!strcmp(arg, "--is-inside-work-tree")) {
+ printf("%s\n", is_inside_work_tree() ? "true"
+ : "false");
+ continue;
+ }
if (!strcmp(arg, "--is-bare-repository")) {
printf("%s\n", is_bare_repository() ? "true"
: "false");
index 8a9d1f3883150fd40ac1b6c0a44fa896c3133b04..ae1990a54ea9cd0171e4298af42101b374a932a2 100644 (file)
--- a/cache.h
+++ b/cache.h
};
#define GIT_DIR_ENVIRONMENT "GIT_DIR"
+#define GIT_WORK_TREE_ENVIRONMENT "GIT_WORK_TREE"
#define DEFAULT_GIT_DIR_ENVIRONMENT ".git"
#define DB_ENVIRONMENT "GIT_OBJECT_DIRECTORY"
#define INDEX_ENVIRONMENT "GIT_INDEX_FILE"
extern int is_bare_repository_cfg;
extern int is_bare_repository(void);
extern int is_inside_git_dir(void);
+extern int is_inside_work_tree(void);
extern const char *get_git_dir(void);
extern char *get_object_directory(void);
extern char *get_refs_directory(void);
diff --git a/connect.c b/connect.c
index 8cbda88dda02e7de74149af1b387e537f77bc497..aafa416229df08010203d948923c547eefe3e107 100644 (file)
--- a/connect.c
+++ b/connect.c
unsetenv(ALTERNATE_DB_ENVIRONMENT);
unsetenv(DB_ENVIRONMENT);
unsetenv(GIT_DIR_ENVIRONMENT);
+ unsetenv(GIT_WORK_TREE_ENVIRONMENT);
unsetenv(GRAFT_ENVIRONMENT);
unsetenv(INDEX_ENVIRONMENT);
execlp("sh", "sh", "-c", command, NULL);
index 29b55a16047837084fd9e2e8238137b8a2fe44ea..05a391b4d66fa9daa0ba1c4409eed1e8ee27be30 100644 (file)
--- a/git.c
+++ b/git.c
#include "quote.h"
const char git_usage_string[] =
- "git [--version] [--exec-path[=GIT_EXEC_PATH]] [-p|--paginate] [--bare] [--git-dir=GIT_DIR] [--help] COMMAND [ARGS]";
+ "git [--version] [--exec-path[=GIT_EXEC_PATH]] [-p|--paginate] [--bare] [--git-dir=GIT_DIR] [--work-tree=GIT_WORK_TREE] [--help] COMMAND [ARGS]";
static void prepend_to_path(const char *dir, int len)
{
handled++;
} else if (!prefixcmp(cmd, "--git-dir=")) {
setenv(GIT_DIR_ENVIRONMENT, cmd + 10, 1);
+ } else if (!strcmp(cmd, "--work-tree")) {
+ if (*argc < 2) {
+ fprintf(stderr, "No directory given for --work-tree.\n" );
+ usage(git_usage_string);
+ }
+ setenv(GIT_WORK_TREE_ENVIRONMENT, (*argv)[1], 1);
+ (*argv)++;
+ (*argc)--;
+ } else if (!prefixcmp(cmd, "--work-tree=")) {
+ setenv(GIT_WORK_TREE_ENVIRONMENT, cmd + 12, 1);
} else if (!strcmp(cmd, "--bare")) {
static char git_dir[PATH_MAX+1];
setenv(GIT_DIR_ENVIRONMENT, getcwd(git_dir, sizeof(git_dir)), 1);
index a45ea8309a9773160597f142f1208a6129885499..7e32de229dbbbabb812479cb42862bc111578b32 100644 (file)
--- a/setup.c
+++ b/setup.c
int is_inside_git_dir(void)
{
- if (inside_git_dir < 0) {
- char buffer[1024];
-
- if (is_bare_repository())
- return (inside_git_dir = 1);
- if (getcwd(buffer, sizeof(buffer))) {
- const char *git_dir = get_git_dir(), *cwd = buffer;
- while (*git_dir && *git_dir == *cwd) {
- git_dir++;
- cwd++;
- }
- inside_git_dir = !*git_dir;
- } else
- inside_git_dir = 0;
+ if (inside_git_dir >= 0)
+ return inside_git_dir;
+ die("BUG: is_inside_git_dir called before setup_git_directory");
+}
+
+static int inside_work_tree = -1;
+
+int is_inside_work_tree(void)
+{
+ if (inside_git_dir >= 0)
+ return inside_work_tree;
+ die("BUG: is_inside_work_tree called before setup_git_directory");
+}
+
+static char *gitworktree_config;
+
+static int git_setup_config(const char *var, const char *value)
+{
+ if (!strcmp(var, "core.worktree")) {
+ if (gitworktree_config)
+ strlcpy(gitworktree_config, value, PATH_MAX);
+ return 0;
}
- return inside_git_dir;
+ return git_default_config(var, value);
}
const char *setup_git_directory_gently(int *nongit_ok)
{
static char cwd[PATH_MAX+1];
- const char *gitdirenv;
- int len, offset;
+ char worktree[PATH_MAX+1], gitdir[PATH_MAX+1];
+ const char *gitdirenv, *gitworktree;
+ int wt_rel_gitdir = 0;
- /*
- * If GIT_DIR is set explicitly, we're not going
- * to do any discovery, but we still do repository
- * validation.
- */
gitdirenv = getenv(GIT_DIR_ENVIRONMENT);
- if (gitdirenv) {
- if (PATH_MAX - 40 < strlen(gitdirenv))
- die("'$%s' too big", GIT_DIR_ENVIRONMENT);
- if (is_git_directory(gitdirenv))
+ if (!gitdirenv) {
+ int len, offset;
+
+ if (!getcwd(cwd, sizeof(cwd)-1) || cwd[0] != '/')
+ die("Unable to read current working directory");
+
+ offset = len = strlen(cwd);
+ for (;;) {
+ if (is_git_directory(".git"))
+ break;
+ if (offset == 0) {
+ offset = -1;
+ break;
+ }
+ chdir("..");
+ while (cwd[--offset] != '/')
+ ; /* do nothing */
+ }
+
+ if (offset >= 0) {
+ inside_work_tree = 1;
+ git_config(git_default_config);
+ if (offset == len) {
+ inside_git_dir = 0;
+ return NULL;
+ }
+
+ cwd[len++] = '/';
+ cwd[len] = '\0';
+ inside_git_dir = !prefixcmp(cwd + offset + 1, ".git/");
+ return cwd + offset + 1;
+ }
+
+ if (chdir(cwd))
+ die("Cannot come back to cwd");
+ if (!is_git_directory(".")) {
+ if (nongit_ok) {
+ *nongit_ok = 1;
+ return NULL;
+ }
+ die("Not a git repository");
+ }
+ setenv(GIT_DIR_ENVIRONMENT, cwd, 1);
+ }
+
+ if (PATH_MAX - 40 < strlen(gitdirenv)) {
+ if (nongit_ok) {
+ *nongit_ok = 1;
return NULL;
+ }
+ die("$%s too big", GIT_DIR_ENVIRONMENT);
+ }
+ if (!is_git_directory(gitdirenv)) {
if (nongit_ok) {
*nongit_ok = 1;
return NULL;
if (!getcwd(cwd, sizeof(cwd)-1) || cwd[0] != '/')
die("Unable to read current working directory");
+ if (chdir(gitdirenv)) {
+ if (nongit_ok) {
+ *nongit_ok = 1;
+ return NULL;
+ }
+ die("Cannot change directory to $%s '%s'",
+ GIT_DIR_ENVIRONMENT, gitdirenv);
+ }
+ if (!getcwd(gitdir, sizeof(gitdir)-1) || gitdir[0] != '/')
+ die("Unable to read current working directory");
+ if (chdir(cwd))
+ die("Cannot come back to cwd");
- offset = len = strlen(cwd);
- for (;;) {
- if (is_git_directory(".git"))
- break;
- chdir("..");
- do {
- if (!offset) {
- if (is_git_directory(cwd)) {
- if (chdir(cwd))
- die("Cannot come back to cwd");
- setenv(GIT_DIR_ENVIRONMENT, cwd, 1);
- inside_git_dir = 1;
- return NULL;
- }
- if (nongit_ok) {
- if (chdir(cwd))
- die("Cannot come back to cwd");
- *nongit_ok = 1;
- return NULL;
- }
- die("Not a git repository");
+ /*
+ * In case there is a work tree we may change the directory,
+ * therefore make GIT_DIR an absolute path.
+ */
+ if (gitdirenv[0] != '/') {
+ setenv(GIT_DIR_ENVIRONMENT, gitdir, 1);
+ gitdirenv = getenv(GIT_DIR_ENVIRONMENT);
+ if (PATH_MAX - 40 < strlen(gitdirenv)) {
+ if (nongit_ok) {
+ *nongit_ok = 1;
+ return NULL;
}
- } while (cwd[--offset] != '/');
+ die("$%s too big after expansion to absolute path",
+ GIT_DIR_ENVIRONMENT);
+ }
+ }
+
+ strcat(cwd, "/");
+ strcat(gitdir, "/");
+ inside_git_dir = !prefixcmp(cwd, gitdir);
+
+ gitworktree = getenv(GIT_WORK_TREE_ENVIRONMENT);
+ if (!gitworktree) {
+ gitworktree_config = worktree;
+ worktree[0] = '\0';
+ }
+ git_config(git_setup_config);
+ if (!gitworktree) {
+ gitworktree_config = NULL;
+ if (worktree[0])
+ gitworktree = worktree;
+ if (gitworktree && gitworktree[0] != '/')
+ wt_rel_gitdir = 1;
+ }
+
+ if (wt_rel_gitdir && chdir(gitdirenv))
+ die("Cannot change directory to $%s '%s'",
+ GIT_DIR_ENVIRONMENT, gitdirenv);
+ if (gitworktree && chdir(gitworktree)) {
+ if (nongit_ok) {
+ if (wt_rel_gitdir && chdir(cwd))
+ die("Cannot come back to cwd");
+ *nongit_ok = 1;
+ return NULL;
+ }
+ if (wt_rel_gitdir)
+ die("Cannot change directory to working tree '%s'"
+ " from $%s", gitworktree, GIT_DIR_ENVIRONMENT);
+ else
+ die("Cannot change directory to working tree '%s'",
+ gitworktree);
}
+ if (!getcwd(worktree, sizeof(worktree)-1) || worktree[0] != '/')
+ die("Unable to read current working directory");
+ strcat(worktree, "/");
+ inside_work_tree = !prefixcmp(cwd, worktree);
- if (offset == len)
+ if (gitworktree && inside_work_tree && !prefixcmp(worktree, gitdir) &&
+ strcmp(worktree, gitdir)) {
+ inside_git_dir = 0;
+ }
+
+ if (!inside_work_tree) {
+ if (chdir(cwd))
+ die("Cannot come back to cwd");
return NULL;
+ }
- /* Make "offset" point to past the '/', and add a '/' at the end */
- offset++;
- cwd[len++] = '/';
- cwd[len] = 0;
- inside_git_dir = !prefixcmp(cwd + offset, ".git/");
- return cwd + offset;
+ if (!strcmp(cwd, worktree))
+ return NULL;
+ return cwd+strlen(worktree);
}
int git_config_perm(const char *var, const char *value)
diff --git a/t/test-lib.sh b/t/test-lib.sh
index dee3ad76212ea95c75c8287c8d8c0f312125bd06..b61e1d598de606a496cbc93345600bf8b380f426 100644 (file)
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
GIT_COMMITTER_NAME='C O Mitter'
unset GIT_DIFF_OPTS
unset GIT_DIR
+unset GIT_WORK_TREE
unset GIT_EXTERNAL_DIFF
unset GIT_INDEX_FILE
unset GIT_OBJECT_DIRECTORY