为什么提交一个文件,但所有文件都在 RStudio 中提交?

Why Commiting one file, but all files are committed in RStudio?

我在 Github 上有一个存储库,里面有一些文件,我在 RStudio 服务器上有一个文件夹,里面也有一些文件。我对一些文件做了一些更改,但我只想使用命令

提交一个文件(test.Rmd)
git init
git add test.Rmd
git commit -m "Adding some plots" 
git push

而不是仅提交此文件,而是提交文件 test.Rmd 所在文件夹中的所有文件。为什么会这样?我尝试对不同文件夹中的另一个文件执行完全相同的操作,并且提交成功了。在此之前,似乎我已经做了一些事情,比如

git init
git add .

这就是它添加目录中所有文件的原因?

使用 git status 结果

我现在怀疑问题是取消添加这些大文件?我想我在最后使用 git push 时不知不觉地提交了所有文件的所有更改。

你的问题充其量是模棱两可的,并且包含一些错误的假设,所以这个答案很长。

一些关于 Git 提交和 git init

的背景

Git 中的所有提交始终包含所有文件。这就是 Git 本身的工作原理。

运行 git init 将:

  • 在当前工作目录中创建一个新的空 Git 存储库,或者
  • 重新初始化现有的 Git 存储库。

你得到 second 行为——重新初始化现有的 Git 存储库——如果 Git 发现你在一些现有的 Git 存储库。 git init 的输出告诉你它做了哪一个:

$ git init
Initialized empty Git repository in [path, redacted]
$ git init
Reinitialized existing Git repository in [path, redacted]

除了一些几乎肯定不适用于您使用方式的特殊情况外 Git,“重新初始化”变体实际上根本没有做任何事情:您现有的存储库保持不变。

git init 创建一个新的、完全空的存储库时,没有提交,因此还没有 b运行ches。因此,您所做的 next 提交是第一次提交。这个提交有点特殊:它是一个 root 提交,没有历史记录。它包含您告诉 Git 要包含的任何文件,使用 git add.

不过,在这一点之后,您将拥有一个包含现有提交的现有 Git 存储库。这包括您使用 git clone 将一些现有存储库(例如,从 GitHub)复制到您自己机器(例如,您的笔记本电脑)上的新 Git 存储库的情况。你会告诉 Git 检查 一些特定的提交——通常是一些 b运行ch name 的提示提交—这意味着 Git 将使用提交的 来自 的所有文件填充其暂存区和您的工作树。

随后,您将编辑一些文件,甚至可能创建一些新文件。然后您 运行 git add 处理一个或多个这些文件。如果您正在 git add-ing 一个 已经存在 在 Git 的暂存区中的文件,Git 会从其暂存区中丢弃旧副本area 并用你的工作树制作的新副本覆盖暂存区副本。或者,如果您 git add 一个全新的文件,Git 将文件 复制到 其暂存区,作为一个新文件。

在所有这些情况下,暂存区中的所有现有文件都保留在那里。您的下一个 git commit 需要 全部 Git 暂存区中的文件,并从中制作快照。

一个具体的例子

假设你有一个现有的存储库,其中主要的 b运行ch(不管它的名字是什么:GitHub 现在鼓励人们使用 main 而旧的存储库倾向于使用 master) 在其最近的提交中有十个文件。你 git clone 把这个存储库放到你的笔记本电脑上,所以你的笔记本电脑 Git 软件(“你的 Git”)检查最后一次提交,将十个文件提取到 Git 的暂存中区域和你的工作树。

您现在更改工作树中十个文件中的 五个,但是 运行 git add一个[=198] =] 五个更新的文件。这意味着您的 Git 的暂存区中有十个文件:九个文件与 当前提交 中的一个匹配,一个与您的 [=127= 中的更新文件匹配]工作树。四个暂存区文件不同于对应的四个工作树文件;其余六个暂存区文件与其对应的工作树匹配。

如果您现在 运行 git commit -m haaaaaands,您将获得包含十个文件的新提交 与它们现在出现在暂存区中的完全一样 。您的工作树中仍然有所有更新的工作树文件,但是暂存区副本仍然与先前提交的副本匹配,因此新提交的副本与旧提交的副本匹配,除了您 运行 git add.

您刚刚进行的新提交 成为 当前 提交,这是您笔记本电脑存储库中当前的最新提交b运行ch。您现在可以使用 git push 将此 commit 发送到 GitHub 存储库;如果你最终这样做了,他们收到的提交将逐位匹配存储在笔记本电脑存储库中的 Git 提交。它将具有 9 个文件匹配一个文件不匹配的情况;他们获得的提交将以先前的提交作为其父提交;等等。

关于 git status

的一些知识

首先,git status 会告诉您有关 当前 b运行ch 的信息。它会说类似 on branch main 的内容。这是你的 Git 告诉你你的笔记本电脑存储库有 main 作为 当前 b运行ch。您的 Git 也可能告诉您您“领先” and/or “落后”其他名称,例如 origin/main:这使用 完全存储在本地的信息 ,在你的笔记本电脑上。此信息可能已过时,具体取决于其他 Git 存储库在 GitHub 上或其他任何地方的活跃程度。

接下来,如果您不在冲突合并的中间——如果您在,剩下的会变得更复杂——git status 命令 运行s two 比较:

  • 首先,它将当前提交中的文件与暂存区中的文件进行比较。其中一些文件通常会完全匹配,因为自从它们从某个提交中提取后您没有对它们进行任何操作。对于那些文件,您的 Git 什么也没说。

    暂存区中的其他文件不会匹配您当前的提交,因为例如您运行 git add在它们上面。在这种情况下,您的 Git 会说这些文件 暂存用于提交 。这只是意味着暂存区副本在某些方面不同于当前提交的副本。

    请注意,暂存区中的一些文件可能是新的。也就是说,这些文件根本不存在于 current 提交中。对于这些文件,Git 会说这些是“新文件”。

  • 已列出文件“暂存以供提交”,或未找到任何要列出的文件,您的 Git 现在继续将暂存区中的文件与工作区中的文件进行比较树。和以前一样,一些文件可能匹配。其他文件可能不同 — 甚至您的工作树中的一些文件在暂存区中根本没有对应文件:和以前一样是新文件。

    不过这一次,您的 Git 只会告诉您有关 已更改的 个文件,并表示此类文件 未暂存提交 。它确实也收集了每个 new 文件的列表,但将它们推迟到下一部分。

  • 列出所有“未准备提交”的文件后,您的 Git 继续告诉您 未跟踪的文件 。这些是您的工作树中 不在 Git 暂存区中的任何文件。换句话说,这些是“新”文件。

    关于这些的奇怪之处在于它们是如何分离出来的,作为一个单独的类别进入“未跟踪”。这样做的原因是 Git 作者 期望 大量 的未跟踪文件 不应该此处报道。 Git 特别适用于创建“目标文件”和其他“构建工件”的编译器,虽然它们可能很重要,但不应添加到提交中并因此永远保存。1

就此而言,Git 通过 .gitignore 和其他排除文件提供了排除功能。在这里,您列出 Git 应该 关闭 ____ up 的文件。它应该而不是抱怨这些未跟踪的文件未被跟踪。此外,当这些文件 未被跟踪时,您可以使用 git add 操作,例如 git add .,添加 all 未跟踪的文件...除了标记为“忽略”的文件。

.gitignore 的误导是它不会忽略 任何 跟踪 的文件。这里的tracked这个词是根据untracked的定义对立定义的。 未跟踪 文件是存在于您的工作树中但不在Git 的索引中的文件。 tracked 文件是 Git 索引中的文件,无论它是否存在于 Git 索引中。永远不会忽略跟踪的文件。

.gitignore 文件的良好维护使 Git 使用起来更加愉快:git status 告诉你只有 有用的东西; git add . 仅添加 正确的 项。


1这样做的原因是构建工件——至少,理想情况下——完全可以从原始来源复制。我们只想保存 originals,而不是派生的工作产品。这至少可以节省大量的 space 以及以后的时间和人工工作。注意,这里有很多“理想”和“潜力”。这些事情并不总是按计划进行,有时保存所有内容实际上是合理的。 Git 在这方面不是很好,所以您可能不想为此目的使用 Git


“所有文件始终提交”的可能来源

如果你 运行 git add .,你是在告诉 Git:扫描我当前的工作目录,找到所有更新的文件和所有新文件以及任何删除的文件,并在每个副本上使用 git add 来更新您的临时区域副本 。此处唯一的例外是 .gitignore 中列出的文件或其他尚未跟踪的排除文件。

如果您 运行 git add *,行为在某种程度上取决于您的命令行解释器:Unix 风格的 CLI(例如 bash 或 zsh)具有 shell 扩展 *,而 MS-DOS 风格的 CLI(例如 CMD.EXE)将文字星号 * 传递给 Git,这然后扩展 *。我不会在这里详细讨论 all 差异的细节,但这往往会大量添加很多或所有文件,具体取决于许多细节。

如果你 运行 git add -u,你告诉 Git 找到 更新的 文件并添加它们。

您可以有一个预提交挂钩。 Git 中的挂钩相当复杂,但某些软件安装程序不仅会为您安装 Git,还会设置某种自动创建挂钩的功能。 (这是一种重新初始化 Git 存储库 可以 产生影响的设置,尽管要这样做,安装程序必须将这些挂钩放入 Git “模板”,似乎很少使用。)预提交挂钩 可以 ,取决于您 运行 git commit, 运行 git add 给你,即使你不想要。

如果你 运行 git commit -a,你实际上是在告诉 Git 到 运行:

git add -u
git commit

这里有一个与预提交挂钩的交互,所以两个命令的顺序并不完全相同,但这可能是您问题的根源。

我已经通过对大文件使用 Git lfs 解决了这个问题。由于我使用的是 RStudio 服务器,我要求管理员安装 Git lfs 然后我执行这些

git lfs install
git lfs track "*.h5ad, *.h5Seurat"
git add .gitattributes
git lfs migrate info
git lfs migrate info --everything
git lfs migrate import --everything --a #override changes in your working copy? 
[Y/n] Y

然后它将提交推送到 Github。请注意,*.h5ad 和 *h5Seurat 是我希望 Git lfs 处理的大文件扩展名。 我正在关注这个 link git lfs