比较 Git 工作流程:您应该知道什么
Git 是当今最常用的版本控制系统。Git 工作流程是如何使用 Git 以一致高效的方式完成工作的秘诀或建议。Git 工作流程鼓励开发人员和 DevOps 团队有效、一致地利用 Git。Git 为用户管理变更提供了很大的灵活性。鉴于 Git 注重灵活性,因此在如何与 Git 交互方面没有标准化的流程。在 Git 管理的项目中与团队合作时,重要的是要确保团队在如何应用变更流程上达成一致。为确保团队保持同步,应开发或选择商定的 Git 工作流程。有几个公开的 Git 工作流程可能很适合您的团队。在这里,我们将讨论其中一些 Git 工作流程选项。
在工作场所实施 Git 时,各种可能的工作流程会让人很难知道从哪里开始。本页通过调查软件团队最常用的 Git 工作流程提供了一个起点。
通读时,请记住,这些工作流程旨在作为指导方针而不是具体规则。我们想向您展示什么是可能的,这样您就可以混合搭配来自不同工作流程的各个方面,以满足您的个性化需求。
什么是成功的 Git 工作流程?
在评估团队的工作流程时,最重要的是要考虑团队的文化。您希望工作流程能够提高团队的效率,而不是成为限制工作效率的负担。评估 Git 工作流程时需要考虑的一些事项是:
- 此工作流程是否会随团队规模而扩展?
- 使用此工作流程可以轻松撤销错误吗?
- 此工作流程是否会给团队带来任何新的、不必要的认知开销?
集中工作流
对于从 SVN 过渡的团队来说,集中式工作流程是一个很棒的 Git 工作流程。与 Subversion 一样,集中式工作流程使用中央存储库作为项目所有变更的单一入口点。默认的开发分支为 main
,而不是 trunk
,所有变更都提交到该分支中。除了 main
之外,此工作流程不需要任何其他分支。
过渡到分布式版本控制系统似乎是一项艰巨的任务,但您不必为了利用 Git 而改变现有的工作流程。您的团队可以用与使用 Subversion 完全相同的方式开发项目。
但是,与 SVN 相比,使用 Git 为开发工作流程提供支持具有一些优势。首先,它为每个开发人员提供了整个项目的本地副本。这种隔离的环境允许每个开发人员独立于项目的所有其他变更进行工作——他们可以将提交添加到本地存储库中,完全忘记上游开发,直到方便为止。
其次,它允许您访问 Git 强大的分支和合并模型。与 SVN 不同,Git 分支设计为一种故障防护机制,用于集成代码并在存储库之间共享变更。集中式工作流与其他工作流相似,它利用了开发人员推送和拉取的远程服务器端托管存储库。与其他工作流相比,集中式工作流没有定义的拉取请求或克隆模式。集中式工作流通常更适合从 SVN 迁移到 Git 的团队和规模较小的团队。
相关资料
高级 Git 日志
查看解决方案
了解 Bitbucket Cloud 的 Git
工作原理
开发人员首先克隆中央存储库。在他们自己的项目本地副本中,他们像使用 SVN 一样编辑文件和提交变更,但是,这些新的提交存储在本地——它们与中央存储库完全隔离。这使开发人员可以将上游同步推迟到方便的中断点为止。
为了发布对官方项目的变更,开发人员将其本地 main
分支“推送”到中央存储库。这相当于 svn commit
,不同之处在于它添加了所有尚未在中央 main
分支中的本地提交。
初始化中央存储库
首先,需要有人在服务器上创建中央存储库。如果是新项目,可以初始化一个空存储库。否则,您需要导入现有的 Git 或 SVN 存储库。
中央存储库应始终是裸存储库(它们不应该有工作目录),可以按如下方式创建:
ssh user@host git init --bare /path/to/repo.git
请务必为 user
使用有效的 SSH 用户名、服务器的域或 IP 地址作为 host
,以及要存储 /path/to/repo.git
代码存储库的位置。请注意,.git
扩展名通常会附加在存储库名称后面,以表示它是一个裸存储库。
托管的中央存储库
中央存储库通常是通过 Bitbucket Cloud 等第三方 Git 托管服务创建的。上面讨论的初始化裸存储库的流程由托管服务为您处理。然后,托管服务将为中央存储库提供一个地址,以便从您的本地存储库进行访问。
克隆中央存储库
接下来,每个开发人员创建整个项目的本地副本。这是通过 git clone 命令完成的:
git clone ssh://user@host/path/to/repo.git
当您克隆存储库时,Git 会自动添加一个名为 origin
的快捷方式,该快捷方式指向“父项”存储库,前提是您未来想与该存储库进行交互。
进行变更并提交
在本地克隆存储库后,开发人员可以使用标准的 Git 提交流程进行变更:编辑、暂存和提交。如果您不熟悉暂存区,这是一种无需将所有变更都包含在工作目录中即可准备提交的方法。这允许您创建高度集中的提交,即使您做了很多本地变更。
git status # View the state of the repo
git add <some-file> # Stage a file
git commit # Commit a file</some-file>
请记住,由于这些命令会创建本地提交,因此 John 可以根据需要多次重复此流程,而不必担心中央存储库中发生了什么。这对于需要分解为更简单、更具原子性的块的大型功能非常有用。
将新提交推送到中央存储库
在本地存储库提交了新变更后。这些变更需要推送,以便与该项目的其他开发人员共享。
git push origin main
此命令会将新提交的变更推送到中央存储库。将变更推送到中央存储库时,之前可能推送了来自其他开发人员的更新,其中包含与预期的推送更新冲突的代码。Git 将输出一条消息,指明此冲突。在这种情况下,首先需要执行 git pull
。下一节将详细介绍这种冲突情景。
管理冲突
中央存储库代表官方项目,因此其提交历史记录应被视为神圣且不可改变。如果开发人员的本地提交与中央存储库不同,Git 将拒绝推送他们的变更,因为这会覆盖官方提交。
在开发人员发布他们的功能之前,他们需要获取更新的中央提交,并在这些提交的基础上变基他们的变更。这就像在说:“我想把我的变更添加到其他人已经完成的事情上。”结果是完美的线性历史记录,就像传统的 SVN 工作流程一样。
如果本地变更与上游提交直接冲突,Git 将暂停复位流程,让您有机会手动解决冲突。Git 的好处在于它使用相同的 git status
和 git add
命令来生成提交和解决合并冲突。这使新开发人员可以轻松管理自己的合并。另外,如果他们遇到麻烦,Git 可以很容易地中止整个变基并重试(或者去寻求帮助)。
示例
我们举一个一般的例子,说明一个典型的小型团队将如何使用此工作流程进行协作。我们来看看 John 和 Mary 这两位开发人员如何开发不同的功能,并通过集中式存储库分享他们的贡献。
John 正在开发他的功能
在他的本地存储库中,John 可以使用标准 Git 提交流程开发功能:编辑、暂存和提交。
请记住,由于这些命令会创建本地提交,因此 John 可以根据需要多次重复此流程,而不必担心中央存储库中发生了什么。
Mary 正在开发她的功能
同时,Mary 正在使用相同的编辑/暂存/提交流程在自己的本地存储库中开发自己的功能。像 John 一样,她不在乎中央存储库中发生了什么,而且她真的不在乎 John 在他的本地存储库中做了什么,因为所有本地存储库都是私有的。
John 发布了功能
John 完成自己的功能后,应该将其本地提交发布到中央存储库,以便其他团队成员可以访问。他可以用 git push 命令来做到这一点,如下所示:
git push origin main
请记住,origin
是 John 克隆中央存储库时 Git 创建的与中央存储库的远程连接。main
参数告诉 Git 尝试让 origin
的 main
分支看起来像他的本地 main
分支。由于自 John 克隆中央存储库以来一直没有更新,因此这不会导致任何冲突,推送将按预期进行。
Mary 试图发布她的功能
我们来看看,如果 Mary 在 John 成功将他的变更发布到中央存储库后尝试推送她的功能,会发生什么。她可以使用完全相同的推送命令:
git push origin main
但是,由于她的本地历史记录与中央存储库有所不同,Git 会用一条相当详细的错误消息拒绝请求:
error: failed to push some refs to '/path/to/repo.git'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Merge the remote changes (e.g. 'git pull')
hint: before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.
这可以防止 Mary 覆盖官方提交。她需要将 John 的更新拉取到她的存储库中,将它们与她的本地变更集成,然后重试。
Mary 以 John 的提交为基础进行了变基
Mary 可以使用 git pull 将上游的变更合并到她的存储库中。这个命令有点像 svn update
—它将整个上游提交历史记录拉取到 Mary 的本地存储库中,并尝试将其与她的本地提交集成:
git pull --rebase origin main
--rebase
选项告诉 Git 在将 Mary 的所有提交与中央存储库中的变更同步后,将其移至 main
分支的尖端,如下所示:
如果您忘记了这个选项,拉取仍然有效,但是每次有人需要与中央存储库同步时,您都会得到一个多余的“合并提交”。对于这个工作流程,最好还是使用变基而不是生成合并提交。
Mary 解决了合并冲突
变基的工作原理是将每个本地提交传输到更新的 main
分支,一次一个。这意味着您可以在逐个提交的基础上捕获合并冲突,而不是在一次大规模的合并提交中解决所有冲突。这样可以使您的提交尽可能集中,并使项目历史记录变得干净。这样一来,可以更轻松地找出错误是在哪里引入的,必要时还可以在对项目影响最小的情况下回滚变更。
如果 Mary 和 John 正在研究不相关的功能,则变基过程不太可能产生冲突。但如果是这样,Git 将在当前提交时暂停变基并输出以下消息以及一些相关指令:
CONFLICT (content): Merge conflict in <some-file>
Git 的好处在于任何人都可以解决自己的合并冲突。在我们的示例中,Mary 只需运行 git status 即可查看问题出在哪里。冲突文件将显示在“未合并路径”部分:
# Unmerged paths:
# (use "git reset HEAD <some-file>..." to unstage)
# (use "git add/rm <some-file>..." as appropriate to mark resolution)
#
# both modified: <some-file>
然后,她将根据自己的喜好编辑文件。在对结果感到满意后,她可以用通常的方式暂存文件,然后通过 git rebase 完成剩下的工作:
git add <some-file>
git rebase --continue
这就好了。Git 将继续进行下一次提交,并对任何其他产生冲突的提交重复该流程。
如果您到了这个点并有所意识,但您不知道发生了什么,不要惊慌。只要执行以下命令,就能马上回到起点:
git rebase --abort
Mary 成功发布了她的功能
在完成与中央存储库的同步后,Mary 就可以成功发布她的变更:
git push origin main
下一步
如您所见,仅使用少量 Git 命令就可以复制传统的 Subversion 开发环境。这对于让团队脱离 SVN 非常有用,但它没有利用 Git 的分布式特性。
集中式工作流程非常适合小型团队。随着团队规模的扩大,上面详述的冲突解决流程可能会成为瓶颈。如果您的团队对集中式工作流程感到满意,但又想简化协作工作,那么功能分支工作流程的好处绝对值得探索。通过为每个功能指定一个单独的分支,可以在将新增功能集成到官方项目之前就新增功能展开深入讨论。
其他常见工作流程
集中式工作流程本质上是其他 Git 工作流程的基石。大多数流行的 Git 工作流程都会有某种集中式代码存储库,开发人员个人可以从这些存储库中推送和拉取。下面我们将简要讨论其他一些流行的 Git 工作流程。这些扩展的工作流程在管理功能开发、热修复和最终版本的分支方面提供了更专业的模式。
功能分支
功能分支是集中式工作流程的逻辑延伸。功能分支工作流程背后的核心理念是,所有功能开发都应在专用分支而不是 main
分支中进行。这种封装使多个开发人员可以轻松开发特定功能,而不会干扰主代码库。这也意味着 main
分支应该永远不会包含损坏的代码,这对于持续集成环境来说是一个巨大的优势。
Git 流工作流
Gitflow 工作流程最初发布于 2010 年 Vincent Driessen 在 nvie 上发表的一篇备受推崇的博客文章中。Gitflow 工作流程定义了围绕项目发布设计的严格分支模型。除了功能分支工作流程所需的概念或命令外,此工作流程不会添加任何新概念或命令。相反,它为不同的分支分配了非常具体的角色,并定义了它们应该如何以及何时进行交互。
创建新拷贝工作流
克隆工作流程与本教程中讨论的其他工作流程有根本的不同。克隆为每个开发人员提供了一个服务器端存储库,而不用将单一服务器端存储库用作“集中式”代码库。这意味着每个贡献者不只有一个而是两个 Git 存储库;即,一个私有的本地存储库和一个公开的服务器端存储库。
准则
没有一刀切的 Git 工作流程。如前所述,开发一个能够提高团队工作效率的 Git 工作流程非常重要。除团队文化外,工作流程还应补充企业文化。分支和标记等 Git 功能应该补充企业的发布计划。如果您的团队正在使用任务跟踪项目管理软件,则可能需要使用与正在进行的任务相对应的分支。此外,在决定工作流程时需要考虑的一些准则包括:
短期分支
分支与生产分支分开的时间越长,合并冲突和部署挑战的风险就越高。短期分支推动了更干净的合并和部署。
最大限度地减少和简化还原
重要的是要有一个工作流程,能够帮助主动防止必须还原的合并。例如,在允许分支合并到 main
分支之前对其进行测试的工作流程。但是,意外时有发生。话虽如此,拥有一个允许轻松还原且不会干扰其他团队成员的工作流程是有益的。
匹配发布时间表
工作流程应补充企业的软件开发发布周期。如果您计划每天发布多次,则需要保持 main
分支的稳定。如果您的发布时间表不太频繁,可以考虑使用 Git 标记将分支标记为某个版本。
摘要
在本文档中,我们讨论了 Git 工作流程。我们通过实际示例深入研究了集中式工作流程。在集中式工作流程的基础上,我们讨论了其他专业工作流程。本文档的一些关键要点包括:
- 没有一刀切的 Git 工作流程。
- 工作流程应该简单,可以提高团队的生产力
- 您的业务需求应该有助于塑造您的 Git 工作流程
要了解下一个 Git 工作流程,请查阅我们对功能分支工作流程的全面细分。
分享此文章
下一主题
推荐阅读
将这些资源加入书签,以了解 DevOps 团队的类型,或获取 Atlassian 关于 DevOps 的持续更新。