Skip to content

Commit e6f8861

Browse files
newrengitster
authored andcommitted
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 hello 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 <[email protected]> Acked-by: Ævar Arnfjörð Bjarmason <[email protected]> Signed-off-by: Elijah Newren <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 8a0d52d commit e6f8861

File tree

3 files changed

+71
-0
lines changed

3 files changed

+71
-0
lines changed

cache.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1834,8 +1834,10 @@ void overlay_tree_on_index(struct index_state *istate,
18341834
struct startup_info {
18351835
int have_repository;
18361836
const char *prefix;
1837+
const char *original_cwd;
18371838
};
18381839
extern struct startup_info *startup_info;
1840+
extern const char *tmp_original_cwd;
18391841

18401842
/* merge.c */
18411843
struct commit_list;

common-main.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ static void restore_sigpipe_to_default(void)
2626
int main(int argc, const char **argv)
2727
{
2828
int result;
29+
struct strbuf tmp = STRBUF_INIT;
2930

3031
trace2_initialize_clock();
3132

@@ -49,6 +50,9 @@ int main(int argc, const char **argv)
4950
trace2_cmd_start(argv);
5051
trace2_collect_process_info(TRACE2_PROCESS_INFO_STARTUP);
5152

53+
if (!strbuf_getcwd(&tmp))
54+
tmp_original_cwd = strbuf_detach(&tmp, NULL);
55+
5256
result = cmd_main(argc, argv);
5357

5458
trace2_cmd_exit(result);

setup.c

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ static int work_tree_config_is_bogus;
1212

1313
static struct startup_info the_startup_info;
1414
struct startup_info *startup_info = &the_startup_info;
15+
const char *tmp_original_cwd;
1516

1617
/*
1718
* The input parameter must contain an absolute path, and it must already be
@@ -432,6 +433,69 @@ void setup_work_tree(void)
432433
initialized = 1;
433434
}
434435

436+
static void setup_original_cwd(void)
437+
{
438+
struct strbuf tmp = STRBUF_INIT;
439+
const char *worktree = NULL;
440+
int offset = -1;
441+
442+
if (!tmp_original_cwd)
443+
return;
444+
445+
/*
446+
* startup_info->original_cwd points to the current working
447+
* directory we inherited from our parent process, which is a
448+
* directory we want to avoid removing.
449+
*
450+
* For convience, we would like to have the path relative to the
451+
* worktree instead of an absolute path.
452+
*
453+
* Yes, startup_info->original_cwd is usually the same as 'prefix',
454+
* but differs in two ways:
455+
* - prefix has a trailing '/'
456+
* - if the user passes '-C' to git, that modifies the prefix but
457+
* not startup_info->original_cwd.
458+
*/
459+
460+
/* Normalize the directory */
461+
strbuf_realpath(&tmp, tmp_original_cwd, 1);
462+
free((char*)tmp_original_cwd);
463+
tmp_original_cwd = NULL;
464+
startup_info->original_cwd = strbuf_detach(&tmp, NULL);
465+
466+
/*
467+
* Get our worktree; we only protect the current working directory
468+
* if it's in the worktree.
469+
*/
470+
worktree = get_git_work_tree();
471+
if (!worktree)
472+
goto no_prevention_needed;
473+
474+
offset = dir_inside_of(startup_info->original_cwd, worktree);
475+
if (offset >= 0) {
476+
/*
477+
* If startup_info->original_cwd == worktree, that is already
478+
* protected and we don't need original_cwd as a secondary
479+
* protection measure.
480+
*/
481+
if (!*(startup_info->original_cwd + offset))
482+
goto no_prevention_needed;
483+
484+
/*
485+
* original_cwd was inside worktree; precompose it just as
486+
* we do prefix so that built up paths will match
487+
*/
488+
startup_info->original_cwd = \
489+
precompose_string_if_needed(startup_info->original_cwd
490+
+ offset);
491+
return;
492+
}
493+
494+
no_prevention_needed:
495+
free((char*)startup_info->original_cwd);
496+
startup_info->original_cwd = NULL;
497+
}
498+
435499
static int read_worktree_config(const char *var, const char *value, void *vdata)
436500
{
437501
struct repository_format *data = vdata;
@@ -1330,6 +1394,7 @@ const char *setup_git_directory_gently(int *nongit_ok)
13301394
setenv(GIT_PREFIX_ENVIRONMENT, "", 1);
13311395
}
13321396

1397+
setup_original_cwd();
13331398

13341399
strbuf_release(&dir);
13351400
strbuf_release(&gitdir);

0 commit comments

Comments
 (0)