From 48a7c1c49d675fa37b609b499dd9e27439ec7f51 Mon Sep 17 00:00:00 2001 From: Giuseppe Bilotta Date: Thu, 25 Feb 2010 00:34:14 +0100 Subject: [PATCH 1/5] Refactor list of of repo-local env vars Move the list of GIT_* environment variables that are local to a repository into a static list in environment.c, as it is also useful elsewhere. Also add the missing GIT_CONFIG variable to the list. Make it easy to use the list both by NULL-termination and by size; the latter (excluding the terminating NULL) is stored in the local_repo_env_size define. Signed-off-by: Giuseppe Bilotta Signed-off-by: Junio C Hamano --- cache.h | 9 +++++++++ connect.c | 14 ++------------ environment.c | 17 +++++++++++++++++ 3 files changed, 28 insertions(+), 12 deletions(-) diff --git a/cache.h b/cache.h index d478eff1f3..58209adbd6 100644 --- a/cache.h +++ b/cache.h @@ -388,6 +388,15 @@ static inline enum object_type object_type(unsigned int mode) #define GIT_NOTES_REF_ENVIRONMENT "GIT_NOTES_REF" #define GIT_NOTES_DEFAULT_REF "refs/notes/commits" +/* + * Repository-local GIT_* environment variables + * The array is NULL-terminated to simplify its usage in contexts such + * environment creation or simple walk of the list. + * The number of non-NULL entries is available as a macro. + */ +#define LOCAL_REPO_ENV_SIZE 8 +extern const char *const local_repo_env[LOCAL_REPO_ENV_SIZE + 1]; + extern int is_bare_repository_cfg; extern int is_bare_repository(void); extern int is_inside_git_dir(void); diff --git a/connect.c b/connect.c index 20054e4d0f..24ce2fc70e 100644 --- a/connect.c +++ b/connect.c @@ -607,18 +607,8 @@ struct child_process *git_connect(int fd[2], const char *url_orig, *arg++ = host; } else { - /* remove these from the environment */ - const char *env[] = { - ALTERNATE_DB_ENVIRONMENT, - DB_ENVIRONMENT, - GIT_DIR_ENVIRONMENT, - GIT_WORK_TREE_ENVIRONMENT, - GRAFT_ENVIRONMENT, - INDEX_ENVIRONMENT, - NO_REPLACE_OBJECTS_ENVIRONMENT, - NULL - }; - conn->env = env; + /* remove repo-local variables from the environment */ + conn->env = local_repo_env; conn->use_shell = 1; } *arg++ = cmd.buf; diff --git a/environment.c b/environment.c index 739ec27040..876c5e5341 100644 --- a/environment.c +++ b/environment.c @@ -63,6 +63,23 @@ static char *work_tree; static const char *git_dir; static char *git_object_dir, *git_index_file, *git_refs_dir, *git_graft_file; +/* + * Repository-local GIT_* environment variables + * Remember to update local_repo_env_size in cache.h when + * the size of the list changes + */ +const char * const local_repo_env[LOCAL_REPO_ENV_SIZE + 1] = { + ALTERNATE_DB_ENVIRONMENT, + CONFIG_ENVIRONMENT, + DB_ENVIRONMENT, + GIT_DIR_ENVIRONMENT, + GIT_WORK_TREE_ENVIRONMENT, + GRAFT_ENVIRONMENT, + INDEX_ENVIRONMENT, + NO_REPLACE_OBJECTS_ENVIRONMENT, + NULL +}; + static void setup_git_env(void) { git_dir = getenv(GIT_DIR_ENVIRONMENT); From 94c8ccaaba4ac8b0225f5adeae4ff29f01951bce Mon Sep 17 00:00:00 2001 From: Giuseppe Bilotta Date: Thu, 25 Feb 2010 00:34:15 +0100 Subject: [PATCH 2/5] rev-parse: --local-env-vars option This prints the list of repo-local environment variables. Signed-off-by: Giuseppe Bilotta Signed-off-by: Junio C Hamano --- Documentation/git-rev-parse.txt | 6 ++++++ builtin-rev-parse.c | 7 +++++++ 2 files changed, 13 insertions(+) diff --git a/Documentation/git-rev-parse.txt b/Documentation/git-rev-parse.txt index d677c72d5e..33092a3373 100644 --- a/Documentation/git-rev-parse.txt +++ b/Documentation/git-rev-parse.txt @@ -149,6 +149,12 @@ shown. If the pattern does not contain a globbing character (`?`, --is-bare-repository:: When the repository is bare print "true", otherwise "false". +--local-env-vars:: + List the GIT_* environment variables that are local to the + repository (e.g. GIT_DIR or GIT_WORK_TREE, but not GIT_EDITOR). + Only the names of the variables are listed, not their value, + even if they are set. + --short:: --short=number:: Instead of outputting the full SHA1 values of object names try to diff --git a/builtin-rev-parse.c b/builtin-rev-parse.c index a8c5043ded..b76f205e62 100644 --- a/builtin-rev-parse.c +++ b/builtin-rev-parse.c @@ -455,6 +455,13 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix) if (argc > 1 && !strcmp("--sq-quote", argv[1])) return cmd_sq_quote(argc - 2, argv + 2); + if (argc == 2 && !strcmp("--local-env-vars", argv[1])) { + int i; + for (i = 0; local_repo_env[i]; i++) + printf("%s\n", local_repo_env[i]); + return 0; + } + if (argc > 1 && !strcmp("-h", argv[1])) usage(builtin_rev_parse_usage); From 7d750f0ea511dcc26c3c9de996a9b75444366ecc Mon Sep 17 00:00:00 2001 From: Giuseppe Bilotta Date: Thu, 25 Feb 2010 00:34:16 +0100 Subject: [PATCH 3/5] shell setup: clear_local_git_env() function Introduce an auxiliary function to clear all repo-local environment variables. This should be invoked by any shell script that switches repository during execution, to ensure that the environment is clean and that things such as the git dir and worktree are set up correctly. Signed-off-by: Giuseppe Bilotta Signed-off-by: Junio C Hamano --- git-sh-setup.sh | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/git-sh-setup.sh b/git-sh-setup.sh index d56426dd39..cf864a6273 100755 --- a/git-sh-setup.sh +++ b/git-sh-setup.sh @@ -159,6 +159,13 @@ get_author_ident_from_commit () { LANG=C LC_ALL=C sed -ne "$pick_author_script" } +# Clear repo-local GIT_* environment variables. Useful when switching to +# another repository (e.g. when entering a submodule). See also the env +# list in git_connect() +clear_local_git_env() { + unset $(git rev-parse --local-env-vars) +} + # Make sure we are in a valid repository of a vintage we understand, # if we require to be in a git repository. if test -z "$NONGIT_OK" From 74ae14199dfb4b3b22a10d3dcecb62b457245564 Mon Sep 17 00:00:00 2001 From: Giuseppe Bilotta Date: Thu, 25 Feb 2010 00:34:17 +0100 Subject: [PATCH 4/5] submodules: ensure clean environment when operating in a submodule git-submodule used to take care of clearing GIT_DIR whenever it operated on a submodule index or configuration, but forgot to unset GIT_WORK_TREE or other repo-local variables. This would lead to failures e.g. when GIT_WORK_TREE was set. This only happened in very unusual contexts such as operating on the main worktree from outside of it, but since "git-gui: set GIT_DIR and GIT_WORK_TREE after setup" (a9fa11fe5bd5978bb) such failures could also be provoked by invoking an external tool such as "git submodule update" from the Git Gui in a standard setup. Solve by using the newly introduced clear_local_git_env() shell function to ensure that all repo-local environment variables are unset. Signed-off-by: Giuseppe Bilotta Signed-off-by: Junio C Hamano --- git-submodule.sh | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/git-submodule.sh b/git-submodule.sh index 664f21721c..e2082fd149 100755 --- a/git-submodule.sh +++ b/git-submodule.sh @@ -222,7 +222,7 @@ cmd_add() module_clone "$path" "$realrepo" "$reference" || exit ( - unset GIT_DIR + clear_local_git_env cd "$path" && # ash fails to wordsplit ${branch:+-b "$branch"...} case "$branch" in @@ -278,7 +278,7 @@ cmd_foreach() name=$(module_name "$path") ( prefix="$prefix$path/" - unset GIT_DIR + clear_local_git_env cd "$path" && eval "$@" && if test -n "$recursive" @@ -434,7 +434,7 @@ cmd_update() module_clone "$path" "$url" "$reference"|| exit subsha1= else - subsha1=$(unset GIT_DIR; cd "$path" && + subsha1=$(clear_local_git_env; cd "$path" && git rev-parse --verify HEAD) || die "Unable to find current revision in submodule path '$path'" fi @@ -454,7 +454,7 @@ cmd_update() if test -z "$nofetch" then - (unset GIT_DIR; cd "$path" && + (clear_local_git_env; cd "$path" && git-fetch) || die "Unable to fetch in submodule path '$path'" fi @@ -477,14 +477,14 @@ cmd_update() ;; esac - (unset GIT_DIR; cd "$path" && $command "$sha1") || + (clear_local_git_env; cd "$path" && $command "$sha1") || die "Unable to $action '$sha1' in submodule path '$path'" say "Submodule path '$path': $msg '$sha1'" fi if test -n "$recursive" then - (unset GIT_DIR; cd "$path" && cmd_update $orig_args) || + (clear_local_git_env; cd "$path" && cmd_update $orig_args) || die "Failed to recurse into submodule path '$path'" fi done @@ -492,7 +492,7 @@ cmd_update() set_name_rev () { revname=$( ( - unset GIT_DIR + clear_local_git_env cd "$1" && { git describe "$2" 2>/dev/null || git describe --tags "$2" 2>/dev/null || @@ -757,7 +757,7 @@ cmd_status() else if test -z "$cached" then - sha1=$(unset GIT_DIR; cd "$path" && git rev-parse --verify HEAD) + sha1=$(clear_local_git_env; cd "$path" && git rev-parse --verify HEAD) set_name_rev "$path" "$sha1" fi say "+$sha1 $displaypath$revname" @@ -767,7 +767,7 @@ cmd_status() then ( prefix="$displaypath/" - unset GIT_DIR + clear_local_git_env cd "$path" && cmd_status $orig_args ) || @@ -818,7 +818,7 @@ cmd_sync() if test -e "$path"/.git then ( - unset GIT_DIR + clear_local_git_env cd "$path" remote=$(get_default_remote) say "Synchronizing submodule url for '$name'" From 5ce9086ddfe6931ef34fcd99778c9235e2ee1839 Mon Sep 17 00:00:00 2001 From: Giuseppe Bilotta Date: Thu, 25 Feb 2010 00:34:18 +0100 Subject: [PATCH 5/5] is_submodule_modified(): clear environment properly Rather than only clearing GIT_INDEX_FILE, take the list of environment variables to clear from local_repo_env, appending the settings for GIT_DIR and GIT_WORK_TREE. Signed-off-by: Giuseppe Bilotta Signed-off-by: Junio C Hamano --- submodule.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/submodule.c b/submodule.c index 7d70c4f7bf..5d286e409e 100644 --- a/submodule.c +++ b/submodule.c @@ -123,16 +123,19 @@ void show_submodule_summary(FILE *f, const char *path, int is_submodule_modified(const char *path) { - int len; + int len, i; struct child_process cp; const char *argv[] = { "status", "--porcelain", NULL, }; - char *env[4]; + const char *env[LOCAL_REPO_ENV_SIZE + 3]; struct strbuf buf = STRBUF_INIT; + for (i = 0; i < LOCAL_REPO_ENV_SIZE; i++) + env[i] = local_repo_env[i]; + strbuf_addf(&buf, "%s/.git/", path); if (!is_directory(buf.buf)) { strbuf_release(&buf); @@ -143,16 +146,14 @@ int is_submodule_modified(const char *path) strbuf_reset(&buf); strbuf_addf(&buf, "GIT_WORK_TREE=%s", path); - env[0] = strbuf_detach(&buf, NULL); + env[i++] = strbuf_detach(&buf, NULL); strbuf_addf(&buf, "GIT_DIR=%s/.git", path); - env[1] = strbuf_detach(&buf, NULL); - strbuf_addf(&buf, "GIT_INDEX_FILE"); - env[2] = strbuf_detach(&buf, NULL); - env[3] = NULL; + env[i++] = strbuf_detach(&buf, NULL); + env[i] = NULL; memset(&cp, 0, sizeof(cp)); cp.argv = argv; - cp.env = (const char *const *)env; + cp.env = env; cp.git_cmd = 1; cp.no_stdin = 1; cp.out = -1; @@ -165,9 +166,8 @@ int is_submodule_modified(const char *path) if (finish_command(&cp)) die("git status --porcelain failed"); - free(env[0]); - free(env[1]); - free(env[2]); + for (i = LOCAL_REPO_ENV_SIZE; env[i]; i++) + free((char *)env[i]); strbuf_release(&buf); return len != 0; }