set_work_tree: use chdir_notify

When we change to the top of the working tree, we manually
re-adjust $GIT_DIR and call set_git_dir() again, in order to
update any relative git-dir we'd compute earlier.

Instead of the work-tree code having to know to call the
git-dir code, let's use the new chdir_notify interface.
There are two spots that need updating, with a few
subtleties in each:

  1. the set_git_dir() code needs to chdir_notify_register()
     so it can be told when to update its path.

     Technically we could push this down into repo_set_gitdir(),
     so that even repository structs besides the_repository
     could benefit from this. But that opens up a lot of
     complications:

      - we'd still need to touch set_git_dir(), because it
        does some other setup (like setting $GIT_DIR in the
        environment)

      - submodules using other repository structs get
        cleaned up, which means we'd need to remove them
        from the chdir_notify list

      - it's unlikely to fix any bugs, since we shouldn't
        generally chdir() in the middle of working on a
        submodule

  2. setup_work_tree now needs to call chdir_notify(), and
     can lose its manual set_git_dir() call.

     Note that at first glance it looks like this undoes the
     absolute-to-relative optimization added by 044bbbcb63
     (Make git_dir a path relative to work_tree in
     setup_work_tree(), 2008-06-19). But for the most part
     that optimization was just _undoing_ the
     relative-to-absolute conversion which the function was
     doing earlier (and which is now gone).

     It is true that if you already have an absolute git_dir
     that the setup_work_tree() function will no longer make
     it relative as a side effect. But:

       - we generally do have relative git-dir's due to the
         way the discovery code works

       - if we really care about making git-dir's relative
         when possible, then we should be relativizing them
         earlier (e.g., when we see an absolute $GIT_DIR we
         could turn it relative, whether we are going to
         chdir into a worktree or not). That would cover all
         cases, including ones that 044bbbcb63 did not.

Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Jeff King 2018-03-30 14:35:08 -04:00 committed by Junio C Hamano
parent 2b5ed37365
commit 8500e0de3f
2 changed files with 25 additions and 7 deletions

View File

@ -13,6 +13,7 @@
#include "refs.h"
#include "fmt-merge-msg.h"
#include "commit.h"
#include "chdir-notify.h"
int trust_executable_bit = 1;
int trust_ctime = 1;
@ -296,7 +297,7 @@ char *get_graft_file(void)
return the_repository->graft_file;
}
void set_git_dir(const char *path)
static void set_git_dir_1(const char *path)
{
if (setenv(GIT_DIR_ENVIRONMENT, path, 1))
die("could not set GIT_DIR to '%s'", path);
@ -304,6 +305,26 @@ void set_git_dir(const char *path)
setup_git_env();
}
static void update_relative_gitdir(const char *name,
const char *old_cwd,
const char *new_cwd,
void *data)
{
char *path = reparent_relative_path(old_cwd, new_cwd, get_git_dir());
trace_printf_key(&trace_setup_key,
"setup: move $GIT_DIR to '%s'",
path);
set_git_dir_1(path);
free(path);
}
void set_git_dir(const char *path)
{
set_git_dir_1(path);
if (!is_absolute_path(path))
chdir_notify_register(NULL, update_relative_gitdir, NULL);
}
const char *get_log_output_encoding(void)
{
return git_log_output_encoding ? git_log_output_encoding

View File

@ -3,6 +3,7 @@
#include "config.h"
#include "dir.h"
#include "string-list.h"
#include "chdir-notify.h"
static int inside_git_dir = -1;
static int inside_work_tree = -1;
@ -378,7 +379,7 @@ int is_inside_work_tree(void)
void setup_work_tree(void)
{
const char *work_tree, *git_dir;
const char *work_tree;
static int initialized = 0;
if (initialized)
@ -388,10 +389,7 @@ void setup_work_tree(void)
die(_("unable to set up work tree using invalid config"));
work_tree = get_git_work_tree();
git_dir = get_git_dir();
if (!is_absolute_path(git_dir))
git_dir = real_path(get_git_dir());
if (!work_tree || chdir(work_tree))
if (!work_tree || chdir_notify(work_tree))
die(_("this operation must be run in a work tree"));
/*
@ -401,7 +399,6 @@ void setup_work_tree(void)
if (getenv(GIT_WORK_TREE_ENVIRONMENT))
setenv(GIT_WORK_TREE_ENVIRONMENT, ".", 1);
set_git_dir(remove_leading_path(git_dir, work_tree));
initialized = 1;
}