That error won't happen again after Git 2.35 (Q1 2022):
Actually, after Git 2.35.1 (Jan. 29th 2022, see last section of this answer)
No more "fatal: Unable to read current working directory: No such file or directory
"
Many git
commands that deal with working tree files tried to remove a directory that becomes empty (i.e.
"git switch
"(man) 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.
See commit 324b170, commit 580a5d7, commit 63bbe8b, commit 0fce211, commit bc3ae46, commit c65744e, commit 00fcce2, commit 0b0ee33, commit b817e54, commit e6f8861, commit 8a0d52d (09 Dec 2021) by Elijah Newren (newren
).
(Merged by Junio C Hamano -- gitster
-- in commit da81d47, 05 Jan 2022)
dir
: avoid incidentally removing the original_cwd
in remove_path()
Acked-by: Derrick Stolee
Acked-by: Ævar Arnfjörð Bjarmason
Signed-off-by: Elijah Newren
Modern git often tries to avoid leaving empty directories around when removing files.
Originally, it did not bother.
This behavior started with commit 80e21a9 ("merge-recursive
::removeFile: remove empty directories", 2005-11-19, Git v0.99.9k -- merge), stating the reason simply as:
When the last file in a directory is removed as the result of a
merge, try to rmdir the now-empty directory.
This was reimplemented in C and renamed to remove_path()
in commit e1b3a2c ("Build-in merge-recursive", 2008-02-07, Git v1.5.5-rc0 -- merge), but was still internal to merge-recursive.
This trend towards removing leading empty directories continued with commit d9b814c (Add builtin , 2006-05-19, Git v1.4.1-rc1 -- merge) (Add builtin "git rm
"(man) command, 2006-05-19), which stated the reasoning as:
The other question is what to do with leading directories.
The old "git rm
" script didn't do anything, which is somewhat inconsistent.
This one will actually clean up directories that have become empty
as a result of removing the last file, but maybe we want to have a
flag to decide the behaviour?
remove_path()
in dir.c
was added in 4a92d1b ("Add remove_path
: a function to remove as much as possible of a path", 2008-09-27, Git v1.6.1-rc1 -- merge), because it was noted that we had two separate implementations of the same idea AND both were buggy.
It described the purpose of the function as
a function to remove as much as possible of a path
Why remove as much as possible? Well, at the time we probably would have said something like:
- removing leading directories makes things feel tidy
- removing leading directories doesn't hurt anything so long as they had no files in them.
But I don't believe those reasons hold when the empty directory happens to be the current working directory we inherited from our parent process.
Leaving the parent process in a deleted directory can cause user confusion when subsequent processes fail: any git command, for example, will immediately fail with
fatal: Unable to read current working directory: No such file or directory
Other commands may similarly get confused.
Modify remove_path()
so that the empty leading directories it also deletes does not include the current working directory we inherited from our parent process.
With Git 2.35.1 (Jan. 29th, 2022), fix a regression in 2.35 that broke the use of "rebase
" and "stash
" in a secondary worktree.
See commit ff5b791 (26 Jan 2022) by Elijah Newren (newren
).
(Merged by Junio C Hamano -- gitster
-- in commit b23dac9, 26 Jan 2022)
sequencer, stash
: fix running from worktree subdir
Test-case-by: Glen Choo
Signed-off-by: Elijah Newren
In commits bc3ae46 (rebase
: do not attempt to remove startup_info->original_cwd, 2021-12-09, Git v2.35.0-rc0 -- merge listed in batch #7) ("rebase: do not attempt to remove startup_info->original_cwd",
2021-12-09) and 0fce211 (stash
: do not attempt to remove startup_info->original_cwd, 2021-12-09, Git v2.35.0-rc0 -- merge listed in batch #7) ("stash: do not attempt to remove startup_info->original_cwd",
2021-12-09), we wanted to allow the subprocess to know which directory the parent process was running from, so that the subprocess could protect it.
However...
When run from a non-main worktree, setup_git_directory()
will note that the discovered git directory (/PATH/TO/.git/worktree/non-main-worktree) does not match DEFAULT_GIT_DIR_ENVIRONMENT
(see setup_discovered_git_dir()
), and decide to set GIT_DIR
in the environment.
This matters because...
Whenever git is run with the GIT_DIR
environment variable set, and GIT_WORK_TREE
not set, it presumes that '.' is the working tree.
So...
This combination results in the subcommand being very confused about the working tree.
Fix it by also setting the GIT_WORK_TREE
environment variable along with setting cmd.dir
.
With Git 2.37 (Q3 2022), disable the "do not remove the directory the user started Git in" logic when Git cannot tell where that directory is.
Earlier we refused to run in such a case.
See commit c37c6dc (24 May 2022) by Kevin Locke (kevinoid
).
(Merged by Junio C Hamano -- gitster
-- in commit 37d4ae5, 03 Jun 2022)
setup
: don't die if realpath(3)
fails on getcwd(3)
Signed-off-by: Kevin Locke
Reviewed-by: Elijah Newren
Prior to Git 2.35.0, git could be run from an inaccessible working directory so long as the git repository specified by options and/or environment variables was accessible.
For example:
git init repo
mkdir -p a/b
cd a/b
chmod u-x ..
git -C "${PWD%/a/b}/repo" status
If this example seems a bit contrived, consider running with the repository owner as a substitute UID (e.g. with runuser(1)
or sudo(8)
) without ensuring the working directory is accessible by that user.
The code added by e6f8861 (setup
: introduce startup_info->original_cwd, 2021-12-09, Git v2.35.0-rc0 -- merge listed in batch #7) ("setup: introduce startup_info->original_cwd")
to preserve the working directory attempts to normalize the path using strbuf_realpath()
.
If that fails, as in the case above, it is treated as a fatal error.
This commit treats strbuf_realpath()
errors as non-fatal.
If an error occurs, setup_original_cwd()
will continue without applying removal prevention for cwd, resulting in the pre-2.35.0 behavior.
The risk should be minimal, since git will not operate on a repository with inaccessible ancestors, this behavior is only known to occur when cwd is a descendant of the repository, an ancestor of cwd is inaccessible, and no ancestors of the repository are inaccessible.