From: Duy Nguyen <pclo...@gmail.com>

When the current directory is moved, all relative paths may become
invalid because they are still relative to the old current
directory. At this point in setup_work_tree() many objects have been
initialized and some keep relative paths in their data structure.

$GIT_DIR and $GIT_WORK_TREE for example are the two examples which are
dealt with explicitly in this code: $GIT_WORK_TREE is reset to "." and
set_git_dir() is called the second time with a new relative path.

Introduce a more generic mechanism to let all code get notified and do
the path adjustment themselves instead of pulling all path adjustment
logic in here. The $GIT_DIR and $GIT_WORK_TREE adjustments will
removed from this code in later patches.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclo...@gmail.com>
---
 cache.h |  5 +++++
 setup.c | 27 ++++++++++++++++++++++++++-
 2 files changed, 31 insertions(+), 1 deletion(-)

diff --git a/cache.h b/cache.h
index 05f32c9659..895abe7e7e 100644
--- a/cache.h
+++ b/cache.h
@@ -522,6 +522,11 @@ extern void set_git_work_tree(const char *tree);
 
 #define ALTERNATE_DB_ENVIRONMENT "GIT_ALTERNATE_OBJECT_DIRECTORIES"
 
+typedef void (*cwd_updated_fn)(const char *old_cwd,
+                              const char *new_cwd,
+                              void *cb_data);
+void add_cwd_update_callback(cwd_updated_fn fn, void *cb_data);
+void removet_cwd_update_callback(cwd_updated_fn fn, void *cb_data);
 extern void setup_adjust_path(const char *name, char **path,
                              const char *old_cwd,
                              const char *new_cwd);
diff --git a/setup.c b/setup.c
index e26f44185e..e340ee2130 100644
--- a/setup.c
+++ b/setup.c
@@ -376,6 +376,24 @@ int is_inside_work_tree(void)
        return inside_work_tree;
 }
 
+struct cwd_update_callback {
+       cwd_updated_fn fn;
+       void *cb_data;
+};
+
+static struct cwd_update_callback *cwd_callbacks;
+static int nr_cwd_callbacks;
+
+void add_cwd_update_callback(cwd_updated_fn fn, void *cb_data)
+{
+       struct cwd_update_callback *cb;
+
+       REALLOC_ARRAY(cwd_callbacks, nr_cwd_callbacks + 1);
+       cb = cwd_callbacks + nr_cwd_callbacks++;
+       cb->fn = fn;
+       cb->cb_data = cb_data;
+}
+
 void setup_adjust_path(const char *name, char **path,
                       const char *old_cwd,
                       const char *new_cwd)
@@ -398,8 +416,10 @@ void setup_adjust_path(const char *name, char **path,
 
 void setup_work_tree(void)
 {
-       const char *work_tree, *git_dir;
        static int initialized = 0;
+       const char *work_tree, *git_dir;
+       struct strbuf old_cwd = STRBUF_INIT;
+       int i;
 
        if (initialized)
                return;
@@ -411,6 +431,7 @@ void setup_work_tree(void)
        git_dir = get_git_dir();
        if (!is_absolute_path(git_dir))
                git_dir = real_path(get_git_dir());
+       strbuf_get_pwd_cwd(&old_cwd);
        if (!work_tree || chdir(work_tree))
                die(_("this operation must be run in a work tree"));
 
@@ -421,6 +442,10 @@ void setup_work_tree(void)
        if (getenv(GIT_WORK_TREE_ENVIRONMENT))
                setenv(GIT_WORK_TREE_ENVIRONMENT, ".", 1);
 
+       for (i = 0; i < nr_cwd_callbacks; i++)
+               cwd_callbacks[i].fn(old_cwd.buf, work_tree,
+                                   cwd_callbacks[i].cb_data);
+       strbuf_release(&old_cwd);
        set_git_dir(remove_leading_path(git_dir, work_tree));
        initialized = 1;
 }
-- 
2.17.0.rc1.439.gca064e2955

Reply via email to