- 教程
- 开发工具
【免费下载链接】githug
Git your game on!
导读
Githug 是一个基于 Ruby 的交互式 Git 学习工具,口号是 "Git Your Game On"。它以一系列难度递增的关卡为载体,要求玩家在真实的 Git 仓库环境中执行正确的 git 命令来过关,把枯燥的命令记忆变成动手实战。本文将以项目根目录 README.md 为主线,完整讲解 Githug 的安装运行、四大游戏命令、关卡编写 DSL、关卡测试方法,并结合仓库源码(如 lib/githug/level.rb、lib/githug/cli.rb、lib/githug/game.rb 等)深入剖析其底层实现。读完本文,你不仅能立即上手玩通全部关卡,还能亲手为 Githug 编写并测试一个新关卡。
一、Githug 是什么:以实战为核心的 Git 教学游戏
Githug 的设计初衷是"给你一种学习 Git 的实用方式"。它内置一系列关卡,每个关卡都要求你使用 git 命令达到正确结果——换句话说,它不是考背诵,而是考操作。玩家在游戏目录git_hug中真实地执行git init、git add、git commit等命令,由 Githug 检查仓库状态并判定是否过关。
与 Git 自带的教程不同,Githug 的关卡覆盖了 Git 工作流的方方面面。从源码中可以看到,完整关卡清单定义在 lib/githug/level.rb 的LEVELS数组中,共 50 余关,按学习路径排列:
init, config, add, commit, clone, clone_to_folder, ignore, include, status, number_of_files_committed, rm, rm_cached, stash, rename, restructure, log, tag, push_tags, commit_amend, commit_in_future, reset, reset_soft, checkout_file, remote, remote_url, pull, remote_add, push, diff, blame, branch, checkout, checkout_tag, checkout_tag_over_branch, branch_at, delete_branch, push_branch, merge, fetch, rebase, rebase_onto, repack, cherry-pick, grep, rename_commit, squash, merge_squash, reorder, bisect, stage_lines, find_old_branch, revert, restore, conflict, submodule, contribute每个关卡文件对应levels/目录下的同名.rb文件,例如 levels/add.rb、levels/merge.rb、levels/bisect.rb。从LEVELS的排列顺序可以看出教学节奏:从init(初始化仓库)起步,历经暂存、提交、分支、合并、变基、樱桃拣选、二分定位、解决冲突,直到最后一关contribute(向 Githug 仓库提交贡献)。关卡编号就是数组下标加 1,因此githug reset merge_squash与githug reset 47效果相同(详见 lib/githug/cli.rb 的加载逻辑)。
二、安装与启动
2.1 环境要求(Prerequisites)
Githug 官方声明支持 Linux、OS X 和 Windows。唯一的前提是 Ruby 环境:
- 需要 Ruby 1.8.7 或更高版本(README 原始声明);
- 注意:README 的 FAQ 同时明确指出,当前版本在 Ruby 3.0.0 及以上不受支持,推荐使用 3.0.0 以下版本(优先 2.7.1)。这点在安装前务必确认。
检查 Ruby 版本:
ruby --version如果未安装 Ruby,请按照 Ruby 官方文档的安装指引进行安装(本文不展开外部链接,按官方说明操作即可)。
2.2 通过 gem 安装
安装 Githug 只需一条命令:
gem install githug如果遇到权限报错,可以加sudo重试:
sudo gem install githug该 gem 的元信息定义在 githug.gemspec 中:依赖grit ~> 2.3.0(用于读写 Git 仓库对象)、thor ~> 0.14.6(命令行框架)、rake < 11;开发依赖rspec ~> 2.8.0。
2.3 使用 Docker 运行
README 提到社区提供了一份非官方的 Docker 镜像(位于 Docker Hub,由 @odiraneyya 提供)。仓库根目录的 Dockerfile 展示了这类镜像的构建思路:基于ruby:slim基础镜像,安装man与git(保留 man 手册页以便玩家在关卡中查阅命令帮助),将源码加入镜像后执行gem build与gem install *.gem,随后自动运行echo "y" | githug创建初始进度,并通过~/.bash_profile/~/.bash_logout脚本在会话进入/退出时保存与恢复关卡进度(记录于$DATA_PATH卷中)。如果你希望在容器化的教学/评分环境中使用 Githug,这份 Dockerfile 是一个很好的参考起点。
2.4 启动游戏
安装完成后,先切换到你想存放游戏资产(关卡工作目录)的位置,然后运行:
githug首次运行时,Githug 会提示你创建游戏目录:
No githug directory found, do you wish to create one? [yn]输入y继续,输入n取消并退出。这一流程对应 lib/githug/cli.rb 中的make_directory!实现:先检查当前目录下是否已有git_hug目录(有则提示进入),否则询问用户并创建git_hug目录后进入。也就是说,游戏资产与关卡练习全部存放在git_hug目录内,玩家在该目录中执行 git 命令完成关卡。
三、四大游戏命令
Githug 提供 4 个游戏命令(定义于 lib/githug/cli.rb):
| 命令 | 作用 | 源码要点 |
|---|---|---|
githug play | 默认命令,检查当前关卡的解法是否正确 | 由 Thor 的default_task :play设为默认任务,见 lib/githug/cli.rb |
githug hint | 给出当前关卡提示(如果有) | 调用level.show_hint,见 lib/githug/level.rb |
githug reset | 重置当前关卡,或重置到指定关卡名/路径 | 支持按数字编号、关卡名或文件路径加载 |
githug levels | 列出全部关卡 | 遍历Level.list并输出#N: name格式 |
3.1 play:默认的过关检测
由于play是默认任务,直接运行githug等价于githug play。其执行流程在 lib/githug/game.rb 中:
- 若玩家没有当前关卡(
profile.level为 nil),输出 "Welcome to Githug!" 并自动进入第一关; - 否则加载当前关卡,调用
level.solve执行关卡自带的solution代码块; - 通过则输出绿色 "Congratulations, you have solved the level!" 并推进到下一关(
level_bump); - 失败则输出红色 "Sorry, this solution is not quite right!",累计尝试次数;每失败 3 次(超过 2 次后)会额外提示你可以使用
githug hint和githug reset。
通关后的level_bump会将当前关卡记入已完成列表,计算下一关并调用setup_level初始化新关卡环境(见 lib/githug/profile.rb)。
3.2 hint:按需索要提示
githug hint会从当前关卡的提示中取一条输出。提示有两种形态:单个hint do ... end代码块,或多个提示组成的hints [...]数组。若为数组形式,show_hint会依据玩家进度文件中记录的current_hint_index依次循环展示(见 lib/githug/level.rb);若关卡未定义任何提示,则输出 "No hints available for this level."。
3.3 reset:重置与跳关
githug reset的重置目标由load_level智能解析(lib/githug/cli.rb):
- 不带参数:重置当前关卡(从玩家进度读取);
- 纯数字参数:按关卡编号加载(
githug reset 47); - 已有关卡名:按名字加载(
githug reset merge_squash); - 其他路径:当作关卡文件路径直接加载(
githug reset PATH_TO_YOUR_LEVEL,用于测试自建关卡)。
reset命令最终调用level.setup_level,它会先执行repo.reset(清空git_hug目录中除.、..、.profile.yml之外的所有文件,并重建.gitignore,见 lib/githug/repository.rb),再执行关卡自身的setup代码块,最后打印关卡完整描述。
3.4 levels:查看关卡列表
githug levels会以#编号: 名称的格式逐行输出全部关卡,方便你了解自己当前所处的位置以及后续要挑战的内容。
四、编写关卡:Githug 的关卡 DSL
这是 README 的核心章节,也是 Githug 最值得研究的设计:用一套极简 Ruby DSL 描述一个关卡。关卡文件本质上是一个在Githug::Level实例上下文中instance_eval执行的 Ruby 脚本(见 lib/githug/level.rb)。
4.1 最小关卡示例
README 给出了一个完整示例(对应仓库中的 levels/add.rb):
difficulty 1 description "There is a file in your folder called README, you should add it to your staging area" setup do repo.init FileUtils.touch("README") end solution do return false unless repo.status.files.keys.include?("README") return false if repo.status.files["README"].untracked true end hint do puts "You can type `git` in your shell to get a list of available git commands" end其中difficulty、description和solution是必填项。
4.2 DSL 方法逐个解析
结合 lib/githug/level.rb 的源码,各 DSL 方法的语义如下:
| 方法 | 必填 | 作用 | 源码 |
|---|---|---|---|
difficulty num | 是 | 设置关卡难度星级,展示时以*个数体现 | level.rb#L54-L56 |
description "..." | 是 | 设置关卡文字描述,full_description会连同名称、编号、难度一起打印 | level.rb#L58-L60 |
setup do ... end | 否 | 初始化关卡环境;默认情况下 Githug 会先清空游戏目录再执行本块 | level.rb#L67-L69 |
solution do ... end | 是 | 判定玩家是否过关,返回true/false | level.rb#L62-L65 |
hint do ... end | 否 | 定义单条提示 | level.rb#L71-L73 |
hints [...] | 否 | 定义多条提示(数组),玩家每次githug hint依次获取 | level.rb#L75-L77 |
4.3 repo 对象与 grit gem
关卡内所有repo调用都指向 lib/githug/repository.rb 中的Repository实例。该类的method_missing会把未知方法转发给底层 grit gem 的Grit::Repo对象(repository.rb#L39-L44),因此你可以直接使用大多数 git 相关操作:
repo.init:初始化一个空仓库(若已存在则不做处理,见 repository.rb#L35-L37);repo.add、repo.commit、repo.commit_all、repo.status、repo.commits、repo.config等:均由 grit 提供。
例如 levels/checkout.rb 的 setup 直接使用repo.init+repo.add("README")+repo.commit_all("initial commit")构建仓库;levels/merge_squash.rb 则用repo.git.native :checkout, {"b" => true}, 'long-feature-branch'创建并切换分支。注意:Repository#init是 Githug 自己定义的方法(区别于 grit 的同名方法),其语义是"初始化仓库,已存在则跳过"。
4.4 init_from_level:从预置仓库初始化关卡
对于需要复杂 Git 历史(多分支、多提交、指定 commit hash)的关卡,逐个用代码构造太繁琐。Githug 提供了init_from_level方法:
setup do init_from_level end其实现见 lib/githug/level.rb:把levels/<你的关卡名>/目录中的全部内容复制到游戏目录,再把预置的.githug目录改名为.git,从而把一份完整的 Git 仓库"移植"为当前关卡环境。
README 推荐按以下步骤准备这类关卡素材:
mkdir "yourlevel":在levels/下创建关卡素材目录;cd "yourlevel"并git init;- 执行一些 git 操作构建历史(提交、分支等);
- 重要:把
.git改名为.githug,避免被当作子模块处理; cd "../"并git add "yourlevel",把素材提交进 Githug 仓库。
仓库中的 levels/blame/(含 config.rb)、levels/merge/(含 file1)、levels/stash/(含 lyrics.txt)、levels/bisect/(含 makefile、prog.rb、test.rb)都是这种做法的实际例子。以 levels/blame.rb 为例,它的 setup 只有三行——init_from_level载入预置历史、把分支改名为 master,而 solution 则通过repo.commit("97bdd0cc...").author.name精确定位某次提交的作者,并让玩家输入答案。
4.5 solution 的判定技巧:不止于 true/false
solution代码块可以写任意 Ruby 逻辑,常见做法包括:
- 检查仓库状态:如 levels/add.rb 检查 README 是否已暂存(
repo.status.files["README"].untracked为假); - 检查文件内容:如 levels/stage_lines.rb 用
git diff --no-ext-diff --no-color --staged的输出去匹配特定改动行,验证玩家是否只暂存了第一个 feature 的改动; - 检查提交历史:如 levels/rebase.rb 比较
repo.commits("feature").map(&:message)是否等于期望的提交信息序列; - 交互式提问:如 levels/config.rb 用
request("What is your name?")读取玩家输入并与repo.config["user.name"]比对; - 组合系统命令:如 levels/merge_squash.rb 同时校验提交数量(
repo.commits.size == 3)与合并后的文件内容。
solution代码块在执行时会被Level#solve包裹(level.rb#L98-L102),任何异常都会被吞掉并返回false,保证关卡不会因脚本错误而崩溃。
4.6 多提示写法
除了单个hint,还可以用数组提供多级提示,玩家多次执行githug hint会按顺序获取:
hints [ "You can type `git` in your shell to get a list of available git commands", "Check the man for `git add`"]参考 spec/support/files/test_level.rb,一个关卡甚至可以同时定义hints和hint(hints优先被展示)。
五、测试关卡
5.1 手动测试流程
README 给出了测试自建关卡的最快路径:
- 进入你的 githug 仓库目录;
- 运行
githug reset PATH_TO_YOUR_LEVEL载入并初始化该关卡; - 按关卡要求解决它;
- 运行
githug test PATH_TO_YOUR_LEVEL验证解法。
其中githug test --errors会输出 solution 方法的错误堆栈,方便调试。对应实现见 lib/githug/cli.rb 与 lib/githug/game.rb:test命令把默认的solve(吞异常)替换为test(不吞异常),因此--errors能暴露真实的 Ruby 异常。
5.2 集成测试
如果为新关卡编写集成测试,测试用例位于 spec/githug_spec.rb,并且必须按顺序运行(before(:all)会先rake build、安装 gem、用echo "y" | githug初始化/tmp/git_hug目录,之后每个用例都依赖前一个关卡已通关)。若某关卡不便自动化测试(如rename_commit、squash、reorder、conflict、contribute),README 要求至少添加一个skip_level测试用例(见 spec/githug_spec.rb 中的skip_level辅助方法),就像contribute关卡那样。Rakefile 中默认任务即运行rspec(见 Rakefile)。
六、底层运行机制速览
为了写出高质量的关卡,理解 Githug 的几个核心对象会很有帮助:
- Profile(进度档案):lib/githug/profile.rb 用 YAML 文件
.profile.yml持久化玩家的level、current_attempts、current_hint_index、completed_levels等状态。每个新关卡的 setup 都会清空这些计数。 - Game(游戏循环):lib/githug/game.rb 负责"加载关卡 → 判定解法 → 晋级/提示"的主循环。
- Repository(仓库封装):lib/githug/repository.rb 包装 grit,提供
reset(清场)、init(建仓)、valid?(判断是否已是仓库)以及向 grit 的透明转发。 - UI(交互层):lib/githug/ui.rb 封装输入输出,
ask实现[yn]问答,error/success分别以红色/绿色输出;在 Windows(检测到OS环境变量)下会自动去掉 ANSI 颜色码。 - 扩展兼容层:lib/githug/extensions/grit/ruby1.9.rb 为旧版 Ruby/grit 提供
String#b、PACK_IDX_SIGNATURE等兼容补丁。
七、FAQ:常见问题与解决办法
7.1 答案没有被正确检查
这是 README 明确记录的一个常见问题(项目方表示正在积极修复)。目前的解决办法是:把默认分支名改回master,再重置当前关卡:
git config --global init.defaultBranch master githug reset这样从当前关卡开始,默认分支就是master。这与关卡实现也吻合——你会发现levels/下许多关卡的 setup 都带有system "git branch -m master"一行(如 levels/add.rb),正是为了把仓库默认分支统一改为 master,保证 solution 中的分支判断逻辑稳定。
7.2githug命令无法工作
Githug 当前不支持 Ruby 3.0.0 及以上版本,请使用 3.0.0 以下版本(优先 2.7.1):
使用 rvm:
rvm install 2.7.1 rvm use 2.7.1使用 rbenv:
rbenv install 2.7.1 rbenv global 2.7.1
八、如何参与贡献
README 的贡献流程如下:
- Fork 仓库;
- 在
levels目录中新建一个关卡(方法见上文"编写关卡"); - 把关卡名加入 lib/githug/level.rb 的
LEVELS数组中的合适位置(例如commit关卡应放在add、init关卡之后,与教学顺序一致); - 确保关卡可以正常过关(方法见上文"测试关卡");
- 提交 Pull Request。
仓库中的Todo List也提到两个演进方向:为关卡添加后续内容(如针对某个命令的更多信息)以及增加更多关卡。最后一关 levels/contribute.rb 的设计正是鼓励玩家完成这一贡献流程:它克隆官方仓库到/tmp/githug,检查玩家的user.name/user.email是否已出现在仓库提交记录中——一个别出心裁的"终极关卡"。
结语
Githug 的价值在于把"学 Git"变成"玩 Git":每一个关卡都是一个真实的仓库环境,每一次过关都是对真实工作流的演练。通过本文,你既掌握了它的安装、四大命令与常见问题处理,也深入理解了关卡 DSL 与底层源码实现——接下来要做的,就是运行githug,亲手把LEVELS数组里的每一个关卡打通。
- 教程
- 开发工具
【免费下载链接】githug
Git your game on!
相关推荐
Githug DSL完全指南:轻松编写Git学习关卡的终极教程
Githug DSL完全指南:轻松编写Git学习关卡的终极教程 Githug是一个创新的Git学习工具,通过游戏化的方式让用户在实际操作中掌握Git命令。这个项
教程开发工具Git学习游戏Githug终极指南:如何通过55个关卡掌握Git技能
Git学习游戏Githug终极指南:如何通过55个关卡掌握Git技能 Githug是一款专为Git学习设计的互动游戏,通过55个精心设计的关卡,让你在实践中掌握
教程开发工具Githug关卡开发终极指南:如何创建自定义Git学习关卡
Githug关卡开发终极指南:如何创建自定义Git学习关卡 Githug是一个通过游戏化方式学习Git命令的实用工具,它提供了完整的关卡开发框架,让开发者能够创
教程开发工具
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考