setup: introduce startup_info->original_cwd

Removing the current working directory causes all subsequent git
commands run from that directory to get confused and fail with a message
about being unable to read the current working directory:

    $ git status
    fatal: Unable to read current working directory: No such file or directory

Non-git commands likely have similar warnings or even errors, e.g.

    $ bash -c 'echo hello'
    shell-init: error retrieving current directory: getcwd: cannot access parent directories: No such file or directory

This confuses end users, particularly since the command they get the
error from is not the one that caused the problem; the problem came from
the side-effect of some previous command.

We would like to avoid removing the current working directory of our
parent process; towards this end, introduce a new variable,
startup_info->original_cwd, that tracks the current working directory
that we inherited from our parent process.  For convenience of later
comparisons, we prefer that this new variable store a path relative to
the toplevel working directory (thus much like 'prefix'), except without
the trailing slash.

Subsequent commits will make use of this new variable.

Acked-by: Derrick Stolee <>
Acked-by: Ævar Arnfjörð Bjarmason <>
Signed-off-by: Elijah Newren <>
Signed-off-by: Junio C Hamano <>
Elijah Newren 10 months ago committed by Junio C Hamano
parent 8a0d52dfd8
commit e6f8861bd4
  1. 2
  2. 4
  3. 65

@ -1834,8 +1834,10 @@ void overlay_tree_on_index(struct index_state *istate,
struct startup_info {
int have_repository;
const char *prefix;
const char *original_cwd;
extern struct startup_info *startup_info;
extern const char *tmp_original_cwd;
/* merge.c */
struct commit_list;

@ -26,6 +26,7 @@ static void restore_sigpipe_to_default(void)
int main(int argc, const char **argv)
int result;
struct strbuf tmp = STRBUF_INIT;
@ -49,6 +50,9 @@ int main(int argc, const char **argv)
if (!strbuf_getcwd(&tmp))
tmp_original_cwd = strbuf_detach(&tmp, NULL);
result = cmd_main(argc, argv);

@ -12,6 +12,7 @@ static int work_tree_config_is_bogus;
static struct startup_info the_startup_info;
struct startup_info *startup_info = &the_startup_info;
const char *tmp_original_cwd;
* The input parameter must contain an absolute path, and it must already be
@ -432,6 +433,69 @@ void setup_work_tree(void)
initialized = 1;
static void setup_original_cwd(void)
struct strbuf tmp = STRBUF_INIT;
const char *worktree = NULL;
int offset = -1;
if (!tmp_original_cwd)
* startup_info->original_cwd points to the current working
* directory we inherited from our parent process, which is a
* directory we want to avoid removing.
* For convience, we would like to have the path relative to the
* worktree instead of an absolute path.
* Yes, startup_info->original_cwd is usually the same as 'prefix',
* but differs in two ways:
* - prefix has a trailing '/'
* - if the user passes '-C' to git, that modifies the prefix but
* not startup_info->original_cwd.
/* Normalize the directory */
strbuf_realpath(&tmp, tmp_original_cwd, 1);
tmp_original_cwd = NULL;
startup_info->original_cwd = strbuf_detach(&tmp, NULL);
* Get our worktree; we only protect the current working directory
* if it's in the worktree.
worktree = get_git_work_tree();
if (!worktree)
goto no_prevention_needed;
offset = dir_inside_of(startup_info->original_cwd, worktree);
if (offset >= 0) {
* If startup_info->original_cwd == worktree, that is already
* protected and we don't need original_cwd as a secondary
* protection measure.
if (!*(startup_info->original_cwd + offset))
goto no_prevention_needed;
* original_cwd was inside worktree; precompose it just as
* we do prefix so that built up paths will match
startup_info->original_cwd = \
+ offset);
startup_info->original_cwd = NULL;
static int read_worktree_config(const char *var, const char *value, void *vdata)
struct repository_format *data = vdata;
@ -1330,6 +1394,7 @@ const char *setup_git_directory_gently(int *nongit_ok)