7C00.ME/houmu 2015-01-12

Git Game

这两天 Github explore today 邮件都推荐了 git-game 的项目。昨天我就 clone 了它,但是一开始就卡住了,今天又试了下,忽然灵光乍现走下去了,虽然后面的解题过程不顺利,但也总算走到最后一关了。这篇文章用来回忆一下解题过程。

友情提醒:剧透深入

首先,把这个 repo 给 clone 下来:

git clone https://github.com/hgarc014/git-game.git
cd git-game/

看代码之前先看 README 是程序员的行为准则。实际上刚刚 clone 的代码除了一个 LICENSE 文件外,就只有 README 了。README 交代了这个游戏的玩法:You should always check the README.md file for your next clue! 然后给出了第一个线索:”When a programmer is born, what is the first thing he/she learns to say?”

这个问题很容易想到答案 hello world,关键是怎么找到这句话。从游戏设计来看,所有线索应该都可以从代码文件 或 git 的 “元数据” 中找到,而面向最终用户的 git 的“元数据” 主要有 branch、tag 和 commit 日志。 文件就这两个文件,没啥可挖掘的,只能从“元数据”入手了。我昨天一直想和试 branch 和 tag,却没试出,今天才忽然想起来还有 commit,于是乎赶紧:

git log

果不其然,Hello World! 闪亮登场,切换到这次提交来继续游戏:

git checkout 9b9380

看 README,这次的线索是一个谜语,谜底是一个 branch 的名字,结合谜面和所有 branch 的印象(用 git branch -av 查看所有 branch),想到了应该是 bug,果断切换过去:

git checkout -b bug origin/bug

实际上这条命令是我搜索之后才想起来怎么用的。每次 checkout 之后先看一下文件变化(ls -al),这次多了两个文件 cool.cpp 和 remember,难道会难一点? 看看 README 再说,意思是 cool.cpp 因为某个程序员提交的代码引入了一个bug,找出这个程序员是谁。我的做法是扫描了一遍 git log, 结果发现除了 git-game 的作者和新近提交 pull request 外,有一个名字比较特别 LinusTorvalds2014, 这个名字代表这什么恐怕没有程序员会陌生(实际上 Linus Torvalds 不写 C++ 甚至反对 C++),但引起我注意的是之前在看 branch 的时候,这个名字也出现了,所以很有可能就是他。这一步,我的做法比较 silly ,后来才知道作者的本意应该是使用 git blame 这条命令:

git blame cool.cpp

另外如果用 git log 的话,相比较直接使用 git log 从全部日志信息里遍历,这样会更省力一点:

git log cool.cpp

当然最佳的做法还是使用 git blame。下面切换到 LinusTorvalds2014 分支:

git checkout -b LinusTorvalds2014 origin/LinusTorvalds2014

切过来以后,README告诉我们答案从 “ignore” 里面找,意思就是看 .gitignore 文件,于是又是一个谜语,猜的是个数据类型,答案是 tree,其实我一开始想到的是 map,但是切到对应的分支不多,接着试了 array、vector,最后锁定 tree (trees也不对),这有点 “蒙” 的味道了,但是过关了:

git checkout -b tree origin/tree

看 README 的意思是下一个线索通过执行 ./outputclue.sh nextclue_input.cpp 获取,执行,然后获得提示:合并 code4life 分支到当前分支,并且解决冲突:

git merge origin/code4life

合并失败,需要手动解决冲突(nextclue_input.cpp 文件),打开这个文件,冲突部分用 «« —- »» 之类的符号标示了出来,从代码的字面提示可以看出需要保留哪一部分,删除掉不要的部分(注意不要多删也不要少删,否则后面验证通过不了)。冲突解决之后,再次执行 ./outputclue.sh nextclude_input.cpp,得知,下一步是切换到 mouse 分支。(这一步看懂outputclue.sh脚本也不难,但是这样就属于cheat了)切换之前先恢复状态,不然会有警告并且切不过去:

git reset --hard origin/tree

然后切到mouse分支:

git checkout -b mouse origin/mouse

先读 README,提示很明显,线索通过 diff 两个分支的 remember 文件 获得(当然需要回忆起来之前是 bug 分支有 remember 文件):

git diff bug..mouse remember

从输出的结果中可以看出线索是 “Henry”,果断切过去:

git checkout -b Henry origin/Henry

README文件有点长,第一段太长没细看,后半部分的指令很明确,切换到 master 分支,然后合并一个 remote 仓库:

git checkout master
git remote add upstream https://github.com/drami025/git-game.git
git fetch upstream
git merge upstream/master

会有冲突,不过查看 README 的话,还是可以知道本次 git-game 已经 final 了。最终版的 README 回顾了整个游戏过程 practise 了那些 git 技能,忽然发现 “saw issues with naming tags and branches the same name” 和 “removed tags” 这两条没有体现,这应该是由于 Henry 分支的README 前半部分没细看的缘故,相应命令就不补充了。

git-game 还是挺有意思的。tree 分支的 shell 脚本不能用于 msysgit,我提交了个 pull request,等待作者 review 。