从github存储库中删除本地文件夹中已删除的每个文件

q43xntqr  于 2023-02-14  发布在  Git
关注(0)|答案(3)|浏览(240)

我是git的新手,我找不到这个问题的答案,这有点奇怪。我想提交对我的文件夹“folder1”中所有文件的更改,下面是“folder1”的内容:

folder1
    pyproject1.py
    pyproject2.py
    myimg.png

为此,我使用以下命令行将我的更改提交到github存储库:

git add *
git commit-m"my changes"
git push origin main

但是,如果我尝试从本地文件夹中删除文件“myimg.png”,并再次执行以下命令行:

git add *
git commit-m"my changes"
git push origin main

myimg.png文件没有从github仓库中删除,我如何确保每次在本地文件夹中提交更改时,所有不在本地文件夹中的文件都从仓库中删除?

bqjvbblv

bqjvbblv1#

从技术上讲,可以用git add删除一个文件。这有点奇怪a-至少在我看来是这样的a a因为“add”看起来是 *add * 的意思,而不是 remove。但是还有一个更直接的命令,字面意思是 remove,也就是git rm
所以,你想要的是:

git rm myimg.png

这会将文件从工作树和Git的 index aka staging area(稍后会详细介绍)中移除,然后:

git add

任何其他更新的文件,然后:

git commit -m "commit message"

(you可以像你一样写引语这只是我个人的偏好,因为-m只带一个参数,在过去的20世纪80年代,这个参数通常是分开的,尽管Git本身直到21世纪初才出现)。

长读数和可选阅读:这里到底发生了什么

不管你使用的是什么Git教程,它都没有先教你Git的古怪之处,这对你有点伤害。Git是一个 * 分布式 * 版本控制系统(DVCS),这意味着额外的古怪之处,但它包含了短语“版本控制系统”,它本身有一些基本的想法:任何Version Control系统通常都需要提供一种“找回”旧版本的方法。有很多不同的方法可以实现这一点。Git是一种更现代的VCS(与Mercurial、Subversion、Bazaar和其他许多系统沿着),它基于 commits 的思想。commits充当检查点:你可以随时回到任何旧的提交。
为了实现这一点,Git将每个 * 提交 * 都存储为 * 每个文件 * 的 * 全快照 *(再加上一些细节,我们在这里就不讨论了)为了防止这一点立刻耗尽你的磁盘空间,Git使用了很多聪明的技巧,包括删除重复内容。所以如果你提交了100次,每一个都包含一个100兆字节的文件,但是文件本身在所有100次提交中都是 * 相同的 ,Git没有复制100个文件,而是有一个冻结的副本供所有人共享。共享这个副本是非常安全的,因为一旦提交完成, 任何提交的一部分都不能被修改 *。
就“删除"文件而言,这意味着什么非常简单:版本控制系统需要知道你的下一个提交不应该有这个文件,如果提交#3有这个文件,而提交#4没有,那么很明显这个文件在第3步和第4步之间被删除了。
Git中的复杂性体现在以下几个方面:首先,虽然Git * 中的提交是有编号的,但编号本身很奇怪。每个提交都有一个唯一的编号,当我说唯一时,我不是指“在某个限制内唯一”,我是指唯一。没有Git提交,无论何时何地,在任何存储库中,已经使用过这个数字。任何Git仓库中的任何提交都不会再使用这个数字!1 Git称这个“提交号”为 hash ID,它又大又丑,不适合人类食用,所以除了用鼠标剪切和粘贴或其他什么,我们自己通常不会使用这些。
不过,那个又大又丑的哈希ID才是每个提交的“真实名称”。通过将哈希ID * 赋给 * Git,你可以取回任何更早的提交,包括你“删除”的文件。因此,被删除的文件仍然存在于 repository 中。但这给我们带来了一些明显的问题:

  • 提交的文件以一种奇怪的、冻结的、Gitty的方式存储。
  • 只有 Git 可以 * 读取 * 它们,而且没有任何东西,什至Git本身,可以 * 覆盖 * 它们。
  • 这意味着我们什么工作都做不成。

所有的版本控制系统都有这个问题,而且几乎所有的版本控制系统都使用相同的解决方案。
1当然,这是mathematically impossible,所以不完全正确。但是如果你把两个不相关的Git仓库放在一起,并且它们不小心在两个不同的提交中使用了相同的编号,Git就会崩溃。Ideally, this never happens, and in practice it doesn't.
2哈希ID或对象ID(OID),实际上,Git过去常常称之为 SHA1,因为现有的哈希函数是SHA-1;如前所述,Git正在缓慢地转向SHA-256,因此有必要停止使用术语“SHA-1”。

“工作树”

在一个面向提交的系统中,你通常从挑选一些已经存在的提交来 check out 开始,使用一些动词,比如 checkoutswitchextract。Git使用git checkoutgit switch。2然后版本控制系统定位那个提交,以及它的所有文件,并从提交中 * 提取 * 文件。Git称这个工作区为你的 * 工作树 * 或 * 工作树 *。3你选择的提交成为你的 * 当前提交 *,在Git中,你选择的 * 分支名称 * 成为你的 * 当前分支名称 *。(这里也有很多特殊的Git怪异之处,出于篇幅的原因,我省略了。

所以在一次结账操作之后(或git switch命令),你的工作树现在已经充满了所有的文件,无论它们在你或其他人提交你刚刚选择使用的提交时是什么形式。工作树中的文件是普通的日常文件,可以被普通的日常编辑器、普通的Python或浏览器或其他使用它们的东西使用。等等。所以现在你可以完成工作了!
重要的是要意识到 * 这些文件不在Git中 *。它们可能刚刚从Git中 * 出来 ,但现在它们已经 * 出来了,它们并没有“进来”。当你处理这些文件时,Git甚至都不知道这一点。4所以当你处理完这些文件时,告诉Git 是很重要的。但这里的事情变得非常奇怪。在其他系统中,比如Mercurial,你使用hg rm来删除一个文件,而你只需要使用hg commit--不需要一直使用hg add--因为hg commit会计算出你修改了什么。
git switch命令是Git 2.23中新增的,它是将过于复杂的git checkout拆分为git switchgit restore的结果,现在你可以使用其中任何一个,但是如果你有Git 2.23或更高版本,我建议首选git switch,因为它 * 通常 * 不那么令人困惑(由于将并发症移到了git restore)。
3运行Git的操作系统有一个 * 当前工作目录 * 或cwd的概念,通常可以通过pwd或打印工作目录命令或$PWD *shell变量 * 获得。Git过去常常把cwd和工作树术语混在一起,人们会感到困惑。现在仍然会相当困惑,因为Git使用cwd来查找存储库。它存储在工作树顶层的一个隐藏的.git文件夹中。这使得一些东西有点颠倒:存储库被存储在工作树中!2即使工作树不是存储库的一部分,这也是正确的。
如果你愿意,Git允许你查看隐藏文件夹的内部,但一般来说,你应该(a)不依赖于它的形式,(B)不接触该文件夹中的任何内容。Git对隐藏文件夹中的文件非常敏感,云同步软件如Dropbox或iCloud * 最终会 * 损坏仓库。因此,将工作树存储在云同步文件夹中是不明智的:储存库在工作树内,因此受到该相同同步的影响,这破坏了该同步。
4为了提高速度,现代的Git正在慢慢地获得一个“文件系统监视器”的设置,它可以让Git在某种程度上感知这里发生的事情。这个的设计 * 必须 * 考虑到一个事实,即旧的Git没有这个,而且在大多数系统上,这样的监视器有时会丢失信息,所以除了让事情更快之外,FSMonitor应该就像它根本不存在一样。如果你的系统有FSMonitor可用--目前Windows和macOS都有--而你打开它后发现它不正常,只需再次关闭它。Linux支持正在酝酿中。

Git的 * 索引 * 或 * 临时区域 *

正如我刚才提到的,其他版本控制系统,如Mercurial,只是让你运行hg commit,这个命令花了很多时间来找出你在工作树中修改了什么,并提交这些修改。(Mercurial使用 * 变更集 * 模型进行提交,而不是Git的 snapshot 模型。)Git是不同的。Git强迫你每次都运行git add。为什么?答案就在于Git多了一个东西,它又大又乱,有三个名字:

  • Git有时会把它叫做"index“,这是一个没有意义的名字,我喜欢用这个词,因为它涵盖了Git所做的一切,但它不是很容易记住。
  • Git有时称之为该高速缓存“,因为它的工作很大一部分是让Git运行得更快(hg commit可能需要几分钟,但git commit通常在几毫秒内完成,其中只有一部分是因为hg在Python中以及Git正在编译,而很大一部分是因为索引)。
  • 最后,在更现代的文档中,Git称之为 staging area,指的是你通常使用它的方式:以 * 暂存 * 将进入 * 下一个 * 提交的内容。

索引中的内容可以非常准确地描述为:**索引保存了 * 建议的下一个提交快照 *。**就是它--这是暂存区的真实的键,它是 * 建议的下一个快照 *--但这有很多后果。
特别是,你现在知道(或者应该知道)任何一个提交中的文件都是某种奇怪的Git化格式,非Git软件无法使用。Git索引中的文件也是如此。在Git中,文件的 committed 副本和文件的 index 副本之间的关键区别在于 index 副本 * 可以被替换 *。(committed副本将被永久冻结。)

这意味着什么也很简单:* * 你总是有(最多)每个"active"文件的三个副本。也就是说,假设你现有的提交有文件README.mdfolder1/pyproject1.py。5那么实际上有README.md的 * 三个副本 * 和folder1/pyproject1.py的 * 三个副本
这些"活动副本"中的一个是冻结的当前提交副本。这个副本 * 不能 * 被更改,因为它在提交中。另一个是 * 索引 * 或 * 暂存区 * 副本。最初,它与提交的副本相同--而且由于Git的内部格式是去重的,所以它被去重后完全使用了原始副本。但是你 * 可以 * 用一个新副本替换它:这不会覆盖原始文件,它只是添加一个新版本的文件-或者找到另一个已有的副本来重用-并准备提交。第三个副本是普通文件,在你的工作树中。
git add命令表示:
读取工作树副本并准备提交,替换旧的索引副本。
git rm命令的含义是:
删除索引副本和工作树副本。*
如果你运行git add removedfile,Git会尝试读取被移除文件的工作树副本,* 然后 * 发现它被移除了。所以git add removedfile注意到,嘿,文件不见了,但它仍然在Git的索引中。显然你是指git rm removedfile! Git从索引中移除文件。并且不对工作树中已经删除的文件执行任何操作,这就是git add * 可以 * 表示git rm的方式。
5请注意,对于Git来说,这是一个名为folder1/pyproject1.py的 * 文件。* 它不是一个名为folder1的文件夹,其中包含一个名为pyproject1.py的文件。Git知道如何在操作系统要求的文件存放在文件夹中Git的要求是索引中的内容必须有一个长文件名,并且要嵌入正斜杠,但事实上索引只能保存文件,这意味着你不能在Git中存储一个空文件夹。这里有一两个技巧:参见How do I add an empty directory to a Git repository?

好吧,但是为什么git add *不起作用呢?

我们现在到了Windows CMD.EXE和目前使用的几乎所有其他命令行解释器不同的地方。
在类Unix shell(bash、csh、sh、tcsh、zsh等)中,是 * shell *(命令行解释器或CLI)处理*

*

或:

foo*

或:

folder1/*

并且 * shell * 查找 * 当前目录中的所有文件 * 或 * 当前目录中以foo开头的所有文件 * 或 * folder1/文件夹中的所有文件 * 并展开它们的名称。6
如果你已经删除了一个文件,git add *不会列出它,因为 * shell * 将*扩展到了这里的文件集。删除的文件不在这里,所以它不会列出!
在旧的CMD.EXE上,CLI * 不 * 处理*。这会传递一个星号给Git。因为Git试图适应这些旧系统,Git有自己的globbing7代码。这段代码使用Git索引中的内容,所以在这里,git add * * 将 * 添加删除文件!
这个索引还有很多内容,但我尽量让这个答案相对简短。如果这看起来像是很多信息,那么请记住,一个 * 好的 * Git教程到目前为止已经涵盖了所有这些内容,这些都应该回顾给你听。
[6]这里有一个微妙的陷阱,在一些shell中是可控的,但不是所有的:*找不到名为.hidden * 的文件,除非在bash中打开dotglob

$ shopt dotglob
dotglob         off
$ echo *
cover.html cover.out Makefile ...
$ shopt -s dotglob
$ echo *
.git .gitignore .golangci.yml cover.html cover.out Makefile ...

大多数人通常会关闭dotglob,以便隐藏.git之类的内容,但这意味着git add *不会添加.gitignore
7 *和其他 * glob字符 * 的扩展称为 * globbing *,对于historical reasons,这些字符称为 * glob字符。他们运行了"另一个程序"来完成这一任务。早期版本的Unix运行在内存不足64k的电脑上,内存最大值为64k,有时为128k。下次你在128GB的手机上下载50MB的应用程序时,请考虑一下这个问题。

nwwlzxa7

nwwlzxa72#

我找到了我想要的东西。我的目标是自动添加所有删除的文件,这样它们就不会再出现在我的存储库中。使用git rm myimg.png这样的方法的问题是,我不想对我文件夹中删除的每个文件都这样做。解决方案是使用git add .而不是git add *。如果我想添加修改和删除的文件,是在我当前的文件夹中,我应该使用git add -A . .更多信息可以在这个网站上找到,例如:https://intellipaat.com/community/14450/git-add-all-files-modified-deleted-and-untracked

xuo3flqw

xuo3flqw3#

this answer中,您将找到一种从Git中删除文件的方法。
无论如何,如果你删除了本地副本上的一个文件,提交并推送它,那么它在你的远程副本上也应该被删除。请尝试使用git commit,而不使用message参数。这将打开一个文本编辑器,在那里你可以看到你的更改(这实际上不是查看更改的方法,但在这种情况下效果很好;)并在此发布截图。

相关问题