Isa*_*Joy 2 git version-control branch repository gitlab
最近,我在同一个项目的两个不同分支中与其他人一起工作。我不小心将包含他的代码的分支合并develop到我的分支中。然后我在我的合并请求中看到了他的文件,随后我经历了惨痛的教训
git rm HIS_FILES
在我的分支中删除他不需要的文件,不仅会从我的分支中删除它们,还会从他的分支(以及整个 git 索引)中删除它们。
我想知道的是,我如何正确地从我的分支中删除他的文件,以便它们不会从他的分支中删除?一旦我意识到他的文件在我的分支中,我是否会创建一个新分支?在将分支合并develop到本地分支之前,我是否会恢复到上一个提交?
谢谢你的帮助
(从技术上讲,这是一条评论,而不是一个答案,但我希望能够使用格式......而且,它永远不会适合。)
\n\n\n\n\n[
\ngit rm] 不仅会从我的分支中删除 [文件],还会从他的分支(以及整个 git 索引)中删除。
不是这种情况。而且,这不是理解 Git 索引的正确方法。
\n\n索引有三个名称:Git 有时将其称为索引,但有时将其称为暂存区。在一些地方,Git 使用了“缓存”一词。这些大多都指的是同一件事,其具体实现大多只是.git名为 的目录中的一个文件index。1 但是,无论您使用哪个名称,索引与现有提交都没有什么关系。索引的主要功能是,它是您构建建议的下一次提交的地方位置。
当我们使用短语暂存区域谈论索引时,我们关心的是保存在索引中的文件副本。2 Git 的工作方式是,每个文件的三个副本 始终触手可及!您选择一个提交 \xe2\x80\x94usinggit checkout或 Git 2.23 或更高版本中的新提交git switch\xe2\x80\x94 作为当前提交。该提交以特殊的只读(且仅限 Git)压缩格式保存所有文件的快照。
提交内的这些冻结格式文件无法更改。任何现有提交都无法更改。这样做有一些很大的优点:例如,由于文件无法更改,因此可以共享它们。如果提交A具有某个文件的某个版本,并且提交Z具有同一文件的相同版本,则两个提交可以简单地共享一个基础文件。(这实际上是基于文件内容,而不是文件名。)但这也有一个很大的缺点:这意味着你实际上不能做任何新的事情操作,即执行任何新工作。
因此,Git 需要一种方法和一个地方来解冻和解压缩 \xe2\x80\x94,即对 \xe2\x80\x94冻结和压缩(脱水)的文件进行再水化。Git 将它们放置在你的工作树中中。工作树中的文件是普通的日常文件,由计算机提供,因此您可以完成工作。
\n\nREADME.md因此,这解释了所有文件的三个副本中的两个:当前(或)提交中有脱水副本,并且工作树中HEAD有普通且有用的副本,您可以在其中工作README.md用它。但这第三个副本在做什么呢?
答案是:它以冻干格式位于您的索引\xe2\x80\x94或“暂存区域”\xe2\x80\x94中,准备进入新的提交。如果您git commit现在运行,Git 将从索引中文件的冻干副本构建新的提交。为什么不使用提交中的内容?这应该是显而易见的:这是因为您无法更改这些副本!但您可以替换索引中的冻干副本。这就是它的作用git add:它压缩(冷冻干燥)文件的工作树版本并将其写入索引。3
因此,假设您修改了README.md. 在 之前 git add README.md, 的索引副本与的副本README.md匹配,但工作树副本不同。 之后, 的索引副本与工作树副本匹配(冻干格式除外)。始终存在三份副本,但其中两份是匹配的。使用替换索引副本,以便它与工作树副本匹配。(副本无法更改。)HEADREADME.md git add README.mdREADME.mdgit addHEAD
这意味着索引在任何时候都已准备就绪:git commit只需将冻干索引文件打包到新的提交中即可。新提交通过添加到当前分支而成为提交。新的提交现在拥有每个HEAD文件的完整且完整的(并永久冻结)副本,如索引中所示。现在提交和索引匹配,如果索引与工作树匹配,则所有三个副本都匹配。HEAD
当您使用 时,Git 会从索引和工作树中git rm删除指定的文件。下一个将不会有该文件,因为它不在索引中。git commit
如果您然后选择git checkout其他分支,Git 现在会找到冻结提交中的所有文件,即该其他分支的尖端。Git 将所有这些冻结格式的文件复制到索引中,以便它们准备好进入您所做的下一次提交;更新索引副本后,Git 将它们重新水合到工作树中,以便您可以查看和使用这些文件。现在(新选择的,不同的)HEAD提交、索引和工作树再次全部匹配,您就可以开始工作了。
如果在从 commit 切换Z回 commit 的过程中A,Git 发现 commitZ有一些文件\xe2\x80\x94to-be-deleted.txt或者 \xe2\x80\x94不在commit 中A,Git 就会to-be-deleted.txt从索引和工作树中删除。所以现在它已经消失了\xe2\x80\x94但它仍然存在于 commit 中Z。如果你git checkout提交Z,Git 会发现它to-be-deleted.txt 不在commit 中A,不在索引中,并且在commit 中Z,因此它将提交Z版本复制to-be-deleted.txt到索引和工作树中......现在,再次HEAD,索引和工作树都匹配。
始终牢记的一个关键是 Git 是关于提交的。 我们将使用git checkout一些分支名称来切换分支,但该名称标识一个特定的提交。然后,Git 将填充索引和工作树\xe2\x80\x94,它们都是该提交的临时区域!\xe2\x80\ x94。当我们进行新的提交时,Git 只需打包索引中的所有内容,添加我们的名称等,写出新的提交,其父级是我们签出的提交,然后更新分支名称以记住哈希 ID新提交的。于是分支名称就动了。提交一旦做出,就永远不会改变,并且通常会永远持续下去。4
1我们不得不说主要是因为这条规则有很多例外。但是,出于特殊目的,您可以将 Git 指向不同的文件,方法是将环境变量设置GIT_INDEX_FILE为您希望 Git 使用的临时索引的路径名。如果该文件不存在,Git 将创建该文件,然后将其用作索引。这git stash例如,
2从技术上讲,索引保存对blob 对象的引用,这就是 Git 以冻结格式存储文件的方式。不过,除非/直到您开始使用诸如和 之类的东西,否则将索引视为包含每个文件的冻结格式副本也同样有效。git hash-objectgit update-index
3这就是 andgit hash-object -w的git update-index用武之地:git add压缩并写入一个新的冻干blob 对象,或者发现现有 blob 具有正确的内容,因此最终会重新使用该现有的、已冻结的 blob 对象。该 blob 对象具有唯一的哈希 ID(如果是新的),并使用与将正确的哈希 ID 写入索引git add相同的代码。git update-index
我们同样可以问为什么不从工作树构建新的提交? 对此没有真正好的答案:另外5 个版本控制系统,它们不会一直把索引塞到你面前,实际上是这样做的,或者看起来像那样的东西。但 Git 把索引推到你面前,所以你需要了解它。
\n\n4要删除某个提交,您需要进行一些安排,以便您找不到该提交。由于分支名称标识了最后一次提交,因此很容易删除最后的提交:只需使分支名称向后,以标识该提交的父级。但是您可以通过向后一步一步找到每个较早的提交,因此您实际上只能删除尾端提交。(这一点在其他一些 VCS 中更清楚,例如 Mercurial,它们不允许提交在多个分支上。在 Git 中事情会变得混乱,其中提交可能在多个分支上同时
\n\n5人们可以指出由此带来的各种功能,例如git add -p,但这是一种较弱的事后证明。真正的问题是这些功能是否值得最初的复杂性。我不认为它们是\xe2\x80\x94我认为Git可以以其他方式提供它们,不会使索引像它那样\xe2\x80\x94那样显眼,但这就是意见和猜测,这并不适合 StackOverflow。