git stash 的一次惊心动魄的误删操作
git stash 的一次惊心动魄的误删操作
简介:行走在互联网最低端的小熊
问题--源起:
小熊和所有混迹在互联网中的开发一样,公司里面用git来管理项目,由于可能经常有几个问题要开发,要频繁在多分支中切换,但是经常会遇到以下情况:
小熊当前正在分支A上干活,突然有一个紧急任务要去分支B上操作,但是由于分支A的活还没有做完,小熊又不想做一次无畏的提交,所以小熊就将分支A上修该的文件使用git stash save 'message' 保存起来,再切换到分支B去处理紧急任务HINT:要切换分支,必去当前的分支没有改动的文件,否者可能需要处理冲突
刚开始,小熊使用git stash 命令用的不亦乐乎,由于以前都是用git commit 去提交之后在切换分支,之后且会有又取消这次的提交,操作麻烦;现在使用git stash完全可以满足小熊的需求,并且操作简单。
git stash 使用教程
git stash用于将当前工作区的修改暂存起来,就像堆栈一样,可以随时将某一次缓存的修改再重新应用到当前工作区。一旦用好了这个命令,会极大提高工作效率。
举例说明:
1、准备工作,首先初始化一个git仓
随便建立一个目录,进去,然后使用 :
$: git init .
添加一个文件:
$: touch hello
$: git add .
$: git commit -m "first add"
2、暂存当前修改内容(git stash)
假设我们在写一个C函数,如下:
void func1(void) {
printf("this is func1");
}
$:~/code/linux/git$ vim hello.c
$:~/code/linux/git$ git diff
diff --git a/hello.c b/hello.c
index e69de29..bdc92a5 100644
--- a/hello.c
+++ b/hello.c
@@ -0,0 +1,2 @@
+void func1(void) {printf("this is func1");}
+void main(void) {return func1();}
调试OK,发现func1功能OK,但是应该优化一下,可能效率更高,这个时候怎么办?
直接改func1的话,如果发现修改不合适,想回退的话很麻烦,这个时候可以用git stash将将修改暂存起来。
$: ~/code/linux/git$ git stash
Saved working directory and index state WIP on master: 452b08d rename hello as hello.c
HEAD is now at 452b08d rename hello as hello.c
$:~/code/linux/git$ git status
On branch master
nothing to commit, working directory clean
3、弹出修改内容(git stash pop)
这个时候你重新编写func1, 发现效果不好,后悔了,于是可以用git stash pop命令,弹出刚才的内容(注意先用git checkout . 清空工作区)
$:~/code/linux/git$ vim hello.c
$:~/code/linux/git$ git diff
diff --git a/hello.c b/hello.c
index e69de29..9c5bff3 100644
--- a/hello.c
+++ b/hello.c
@@ -0,0 +1 @@
+some bad chenges....
$:~/code/linux/git$ git checkout .
$:~/code/linux/git$ git stash pop
On branch master
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: hello.c
no changes added to commit (use "git add" and/or "git commit -a")
Dropped refs/stash@{0} (208ca2e2c0c455da554986a6770a74ad0de5b1e0)
$:~/code/linux/git$ git diff
diff --git a/hello.c b/hello.c
index e69de29..bdc92a5 100644
--- a/hello.c
+++ b/hello.c
@@ -0,0 +1,2 @@
+void func1(void) {printf("this is func1");}
+void main(void) {return func1();}
注意,git stash pop 弹出成功后,暂存列表里面就没有了,如果当前工作区不干净,弹出时有冲突,则暂存列表会继续保留修改。
4、可以保存多个修改
假设你在实现一个功能,有好几种算法可以实现,你想逐个尝试看效果。
现在你在func1中实现了一种方法,准备尝试写func2,用另一种方法。
那么可以将func1的修改入栈,去写fun2,等fun2写好后,你又想试试func3,那么没关系,可以用同样的方法保存func2的修改:
$:~/code/linux/git$ git diff
diff --git a/hello.c b/hello.c
index e69de29..bdc92a5 100644
--- a/hello.c
+++ b/hello.c
@@ -0,0 +1,2 @@
+void func1(void) {printf("this is func1");}
+void main(void) {return func1();}
$:~/code/linux/git$ git stash
Saved working directory and index state WIP on master: 452b08d rename hello as hello.c
HEAD is now at 452b08d rename hello as hello.c
$:~/code/linux/git$ git status
On branch master
nothing to commit, working directory clean
$:~/code/linux/git$ vim hello.c
$:~/code/linux/git$ git diff
diff --git a/hello.c b/hello.c
index e69de29..7fd0a13 100644
--- a/hello.c
+++ b/hello.c
@@ -0,0 +1,2 @@
+void func2(void) {printf("this is func2");}
+void main(void) {return func2();}
$:~/code/linux/git$ git stash
Saved working directory and index state WIP on master: 452b08d rename hello as hello.c
HEAD is now at 452b08d rename hello as hello.c
$:~/code/linux/git$ git status
On branch master
nothing to commit, working directory clean
5、查看保存的内容列表(git stash list)
现在我们保存了两个修改,一个func1,一个func2,可以通过git stash list去查看保存内容列表:
$:~/code/linux/git$ git stash list
stash@{0}: WIP on master: 452b08d rename hello as hello.c
stash@{1}: WIP on master: 452b08d rename hello as hello.c
可以清楚的看到这两次修改,stash@{0}和stash@{1}, 那么哪个对应func1,哪个对应func2的修改呢?
这时我们需要使用git stash show stash@{X}命令来查看,其中‘X’表示列表号。
$:~/code/linux/git$ git show stash@{0}
commit 72e6a391bcad186ab24676aa1db8d5831c99cec9
Merge: 452b08d 6c95c30
Author: hiekay
Date: Sat Mar 12 19:56:18 2016 +0800
WIP on master: 452b08d rename hello as hello.c
diff --cc hello.c
index e69de29,e69de29..7fd0a13
--- a/hello.c
+++ b/hello.c
@@@ -1,0 -1,0 +1,2 @@@
++void func2(void) {printf("this is func2");}
++void main(void) {return func2();}
$:~/code/linux/git$ git show stash@{1}
commit 7fcca4b66640c51ca76e637df03264b7c41885be
Merge: 452b08d 1c37881
Author: hiekay
Date: Sat Mar 12 19:54:35 2016 +0800
WIP on master: 452b08d rename hello as hello.c
diff --cc hello.c
index e69de29,e69de29..bdc92a5
--- a/hello.c
+++ b/hello.c
@@@ -1,0 -1,0 +1,2 @@@
++void func1(void) {printf("this is func1");}
++void main(void) {return func1();}
发现stash@{0}对应func2的修改, stash@{1}对应func1的修改,原来新入栈的修改,其代号为0,循环命名。
6、应用任意一次修改到当前目录(git apply stash@{x})
如果现在又想回到func1的修改,怎么办呢?在工作区干净的情况下,要使用git stash apply stash@{1}。
注意这时不能使用git stash pop, 它将最栈顶,即stash@{0}的修改弹出来,而func1现在已经是stash@{1}了。
$:~/code/linux/git$ git stash apply stash@{1}
On branch master
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: hello.c
no changes added to commit (use "git add" and/or "git commit -a")
$:~/code/linux/git$ git diff
diff --git a/hello.c b/hello.c
index e69de29..bdc92a5 100644
--- a/hello.c
+++ b/hello.c
@@ -0,0 +1,2 @@
+void func1(void) {printf("this is func1");}
+void main(void) {return func1();}
可见git stash apply可以将列表中任何一次修改应用到当前工作区,我们再次git stash list一把:
$:~/code/linux/git$ git stash list
stash@{0}: WIP on master: 452b08d rename hello as hello.c
stash@{1}: WIP on master: 452b08d rename hello as hello.c
我们发现,虽然func1的修改已经被弹出应用到当前工作区,其修改内容还继续保留在暂存列表,并未丢弃。
当然,我们可以使用git stash drop stash@{1}来丢掉stash@{1}
7、保存时打标记(git stash save)
假设现在我们又开始尝试写func3, 这样越来越多,这样列表会越来越大,你要想搞清楚某次修改对应哪个函数,就要挨个用git stash show看一遍,很麻烦。
那么,这个时候git stash 的save参数就有用了,它可以为这次暂存做个标记,使得你用git stash list的时候显示这些标记,方便你回忆是修改的什么:
$:~/code/linux/git$ vim hello.c
$:~/code/linux/git$ git diff
diff --git a/hello.c b/hello.c
index e69de29..786c214 100644
--- a/hello.c
+++ b/hello.c
@@ -0,0 +1,2 @@
+void func3(void) {printf("this is func3");}
+void main(void) {return func3();}
$:~/code/linux/git$ git stash save "this is func3"
Saved working directory and index state On master: this is func3
HEAD is now at 452b08d rename hello as hello.c
$:~/code/linux/git$ git stash list
stash@{0}: On master: this is func3
stash@{1}: WIP on master: 452b08d rename hello as hello.c
stash@{2}: WIP on master: 452b08d rename hello as hello.c
我们在save后面指定一个字符串,作为提醒,这样在git stash list查看时就能知道每一个代号对应的修改了。
可是由于一次的误操作事件,让小熊瞬间陷入了恐慌;那是一个夜黑风高的夜晚,小熊刚刚改完这几天的bug,还没commit,只是用stash 保存起来了,但是由于小熊的一个手滑操作,本打算删除以前使用stash保存的废弃记录,可是由于手滑的失误让小熊这几天修改的BUG,被删除了;突然小熊一下子就懵了,还好小熊深呼吸一口,沉着稳定的去查找是否有,回退的操作。


问题--修复
小熊,本着忐忑的心情,再百度输入了
git stash 误删想要找到相关的回退操作文档,果然皇天不负有心人,一篇精彩绝伦的回退操作文档,完美的解决了,小熊这次的手贱操作。
1. 使用git fsck --unreachable命令查找所有unreachable的记录
这条命令会打印出所有不能从任何索引节点访问但是确存在的对象,回车之后我们会看到如下的显示:

如图中所示,大概有三种类型的内容,blob、tree和commit。我们这样看的话是看不出任何有用信息的,我们需要另外一条命令将其内容show出来。
记录太多,还好小熊把当时误删除的stash id 记录下来了,可以用删除的stash id直接定位到,那条记录,可以看到是一个commit 类型的记录。

2. 使用git show命令显示记录内容
Shows one or more objects (blobs, trees, tags and commits).
git show后面跟上要show的id,就可以展示这个id所对应的blob,tree,tag和commit。比如:git show f19aa7d5a056b4f1fe9f30ec86137431d063db57。比较诡异的是,这些id所对应的记录并不是有序的,如果想要找到之前误删的内容,需要我们一条条的去show出这些内容,然后判断是否是要找回的。万幸的是有两点如果能善加利用的话,会起到事半功倍的效果。一是我们只需要关心commit类型的内容,这些才是我们保存过或者提交过的内容;二是show出来的内容是有日期的,我们只要能大概记住误删内容的保存或提交日期,那么找起来自然轻松很多。

3. 使用git stash apply命令恢复记录内容
根据第二步找到我们所要恢复内容的id,使用git stash apply就可以完美治愈本次的手残,命令执行完后会发现,之前的stash内容又在工作区出现了,是不是很有趣呢,git果然是无比强大!这个地方需要注意的是git stash apply只能恢复commit类型的记录,如果使用这条命令来恢复blob,tree或tag可能会报错。
在使用
git fsck –unreachable命令输出的很多文件里面,有很多是带有commit和tree的标识的,这些可以使用git stash apply加标记号进行找回。而blob的文件是只能手动拷贝的,或者使用>输出到指定的路径去 [ 例如git show 302063e31742cbce7c5fdb917edf520183154cc1 > D:\recovery\backup.txt]
小记
git使用了这么久,其实还是有很多东西没能深入了解,比如blob,tree,tag和commit都代表了什么含义,各有什么作用,查找了一些资料,学习记录一下。
每个object包含三个部分:类型,大小和内容。大小就是指内容的大小,内容取决于对象的类型,有四种类型的对象,也就是上面提到的blob,tree,tag和commit。
blob用来存储文件数据,通常是一个文件tree有点像一个目录,它管理一些tree或blob,就像文件和子目录tag标签,用来标记某一次的commitcommit只指向一个tree,它用来标记项目某一个特定时间点的状态。它包括一些关于时间点的元数据,比如时间戳、最近一次提交的作者,指向上次提交的指针等等。
git stash 常用命令
git stash save "message"git stash listgit stash drop <stash@{num}>git stash apply <stash@{num}>
参考链接:
- 三歪建议 去工作之前 最好学学这个技术
- git stash内容误删找回
- 记一次误删 git stash 文件恢复操作
- Git 代码防丢指南
- Git 入门看这一篇就够了!程序员防被diss必会技能走一波!
- IDEA万能快捷键,你不知道的17个实用技巧!!!
- git stash使用教程
git stash 的一次惊心动魄的误删操作的更多相关文章
- git stash 暂存恢复和文件误删恢复
git commit提交文件,服务器返回本地文件有修改. 1.git stash :暂存本地代码 2.git pull origin develop : 获取远程分支代码 3.git stash po ...
- Git Stash紧急处理问题,需要切分支
在开发过程中,大家都遇到过bug,并且有些bug是需要紧急修复的. 当开发人员遇到这样的问题时,首先想到的是我新切一个分支,把它修复了,再合并到master上. 当时问题来了,你当前正在开发的分支上面 ...
- git stash 用法
git stash用于将当前工作区的修改暂存起来,就像堆栈一样,可以随时将某一次缓存的修改再重新应用到当前工作区. 一旦用好了这个命令,会极大提高工作效率. 直接举例说明: 1.准备工作,首先初始 ...
- git stash和git stash pop
git stash 可用来暂存当前正在进行的工作, 比如想pull 最新代码, 又不想加新commit, 或者另外一种情况,为了fix 一个紧急的bug, 先stash, 使返回到自己上一个comm ...
- git stash -u 添加新文件
git 提交 有新文件执行 git stash -u ------ 如果已经执行git stash,会发现有UNtracked这个单词 说明新文件没有添加进去,此时 执行 git stash ...
- 每天一命令 git stash
git stash 命令是用于保存当前进度的命令.该命令会保存当前工作区的改动.保存的改动是已经跟踪的文件的改动,对于未跟踪的改动stash是不会保存的. git stash 命令常用于分支切换的 ...
- git stash提交PR的正确步骤&git squash技术
1.git stash梳理 1.1git stash的克隆与同步 首先整理下git stash的逻辑是这样 在本地做出了新的修改,提交时显示当前的版本不是最新版本,这时就需要先pull一下自己代码仓库 ...
- git merge git pull时候遇到冲突解决办法git stash
在使用git pull代码时,经常会碰到有冲突的情况,提示如下信息: error: Your local changes to 'c/environ.c' would be overwritten b ...
- git stash简介
原文:http://gitbook.liuhui998.com/4_5.html 一.基本操作 当你正在做一项复杂的工作时, 发现了一个和当前工作不相关但是又很讨厌的bug. 你这时想先修复bug再做 ...
随机推荐
- 状态机引擎在vivo营销自动化中的深度实践 | 引擎篇02
本文是<vivo营销自动化技术解密>的第3篇文章,分析了营销自动化业务背景和状态机引入原因.状态机的三种基本实现方式,同时介绍了几种业界流行的开源状态机框架实现和特点,以及在项目开发过程中 ...
- pytest进阶使用【fixture(一)fixture与setup/teardown区别】
fixture翻译为装置. 我觉得名字是很贴合功能的,可以自由给函数装置上自己想要的功能. 当在说pytest比unitest灵活时,fixture肯定是其中的一个理由. 测试数据的准备和执行以后的数 ...
- JavaScript学习总结7-BOM
今天学习了BOM模型,可以利用其来获得屏幕数据,网页历史,以及网页location等数据
- uniapp-app 打开小程序
plus.share.getServices( res => { let sw ...
- python基础练习题(题目 画圈,学用circle画圆形。)
day37 --------------------------------------------------------------- 实例056:画圈 题目 画图,学用circle画圆形. 分析 ...
- python学习番外篇——字符串的数据类型转换及内置方法
目录 字符串的数据类型转换及内置方法 类型转换 内置方法 优先掌握的方法 需要掌握的方法 strip, lstrip, rstrip lower, upper, islower, isupper 插入 ...
- KTL 一个支持C++14编辑公式的K线技术工具平台 - 第六版,支持OpenGL,3D上帝视角俯视K线概貌。
K,K线,Candle蜡烛图. T,技术分析,工具平台 L,公式Language语言使用c++14,Lite小巧简易. 项目仓库:https://github.com/bbqz007/KTL 国内仓库 ...
- LINUX系统下安装PyCharm和annaconda3并配置
以下是在ubantu18.04版本下的配置教程: Step 1 去PyCharm官网下载Linux版的PyChram安装压缩包 网址:https://www.jetbrains.com/zh-cn/p ...
- 最新 x86_64 系统调用入口分析 (基于 5.7.0)
最新 x86_64 系统调用入口分析 (基于5.7.0) 整体概览 最近的工作涉及系统调用入口,但网上的一些分析都比较老了,这里把自己的分析过程记录一下,仅供参考. x86_64位系统调用使用 SYS ...
- MySQL执行计划explain
一.简介 分析查询慢的原因,在查询语句前加explain即可.如: 二.输出格式 2.0 测试数据 # 表user_info CREATE TABLE `user_info` ( `id` bigin ...