Githug 记录

Githug 通关记录,简要写关于涉及到的部分命令的使用。一个适用于 Git 初学者的练习游戏。

写在前面

刚开始接触 Git 推荐先使用Learn Git Branching 可视化学习一下分支,然后可以试一下 Githug。另外还有相似的Git Exercises。虽然我自己玩这几个练习的时候因为并不清楚具体的区别,并不是按这个顺序,都玩过一遍后觉得这可能是一个比较合适的顺序。几个练习的区别是,Learning Git Branching 可视化学习最适合初学者,有命令指引和 solution,Githug 涉及的命令比较广,不过大多比较浅,没有 solution,所以在此记录,Git Exercises 有些关卡的场景比较复杂,难度上较 Githug 难一点,完成后每个关卡有讲解。后面两个游戏都是命令行 base, 可能会涉及一些最基本的命令行操作。目前已有许多 Git 的 GUI 客户端,并且主流编辑器大多也有 Git 插件可以实现图形化操作,不过个人使用 Git 还是更习惯使用命令行,当然在 diff 的时候 GUI 界面还是更方便一些 。公司使用的团队合作控制是 TFS,对于本地的版本控制几乎没有,同时改多个项目的时候很难记录变更,尤其是时间跨度比较长的时候,所以我在本地引入了 Git 作为自己的版本管理控制,也方便记录哪些已提交到团队的 TFS 上面,对于近期刚完成的半年多时长的项目,引入 Git 之后对自己开发的过程追溯就容易了许多。而最近的工作比较多涉及数据库脚本,没有版本控制就非常痛苦。

你可以使用 Gitpod 来运行后面两个命令行的 Git 练习。

Level 1 - Init

A new directory, git_hug, has been created; initialize an empty repository in it.

1
git init

初始化仓库,无论你是使用一个新的仓库,还是在已有的文件系统内建仓库,都是必不可缺的一个命令。

Level 2 - Config

Set up your git name and email, this is important so that your commits can be identified.

1
2
git config --global user.name "name"
git config --global user.email email@example.com

设置 Git 配置,--global 是一个全局配置参数,之后所有的提交都会使用此配置。

Level 3 - Add

There is a file in your folder called README, you should add it to your staging area Note: You start each level with a new repo. Don't look for files from the previous one.

1
2
3
git add README 

git add .

添加文件至暂存区,日常中最常用的命令了,对于一次变更同时涉及多个文件时可以使用 git add .,利用通配符同时提交多个文件,通配符同时也作用于比如提交某个文件夹的全部文件,与 Linux 中的通配符规则是一致的。

原则上一次提交不应该包含多个改动,即小步提交,而暂存后的文件才进行提交,所以一次暂存通常也只包含本次提交中的内容。曾看到过一个比喻,Git 有点像是打游戏断点存档,在哪里断点存档你就可以从那里重新开始。一次提交包含多个改动,当你追溯自己的版本变更时就非常困难。

理解 Git 命令与各个不同区域的关系参见 Git Cheatsheet1

Level 4 - Commit

The README file has been added to your staging area, now commit it.

1
git commit -m “add readme”

提交变更,通常使用 -m 参数在提交时也提交对本次提交的内容的附注。如没有使用此参数,Git 将会使用唤起你的编辑器以便键入提交信息。提交信息推荐参考 Convertional Commits2,以让你的提交信息更通用,更规范,也更易读。

Level 5 - Clone

Clone the repository at https://github.com/Gazler/cloneme.

1
git clone 

Level 6 Clone to folder

Clone the repository at https://github.com/Gazler/cloneme to my_cloned_repo.

1
git clone … my_cloned_repo

Level 7 Ignore

The text editor 'vim' creates files ending in .swp (swap files) for all files that are currently open. We don't want them creeping into the repository. Make this repository ignore those swap files which are ending in .swp.

1
vim .gitignore
1
*.swp

配置 gitignore 文件,对于一些临时文件和不希望提交的文件非常有用,尤其是编辑器/IDE环境会产生大量的配置文件,这时候可能不希望追溯这些文件的变更。在 VS 中的 Git 环境会默认写一个 gitignore 帮助你忽视掉不必要的 VS 产生的文件。

两个 gitignore 的参考:

Level 8 - Include

Notice a few files with the '.a' extension. We want git to ignore all but the 'lib.a' file.

1
vim .gitignore
1
2
*.a
!lib.a

Level 9 - Status

There are some files in this repository, one of the files is untracked, which file is it?

1
git status

Level 10 - Number of files commited

There are some files in this repository, how many of the files will be committed?

1
2
3
git status
git diff --stat
git diff --cached --stat

使用 status 可能是最简单的方式,但文件较多时就不方便了。参考 git count files in the staged index - Stack Overflow5

Level 11 - Rm

A file has been removed from the working tree, however the file was not removed from the repository. Find out what this file was and remove it.

1
git commit -a -m “delete”

Level 12 - Rm cached

A file has accidentally been added to your staging area, find out which file and remove it from the staging area. NOTE Do not remove the file from the file system, only from git.

1
git rm

使用 git status 时会提示该命令的使用。

Level 13 - Stash

You've made some changes and want to work on them later. You should save them, but don't commit them.

1
git stash

Level 14 - Rename

We have a file called oldfile.txt. We want to rename it to newfile.txt and stage this change.

1
git mv oldfile.txt newfile.txt

这和 Linux 中的重命名是一样的,其实 Git 中有很多命令与 Linux 命令相似。

Level 15 - Restructure

You added some files to your repository, but now realize that your project needs to be restructured. Make a new folder named src and using Git move all of the .html files into this folder.

1
2
mkdir src
git mv *.html src/

Level 16 - Log

You will be asked for the hash of most recent commit. You will need to investigate the logs of the repository for this.

1
git log -1

Level 17 - Tag

We have a git repo and we want to tag the current commit with new_tag.

1
git tag new_tag

Level 18 - Push tags

There are tags in the repository that aren't pushed into remote repository. Push them now.

1
git push - -tags

Level 19 - Commit amend

The README file has been committed, but it looks like the file forgotten_file.rb was missing from the commit. Add the file and amend your previous commit to include it.

1
2
git add .
git commit —amend —no-edit

添加 --no-edit 参数不会弹出编辑窗口。

Level 20 - Commit in furture

Commit your changes with the future date (e.g. tomorrow).

1
git commit -m “commit msg” —date “2023-08-01”

Level 21 - Reset

There are two files to be committed. The goal was to add each file as a separate commit, however both were added by accident. Unstage the file to_commit_second.rb using the reset command (don't commit anything).

1
git restore --staged to_commit_second.rb

Level 22 - Reset soft

You committed too soon. Now you want to undo the last commit, while keeping the index.

1
2
git log --oneline
git reset --soft fa51390

Level 23 - Checkout file

A file has been modified, but you don't want to keep the modification. Checkout the config.rb file from the last commit.

1
git checkout — config.rb

Level 24 - Remote

This project has a remote repository. Identify it.

1
git remote

Level 25 - Remote url

The remote repositories have a url associated to them. Please enter the url of remote_location.

1
git remote -v

Level 26 - Pull

You need to pull changes from your origin repository.

1
git pull origin master

Level 27 - Remote add

Add a remote repository called origin with the url https://github.com/githug/githug

1
git remote add origin https://github.com/githug/githug

Level 28 - Push

Your local master branch has diverged from the remote origin/master branch. Rebase your commit onto origin/master and push it to remote.

1
2
git rebase origin/master 
git push

Level 29 - Diff

There have been modifications to the app.rb file since your last commit. Find out which line has changed.

1
git diff -U0

Git diff 的信息并非实际行数,参考 Git diff with line numbers (Git log with line numbers) - Stack Overflow6

Level 30 - Blame

Someone has put a password inside the file config.rb find out who it was.

1
git blame config.rb

Level 31 - Branch

You want to work on a piece of code that has the potential to break things, create the branch test_code.

1
git branch test_code

Level 32 - Checkout

Create and switch to a new branch called my_branch. You will need to create a branch like you did in the previous level.

1
git checkout -b my_branch

Level 33 - Checkout tag

You need to fix a bug in the version 1.2 of your app. Checkout the tag v1.2.

1
git checkout v1.2

Level 34 - Checkout tag over branch

You need to fix a bug in the version 1.2 of your app. Checkout the tag v1.2 (Note: There is also a branch named v1.2).

1
2
git log —tags —online 
git checkout [commit-SHA]

先找到这个 tag 的 SHA 值,如果你直接 checkout v1.2 将会变为 checkout 分支。

Level 35 - Branch at

You forgot to branch at the previous commit and made a commit on top of it. Create branch test_branch at the commit before the last.

1
git branch test_branch HEAD~1

Level 36 - Delete branch

You have created too many branches for your project. There is an old branch in your repo called 'delete_me', you should delete it.

1
git branch -d delete_me

Level 37 - Push branch

You've made some changes to a local branch and want to share it, but aren't yet ready to merge it with the 'master' branch. Push only 'test_branch' to the remote repository

1
git push origin test_branch

Level 38 - Merge

We have a file in the branch 'feature'; Let's merge it to the master branch.

1
git merge feature

Level 39 - Fetch

Looks like a new branch was pushed into our remote repository. Get the changes without merging them with the local repository

1
git fetch

Level 40 - Rebase

We are using a git rebase workflow and the feature branch is ready to go into master. Let's rebase the feature branch onto our master branch.

1
git rebase master feature

Level 41 - Rebase onto

You have created your branch from wrong_branch and already made some commits, and you realise that you needed to create your branch from master. Rebase your commits onto master branch so that you don't have wrong_branch commits.

now: readme-update branch

1
git rebase —onto master wrong_branch readme-update

关于 rebase 的使用,参考Git rebase --onto an overview7

Level 42 - Repack

Optimise how your repository is packaged ensuring that redundant packs are removed.

1
git repack -d

Level 43 - Pick

Your new feature isn't worth the time and you're going to delete it. But it has one commit that fills in README file, and you want this commit to be on the master as well.

1
2
3
4
5
git branch
git switch new-branch
git log —oneline — README.md
git switch master
git cherry-pick [commit-SHA]

Level 44 - Grep

Your project's deadline approaches, you should evaluate how many TODOs are left in your code

1
git grep TODO

Level 45 - Rename commit

Correct the typo in the message of your first (non-root) commit.

1
2
3
git rebase -i HEAD~2
% change `pick` to `reword`
% fix the message then save

Level 46 - Squash

You have committed several times but would like all those changes to be one commit.

1
2
3
4
git rebase -i HEAD~4

% change `pick` to `squash`
% comment other messages

这两个关卡都涉及了 git rebase -i,一个相当有用的命令,可以让你做出非常多的对过去提交的变更,Git Exercise 中有关于这个命令的更复杂的练习。

Level 47 - Merge squash

Merge all commits from the long-feature-branch as a single commit.

1
2
git merge long-feature-branch —squash
git commit -am ""

Level 48 - Reorder

You have committed several times but in the wrong order. Please reorder your commits.

1
git rebase -i HEAD~3
1
2
3
pick 468b4ea First commit
pick b497bf6 Third commit
pick c4ebdaf Second commit

git log 不同,git rebase -i 模式下显示的提交顺序是最近的提交在末端,最初的提交在开始。

Level 49 - Bisect

A bug was introduced somewhere along the way. You know that running ruby prog.rb 5 should output 15. You can also run make test. What are the first 7 chars of the hash of the commit that introduced the bug.

1
2
3
4
5
6
git log —online 
% get the first commit
git bisect start
git bisect bad
git bisect good [SHA]
git bisect run make test

这个命令对于查找哪个版本引入的变更非常有用,尤其是利用测试模块测试哪个版本引入 bug。我常常在公司的项目中要查找哪个版本开始改动,对于有明确提交信息的变更还相对好找,很多提交没有写明版本变更,找历史变更是非常痛苦的事情。

Level 50 - Stage lines

You've made changes within a single file that belong to two different features, but neither of the changes are yet staged. Stage only the changes belonging to the first feature.

1
2
3
git add -p 
e
%remove second line
1
2
+This change belongs to the first feature
+This change belongs to the second feature

这个命令也是一个非常丰富的命令, 可以将未暂存的一次大变更分为几个小变更,前面说到小步提交,但实际开发过程中其实很经常会习惯过去的方式一口气写完,这时候会出现这样的问题,可以通过这个命令来帮助你把一个大的变更拆解成几个小的变更。

Level 51 - Find old branch

You have been working on a branch but got distracted by a major issue and forgot the name of it. Switch back to that branch.

1
git reflog

Level 52 - Revert

You have committed several times but want to undo the middle commit. All commits have been pushed, so you can't change existing history.

1
2
git log —oneline
git revert [commit-SHA]

Level 53 - Restore

You decided to delete your latest commit by running git reset --hard HEAD^. (Not a smart thing to do.) You then change your mind, and want that commit back. Restore the deleted commit.

1
2
git reflog
git reset —hard HEAD@{1}

Level 54 - Conflict

You need to merge mybranch into the current branch (master). But there may be some incorrect changes in mybranch which may cause conflicts. Solve any merge-conflicts you come across and finish the merge.

1
2
git merge mybranch
vim poem.txt

Level 55 - Submodule

You want to include the files from the following repo: https://github.com/jackmaney/githug-include-me into a the folder ./githug-include-me. Do this without manually cloning the repo or copying the files from the repo into this repo.

1
git submodule add https://github.com/jackmaney/githug-include-me ./githug-include-me

参考资料


  1. Git Cheatsheet↩︎

  2. Convertional Commits↩︎

  3. github/gitignore: A collection of useful .gitignore templates↩︎

  4. gitignore.io - Create Useful .gitignore Files For Your Project↩︎

  5. git count files in the staged index - Stack Overflow↩︎

  6. Git diff with line numbers (Git log with line numbers) - Stack Overflow↩︎

  7. Git rebase --onto an overview↩︎