因为学习资料中讲的是在没听懂,自己从网上找了一个写的挺好的文章:https://blog.csdn.net/flysqrlboy/article/details/79250150

感谢!

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_HEAD
       7dd2e09..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.txt

    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:   b.txt

如果想要切换分支,必须保证当前的分支是noting to commit的,或者commit或者stash下

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.txt

    no 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.txt
        modified:   b.txt

    no 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.txt

    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:   b.txt

    Dropped refs/stash@{0} (c62afccafe9aaec2b44abe85b4206728479b9902)

    $ git status
    On branch master
    Changes to be committed:
      (use "git reset HEAD <file>..." to unstage)

        modified:   a.txt

    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:   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.txt

    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:   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.txt

    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:   b.txt

在 “Changes to be committed” 下面,

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

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

    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.txt
        modified:   b.txt

    no 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.txt
        modified:   b.txt

    $ git commit -m 'modify a.txt b.txt'
    [master c80c16c] modify a.txt b.txt
     2 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.txt
        modified:   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.git
       d7e1e19..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.git
       f0e0628..9086b68  master -> master

Ok! 成功push 到远程。

7. 小结

======

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

git分布式版本控制系统权威指南学习笔记(六):git reset、get stash、git checkout总结的更多相关文章

  1. git分布式版本控制系统权威指南学习笔记(一):配置文件、简单流程和小问题

    文章目录 git配置文件简介 git config各种命令 配置级别: 用户信息 文本编辑器 差异分析工具 配置命令别名 公钥 git协同流程 简单流程 初始化版本库 提交至缓存区 查看状态 提交分支 ...

  2. git分布式版本控制系统权威指南学习笔记(三):简单了解git对象、head以及sha1sum

    文章目录 git对象(简单了解) 对象是存在哪里的? head和master分支 上面的hash值怎么来的? git对象(简单了解) 每次提交都有tree.parent.author.committe ...

  3. git分布式版本控制系统权威指南学习笔记(四):git reset

    文章目录 git reset目录树重写 git reset 重置 git reset目录树重写 git reset --soft 暂存区工作区不变 git reset --hard git reset ...

  4. git分布式版本控制系统权威指南学习笔记(二):git add暂存区的三个状态以及暂存区的理解

    文章目录 不经过git add(到暂存区),能直接进行commit吗? 举个

  5. git分布式版本控制系统权威指南学习笔记(五):git checkout

    文章目录 分离头指针 通过cat可以查看当前的分支 通过branch查看当前分支 checkout commitId(真正的

  6. netty权威指南学习笔记六——编解码技术之MessagePack

    编解码技术主要应用在网络传输中,将对象比如BOJO进行编解码以利于网络中进行传输.平常我们也会将编解码说成是序列化/反序列化 定义:当进行远程跨进程服务调用时,需要把被传输的java对象编码为字节数组 ...

  7. IDA Pro 权威指南学习笔记(六) - 次要的 IDA 显示窗口

    十六进制窗口 IDA 十六进制窗口可以配置为显示各种格式,并可作为十六进制编辑器使用 默认情况下,十六进制窗口显示程序内容和列表的标准十六进制代码,每行显示 16 个字节,以及其对应的 ASCII 字 ...

  8. 《Linux就该这么学》自学笔记_ch21_使用Git分布式版本控制系统

    <Linux就该这么学>自学笔记_ch21_使用Git分布式版本控制系统 文章主要内容: 分布式版本控制系统 使用Git服务程序 提交数据 移除数据 移动数据 历史记录 还原数据 管理标签 ...

  9. g4e基础篇#2 Git分布式版本控制系统的优势

    g4e 是 Git for Enterprise Developer的简写,这个系列文章会统一使用g4e作为标识,便于大家查看和搜索. 章节目录 前言 1. 基础篇: 为什么要使用版本控制系统 Git ...

随机推荐

  1. python 去除字符串两端字符串

    转载:http://blog.sina.com.cn/s/blog_940224600100w8l0.html Python中的strip用于去除字符串的首位字符,同理,lstrip用于去除左边的字符 ...

  2. 集合类不安全之ArrayList

    1. 不安全的ArrayList 大家都知道ArrayList线程不安全,怎么个不安全法呢?上代码: public class ContainerNotSafeDemo { public static ...

  3. 仿flask写的web框架

    某大佬仿flask写的web框架 web_frame.py from werkzeug.local import LocalStack, LocalProxy def get_request_cont ...

  4. Oracle 表空间详解

    目录 目录 表空间概述 表空间的分类 默认表空间 查看默认的永久表空间 查看默认的TEMP表空间 查看默认的表空间类型 逻辑结构到物理结构的映射 对表空间的操作 查看表空间使用情况 查看数据库拥有的表 ...

  5. Android 发布自动版本号方案

    以前看到一些自动化版本号打包的文章.如果您的项目是用 Git 管理的,并且恰巧又是使用 Gradle 编译(应该绝大部分都是这样的了吧?),本文试图找到一种更加优雅的自动版本管理方法. 背景 我们都知 ...

  6. 模板引擎的简单原理template

    ​ var templateStr = "我的名字叫<%=name%>我是一只小狗,今年<%=age%>岁."; var data = { name:'旺财 ...

  7. VEX IR语言语法

    /*---------------------------------------------------------------*//*--- High-level IR description - ...

  8. LeetCode N皇后 & N皇后 II

    题目链接:https://leetcode-cn.com/problems/n-queens/ 题目链接:https://leetcode-cn.com/problems/n-queens-ii/ 题 ...

  9. WinDows应急响应基础

    文件排查 开机启动有无异常文件 msconfig 敏感的文件路径 %WINDIR% %WINDIR%\SYSTEM32\ %TEMP% %LOCALAPPDATA% %APPDATA% 用户目录 新建 ...

  10. Java对象相等比较(Equals)

    以下代码显示如何实现equals()和hashCode()方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 ...