让我从这个开始,因为它可能更有用:
有没有更好的方法来解决这个问题?
理论上,你完全可以不用master 分支。有三个分支,其中没有一个包含最终组合结果。在 Git 之外进行组装。如果需要,创建一个“孤立分支”(或使用标签)来记录组装结果,或者将组装结果保存在完全不同的存储库中。但是这些都导致了你提到的那些小困难。
出了什么问题
Git 根本无法按照您想要的方式工作:您不能(无论如何有用)“关心”某些文件并让其他“不关心”的文件基于分支进行“关心”切换。那是因为“分支”,在您使用的这个词的意义上,不存在。
现在,这是一个强有力的声明,需要证明。显然,分支确实存在。问题在于branch这个词的含义。它有太多的含义,人们只是在它们之间来回切换,没有意识到他们正在这样做,这给他们带来了麻烦。 (另请参阅What exactly do we mean by "branch"?)所以让我们避免使用 Git 真正使用的术语:提交哈希 ID。
当你运行时:
git checkout br2
你告诉 Git 做两件事:
- 保存名称
br2 以备将来使用;
- 将名称
br2 转换为提交哈希ID,并从该提交中提取(包括“关心”)所有文件的快照。李>
第二步 是现在真正重要的一步:只有在以后运行git commit 进行new 提交时才需要第一步,或者其他一些需要名称的 Git 命令(例如,git branch 或 git status 或 git rebase)。
除了一个例外——你在一个尚未运行的新克隆中看到git checkout——Git 总是有一些提交检出现在。你的git checkout 告诉 Git:扫掉我们现在拥有的那个,然后给我一些其他的提交作为签出的提交。
假设现在,您已签出br1,即提交b100。稍后,name br1 可能意味着一些 other 提交,但现在它意味着那个。你运行 git checkout br2,它告诉 Git 从提交 b100 切换到提交 b200,因为这就是 name br2 的意思 现在。1
好的,没什么大不了的,对吧?我们正在从提交 b100 转移到提交 b200。 Commit b100 包含 *.h 文件,省略 *.jpg 文件。所以Git“关心”*.h文件,而我们有b100。这些文件被跟踪,这意味着它们在(单个)索引中。不过,我们正在从 b100 转移到 b200,其中包含 *.jpg 文件并省略 *.h 文件。 Git 必须将*.jpg 文件复制到 其索引并删除 *.h 文件从 其索引,这意味着它必须删除*.h 文件也来自您的工作树。
到目前为止,一切都很顺利:您得到了您想要的。但是现在你想去master 并组装零件。 master 这个名字意味着其他一些提交,可能是 a123。
无论你现在如何到达master,从br1(目前为b100)或br2(b200),你都没有所有 *.h 和 *.jpg 文件。你只能得到一套或另一套。这里的根本问题是“关心”的发生是因为文件在 Git 的 index 中。在 .gitignore 文件中列出文件,这是您为防止它们进入 Git 的索引而采取的措施,只有在它们不存在的情况下才有帮助——并且当您切换到提交时 拥有文件,Git 将将它们放入 Git 的索引中,无论 .gitignore 文件中有什么内容。当您切换到省略文件的提交时,Git 会从 Git 的索引中删除它们,无论 .gitignore 文件中有什么内容。
索引的内容反映了您签出的提交。每个提交都有该提交中每个文件的完整快照。该快照最终出现在 Git 的索引中。除非您更改它们——例如使用git add、或git rm,或者通过另一个git checkout 来替换它们,否则这些文件将进入下一个 提交。
最后,当你使用git merge 组合工作时,Git:
- 找到一个合并基础提交;
- 将两个分支提示提交与此合并基础进行比较;和
- 使用它来确定要在新提交中添加什么。
与任何提交一样,新提交具有所有文件的快照:git merge 进行合并提交时 Git 索引中的所有文件,这些文件是上述合并过程的结果。合并提交与任何其他提交相同:它们具有快照和元数据。唯一让它们特别的地方——使它们合并提交——是它们的元数据中列出了两个(或更多)父提交哈希 ID。
这些互锁行为妨碍了:master 实际上确实拥有所有文件,在这种情况下,其他分支名称找到的其他提交也需要拥有所有文件,或者master 没有任何文件,在这种情况下,其他分支可以像这样独占,但您不能将它们合并回到 master,因为 Git 将找到的共同提交,将充当合并基础,将导致他们将文件添加文件到进入master的新提交——并且现在master 拥有所有文件!如果您在返回分支时删除它们,这次合并将删除这些文件。
归根结底,Git 完全是关于提交。 commits 决定了一切!提交是快照加元数据。 branch name 所做的只是找到一个特定的提交:某个链上的最后一个。可以从多个分支名称进行提交,并且许多或大多数提交同时在多个分支上。所以 name 与提交中的文件无关:当多个名称找到该提交时,它实际上 不能。
1提交哈希 ID 映射的分支名称更改,这是 Git 中分支的增长方式。 Git 是为添加新提交而构建的,因此名称更改的正常方式是,它现在意味着一个更新的提交,它通过提交图引导回到旧的提交——以及更多的提交。另见Think Like (a) Git。