diff options
| author | Junio C Hamano <gitster@pobox.com> | 2022-01-05 14:01:28 -0800 |
|---|---|---|
| committer | Junio C Hamano <gitster@pobox.com> | 2022-01-05 14:01:28 -0800 |
| commit | da81d473fcfa67dfbcf0504d2b5225885e51e532 (patch) | |
| tree | 69f054e9d22dac00cf4b68705f3ab28dbb51a0b2 /setup.c | |
| parent | d0c99fcc618fc71cff261246b9d5605cbd225329 (diff) | |
| parent | 324b170b88475811cb0506a30b4710ffc89ae936 (diff) | |
| download | git-da81d473fcfa67dfbcf0504d2b5225885e51e532.tar.xz | |
Merge branch 'en/keep-cwd'
Many git commands that deal with working tree files try to remove a
directory that becomes empty (i.e. "git switch" from a branch that
has the directory to another branch that does not would attempt
remove all files in the directory and the directory itself). This
drops users into an unfamiliar situation if the command was run in
a subdirectory that becomes subject to removal due to the command.
The commands have been taught to keep an empty directory if it is
the directory they were started in to avoid surprising users.
* en/keep-cwd:
t2501: simplify the tests since we can now assume desired behavior
dir: new flag to remove_dir_recurse() to spare the original_cwd
dir: avoid incidentally removing the original_cwd in remove_path()
stash: do not attempt to remove startup_info->original_cwd
rebase: do not attempt to remove startup_info->original_cwd
clean: do not attempt to remove startup_info->original_cwd
symlinks: do not include startup_info->original_cwd in dir removal
unpack-trees: add special cwd handling
unpack-trees: refuse to remove startup_info->original_cwd
setup: introduce startup_info->original_cwd
t2501: add various tests for removing the current working directory
Diffstat (limited to 'setup.c')
| -rw-r--r-- | setup.c | 65 |
1 files changed, 65 insertions, 0 deletions
@@ -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) + return; + + /* + * 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); + free((char*)tmp_original_cwd); + 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 = \ + precompose_string_if_needed(startup_info->original_cwd + + offset); + return; + } + +no_prevention_needed: + free((char*)startup_info->original_cwd); + 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) setenv(GIT_PREFIX_ENVIRONMENT, "", 1); } + setup_original_cwd(); strbuf_release(&dir); strbuf_release(&gitdir); |
