这个错误在 Git 2.35(2022年第一季度)之后不会再发生:
实际上,在 Git 2.35.1(2022年1月29日,见本答案的最后一部分)之后也不会再出现了。
不再出现 "
fatal: Unable to read current working directory: No such file or directory
" 错误。
许多处理工作树文件的
git
命令会尝试删除一个变成空目录的目录(例如从包含该目录的分支“
git switch
”
(man) 切换到不包含该目录的另一个分支,会尝试删除该目录中的所有文件和该目录本身)。如果该命令运行在一个由于该命令而成为可删除对象的子目录中,则会将用户置于一个陌生的情境中。
为了避免给用户带来惊喜,这些命令已经被修改,使它们在起始目录为空目录时保留该目录。
查看
提交 324b170,
提交 580a5d7,
提交 63bbe8b,
提交 0fce211,
提交 bc3ae46,
提交 c65744e,
提交 00fcce2,
提交 0b0ee33,
提交 b817e54,
提交 e6f8861,
提交 8a0d52d (于2021年12月09日) 由
Elijah Newren (newren
)完成。
(合并自Junio C Hamano -- gitster
--在提交 da81d47,于2022年01月05日)
dir
:在
remove_path()
中避免意外删除
original_cwd
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.
在Git 2.35.1(2022年1月29日)中,修复了2.35中的回归问题,该问题破坏了在辅助工作树中使用“
rebase
”和“
stash
”的功能。
请参见
commit ff5b791(2022年1月26日),作者为
Elijah Newren (newren
)。
(由Junio C Hamano -- gitster
--于commit b23dac9合并,2022年1月26日)
sequencer, stash
:修复从工作树子目录运行的问题
测试用例由Glen Choo提供
由Elijah Newren签名
在提交
bc3ae46(
rebase
:不要尝试删除startup_info->original_cwd,2021-12-09,Git v2.35.0-rc0 --
合并列在
批次#7中)(“rebase:不要尝试删除
startup_info->original_cwd
”,2021-12-09)和
0fce211(
stash
:不要尝试删除startup_info->original_cwd,2021-12-09,Git v2.35.0-rc0 --
合并列在
批次#7中)(“stash:不要尝试删除
startup_info->original_cwd
”,2021-12-09),我们希望子进程能够知道父进程从哪个目录运行,以便子进程可以保护它。
然而...
当从非主工作树运行时,
setup_git_directory()
将注意到发现的git目录(/PATH/TO/.git/worktree/non-main-worktree)与
DEFAULT_GIT_DIR_ENVIRONMENT
不匹配(请参见
setup_discovered_git_dir()
),并决定在环境中设置
GIT_DIR
。
这很重要,因为...
每当设置了
GIT_DIR
环境变量并且未设置
GIT_WORK_TREE
时运行git,它会假定“.”是工作树。
所以...
这种组合导致子命令对工作树非常困惑。
通过设置
cmd.dir
同时设置
GIT_WORK_TREE
环境变量来修复它。
使用 Git 2.37(2022 年第三季度),当 Git 无法确定用户启动 Git 的目录时,禁用“不要删除该目录”的逻辑。
早期我们会拒绝在这种情况下运行。
请参见 commit c37c6dc(2022 年 5 月 24 日)由 Kevin Locke (kevinoid
) 提交。
(由 Junio C Hamano -- gitster
-- 在 commit 37d4ae5 中合并,2022 年 6 月 3 日)
“设置:如果在获取当前工作目录时realpath(3)
失败,请勿死亡。”
签名作者:Kevin Locke
审核者: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.