【问题标题】:Is git supposed to delete empty directories?git应该删除空目录吗?
【发布时间】:2019-04-03 03:59:09
【问题描述】:

我最近对目录中的最后一个文件进行了git rm(a),由于某种原因,它决定也删除该目录。我用一个新文件测试了如下行为:

mkdir newdir
touch newdir/newfile
git add newdir/newfile
git commit
git rm newdir/newfile

当我执行最后一行时,newdir 目录完全消失了。这是预期的行为吗?我的理解是 Git 跟踪的是文件,而不是目录。

既然在上面的第一步之后它没有抱怨,创建一个没有跟踪文件的目录,为什么仅仅因为我从中删除了最后一个跟踪文件就删除了一个目录? p>

不管怎样,我运行的是 2.7.4 版。


(a) 我有一个带有 gitDummy 文件的占位符目录,因此它被推送到 repo。然后我有很多 real 文件要添加,所以我删除了虚拟文件,然后尝试复制新文件以准备添加、提交和推送。

你瞧,复制操作失败了,因为目录已经消失了。我怀疑如果我在删除虚拟对象之前复制了文件之前会起作用,但我仍然感到奇怪的是,Git 在不应该关心目录时删除了目录。

【问题讨论】:

  • 也可在 v2.17.1 上重现
  • 我可以在 2.20.1 中重现相同的内容。但是,如果我添加 test/.gitkeep 目录会保留并且 git 不会删除它。也许 git 删除本地目录很奇怪,但既然它无论如何都会是空的,而且 git 无论如何都会忽略它,我觉得它在帮我一个忙,把它一起删除,这样我以后就不会被它弄糊涂了。在 GIt 中维护空文件夹的正确方法是使用 .gitkeep 文件
  • 由于 git rm 阶段发生变化,我认为根据这些变化将工作树与 repo 的状态同步是有意义的。 (毕竟,如果有人拉了它,它会删除他们的目录副本。)
  • TLDR;我的长答案:是的,Git 应该删除删除最后跟踪内容的空文件夹。
  • 附带说明一下,我见过 Git 删除最终没有文件的目录的情况(例如,在git checkout 之后)。我从来没有能够重现这个,所以我不确定是什么原因造成的。

标签: git


【解决方案1】:

2022:

这应该不再是Git 2.35 (Q1 2022) 的问题

不再有“fatal: Unable to read current working directory: No such file or directory


2019:原始答案:

在此June 2018 thread 中紧随其后,报告为“git rm bug

TLDR;这不是错误。

当从提交 X 移动到 Y 时,任何 Git 命令都不应该让树处于这样一种状态,如果您重新克隆,您将不会得到相同的 Y

进入话题:

概览

"git rm" 将删除比指定更多的文件。这是一个错误或未记录的行为(不在手册页中)。

设置

  1. 在 git 存储库中,创建一个空目录或一个空目录链

    $ mkdir -p path/to/some/

  2. 在最深的目录中创建一个文件并添加到跟踪中

    $ touch path/to/some/file $ git 添加路径/到/一些/文件 $ git commit -m '添加路径/到/一些/文件'

错误

对跟踪的文件运行“git rm”。

预期行为

$ git rm path/to/some/file
rm 'path/to/some/file'
$ ls path
to/
$ ls path/to
some/

请注意,path/path/to/path/to/some/ 仍然存在。

实际行为

$ git rm path/to/some/file
rm 'path/to/some/file'
$ ls path
ls: cannot access 'path': No such file or directory

尽管 git 仅输出“rm 'path/to/some/file'”,但删除了整个空目录链。

只有在删除跟踪文件后链中的所有目录都为空时才会发生这种情况。

此行为未记录在手册页中。

我建议将“rmdir”语句添加到“git rm”输出中,或者更新手册页以反映这种行为。

一般原则是:

Git 无法跟踪空目录。
由于这是整个层次结构中的唯一内容,因此必须删除整个层次结构。

d9b814cc97 ("Add builtin "git rm" command", 2006-05-19, Git v1.4.0-rc1) 开始,这种行为似乎已经存在很多年了。
有趣的是,Linus 在提交消息中指出,前导目录的删除与 git-rm 是一个 shell 脚本时不同。
他想知道是否值得选择控制 这种行为。

我想大多数用户要么想要当前的行为 或者他们很少遇到这种情况并感到惊讶,因为 long git rm 就是这样工作的。

这也与 Git 中删除文件的其他部分一致。例如。, "git checkout" 到没有文件的状态将删除 前导目录(当然,如果它们是空的)。

更笼统地说:

我将逆向和固执,并建议当前的行为很好,因为没有任何其他行为的令人信服的理由。

对于挂在空目录上的所有防御措施总是沸腾 归结为,“我将来可能会做一些期望这些目录存在的事情。”
好吧,如果是这样的话,那么当你需要它们时创建它们——你所做的任何事情都不应该简单地假设基本目录的存在。

此外,通过“取消跟踪”这些目录,您建议 Git 悄悄地做通常应该由“git rm --cached”做的事情。
如果我想要这种行为,我宁愿自己输入。

举例说明为什么删除空文件夹会有问题:

其他人已经说了原因,但这里有一个你可能没有的极端情况 想到了:

(
   rm -rf /tmp/repo &&
   git init /tmp/repo &&
   cd /tmp/repo &&
   mkdir -p foo/bar/baz &&
   git status
)

如果您只有空目录“git status”将不会报告任何内容, 虽然“git clean -dxfn”会显示要清理的内容。

因此,如果这按您的建议进行,那么有人可以git rm some 文件,然后一切都会报告他们正在提交XYZ,但如果他们在该提交处重新克隆,他们会得到一棵看起来不同的树。

任何 Git 命令都不应该以将树留在 从提交 X->Y 移动时的状态,如果你不会得到相同的 Y 你重新克隆了。


注意:Git 存储库本身的官方git rm test (git/git/t/t3600-rm.sh) 非常清楚它的预期:

test_expect_success 'rm removes subdirectories recursively' '
    mkdir -p dir/subdir/subsubdir &&
    echo content >dir/subdir/subsubdir/file &&
    git add dir/subdir/subsubdir/file &&
    git rm -f dir/subdir/subsubdir/file &&
    ! test -d dir

【讨论】:

  • 这是一个很好的答案。谢谢。
  • “在从提交 X 移动到 Y 时,任何 Git 命令都不应该以这样的方式运行,即如果重新克隆,您将不会得到相同的 Y。” --- ".gitignore" 很容易违背这个承诺。
  • @zerkms 有点……但.gitignore 是指令,而不是命令。 git rm 是一个命令。而.gitignore 是关于未跟踪 的内容。 git rm 删除文件夹是关于提交之间的跟踪内容一致性。
猜你喜欢
  • 2021-02-27
  • 2010-12-29
  • 2013-05-25
  • 1970-01-01
  • 2021-04-11
  • 2013-08-05
  • 2014-04-15
  • 2018-01-02
  • 2010-11-16
相关资源
最近更新 更多