* [PATCH 1/7] rev-parse: document --is-inside-git-dir
2007-06-03 14:44 [RFC] GIT_WORK_TREE Matthias Lederhofer
@ 2007-06-03 14:46 ` Matthias Lederhofer
2007-06-03 14:46 ` [PATCH 2/7] rev-parse: introduce --is-bare-repository Matthias Lederhofer
` (7 subsequent siblings)
8 siblings, 0 replies; 22+ messages in thread
From: Matthias Lederhofer @ 2007-06-03 14:46 UTC (permalink / raw)
To: Git Mailing List, Nguyen Thai Ngoc Duy
Signed-off-by: Matthias Lederhofer <matled@gmx.net>
---
Documentation/git-rev-parse.txt | 4 ++++
1 files changed, 4 insertions(+), 0 deletions(-)
diff --git a/Documentation/git-rev-parse.txt b/Documentation/git-rev-parse.txt
index 7757abe..5fcec19 100644
--- a/Documentation/git-rev-parse.txt
+++ b/Documentation/git-rev-parse.txt
@@ -89,6 +89,10 @@ OPTIONS
--git-dir::
Show `$GIT_DIR` if defined else show the path to the .git directory.
+--is-inside-git-dir::
+ When the current working directory is below the repository
+ directory print "true", otherwise "false".
+
--short, --short=number::
Instead of outputting the full SHA1 values of object names try to
abbreviate them to a shorter unique name. When no length is specified
--
1.5.0.3
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH 2/7] rev-parse: introduce --is-bare-repository
2007-06-03 14:44 [RFC] GIT_WORK_TREE Matthias Lederhofer
2007-06-03 14:46 ` [PATCH 1/7] rev-parse: document --is-inside-git-dir Matthias Lederhofer
@ 2007-06-03 14:46 ` Matthias Lederhofer
2007-06-03 14:47 ` [PATCH 3/7] test git rev-parse Matthias Lederhofer
` (6 subsequent siblings)
8 siblings, 0 replies; 22+ messages in thread
From: Matthias Lederhofer @ 2007-06-03 14:46 UTC (permalink / raw)
To: Git Mailing List, Nguyen Thai Ngoc Duy
Signed-off-by: Matthias Lederhofer <matled@gmx.net>
---
Documentation/git-rev-parse.txt | 3 +++
builtin-rev-parse.c | 5 +++++
git-sh-setup.sh | 6 +-----
git-svn.perl | 3 +--
4 files changed, 10 insertions(+), 7 deletions(-)
diff --git a/Documentation/git-rev-parse.txt b/Documentation/git-rev-parse.txt
index 5fcec19..c817d16 100644
--- a/Documentation/git-rev-parse.txt
+++ b/Documentation/git-rev-parse.txt
@@ -93,6 +93,9 @@ OPTIONS
When the current working directory is below the repository
directory print "true", otherwise "false".
+--is-bare-repository::
+ When the repository is bare print "true", otherwise "false".
+
--short, --short=number::
Instead of outputting the full SHA1 values of object names try to
abbreviate them to a shorter unique name. When no length is specified
diff --git a/builtin-rev-parse.c b/builtin-rev-parse.c
index 37addb2..71d5162 100644
--- a/builtin-rev-parse.c
+++ b/builtin-rev-parse.c
@@ -352,6 +352,11 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
: "false");
continue;
}
+ if (!strcmp(arg, "--is-bare-repository")) {
+ printf("%s\n", is_bare_repository() ? "true"
+ : "false");
+ continue;
+ }
if (!prefixcmp(arg, "--since=")) {
show_datestring("--max-age=", arg+8);
continue;
diff --git a/git-sh-setup.sh b/git-sh-setup.sh
index f24c7f2..9ac657a 100755
--- a/git-sh-setup.sh
+++ b/git-sh-setup.sh
@@ -29,11 +29,7 @@ set_reflog_action() {
}
is_bare_repository () {
- git-config --bool --get core.bare ||
- case "$GIT_DIR" in
- .git | */.git) echo false ;;
- *) echo true ;;
- esac
+ git-rev-parse --is-bare-repository
}
cd_to_toplevel () {
diff --git a/git-svn.perl b/git-svn.perl
index e350061..e3a5cbb 100755
--- a/git-svn.perl
+++ b/git-svn.perl
@@ -594,8 +594,7 @@ sub post_fetch_checkout {
my $index = $ENV{GIT_INDEX_FILE} || "$ENV{GIT_DIR}/index";
return if -f $index;
- chomp(my $bare = `git config --bool --get core.bare`);
- return if $bare eq 'true';
+ return if command_oneline(qw/rev-parse --is-bare-repository/) eq 'true';
return if command_oneline(qw/rev-parse --is-inside-git-dir/) eq 'true';
command_noisy(qw/read-tree -m -u -v HEAD HEAD/);
print STDERR "Checked out HEAD:\n ",
--
1.5.0.3
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH 3/7] test git rev-parse
2007-06-03 14:44 [RFC] GIT_WORK_TREE Matthias Lederhofer
2007-06-03 14:46 ` [PATCH 1/7] rev-parse: document --is-inside-git-dir Matthias Lederhofer
2007-06-03 14:46 ` [PATCH 2/7] rev-parse: introduce --is-bare-repository Matthias Lederhofer
@ 2007-06-03 14:47 ` Matthias Lederhofer
2007-06-06 7:01 ` [PATCH 3/7 (amend)] " Matthias Lederhofer
2007-06-03 14:47 ` [PATCH 4/7] introduce GIT_WORK_TREE to specify the work tree Matthias Lederhofer
` (5 subsequent siblings)
8 siblings, 1 reply; 22+ messages in thread
From: Matthias Lederhofer @ 2007-06-03 14:47 UTC (permalink / raw)
To: Git Mailing List, Nguyen Thai Ngoc Duy
Signed-off-by: Matthias Lederhofer <matled@gmx.net>
---
t/t1500-rev-parse.sh | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 58 insertions(+), 0 deletions(-)
create mode 100755 t/t1500-rev-parse.sh
diff --git a/t/t1500-rev-parse.sh b/t/t1500-rev-parse.sh
new file mode 100755
index 0000000..a180309
--- /dev/null
+++ b/t/t1500-rev-parse.sh
@@ -0,0 +1,58 @@
+#!/bin/sh
+
+test_description='test git rev-parse'
+. ./test-lib.sh
+
+test_rev_parse() {
+ name=$1
+ shift
+
+ test_expect_success "$name: is-bare-repository" \
+ "test '$1' = \"\$(git rev-parse --is-bare-repository)\""
+ shift
+ [ $# -eq 0 ] && return
+
+ test_expect_success "$name: is-inside-git-dir" \
+ "test '$1' = \"\$(git rev-parse --is-inside-git-dir)\""
+ shift
+ [ $# -eq 0 ] && return
+
+ test_expect_success "$name: prefix" \
+ "test '$1' = \"\$(git rev-parse --show-prefix)\""
+ shift
+ [ $# -eq 0 ] && return
+}
+
+test_rev_parse toplevel false false ''
+
+cd .git || exit 1
+test_rev_parse .git/ false true .git/
+cd objects || exit 1
+test_rev_parse .git/objects/ false true .git/objects/
+cd ../.. || exit 1
+
+mkdir -p sub/dir || exit 1
+cd sub/dir || exit 1
+test_rev_parse subdirectory false false sub/dir/
+cd ../.. || exit 1
+
+git config core.bare true
+test_rev_parse 'core.bare = true' true
+
+git config --unset core.bare
+test_rev_parse 'core.bare undefined' false
+
+mv .git foo.git || exit 1
+export GIT_DIR=foo.git
+export GIT_CONFIG=foo.git/config
+
+git config core.bare true
+test_rev_parse 'GIT_DIR=foo.git, core.bare = true' true
+
+git config core.bare false
+test_rev_parse 'GIT_DIR=foo.git, core.bare = false' false
+
+git config --unset core.bare
+test_rev_parse 'GIT_DIR=foo.git, core.bare undefined' true
+
+test_done
--
1.5.0.3
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH 3/7 (amend)] test git rev-parse
2007-06-03 14:47 ` [PATCH 3/7] test git rev-parse Matthias Lederhofer
@ 2007-06-06 7:01 ` Matthias Lederhofer
0 siblings, 0 replies; 22+ messages in thread
From: Matthias Lederhofer @ 2007-06-06 7:01 UTC (permalink / raw)
To: Git Mailing List
Signed-off-by: Matthias Lederhofer <matled@gmx.net>
---
The amended version has a new test:
When GIT_DIR is set and the repository is not bare the current working
directory should be used as working tree.
---
t/t1500-rev-parse.sh | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 72 insertions(+), 0 deletions(-)
create mode 100755 t/t1500-rev-parse.sh
diff --git a/t/t1500-rev-parse.sh b/t/t1500-rev-parse.sh
new file mode 100755
index 0000000..66b0e58
--- /dev/null
+++ b/t/t1500-rev-parse.sh
@@ -0,0 +1,72 @@
+#!/bin/sh
+
+test_description='test git rev-parse'
+. ./test-lib.sh
+
+test_rev_parse() {
+ name=$1
+ shift
+
+ test_expect_success "$name: is-bare-repository" \
+ "test '$1' = \"\$(git rev-parse --is-bare-repository)\""
+ shift
+ [ $# -eq 0 ] && return
+
+ test_expect_success "$name: is-inside-git-dir" \
+ "test '$1' = \"\$(git rev-parse --is-inside-git-dir)\""
+ shift
+ [ $# -eq 0 ] && return
+
+ test_expect_success "$name: prefix" \
+ "test '$1' = \"\$(git rev-parse --show-prefix)\""
+ shift
+ [ $# -eq 0 ] && return
+}
+
+test_rev_parse toplevel false false ''
+
+cd .git || exit 1
+test_rev_parse .git/ false true .git/
+cd objects || exit 1
+test_rev_parse .git/objects/ false true .git/objects/
+cd ../.. || exit 1
+
+mkdir -p sub/dir || exit 1
+cd sub/dir || exit 1
+test_rev_parse subdirectory false false sub/dir/
+cd ../.. || exit 1
+
+git config core.bare true
+test_rev_parse 'core.bare = true' true
+
+git config --unset core.bare
+test_rev_parse 'core.bare undefined' false
+
+mkdir work || exit 1
+cd work || exit 1
+export GIT_DIR=../.git
+export GIT_CONFIG="$GIT_DIR"/config
+
+git config core.bare false
+test_rev_parse 'GIT_DIR=../.git, core.bare = false' false false ''
+
+git config core.bare true
+test_rev_parse 'GIT_DIR=../.git, core.bare = true' true
+
+git config --unset core.bare
+test_rev_parse 'GIT_DIR=../.git, core.bare undefined' false false ''
+
+mv ../.git ../repo.git || exit 1
+export GIT_DIR=../repo.git
+export GIT_CONFIG="$GIT_DIR"/config
+
+git config core.bare false
+test_rev_parse 'GIT_DIR=../repo.git, core.bare = false' false false ''
+
+git config core.bare true
+test_rev_parse 'GIT_DIR=../repo.git, core.bare = true' true
+
+git config --unset core.bare
+test_rev_parse 'GIT_DIR=../repo.git, core.bare undefined' true
+
+test_done
--
1.5.2.1.116.g9f308
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH 4/7] introduce GIT_WORK_TREE to specify the work tree
2007-06-03 14:44 [RFC] GIT_WORK_TREE Matthias Lederhofer
` (2 preceding siblings ...)
2007-06-03 14:47 ` [PATCH 3/7] test git rev-parse Matthias Lederhofer
@ 2007-06-03 14:47 ` Matthias Lederhofer
2007-06-05 7:52 ` Junio C Hamano
2007-06-06 7:10 ` [PATCH 4/7 (amend)] introduce GIT_WORK_TREE to specify the work tree Matthias Lederhofer
2007-06-03 14:48 ` [RFC] GIT_WORK_TREE Matthias Lederhofer
` (4 subsequent siblings)
8 siblings, 2 replies; 22+ messages in thread
From: Matthias Lederhofer @ 2007-06-03 14:47 UTC (permalink / raw)
To: Git Mailing List, Nguyen Thai Ngoc Duy
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
repository is bare (config or guessing)
no work tree is used
GIT_DIR specified
GIT_WORK_TREE/core.worktree unspecified
repository is not bare (config or guessing)
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). In general a bare repository is intended to be
used without a work tree. If such a repository is used with a
work tree anyway some protection mechanisms which are useful
with a work tree are disabled. Currently this changes if a
repository is bare:
updates of HEAD are allowed
git gc packs the refs
the reflog is disabled by default
cwd is not used as fallback work tree
(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>
---
Documentation/config.txt | 7 ++
Documentation/git-rev-parse.txt | 4 +
Documentation/git.txt | 18 +++-
builtin-rev-parse.c | 5 +
cache.h | 2 +
connect.c | 1 +
git.c | 12 ++-
setup.c | 217 +++++++++++++++++++++++++++++----------
t/test-lib.sh | 1 +
9 files changed, 210 insertions(+), 57 deletions(-)
diff --git a/Documentation/config.txt b/Documentation/config.txt
index 5868d58..4d0bd37 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -172,6 +172,13 @@ repository that ends in "/.git" is assumed to be not bare (bare =
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
diff --git a/Documentation/git-rev-parse.txt b/Documentation/git-rev-parse.txt
index c817d16..6e4d158 100644
--- a/Documentation/git-rev-parse.txt
+++ b/Documentation/git-rev-parse.txt
@@ -93,6 +93,10 @@ OPTIONS
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 98860af..4b567d8 100644
--- a/Documentation/git.txt
+++ b/Documentation/git.txt
@@ -10,7 +10,8 @@ SYNOPSIS
--------
[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
-----------
@@ -101,6 +102,14 @@ OPTIONS
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`.
@@ -345,6 +354,13 @@ git so take care if using Cogito etc.
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 71d5162..497903a 100644
--- a/builtin-rev-parse.c
+++ b/builtin-rev-parse.c
@@ -352,6 +352,11 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
: "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");
diff --git a/cache.h b/cache.h
index 8a9d1f3..ae1990a 100644
--- a/cache.h
+++ b/cache.h
@@ -192,6 +192,7 @@ enum object_type {
};
#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"
@@ -207,6 +208,7 @@ enum object_type {
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 8cbda88..aafa416 100644
--- a/connect.c
+++ b/connect.c
@@ -589,6 +589,7 @@ pid_t git_connect(int fd[2], char *url, const char *prog, int flags)
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);
diff --git a/git.c b/git.c
index 29b55a1..05a391b 100644
--- a/git.c
+++ b/git.c
@@ -4,7 +4,7 @@
#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)
{
@@ -69,6 +69,16 @@ static int handle_options(const char*** argv, int* argc)
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);
diff --git a/setup.c b/setup.c
index a45ea83..4856232 100644
--- a/setup.c
+++ b/setup.c
@@ -174,41 +174,93 @@ static int inside_git_dir = -1;
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;
@@ -218,41 +270,96 @@ const char *setup_git_directory_gently(int *nongit_ok)
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 (offset == len)
+ /* stop if the repository is bare and does not have a work tree */
+ if (!gitworktree && is_bare_repository()) {
+ inside_work_tree = 0;
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 (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 (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;
+ }
+
+ 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 dee3ad7..b61e1d5 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -26,6 +26,7 @@ GIT_COMMITTER_EMAIL=committer@example.com
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
--
1.5.0.3
^ permalink raw reply related [flat|nested] 22+ messages in thread
* Re: [PATCH 4/7] introduce GIT_WORK_TREE to specify the work tree
2007-06-03 14:47 ` [PATCH 4/7] introduce GIT_WORK_TREE to specify the work tree Matthias Lederhofer
@ 2007-06-05 7:52 ` Junio C Hamano
2007-06-05 16:49 ` [PATCH] filter-branch: always export GIT_DIR if it is set Matthias Lederhofer
2007-06-06 7:10 ` [PATCH 4/7 (amend)] introduce GIT_WORK_TREE to specify the work tree Matthias Lederhofer
1 sibling, 1 reply; 22+ messages in thread
From: Junio C Hamano @ 2007-06-05 7:52 UTC (permalink / raw)
To: Matthias Lederhofer; +Cc: Git Mailing List, Nguyen Thai Ngoc Duy
Hmph.
When this series is applied on top of 'next' (or whatever
contains t7003-filter-branch.sh), this seems to break it quite
badly.
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH] filter-branch: always export GIT_DIR if it is set
2007-06-05 7:52 ` Junio C Hamano
@ 2007-06-05 16:49 ` Matthias Lederhofer
2007-06-05 17:27 ` Johannes Schindelin
2007-06-06 7:16 ` [PATCH (amend)] " Matthias Lederhofer
0 siblings, 2 replies; 22+ messages in thread
From: Matthias Lederhofer @ 2007-06-05 16:49 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git
Currently filter-branch exports GIT_DIR only if it is a
relative path but git-sh-setup might also set GIT_DIR to an
absolute path that is not exported yet. Additionally we need
to export GIT_WORK_TREE with GIT_DIR to ensure that the
current working directory is used as working tree even for
bare repositories.
Signed-off-by: Matthias Lederhofer <matled@gmx.net>
---
Junio C Hamano <gitster@pobox.com> wrote:
> Hmph.
>
> When this series is applied on top of 'next' (or whatever
> contains t7003-filter-branch.sh), this seems to break it quite
> badly.
With the GIT_WORK_TREE patch series a relative path in GIT_DIR is
expanded to an absolute path. Therefore
GIT_DIR=$(GIT_DIR=.git git rev-parse --git-dir)
in git-sh-setup will give the full path to the repository.
git-filter-branch exports GIT_DIR only if the path is relative. In
consequence GIT_DIR was not set at all and the following git commands
failed. Additionally GIT_WORK_TREE has to be exported because to make
sure that the current directory is used as working tree even for bare
repositories.
I merged the worktree branch to next and applied the patch, all tests
passed.
This problem reveals a small change which might cause trouble with other
scripts. I looked at the git repository and found no other script which
should have problems with this series. With
$ git grep -e export --and -e GIT_DIR
I found:
Documentation/install-doc-quick.sh
git-clone.sh
git-instaweb.sh
These do not need a working tree.
git-cvsexportcommit.perl
git apply is used with GIT_DIR='', this forces git-apply not to
use the git repository.
I'm not sure if any other script out there tries to do this. Perhaps we
should just keep the old behaviour and use the current directory as
working tree when the repository name ends in /.git even though
core.bare is true?
---
git-filter-branch.sh | 3 +++
1 files changed, 3 insertions(+), 0 deletions(-)
diff --git a/git-filter-branch.sh b/git-filter-branch.sh
index 0c8a7df..f4cfbea 100644
--- a/git-filter-branch.sh
+++ b/git-filter-branch.sh
@@ -313,9 +313,12 @@ workdir="$(pwd)"
case "$GIT_DIR" in
/*)
+ export GIT_DIR
+ export GIT_WORK_TREE=.
;;
*)
export GIT_DIR="$(pwd)/../../$GIT_DIR"
+ export GIT_WORK_TREE=.
;;
esac
--
1.5.2.1.120.g3877-dirty
^ permalink raw reply related [flat|nested] 22+ messages in thread
* Re: [PATCH] filter-branch: always export GIT_DIR if it is set
2007-06-05 16:49 ` [PATCH] filter-branch: always export GIT_DIR if it is set Matthias Lederhofer
@ 2007-06-05 17:27 ` Johannes Schindelin
2007-06-05 20:39 ` Junio C Hamano
2007-06-06 7:16 ` [PATCH (amend)] " Matthias Lederhofer
1 sibling, 1 reply; 22+ messages in thread
From: Johannes Schindelin @ 2007-06-05 17:27 UTC (permalink / raw)
To: Matthias Lederhofer; +Cc: Junio C Hamano, git
Hi,
On Tue, 5 Jun 2007, Matthias Lederhofer wrote:
> diff --git a/git-filter-branch.sh b/git-filter-branch.sh
> index 0c8a7df..f4cfbea 100644
> --- a/git-filter-branch.sh
> +++ b/git-filter-branch.sh
> @@ -313,9 +313,12 @@ workdir="$(pwd)"
>
> case "$GIT_DIR" in
> /*)
> + export GIT_DIR
> + export GIT_WORK_TREE=.
> ;;
Doesn't it strike somebody else as intrusive, if GIT_WORK_TREE has to
touch that many places?
IMHO there should be a less intrusive, and possibly simpler, way to do it.
I am not at all interested in that feature, and I don't want to suffer
bugs from it either.
Ciao,
Dscho
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH] filter-branch: always export GIT_DIR if it is set
2007-06-05 17:27 ` Johannes Schindelin
@ 2007-06-05 20:39 ` Junio C Hamano
0 siblings, 0 replies; 22+ messages in thread
From: Junio C Hamano @ 2007-06-05 20:39 UTC (permalink / raw)
To: Matthias Lederhofer; +Cc: Johannes Schindelin, git
Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:
> On Tue, 5 Jun 2007, Matthias Lederhofer wrote:
>
>> diff --git a/git-filter-branch.sh b/git-filter-branch.sh
>> index 0c8a7df..f4cfbea 100644
>> --- a/git-filter-branch.sh
>> +++ b/git-filter-branch.sh
>> @@ -313,9 +313,12 @@ workdir="$(pwd)"
>>
>> case "$GIT_DIR" in
>> /*)
>> + export GIT_DIR
>> + export GIT_WORK_TREE=.
>> ;;
>
> Doesn't it strike somebody else as intrusive, if GIT_WORK_TREE has to
> touch that many places?
>
> IMHO there should be a less intrusive, and possibly simpler, way to do it.
> I am not at all interested in that feature, and I don't want to suffer
> bugs from it either.
I suspect "bug" might be a bit too strong a word here, but this
definitely shows that work-tree series has a change of behaviour
that is subtle on the suface but with a huge impact.
It _might_ a bug for filter-branch to export GIT_DIR; sh-setup
deliberately chooses _not_ to export it. I haven't really
thought through the issues, though...
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH (amend)] filter-branch: always export GIT_DIR if it is set
2007-06-05 16:49 ` [PATCH] filter-branch: always export GIT_DIR if it is set Matthias Lederhofer
2007-06-05 17:27 ` Johannes Schindelin
@ 2007-06-06 7:16 ` Matthias Lederhofer
1 sibling, 0 replies; 22+ messages in thread
From: Matthias Lederhofer @ 2007-06-06 7:16 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git
Currently filter-branch exports GIT_DIR only if it is an
relative path but git-sh-setup might also set GIT_DIR to an
absolute path that is not exported yet. Additionally export
GIT_WORK_TREE with GIT_DIR to ensure that cwd is used as
working tree even for bare repositories.
Signed-off-by: Matthias Lederhofer <matled@gmx.net>
---
The last one was a bit bloated :)
---
git-filter-branch.sh | 3 ++-
1 files changed, 2 insertions(+), 1 deletions(-)
diff --git a/git-filter-branch.sh b/git-filter-branch.sh
index 0c8a7df..acd52bd 100644
--- a/git-filter-branch.sh
+++ b/git-filter-branch.sh
@@ -315,9 +315,10 @@ case "$GIT_DIR" in
/*)
;;
*)
- export GIT_DIR="$(pwd)/../../$GIT_DIR"
+ GIT_DIR="$(pwd)/../../$GIT_DIR"
;;
esac
+export GIT_DIR GIT_WORK_TREE=.
export GIT_INDEX_FILE="$(pwd)/../index"
git-read-tree # seed the index file
--
1.5.2.1.116.g9f308
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH 4/7 (amend)] introduce GIT_WORK_TREE to specify the work tree
2007-06-03 14:47 ` [PATCH 4/7] introduce GIT_WORK_TREE to specify the work tree Matthias Lederhofer
2007-06-05 7:52 ` Junio C Hamano
@ 2007-06-06 7:10 ` Matthias Lederhofer
1 sibling, 0 replies; 22+ messages in thread
From: Matthias Lederhofer @ 2007-06-06 7:10 UTC (permalink / raw)
To: Git Mailing List
Dscho, Junio and me discussed about this in #git and it seems that the
best way to handle GIT_DIR is to use the current working directory as
fallback for the working tree always, ignoring if the repository is
bare. With this change all scripts that worked before this series
should still work as long as the user does not set GIT_WORK_TREE or
core.worktree.
With this series scripts which want to use a specific repository with
a specific working tree should just set GIT_DIR and GIT_WORK_TREE.
This tells git explicitly which directory should be used as work tree.
The problem before this change was:
Some scripts export GIT_DIR (set by git-sh-setup) and expect that the
current working directory is used as working tree after this. This
did not work anymore if the repository was bare. Even before the
patch series there were cases where this did not work but after this
change to the patch the new behaviour should be less strict.
-----8<-----
introduce GIT_WORK_TREE to specify the work tree
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
cwd is not used as fallback work tree
(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>
---
Documentation/config.txt | 7 ++
Documentation/git-rev-parse.txt | 4 +
Documentation/git.txt | 18 +++-
builtin-rev-parse.c | 5 +
cache.h | 2 +
connect.c | 1 +
git.c | 12 ++-
setup.c | 211 +++++++++++++++++++++++++++++----------
t/test-lib.sh | 1 +
9 files changed, 204 insertions(+), 57 deletions(-)
diff --git a/Documentation/config.txt b/Documentation/config.txt
index 5868d58..4d0bd37 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -172,6 +172,13 @@ repository that ends in "/.git" is assumed to be not bare (bare =
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
diff --git a/Documentation/git-rev-parse.txt b/Documentation/git-rev-parse.txt
index c817d16..6e4d158 100644
--- a/Documentation/git-rev-parse.txt
+++ b/Documentation/git-rev-parse.txt
@@ -93,6 +93,10 @@ OPTIONS
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 98860af..4b567d8 100644
--- a/Documentation/git.txt
+++ b/Documentation/git.txt
@@ -10,7 +10,8 @@ SYNOPSIS
--------
[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
-----------
@@ -101,6 +102,14 @@ OPTIONS
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`.
@@ -345,6 +354,13 @@ git so take care if using Cogito etc.
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 71d5162..497903a 100644
--- a/builtin-rev-parse.c
+++ b/builtin-rev-parse.c
@@ -352,6 +352,11 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
: "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");
diff --git a/cache.h b/cache.h
index 8a9d1f3..ae1990a 100644
--- a/cache.h
+++ b/cache.h
@@ -192,6 +192,7 @@ enum object_type {
};
#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"
@@ -207,6 +208,7 @@ enum object_type {
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 8cbda88..aafa416 100644
--- a/connect.c
+++ b/connect.c
@@ -589,6 +589,7 @@ pid_t git_connect(int fd[2], char *url, const char *prog, int flags)
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);
diff --git a/git.c b/git.c
index 29b55a1..05a391b 100644
--- a/git.c
+++ b/git.c
@@ -4,7 +4,7 @@
#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)
{
@@ -69,6 +69,16 @@ static int handle_options(const char*** argv, int* argc)
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);
diff --git a/setup.c b/setup.c
index a45ea83..7e32de2 100644
--- a/setup.c
+++ b/setup.c
@@ -174,41 +174,93 @@ static int inside_git_dir = -1;
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;
@@ -218,41 +270,90 @@ const char *setup_git_directory_gently(int *nongit_ok)
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 dee3ad7..b61e1d5 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -26,6 +26,7 @@ GIT_COMMITTER_EMAIL=committer@example.com
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
--
1.5.2.1.116.g9f308
^ permalink raw reply related [flat|nested] 22+ messages in thread
* Re: [RFC] GIT_WORK_TREE
2007-06-03 14:44 [RFC] GIT_WORK_TREE Matthias Lederhofer
` (3 preceding siblings ...)
2007-06-03 14:47 ` [PATCH 4/7] introduce GIT_WORK_TREE to specify the work tree Matthias Lederhofer
@ 2007-06-03 14:48 ` Matthias Lederhofer
2007-06-03 14:51 ` Matthias Lederhofer
2007-06-03 14:48 ` [PATCH 6/7] extend rev-parse test for --is-inside-work-tree Matthias Lederhofer
` (3 subsequent siblings)
8 siblings, 1 reply; 22+ messages in thread
From: Matthias Lederhofer @ 2007-06-03 14:48 UTC (permalink / raw)
To: Git Mailing List, Nguyen Thai Ngoc Duy
Up to now to check for a working tree this was used:
!is_bare && !inside_git_dir
(the check for bare is redundant because is_inside_git_dir
returned already 1 for bare repositories).
Now the check is:
inside_work_tree && !inside_git_dir
Signed-off-by: Matthias Lederhofer <matled@gmx.net>
---
builtin-ls-files.c | 2 +-
git-sh-setup.sh | 2 +-
git-svn.perl | 2 +-
git.c | 20 ++++++++++----------
setup.c | 2 +-
5 files changed, 14 insertions(+), 14 deletions(-)
diff --git a/builtin-ls-files.c b/builtin-ls-files.c
index f7c066b..48a3135 100644
--- a/builtin-ls-files.c
+++ b/builtin-ls-files.c
@@ -470,7 +470,7 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix)
}
if (require_work_tree &&
- (is_bare_repository() || is_inside_git_dir()))
+ (!is_inside_work_tree() || is_inside_git_dir()))
die("This operation must be run in a work tree");
pathspec = get_pathspec(prefix, argv + i);
diff --git a/git-sh-setup.sh b/git-sh-setup.sh
index 9ac657a..0de49e8 100755
--- a/git-sh-setup.sh
+++ b/git-sh-setup.sh
@@ -44,7 +44,7 @@ cd_to_toplevel () {
}
require_work_tree () {
- test $(is_bare_repository) = false &&
+ test $(git-rev-parse --is-inside-work-tree) = true &&
test $(git-rev-parse --is-inside-git-dir) = false ||
die "fatal: $0 cannot be used without a working tree."
}
diff --git a/git-svn.perl b/git-svn.perl
index e3a5cbb..886b898 100755
--- a/git-svn.perl
+++ b/git-svn.perl
@@ -594,7 +594,7 @@ sub post_fetch_checkout {
my $index = $ENV{GIT_INDEX_FILE} || "$ENV{GIT_DIR}/index";
return if -f $index;
- return if command_oneline(qw/rev-parse --is-bare-repository/) eq 'true';
+ return if command_oneline(qw/rev-parse --is-inside-work-tree/) eq 'false';
return if command_oneline(qw/rev-parse --is-inside-git-dir/) eq 'true';
command_noisy(qw/read-tree -m -u -v HEAD HEAD/);
print STDERR "Checked out HEAD:\n ",
diff --git a/git.c b/git.c
index 05a391b..cd3910a 100644
--- a/git.c
+++ b/git.c
@@ -224,7 +224,7 @@ const char git_version_string[] = GIT_VERSION;
* require working tree to be present -- anything uses this needs
* RUN_SETUP for reading from the configuration file.
*/
-#define NOT_BARE (1<<2)
+#define NEED_WORK_TREE (1<<2)
static void handle_internal_command(int argc, const char **argv, char **envp)
{
@@ -234,7 +234,7 @@ static void handle_internal_command(int argc, const char **argv, char **envp)
int (*fn)(int, const char **, const char *);
int option;
} commands[] = {
- { "add", cmd_add, RUN_SETUP | NOT_BARE },
+ { "add", cmd_add, RUN_SETUP | NEED_WORK_TREE },
{ "annotate", cmd_annotate, RUN_SETUP | USE_PAGER },
{ "apply", cmd_apply },
{ "archive", cmd_archive },
@@ -244,9 +244,9 @@ static void handle_internal_command(int argc, const char **argv, char **envp)
{ "cat-file", cmd_cat_file, RUN_SETUP },
{ "checkout-index", cmd_checkout_index, RUN_SETUP },
{ "check-ref-format", cmd_check_ref_format },
- { "check-attr", cmd_check_attr, RUN_SETUP | NOT_BARE },
+ { "check-attr", cmd_check_attr, RUN_SETUP | NEED_WORK_TREE },
{ "cherry", cmd_cherry, RUN_SETUP },
- { "cherry-pick", cmd_cherry_pick, RUN_SETUP | NOT_BARE },
+ { "cherry-pick", cmd_cherry_pick, RUN_SETUP | NEED_WORK_TREE },
{ "commit-tree", cmd_commit_tree, RUN_SETUP },
{ "config", cmd_config },
{ "count-objects", cmd_count_objects, RUN_SETUP },
@@ -274,7 +274,7 @@ static void handle_internal_command(int argc, const char **argv, char **envp)
{ "mailsplit", cmd_mailsplit },
{ "merge-base", cmd_merge_base, RUN_SETUP },
{ "merge-file", cmd_merge_file },
- { "mv", cmd_mv, RUN_SETUP | NOT_BARE },
+ { "mv", cmd_mv, RUN_SETUP | NEED_WORK_TREE },
{ "name-rev", cmd_name_rev, RUN_SETUP },
{ "pack-objects", cmd_pack_objects, RUN_SETUP },
{ "pickaxe", cmd_blame, RUN_SETUP | USE_PAGER },
@@ -287,9 +287,9 @@ static void handle_internal_command(int argc, const char **argv, char **envp)
{ "rerere", cmd_rerere, RUN_SETUP },
{ "rev-list", cmd_rev_list, RUN_SETUP },
{ "rev-parse", cmd_rev_parse, RUN_SETUP },
- { "revert", cmd_revert, RUN_SETUP | NOT_BARE },
- { "rm", cmd_rm, RUN_SETUP | NOT_BARE },
- { "runstatus", cmd_runstatus, RUN_SETUP | NOT_BARE },
+ { "revert", cmd_revert, RUN_SETUP | NEED_WORK_TREE },
+ { "rm", cmd_rm, RUN_SETUP | NEED_WORK_TREE },
+ { "runstatus", cmd_runstatus, RUN_SETUP | NEED_WORK_TREE },
{ "shortlog", cmd_shortlog, RUN_SETUP | USE_PAGER },
{ "show-branch", cmd_show_branch, RUN_SETUP },
{ "show", cmd_show, RUN_SETUP | USE_PAGER },
@@ -326,8 +326,8 @@ static void handle_internal_command(int argc, const char **argv, char **envp)
prefix = setup_git_directory();
if (p->option & USE_PAGER)
setup_pager();
- if ((p->option & NOT_BARE) &&
- (is_bare_repository() || is_inside_git_dir()))
+ if ((p->option & NEED_WORK_TREE) &&
+ (!is_inside_work_tree() || is_inside_git_dir()))
die("%s must be run in a work tree", cmd);
trace_argv_printf(argv, argc, "trace: built-in: git");
diff --git a/setup.c b/setup.c
index 4856232..ddf4013 100644
--- a/setup.c
+++ b/setup.c
@@ -95,7 +95,7 @@ void verify_non_filename(const char *prefix, const char *arg)
const char *name;
struct stat st;
- if (is_inside_git_dir())
+ if (!is_inside_work_tree() || is_inside_git_dir())
return;
if (*arg == '-')
return; /* flag */
--
1.5.0.3
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH 6/7] extend rev-parse test for --is-inside-work-tree
2007-06-03 14:44 [RFC] GIT_WORK_TREE Matthias Lederhofer
` (4 preceding siblings ...)
2007-06-03 14:48 ` [RFC] GIT_WORK_TREE Matthias Lederhofer
@ 2007-06-03 14:48 ` Matthias Lederhofer
2007-06-06 7:13 ` [PATCH 6/7 (amend)] " Matthias Lederhofer
2007-06-03 14:49 ` [PATCH 7/7] test GIT_WORK_TREE Matthias Lederhofer
` (2 subsequent siblings)
8 siblings, 1 reply; 22+ messages in thread
From: Matthias Lederhofer @ 2007-06-03 14:48 UTC (permalink / raw)
To: Git Mailing List, Nguyen Thai Ngoc Duy
Signed-off-by: Matthias Lederhofer <matled@gmx.net>
---
t/t1500-rev-parse.sh | 33 +++++++++++++++++++--------------
1 files changed, 19 insertions(+), 14 deletions(-)
diff --git a/t/t1500-rev-parse.sh b/t/t1500-rev-parse.sh
index a180309..44cb141 100755
--- a/t/t1500-rev-parse.sh
+++ b/t/t1500-rev-parse.sh
@@ -17,42 +17,47 @@ test_rev_parse() {
shift
[ $# -eq 0 ] && return
+ test_expect_success "$name: is-inside-work-tree" \
+ "test '$1' = \"\$(git rev-parse --is-inside-work-tree)\""
+ shift
+ [ $# -eq 0 ] && return
+
test_expect_success "$name: prefix" \
"test '$1' = \"\$(git rev-parse --show-prefix)\""
shift
[ $# -eq 0 ] && return
}
-test_rev_parse toplevel false false ''
+test_rev_parse toplevel false false true ''
cd .git || exit 1
-test_rev_parse .git/ false true .git/
+test_rev_parse .git/ false true true .git/
cd objects || exit 1
-test_rev_parse .git/objects/ false true .git/objects/
+test_rev_parse .git/objects/ false true true .git/objects/
cd ../.. || exit 1
mkdir -p sub/dir || exit 1
cd sub/dir || exit 1
-test_rev_parse subdirectory false false sub/dir/
+test_rev_parse subdirectory false false true sub/dir/
cd ../.. || exit 1
git config core.bare true
-test_rev_parse 'core.bare = true' true
+test_rev_parse 'core.bare = true' true false true
git config --unset core.bare
-test_rev_parse 'core.bare undefined' false
+test_rev_parse 'core.bare undefined' false false true
-mv .git foo.git || exit 1
-export GIT_DIR=foo.git
-export GIT_CONFIG=foo.git/config
-
-git config core.bare true
-test_rev_parse 'GIT_DIR=foo.git, core.bare = true' true
+mv .git repo.git || exit 1
+export GIT_DIR=repo.git
+export GIT_CONFIG=repo.git/config
git config core.bare false
-test_rev_parse 'GIT_DIR=foo.git, core.bare = false' false
+test_rev_parse 'GIT_DIR=repo.git, core.bare = false' false false true ''
+
+git config core.bare true
+test_rev_parse 'GIT_DIR=repo.git, core.bare = true' true false false
git config --unset core.bare
-test_rev_parse 'GIT_DIR=foo.git, core.bare undefined' true
+test_rev_parse 'GIT_DIR=repo.git, core.bare undefined' true false false
test_done
--
1.5.0.3
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH 6/7 (amend)] extend rev-parse test for --is-inside-work-tree
2007-06-03 14:48 ` [PATCH 6/7] extend rev-parse test for --is-inside-work-tree Matthias Lederhofer
@ 2007-06-06 7:13 ` Matthias Lederhofer
0 siblings, 0 replies; 22+ messages in thread
From: Matthias Lederhofer @ 2007-06-06 7:13 UTC (permalink / raw)
To: Git Mailing List, Nguyen Thai Ngoc Duy
Signed-off-by: Matthias Lederhofer <matled@gmx.net>
---
New: tests that cwd is used as working tree when GIT_DIR is set (and
GIT_WORK_TREE/core.worktree are unspecified).
---
t/t1500-rev-parse.sh | 29 +++++++++++++++++------------
1 files changed, 17 insertions(+), 12 deletions(-)
diff --git a/t/t1500-rev-parse.sh b/t/t1500-rev-parse.sh
index 66b0e58..ec49966 100755
--- a/t/t1500-rev-parse.sh
+++ b/t/t1500-rev-parse.sh
@@ -17,30 +17,35 @@ test_rev_parse() {
shift
[ $# -eq 0 ] && return
+ test_expect_success "$name: is-inside-work-tree" \
+ "test '$1' = \"\$(git rev-parse --is-inside-work-tree)\""
+ shift
+ [ $# -eq 0 ] && return
+
test_expect_success "$name: prefix" \
"test '$1' = \"\$(git rev-parse --show-prefix)\""
shift
[ $# -eq 0 ] && return
}
-test_rev_parse toplevel false false ''
+test_rev_parse toplevel false false true ''
cd .git || exit 1
-test_rev_parse .git/ false true .git/
+test_rev_parse .git/ false true true .git/
cd objects || exit 1
-test_rev_parse .git/objects/ false true .git/objects/
+test_rev_parse .git/objects/ false true true .git/objects/
cd ../.. || exit 1
mkdir -p sub/dir || exit 1
cd sub/dir || exit 1
-test_rev_parse subdirectory false false sub/dir/
+test_rev_parse subdirectory false false true sub/dir/
cd ../.. || exit 1
git config core.bare true
-test_rev_parse 'core.bare = true' true
+test_rev_parse 'core.bare = true' true false true
git config --unset core.bare
-test_rev_parse 'core.bare undefined' false
+test_rev_parse 'core.bare undefined' false false true
mkdir work || exit 1
cd work || exit 1
@@ -48,25 +53,25 @@ export GIT_DIR=../.git
export GIT_CONFIG="$GIT_DIR"/config
git config core.bare false
-test_rev_parse 'GIT_DIR=../.git, core.bare = false' false false ''
+test_rev_parse 'GIT_DIR=../.git, core.bare = false' false false true ''
git config core.bare true
-test_rev_parse 'GIT_DIR=../.git, core.bare = true' true
+test_rev_parse 'GIT_DIR=../.git, core.bare = true' true false true ''
git config --unset core.bare
-test_rev_parse 'GIT_DIR=../.git, core.bare undefined' false false ''
+test_rev_parse 'GIT_DIR=../.git, core.bare undefined' false false true ''
mv ../.git ../repo.git || exit 1
export GIT_DIR=../repo.git
export GIT_CONFIG="$GIT_DIR"/config
git config core.bare false
-test_rev_parse 'GIT_DIR=../repo.git, core.bare = false' false false ''
+test_rev_parse 'GIT_DIR=../repo.git, core.bare = false' false false true ''
git config core.bare true
-test_rev_parse 'GIT_DIR=../repo.git, core.bare = true' true
+test_rev_parse 'GIT_DIR=../repo.git, core.bare = true' true false true ''
git config --unset core.bare
-test_rev_parse 'GIT_DIR=../repo.git, core.bare undefined' true
+test_rev_parse 'GIT_DIR=../repo.git, core.bare undefined' true false true ''
test_done
--
1.5.2.1.116.g9f308
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH 7/7] test GIT_WORK_TREE
2007-06-03 14:44 [RFC] GIT_WORK_TREE Matthias Lederhofer
` (5 preceding siblings ...)
2007-06-03 14:48 ` [PATCH 6/7] extend rev-parse test for --is-inside-work-tree Matthias Lederhofer
@ 2007-06-03 14:49 ` Matthias Lederhofer
2007-06-06 7:14 ` [PATCH 7/7 (amend)] " Matthias Lederhofer
2007-06-03 16:02 ` [RFC] GIT_WORK_TREE Sergio
2007-06-06 21:29 ` [PATCH] setup_git_directory: fix segfault if repository is found in cwd Matthias Lederhofer
8 siblings, 1 reply; 22+ messages in thread
From: Matthias Lederhofer @ 2007-06-03 14:49 UTC (permalink / raw)
To: Git Mailing List, Nguyen Thai Ngoc Duy
Signed-off-by: Matthias Lederhofer <matled@gmx.net>
---
t/t1501-worktree.sh | 119 +++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 119 insertions(+), 0 deletions(-)
create mode 100755 t/t1501-worktree.sh
diff --git a/t/t1501-worktree.sh b/t/t1501-worktree.sh
new file mode 100755
index 0000000..d9d9e4a
--- /dev/null
+++ b/t/t1501-worktree.sh
@@ -0,0 +1,119 @@
+#!/bin/sh
+
+test_description='test separate work tree'
+. ./test-lib.sh
+
+test_rev_parse() {
+ name=$1
+ shift
+
+ test_expect_success "$name: is-bare-repository" \
+ "test '$1' = \"\$(git rev-parse --is-bare-repository)\""
+ shift
+ [ $# -eq 0 ] && return
+
+ test_expect_success "$name: is-inside-git-dir" \
+ "test '$1' = \"\$(git rev-parse --is-inside-git-dir)\""
+ shift
+ [ $# -eq 0 ] && return
+
+ test_expect_success "$name: is-inside-work-tree" \
+ "test '$1' = \"\$(git rev-parse --is-inside-work-tree)\""
+ shift
+ [ $# -eq 0 ] && return
+
+ test_expect_success "$name: prefix" \
+ "test '$1' = \"\$(git rev-parse --show-prefix)\""
+ shift
+ [ $# -eq 0 ] && return
+}
+
+mkdir -p work/sub/dir || exit 1
+
+say "fallback work tree (name ending in .git)"
+cd work || exit 1
+export GIT_DIR=../.git
+export GIT_CONFIG=$GIT_DIR/config
+unset GIT_WORK_TREE
+git config core.bare true
+test_rev_parse 'core.bare = true' true false false
+git config --unset core.bare
+test_rev_parse 'core.bare undefined' false false true
+git config core.bare false
+test_rev_parse 'core.bare = false' false false true ''
+cd .. || exit 1
+
+mv .git repo.git || exit 1
+
+say "fallback work tree (name ending in repo.git)"
+cd work || exit 1
+export GIT_DIR=../repo.git
+export GIT_CONFIG=$GIT_DIR/config
+unset GIT_WORK_TREE
+git config core.bare true
+test_rev_parse 'core.bare = true' true false false
+git config --unset core.bare
+test_rev_parse 'core.bare undefined' true false false
+git config core.bare false
+test_rev_parse 'core.bare = false' false false true ''
+cd .. || exit 1
+
+say "core.worktree = relative path"
+export GIT_DIR=repo.git
+export GIT_CONFIG=$GIT_DIR/config
+unset GIT_WORK_TREE
+git config core.worktree ../work
+test_rev_parse 'outside' false false false
+cd work || exit 1
+export GIT_DIR=../repo.git
+export GIT_CONFIG=$GIT_DIR/config
+test_rev_parse 'inside' false false true ''
+cd sub/dir || exit 1
+export GIT_DIR=../../../repo.git
+export GIT_CONFIG=$GIT_DIR/config
+test_rev_parse 'subdirectory' false false true sub/dir/
+cd ../../.. || exit 1
+
+say "core.worktree = absolute path"
+export GIT_DIR=$(pwd)/repo.git
+export GIT_CONFIG=$GIT_DIR/config
+git config core.worktree "$(pwd)/work"
+test_rev_parse 'outside' false false false
+cd work || exit 1
+test_rev_parse 'inside' false false true ''
+cd sub/dir || exit 1
+test_rev_parse 'subdirectory' false false true sub/dir/
+cd ../../.. || exit 1
+
+say "GIT_WORK_TREE=relative path (override core.worktree)"
+export GIT_DIR=$(pwd)/repo.git
+export GIT_CONFIG=$GIT_DIR/config
+git config core.worktree non-existent
+export GIT_WORK_TREE=work
+test_rev_parse 'outside' false false false
+cd work || exit 1
+export GIT_WORK_TREE=.
+test_rev_parse 'inside' false false true ''
+cd sub/dir || exit 1
+export GIT_WORK_TREE=../..
+test_rev_parse 'subdirectory' false false true sub/dir/
+cd ../../.. || exit 1
+
+mv work repo.git/work
+
+say "GIT_WORK_TREE=absolute path, work tree below git dir"
+export GIT_DIR=$(pwd)/repo.git
+export GIT_CONFIG=$GIT_DIR/config
+export GIT_WORK_TREE=$(pwd)/repo.git/work
+test_rev_parse 'outside' false false false
+cd repo.git || exit 1
+test_rev_parse 'in repo.git' false true false
+cd objects || exit 1
+test_rev_parse 'in repo.git/objects' false true false
+cd ../work || exit 1
+test_rev_parse 'in repo.git/work' false false true ''
+cd sub/dir || exit 1
+test_rev_parse 'in repo.git/sub/dir' false false true sub/dir/
+cd ../../../.. || exit 1
+
+test_done
--
1.5.0.3
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH 7/7 (amend)] test GIT_WORK_TREE
2007-06-03 14:49 ` [PATCH 7/7] test GIT_WORK_TREE Matthias Lederhofer
@ 2007-06-06 7:14 ` Matthias Lederhofer
0 siblings, 0 replies; 22+ messages in thread
From: Matthias Lederhofer @ 2007-06-06 7:14 UTC (permalink / raw)
To: Git Mailing List
Signed-off-by: Matthias Lederhofer <matled@gmx.net>
---
Remove test for fallback work tree with GIT_DIR, this is now in
t1500-rev-parse.sh.
---
t/t1501-worktree.sh | 92 +++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 92 insertions(+), 0 deletions(-)
create mode 100755 t/t1501-worktree.sh
diff --git a/t/t1501-worktree.sh b/t/t1501-worktree.sh
new file mode 100755
index 0000000..aadeeab
--- /dev/null
+++ b/t/t1501-worktree.sh
@@ -0,0 +1,92 @@
+#!/bin/sh
+
+test_description='test separate work tree'
+. ./test-lib.sh
+
+test_rev_parse() {
+ name=$1
+ shift
+
+ test_expect_success "$name: is-bare-repository" \
+ "test '$1' = \"\$(git rev-parse --is-bare-repository)\""
+ shift
+ [ $# -eq 0 ] && return
+
+ test_expect_success "$name: is-inside-git-dir" \
+ "test '$1' = \"\$(git rev-parse --is-inside-git-dir)\""
+ shift
+ [ $# -eq 0 ] && return
+
+ test_expect_success "$name: is-inside-work-tree" \
+ "test '$1' = \"\$(git rev-parse --is-inside-work-tree)\""
+ shift
+ [ $# -eq 0 ] && return
+
+ test_expect_success "$name: prefix" \
+ "test '$1' = \"\$(git rev-parse --show-prefix)\""
+ shift
+ [ $# -eq 0 ] && return
+}
+
+mkdir -p work/sub/dir || exit 1
+mv .git repo.git || exit 1
+
+say "core.worktree = relative path"
+export GIT_DIR=repo.git
+export GIT_CONFIG=$GIT_DIR/config
+unset GIT_WORK_TREE
+git config core.worktree ../work
+test_rev_parse 'outside' false false false
+cd work || exit 1
+export GIT_DIR=../repo.git
+export GIT_CONFIG=$GIT_DIR/config
+test_rev_parse 'inside' false false true ''
+cd sub/dir || exit 1
+export GIT_DIR=../../../repo.git
+export GIT_CONFIG=$GIT_DIR/config
+test_rev_parse 'subdirectory' false false true sub/dir/
+cd ../../.. || exit 1
+
+say "core.worktree = absolute path"
+export GIT_DIR=$(pwd)/repo.git
+export GIT_CONFIG=$GIT_DIR/config
+git config core.worktree "$(pwd)/work"
+test_rev_parse 'outside' false false false
+cd work || exit 1
+test_rev_parse 'inside' false false true ''
+cd sub/dir || exit 1
+test_rev_parse 'subdirectory' false false true sub/dir/
+cd ../../.. || exit 1
+
+say "GIT_WORK_TREE=relative path (override core.worktree)"
+export GIT_DIR=$(pwd)/repo.git
+export GIT_CONFIG=$GIT_DIR/config
+git config core.worktree non-existent
+export GIT_WORK_TREE=work
+test_rev_parse 'outside' false false false
+cd work || exit 1
+export GIT_WORK_TREE=.
+test_rev_parse 'inside' false false true ''
+cd sub/dir || exit 1
+export GIT_WORK_TREE=../..
+test_rev_parse 'subdirectory' false false true sub/dir/
+cd ../../.. || exit 1
+
+mv work repo.git/work
+
+say "GIT_WORK_TREE=absolute path, work tree below git dir"
+export GIT_DIR=$(pwd)/repo.git
+export GIT_CONFIG=$GIT_DIR/config
+export GIT_WORK_TREE=$(pwd)/repo.git/work
+test_rev_parse 'outside' false false false
+cd repo.git || exit 1
+test_rev_parse 'in repo.git' false true false
+cd objects || exit 1
+test_rev_parse 'in repo.git/objects' false true false
+cd ../work || exit 1
+test_rev_parse 'in repo.git/work' false false true ''
+cd sub/dir || exit 1
+test_rev_parse 'in repo.git/sub/dir' false false true sub/dir/
+cd ../../../.. || exit 1
+
+test_done
--
1.5.2.1.116.g9f308
^ permalink raw reply related [flat|nested] 22+ messages in thread
* Re: [RFC] GIT_WORK_TREE
2007-06-03 14:44 [RFC] GIT_WORK_TREE Matthias Lederhofer
` (6 preceding siblings ...)
2007-06-03 14:49 ` [PATCH 7/7] test GIT_WORK_TREE Matthias Lederhofer
@ 2007-06-03 16:02 ` Sergio
2007-06-03 19:32 ` Matthias Lederhofer
2007-06-06 21:29 ` [PATCH] setup_git_directory: fix segfault if repository is found in cwd Matthias Lederhofer
8 siblings, 1 reply; 22+ messages in thread
From: Sergio @ 2007-06-03 16:02 UTC (permalink / raw)
To: git
Matthias Lederhofer <matled <at> gmx.net> writes:
> This series introduces the GIT_WORK_TREE environment variable (and
> core.worktree config option) to specify the working tree that should
> be used with the repository (not for repositories found as .git
> directory). This allows to separate the repository and working tree.
Hi,
a question regarding GIT_WORK_TREE and (possibly) a suggestion...
If I am not wrong, with this we detach the WT from the REPO by letting git know
our working tree if the working tree does not include a repo (.git) directory.
And this is done either:
- by setting the GIT_WORK_TREE environment variable whenever needed
- by passing the --work-tree parameter to git when needed
- by setting the core.worktree config option in the git repo, so that the
repository knows where its default work tree is...
Is this correct? or am I missing some other ways?
Would it make sense to make the _WT_ know where its repo is?
I.e. having something like a .git-repo file a the top dir of a WT, so that when
git is invoked within the WT it can scan up the WT until it finds the .git-repo
file and automatically decide that GIT_WORK_TREE is at the dir containing that
.git-repo file and that GIT_DIR is at the file pointed by that .git-repo?
Thanks,
Sergio
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [RFC] GIT_WORK_TREE
2007-06-03 16:02 ` [RFC] GIT_WORK_TREE Sergio
@ 2007-06-03 19:32 ` Matthias Lederhofer
2007-06-03 21:34 ` Sergio
0 siblings, 1 reply; 22+ messages in thread
From: Matthias Lederhofer @ 2007-06-03 19:32 UTC (permalink / raw)
To: Sergio; +Cc: git
Sergio <sergio.callegari@gmail.com> wrote:
> Matthias Lederhofer <matled <at> gmx.net> writes:
> If I am not wrong, with this we detach the WT from the REPO by letting git know
> our working tree if the working tree does not include a repo (.git) directory.
> And this is done either:
> - by setting the GIT_WORK_TREE environment variable whenever needed
> - by passing the --work-tree parameter to git when needed
> - by setting the core.worktree config option in the git repo, so that the
> repository knows where its default work tree is...
>
> Is this correct? or am I missing some other ways?
That's right, you'd set GIT_DIR and core.worktree/GIT_WORK_TREE.
> Would it make sense to make the _WT_ know where its repo is?
>
> I.e. having something like a .git-repo file a the top dir of a WT, so that when
> git is invoked within the WT it can scan up the WT until it finds the .git-repo
> file and automatically decide that GIT_WORK_TREE is at the dir containing that
> .git-repo file and that GIT_DIR is at the file pointed by that .git-repo?
Symlinking the .git directory is quite similar to this and works
already without this patch series. Anyway I spontaneously can think
of the following use cases, so it might be interesting to add this
feature:
- The use case Nguyen mentioned, e.g. the filesystem does not support
symlinks and for some reason it is not possible to use the git
repository next to the working tree.
- When executing potentially 'dangerous' programs in the working tree
it is safer to have a file pointing to the repository than placing
the repository or a symlink to the repository in the working tree
(breaking the .git-repo file might be confusing but is not as bad as
breaking the repository).
- In case of a publicly available working tree it might be ok to
publish the path to the repository accidentially (which might happen
if the permissions for the .git-repo file are too loose) but there
would be no risk that wrong permissions could disclose the
repository itself.
What I haven't thought through is if it could make sense to honor the
GIT_WORK_TREE/core.worktree setting when such a .git-repo file is used
or just use the directory containing the file as work tree.
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [RFC] GIT_WORK_TREE
2007-06-03 19:32 ` Matthias Lederhofer
@ 2007-06-03 21:34 ` Sergio
0 siblings, 0 replies; 22+ messages in thread
From: Sergio @ 2007-06-03 21:34 UTC (permalink / raw)
To: git
Matthias Lederhofer <matled <at> gmx.net> writes:
> What I haven't thought through is if it could make sense to honor the
> GIT_WORK_TREE/core.worktree setting when such a .git-repo file is used
> or just use the directory containing the file as work tree.
I would do the first... for the following reason...
Suppose that by accident you move the working tree and you cd to some
point in the moved WT...
You issue a git command...
By climbing up the directory hierarchy, git gets to the .git-repo file
so now it knows where the repo is...
But running a command and following the core.worktree config it might
put output in the wrong output dir...
But actually I also see problems the other way round...
Suppose you have project A containing a dir B that is under its own git
tracking...
Also suppose that both A and B have repos separated from WT.
If for some reason WT of B misses its .git-repo, then there is trouble
on the way: when issuing a command in B, by climbing up git would find
the .git-repo of A, thinking that it is the git-repo of B...
A weird case, though.
Sergio
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH] setup_git_directory: fix segfault if repository is found in cwd
2007-06-03 14:44 [RFC] GIT_WORK_TREE Matthias Lederhofer
` (7 preceding siblings ...)
2007-06-03 16:02 ` [RFC] GIT_WORK_TREE Sergio
@ 2007-06-06 21:29 ` Matthias Lederhofer
8 siblings, 0 replies; 22+ messages in thread
From: Matthias Lederhofer @ 2007-06-06 21:29 UTC (permalink / raw)
To: Git Mailing List
Additionally there was a similar part calling setenv and getenv
in the same way which missed a check if getenv succeeded.
Signed-off-by: Matthias Lederhofer <matled@gmx.net>
---
There seems to be no easy way to test this case. We'd have to run the
test in a directory which never has a .git directory in any parent.
---
setup.c | 5 +++++
1 files changed, 5 insertions(+), 0 deletions(-)
diff --git a/setup.c b/setup.c
index 14a4d95..dba8012 100644
--- a/setup.c
+++ b/setup.c
@@ -251,6 +251,9 @@ const char *setup_git_directory_gently(int *nongit_ok)
die("Not a git repository");
}
setenv(GIT_DIR_ENVIRONMENT, cwd, 1);
+ gitdirenv = getenv(GIT_DIR_ENVIRONMENT);
+ if (!gitdirenv)
+ die("getenv after setenv failed");
}
if (PATH_MAX - 40 < strlen(gitdirenv)) {
@@ -290,6 +293,8 @@ const char *setup_git_directory_gently(int *nongit_ok)
if (gitdirenv[0] != '/') {
setenv(GIT_DIR_ENVIRONMENT, gitdir, 1);
gitdirenv = getenv(GIT_DIR_ENVIRONMENT);
+ if (!gitdirenv)
+ die("getenv after setenv failed");
if (PATH_MAX - 40 < strlen(gitdirenv)) {
if (nongit_ok) {
*nongit_ok = 1;
--
1.5.2.1.887.ge344-dirty
^ permalink raw reply related [flat|nested] 22+ messages in thread