前言
本篇作为 GMS 中文教程系列的特别篇放出,来和大家聊聊版本管理的问题。
我相信有很多刚开始做独立游戏的人不用版本管理(VCS),因为我自己常常也懒得用。但如果你是认真的想要做出点什么像样的东西,很难想象你能不通过版本管理而完成这一切。比如看看以下这些场景:
- 你想尝试一个新的功能,结果发现把整个游戏搞砸了,这时你是否想要直接回滚到上一个能让游戏正常运行的版本?如果没有这样回滚的功能,也许你根本就不敢尝试有风险性的改动?
- 你和你的团队远程合作(这种情况在独立游戏里很常见),如何共享内容给彼此呢?曾经我合作的一次是双方互相发送邮件附件来传送项目文件……直到项目文件超过了25M(Gmail的附件大小限制)。更不用说多方同时对一个文件进行修改时的冲突管理了。
- 你是否会在多个地点或者设备制作你的游戏,例如家里的台式机以及外出时的笔记本?
- 你是否会为不同的场合交付不同的游戏版本?例如为独立游戏节提交的参赛版需要是一个稳定的版本,而给帮你测试的小伙伴们的是包含最新内容的版本。
- 当帮你测试的小伙伴告诉你bug出现的时候,你要如何迅速知道是哪里的改动导致了这个 bug?
- 当游戏发布以后每次版本更新时,你要告诉玩家此次更新所包含的内容,你如何得到确切的改动列表?
上面所提到的这些情形,都可以通过版本管理来得到很好的解决。所以,今天我会介绍如何用 GitHub 提供的免费 git 仓库以及 GitHub Desktop 客户端来对你的 GameMaker:Studio 游戏项目进行版本管理。当然,其实这个版本管理的过程与 GMS 完全无关,即使你以后用 Unity 或者别的引擎来开发游戏也同样适用。
正如前文的介绍,版本控制会记录项目之下一个或多个文件的内容变化,以便将来查阅特定版本。即便不使用专门的版本控制系统,在游戏的开发过程中,无论是出于协作还是备份的目的,我们也经常会有保存不同版本的需求:许多人习惯复制整个项目来备份不同版本,还会重命名文件标注时间以示区别。这样做看似简单,但问题却不少:一旦混淆了所在的工作目录,弄错了文件损失了数据,就没法简单地实现撤销恢复。
为了解决这些问题,版本控制系统出现了,最早是模仿复制备份操作的本地版本控制系统,其中最流行的一种是 rcs,直到今天它甚至还存在于许多计算机系统之中,它的工作原理基本上是保存并管理文件补丁(patch)。文件补丁是一种特定格式的文本文件,记录了对应文件修订前后的变化。因此,根据每次修订后的补丁,rcs 可以通过不断打补丁,计算出各个版本的文件内容。
本地版本控制系统确实解决了部分问题,但如果遇到需要多人协作的场合就显得不那么适用了。在稍微成规模的项目中,这非常常见,因此,集中版本控制系统(Centralized Version Control Systems,即 CVCS)出现了,CVS、SVN、Perforce 这类系统,会有一个单一的集中管理服务器,用来保存所有文件的修订版本,而协同工作的人会通过客户端链接到服务器上,同步最新文件或者提交更新。
CVCS 一度成为版本管理的标准做法,但文件集中保存在中央服务器上,容易因为单点故障影响整个项目,在协作管理方面也不够灵活方便,于是,有人提出了分布式版本控制系统( Distributed Version Control System,即 DVCS ):在分布式版本控制系统中,每个参与协作的人都保存完整的代码库,而不是仅仅从服务器同步文件快照,此外,分布式版本控制系统允许指定和多个不同的远端代码库进行交互,这样,在同一项目下也可以分别组成不同的工作小组进行协作。整个项目的管理可以根据实际需要指定多层次的工作流,相比集中式的系统,灵活性大大提高。
Git 诞生于 2005 年,是 Linus Torvalds 在进行 Linux 内核开发时开发的一个工具类产品。与CVS、Subversion这类的集中式版本控制工具不同,它采用了分布式版本库的做法,不需要服务器端软件,就可以运作版本控制,使得源代码的发布和交流极其方便。git的速度很快,这对于诸如Linux内核这样的大项目来说自然很重要。git 的主要缺点(如果非要认为是缺点的话)可能在权限管理方面,作为诞生自开源社区的项目,它没有对版本库的浏览修改做任何权限限制,但通过其他工具可以实现有限的权限控制。
本教程介绍的 GitHub 是一个通过 Git 进行版本控制的代码托管服务,使用 Ruby on Rails 编写而成,最早在 Ruby 社区中十分活跃,随着注册用户和托管项目的激增,以及一些重量级的项目也逐渐迁移到 GitHub 上,它事实上已经成为世界上最大的代码托管平台与开源社区。
GitHub 注册
GitHub 是一个通过 Git 进行版本控制的软件源代码托管服务,这个 GMS 系列教程之前的所有项目资源均存放在 GitHub上。
它提供 1G 的免费公开代码仓库,公开代码仓库的意思是任何人都可以看到你的项目文件,如果需要无限量的空间或私有代码仓库,则需要升级到付费账户。与 GitHub 类似,但可以提供免费的私有代码仓库的网站有 GitLab.com 和 Bitbucket.org,所以如果你很介意不希望你的项目公开的话,可以选择这两个地方。
首先你需要注册一个 Github 账号,这个过程相当简单,首先在 github.com 的首页上的注册区填入你想要起的用户名、邮箱和密码,然后点击 Sign up for GitHub 注册即可。点击进去后会让你选择是免费的公开仓库还是付费的私有仓库,默认是免费账户,所以点 Continue 继续下一步就好。然后到了第三步会让你填写一些个人信息,不过这些都是可以跳过的,直接点 Submit 提交就完成了注册。你会看到下面这个欢迎页面:
同时你所填入的邮箱也会收到一封验证邮件,点击邮件内的链接验证你的邮箱有效即可。
建立代码仓库
点击 Start a project(新建项目)来到建立代码仓库的页面,你所要填写的仅仅是你的代码仓库名称(Repository name):
例如我这里新建了一个叫做 GMS_Repository 的仓库,然后点击左下角的 Create repository(新建仓库)就完成了创建过程。这时就来到了你的代码仓库的首页,这里显示了你的git访问地址和一些操作的命令行简介:
这个地址以及你的用户名密码等信息会在使用第三方工具访问 GitHub 时用到。
以上步骤完成后,还需要配置 SSH 公钥。它来为用户提供提交代码的身份认证。这一步需要用到简单的命令行操作,按部就班如下面的指南操作即可。
~/.ssh
目录下,如果是 Windows 系统,则在形如 C:Documents and SettingsAdministrator.ssh
的目录下。
为方便起见,如果没有合适的命令行工具,推荐在前往这里安装 git 的 windows 版本。安装完成后,打开 git bash 会出现一个命令行窗口。
按下列步骤操作:
- 输入命令:
ssh-keygen -t rsa -C "yourgithubaccout@email.com"
,邮箱建议使用 github 注册邮箱。 - 一路回车,提示中会要求是否使用密钥口令,建议留空。
- 生成的密钥会出现在前文所说的路径下,其中 .pub 后缀文件即为公钥。
- 用文本编辑器打开 .pub 文件,复制密钥,粘贴到 github 管理界面的密钥管理页面中(用户头像->setting->SSH and GPG keys->New SSH key),如果使用其他的托管平台,操作方式也差不多,如果是自建 git 服务器,相信你有办法解决这个小问题:D。
- 大功告成~
安装GitHub Desktop
本来这里是打算介绍使用 SourceTree 这个工具的,但后来看了一下它的注册过程需要翻墙,所以本着尽量方便的原则,就用 GitHub 的官方工具 GitHub Desktop 来演示好了。其实一旦熟悉了版本管理的概念后,任何工具都是类似的,或者有人会更喜欢用命令行的方式来操作。
隆重推荐 githug (点击这里来获得它)这个通过命令行来完成的交互小游戏。
在通关同时,你应该也差不多能够掌握使用 git 所需的大部分指令了。
点击上图中代码仓库首页的 Set up in Desktop(设置桌面)就会跳转到GitHub Desktop的下载页面。下载安装过程一路确定就好,在安装成功的欢迎页面会有三个步骤(如下图),分别是登录、配置、仓库,首先在登录页面会需要你用之前注册的 GitHub 账号登录:
在配置页面使用默认的设置继续下一步,在最后的仓库选择页面,如果你之前没有配置过任何 git 仓库的话,应该是看到以下的空白信息,选择 Skip 跳过就好。
最后就来到了GitHub Desktop的主界面:
GitHub Desktop实践
Git 是一个很强大的分布式版本管理系统,但正因为如此强大灵活,以致与我刚从 svn 这样的集中式版本管理切换过来的时候都晕了好一阵。所以不如我们直接通过对工具的使用来熟悉 Git 的各个概念。
一、克隆(Clone)
你应该还记得在 GitHub 注册那一节内容里,我们在 GitHub 网站上创建了一个叫做 GMS_Repository 的仓库,这个仓库是存在于网站上的,叫做远程仓库(Remote Repository),我们要做的第一件事是将这个远程仓库克隆到本地,有了 GitHub Desktop 的支持,这个操作非常简单:
在点击左上角的+号并选择 Clone 后,它会列出你在 GitHub 网站上已有的仓库,选择我的仓库 GMS_Repository 并确定后,再选择一个本地的目录,就会将远程仓库克隆到本地。
因为我们这时仓库里没有任何内容,所以只是会克隆到一个空的本地目录,但假设我们的游戏开发到一半的时候,团队增加了一个新的成员。那么此时他在克隆项目仓库时,将会得到所有远程仓库中已有的游戏内容。
而那个我们将远程仓库克隆到的本地目录,在上面的动图演示中,就是我桌面上的“GMSFolder”目录,被称为工作目录。我们在本地创建和修改游戏项目,是在这个目录中进行的。
二、本地改动(Local Changes)
现在,在 GitHub Desktop 显示的本地仓库下面,还没有任何改动,这个页面是这样的:
接下来我们用 GMS 来在这个目录中新建一个项目,我把这个项目的名字叫做 GitHubSample,建立后保存一下,再回到 GitHub Desktop 工具,稍等一下工具的刷新,就会看到所有 GMS 新建的项目文件都已经被显示在了改动列表当中:
上图中那些打勾的文件即为 git 所检查出来发生改动的文件,而右边绿色的+号表示这些文件是新加入的文件。
三、提交改动(Commit)
在上图的的改动列表下面就是提交改动的地方,分别是所要提交改动的概要和描述,其中改动概要是必填项,填好以后就可以提交你的改动了。
这里所谓的“提交改动”是指让本地的git版本管理系统能够记录你的版本信息。举例说,假如现在我去这个项目的本地目录 GitHubSample。gmx 里将 GMS 所生成的项目文件全部删除掉,我依然可以在 GitHub Desktop 中通过 Discard changes(撤销改动)命令来把这些文件恢复回来,这就说明了本地的git仓库中保留了这些文件的信息。
但如果我们把本地的git仓库删除掉,那么这些文件的版本信息就丢失了,因此我们需要把本地的版本改动推送到GitHub的远程仓库中。
四、推送改动(Push)
推送改动的意思是指将本地已经记录下来的版本改动(对我们来说是新建了一个GMS项目),也同样的应用到你在GitHub的远程仓库(也就是说GitHub也保存一份你新建的这些项目文件)。
推送的操作在GitHub Desktop中叫做Publish,我们将GitHub Desktop页面切换至History栏,左边这里会显示之前提交的本地改动:
点击右上角的Publish按钮,即开始了将推送的操作,这一步根据网络状况会持续数秒左右,等到那个转动的图片停止下来的时候即完成推送。这时候我们再登录GitHub网站查看,就会看到改动已经在远程仓库里了:
那么在这个时候,即使你删除掉本地仓库或者是你换了另一台电脑,你都可以通过再次克隆(Clone)这个远程仓库到本地来重新获取项目文件。
五、拉取改动(Pull)
如果这是你的个人项目,那么你的工作流程应该是这样:对每一个新添的游戏内容或者功能,首先在本地修改实现,然后提交改动到本地仓库,最后推送改动到远程仓库。但如果是多人的远程合作,那么每个人都会将自己的改动推送到远程仓库,如果你想要获取别人的改动(你应该总是尽可能的及时获取其他人的改动,以避免修改冲突),这时你需要去做一个拉取(Pull)的操作。
这里我们通过直接在GitHub网站上对远程仓库操作来演示。先登录GitHub,进入你的仓库后,可以通过网页直接进行文件的添加、修改或删除等操作。我们以添加文件为例:
红色框那里的按钮可以在当前目录新建一个文件,点击后进入文本编辑页面:
这里我新建了一个Test.txt文件,并随便填入了一些测试文本。在这个页面的下方点击绿色的Commit new file(提交新文件)按钮即可完成提交。完成后,就可以在仓库的首页看到这个新加的文件了。
然后我们回到本地的GitHub Desktop客户端,在这里Pull操作是通过一个标签为Sync的按钮完成(这个Sync按钮和之前提交改动时的Publish按钮其实是同一个,根据当前仓库状态的不同而显示不同内容):
数秒后等待操作完成,即可看到在改动列表里显示了我们之前在GitHub网页上提交的新文件:
同时在文件目录中也可以发现这个新的 Test.txt 已经更新至本地了。
六、合并改动(Merge)
在远程合作时,多方常常需要同时对项目进行修改。当相互之间改动的文件没有重叠时,这些改动的合并是非常简单的。而如果两方同时修改了一个文件,情况就会稍微复杂一些,因为这需要你去手动解决双方的改动冲突(Resolve conflicts)。这里我们来演示一下这样的情形。
我们首先来在本地进行一些改动:
- 修改Test.txt
在之前文本的下方再加入三行文本:
This is line 1. This is line 2. This is line 3.
- 新建一个FileA.txt
完成后 GitHub Desktop 会自动检测到这两处改动:
注意左边红色标注的这里表示这两个文件的改动,一个是添加的新文件,一个是修改文件内容。上方红色标注这里是每当 GitHub Desktop 检测到本地改动时,Change 标签上会显示一个小圆点。
接下来我们按照之前说过的步骤,给这个改动的概要填写为“本地的第一次改动”,然后将改动提交到本地。
此时,我们先不要将改动推送至远程仓库,而是在 GitHub 网站上进行另一项改动来模拟多人合作时的情形:
- 修改Test.txt
在之前文本的下方再加入四行文本:This is line 1. This is not line 2. This is line 3. This is line 4.
这里我们特意将远程的修改与本地修改的内容不同。
在GitHub上修改文件的操作是先点击Test.txt文件,进入到这个页面后点击右上的编辑按钮:
将新的内容粘贴之后点击下方的绿色按钮将改动提交至远程仓库。
此时本地和远程仓库的改动列表就存在了差异,这是本地的历史记录:
这个是远程的改动记录:
这个时候,假设我作为进行了本地改动的人,想要将我的改动提交到远程仓库,我会去做推送的操作,于是去点击那个Sync按钮,结果就会遇到同步冲突的提示:
当你确认后,此时的改动列表里会显示Test.txt这个文件存在冲突
于是接下来需要我们去手动如果解决冲突的内容,点击右键选择打开文件或者直接在目录中打开Test.txt文件均可。其中:
<<<<<<< HEAD This is line 2. This is line 3. =======
这部分是显示的本地的改动,而下面这一半显示的是远程的改动:
======= This is not line 2. This is line 3. This is line 4. >>>>>>> origin/master
值得注意的是,虽然版本管理能帮我们很大的忙,甚至有的版本管理工具能够一定程度的自动解决冲突。但最好的避免冲突的办法还是尽量在人员划分上清晰设置每个人的工作内容,在项目结构上不要将不相关的内容放置在同一处地方。原因是:
- 只有文本文件(代码文件)能够进行冲突合并,而对于图片、二进制数据文件等,就只能二选一选择继续使用本地的改动或者远程的改动了。
- 就算是自动解决冲突的方案,本质上也只是通过文本的匹配来识别双方修改中共同的部分(例如上面那个改动例子里的This is line 3.)、一方新增的部分(如This is line 4.)等基本情形。而如果双方的改动涉及复杂的逻辑,这个过程通常就只能手动进行,这需要对双方的代码逻辑都十分清楚才能完成。
对于我们示例中的情况,我们只需用文本编辑器打开Test.txt后,修改成以下内容即可:
This is line 1. This is line 2. This is line 3. This is line 4.
然后在GitHub Desktop中提交这个改动后再次推送,这次就应该能够成功进行了。这时再到GitHub网站上去查看远程仓库,就能够看到“本地的第一次改动”和刚才解决冲突的改动都已经存在了:
附录
以上介绍这些内容能够让你初步使用 git 进行版本管理了,但是,如果希望深入了解更全面的内容,还远远不够。
这里再提供一些入门资料供大家进一步参考:
好详细。。。
推荐一篇简易的
http://www.bootcss.com/p/git-guide/
一直用小乌龟来着
github客户端打开不知道为啥是白的…………
慢慢学会使用虽然可能会更花费时间,但这些学习的时间对以后对自己都是有好处的
感谢分享~青铜良心作者。
多次学git未过,还在用svn,感觉也足够了。
github的提交速度怎么样 之前一直用smartsvn 服务器搭在国外 国内提交速度简直心塞
@SuleyWu:感觉github还行,国内用coding.net也可以
职业码农,重度使用Git和GitHub三年,帮作者补充一下:
1. Git的老爹是Open Software运动的先锋之一,著名的“大教堂与集市”理论为Open Software提供了社区驱动的发展模式,在这种模式下,每个人都是代码版本库的服务端和客户端,大家可以互相拉取(pull)各自的代码分支(branch),这样可以集思广益,也可以促进原项目的不同方向的衍生版的多样化,每个人的开发和代码版本管理都是独立的,可以在需要或方便的时候进行互相合并(merge)。
2. Git本身确实没有认证和权限管理方面的功能,可以说是一丁点儿都没有,但是并不是说Git就完全不适用于认证和权限相关场景,只是思想完全不同。Git通常是使用HTTP(S)或SSH协议作为传输协议的,认证机制完全可以通过配置SSH和HTTP(S)来实现,权限机制完全可以通过配置linux文件系统权限来完成,这样更加灵活和可靠。
3. GitHub提供了很多有助于高效开源开发的功能,通常开发的过程是:fork源项目(对于你来说就是上游项目(upstream))到自己的GitHub项目库(repository)中--》将此项目从自己的GitHub上clone到本地--》进行开发、提交和推送(push)--》向源项目发送pull request--》源项目的维护者收到请求,审核你的代码,没问题的话直接pull你的代码到本地,并合并(merge)到源项目上,再push到源项目的GitHub项目库中。
然后给新手几条忠告,希望能有所帮助:
1. 初学不要使用图形化Git工具,使用命令行更加快捷,而且有助于理解Git工作方式,从而找到科学的、适合自己的Git使用方式;
2. 建议提交的时候使用gitk或gitx等工具(不推荐git diff是因为效率差)好好看一下自己改动的每一行,因为很可能自己会无意提交了本不想提交的修改;另外避免使用git commit的-m参数也是出于同样的原因;
3. 永远不要使用git reset --hard和git push --force,会被队友乱刀砍死;
4. 勤提交(commit),控制好提交修改代码的力度,最佳的方案是每写或改完一个最小功能单元就提交一次,不要厌烦撰写提交说明,因为这正是版本控制系统的价值所在;
5. 勤push和pull,减少代码冲突(不同人修改同一文件同一行的提交)的几率,如果积攒了一周的提交(commit)再pull和push就会解代码冲突解到死;
6. 养成在开始开发前创建分支(branch)的习惯,特别是在尝试一种不确定的技术方案的时候,如果测试可用就可以合并到主要的分支上,测试不可行就可以直接删掉开发分支;这样可以避免代码版本回滚;
7. 项目开发到每一个里程碑,最好打一个标签(tag),这样有助于使用CI自动化构建(build),也有助于更加清晰可靠地部署程序;通常都是使用版本号来命名标签。
通篇真的没几个字提到 gms 啊..
目前就我个人理解:
(1) gms 官网所提到的所有 source control 设定都没用或不存在
(2) gms 内部使用 gmx 文字 xml 档案管理专案, 因此可以直接在专案根目录下 git init 不需要特殊设定 (如 Unity 需要设定使用 .meta 档)
想请教是否正确?
@caroparo:是的,其实和gms本身没有关系:)也不需要额外设定什么
非常感谢您的分享!
对我这种非技术岗位的人来说真的是太实用了,并且非常有兴趣继续学习下去。
太有用了!一直觉得git好难入门……