提交和回退
这篇笔记我们详细介绍Git本地仓库的提交、回退和查看历史等操作。为了简单起见,我们这里使用Linux命令行环境进行演示。
配置用户名和邮箱
在进行所有的Git操作之前,我们需要先配置我们(提交者)的用户名和邮箱,否则是无法向仓库提交内容的。下面例子中我们执行配置全局用户名和邮箱为gacfox
和gacfox@gmail.com
,这里我们需要替换为自己的信息。
git config --global user.name gacfox
git config --global user.email gacfox@gmail.com
--global
:该参数指定Git的全局配置,即配置的用户名和邮箱将默认应用于所有仓库。如果不指定该参数,则配置的用户名和邮箱只应用于当前仓库(非全局配置命令需要在一个Git仓库中执行)。
全局配置的用户名和邮箱信息实际保存在用户家目录下的~/.gitconfig
文件中,我们可以查看该文件,也可以在这里直接修改Git全局配置。
创建本地仓库
这里我们新建demo
目录,然后进入该文件夹并执行以下命令。
git init
如下图所示,我们可以看到提示信息,说明本地仓库已经创建成功。
初始化Git仓库后,实际上文件夹内会多出一个.git
目录,这个文件夹是Git用来管理仓库的数据目录,一般来说我们不需要手动修改这个文件夹的内容(自定义hooks等高级操作则可能涉及这些文件的修改)。
向本地仓库提交文件
现在假设我们在本地仓库中创建一个README.md
文件并随便写入一些内容,然后执行以下命令将修改提交到本地仓库中。
git add README.md
git commit -m "添加README文件"
第一条命令将修改添加到Git的暂存区,如果我们修改了多个文件,也可以使用git add --all
添加所有更改到暂存区,实际开发中--all
其实更常用;第二条命令提交了暂存区中的所有更改。
-m
参数:提交(commit)更改时,我们必须为更改指定一个说明信息,使用一个简洁概括的文本说明即可。
执行结果如下图所示。
Git仓库中有工作区、暂存区和版本库的概念。
工作区:我们修改文件的地方就是工作区。
暂存区:git add
命令将工作区的修改添加到暂存区,我们修改仓库中的内容后可以随时将修改添加到暂存区或是从暂存区中移除,git commit
命令则可以将暂存区中的所有变更提交到版本库。如果工作区中的变更没有添加到暂存区,则提交时不会包含这些变更。
版本库:版本库是Git用来保存仓库历史的地方,我们每次提交的更改都会被保存到版本库中,版本库中保存了仓库的完整历史,我们可以随时查看历史,也可以回退到历史中的任意一个版本。
为提交设置标签
在实际开发中,我们可以使用提交的commitID唯一标识一次提交,但commitID是一个hash值,不方便记忆和展示,Git支持给一次提交打标签,方便其他人直接通过标签找到一次提交。下面命令我们为当前提交打标签v1.0
。
git tag v1.0
如果我们需要为某个特定的提交打标签,可以使用类似如下形式。
git tag v1.0 66d4c1c677216b8611e69ffa3e39a063c853bf43
注意:标签名必须是唯一的,两个标签的名字不能相同。
如果想要查看所有标签,可以使用git tag
命令,如果想要删除这个标签,使用git tag -d v0.1
即可。
查看当前工作区状态
我们可以使用git status
命令查看工作区的当前状态。
git status
如果我们的工作区中没有需要提交的内容,可以看到提示“nothing to commit, working tree clean”。
如果我们添加了一个新文件,可以看到提示“nothing added to commit but untracked files present”,提醒我们该文件没有被Git跟踪。
此外,对于其它未被提交的状态,包括修改被追踪的文件、添加到暂存区未提交等,只要是未被提交的更改git status
命令都会给出相应的提示信息。
查看更改的内容
当我们对工作区中的内容做出修改后,我们可以使用git diff
命令查看修改的内容。Git是一个基于行的版本控制系统,所以git diff
命令会逐行显示修改的内容,下面是一个例子。
git diff
图中显示的内容被称为Unix下的通用diff格式,其中a/README.md
是修改前的文件版本,b/README.md
是当前的文件版本,index 5e882f9..ede697f 100644
这一行包含了文件的索引信息和文件的权限标识值,100644
表示文件所有者有文件的读写权限,组用户和其他人有读权限,这些信息我们了解即可,其实不太常用。至于@@ -1,2 +1,2 @@
是修改的行号范围,其中-1,2
表示修改在原文件的第1行开始涉及2行,+1,2
表示修改在目标文件的第1行开始涉及2行,后面的+
和-
就是具体的添加和删除的行变更内容了。
除了直接使用git diff
命令查看当前工作区中的修改,我们也可以基于两次commitID查询特定的某两次提交之间的修改内容,下面是一个例子。
git diff fa8f4c720ac6ca514b0a48e4ea5045948a60ed0e 76d6f64a5b2a2a0c432dcef25a595b391e7c9422
其中,commitID可以在不产生冲突的情况下简写,例如git diff fa8f4 76d6f
。
diff功能其实非常有用,在实际开发中它也是Git工作流中重要的一环,代码审查、Bug追踪和版本回溯都依赖diff功能来显示提交的行变更,不过实际开发中我们通常不会直接在命令行中使用diff,而是使用图形化的工具查看。
丢弃工作区的修改
当你在工作区修改了文件内容后(但尚未添加到暂存区)想还原,可以使用如下命令,它可以丢弃工作区的修改。
git checkout -- README.md
取消添加修改到暂存区
如果想还取消加到暂存区的修改,可以使用如下命令。
git reset HEAD README.md
如图所示,可以看到添加到暂存区的修改被撤回了,但修改仍然存在于工作区。如果想将被修改的文件彻底还原,可以使用前面的git checkout
命令。
查看版本提交日志
git log
命令可以用于查看版本库的提交日志。
git log
图中,commit
后面的数字是一个hash值,被称为commitID,版本库中每次提交都有唯一的ID,这个值很重要,我们可以依据该值在版本库的大量提交中对应找到一次特定的提交,此外提交日志中还包含了作者信息和提交说明。
git log
命令还支持一些参数:
--oneline
:简洁输出,只显示commitID和提交说明。--graph
:显示分支图。--author
:过滤指定作者的提交日志。
git reflog
不同于git log
,它用于查看所有本地引用更新的历史,它不仅包括正常的提交记录,还包含reset
、rebase
等操作,可以用于撤销回退。有关git reflog
将在后文介绍。
回退到上一个版本
git reset
用于回退,它可以撤回一次提交,下面例子命令可以撤回到本次提交的上一个版本。
git reset --soft HEAD~1
git reset
有3种模式,--soft
、--mixed
和--hard
。
--soft
:回退到指定版本,但保留工作区和暂存区的修改,通常来说简单的版本回退我们都使用该选项--mixed
:回退到指定版本,保留工作区的修改,当前暂存区的修改会被丢弃--hard
:回退到指定版本,同时丢弃当前工作区和暂存区的修改,这可能是一个不可恢复的破坏性操作,要谨慎使用
HEAD~1
表示回退到当前版本的上一个版本,HEAD~2
表示回退到当前版本的上两个版本,以此类推。除了这种方式,我们也可以直接使用commitID指定回退的版本。
撤销版本回退
如果你撤回了一次提交,但又想撤销这次撤回,这就需要用到git reflog
来查看本地的索引变更历史了。下图中,我们可以看到reflog中显示我们进行过reset
操作。
此时我们使用git reset
将版本回退到reset
之前,就可以撤销版本回退了。
git reset --hard c7dba87
操作完成后,我们可以在reflog中看到2次reset操作。