Git快速入门系列文章
- Git快速入门-安装配置篇
- Git快速入门-常用命令之独奏篇
- Git快速入门-常用命令之交响乐篇
- Git快速入门-git stash 暂存变更,git reset 撤销commit,git revert 回退远程版本库

注:本文基于git version 2.13.5 版本进行演示

1. 概述

Git入门系列第四篇,基于场景,介绍一些非常实用的Git命令,也许这些命令会让你产生“还有这种操作”的感叹。例如如何把修改暂存起来,留着以后使用?想撤销已提交(commit)到本地版本库的代码该怎么办?撤销已push到远程代码库的代码呢?

2. 如何把修改暂存起来,留着以后使用?

2.1 使用场景

实际开发过程中,我们经常会遇到这样的问题,当我们想把远程仓库的最新代码拉下来时,发现git会提示说我们本地做的修改会被覆盖,建议先commit代码或者stash(暂存)代码。你一定遇到过类似下面这样的提示:

$ git pull origin master
remote: Counting objects: 4, done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 4 (delta 1), reused 3 (delta 1), pack-reused 0
Unpacking objects: 100% (4/4), done.
From github.com:flysqrlboy/git-command-tutorials* branch            master     -> FETCH_HEAD7dd2e09..d7e1e19  master     -> origin/master
Updating 7dd2e09..d7e1e19
error: Your local changes to the following files would be overwritten by merge:b.txt
Please commit your changes or stash them before you merge.
Aborting

留意下面两句提示,我们可以有两个选择:commit或stash。

error: Your local changes to the following files would be overwritten by merge:
b.txt
Please commit your changes or stash them before you merge.

如果我们本地的代码修改得差不多了,可以选择commit到本地版本库。但如果我们的修改只是个半成品,我们不想把这样的代码留在提交历史里的话。git stash就能派上用场了。

2.2 git stash 暂存进度

先来看下当前的工作区和暂存区状态:

$ git status
On branch master
Changes to be committed:(use "git reset HEAD <file>..." to unstage)modified:   a.txtChanges 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:   b.txt

git status 输出中告诉我们,a.txt 和 b.txt 都有修改,a.txt 已加入到暂存区(在Changes to be committed下面),b.txt 的修改则还在工作区中(在Changes not staged for commit下面)。正是因为远程代码库有人更改了b.txt ,才导致本地拉取代码时提示会被覆盖。这里,用git stash 命令保存当前工作进度。

$ git stash
Saved working directory and index state WIP on master: 7dd2e09 add two files a.txt b.txt

运行git stash 之后,再查看工作区状态,会发现之前工作区和暂存区的修改都不见了。

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

2.3 查看进度

查看stash进度用命令git stash list

$ git stash list
stash@{0}: WIP on master: 7dd2e09 add two files a.txt b.txt

可以看到刚刚暂存的进度有个标识 stash@{0}。如果想查看某个进度具体修改的文件可以用命令git stash show

$ git stash show stash@{0}a.txt | 1 +b.txt | 1 +2 files changed, 2 insertions(+)

2.4 恢复进度

使用 git stash pop 从最近保存的进度进行恢复。

$ 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:   a.txt
modified:   b.txtno changes added to commit (use "git add" and/or "git commit -a")
Dropped refs/stash@{0} (ddc97ea74d33f3417f5ddab429a1dfeb3c08ca19)

通过git status查看工作区状态,可以看到之前的修改又回来了。

$ git status
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:   a.txtmodified:   b.txtno changes added to commit (use "git add" and/or "git commit -a")

不过可能你也发现了一个小瑕疵,原来的a.txt 的修改已经添加到暂存区的,但现在用git stash pop 恢复进度后,a.txt 的修改却还在工作区,暂存区的修改被撤销了。这里其实可以在运行git stash pop命令时带上一个 –index 的选项来告诉git重新应用被暂存的变更。

git stash pop --index
On branch master
Changes to be committed:(use "git reset HEAD <file>..." to unstage)modified:   a.txtChanges 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:   b.txtDropped refs/stash@{0} (c62afccafe9aaec2b44abe85b4206728479b9902)
$ git status
On branch master
Changes to be committed:(use "git reset HEAD <file>..." to unstage)modified:   a.txtChanges 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:   b.txt

3. 如何撤销工作区的修改?

如果觉得对b.txt这个文件的修改是没有必要的,该如何撤消修改,回到之前的状态(也就是回到没有修改前的状态)?git status 命令输出是有告诉我们怎么做的:

$ git status
On branch master
Changes to be committed:(use "git reset HEAD <file>..." to unstage)modified:   a.txtChanges 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:   b.txt

就在“Changes not staged for commit”下面第二个括号内,

(use “git checkout – < file >…” to discard changes in working directory)

git checkout – filename 可以丢弃某个文件在工作区的改动。我们试试看。

$ git checkout -- b.txt
$ git status
On branch master
Changes to be committed:(use "git reset HEAD <file>..." to unstage)modified:   a.txt

git status 已经没有b.txt 的信息,说明b.txt的修改已经撤出工作区,恢复到修改前的版本了。这里提醒一下:git checkout – filename 这个命令是有点危险的,因为它会丢弃掉之前做的改动,这是找不回来的。只有在确定某个文件是真的不需要改动才撤销。一般情况下,如果只是想回到没修改前的版本,但仍然想保留修改的内容,可以用git stash命令把改动暂存起来。

4. 如何把暂存区的修改撤回到工作区

如果我们不小心把一些还不想提交的修改添加到了暂存区(例如不小心用了 git add . 命令把所有改动都add 到暂存区),我们怎么把某些文件撤回工作区呢?实际上git status命令也有告诉我们。

$ git status
On branch master
Changes to be committed:(use "git reset HEAD <file>..." to unstage)modified:   a.txtChanges 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:   b.txt

在 “Changes to be committed” 下面,

(use “git reset HEAD < file >…” to unstage)

用 git reset HEAD filename 命令把暂存区的改动撤回到工作区,我们试试。

$ git reset HEAD a.txt
Unstaged changes after reset:
M   a.txt
M   b.txt$ git status
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:   a.txtmodified:   b.txtno changes added to commit (use "git add" and/or "git commit -a")

git status 输出可以看到,a.txt 的改动已经被撤出暂存区了。

5. 如何把最近的一次commit撤回到暂存区

如果我们对最近的一次commit感到不满意,想把它从本地版本库撤回到暂存区,该怎么做呢?让我们先做一次commit:

git status
On branch master
Changes to be committed:(use "git reset HEAD <file>..." to unstage)modified:   a.txtmodified:   b.txt$ git commit -m 'modify a.txt b.txt'
[master c80c16c] modify a.txt b.txt2 files changed, 2 insertions(+)$ git log --oneline
c80c16c (HEAD -> master) modify a.txt b.txt
7dd2e09 add two files a.txt b.txt
e6e0035 1.oneline 2.second line

提交已经成功,commitid 为 c80c16c 。现在要撤销这次提交,把改动撤回到暂存区。同样是使用命令 git reset,只不过这次要加上 –soft 选项。

$ git reset --soft HEAD^
$ git status
On branch master
Changes to be committed:(use "git reset HEAD <file>..." to unstage)modified:   a.txtmodified:   b.txt

git status 输出告诉我们,a.txt 和 b.txt的改动又回到暂存区了。再查看提交历史。

$ git log --oneline
7dd2e09 (HEAD -> master) add two files a.txt b.txt
e6e0035 1.oneline 2.second line

commitid 为 c80c16c 的那次提交已经没有了。现在来解释下 git reset –soft HEAD^ 的含义。先说一下”HEAD^”,它代表最新的一次提交的前一次提交。“HEAD”在Git中就是一个引用,它总是指向(当前分支中)最新的那一次提交。所以上面的命令意思是把头部引用(HEAD)向前回退一次。而选项–soft 的作用就是把最新那次提交的所有改动撤回到暂存区。

6. 如何回退已经push到远程版本库的提交

上面我们讨论的只是撤销本地做的提交,那如果提交已经push到远程代码库。要怎么回退呢?我们先把上面对a.txt , b.txt的修改push到远程代码库。

$ git push origin master
Counting objects: 4, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (4/4), 373 bytes | 373.00 KiB/s, done.
Total 4 (delta 0), reused 0 (delta 0)
To github.com:flysqrlboy/git-command-tutorials.gitd7e1e19..f0e0628  master -> master

已push成功,看下提交历史

$ git log --oneline
f0e0628 (HEAD -> master, origin/master) modify a.txt b.txt
d7e1e19 Merge pull request #1 from imflysquirrel/master
0c550df modify b.txt by imflysquirrel
7dd2e09 add two files a.txt b.txt

commitid 为 f0e0628的这次提交已经push到远程。现在想回退远程的这次提交,可能你会想到,先在本地用git reset命令撤销f0e0628 ,再push到远程,这种方案可行吗?试试看:

$ git reset --soft HEAD^
$ git log --oneline
d7e1e19 (HEAD -> master) Merge pull request #1 from imflysquirrel/master
0c550df modify b.txt by imflysquirrel
7dd2e09 add two files a.txt b.txt

执行git reset后本地已经回退到上一次提交,这时我们使用git push推送到远程看看能否成功。

$ git push origin master
To github.com:flysqrlboy/git-command-tutorials.git! [rejected]        master -> master (non-fast-forward)
error: failed to push some refs to 'git@github.com:flysqrlboy/git-command-tutorials.git'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Integrate the remote changes (e.g.
hint: 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.

推送失败了,reject的原因是说本地当前分支落后于远程代码库,如下

hint: Updates were rejected because the tip of your current branch is behind

因为我们本地的HEAD引用当前指向的提交是 d7e1e19,而远程的HEAD指向的是f0e0628。d7e1e19落后于f0e0628。其实不应该用git reset来回退远程仓库的提交,取而代之的是用git revert。git revert 这个命令也会创建一次提交,只不过这个提交相当于被回退的那次提交的一个反向提交。比如在f0e0628 这次提交提交中,b.txt增加了一行“Hello World!”,git diff 如下

diff --git a/b.txt b/b.txt
index 696ac20..0f47c73 100644
--- a/b.txt
+++ b/b.txt
@@ -1 +1,2 @@add by imflysquirrel
+Hello World!

那么反向提交的话就会删掉这行“Hello World!”, 下面用git revert 演示下。

$ git revert HEAD
[master 9086b68] Revert "modify a.txt b.txt"2 files changed, 2 deletions(-)

git revert HEAD 表示revert HEAD指向的那次提交,也就是最新的那一次提交f0e0628。用git log看下提交历史:

git log --oneline
9086b68 (HEAD -> master) Revert "modify a.txt b.txt"
f0e0628 (origin/master) modify a.txt b.txt
d7e1e19 Merge pull request #1 from imflysquirrel/master
0c550df modify b.txt by imflysquirrel
7dd2e09 add two files a.txt b.txt

新增了一个提交9086b68 ,原来的f0e0628 是还存在的。看下这时的b.txt,

$ cat b.txt
add by imflysquirrel

“Hello World!” 那行已经被删除掉了。那么现在可以push了。

$ git push origin master
Counting objects: 3, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 316 bytes | 316.00 KiB/s, done.
Total 3 (delta 1), reused 0 (delta 0)
remote: Resolving deltas: 100% (1/1), completed with 1 local object.
To github.com:flysqrlboy/git-command-tutorials.gitf0e0628..9086b68  master -> master

Ok! 成功push 到远程。

7. 小结

本文介绍了几个使用的git 命令。git stash 暂存代码。git reset 撤销本地提交。git revert 回退远程代码库。希望对你在使用git时有所帮助。如果觉得本文写的还行,请点个赞吧!也欢迎在讨论区留言做进一步交流。


本作品采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议进行许可。

Git快速入门-git stash 暂存变更,git reset 撤销commit,git revert 回退远程版本库相关推荐

  1. Git版本控制管理——远程版本库

    之前提到的Git的所有操作都是在本地完成的,而实际项目开发并不是一个人就可以搞定的,通常需要团队的协作,而这些协作可能又不是在同一个地区的,这就涉及到Git的分布式特性了. Git的分布式特定会涉及到 ...

  2. git stash暂存的操作

    git stash暂存的操作 多人开发,经常遇到开发某一个分支时,需要处理其他事情,这时就可以暂存手头的工作,进行其他工作,完事后再恢复,继续工作 1. 暂存操作 #查看当前状态git status ...

  3. git stash暂存修改

    较常用的几个命令: git stash git stash list git stash clear git stash apply git stash 将当前所有修改项(未提交的)暂存,压栈.此时代 ...

  4. Git快速入门篇—— Windows版本淘宝镜像快速下载安装详细步骤及简单入门教程(附带图文教程)

    Git快速入门篇-- Windows版本淘宝镜像快速下载安装详细步骤及简单入门教程(附带图文教程) 前言:我们平时在整理代码的时候,尤其是与别人一起开发项目的时候,常常涉及到代码的更新,因此代码版本问 ...

  5. git快速入门-笔记(MD格式)

    git快速入门-笔记(MD格式) http://www.php.cn/code/9058.html git是一种版本控制器.原来就是针对linux系统. 下载安装 - https://git-scm. ...

  6. git如何查看缓存区文件内容_详解Git工作区、暂存区、历史记录区以及git reset、git revert、git checkout等撤销命令的区别...

    一.可以将git简单的分为三个区域   1.工作区(working directory)    2.暂缓区(stage index)    3.历史记录区(history)    如图: 其中git ...

  7. git 取消 所有暂存_Git版本管理完全指南—学好Git一文足矣

    开心?一下 image.png 第一部分 命令行 1.分支操作 1. git branch 创建分支2. git checkout -b 创建并切换到新建的分支上3. git checkout 切换分 ...

  8. Git三大特色之Stage(暂存区)

    这是开篇 有人说,暂存区是 Git 最精彩的设计,同时也是最难理解的部分,两者我都感觉不太明显,但当我想写关于暂存区的理解后,发现的确不怎么好讲,这个玩意,有点只可意会的感觉,用 Git 用熟练了,很 ...

  9. Git快速入门(Win版+IDEA+Gitee实战)【基于狂神讲解】

    1.为什么要使用Git 学习git之前,我们需要先明白一个概念 版本控制! 什么是版本控制 版本控制(Revision control)是一种在开发的过程中用于管理我们对文件.目录或工程等内容的修改历 ...

最新文章

  1. 数据增强之图像旋转及坐标对应(附代码)
  2. 如何向Spring Bean 中注入java.util.Properties?
  3. JSON.parse()和JSON.stringify()的区别
  4. python kmeans聚类 对二维坐标点聚类_Kmeans均值聚类算法原理以及Python如何实现
  5. c 高级语言,C作为高级语言?
  6. 17. OD-带有多态、变形的程序进行打补丁去掉nag(分析xor加密解密、自身修改代码的程序)
  7. 如何设置省略号对其序号 html,html – 包含省略号和垂直对齐中间的框中的多行...
  8. HP的.NET职位面试题
  9. 安装 Redis的Python客户端redis-py
  10. 他们才是全球高频交易顶级玩家
  11. 逆向之汇编(堆栈平衡函数)
  12. kubernetes 学习记录-two
  13. Stripe/Paypal 多账户轮询系统操作【一】
  14. beta版和alpha版
  15. 每日一面 - 从 innodb 的索引结构分析,为什么索引的 key 长度不能太长?
  16. 亿格瑞A5-hdmi故障了
  17. linux dup作用,linux dup()\dup2()函数
  18. 小白量化彩票实战(6)彩票号码中六保五缩水和旋转矩阵
  19. Kaggle数据竞赛记录 - IEEE-CIS Fraud Detection
  20. 给定字符串A和B,输出A和B中的最大公共子串。

热门文章

  1. C语言程序设计的出版人,《出版科学》2018年(第1—6期)年度索引-图书情报知识-武汉大学.PDF...
  2. 计算机系统维护博客,关于Windows系统简单日常维护
  3. 通过JAVA读取Visio
  4. 数码相机变焦镜头故障解析与解决
  5. 【链环科技】如何利用“私域流量”——小程序直播做到高转化低退货
  6. how to send email by jmail?
  7. CSS字体颜色滚动渐变动画
  8. 学习笔记(15):R语言入门基础-增加行或列
  9. 一文搞懂华为ML Kit数字人,超简单集成
  10. 清北学堂第一题 游乐园 SmartOJ 1815(二分查找的精髓)