65.9K
CodeProject 正在变化。 阅读更多。
Home

版本控制:游戏开发视角的有效使用、问题与思考

starIconstarIconstarIconstarIconstarIcon

5.00/5 (1投票)

2016年10月10日

MIT

60分钟阅读

viewsIcon

18442

从游戏开发者的视角审视版本控制

首发于 What Could Possibly Go Wrong。

你应该使用版本控制吗?

我喜欢这张图,它完美地总结了这一切。

图片来源

那么,让我们来谈谈版本控制。你必须使用它,对吧?当你编写代码时,尤其是在团队中,它是必需的。作为一名专业的开发人员,在大多数情况下,当你加入一家软件公司时,你甚至没有选择,你必须使用他们选择的版本控制系统才能为团队做出贡献。然而,我认为即使对于业余或爱好者开发人员来说,版本控制也是无价的。

在本文中,我将论证版本控制的好处。我将帮助你理解它解决的问题,并向你展示如何更有效地使用版本控制。我还会揭露它可能带来的问题。我将披露版本控制在游戏行业中未解决的问题。

我将介绍我使用过的特定软件包。我自己的经验可以追溯到我第一份编程工作时使用的 Microsoft Visual SourceSafe。这几乎足以让我放弃版本控制!然而,从那时起,我实战检验了许多来自传统模型和更新的分布式模型的其他软件包。它们都有各自的优缺点,没有一个模型是完美的。

对于比最简单的项目更复杂的项目,版本控制对于保持你的理智非常重要。然而,对于不熟悉的人来说, هناك عالم من الألم والمشاكل تنتظرك.

此外,你必须做出一个重要的选择。我应该使用哪个版本控制系统?这个问题没有简单的答案,事实上,也没有正确的答案。你必须根据你的需求接受某个选项。然后,你必须学会绕过你所采用的系统的不足之处(或者选择一个不同的系统,并接受它的不足之处)。

我可以帮助你理解为什么你应该使用版本控制,以及如何更好地使用它。你使用什么软件远不如你确实使用版本控制这一事实重要!

目录

什么是版本控制?

我需要解释什么是版本控制吗?也许不必。许多人已经对此进行了广泛的阐述。

这是一份出色的可视化指南,可以帮助你准确理解什么是版本控制。这是分布式版本控制的可视化指南。

这是另一个好的介绍,解释了版本控制的概念。

简而言之……版本控制允许你随着时间管理更改。它最常用于跟踪源代码的修订。对于游戏开发,我们还跟踪项目(例如,Unity 项目)和资源的修订。它就像一个超级强大的撤销系统。犯错了?没问题,回滚到以前的修订版或撤销有问题的更改。

更改由一组开发人员提交到版本控制代码库。在任何时候,你都可以获取整个代码库的当前状态,即所有更改的总和。这就是你用来构建当前版本游戏的工具。

我是开发新手,我应该使用版本控制吗?

也许吧。考虑一下你最终需要学会它。

然而,要注意不要被学习过程压垮。在学习版本控制之前,你应该专注于熟悉编写代码和制作游戏。

但是,如果你正在团队中工作……那么他们可能会强制使用版本控制。或者你们可能会一起决定学习版本控制是值得的,因为它就是协调开发团队的最佳方式。

我独自工作或做一个小型项目,值得使用版本控制吗?

是的,绝对值得。

我甚至在小型实验性或业余项目中使用它。如果我在任何项目上花费超过,比如说,一个小时。我就会对其进行版本控制。在现有代码上设置一个代码库只需要几分钟。如果项目变得重要,或者我想与团队共享,那么我就会克隆它并将其放到服务器上。这又需要几分钟。

当然,项目和团队越大,你从版本控制中获得的收益就越多。小型项目非常适合学习版本控制等新技术。小型项目更容易管理,压力也更小。任何新技术的使用都不可避免地会导致错误,你必须为此做好计划并准备好付出代价。当项目很小时,我们可以承担犯错的代价,因为在这种情况下,它们更容易纠正。

现代版本控制很容易上手。没有借口不使用它。

我应该说服我的队友使用它吗?

是的。

嗯,也许吧。如果你的团队反对使用版本控制,那可能不值得去争论,那样的话就节省你的精力去做更有意义的事情。改变你的团队可能比说服他们使用版本控制更容易。

如果你的队友不情愿,那可能只是因为他们需要亲身经历没有版本控制的协作开发带来的痛苦,然后才愿意尝试。

教育是一种答案。如果你的队友理解版本控制的必要性,他们就会想使用它。内化本文提出的论点,并开始努力说服他们接受你的观点!

如果我不喜欢使用版本控制怎么办?

这很容易。就是不用。

虽然,也许你只是不喜欢你尝试过的第一个版本控制系统?好吧,试试不同的软件包,看看是否更符合你的喜好。你有选择的好处。

也许你尝试过传统的版本控制系统,但你使用分布式系统会更好?反之亦然。

也许你还没准备好使用版本控制。没关系。尝试使用 Dropbox 或 U 盘与队友共享你的代码。你很快就会明白为什么版本控制很有用。

我不是开发人员,我应该使用版本控制吗?

是的。嗯,也许吧。

你可以使用版本控制来管理各种东西。它对文本文件最有效,因为版本控制系统通常是为处理源代码而构建的。你还可以管理二进制文件,如艺术资产、电子表格和文档,尽管这在某些系统中的效果比其他系统更好。这意味着你可以管理几乎你能想象的任何文件。

如果你需要跟踪和维护文件版本,版本控制就是为你准备的,而且你不需要是开发人员也能从中受益。

作家绝对可以使用版本控制来跟踪他们的书籍修订。例如,GitBook 就是基于此创建了整个商业模式。

数据分析师也可以利用版本控制。看看用于表格数据的DAT 包

为什么使用版本控制?

每个人对此都有自己的看法。这是我关于版本控制能为你做什么的列表……

实现安全的工作流程

以小型且易于测试的增量方式提交代码。如果任何提交导致问题……可以轻松撤销。

实现无畏的实验

实验或重构不成功?只需将你的进行中的工作恢复到干净的版本。

把本地代码库弄得一团糟?只需删除它,然后从主代码库克隆一个新副本。

回滚到以前的版本

版本控制允许回滚。就是恢复旧版本的代码。这就是我称之为超级强大的撤销系统的原因。

当前版本有糟糕的错误吗?恢复先前起作用的代码版本。

删除了现在需要的代码吗?恢复已删除代码的副本。

性能急剧下降?找到一个性能良好的先前版本,这将帮助你了解问题的原因。

需要重建一个先前可用的版本?假设你想修改并重新构建两个月前制作的 PAX 演示。使用版本控制回到过去,进行所需的更改,然后重新构建演示。

隔离有问题的修订

使用版本控制,你可以搜索以前的修订版,以找到引入问题的点。这很有帮助,因为找到问题的根源通常占工作量的 90%。

管理多个版本

使用分支、fork 或标签来维护产品的多个版本。当你需要有多个开发流并行进行且不相互干扰时很有用。例如,许多开发人员至少维护一个经过充分测试的生产版本和一个正在进行的开发版本的代码。

协调团队合作

版本控制可以防止在开发团队中工作时出现绝对的混乱。它支持协作工作。手动共享和合并代码既耗时又容易出错。如果你通过 Dropbox 或类似替代品共享协作项目,那么你就是在玩火。

了解项目的历史

版本控制允许你了解项目的历史和发生的事情。你可以看到是谁创建了一个文件,又是谁最后编辑了它。事实上,你可以看到自创库(至少在代码库看来)以来,对每个文件所做的所有编辑历史。

版本控制可以审计代码库的历史。

备份

所有 PC 最终都会损坏。当你的 PC 损坏时,它会带走你的绝佳项目吗?

使用版本控制意味着至少,你应该在服务器上有一个项目的master版本。如果你的 PC 损坏,你只会丢失你尚未集成到服务器上的最新工作。

如果你的服务器损坏了怎么办?好吧,你要么需要对你的服务器进行自动备份。或者你应该考虑使用分布式版本控制系统(DVCS),其中将代码库克隆到备份驱动器非常简单。

实现持续集成和持续交付

虽然这不是本文的重点,但持续集成(CI)和持续交付(CD)是扩展开发团队和自动化构建、测试和部署非常重要的技术。版本控制是这些高级技术的关键支持者。

传统模型还是分布式模型?

在本节中,我将介绍两种不同的版本控制模型。这是对概念的介绍,然后是我对每种模型的优缺点的简洁列表。

关于此的更多信息,Atlassian 提供了一个对模型的不错比较,其中包含大量视觉效果和图表。

传统版本控制

传统的版本控制系统依赖于一个中央服务器。在此模型中,多个客户端与共享服务器通信以提交更改并处理修订历史。客户端拥有所谓的工作副本,这是所有文件以及迄今为止所有更改的累积副本。对工作副本的更改会直接提交到共享服务器。每当客户端提交一个更改时,该更改就会立即提供给所有其他客户端。

优点

  • 客户端-服务器模型易于人们理解,因为像 FTP 这样的客户端-服务器程序早已存在。
  • 它在传统的办公室环境中运行良好。人们在一个私有局域网中一起工作,并且都可以方便地访问服务器。
  • 该软件成熟且健壮。
  • 只有一个服务器,所以很容易记住你的代码在哪里,尽管如果你使用大量分支,它仍然会变得失控。
  • 在大多数软件中,都可以锁定文件进行编辑。这有助于防止多个人编辑二进制文件。
  • 代码库可以部分同步。当你需要获取代码库的一部分,而不是整个代码库时,这很有用。

缺点

  • 对于分布式团队、远程工作者和外包团队来说,传统模型就显得不够理想了。这是因为你需要访问服务器才能使用它。良好的互联网连接可以缓解这个问题。
  • 它不灵活。很难复制代码库。当然,你可以创建所需的任意数量的工作副本,但要创建包含历史记录的代码库的完整副本是困难的。也不能在代码库之间合并(至少不容易或没有附加工具)。
  • 如果你使用传统的代码库来存放多个项目,随着时间的推移,它会不断增长。最终,它会变得臃肿且难以管理。你可能需要归档旧项目,因此与管理传统版本控制相关的维护成本更高。

分布式模型

版本控制的分布式模型是一个点对点系统,而不是传统模型的客户端-服务器方法。每个节点在分布式网络中都是一个完整的代码库,而不是一个中央服务器。用户在他们的工作副本中进行更改,然后将这些更改提交到他们的本地代码库。然后可以与其他代码库交换更改(推送拉取)。

分布式版本控制非常适合处理代码,但所有分布式系统目前在处理二进制资产和非常大的项目时都存在问题(尽管Facebook 正在为 Mercurial 开发此功能)。

Mercurial 和 Git 之间曾有过一场竞争。我个人更喜欢 Mercurial,但我也经常为开源项目使用 Git。

优点

  • 对于分布式团队、远程工作者和外包团队来说非常有效。
  • 分布式系统内置支持离线工作,并且非常适合旅行时使用。喜欢在咖啡馆工作?去做吧,在离线时累积提交,回到办公室时再与你的代码库同步。
  • fork(或clone)代码库非常容易。这使得备份和归档变得容易。它使得使用代码库的多个并排副本变得容易。
  • 在服务器崩溃等灾难发生时,丢失代码库的风险要小得多。代码库很可能在团队成员之间有许多克隆副本,因此丢失代码库的可能性要小得多。对于传统的集中式系统,如果丢失了中央代码库,你就会丢失所有项目的历史记录。
  • 技术上不需要服务器,尽管为了方便起见,你很可能会将某个 PC 上的特定代码库指定为代码库。
  • 工作流程非常灵活。你可以轻松地使用一个代码库和多个客户端代码库来模拟传统结构,但你不限于此布局。
  • 主要的分布式系统都是开源且免费的。
  • 无需签出即可编辑,它会为你处理(实际上 SVN 也可以做到这一点,尽管令人讨厌的是 Perforce 不行)。
  • 非常容易忽略文件(说实话,SVN 也允许这样做,但在 Git 和 Mercurial 中,ignore 设置都存储在一个简单的版本化文本文件中)。

缺点

  • 模型难以被人们理解,并且难以解释。即使是一些程序员也难以理解这个概念,试着向非技术人员解释一下!
  • 对二进制文件的支持很差!它们不擅长处理二进制资产,尤其是大型二进制资产。我注意到有大型文件扩展,但我没有尝试过。
  • 处理大型项目(我指的是 GB 级项目大小)不太好。
  • 随着项目规模的增加,性能往往会下降。
  • 你可能会最终拥有许多代码库,特别是如果你像我们在 Real Serious Games 那样快速地处理项目。这会变得难以管理。很难记住哪个项目包含什么。可以通过良好的流程和文档在一定程度上解决这个问题。
  • 分布式版本控制不支持部分同步。你不能只同步项目的一部分,你必须同步整个项目。当你理解了分布式系统的本质时,这很有意义,但如果你来自传统模型,你可能会怀念同步非常大的代码库的某个部分的能力。这是一个保持分布式代码库小型轻便的好理由。

版本控制与游戏开发

游戏有普通软件开发项目无需处理的独特问题。作为一名游戏开发者,你需要从你的版本控制工具集中获得一些不同的要求。

学科和团队

首先……除了程序员之外,其他人也从事游戏制作。根据需要,游戏团队会结合来自构建游戏所需学科的个人。程序员在使用版本控制时通常没有太大困难(经过一些经验后)。然而,其他学科(艺术家、设计师、制作人、QA 等)可能会发现这些工具复杂且令人不知所措,尤其是在合并方面(许多程序员甚至觉得这很困难)。

良好的培训、教育和对持续改进的承诺可以帮助更广泛的团队在版本控制方面取得成功。如果你是一名程序员,你可以通过创建脚本和工具来使版本控制对其他团队成员更容易使用,尽管资源稀缺的小型工作室可能难以实现这一点。至少,程序员应该随时准备帮助团队成员解决版本控制问题。

游戏团队的规模和结构各不相同。最小的团队有 1-2 人。最大的团队可能有数百人协作。版本控制系统通常能够很好地扩展到大型团队。有许多大型软件开发公司有数千名程序员使用版本控制。大型团队至少是版本控制已解决的问题。

二进制资产

普通软件开发项目大多版本化代码(例如,文本文件)。游戏通常混合了文本和二进制资产。有代码、配置文件和其他各种文本资产。然后是二进制资产,如网格、纹理和关卡/场景。

大多数版本控制系统都是为处理源代码而设计的,它们在处理游戏开发中常见的海量二进制资产时非常吃力。特别是,分布式版本控制系统在处理二进制资产和大型项目时非常吃力。不过情况正在发生变化,例如,Facebook 正在使用和改进 Mercurial 来处理他们巨大的代码库。

版本控制的一个关键特性是能够合并多个程序员同时编辑的源代码。不幸的是,这对于二进制资产完全不起作用!这些无法通过版本控制进行合并,这会造成一个糟糕的流程瓶颈,即一次只有一个人可以处理一个二进制资产。让多个人处理二进制资产会导致一个人(甚至更多人)丢失他们所做的工作。

一些版本控制系统允许锁定资产,这是一个可接受的,即使不理想的,解决这个问题的方法。这可以确保一次只有一个人可以编辑一个二进制资产,并且没有人有丢失工作的风险。当然,这只在传统系统中可能,分布式系统的本质阻止了锁定。当然,你可以创建一个插件或其他方法来自己实现锁定系统,但这会分散你制作游戏的精力。

如果由于你的版本控制系统选择而无法锁定二进制文件,你必须找到另一种处理此问题的方法。

流程和工作流程

有一件事你应该绝对去做,那就是努力使你的工作模块化,以便更容易地将任务分配给团队,而不会引起冲突。程序员在制作代码模块时已经这样做了。我们将代码按文件拆分。然后一个开发人员可以处理一个文件,另一个开发人员可以处理另一个文件,只要开发人员处理的是不同的文件,就不需要合并。我们创建的独立模块越多,开发人员就越有可能在不相互干扰的情况下工作,并且合并冲突的风险就会降到最低。在某种程度上,这种方法也可以用于资产……网格、纹理和场景都可以被分解成模块(并在运行时加载/流式传输),这意味着艺术家和设计师在他们需要编辑的资产上发生重叠的可能性更小。

处理此问题的另一种方法是制定流程或工作流。许多人使用我称之为谁拥有资产?的系统。在此系统中,一次只有一个人可以声明资产的所有权。在此期间,只有该个人可以编辑该资产。此系统仅在团队遵循流程中定义的规则时强制执行,我的意思是团队必须足够自律以坚持规则。每个团队成员必须了解其他人当前正在处理的资产,并且必须尊重地克制自己不处理其他人当前占用的资产。如果你们都在同一个房间里,这并不特别困难,在工作时大声喊出来!或者也许把它写在白板上以跟踪谁拥有什么。对于分布式团队,你可以通过在线通信来实现这一点,像Slack 这样的工具就足够了。

你可能会认为多么糟糕的流程游戏行业是怎么走到这一步的。是的,这离理想情况相去甚远。不幸的是,有时,我们因为我们的处境、团队或技术选择而不得不采取这样的策略,而我们仍然需要以保持理智的方式完成工作!

版本管理

游戏开发者面临的另一个有趣问题是,我们项目完成的速度通常比普通软件开发快。软件项目通常持续多年。另一方面,游戏可以很快完成,最小的游戏可以在几个月内创建。移动游戏的趋势以及技术的进步意味着游戏的构建速度比以往任何时候都快。这就引出了一个问题:项目完成后我们该做什么?我们需要退役项目并将其归档,尽管如果我们以后可以再次访问该项目用于参考或从中提取代码和资产用于另一个项目,那会很好。正如我们很快将看到的,一些版本控制系统在这方面比其他系统做得更好。

游戏,与传统软件项目一样,通常需要管理和维护多个版本。在某个时候,你需要开发生产版本的代码。通常,游戏也有多个版本并行开发。例如,发布一个你正在收集反馈、更新和重新发布的alpha 版本并不罕见。同时,其他团队成员正在单独努力实现beta 版本。然后还有一个人不得不 fork 了alpha 版本并 hack 了一个原型演示以在PAX 上展示。

你明白了我的意思。我们需要一个项目的多个版本,多人为每个版本做出贡献。每个单独的项目版本不能相互干扰。别松口气,还有更多。你最终还需要将所有项目的更改合并到一个主版本中。例如,你可能已经在alpha 版本中修复了一些错误,而你需要将它们带入beta 版本。如果你是开发新手,这听起来可能是一场噩梦。好吧,它可能会。但这些我所描述的情况只有通过版本控制才能实现。它可能仍然显得混乱,难以跟踪正在发生的事情和谁在做什么,但有了版本控制,你就有了一种手段来管理和控制混乱,并将其引导到一个合理的方向。你可以使用的工具是分支fork标签。分布式版本控制系统在管理多个版本方面表现出色

版本控制与 Unity

Unity 为Perforce 和 Plastic SCM 提供了集成。如果你正在使用 Perforce 或 Plastic,这些可以使你的生活更轻松。不幸的是,Subversion、Mercurial 或 Git 没有内置集成。这些插件的代码是开源的,你可以在 Bitbucket 上找到它。如果你查看代码,可以看到它支持 SVN!然而,SVN 尚未包含在 Unity 中。如果你在 Asset Store 上搜索,你会找到各种支持 Mercurial 和 Git 的包,尽管我个人并不认为有必要,我认为 Mercurial 和 Git 在没有插件的情况下与 Unity 的配合效果很好。

如果你不使用 Unity 的版本控制插件,那么你应该将版本控制模式设置为可见的 Meta 文件如 Unity 手册中所述

如果可能,我还喜欢将资产序列化模式设置为强制文本。这会导致像项目设置、meta 文件和场景这样的资产以文本文件的形式存储。这一点有争议,但这样做的好处是可以查看场景等资产的差异,而这些资产通常以二进制形式存储,因此无法进行差异比较。这有助于你理解 Unity 资产的结构。不幸的是,此设置对于非常大的项目来说扩展性不佳,并且可能导致来自 Asset Store 的第三方包出现问题。在这些情况下,你应该为大型项目将其设置为混合强制文本对于小型项目最有用,尤其是在你学习 Unity 数据格式时。

问题

编辑场景和其他二进制资产

编辑 Unity 场景和其他二进制资产是一个巨大的流程瓶颈。通常,一次只能有一个艺术家设计师处理这些文件。

使用强制文本(前面提到)会有所帮助。这将你的场景文件存储为文本文件,因此可以合并它们,尽管合并很少容易,而且强制文本对于大型项目来说可能不可行。如果你的版本控制系统支持文件锁定,那么这将有助于强制单用户编辑 Unity 场景和二进制资产。

即使如此,复杂的开发人员也会因此而陷入困境。事实是,一次只有一个团队成员可以处理一个场景。我认为这是 Unity 应该修复的最大问题。

模块化可以提供帮助。将大型场景分解并使用流式传输在运行时合并它们。Unity 5.3 的新SceneManager 可以帮助实现这一点。

同步时不要 alt-tab

当你从版本控制同步 Unity 项目时,请小心不要alt-tab 返回 Unity。如果在同步过程中这样做,可能会发生糟糕的事情。想象一下这种情况:同步正在进行中,你的资产和场景已更新,但尚未更新你的meta 文件。你 alt-tab 回到 Unity。Unity 然后认为你有一堆没有 meta 文件的资产。所以它会生成 meta 文件。与此同时,版本控制同步继续进行并获取 meta 文件,但它没有获取 meta 文件,因为它很保守,不想覆盖 Unity 刚刚生成的 meta 文件。现在你打开你的场景,却发现脚本和预制件的链接已断裂!

这不仅仅是一个人为的案例,我见过它发生过很多次。随着代码库大小的增加,问题会越来越大,同步代码库所需的时间越长,触发此行为的可能性就越大。

管理发布的技巧

分支、标签和 fork 是管理发布的三个不同技巧。你选择哪种取决于你的需求和你舒适使用的程度。

分支

分支可以看作是代码库的内部克隆。

当你处理一个代码库时,你会选择要处理的分支。如果你没有创建任何分支,那么你将自动处理默认分支。在任何时候,你都可以基于现有分支创建一个新分支,然后根据你当时需要处理的内容在分支之间切换。

开发人员出于各种原因创建分支。通常,为特定版本创建一个分支,这允许你维护一个与生产代码分开的代码库开发版本。

我还知道团队为功能创建分支(他们在单独的分支中实现一个功能,然后进行测试,再将其合并回主干)。你也可以按任务、团队和个人进行分支。

Jeff Atwood 对分支和分支策略有一个很好的概述。

标签

标签允许你标记一个特定的修订。这可以作为将修订与特定发布或里程碑关联的绝佳方式。例如,一旦你完成了PAX 演示,你就可以用该名称标记修订。这样做,你就有了一种在修订历史中识别代码版本的方法。

标签比分支更容易处理,但它们不如分支强大。例如,如果你想回去编辑PAX 演示并重新发布该代码,你会发现使用标签实现这一点很棘手,并且可能会在你的修订历史中造成混乱。

Fork

Forking克隆你的代码库是分支的替代方案。

分支是代码库的内部副本,而 fork 是外部副本:一个完全独立的代码库。fork 的代码库与原始代码库相关,代码更改可以轻松地在它们之间合并。你可以用分支做的任何事情,也可以通过 fork 来做。你可以为开发和生产 fork 独立的代码库,你可以为功能、任务和个人 fork 独立的代码库。

Fork 可能比分支更灵活。一旦你分支了你的代码库,它就会保留在你的代码库中,并增加其大小(使代码库臃肿)。Fork 的代码库存在于外部,这使得在不再需要时可以安全地处理它们。如果你发现自己创建了短暂的或大量的分支,你可能想考虑使用 fork。

Fork 可能比分支更容易理解。毕竟,fork 只是代码库的另一个副本。你可以在文件系统中看到它。你无法在文件系统中看到分支,分支只通过你的版本控制系统提供的工具存在。

选择哪个?

我提倡一种平衡的方法。

代码库之间长期存在且高度耦合的关系应表示为分支。开发生产分支是一个很好的例子。

代码库之间短期关系应表示为 fork。例如,你的PAX 演示将在几周内完成。你可能需要大量修改你的代码,所以你想分支。我认为 fork 是这里的更好选择,因为你可能想在一个月左右后淘汰代码库。淘汰 fork 比淘汰分支更容易,因为 fork 可以轻松地从文件系统中删除(或归档到其他文件夹)。

当你有很多代码库关系时,你也应该考虑 fork。例如,在 Real Serious Games,我们定期(每 3-6 个月)从我们的开发代码库中 fork代码版本。我们给代码版本编号,从版本 1 开始。我们现在已经到版本 22。我们喜欢保留这些旧的代码版本,因为我们可以归档旧代码,并在客户回来要求新功能时轻松地恢复它。对我们来说,拥有 22 个分支,使我们的主代码库臃肿是不切实际的。

有效使用版本控制

这里展示了我收集的技巧和最佳实践。这些将帮助你更有效地使用版本控制。

请记住,一个人的最佳实践是另一个人的最差实践。这些建议仅供参考。我已经尝试了所有这些策略,并发现它们在大多数情况下都有效。然而,规则和流程需要灵活。软件开发行业非常复杂,我们需要灵活性。在可能的情况下遵循最佳实践,在不能的情况下抛弃它们,或者根据你的需要进行调整。

培训

确保每个人都接受了如何使用版本控制的教育。如果你的团队中有比你更了解它的人,让他们教你。如果你比你的队友更了解它,教他们。教育和培训有助于解决人们在使用版本控制时遇到的许多问题。

版本控制一切……除了可安装或可生成的内容

版本控制任何你不能承受丢失的原创作品。源代码、配置文件、测试脚本、源资产。

不要提交可通过设置或构建过程生成的文件!

你应该有一个项目设置脚本,用于安装第三方包和依赖项。你还需要一个构建脚本,负责从源代码和资产创建构建。拥有这两样东西可以使新开发人员更容易开始一个项目。这也意味着安装和生成的文件不必包含在你的版本控制中。将这些文件包含在版本控制中会使你的代码库臃肿,并使其复制和同步变慢。

代码审查

我们的流程与版本控制交互的地方为我们提供了一些进行代码审查的自然点。

在提交之前,你应该进行自我审查同行评审。自我审查类似于同行评审,只是你在审查自己的代码,但你应该假装你在审查别人的代码!这使得更容易发现代码中的错误。

使用分支的人可以在将代码合并到分支之前进行代码审查。例如,当你将代码合并到你的发布候选版分支时,你可以对其进行审查。或者当你将代码合并到你的生产分支时,你可以在代码进入公众之手之前进行最终的代码检查。

如果你使用分布式版本控制,你还有另一个审查机会……当你推送到主代码库时。这是另一个确保你不将不良代码推送到队友的机会。

Github 有一个很棒的系统,支持远程代码审查。当你准备将更改合并回主代码库时,你可以提交一个pull-request。其他人应该审查 pull-request 并将其合并到主代码库。如果在审查过程中出现任何问题,审查员可以注释 pull-request 并提出应解决的查询和问题。

提交前测试,不要破坏构建!

确保你在提交到版本控制之前彻底测试了你的代码

测试和代码审查有助于防止问题进入主代码库。这是发现和修复缺陷的最廉价的时间点。随着代码和功能沿着管道进一步推进并进入玩家手中,发现和修复缺陷会越来越困难且昂贵。

同步时要小心

请注意,构建可能随时被破坏!

代码审查、自动化测试、持续集成和认真的开发人员都可以帮助最大限度地减少构建损坏的发生,但人为错误确实会发生,有时问题会悄悄溜走!

当你与他人的工作同步时,准备好停止正常工作并修复问题。有时你会因为构建被破坏而受阻。发生这种情况时,只需参与并修复它。事后回顾留待以后,在构建修复之后。

错误会发生。请注意,当你同步时,你可能会将问题合并到你的本地代码库中。请在你方便的时候这样做!然后准备好处理可能出现的任何问题,这样你就可以继续你的工作了。

提交消息

你的提交消息是一种沟通方式。你正在向你的队友或甚至你的未来自己发送消息!善待你的同事。善待你的未来自己。确保你的提交消息是有意义的。

代码注释一样,提交消息最重要的就是解释代码更改的意图。解释“为什么”而不是“如何”。就像你的代码注释不应仅仅解释从阅读代码中容易看到的内容一样,你的提交注释也不应仅仅解释通过检查更改集可以轻松读取的内容。比解释代码如何工作更重要的是——许多程序员似乎在这方面失败了——解释更改背后的思考过程。解释为什么需要更改以及它增加了什么价值。

更改是否修复了错误?解释错误并说明更改如何修复错误。

在某个时候,也许当你试图弄清楚某个特定错误是什么时候添加的,你将不得不回去查看旧的代码修订。当发生这种情况时,你会很高兴你写了有意义的提交消息。

你还应该将提交消息与你的流程和系统相关联。如果你正在完成任务跟踪系统中的一项任务,请务必在提交消息中包含任务编号。修复错误也是如此。修复错误时,请在提交消息中包含错误编号。

这是你的日记

我喜欢将版本控制视为我的日记。

忘记了上周做了什么?忘记了昨天在做什么?看看你的版本控制历史。

当我写提交消息时,我把它们写成日记条目,准备好让别人阅读。用你的提交消息讲一个完整的故事。如果你能想象出别人将如何阅读这个故事,你就会写出更好的故事。

进行小型频繁提交

进行小型提交,频繁进行。

小型提交更容易测试,因为需要测试的内容较少。它们更容易进行代码审查,并且问题会被更快地发现。许多小型且经过充分测试的代码更改加起来可以使代码稳定得多。这大大降低了未知问题累积并在稍后给你带来惊喜的风险。一旦你有了一个运转良好的工作流程,进行频繁的小型且可靠的提交,你的工作将很快累积成大事。而且一切都会正常工作!最糟糕的事情莫过于在你需要做一个重要的构建之前才发现糟糕的问题。

大型提交可能会隐藏许多问题。更糟糕的是,这些问题可能纠缠在一起,从而加剧了问题。小型提交,其性质上,包含的问题很少,而且这些问题更容易检测。问题会更少,因为它们不会纠缠在一起,这再次使它们更容易被发现和解开。

每次提交都应该只做一件事,它应该是一个逻辑单元,并且所有代码更改都应该是相关的。你听说过单一职责原则吗?在提交代码时,我们也应该追求类似的目标。提交中的所有更改都应该高度相关。你应该明确地将行为更改、重构和性能优化分开提交。当问题被组合在一起时(因为你在一次大型提交中将它们组合在一起),它们引起的问题将更难处理。

如果你正在修复一个错误,请确保修复本身就是一个单独的提交。

如果你正在添加一个功能,只需提交该功能。不要试图偷偷进行不必要的重构和格式更改。许多功能实际上需要多次提交,但通常不难将一个大型功能分解成多个逻辑单元。

如果你在进行小型提交时遇到困难,可能是因为你的工作计划不充分。复杂的更改应进行规划并在一系列小型但相关的提交中执行。如果你仍然是开发新手,这可能会很困难,你甚至可能没有意识到它的必要性。努力提高你的规划能力,练习将你的工作分解成更小的提交,你会随着实践而提高。小型简洁的提交是技能和经验的标志。

与所有这些指南一样,不要走得太远!不要仅仅为了看起来你在做小型提交而分割一次大型提交!不要人为地制造小型提交以适应流程。我见过一些经验不足的程序员准备好了巨大的提交……然后将其分成小型提交,以满足流程。这只是将一次大型提交隐藏为一系列小型提交,并没有真正解决任何问题。不可避免地,一些小型提交最终会难以单独解释,或者干脆是损坏的。在进行代码审查时要注意这些警报。

如果你需要进行一次大型提交,那就去做吧。有时,我们必须进行大型提交,尽管通常我们应该避免这样做。当你必须这样做时,请留出一些时间进行反思。问问自己,是否有其他方式可以将一次大的更改分解为一系列小的提交?自我反思对我们成长和积累经验非常重要。

频繁推送

这是对进行小型频繁提交的扩展,适用于使用分布式版本控制的人。

频繁推送到你的主代码库。尽可能每天推送。你等待与团队集成工作的时间越长,合并就会越困难,并且你破坏构建的可能性就越大。

长时间不推送代码会增加你的电脑崩溃并丢失工作的风险。这种情况不常发生,但确实会发生。在你的编程生涯中,总有一天会发生在你身上。你会丢失多少工作?频繁推送可以最大程度地减少这种情况发生时丢失的工作量。如果你需要一些动力……想想因为丢失了工作而错过了重要截止日期。想想如果发生这种情况,你的队友或老板会怎么想。每天推送(或可能使用自动备份系统)是你唯一的保护。

如果你正在处理一个实验性或不确定的功能,并且不想冒将内容推送到主代码库的风险,只需 fork 主代码库并推送到该副本即可。当然,你必须使用分布式系统才能做到这一点。

保持代码库干净的副本

通常值得在你的开发工作站上维护两个代码副本。你有一个副本用于开发。你可以使用另一个副本进行测试或将你的更改与基线进行比较。你可以使用传统和分布式版本控制来做到这一点。使用传统代码,只需将服务器代码库的新副本获取到另一个工作目录,尽管以我的经验来看,这比 Perforce 使用 SVN 更容易。如果你正在使用分布式版本控制,那么它就更容易了。只需创建一个主代码库的单独克隆。

拥有多个代码库副本对于分布式版本控制来说更容易,也更有效。例如。在你的开发副本中进行更改。测试、审查并提交你的更改。现在将你的更改推送到你的干净副本(当然它将不再是干净的)。现在在你的干净代码库中测试你的更改。你的测试仍然通过吗?代码经常在你推送到主代码库时中断。也许你忘了导入或提交一个文件?将更改推送到一个单独的干净副本并在那里测试可以防止这些类型的错误强加给你的队友。一旦你在干净的代码库中纠正了任何问题,你就可以安全地将更改推送到你的主代码库了。

有一个干净的副本对于你的开发代码库中存在错误很有好处。你可以并排拥有两个代码库进行比较。这有助于你更好地理解你所做的更改。它非常有助于理解一个错误是刚刚创建的,还是它已经存在于代码中。当你有一个干净的副本时,你可以测试这样的问题。在干净的副本中再次运行你的测试,你很快就会发现你是否刚刚引入了一个错误,或者它是否早已存在于代码中。

需要时回滚更改

有一些实验性的代码更改没有成功?你一直在处理代码,并且遇到了问题。你继续强行解决问题。如果你提交了这些有问题的代码,你可能会花费数周时间来清理问题。你可能已经经历过这种情况。重构,尤其是在没有自动化测试的安全网的情况下,可能会导致代码严重损坏,并在几个月后出现 bug。

编码通常是关于找到正确的前进道路。有些路径明显优于其他路径,而有些方向则完全错误。如果你朝着错误的方向前进,你就不能继续前进并用代码来解决它。当你认识到当前方向的问题时,停止为自己挖更深的洞!

不要害怕在更改不顺利时回滚更改!如果存在明显的问题或感觉不对劲,只需回滚你的代码,花点时间思考,然后从另一个角度处理问题。你已经在做小型提交……因此你将丢失的工作量会很小。

另一种选择是stashshelve你的更改,直到你弄清楚如何解决问题。另外,当你计划重构或进行实验性更改时,请考虑forkingbranching,这样你就可以让你潜在损坏的更改不影响你的队友。

测试

版本控制可以帮助测试。考虑使用一个单独的代码库来记录你的输出测试结果(请在测试文章的技巧部分中查看)。当你运行测试时,你可以使用你的版本控制系统来比较更改,以了解行为是否已改变或某事是否已损坏。

代码冻结

在你的开发生命周期中,会有一些时候你想冻结代码库

例如,假设你刚刚发布了一个版本的游戏到生产环境,或者你已经通过了一个重要的里程碑。你需要保留此时的游戏版本。不可避免地,你将不得不再次更新和发布该版本。同时,你的开发人员必须能够为将来的版本继续进行进行中的工作。你需要将这些工作流分开,以便你的开发人员(他们正在尽最大努力快速工作)不会破坏先前可用的生产版本。

如果你的版本控制系统支持这一点,请使用它来强制执行代码冻结。特定的版本控制系统,尤其是传统系统,可能支持可配置的读/写权限。如果是这样,在代码冻结期间删除写权限。对于分布式版本控制,一种简单的技术是重命名你的冻结代码库。将代码库重命名为显眼的名称,如冻结里程碑 2。这可以防止你的开发人员意外推送到冻结的代码库。

当然,你还需要一个进行中的工作的代码库副本供开发人员继续他们的工作。分布式版本控制使这变得微不足道。你只需forkclone冻结的代码库,然后在新代码库中继续进行中的工作。

仅在需要时分支或 fork

请记住,你创建的每个分支或 fork 都需要你的大脑空间来记住发生了什么。保持简单。只有当你有一个合理的理由时才分支或 fork,或者当你有一个使每个分支或 fork 的目的易于理解的系统时。

如果你必须有许多分支或 fork,请记录每个分支或 fork 的目的,以免你费力记忆。

错误恢复和 Bug 调查

你是否曾意外地将一个重要的 bug 发布到生产代码?你的老板是否在你拼命调试问题时在一旁监督?

版本控制可以提供帮助,它为暴露给用户的新问题提供了一种便捷的解决方案。只需回滚撤销以删除已更新且有问题的代码。尽快将用户恢复到可用的版本。然后,只有在一切恢复正常后,才有时间评估出了什么问题并调查问题。

你当前的修订版是否极其损坏,而你却不知道为什么?识别导致问题的修订版。你会发现问题更容易修复。通常,修复 bug 最困难的部分是找到导致它的代码。我确信你曾有过这样的经历:花费数天时间找到一个问题的根源,然后只用 5 分钟修复了负责的那一行代码。如果你能找到引入问题的修订版,那么理解问题将大大容易。理解问题通常比修复问题困难得多。

为了找到 bug 的原因,我们必须在代码中定位它。如果你搜索整个代码库,就像大海捞针。任何能缩小搜索范围的方法都会有帮助。通常,这需要你利用你对代码的理解和一些直觉来定位你怀疑与问题相关的特定代码模块。但也要考虑这一点,如果你将搜索范围缩小到一个修订版,那么你的搜索将非常有针对性。你必须搜索的代码大大减少了,特别是当你进行小型提交时。这会自动让你更接近找到 bug。在许多情况下,当检查有问题的代码修订时,bug 的原因会立即显现。

这引出了一个问题:我们如何找到引入 bug 的修订版?你正在寻找的技术称为二分法。这就像将二分查找应用于你的代码库。你有一系列代码修订,最新的修订是损坏的,某个过去的修订是好的:你必须搜索中间的修订,其中引入了 bug。当然,你可以手动使用任何版本控制系统来完成这个任务,尽管这可能需要大量的时间和耐心,但有时即使是手动方法也值得,因为对于最糟糕的 bug 来说,它仍然可能是找到问题根源的最快途径。

幸运的是,现代分布式版本控制系统提供了内置的二分法工具。一旦你理解了这意味着什么,你就会觉得它非常神奇。二分法工具可以极大地加速你的手动过程。它们也提供了自动二分法的可能性。要实现这一点,你需要投资于自动化构建和测试流程,这并不便宜,但它有很多其他优点。在这种情况下,优点是我们可以运行一个完全自动化的二分法过程。让它完成工作,当你回到你的工作站时,它会告诉你代码何时损坏。对我来说,这感觉就像拥有超能力。如果你能做到这一点,你的队友将向你崇拜的编码能力屈服。

责备

Blame(追溯)有时在你需要找出最后修改代码行的程序员时会很有用。通常,我提倡代码的共同责任无责备的文化。尽管如此,有时你仍需要知道谁对某一行特定代码负责。这在拥有众多开发者的公司里尤其有用,例如,当你需要理解一个你以前未编辑过的代码模块时。Blame 会告诉你最后编辑了你正在查看的代码的人。这样你就能找到他们,询问他们关于代码的问题。

钩子 (Hooks)

版本控制钩子 (hooks) 可以非常有用。用它们来检测何时有人将代码推送到仓库。例如,当有人将更改推送到主仓库时,你可能想发送一个通知。或者触发一个自动构建和测试。更进一步:当你将代码推送到云虚拟机上的仓库时,触发服务器重启。这是用于简单服务器部署的有用技术。

删除旧代码

不要害怕删除旧代码。最好是删除它,而不是注释掉它,并在你阅读代码时让它占用你的脑力。如果你以后还需要那段代码(大多数时候你不会),你可以很容易地从版本控制历史中恢复它。

不要将应该删除的注释掉的代码留在原地。我保证将来有人(可能是未来的你)不得不去弄清楚如何处理那段代码。为了自己/他人着想,请在最理解那段代码的时候就将其删除。

如果你确实有留下注释掉代码的合理理由……请用注释来记录那段代码,并说明你必须保留该代码的原因。

合并 (Merging)

不要害怕合并。如果你与其他程序员一起工作,迟早你需要合并代码。有时,合并会出错,并且非常难以解决。学会自信地进行合并是值得的。创建一个示例仓库并不断练习。确保尝试几种不同的合并软件,并非所有软件都一样,你可能会发现有些比其他更容易理解。
永远不要尝试合并二进制文件。

永远不要尝试合并生成的文本文件。你可以直接重新生成这些文件,因此无需浪费宝贵的脑力去尝试合并它们(请注意:生成的文件的版本控制可能本身就不应该被纳入)。

保持代码整洁有序。分离良好的代码模块意味着编码人员更有可能在不同的模块上工作,因此他们的工作重叠的可能性就越小,从而需要合并的可能性也越小。

与其他工具集成

尽可能将版本控制与其他工具集成。Visual Studio 2015 内置了 Git 集成,非常有用。还有针对各种其他版本控制系统的 Visual Studio 扩展。

如果你使用 Perforce 或 PlasticSCM 以及 Unity,请务必查看 Unity 版本控制集成

尽可能将你的版本控制与持续集成和持续交付系统集成。

版本控制软件

本节是我使用过的版本控制软件的盘点以及我对它们的看法。

请查阅维基百科以获取完整的 版本控制软件比较

Subversion (SVN)

一个广泛使用的开源/免费的传统版本控制系统。如果你想使用传统模型并且不想为专有解决方案付费,这就是你想要使用的选项。

它相当成熟,入门也相对容易。我曾在几家公司使用过它,它可以处理庞大的仓库和许多分支。

它对二进制或大型资产的支持还可以。

SVN 有一个文件锁定系统,可以帮助你阻止多人同时处理同一个文件,但它并没有真正内置到流程中,因为你不需要检出文件就可以编辑它。在很多方面,这很好,因为你可以修改文件,SVN 会为你找出你更改的内容,但对于文件锁定来说,这很糟糕,因为它使得用户有责任在更改文件之前检查它是否被锁定。这为用户错误留下了空间,意味着即使文件被锁定,多个用户也可以编辑二进制文件,当用户提交时,他们会发现如果其他人已经锁定了文件,他们将不得不丢失他们的更改。

Alienbrain

我使用 Alienbrain 已经超过 10 年了。我发现它是一个非常强大的解决方案,对大型二进制文件和大型项目有很好的支持。Alienbrain 是为娱乐行业设计的,主要由数字艺术家使用。它与 3ds max 和 Photoshop 等艺术工具集成和支持得很好。它还有很好的 API,并且非常可定制。不幸的是,它非常昂贵,这使得它除了最大的工作室之外,其他人都无法负担。

Perforce

我曾在不同公司使用过 Perforce。它是专业行业中的一个标准。它很健壮,相当可靠。它可以支持庞大的团队和成千上万的分支。它的性能非常好,并且能很好地处理二进制资产和大型项目。Unity 对与 Perforce 协同工作有内置支持

然而,Perforce 也有一些严重的缺点。偶尔,我们会遇到无法重现的奇怪的坏行为。我们的构建服务器有时会产生错误的构建。通常可以通过强制获取资产并重新构建来轻松修复。我们无法确定 Perforce 还是 Unity 是真正的罪魁祸首,但这并不意味着我不能肯定地说 Perforce 是 100% 稳固的。

我们似乎经常与随机的 Perforce 问题、其晦涩的 API 或其笨拙过时的界面作斗争。是的,版本控制可能很复杂,可能很难理解,然而 Perforce 有时似乎会竭力让我们的情况变得更糟。我有时会想为什么 Perforce 的使用如此广泛。当然,使用 Perforce 有很多合理的理由,但就个人而言,我发现很难推荐它,特别是对小型工作室。它确实能很好地解决一些问题,所以是否值得考虑确实取决于你的具体情况。

由于分布式模型的兴起,Perforce 已着手参与这场革命。我没有尝试过 Perforce 的这一新功能,因此无法评论,我只是提到它,因为注意到 Perforce 已经注意到分布式运动很有意思。

Perforce 让我非常恼火的一点是,你必须先检出文件才能编辑它。在使用 Subversion 和分布式系统时,你只需开始编辑你的代码或资产,软件就会为你找出你更改了什么。这是让 Perforce 显得极其过时的原因之一。当然,先检出再编辑的模型对于二进制资产来说效果最好(因为它允许锁定这些文件——Perforce 的一个有用功能),但出于所有其他原因,这是一种不必要的挫败。

Perforce 的一个很棒的优点,我之前已经提过,就是它非常快。尝试将一个 1GB 的项目从仓库同步到你的工作站。Perforce 会比你的操作系统通过同一网络复制一个 1GB 的文件快得多。你会想,*它真的获取了所有文件吗?*

我不知道 Perforce 如何能如此快速地复制文件,这似乎是魔法。这背后的另一面是 Perforce 极其愚蠢。我已经提到 Perforce 无法找出你更改了什么,你必须检出才能编辑。当然,你可以使用“Reconcile offline changes”(调和离线更改)功能,但在大型项目上,这个功能非常慢。还有一个缓存系统,使 Perforce 复制文件非常快。这对性能来说很好,但这意味着 Perforce 无法跟上你实际工作目录中的最新状态。例如,你可以删除工作目录的一部分,然后执行“Get latest”(获取最新),什么也不会下载。就 Perforce 而言,你仍然完全是最新的!这是因为 Perforce 没有检查你的工作目录的状态,它检查的是它的缓存,而它的缓存已过期。

正如我所说,Perforce 并不聪明。此外,Perforce 没有充分清理工作副本中删除的文件。当某个被删除的 DLL 留在项目中并导致构建失败时,这是一个痛苦的问题。由于 Unity 中与 DLL 问题相关的错误消息很糟糕,你可能甚至无法找出是哪个 DLL 导致了问题!处理此问题的标准方法是删除项目并在 Perforce 中执行“force get”(强制获取)。(必须使用“force get”来覆盖 Perforce 的缓存,这阻止 Perforce 理解你已删除工作副本的一部分,又是愚蠢的 Perforce。)现在“force get”会相当快速地完成,Perforce 在这方面很快,但现在你必须将整个项目重新导入 Unity,这可能需要一个小时或更长时间(对于大型项目)。这一切都是因为 Perforce 在文件被删除时没有正确清理其工作目录。

总而言之。Perforce 能很好地解决一些问题。它速度快,能很好地处理二进制文件和大型项目。它允许锁定文件,这可以阻止多人编辑二进制文件。

然而,它也带来了许多问题。Perforce 很老旧,它们的工具复杂、缓慢且有错误。你将不得不处理各种工作流程问题,并且维护使其正常工作的成本会消耗大量时间和资源。关于如何解决 Perforce 问题的答案可能很难找到,虽然它易于入门,但要精通它却极其困难且耗时。

Perforce 提供了大量的控制和灵活性,这很好,但要利用它,你必须处理其命令和 API,这些命令和 API 可能不一致且难以使用。Perforce 命令的输出可能难以解析。

如果你必须使用 Perforce,请查看我们的开源 NodeJS API。我们认为这是 Perforce API 的一个更简单的抽象。如果它不能完全满足你的需求,请在 Github 上贡献

Mercurial (HG)

分布式版本控制是管理代码的一种绝佳方式。无论你是独立开发者还是团队,这都适用。当我刚开始使用分布式版本控制时,我喜欢在通勤火车上累积提交。然后,当晚上到家时,我可以将所有工作推送到我的 NAS 上的主仓库。分布式版本控制在 Real Serious Games 的开发团队中也表现良好,我很快就会详细介绍。

我喜欢 Mercurial,因为它很简单,至少我认为它比 Git 简单。它非常可靠,并且易于设置和使用。

如果你想开始使用 Mercurial,Joel Spolsky 有一个很棒的在线教程。官方的教程也很不错。

如果你深入了解 Mercurial,请务必查看 The Definitive Guide

BitBucket 是 Mercurial 的一个很棒的在线托管解决方案,并且与 Atlassian 的其他工具集成良好。

Git

Git 是另一种分布式版本控制,是 Mercurial 的主要替代品。Git 是最流行的 DVCS,尤其是在开源领域。Git 和 DVCS 的崛起在很大程度上得益于 GitHub 的兴起。

我在 GitHub 上通过我的开源开发使用 Git(个人和在 Real Serious Games)。在大多数方面,它与 Mercurial 非常相似。GitHub 通常使 Git 仓库的管理变得非常容易。然而,Git 实际上相当复杂且灵活。如果你想构建一个高度定制化的开发工作流程,这很有用,尽管我更喜欢 Mercurial,因为我更喜欢一个开箱即用、无需任何设置或定制的版本控制系统。不过,正如我所说,如果你使用 GitHub,那么 Git 就变得相当简单,事实上,如果你使用类似 SourceTree 的工具,那么你很少需要关心你是在处理 Mercurial 还是 Git。

这里有一些能帮助你开始使用 Git 的资源。

Git 还有一个出色的参考手册

GitHub 是一个很棒的托管平台,对公共(开源)仓库是免费的。Bitbucket 也可以用于托管 Git 仓库,但与 GitHub 不同的是,Bitbucket 提供免费的私有仓库。

SourceTree

我认为提及 SourceTree 是值得的。这是来自 Atlassian 的一个工具,可以用作 Mercurial 和 Git 的 UI。它抹平了这些包之间(为数不多的真正)差异,以至于你很少需要关心你实际上使用的是哪种类型的仓库。

不幸的是,在撰写本文时,SourceTree 的最新版本存在大量 bug。我个人坚持使用 1.6.25 版本,直到情况有所改善,你可以通过 Chocolatey 轻松安装此版本

值得关注的软件

这些是我非常感兴趣的一些软件。如果有人有使用这些软件的经验并且愿意分享,请联系我。

Plastic SCM

Plastic SCM 是 VCS(版本控制系统)领域一个相对新进入者,我对此非常关注。他们以游戏和娱乐行业为目标。Plastic SCM 旨在成为传统模型和分布式模型的一种交叉。

Unity 对 Plastic SCM 有内置支持,这是对该软件包的巨大认可,但它是否名副其实?

版本控制的替代方案

如果没有提及版本控制在协作工作中的替代方案,这篇文章就不完整了。

Dropbox

Dropbox 是在简单协作环境中共享工作的绝佳方式。它是与团队共享资产和文档的便捷方式。它是与你的测试者共享构建的绝佳方式。

然而,存在许多潜在问题

  • 不要将其作为数据的首选副本。如果你这样做,你就有可能被队友意外删除你的工作。
  • Dropbox 处理冲突的能力不强,也无法合并对同一文件同时进行的工作。
  • Dropbox 占用大量互联网带宽。在局域网上这没问题,你也可以限制它。但在移动数据连接上这很糟糕。

此外,Dropbox 不跟踪版本,因此你无法恢复旧的修订版(除非你付费购买非常昂贵的 Pro 版本)。如果你发现自己想跟踪版本,那么你确实应该使用专业的版本控制系统,而不是 Dropbox。

永远不要将 Dropbox 与版本控制系统结合使用。过去,我曾尝试将 Mercurial 仓库放在 Dropbox 中,结果仓库损坏了。问题在于 Dropbox 处理冲突的方式。这意味着,如果两个人同时尝试处理同一个仓库,那么该仓库很可能被 Dropbox 的冲突解决机制破坏。如果你想这样工作,你必须非常非常小心,并且很有可能*会以悲剧告终*。即使你是独立开发者,也可能发生这种情况!

Google Drive

我经常使用 Google Drive 进行文档、电子表格、表单和演示文稿的个人和协作工作。对于这类工作来说,它非常棒,尽管我无法想象将其用于共享代码或从事软件项目。有一件非常酷的事情是,你可以创建脚本来自动化和自定义你的 Google Drive 工作流程,这是我唯一一次在存储在 Google Drive 中的代码上工作。它带有一个基本的 IDE/代码编辑器,这使得开发体验非常糟糕,但我不抱怨,能够脚本化 Google Drive 并且这项服务是免费的,这真是太酷了!

Google Drive 也可以以类似 Dropbox 的方式使用,这会带来我上面提到的同样类型的问题。

我们在 Real Serious Games 的使用情况

我们在 Real Serious Games 的需求非常独特。我们的工作节奏快且要求高。在 RSG 获胜的技术和方法往往是最简单、带来的好处最多且麻烦最少的。当事情阻碍我们交付产品的能力时,会发生两件事之一:我们设法解决了,无论如何;否则我们就把它淘汰掉。

我们使用 Mercurial 来管理我们长期的内部代码库,它工作得相当好。

我们使用 Git 和 GitHub 来与开源世界互动。也许有一天,我们将完全过渡到使用 Git 来管理我们所有的代码。

对于我们的 Unity 项目和艺术资产,我们使用 Perforce。这是因为 Perforce 易于向我们技术水平较低的员工解释,并且他们更容易理解。这也是因为 Perforce 通常速度快,并且能很好地处理二进制资产和大型项目。Perforce 支持部分同步项目。Perforce 允许我们锁定二进制文件,这可以阻止多人同时处理它们,从而防止合并问题。我们与 Perforce 确实有许多问题需要解决,但目前为止,它的好处仍然大于它的坏处。

我们已经在我们开源的 Perforce 脚本 API 上投入了一些精力。如果你正在使用 Perforce,这可能也会对你有帮助。

结论

在这篇文章中,我详细讨论了版本控制。为什么它有用。为什么它是开发中必不可少的,尤其是在协作团队中。以及它与游戏开发的关系。我回顾了我经验中的软件软件包,并展示了我们目前在 Real Serious Games 的使用情况。

传统和分布式版本控制模型都有其优缺点。在做出决定之前,你确实需要了解对你和你的团队来说什么最重要。无论你做出什么决定,你都需要处理问题,因为无论你选择哪种版本控制软件,它都会给你带来一些问题。

当然,还有许多未解决的问题。大多数分布式 VCS 对二进制文件和大型项目的支持较差。这仅仅是因为它们是新的,还没有成熟吗?也许吧。也可能是因为分布式模型的性质使得解决这些问题很困难。我不确定。

我只能希望分布式系统最终能够解决这些问题,因为分布式系统非常棒,而且它们确实是未来的方向。然而,这些未解决的问题使游戏开发者的生活变得困难。也许有一位正在阅读本文的读者会接受挑战,并着手开发一个新的开源分布式系统,以完美满足游戏开发者的需求?你会是那个人吗?

资源

历史

  • 2016年10月10日:初始版本
© . All rights reserved.