因为学习资料中讲的是在没听懂,自己从网上找了一个写的挺好的文章: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. jsp中jstl、el使用

    tomcat7.0+JSTL1.1.2(不冲突) EL表达式获取变量 ${表达式} 如:${user.name} 不可以动态取值 ${user[name]}可以动态取值,变量名中含有特殊字符时只能用此 ...

  2. 运维01 VMware与Centos系统安装

    VMware与Centos系统安装   今日任务 1.Linux发行版的选择 2.vmware创建一个虚拟机(centos) 3.安装配置centos7 4.xshell配置连接虚拟机(centos) ...

  3. computed和watch运用场景

    computed:通过属性计算而得来的属性 1.computed内部的函数在调用时不加(). 2.computed是依赖vm中data的属性变化而变化的,也就是说,当data中的属性发生改变的时候,当 ...

  4. java 并发——volatile

    java 并发--volatile 介绍 维基百科: volatile 是一个类型修饰符(type specifier).volatile 的作用是确保本条指令不会因编译器的优化而省略,且要求每次直接 ...

  5. 20140923 cin.get() getline cin

    #include<iostream> #include<string> using namespace std; int main() {     string title; ...

  6. WireMock提供Restful接口数据

    1.去官网下载并启动: 2.引入Pom依赖(主要是com.github.tomakehurst:wiremock): <dependency> <groupId>com.git ...

  7. Python中过滤HTML标签的函数

    #用正则简单过滤html的<>标签 import re str = "<img /><a>srcd</a>hello</br>&l ...

  8. sudo: unable to resolve host 枝桠

    Ubuntu环境, 主机名字叫枝桠(机器的hostname), 每次执行sudo 就出现这个警告讯息: 虽然sudo 还是可以正常执行, 所以就直接从/etc/hosts 设定, 让枝桠(hostna ...

  9. Error(10028):Can't resolve multiple constant drivers for net “ ” at **.v

    两个进程里都有同一个条件判断的话,会产生并行信号冲突的问题. 同一个信号不允许在多个进程中赋值,否则则为多驱动. 进程的并行性决定了多进程不同能对同一个对象进行赋值.

  10. wait/notify方法

    执行wait方法会释放锁,执行notify不会释放锁 package com.qf.test05.pojo; /** * @author qf * @create 2018-09-18 10:41 * ...