上一讲主要是讲了一些 Git 的最基本操作,这一讲来讲几个比较高级,但是也很常用的操作。
1. 版本切换
1.1 准备工作
所谓版本切换在实际应用当中十分常见。现在假设我们正在做一个简单的工程,这是我们的工作目录:
zuoyiping@ZuoYipingPC MINGW64 ~/Desktop/Temp (master)
$ tree
.
|-- README.txt
`-- hello.cpp
0 directories, 2 files
两个文件的内容如下。
1 | //hello.cpp |
1 | This is just a empty README file! |
当前目录的仓库是刚刚被建立的,还没有跟踪文件,所以我们首先做了一些初始化的工作。
1 | zuoyiping@ZuoYipingPC MINGW64 ~/Desktop/Temp (master) |
然后我们在原先的工程上做了一些修改:
- 修改 cpp 文件
- 删除了 README 文件
- 新加了一个文本文件 Hello
1 | zuoyiping@ZuoYipingPC MINGW64 ~/Desktop/Temp (master) |
然后提交更改:
1 | zuoyiping@ZuoYipingPC MINGW64 ~/Desktop/Temp (master) |
现在我们就有两个版本的工程:
1 | zuoyiping@ZuoYipingPC MINGW64 ~/Desktop/Temp (master) |
在多做几个更改,现在就成了这样:
1 | zuoyiping@ZuoYipingPC MINGW64 ~/Desktop/Temp (master) |
有了多个版本,我们现在就可以讲怎么在各个版本之间随意切换了。
1.2 方法1:使用 HEAD
指针
要想切换版本,Git 必须知道当前版本是哪个版本。在Git中,用 HEAD
表示当前版本,也就是最新的提交 aa57e...,上一个版本就是 HEAD^
,上上一个版本就是 HEAD^^
,当然往上 100 个版本写 100 个 ^ 比较容易数不过来,所以写成 HEAD~100
。
使用 reset 命令来修改版本:
1 | git reset --hard <version> |
现在我们正处在第 4 个版本,我们想把它改回到第 2 个版本上,可以这样:
1 | zuoyiping@ZuoYipingPC MINGW64 ~/Desktop/Temp (master) |
显然版本已经被成功的修改为了原先的第 2 个版本,如果再次查看 log:
1 | zuoyiping@ZuoYipingPC MINGW64 ~/Desktop/Temp (master) |
显然我们发现当前的版本已经指向到了第 2 个版本,但同时我们也发现原先的第 3 个和第 4 个版本都不见了。
1.2 方法2:使用 commit ID
上面那种方法仅适合于从当前版本回退到以前的某个版本。但是如果我们想要重新返回到第 4 个版本该怎么办呢?
还记得这个命令吗。
1 | git reset --hard <version> |
这里 <version>
不仅仅可以是 HEAD
,还可以是 commit ID,也就是我们在查看 log 是前面那一大串字符:
1 | zuoyiping@ZuoYipingPC MINGW64 ~/Desktop/Temp (master) |
在填写的时候不需要把整个字符串全部填进去,只要填写前面几位,能保证可以找到目标就行了。
1 | # 回退到初始版本 |
不过我们注意到 git log
只能查看在当前版本之前的记录。我们如何才能查看该版本之后的版本记录号呢?答案是使用命令:
1 | git reflog |
这个命令可以查看我们所有提交过的记录。
1 | # 从下往上依次是版本库的版本记录 |
根据第 1 行,我们可以看出当前的 HEAD
指针移动到了 5f74def。而我们的第四个版本是 aa57e7c。所以:
1 | zuoyiping@ZuoYipingPC MINGW64 ~/Desktop/Temp (master) |
搞定!
2. 远程仓库的使用
远程仓库是指托管在因特网或其他网络中的你的项目的版本库。你可以有好几个远程仓库,通常有些仓库对你只读,有些则可以读写。与他人协作涉及管理远程仓库以及根据需要推送或拉取数据。
管理远程仓库包括了解如何添加远程仓库、移除无效的远程仓库、管理不同的远程分支并定义它们是否被跟踪等等。
2.1 查看远程仓库
在一个工作区目录中,我们可以可以运行 git remote
命令来查看你已经配置的远程仓库服务器。
比如对于我们之前克隆出来的项目 mylibgit
而言,如果运行那么至少应该能看到 origin——这是 Git 给你克隆的仓库服务器的默认名字:
1 | E:\MyGithub\mylibgit (master -> origin) (libgit2@0.27.0) |
你也可以指定选项 -v
,会显示需要读写远程仓库使用的 Git 保存的简写与其对应的 URL。
1 | $ git remote -v |
而对于一个纯粹的本地仓库,那么就不会有显示了。
1 | zuoyiping@ZuoYipingPC MINGW64 ~/Desktop/Temp (master) |
2.2 添加远程仓库
现在如果我建立了一个远程仓库,并且想把我本地的仓库放到远端去。
我需要在工作区目录里运行 git remote add <shortname> <url>
给当前的仓库添加一个新的远程 Git 仓库,同时指定一个可以轻松引用的简写。
现在我要把仓库加进来了,首先复制链接。
1 | zuoyiping@ZuoYipingPC MINGW64 ~/Desktop/Temp (master) |
2.3 关联到远程仓库
有了远程的仓库,我们就会想将自己的项目推送到远程仓库,需要使用push
命令:git push [remote-name][branch-name]
。
比如我们要把当前的 master 分支推送到 Temp
服务器:
1 | zuoyiping@ZuoYipingPC MINGW64 ~/Desktop/Temp (master) |
只有当你有隆服务器的写入权限,并且之前没有人推送过时,这条命令才能生效。
另外注意,当其他人先推送到上游然后你再推送到上游,你的推送就会毫无疑问地被拒绝。 你必须先将他们的工作拉取下来并将其合并进你的工作后才能推送。
比如我刚才运行的那一条命令就是失败的。
1 | zuoyiping@ZuoYipingPC MINGW64 ~/Desktop/Temp (master) |
为啥?因为刚才我新建的那个仓库里初始化的时候,它自动添加了两个 readme 文件。必须先拉取下来才行:
1 | zuoyiping@ZuoYipingPC MINGW64 ~/Desktop/Temp (master) |
咦,怎么又失败了?我上网上查了一下资料,大体的意思是本地的仓库和远端的库没有任何吻合的地方,所以它不允许你拉下来合并。解决方法是加一个 --allow-unrelated-histories
1 | zuoyiping@ZuoYipingPC MINGW64 ~/Desktop/Temp (master) |
现在我们再推送上去就不会遇到任何问题了。
1 | zuoyiping@ZuoYipingPC MINGW64 ~/Desktop/Temp (master) |
2.4 抓取与合并
一种常见的情况是当你和多个人进行合作时,远端仓库此刻的内容和你本地仓库的内容不再匹配。
为了模拟这种情况,我在我测试了远程仓库当中,分别删了一个文件,新增加了一个文件并修改了一个文件。
从远程仓库中获得数据,可以执行:
1 | $ git fetch [remote-name] |
这个命令会访问远程仓库,从中拉取所有你还没有的数据。 执行完成后,你将会拥有那个远程仓库中所有分支的引用,可以随时合并或查看。
必须注意 git fetch
命令会将数据拉取到你的本地仓库 —— 它并不会自动合并或修改你当前的工作。 当准备好时你必须手动将其合并入你的工作。
2.5 查看远程仓库信息
如果想要查看某一个远程仓库的更多信息,可以使用 git remote show [remote-name]
命令:
1 | zuoyiping@ZuoYipingPC MINGW64 ~/Desktop/Temp (master) |
它同样会列出远程仓库的 URL 与跟踪分支的信息。
这些信息非常有用,它告诉你正处于 master 分支,并且如果运行 git pull,就会抓取所有的远程引用,然后将远程 master 分支合并到本地 master 分支。 它也会列出拉取到的所有远程引用。
2.6 远程仓库的移除和重命名
如果想要重命名引用的名字可以运行 git remote rename <oldName> <newName>
去修改一个远程仓库的简写名。
1 | $ git remote rename Test Demo |
如果因为一些原因想要移除一个远程仓库 - 你已经从服务器上搬走了或不再想使用某一个特定的镜像了,又或者某一个贡献者不再贡献了 - 可以使用 git remote rm
:
1 | $ git remote rm Demo |