Git:如何从远程存储库中取消跟踪文件,但仍将其保留在所有开发人员的本地存储库中?

guo*_*guo 3 git

git rm --cached mylogfile.log可以mylogfile.log从存储库中取消跟踪,同时仍将其保留在我的本地存储库中。

但是,如果其他开发人员在我提交后从远程存储库中拉取,他们将在本地存储库中丢失该文件。

情况是我已经提交了一个不应该提交的文件,例如,一个机器特殊文件到远程存储库。我想修复错误而不影响其他开发人员。当然,我不能像这样进行提交git rm --cached mylogfile.log,然后所有其他开发人员都丢失了他们的文件。

如果我使用git update-index --assume-unchanged,文件仍然会被 git 跟踪,这不是我想要的。

有办法解决这个问题吗?

tor*_*rek 5

在 Git 中,tracked 的意思是“在索引中”。未跟踪意味着“不在索引中”。

\n\n

虽然只有一个(因此是定冠词“the” )索引,但该索引与当前提交相关。每次您检查任何特定的 commit\xe2\x80\x94include 时,都会检查提示git checkout somebranch提交时,您都在告诉Git从索引和工作树中删除任何文件的任何版本这与目标提交不同,并将与目标提交相关的文件版本插入到索引和工作树中。

\n\n

那么,假设您正在执行一个哈希 ID 为 的提交a4ef00d,并且您告诉 Git 检出另一个 ID 为 的提交1c0ffee。如果文件mylogfile.log存在于 commit 中a4ef00d但不在 commit 中1c0ffee,Git 必须从索引和工作树中删除该文件。现在该文件不再被跟踪\xe2\x80\x94,但它根本不存在。

\n\n

现在您已经打开了1c0ffee,如果您这样做git checkout a4ef00d,Git 必须将中的版本放入索引和工作树中。现在再次跟踪该文件,工作树中的版本就是.mylogfile.loga4ef00da4ef00d

\n\n

无论您执行其他操作,这始终是正确的:假设一个文件至少在一次提交中,并且没有在一次提交中。不在另一次提交中当您从包含它的提交移至不包含它的提交时,Git 会将其从索引和工作树中删除。当您从任何没有它的提交移动到有它的提交时,Git 会将其放回索引和工作树中。

\n\n

这意味着一个文件同时被跟踪和未跟踪\xe2\x80\x94(这可能的\xe2\x80\x94)将导致 Git 有时删除或重新创建该文件。你不能阻止这个过程。文件的跟踪或未跟踪取决于您签出的提交,即您告诉 Git 复制到索引中的内容。

\n\n

索引版本可以不同于当前提交或工作树

\n\n

事实上,索引是您构建下一次提交的地方。这是它自己的原因之一,与“当前提交”分开。您可以更改索引内容;这些更改将“暂存”以供下一次提交。您不必暂存工作树更改;这种变化是非阶段性的但仍然存在,并显示为“已修改但未上演”。

\n\n

设置--assume-unchanged--skip-worktree告诉 Git 不要查看索引和工作树版本是否不同。因此,无论您进行多少次新提交,索引版本都可以与先前的提交保持匹配。 但要设置任一位,索引中必须有一个条目。 这意味着当前必须跟踪该文件。

\n\n

如果文件被跟踪,它就会被提交。 您所做的每个新提交都会以索引中当前的形式保存索引中的每个文件。您也无法停止此过程。

\n\n

解决这个困境的唯一真正的解决方案是删除该文件

\n\n

一旦删除文件 ( ),该文件将从索引工作树中git rm mylogfile.log消失。您现在可以提交结果,新提交缺少该文件,因为它不在索引中。

\n\n

现在该文件不在索引中,您可以将其恢复到工作树中。现在已经无人追踪了。只要您不将文件放回到索引中,它就会保持这种状态\xe2\x80\x94未跟踪,但会出现在工作树\xe2\x80\x94中。现在你必须避免git add-ing 它,也避免 git checkout-ing 包含它的旧提交。

\n\n

当然,您可能希望在删除和提交时将其保存在某个地方。最简单的方法是将其复制到 Git 之外的某个位置,即git rm文件、提交,然后将其复制回原位。您可以使用git rm --cached将其从索引中删除,而不将其从工作树中删除,作为此过程\xe2\x80\x94的一种快捷方式,但实际上您是将文件保存在存储库之外。请记住这一点以用于以下步骤。

\n\n

(现在,您可以通过在文件中列出该文件来让 Git 停止抱怨它未被跟踪.gitignore这具有使 Git 停止抱怨的主要效果。git add当您添加“所有”文件或包含文件\xe2\x80\x94 的目录,正如我们所见,该文件会导致文件被跟踪。 如果文件被跟踪,则.gitignore该文件的条目无效。

\n\n

该文件现在会在各种操作中被删除

\n\n

正如我们上面已经提到的,如果您移动到包含该文件的提交该文件将进入索引和工作树。(如果工作树中已经存在同名文件,Git 会让您先将该文件移开。)

\n\n

正如您还指出的:

\n\n
\n

但是,如果其他开发人员在我提交后从远程存储库中提取数据,他们将在本地存储库中丢失该文件。

\n
\n\n

更准确地说,如果其他人获取了您缺少该文件的提交(因此它未被跟踪),他们现在就会遇到我们上面提到的情况:他们有包含该文件的提交,以及缺少该文件的提交。如果它们git checkout从包含该文件的提交移动到不包含该文件的提交(如 中所示),Git 将从索引和工作树中删除该文件。

\n\n

然而,该git pull命令并不简单地运行git checkout. 它运行两个Git 命令。第一个是git fetch,它从远程(另一个 Git)获取提交。第二个取决于你告诉 Git 做什么:

\n\n
    \n
  • git pull会跑git merge默认运行。这要么执行常规合并,要么执行快进“合并”(这不是真正的合并)。
  • \n
  • git pullgit rebase如果你告诉它的话,可以改为运行。这比 更复杂git merge,但相当于执行一系列git cherry-pick操作来复制他们的原始提交以跟随您的提交。其中之一将在完成git checkout您的提交后尝试将其工作与您的“删除日志文件”提交结合(即合并)。
  • \n
\n\n

使用这些命令\xe2\x80\x94git mergegit rebase\xe2\x80\x94 将导致 Git 想要从索引和工作树中删除该文件,类似于使用 Straight 发生的情况git checkout,但有以下差异:

\n\n
    \n
  • 如果他们的提交修改(保存新的/不同的版本)mylogfile.log,他们将看到“修改/删除冲突”,他们必须通过删除来解决该冲突mylogfile.log(在首先保存他们想要保存的任何内容之后,在其他地方)。

  • \n
  • 如果不是(他们提交的版本mylogfile.log与“合并库”中的内容匹配),那么他们的工作树版本要么mylogfile.log与提交的版本匹配(Git 将继续删除该文件),要么不匹配(Git 会抱怨,并且他们必须将想要保存的任何内容保存在其他地方,然后删除该文件以便 Git 可以继续)。

  • \n
\n\n

一旦他们有一个提交\xe2\x80\x94a合并提交,或者他们自己的重新基提交\xe2\x80\x94不再有该文件,它们的形状就和你原来的一样了:文件现在从索引和索引中都消失了。工作树。他们现在可以将其恢复到工作树(但不能恢复到索引)并将其作为未跟踪文件维护,就像您所做的那样。

\n\n

这项工作没有办法解决

\n\n

避免所有这些工作的唯一方法是不提交(并因此跟踪)文件。但有人已经提交(并因此跟踪)该文件。现在每个人都必须执行这项额外的工作。请注意,每个人都必须执行此操作\xe2\x80\x94,即每次从不包含该文件的提交跨越到包含该文件的提交时,将仅工作树版本保存在其他地方\xe2\x80\ x94包含该文件的。没有办法解决这个问题,因为过去有人错误地提交了该文件,而 Git 会永远存储每个提交。

\n\n

好吧,有一种方法可以解决这项工作,但它涉及到完成这项工作

\n\n

您可以“重写历史记录”:将存储库更改为一个新的、不同的存储库,其中从未有人提交过此文件。现在这个错误从一开始就没有犯过。问题是,您现在必须让所有使用旧存储库的人切换到这个新的、不同的存储库。

\n\n

要像这样重写历史,您可以使用git filter-branch, 或The BFG。搜索现有示例;有很多。

\n\n

请注意,在进行此切换时,您必须做一些额外的工作:将日志文件从有错误的旧存储库复制到没有错误的新存储库的工作树中。所以你毕竟并没有真正回避这项工作:你只是改变了做这件事的时间。

\n