一文让你明白 Git 分支是如何工作的
分支用于拆分 Git 历史记录。您可以将 Git 提交想象成一系列可以追溯到过去的更改。您可以“签出checkout”任何这些提交,并将本地目录及时移回提交时的状态。
分支通常用于处理实验性功能,或需要一段时间的更改,或任何其他可能破坏存储库的东西。例如,您可能正在重构代码库的一个重要组件,并且在完成之前,您希望master 分支保持稳定。
一旦新feature 分支稳定了,它就可以重新合并到master中,通常是通过 拉取请求,这是一个允许在进行更改之前进行代码审查和测试的过程。
然而,在幕后,分支的工作方式与您最初预期的略有不同。在 Git 中,分支只是指向特定提交的标签或指针。就是这样,master 分支只是指向最新的提交master;当您进行新的提交时,标签会更新为指向新的提交。
虽然将提交视为及时推进是有用的;实际上,Git 提交指向彼此。每个提交都有对最后一次提交的引用,并且这个链用于构造存储库的状态。
但是,如果您创建一个新分支,则情况会有所不同。您签出的任何分支(使用git checkout )都将用作新提交的标签。
要在此示例中创建分支,您必须首先确保将存储库 HEAD 设置为master 分支。这是因为您实际上可以从任何地方开始创建分支——包括过去的提交或其他分支上的提交。
git checkout master
然后创建一个新分支,并交换到它:
git branch feature git checkout feature
此时,您的存储库中的任何内容都没有改变。feature 和分支标签都master 指向同一个提交。
但是,您从此时开始提交的任何内容都将添加到feature 分支中。更具体地说,将创建一个新提交,设置为指向当前提交,并且“功能”标签将更新为指向这个新提交。
您甚至可以checkout master 在主分支上进行更多提交。它不会影响feature 分支,因为标签所知道的只是它指向那个特定的提交。它不会随master 标签更新。
当然,如果分支永远卡在那里,它们就不会太有用了,因此 Git 提供了将它们合并回master 分支的工具。从技术上讲,只要历史兼容,您就可以将子分支合并到任何其他分支中。
最简单的情况是您有一个只需要合并回来的简单分支。您可以签出master 分支,然后运行git merge feature 以将在功能分支上所做的所有提交“重播”到 master 上。
这会将它们合并到主时间线中,并使用更改创建一个新的“合并提交”。
但它并不总是那么简单,而且在许多情况下,您将遇到 需要解决的合并冲突。这可能包括分支修改文件中的相同行、文件移动或删除,或feature 在创建分支后更改软件时出现的其他类型的错误。
如果您有一个长时间运行的feature 分支,则将这个问题最小化的一种方法是执行频繁的合并,这次相反——从master 主支到 feature 分支上,这保持feature 最新,虽然它并没有真正减少所需的工作量,但它可以防止它陷入一片混乱。
这种策略对于长期存在的分支很常见,通常被认为是 Git 的最佳实践。
在这种情况下也使用的另一个工具是变 基。基本上,变基就像拿起整个分支并将其移动到从新位置开始,通常是存储库中的最新提交。在某些情况下,这会导致更清晰的 Git 历史记录,并且是某些复杂情况的首选解决方案。
然而,Git 历史是“不可变的”,并且由于这种变基复制提交而不是实际移动它们。如果没有与您的团队正确协调,这可能会导致共享分支上的许多问题——如果您重新设置基准,并且您的同事在“旧”、现已删除的功能分支上进行新提交,它将被搁置。他们将不得不隐藏提交并将其弹出到新分支以协调更改。
要开始创建新分支,您需要将存储库置于正确状态,以便新分支标签从您想要的位置开始。如果您要从 分支master,只需签出整个分支以从最新提交开始。否则,您可以通过签出单个提交将您的 repo 置于分离的 HEAD 状态。
git checkout master git checkout aa3e570923b8ee61414cec17d9033faab4f084a6
然后,您可以创建新分支,并使用checkout切换到它:
git branch feature git checkout feature
这可以在一个命令中完成,带有-b 结帐标志:
git checkout -b feature
此时,您的 repo 中所做的任何提交都将提交到新分支。
如果您需要再次交换分支,只需运行git checkout master 即可恢复正常。
如果您有需要移动的本地更改,可以将它们放入git stash. 更改将被存储,并且可以在交换分支后重新应用。
git stash git checkout feature git stash apply