2. 重置 HEAD 指针
在使用 Git 进行版本控制时,每次提交后 HEAD 和当前的分支指针都指向最后一次提交的提交对象。下一次提交会将此刚提交的提交对象作为下一此提交的父对象。如果你希望丢弃本地提交。你的提交从当前的父提交重新创建一个新的提交,你可以使用 get reset 命令重置 HEAD 指针的位置。
之前我们已经完成了 my_project 的分支合并。最终仓库结构如下:
HEAD
|
.--------.
| master |
`--------`
|
+-------+ +-------+ +-------+ +-------+
|8cb34d1| <-- |5dcccb0| <-- |9d3b213| <-- |11caedf|
+-------+ +-------+ +-------+ +-------+
^ |
| +-------+ <----+
`-------- |8e7f7c7|
+-------+
|
.--------.
| myb1 |
`--------`
如果我们在主分支上再次进行提交则提交对象会放在 11caedf 这个提交对象之后。新创建的提交对象会指向 11caedf 让其作为父对象。如果我们希望丢弃 11caedf 这次提交,那我们可以将 HEAD 指针指向 9d3b213 这个提交对象,然后再次提交则新创建的提交对象会以 9d3b213 作为父对象。这这样 master 分支就丢弃了 11caedf, 此对象成为了悬空对象。此悬空对象在一定时间后会被 Git 的垃圾回收机制回收,从而达到丢弃 11caedf 这次提交的目的。
git reset 命令
作用: 移动当前分支的 HEAD 指针到指定的提交对象。并可以选择是否重置暂存区和工作区。
命令格式
git reset [选项] 提交对象位置
注意:这是一个比较危险的命令,请谨慎使用。
git reset 的常用选项
--mixed--soft--hard--merge--keep--no-refresh-- 路径示例:
1、 使用 git reset --hard 将之前工作区和暂存区的内容都清空,HEAD 指针位置不变,等同于 git restore --staged --worktree .,如:
weimingze@mzstudio:~/my_project$ git log --graph --all --oneline
* 11caedf (HEAD -> master) 将功能1合并到 master分支
|\
| * 8e7f7c7 (myb1) 完成了功能1
* | 9d3b213 完成了功能2
|/
* 5dcccb0 (origin/master) 魏明择在当前项目中修改了 README.md 文件,并添加了 website.txt 文件
* 8cb34d1 魏明择在当前项目中添加了 README.md文件
weimingze@mzstudio:~/my_project$ git status
On branch master
Your branch is ahead of 'origin/master' by 3 commits.
(use "git push" to publish your local commits)
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
modified: website.txt
weimingze@mzstudio:~/my_project$ git reset --hard
HEAD is now at 11caedf 将功能1合并到 master分支
weimingze@mzstudio:~/my_project$ git log --graph --all --oneline
* 11caedf (HEAD -> master) 将功能1合并到 master分支
|\
| * 8e7f7c7 (myb1) 完成了功能1
* | 9d3b213 完成了功能2
|/
* 5dcccb0 (origin/master) 魏明择在当前项目中修改了 README.md 文件,并添加了 website.txt 文件
* 8cb34d1 魏明择在当前项目中添加了 README.md文件
weimingze@mzstudio:~/my_project$ git status
On branch master
Your branch is ahead of 'origin/master' by 3 commits.
(use "git push" to publish your local commits)
nothing to commit, working tree clean
2、 使用 git reset --hard HEAD~1 将 当前指针重置到 9d3b213,如:
weimingze@mzstudio:~/my_project$ git reset --hard HEAD~1
HEAD is now at 9d3b213 完成了功能2
weimingze@mzstudio:~/my_project$ ls
README.md function2.txt website.txt
weimingze@mzstudio:~/my_project$ git log --graph --all --oneline
* 9d3b213 (HEAD -> master) 完成了功能2
| * 8e7f7c7 (myb1) 完成了功能1
|/
* 5dcccb0 (origin/master) 魏明择在当前项目中修改了 README.md 文件,并添加了 website.txt 文件
* 8cb34d1 魏明择在当前项目中添加了 README.md文件
可见当前 HEAD 指针指向了 9d3b213 提交对象。此时使用 git log 命令已经看不到最后一次合并后的节点 11caedf。目前的仓库状态如下所示:
HEAD
|
.--------.
| master |
`--------`
|
+-------+ +-------+ +-------+ +-------+
|8cb34d1| <-- |5dcccb0| <-- |9d3b213| <-- |11caedf|
+-------+ +-------+ +-------+ +-------+
^ |
| +-------+ <----+
`-------- |8e7f7c7|
+-------+
|
.--------.
| myb1 |
`--------`
假如此时在当前分支 master 上创建新的提交 6666666,则此提交对象的父节点则是 9d3b213。如下图所示
HEAD
|
.--------.
+--------------------+ | master |
| | `--------`
V | |
+-------+ +-------+ +-------+ +-------+ | +-------+
|8cb34d1| <-- |5dcccb0| <-- |9d3b213| <-- |11caedf| +- |6666666|
+-------+ +-------+ +-------+ +-------+ +-------+
^ |
| +-------+ <----+
`-------- |8e7f7c7|
+-------+
|
.--------.
| myb1 |
`--------`
如果我们需要将 HEAD 指针再次重定位到之前合并后的节点 11caedf, 则必须使用 git reset 11caedf 命令来实现。因为此时已经无法通过 HEAD 找到它的位置了。
引用日志
在上述示例中,在移动HEAD 指针后,就再也无法通过 git log 等命令看到合并后的提交对象 11caedf,也无法恢复本次提交后的内容。那我们如何查找到我们之前创建过的提交对象的历史记录呢。如果你有这样的需求,那你需要使用 git reflog 命令来查看引用日志了。
引用日志(简称 "reflogs")记录了分支头指针及其它引用在本地仓库中更新的时间点。它记录了仓库中 HEAD 指针的所有移动历史,可以帮助你找回 丢失 的提交、分支或更改。
git reflog 命令
作用: 用于查看和管理引用日志中的记录信息。
命令格式
git reflog [选项] [引用信息]
示例:
查看 git reset --hard HEAD~1 后的引用日志
weimingze@mzstudio:~/my_project$ git reflog
9d3b213 (HEAD -> master) HEAD@{0}: reset: moving to HEAD~1
11caedf HEAD@{1}: commit (merge): 将功能1合并到 master分支
9d3b213 (HEAD -> master) HEAD@{2}: commit (amend): 完成了功能2
2d700a1 HEAD@{3}: commit: 完成了功能1
5dcccb0 (origin/master) HEAD@{4}: checkout: moving from myb1 to master
8e7f7c7 (myb1) HEAD@{5}: commit: 完成了功能1
5dcccb0 (origin/master) HEAD@{6}: checkout: moving from master to myb1
5dcccb0 (origin/master) HEAD@{7}: checkout: moving from myb1 to master
...
上述日志中,第一列是提交对象的 哈希值,如 9d3b213。括号中是分支信息。HEAD@{n} 表示距离当前操作的第n次 HEAD指针的变动。冒号后面是具体的操作信息。
如果我们希望将 HEAD 再次指向 11caedf HEAD@{1}: commit (merge): 将功能1合并到 master分支 这次操作的位置。则我们可以使用 git reset 11caedf 或 git reset HEAD@{1} 来实现此操作。
实验:
使用 git reset 命令任意改动 HEAD 指针的位置,然后通过 git reflog 查看引用日志。最后通过引用日志中的信息,使用 git reset 重新将 HEAD 指针定位到你去到某个位置之前的位置。