当前位置:   article > 正文

git head详解_无痛的Git实践笔记(二):时光穿梭之版本回退与切换

git head详解_无痛的Git实践笔记(二):时光穿梭之版本回退与切换

f259862e74b2811e3be8fda8a7da6d5d.png

1 版本回退与切换

之前在实习时因为版本回退问题踩过坑,现在开始填坑,顺便系统了解了解Git的回退机制。
前沿知识:
Git在管理修改时在本地可以分为三个区域:
1. 工作区(working tree)
2. 暂存区(index)
3. 版本库(tree-ish)
其中 工作区就是我们日常编辑代码的区域,git记录工作区的所有修改。
我们使用了 git add <file>就将工作区的修改提交到了 暂存区中。
我们使用了 git commit就将暂存区中的内容全部提交到了 版本库中,此时版本库中增加了一个最新的版本,HEAD指向该版本。 git push将当前版本库中对应分支的最新版本提交到远端。

8cb6f97a8a0544298605a79f9fc359a6.png

step 1. 首先我们在GitHub上创建一个项目Test,用于测试使用,并将该项目clone到本地。

这样我们就相当于是在本地直接获得了一个git管理的项目,并且已经和远端建立好了联系。如果我们直接使用

git init

也是可以在本地创建一个git管理的项目的,只是还没有和远端建立联系。

step 2. 我们尝试做一些commit,我是创建了文件info.txt。我一共做了3次commit,commit的内容可以使用

git log

来查看:

a117bb8463159e30d495642f82c658a3.png

当然,使用

git log --pretty=oneline

也是可以的,可以获得简洁版的commit log:

f5a2b3ec548d5a12bc1cf97cc282ab05.png

可以看出我一共commit了4次:

(1)Initial commit(这一次是在GitHub上创建repo的时候自动提交的)。

(2)add student.

(3)add AnHui.

(4)add age.

前面一大串黄色的字符串是commit id. 我们需要使用commit id来指定回退到哪个版本。

其中:

(1)commit message为Initial commit,此时还没有创建任何文件。

(2)commit message为add student时,info.txt的内容是:

I am a student.

(3)commit message为add AnHui时,info.txt的内容是:

  1. I am a student.
  2. I am from AnHui.

(4)commit message为add age时,info.txt的内容是:

  1. I am a student.
  2. I am from AnHui.
  3. I am 21 years old.

版本记录如下图所示:

d789c7ea1887a91f4a6aed4a777d76fc.png

step 3. 我们当前的版本就是HEAD指向的版本,上一个版本就是HEAD^,上上个版本就是HEAD^^,上100个版本就是HEAD~100。OK,我们现在使用:

git reset --hard HEAD^

来回退到上一个版本:

a6e44abd69b51e64b45fc8cdba91d5ce.png

查看cat info.txt,果然回退成功,最后一次commit的修改(增加了I am 21 years old)被撤销了:

948869a2d0ced9e56d8ab239872bf3be.png

版本记录如下图所示:

58da2980bae4043051986fdbc788eead.png

如果这时我又想回到之前的add age的commit版本也是可以的,前提是你得记得它的commit id。因为这时我们使用git log查看的时候发现add age的commit已经没有了,取而代之的是HEAD指向add AnHui的commit!!

32b33f5922931461c6813c381331b794.png

我在命令行窗口中向上翻,查到add age的commit id,键入命令

git reset --hard f913a5

即可。

注意:commit id不需要全部输入,只需要输入前几个字符即可。

果然又穿梭成功了:

5982ab9ea0f8c9ab040f4b4e1d0e38fd.png

注:如果无法在命令行窗口找到add age的commit id,使用

git reflog

可以查看每一次命令的记录:

06a03377e4cc978441bafab2f60faff0.png

前面黄色字符串就是每次命令操作之后的commit id的前几位。

2 撤销修改

我们接着上面的内容来,我们对info.txt进行修改,添加一行

I love programming.

此时git status

118ebb1be876684d3664531b918f4c5a.png

此时修改已经产生,我们分3种情况讨论如何将刚刚的修改撤销掉。

情况1:未git add

这是最简单的情况,此时修改仅保存在工作区,还没有进入暂存区

使用

git checkout -- info.txt

info.txt在工作区的修改全部撤销到最近的一次git add或者git commit(如果最近没有git add的话)。

果然撤销了修改。

情况2:已经git add,但未git commit

此时修改已经被提交到了暂存区,但是还没有进入版本库中。你可以:

  1. 使用git reset HEAD info.txt先把info.txt在暂存区的修改撤销掉,回到工作区:

f5241841546c54913f236357992c63bc.png

2. 同上,使用git checkout -- info.txt对工作区中的修改撤销。

情况3:已经git commit

此时修改已经从暂存区被提交到了版本库中。这个时候可以使用

git reset --hard HEAD^

来强行回退到上一个版本,此时工作区的内容也回退到之前的版本。

其他彩蛋:

以上3种情况的撤销修改也可以直接使用某些可视化工具来进行。

这里我力荐VS Code,我简单介绍一下其git操作的几个小功能,更多功能欢迎探索:

一、可直接查看工作区和暂存区的修改

  • STAGED CHANGES:暂存区(已add未commit)的修改
  • CHANGES:工作区(未add)的修改

91c4068f0731e60882c834ffa2129d02.png

二、直接查看对应修改文件与原状态diff

d8d4d45803e223a00c1718ceecf78c49.png

三、撤销工作区修改

直接点击Discard Changes即可将文件回复到原始状态:

21dc272ab15ce5c993b61397bdb872bb.png

四、撤销暂存区修改

需要先Unstage Changes,将该文件对应修改的状态由STAGED CHANGES转换为CHANGES,相当于撤销了InstanceSolver.py修改的git add:

083ad97f673fe6de1ef5af986cb668d7.png

后面要想将文件回复到原始状态,操作就和 三、撤销工作区修改 一样了~

五、直接撤销上一次commit

操作如下图所示:

注意这里的undo last commit只是撤销你最近一次commit的所有修改,将这些修改转移到暂存区(即STAGED CHANGES)中

35d7fa29521a1254f8fe11e921e349ae.png

3 命令详解

关于命令git reset

看了上面,我们可以看出,git reset不仅可以回退版本,也可以把暂存区中的修改回退到工作区中。感觉那个命令git reset HEAD info.txt也是很神奇的(Pro Git书中原话The command is a bit strange, but it works.)。

Git官方文档中reset命令的格式为:

  1. git reset [-q] [<tree-ish>] [--] <paths>
  2. git reset (--patch | -p) [<tree-ish>] [--] [<paths>…]
  3. git reset [--soft | --mixed [-N] | --hard | --merge | --keep] [-q] [<commit>]
index就是指 暂存区!而 tree-ish可以理解成就是 版本库了。

第1条命令:

This form resets the index entries for all `<paths>` to their state at `<tree-ish>`. (It does not affect the working tree or the current branch.)

git reset HEAD info.txt就是第1条命令,意思是将暂存区中的info.txt(<path>)回复到与版本库HEAD指向的commit相同的状态。也就是将暂存区中git addinfo.txt给撤销掉了,因为info.txt的这个修改还并没有添加到版本库中,所以版本库中HEAD指向的commit info.txt还是之前的状态。

我们再来说说第3条命令

This form resets the current branch head to `<commit>` and possibly updates the index (resetting it to the tree of `<commit>`) and the working tree depending on `<mode>`. If `<mode>` is omitted, defaults to `--mixed`.

也就是会将:

  • 当前分支的HEAD指向`<commit>`(修改版本库tree-ish),
  • 暂存区是否会重置到`<commit>`取决于参数`<mode>`(可能修改暂存区index),
  • 工作区是否会改变取决于参数`<mode>`(可能修改工作区working tree).

关于参数`<mode>`(仅介绍`soft`和`hard`):

--soft: Does not touch the index file or the working tree at all (but resets the head to `<commit>`, just like all modes do). This leaves all your changed files "Changes to be committed", as `git status` would put it.

仅仅重置HEAD指向`<commit>`,而并不会改变暂存区和工作区的内容。

--hard: Resets the index and working tree. Any changes to tracked files in the working tree since `<commit>`are discarded.

将HEAD指向`<commit>`,会重置暂存区和工作区,`<commit>`之后的改变全部都会丢弃。

4 参考资料

Git - git-reset Documentation​git-scm.com 版本回退​www.liaoxuefeng.com
c4c5760ff16070b7ba2a832b3e9f60d7.png
Git - Undoing Things​git-scm.com Reset Demystified​git-scm.com
17db075c00a218aff339d83943967948.png
Git:git-reset的用法总结_IT老兵的驿站-CSDN博客_git reset 用法​blog.csdn.net
17a12206e9765c530406efac827e21b0.png
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小惠珠哦/article/detail/819217
推荐阅读
相关标签
  

闽ICP备14008679号