Git:如何从远程存储库中删除文件但仍保留在所有开发人员的本地存储库中?

时间:2017-05-16 08:48:59

标签: git

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

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

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

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

有什么想法解决这个问题?

1 个答案:

答案 0 :(得分:3)

在Git中,跟踪表示"在索引"中。未跟踪意味着"不在索引"。

虽然只有一个(因此是definite article "the")索引,但索引与当前提交相关。每次你检查任何特定的提交 - 包括git checkout somebranch,它检查命名分支的提示提交 - 你告诉Git从索引和工作树中删除任何任何与目标提交不同的文件的版本,并在索引和工作树中插入与目标提交一起使用的该文件的版本。

然后,假设您正在进行其哈希ID为a4ef00d的提交,并告诉Git检出ID为1c0ffee的其他提交。如果文件mylogfile.log存在于提交a4ef00d中但不存在于提交1c0ffee中,则Git必须从索引和工作树中删除该文件。现在不再跟踪文件 - 但它根本不存在。

现在您已经1c0ffee,如果您git checkout a4ef00d,Git必须将放入索引和工作树中mylogfile.log的版本a4ef00d中的那个。现在再次跟踪文件,工作树中的版本是a4ef00d中的版本。

无论你做什么,总是如此:假设至少一次提交中的文件 ,并且至少在另一次提交中不是 。当你从拥有它的提交转移到没有提交的提交时,Git会将它从索引和工作树中删除。当你从任何没有它的提交转移到那个提交时,Git会把它放回到索引和工作树中。

这意味着有一个文件被跟踪和未跟踪 - 可能 - 将导致Git有时删除或重新创建该文件。您无法停止此过程。文件的跟踪或未跟踪将取决于您检查的提交,即您告诉Git将其复制到索引中的内容。

索引版本可能与当前提交或工作树

不同

实际上,索引是构建 next 提交的地方。这是其自身的原因之一,与当前的提交分开#34;。您可以更改索引内容;这些变化是“上演的”#34;用于下一次提交。您不必 阶段工作树更改;此类更改 unstaged 但仍然存在,并显示为"已修改但未上演"。

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

如果跟踪文件,它将被提交。您创建的每个新提交都会以索引中现有的格式保存索引中的每个文件。你也无法阻止这个过程。

解决这个难题的唯一真正方法是删除文件

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

现在该文件不在索引中,您可以将其还原到工作树。它现在未跟踪。它将保持这种方式 - 未跟踪,但存在于工作树中 - 只要您不将文件放回索引中。现在你必须避免使用git add - 和 git checkout - 使用它的旧提交。

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

(你现在可以通过在.gitignore文件中列出文件来让Git停止抱怨 未跟踪。这主要是让Git停止抱怨。它还可以防止当你添加"所有"文件或包含该文件的目录时,自动git add来自Git文件 - 正如我们所见,这会导致文件被跟踪。如果是跟踪文件,.gitignore条目无效。

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

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

你还注意到:

  

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

更准确地说,如果其他人获得了缺少文件的提交(以便它未被跟踪),他们现在就具有我们上面提到的情况:他们有提交文件的提交,并提交缺少文件。如果他们从一个拥有该文件的提交移动(如在git checkout中)到一个没有提交的提交,Git将从索引和工作树中删除该文件。

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

  • git pull默认会运行git merge。这可以是常规合并,也可以是快进"合并" (这不是真正的合并)。
  • 如果您告诉,
  • git pull可以运行git rebase。这比git merge更复杂,但相当于执行一系列git cherry-pick操作来复制他们的原始提交。其中一个将尝试将他们的工作与你的"删除日志文件"结合起来(即合并)。在提交git checkout之后提交。

使用这些命令中的任何一个 - git mergegit rebase - 将导致Git想要从索引和工作树中删除文件,类似于直接{{1}所发生的情况},但有这些差异:

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

  • 如果不是(他们的mylogfile.log的已提交版本与"合并基础")中的内容相匹配,则其mylogfile.log的工作树版本与提交的匹配版本(和Git将继续并删除文件)或它没有(和Git会抱怨,他们必须保存他们想要保存的任何东西,在其他地方,然后删除文件,以便Git可以继续)。

一旦他们进行了提交 - 合并提交或他们自己的重新提交 - 不再拥有该文件,它们就会处于您所处的相同形状中:文件现在已从索引和工作树中消失。他们现在可以恢复到工作树(但到索引)并将其保存为未跟踪的文件,就像您一样。

无法绕过这项工作

避免所有这些工作的唯一方法是不提交(并因此跟踪)文件。但有人已经提交(并因此跟踪)该文件。现在每个人都必须完成这项额外工作请注意, everyone 必须执行此操作 - 也就是说,将工作树版本保存在其他位置 - 每隔时间从的提交中删除>将文件放入 拥有该文件的文件中。没有办法解决这个问题,因为过去有人错误地提交了文件,Git会永久存储每个提交。

嗯,围绕这项工作的一种方式,但它涉及做这项工作

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

要重写此类历史记录,您可以使用mylogfile.logThe BFG。搜索现有示例;有很多。

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