Git 基础知识--stash 存储、reset 回退及恢复

Git 存储

简介

Git 提供了 stash 存储的功能,即当你在工作到一半突然需要切换到另一个分支上,但又不想提交时,可将当前做出的修改通过 git stash 命令存储起来,之后再从其中重新读取之前的状态。

注意事项

若修改的文件没有执行 git add 即未被跟踪,则该文件不会被 git stash 存储,会提示 No local changes to save

git stash

git stash

Saved working directory and index state WIP on master: 4fae394 a

作用:将未完成的修改保存到一个栈上,在任何时候都可以重新应用这些改动。

git stash 其实会帮你做一次提交,只不过不被 git log 记录。

git stash list
$ git stash list
stash@{0}: WIP on master: 4fae394 a

作用:查看当前 Git 存储的栈空间。

git stash apply
$ git stash apply stash@{0}
On branch master
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        new file:   b

作用:重新应用某个分支的修改状态。

git stash pop
$git stash pop [stash@{0}]

On branch master
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        new file:   b

Dropped stash@{1} (748234869014c1bbbea8abcc1c781abfbace25ee)

作用:应用栈上存储的 stash@{0} 改动,并移除它。

git stash drop
$ git stash drop stash@{0}

Dropped stash@{0} (e1aaddefd1f1c2500822a1a8753f3e53445585ff)

作用:移除 Git 栈上存储的 stash@{0} 的改动。

Git 后悔药

Git 后悔药是指在 Git 工作系统中的任意位置的修改都可以进行撤回或回滚操作。

首先来看三大分区的流程图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gqHy4Bxa-1657786039356)(git-media/三大分区的转换关系.png)]

可以看出,Git 能够实现回滚操作的位置主要是三大分区:工作目录暂存区本地版本库

注意:一切撤销回滚的操作都是基于文件被 Git 系统跟踪监听的状态,即执行了 git add 命令。否则会提示:

error: pathspec ‘init.txt’ did not match any file(s) known to git 【没有匹配到任何已知的 git 文件】

工作目录 checkout

针对工作目录的修改撤销,Git 主要提供了以下两种方式:

checkout – [file]

注:这是 Git 的早期命令,在Git @2.26.0 之后便不推荐这么做。后期推荐使用 restore 命令。

语法:

  • [file] :撤销单个文件的修改
  • . :撤销所有文件的修改
$ git status
On branch master
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory) 
  # 使用"git restore …"丢弃工作目录中的更改
        modified:   init.txt

no changes added to commit (use "git add" and/or "git commit -a")

$ git checkout -- init.txt

$ git status
On branch master
nothing to commit, working tree clean

作用:撤销针对当前工作目录的上一次更改

原理:checkout 切换分支会重新覆盖工作目录。

restore [file]

语法:

  • [file] :撤销单个文件的修改
  • . :撤销所有文件的修改
$ git status
On branch master
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory) 
  # 使用"git restore …"丢弃工作目录中的更改
        modified:   init.txt

no changes added to commit (use "git add" and/or "git commit -a")

$ git restore init.txt

$ git status
On branch master
nothing to commit, working tree clean

作用:撤销针对当前工作目录的上一次更改

暂存区 add

Git 提供了几种方式来将文件已跟踪 状态回滚到 未跟踪 状态

已跟踪:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hhb2vTVy-1657786039357)(git-media/Git add.png)]

reset [file]

早期不推荐指令

git reset a.txt/.

作用:将文件撤回到 未跟踪 状态

reset HEAD [file]

早期不推荐指令

git reset HEAD a.txt/.

作用:重置 HEAD 指向的同时将文件撤回到 未跟踪 状态

restore --staged [file]

推荐指令

git restore --staged a.txt/.

作用:将文件撤回到 未跟踪 状态

未跟踪状态:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aWHCRYwW-1657786039358)(git-media/git 撤回 add.png)]

rm -r --cached
$git rm -r --cached [. || fileName]

作用:删除暂存区文件

$ git ls-files -s
100644 d905d9da82c97264ab6f4920e20242e088850ce9 0 a,nd

$ git rm -r --cached .
rm ‘a,nd’

本地库 commit

本地库的回滚操作对应的是 commit 提交的撤销操作

commit 提交的撤回系列操作主要有以下场景:

修改已提交的备注信息
–amend

当你修改了某些文件并提交之后发现 commit message 提交的备注信息写错了,那么可以通过 --amend 参数来修改:

$ git commit -m "init commit"
$ git add .
$ git commit --amend

注意:--amend 参数只针对上一次提交的备注信息更改,不包含对 commit 提交对象本身的撤回

--amend 指令会进入 vim 文本编辑器页面来支持你修改上一次 commit 提交的任何表面信息。

注:--amend 指令会帮你重新提交一次,相当于有两次提交,只不过最后一次会覆盖上一次的提交。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0EgOeupZ-1657786039358)(git-media/git commit --amend.png)]

删除上次提交
reset 三部曲

reset 指令主要用于撤销、删除等重置操作。

注意:删除上次提交后本地和远程仓库的数据都将被删除,故在删除上次提交时,记得备份数据!

语法:

$git reset [--soft | --mixed | --hard | --merge | --keep ] [-q] [ HEAD || commit hash]

作用:实现对工作目录暂存区commit 一系列流程的撤销操作。

说明:

  • HEAD:将 HEAD 指针往前顺移
    • HEAD :删除当前最新的提交
    • HEAD^ / HEAD~:删除上一次提交
    • HEAD^^ / HEAD~2:删除上上次提交
  • <commit hash>直接跳到某次提交。
reset 与 checkout 的区别

一个 Git 系统的指引流程主要有三部分参与:HEAD 分支指向Index 暂存区Working Directory 工作目录

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Dn9lurZG-1657786039359)(git-media/git reset.png)]

reset 与 checkout 的区别就在于:

  • reset 会移动 HEAD 分支的指向,而 checkout 只会移动 HEAD 自身来指向另一个分支。

如图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UnrHExc5-1657786039359)(git-media/Git 分离头指针.png)]

git reset 命令提供了 3 个参数来针对 HEAD 分支指向Index 暂存区Working Directory 工作目录 三部分的撤销操作:

–soft
git reset --soft [HEAD^ | <commit hash>]

作用:撤销 commit 提交,不撤销 git add,不删除工作空间改动代码

本地仓库、暂存区、工作区都不改变。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8c57Bi29-1657786039360)(git-media/git reset.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dw2l9QOU-1657786039360)(git-media/git reset --soft.png)]

–mixed

默认参数:git reset --mixed HEAD^git reset HEAD^ 效果是一样的。

git reset --mixed [HEAD^ | <commit hash>]

作用:撤销 commit 提交,撤销 git add ,不删除工作空间改动代码

修改暂存区的内容 >> 工作区、本地仓库不变

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Y1GkiJqo-1657786039360)(git-media/git reset --mixed.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mf17MIFW-1657786039361)(git-media/git reset --mixed 代码.png)]

–hard <慎用>
git reset --hard [HEAD^ | <commit hash>]

作用:撤销 commit 提交,撤销 git add 状态,删除工作空间改动代码

修改暂存区、工作区的内容,本地仓库不变。

注意:完成这个操作后,就完全恢复到了上一次的commit状态这个操作相当于是完全重置,会删除很多文件,慎用!

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-c9OZKZEg-1657786039361)(git-media/git reset --hard.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vRsnx3sI-1657786039361)(git-media/git reset --hard 代码.png)]

revert HEAD
git revert HEAD <[commit Hash]|''>

作用:放弃指定 commit hash 提交的修改,但是会生成一次新的提交,需要填写新的注释,以前的 git los 历史记录都在。

  • '' :不给 commit hash 则指向最近一次的提交
  • commit hash:指定某次提交,并以此为基础重新生成一次提交。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KTfHkaKU-1657786039361)(git-media/GIt 删除上次提交-revert.png)]

reset 和 revert 的区别
  • reset:将 HEAD 指针指向到指定提交,git log 历史记录中不会出现放弃的提交记录
  • revert:放弃指定 commit hash 提交的修改,但是会生成一次新的提交,需要填写新的注释,以前的 git los 历史记录都在。
checkout
不带路径
  • git checkout [branch]

运行 git checkout [branch] 与运行 git reset --hard [branch] 非常相似,它会更新三者使其看起来像 [branch]

不过有两点重要的区别:

1、首先不同于 reset --hard 指令,checkout 对工作目录是安全的,它会通过检查来确保不会将已更改的文件弄丢。而 reset --hard 则会不做检查就全面地替换所有东西。

2、其次是如何更新 HEAD。

reset 会移动 HEAD 分支的指向【commit 提交】,而 checkout 只会移动 HEAD 自身来指向另一个分支。

​ 例如,假设我们有 master 和 develop 分支,它们分别指向不同的提交;我们现在在 develop 上。 如果我们运行 git reset master,那么 develop 自身现在会和 master 指向同一个提交。而如果我们运行 gitcheckout master 的话,develop 不会移动,HEAD 自身会移动。 现在HEAD 将会指向 master。所以,虽然在这两种情况下我们都移动 HEAD 使其指向了提交 A,但做法_是非常不同的。 reset 会移动 HEAD 分支的指向,而 checkout 则移动 HEAD 自身。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qrLQYqfv-1657786039361)(git-media/git checkout 删除提交.png)]

带路径
  • git checkout commithash

运行 checkout 的另一种方式就是指定一个文件路径,这会像 reset 一样不会移动 HEAD。 它就像是 git reset --hard [branch] file。 这样对工作目录并不安全,它也不会移动 HEAD 将会跳过第 1 步 更新暂存区 和 工作目录

  • git checkout –

区别:相比于 git reset – hard commitHash 跟文件名的形式第一 第二步都没做

Git 恢复

当在使用 Git 工作出现意外丢失了一次提交时,可以通过以下方式来恢复:

场景:假设已经提交了 5 次,需要跳转到 v3 版本的提交。

原理:reset --hard 重置到指定提交,后建立 branch 新分支来指向越过的分支,从而让其恢复工作

过程

1、git log 查看要跳转的提交:

$git log --oneline
1d80c97 (HEAD -> master) v5
646f08d v4
5ad5c4f v3
c23755e v2
ac163ce v1

$git reset --hard 5ad5c4f

硬重置到 v3 提交,提示 HEAD is now at 5ad5c4f v3 代表已经 HEAD 指向已经变更。

现在顶部的两个提交已经丢失了 - 没有分支指向这些提交。 你需要找出最后一次提交的 SHA-1 然后增加一个指向它的分支。

2、git reflog 查看要恢复的分支:

$git reflog

1d80c97 (HEAD -> master) HEAD@{0}: reset: moving to 1d80c97
5ad5c4f HEAD@{1}: reset: moving to 5ad5c4f9866a673305719c6c6a7c896688ba30d1
1d80c97 (HEAD -> master) HEAD@{2}: commit: v5
646f08d HEAD@{3}: commit: v4
5ad5c4f HEAD@{4}: commit (amend): v3
75f473e HEAD@{5}: commit: v2
c23755e HEAD@{6}: commit: v2
ac163ce HEAD@{7}: commit (initial): v1
  • 可以选择硬重置回去,也可以选择新建分支来指向顶部的两个提交

但是硬重置还是在当前分支操作,所以推荐新建分支

方式

reset --hard 恢复

后悔药

git reset --hard 1d80c97  # 在当前分支重置回 v5 提交,但 v3 提交不保证。
branch [name] [hash] 新建分支恢复

版本穿梭(时光机)

git branch recover-branch 1d80c97 # 新建一个分支指向 v5 提交,让其恢复。
  • 1
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值