Githug
他喵的这是个啥!?难道不是 GitHub 拼错了么,和 Git 什么关系? 和游戏又有什么关系?
其实,他的元身在这里:https://github.com/Gazler/githug ,这个命令行工具被设计来练习你的 Git 技能,它把平常可能遇到的一些场景都实例化,变成一个一个的关卡,一共有 55 个关卡,所以将他形象的形容为 Git 游戏。
既然是游戏,作为一个专业的游戏玩家,通关自然是我的最终目标了!!!
安装游戏
没什么好说的,终端运行如下命令即可,如果碰到了墙,自行搬梯子
![](https://i-blog.csdnimg.cn/blog_migrate/fb1eea87e41b03bbe7c740dbcdbe0450.webp?x-image-process=image/format,png)
游戏开始
直接输入 githug
就可以开始游戏了!开始的时候会询问是否创建文件夹,输入 y
确认创建,以后的操作将都在这个文件夹中进行。
![](https://i-blog.csdnimg.cn/blog_migrate/a34cd79f9b3f0cdc0452fe5e2b9c034f.webp?x-image-process=image/format,png)
第一关(Init)
紧接着,马上进入到了第一个关卡, 按照提示初始化这个这个 githug
文件夹为仓库。完成关卡可以通过调用 githug play
验证操作,成功则会进入下一个关卡
![](https://i-blog.csdnimg.cn/blog_migrate/1dc25451fa70261fbad93855e5c6fda2.webp?x-image-process=image/format,png)
第二关(Config)
设置 Git 用户名和邮箱,为了不影响全局的配置,我设置的是仓库级别的。
![](https://i-blog.csdnimg.cn/blog_migrate/c639c962a4174fa41df604630f661227.webp?x-image-process=image/format,png)
第三关 (Add)
使用 add
命令将 README 文件添加到 staging area.
![](https://i-blog.csdnimg.cn/blog_migrate/51084410511bdcd79d04a617ea7f0baf.webp?x-image-process=image/format,png)
第四关 (Commit)
提交 README 文件,记得每次 commit
使用 -m
参数加上备注是个好习惯
![](https://i-blog.csdnimg.cn/blog_migrate/a6133d77001d11c9fa3cce84432a520e.webp?x-image-process=image/format,png)
第五关(Clone)
克隆一个仓库,默认的文件夹名是远端的仓库名
![](https://i-blog.csdnimg.cn/blog_migrate/22f2dd4eafc8f02b5f22cd45c187a38b.webp?x-image-process=image/format,png)
第六关(Clone to folder)
同样是克隆一个仓库,不同的是可以指定一个文件夹名
![](https://i-blog.csdnimg.cn/blog_migrate/083efcc7c3cb3f916dda232d2f58eb6c.webp?x-image-process=image/format,png)
第七关(Ignore)
忽略所有 .swp
后缀名的文件。这里使用 vim 编辑器打开 .gitignore
,这个文件记录了 git 忽略文件的规则, 不会 vim 的同学可以用自己熟悉的编辑器。
![](https://i-blog.csdnimg.cn/blog_migrate/ca2b2bfab86e4f7e61700e89db9f6f50.webp?x-image-process=image/format,png)
使用正则(glob 模式)匹配所有的 .swp
文件,然后保存并退出
![](https://i-blog.csdnimg.cn/blog_migrate/09749edb60901a3112d10afc92356464.webp?x-image-process=image/format,png)
第八关(Include)
除了 lib.a
文件,其他所有的 .a
后缀名的文件都忽略。和上一关的操作一样,修改 .gitignore
文件
![](https://i-blog.csdnimg.cn/blog_migrate/2ee6acfcf1f28721704afc4217701cda.webp?x-image-process=image/format,png)
其中 #
开头的是注释,用 *.a
匹配所有 .a
文件,!
开头代表不要忽略
![](https://i-blog.csdnimg.cn/blog_migrate/229b275ab96038c1fe75b128d7849468.webp?x-image-process=image/format,png)
第九关(Status)
查看所有处于 untracked
状态的文件。使用 git status
查看当前仓库的状态,可以看到红色部分就是 untracked
状态的文件
![](https://i-blog.csdnimg.cn/blog_migrate/c66fcd05e1ad91dc9efd6e2247acc814.webp?x-image-process=image/format,png)
第十关(Number of files committed)
其实就是查看处于 staged 状态的文件,图中黄色部分就是,所以个数就是2
![](https://i-blog.csdnimg.cn/blog_migrate/2ef7ccf99075131680e59c8a3d17725f.webp?x-image-process=image/format,png)
第十一关(rm)
有一个文件从硬盘中删除了,但是并未从 git 仓库中删除,找到它并从 git 仓库中删除。删除也是修改的一种,提交这个修改就好了
![](https://i-blog.csdnimg.cn/blog_migrate/4cfc3828d71ef6b286fbceef56badc4f.webp?x-image-process=image/format,png)
第十二关(rm cached)
讲一个新文件从 staging area
中删除。按照要求,不应该直接从硬盘上删除这个文件,只是从 Git 中删除而已。加上 --cache
可以是文件只是从 staging area 中移除,不会真正的删除物理文件,如果要连这个物理文件也一起删除,请使用 -f
选项
![](https://i-blog.csdnimg.cn/blog_migrate/1ee263ef0259a20437ca60fb52a4cf05.webp?x-image-process=image/format,png)
第十三关(stash)
临时提交某个文件。这个操作在需要临时保存修改,而又不想提交的时候特别好用!而且 git 中维护了一个栈来保存,所以支持提交多次。如果需要恢复某次提交,使用 git stash apply
即可。
![](https://i-blog.csdnimg.cn/blog_migrate/b299c680c7f264d2de69ed4b659af2ae.webp?x-image-process=image/format,png)
第十四关(Rename)
重命名文件。首先这个文件需要是已经是已追踪状态,才可以使用 git mv
命令,操作完成后自动处于 staging 状态
![](https://i-blog.csdnimg.cn/blog_migrate/cdc846a333bc528cd7cbcfa3a1049dfe.webp?x-image-process=image/format,png)
第十五关(Restructure)
移动所有 .html
文件到 src
文件夹。git mv
后面的第二个参数可以接受文件或目录,如果是目录,则文件会直接放入目录内,可以使用正则(glob模式)匹配所有 .html 文件
![](https://i-blog.csdnimg.cn/blog_migrate/9cd6059b5a642246056afe719c5f69ec.webp?x-image-process=image/format,png)
第十六关(Log)
找到最新的 commit 的 hash 值。使用 git log
查看历史提交记录, 找到最新的 commit 的 hash 值,记录下来用户回答问题
![](https://i-blog.csdnimg.cn/blog_migrate/a24dac888167bacb77e4ba66aa938bc9.webp?x-image-process=image/format,png)
这里是按照倒叙排列的,最新的在最前面,commit
关键字后面跟着的就是这个 commit 的 hash 值
![](https://i-blog.csdnimg.cn/blog_migrate/eaff7c39c678566374d52a7f1e29865f.webp?x-image-process=image/format,png)
第十七关(Tag)
为最新的 commit 打 tag。不加额外参数就是为当前 commit 记录 tag, 当然可以为特定的 commit 打
![](https://i-blog.csdnimg.cn/blog_migrate/5b5c1a9ac3f09d0238b811d138f04c18.webp?x-image-process=image/format,png)
第十八关(Push tags)
将所有本地 tag 都推送到远端。--tags
参数代表将所有的 tags 都推送到远端
![](https://i-blog.csdnimg.cn/blog_migrate/c459c77f23a3d4d059cb0e19f3bd194c.webp?x-image-process=image/format,png)
第十九关(Commit amend)
某个文件在上次提交中遗漏了,在那次提交中补上这个文件。 其实,使用 git commit --amend
会进入编辑界面修改备注信息,我这里直接 :wq
保存并退出
![](https://i-blog.csdnimg.cn/blog_migrate/812d390e0db5d63e003014d1258aa1db.webp?x-image-process=image/format,png)
第二十关(Commit in feature)
为提交指定一个未来的时间。
![](https://i-blog.csdnimg.cn/blog_migrate/ba1da1937d2aa98d799aff3d584a751d.webp?x-image-process=image/format,png)
![](https://i-blog.csdnimg.cn/blog_migrate/3db854f0289dbd1fe6ff283334228675.webp?x-image-process=image/format,png)
第二十一关(Reset)
两个文件都被添加到了 staging area
, 但是只想提交其中一个。使用 git reset
可以用仓库中的版本覆盖 staging area
的版本。
git reset
使用仓库中的版本覆盖staging area
中的,如果working directory
该文件没有其他修改,则staging area
中的修改将应用到working directory
中。反之working directory
中的版本将被保留,丢弃staging area
中的修改。git checkout
则是使用staging area
的中的版本覆盖working directory
。
Paste_Image.png
第二十二关(Reset soft)
撤销上一次提交。
--soft
参数将上一次的修改放入staging area
--mixed
参数将上一次的修改放入working directory
--hard
参数直接将上一次的修改抛弃
第二十二关
第二十三关(Checkout file)
抛弃某一次的修改,使用上次提交的版本。checkout
和 reset
的区别参照第二十一关
![](https://i-blog.csdnimg.cn/blog_migrate/119a2422e6ec332850ef974b06ca71a4.webp?x-image-process=image/format,png)
第二十四关(Remote)
查看远端仓库。其实可以不加-v
参数,加这个参数只是可以将地址也一起输出(没想到下一关就是考察这个参数,平常习惯加这个参数了。。。)
![](https://i-blog.csdnimg.cn/blog_migrate/bbdd18bf2df8b51cde977016ae3f05c7.webp?x-image-process=image/format,png)
第二十五关(remote url)
查看远端仓库的 URL
![](https://i-blog.csdnimg.cn/blog_migrate/c2cf968194a6af5f04b51b59b8512a18.webp?x-image-process=image/format,png)
第二十六关(pull)
拉取远端仓库。
其实可以指定分支,格式如下
git pull origin remote : local
对应的推送的格式如下
git push origin local : remote
需要注意的两个操作的分支顺序是相反的,记忆的方法很简单,拉取是从远端到本地,所以远端在前,而推送是从本地到远端,所以本地在前。
![](https://i-blog.csdnimg.cn/blog_migrate/7d18a3eac2005dec31aa1ebe82fb28da.webp?x-image-process=image/format,png)
第二十七关(Remote add)
添加一个远端仓库
![](https://i-blog.csdnimg.cn/blog_migrate/480b8a6c5e16099e5de75746f14b4c93.webp?x-image-process=image/format,png)
第二十八关(Push)
推送本地修改到远端
![](https://i-blog.csdnimg.cn/blog_migrate/e5e73bdc600e4e17a4555d6ca9f295c9.webp?x-image-process=image/format,png)
第二十九关(Diff)
查看 staging area
和 working directory
中文件的差异。
![](https://i-blog.csdnimg.cn/blog_migrate/afec012fe7ec9cc00c9c2d0a29c852d7.webp?x-image-process=image/format,png)
对应 git diff
的显示结果
![](https://i-blog.csdnimg.cn/blog_migrate/fe532a1e2073a39a31c35ea17da505de.webp?x-image-process=image/format,png)
第三十关(Blame)
查看某个文件的修改人。这个命令简直邪恶,锅终于有人背了!!!
![](https://i-blog.csdnimg.cn/blog_migrate/72045ef2c263fedd855ccb31c8e39c93.webp?x-image-process=image/format,png)
git blame
列出了文件中每行的修改人是谁
![](https://i-blog.csdnimg.cn/blog_migrate/746d21dc5b347c4f30570d3bca317e57.webp?x-image-process=image/format,png)
第三十一关(Branch)
创建一个分支
![](https://i-blog.csdnimg.cn/blog_migrate/d99202e1c6592cf3d6ebcf212951256f.webp?x-image-process=image/format,png)
第三十二关(Checkout)
创建一个分支,并切换过去。其实,git checkout -b my_branch
就是创建一个分支,并切换过去,而且这种方法更方便,平常用的更多
![](https://i-blog.csdnimg.cn/blog_migrate/58a3d92edea21739d5d4141b2347e285.webp?x-image-process=image/format,png)
第三十三关(Checkout tag)
切换到某个特定的 tag
![](https://i-blog.csdnimg.cn/blog_migrate/31554bfd04c7331a98aeeccb1040f3ba.webp?x-image-process=image/format,png)
第三十四关(Checkout tag over branch)
切换到某个特定的分支,但是分支名和标签名重叠了
![](https://i-blog.csdnimg.cn/blog_migrate/75c18011f90a371e34e03ed5d20e5e1b.webp?x-image-process=image/format,png)
第三十五关(branch at)
根据一个特定的提交创建新分支
![](https://i-blog.csdnimg.cn/blog_migrate/164c585c1ffad7e65a56ec8f9c5b4e73.webp?x-image-process=image/format,png)
第三十六关(delete branch)
删除一个分支
![](https://i-blog.csdnimg.cn/blog_migrate/6517acfdc29da12a46b08184a6487eb8.webp?x-image-process=image/format,png)
第三十七关(Push branch)
将分支推送到远端仓库
![](https://i-blog.csdnimg.cn/blog_migrate/f058338c959075604735b1b3907d4701.webp?x-image-process=image/format,png)
第三十八关(merge)
合并分支。为了简化分支模型,可以使用 rebase
代替,后续关卡会遇到。
![](https://i-blog.csdnimg.cn/blog_migrate/e462b4074d34eee23a0ce6c586ba7bbb.webp?x-image-process=image/format,png)
第三十九关(fetch)
获取远端的修改,但是并不合并到当前分支。其实,git pull
就是 git fetch
和 git merge
组成的。
![](https://i-blog.csdnimg.cn/blog_migrate/86af60d16534232e84347572a4a3f315.webp?x-image-process=image/format,png)
第四十关(rebase)
其实不知道怎么翻译 git rebase
这个命令。大概意思是从某个提交分化出两个分支,然后其中一个分支需要将另一个分支的修改合并过来,但是又不想在提交记录上留下两个分支合并的痕迹,只留下一个分支以前后顺序记录两边的修改。
git rebase
一个分支的所有修改在另一个分支上重新应用一遍,所以在提交记录上看,会发现一个分支的所有提交在另一个分支之前或者之后。然后删除另一个被合并的分支,保持分支简洁。
git rebase master feature
表示将 feature
上的修改在 master
上重新应用一遍
![](https://i-blog.csdnimg.cn/blog_migrate/13174632d003d2210c1132ce1c84abc1.webp?x-image-process=image/format,png)
对应第一个 git log --graph -all
,--graph
会用图形化将提交记录显示出来,而--all
会显示所有分支的提交记录
![](https://i-blog.csdnimg.cn/blog_migrate/ef451a8c9dbc76c3e665d3ffd67545ed.webp?x-image-process=image/format,png)
对应第而二个 git log --graph -all
,可以发现只保留了一个分支,看起来简洁了很多。
![](https://i-blog.csdnimg.cn/blog_migrate/c53e1a95edb8a6ec13d8c902f7024100.webp?x-image-process=image/format,png)
在使用此命令的时候,需要非常注意的是,不要 rebase 哪些已经推送到公共库的更新,因为此操作是重新应用修改,所以公共库的更新可能已经被其他协作者所同步,如果再次 rebase 这些修改,将可能zh
第四十一关(repack)
将版本库未打包的松散对象打包
![](https://i-blog.csdnimg.cn/blog_migrate/9ff542d8c89aeffb4efde02efc788afd.webp?x-image-process=image/format,png)
第四十二关(cherry pick)
应用某一个提交的修改。
![](https://i-blog.csdnimg.cn/blog_migrate/93ee99126a1303bae4fd796b300689a9.webp?x-image-process=image/format,png)
找到我们想要的那个提交,记录下它的 hash 值
ca32a6dac7b6f97975edbe19a4296c2ee7682f68
![](https://i-blog.csdnimg.cn/blog_migrate/d94a9148b39b26e4c68d9697f592379a.webp?x-image-process=image/format,png)
第四十三关 (Grep)
git grep
支持各种条件搜索及正则表达式,平时用的不多,但感觉功能强大。
![](https://i-blog.csdnimg.cn/blog_migrate/8b5dc09cd2857b5ae533c9563a716a2e.webp?x-image-process=image/format,png)
对应 git grep TODO
的结果
![](https://i-blog.csdnimg.cn/blog_migrate/baca3179c1f9cf77293aa4244f3bcfb4.webp?x-image-process=image/format,png)
第四十四关(rename commit)
重命名提交。当涉及提交修改时,应该想到 git rebase -i
命令,它接受可以一个参数(提交的哈希值),它将罗列出此提交之后的所有提交,然后可以对个个提交做对应的操作。
![](https://i-blog.csdnimg.cn/blog_migrate/7fbe17d1df3415ab32bb4ae6b5e40ea3.webp?x-image-process=image/format,png)
重命名前的提交记录
![](https://i-blog.csdnimg.cn/blog_migrate/713a261a16d3d5d16e441a65b6284c15.webp?x-image-process=image/format,png)
将需要重命名的提交前的 pick
修改为 reword
![](https://i-blog.csdnimg.cn/blog_migrate/c3a4181429acc255d91ca020a0a0c5db.webp?x-image-process=image/format,png)
修改成新的备注,保存并推出
![](https://i-blog.csdnimg.cn/blog_migrate/1de2be066f6e2de57eeb804cdb4a99ce.webp?x-image-process=image/format,png)
第四十五关(squash)
合并多个提交。
![](https://i-blog.csdnimg.cn/blog_migrate/3fcf648e58c5ab2f46cf3c9a4ebfbacd.webp?x-image-process=image/format,png)
合并前的提交记录。
![](https://i-blog.csdnimg.cn/blog_migrate/d5dc45bd9a593bb599bf979f64ecb5f3.webp?x-image-process=image/format,png)
将需要合并的提交前的 pick
改成 squash
或 s
。squash
代表并入前一个提交,保存并退出。
![](https://i-blog.csdnimg.cn/blog_migrate/4a97af958115bbb5cab58c6c5024da4d.webp?x-image-process=image/format,png)
为新的提交修改备注
![](https://i-blog.csdnimg.cn/blog_migrate/fd84e083c1a37fbac8b2e226e5ad5c85.webp?x-image-process=image/format,png)
第四十六关(merge squash)
将某个分支上的所有修改都应用成一个提交。默认修改都将进入暂存区
![](https://i-blog.csdnimg.cn/blog_migrate/5ed19ad2379e14fa649da1f55294fd0e.webp?x-image-process=image/format,png)
第四十七关
重新排列提交顺序。
![](https://i-blog.csdnimg.cn/blog_migrate/7ba541a986c5598d54581914aef168ea.webp?x-image-process=image/format,png)
排序前,对应第一个 git log
![](https://i-blog.csdnimg.cn/blog_migrate/9b98c8d9e35ee63bdac441e728113cb2.webp?x-image-process=image/format,png)
在编辑界面,将 Second commit
和 Third commit
的顺序调换
![](https://i-blog.csdnimg.cn/blog_migrate/eff71785819521c17c11a37fdb934b47.webp?x-image-process=image/format,png)
排序后,对应第二个 git log
![](https://i-blog.csdnimg.cn/blog_migrate/e4015e74fbd41c2a295fd362da2d3783.webp?x-image-process=image/format,png)
第四十八关
使用 git log
查看所有的提交记录,太长我就不全贴出来了,找到最开始的提交 f608824888b83bbedc1f658be7496ffea467a8fb
![](https://i-blog.csdnimg.cn/blog_migrate/0ee3e96b12f9cdef392ca345d70ffb8e.webp?x-image-process=image/format,png)
git bisect start master f608824888b83
中,master
是有 bug 的节点,f608824888b83
是没有 bug 的节点。
![](https://i-blog.csdnimg.cn/blog_migrate/11c969baefd546eaee27ae01b00db82c.webp?x-image-process=image/format,png)
第四十九关(Stage lines)
其实,提交文件的部分修改这种需求平时还是比较常见的,不过平时都是用 Source Tree 来操作的,但是看到这题之后,好像又开启了一扇大门。
![](https://i-blog.csdnimg.cn/blog_migrate/ab50a348e5cde9794a66b8774eb9ffd2.webp?x-image-process=image/format,png)
![](https://i-blog.csdnimg.cn/blog_migrate/2ecd4f37238ee2edb876e808ccf80ac6.webp?x-image-process=image/format,png)
![](https://i-blog.csdnimg.cn/blog_migrate/fe21d3651caf62536469461dd2e9068e.webp?x-image-process=image/format,png)
第五十关(Find old branch)
git reflog
可以列出所有的操作记录,所以找到之前忘记的信息并不是什么难事
![](https://i-blog.csdnimg.cn/blog_migrate/7dfe50d52e0dc7a602beae166aaf7191.webp?x-image-process=image/format,png)
对应 git reflog
的显示内容
![](https://i-blog.csdnimg.cn/blog_migrate/da8388b8fff63f79a921cd522caabb43.webp?x-image-process=image/format,png)
第五十一关(Revert)
与 reset
不同的是,revert 只会撤销当前的 commit,而之后的 commit 操作的修改还会保留,但是reset
还会将之后的所有 commit 操作的修改全部退回 staging area 或丢弃。
![](https://i-blog.csdnimg.cn/blog_migrate/2c641a329044964c78cfbf912099ec59.webp?x-image-process=image/format,png)
这是执行撤销操作前的记录,对应第一个git log
![](https://i-blog.csdnimg.cn/blog_migrate/cc1b475696b4fe3113d225ca54a568cb.webp?x-image-process=image/format,png)
撤销操作会生成一个新的 commit,保存并退出即可
![](https://i-blog.csdnimg.cn/blog_migrate/5e29e3b22bb908178180829d7cc4cc03.webp?x-image-process=image/format,png)
撤销之后的记录,它不破坏原有的记录,对应第二个 git log
![](https://i-blog.csdnimg.cn/blog_migrate/2d2af9c32b3d8ec319cfb870037fcbd0.webp?x-image-process=image/format,png)
第五十二关(Restore)
根据之前的经验,git reflog
可以查看所有的操作记录,所以只要能找到误操作之前的 commit id,一样能够恢复现场。
![](https://i-blog.csdnimg.cn/blog_migrate/8a9ebc8ccb880c0fe8d4bf5100d16ded.webp?x-image-process=image/format,png)
执行 git reflog
后画面如下,根据操作记录,找到你误操作的之前的 commit id
![](https://i-blog.csdnimg.cn/blog_migrate/a58ee6986686158b5c5f2dbaede7623c.webp?x-image-process=image/format,png)
第五十三关(Conflict)
冲突处理在平常的协同工作中真是再常见不过了,需要注意的是存在冲突的文件是在 working directory 中的,在解决完冲突之后需要添加到 staging area 并提交。
![](https://i-blog.csdnimg.cn/blog_migrate/57f8495ee4f8f025aef9bc446ff89b22.webp?x-image-process=image/format,png)
其实冲突解决完成的图片丢失了,只能口述了。
<<<<<<< HEAD
到 =======
之间的内容代表 master
分支的修改,=======
到 >>>>>> mybranch
之间的内容代表 mybranch
分支的修改,保留 mybranch
分支的修改,删除master
分支的修改即可,当然这些特殊符号所在行也要一并删除。
![](https://i-blog.csdnimg.cn/blog_migrate/f731f1f9367540b4d0f269460d3f4227.webp?x-image-process=image/format,png)
第五十四关(Submodule)
submodule 是一个很方便的将一个仓库分解成多个子模块的命令,特别是项目比较大且依赖其他 Git 项目的时候,比如 Cocos2d-x。虽然好用,但是门槛也相对高点,如果维护好 submodule 还是需要好好研究一下。
![](https://i-blog.csdnimg.cn/blog_migrate/7a158e5826a9747dc567c8f90d63fc74.webp?x-image-process=image/format,png)
第五十五关(Contribute)
其实到这里已经可以算是通关,如果感兴趣的话可以到 GitHub 为这个项目贡献代码。
![](https://i-blog.csdnimg.cn/blog_migrate/301906bb8254844d44755e3742bee454.webp?x-image-process=image/format,png)
结尾
其实这里的所有关卡展示的内容只是 Git 的冰山一角,Git 的魅力远不止这些,还需我们慢慢探索~
如果文章有表述错误,欢迎指正。
最后,感谢这篇文章带我入坑:
http://gold.xitu.io/entry/5684844560b2cd25b7cb41a3
from: http://www.jianshu.com/p/482b32716bbe