zoukankan      html  css  js  c++  java
  • GIT常见命令(二)

    参考:

    https://blog.csdn.net/yxlshk/article/details/79944535

    https://www.cnblogs.com/0616--ataozhijia/p/3709917.html

    https://blog.csdn.net/rebeccachong/article/details/39379703

    https://blog.csdn.net/weixin_44781409/article/details/107560533

    https://www.jianshu.com/p/c2ec5f06cf1a

     git reset、revert、rebase

    Git恢复之前版本的两种方法reset、revert(图文详解)

    一、问题描述

    在利用github实现多人合作程序开发的过程中,我们有时会出现错误提交的情况,此时我们希望能撤销提交操作,让程序回到提交前的样子,本文总结了两种解决方法:回退(reset)、反做(revert)

    二、背景知识

    git的版本管理,及HEAD的理解

    使用git的每次提交,Git都会自动把它们串成一条时间线,这条时间线就是一个分支。如果没有新建分支,那么只有一条时间线,即只有一个分支,在Git里,这个分支叫主分支,即master分支。有一个HEAD指针指向当前分支(只有一个分支的情况下会指向master,而master是指向最新提交)。每个版本都会有自己的版本信息,如特有的版本号、版本名等。如下图,假设只有一个分支:
    这里写图片描述

    三、解决方法

    方法一:git reset

    原理: git reset的作用是修改HEAD的位置,即将HEAD指向的位置改变为之前存在的某个版本,如下图所示,假设我们要回退到版本一:
    这里写图片描述
    适用场景: 如果想恢复到之前某个提交的版本,且那个版本之后提交的版本我们都不要了,就可以用这种方法

    具体操作:

    1. 查看版本号:
    可以使用命令“git log”查看:
    在这里插入图片描述
    也可以在github网站上查看:
    这里写图片描述
    2. 使用“git reset --hard 目标版本号”命令将版本回退
    这里写图片描述
    再用“git log”查看版本信息,此时本地的HEAD已经指向之前的版本:
    在这里插入图片描述
    3. 使用“git push -f”提交更改
    此时如果用“git push”会报错,因为我们本地库HEAD指向的版本比远程库的要旧:
    这里写图片描述
    所以我们要用“git push -f”强制推上去,就可以了:
    这里写图片描述
    在github图形化界面上看,远程库的HEAD也已经指向目标版本:
    这里写图片描述

    回退成功!

    方法二:git revert

    原理: git revert是用于“反做”某一个版本,以达到撤销该版本的修改的目的。比如,我们commit了三个版本(版本一、版本二、 版本三),突然发现版本二不行(如:有bug),想要撤销版本二,但又不想影响撤销版本三的提交,就可以用 git revert 命令来反做版本二,生成新的版本四,这个版本四里会保留版本三的东西,但撤销了版本二的东西。如下图所示:
    这里写图片描述
    适用场景: 如果我们想撤销之前的某一版本,但是又想保留该目标版本后面的版本,记录下这整个版本变动流程,就可以用这种方法

    具体操作:

    举个例子,现在库里面有三个文件:READ.md、text.txt、text2.txt。
    在这里插入图片描述
    1. 查看版本号:
    可以通过命令行查看(输入git log):
    如图,最近的两个版本分别叫:“add text.txt”(即新增了文件text.txt)、“add text2.txt”(新增了文件text2.txt)。这个时候我们不需要text.txt这个文件了,那就是说不想要“add text.txt”那个版本的操作,那可以通过反做“add text.txt”这个版本来实现。
    在这里插入图片描述
    也可以通过github网站图形化界面查看版本号:
    在这里插入图片描述
    2.使用“git revert -n 版本号”反做,并使用“git commit -m 版本名”提交:
    (1)反做,使用“git revert -n 版本号”命令。如下命令,我们反做版本号为8b89621的版本:

    git revert -n 8b89621019c9adc6fc4d242cd41daeb13aeb9861
    

    注意: 这里可能会出现冲突,那么需要手动修改冲突的文件。而且要git add 文件名。
    (2)提交,使用“git commit -m 版本名”,如:

    git commit -m "revert add text.txt" 
    

    此时可以用“git log”查看本地的版本信息,可见多生成了一个新的版本,该版本反做了“add text.txt”版本,但是保留了“add text2.txt”版本:
    在这里插入图片描述
    3.使用“git push”推上远程库:

    git push
    

    查看github上显示的远程库版本信息:
    在这里插入图片描述
    此时查看仓库的文件,剩下两个:READ.md、text2.txt
    在这里插入图片描述

    反做成功!

    git revert 用法

    git revert 撤销 某次操作,此次操作之前和之后的commit和history都会保留,并且把这次撤销作为一次最新的提交

        * git revert HEAD                  撤销前一次 commit
        * git revert HEAD^               撤销前前一次 commit
        * git revert commit (比如:fa042ce57ebbe5bb9c8db709f719cec2c58ee7ff)撤销指定的版本,撤销也会作为一次提交进行保存。
    git revert是提交一个新的版本,将需要revert的版本的内容再反向修改回去,版本会递增,不影响之前提交的内容

    --------------------------------------------------------------------------------------------------------------------------------------------

    git revert 和 git reset的区别 
    1. git revert是用一次新的commit来回滚之前的commit,git reset是直接删除指定的commit。 
    2. 在回滚这一操作上看,效果差不多。但是在日后继续merge以前的老版本时有区别。因为git revert是用一次逆向的commit“中和”之前的提交,因此日后合并老的branch时,导致这部分改变不会再次出现,但是git reset是之间把某些commit在某个branch上删除,因而和老的branch再次merge时,这些被回滚的commit应该还会被引入。 
    3. git reset 是把HEAD向后移动了一下,而git revert是HEAD继续前进,只是新的commit的内容和要revert的内容正好相反,能够抵消要被revert的内容

    git reset 、rebase和 revert的区别

    git revert 放弃某次提交

    git revert 之前的提交仍会保留在git log中,而此次撤销会做为一次新的提交。

    git reset 是回滚到某次提交
    git reset --soft
    此次提交之后的修改会被退回到暂存区
    git reset --hard
    此次提交之后的修改不做任何保留,git status干净的工作区。
     
    git rebase 当两个分支不在一条直线上,需要执行merge操作时,使用该命令操作
    该命令执行时极有可能显示merge失败,如下图1,使用git diff命令查看冲突内容,手动
    修改冲突,git add filename,表示冲突已解决,再执行git rebase --continue,继续rebase。
    图1
    git rebase 执行结果如下图2
    图2

    Git恢复之前版本的三种方法reset、revert、rebase 及其他操作

    一. 问题描述

    在利用github实现多人合作程序开发的过程中,我们有时会出现错误提交的情况,此时我们希望能撤销提交操作,让程序回到提交前的样子,本文总结了三种解决方法:回退(reset)、反做(revert)、回扣(rebase)。

    二. 解决方案

    方法一:git reset

    原理: git reset的作用是修改HEAD的位置,即将HEAD指向的位置改变为之前存在的某个版本
    具体实现:

    1. 查看版本号 使用命令“git log”查看:

    2. 使用“git reset --hard 目标版本号”命令将版本回退:

    3. 再用“git log”查看版本信息,此时本地的HEAD已经指向之前的版本:

    4. 使用“git push -f”提交到远程更改
      注意: 此时如果用“git push”会报错,因为我们本地库HEAD指向的版本比远程库的要旧

    方法二:git revert

    原理: git revert是用于“反做”某一个版本,以达到撤销该版本的修改的目的。比如,我们commit了三个版本(版本一、版本二、 版本三),突然发现版本二不行(如:有bug),想要撤销版本二,但又不想影响撤销版本三的提交,就可以用 git revert 命令来反做版本二,生成新的版本四,这个版本四里会保留版本三的东西,但撤销了版本二的东西。

    适用场景: 如果我们想撤销之前的某一版本,但是又想保留该目标版本后面的版本,记录下这整个版本变动流程,就可以用这种方法。

    具体实现:

    1.查看 使用命令“git log”查看commit提交记录

    2.使用“git revert 版本号”反做,并使用“git commit -m 版本名”提交

    3.使用“git push”推上远程库

    方法三:git rebase -i (commit-id) 或 git rebase -i HEAD~(回退几步)

    1.查看 使用命令“git log”查看commit提交记录

    2.git rebase -i (commit-id) 选择回退版本之前的一次commit版本

    3.编辑文件命令行输入 a,切换到编辑模式 将要删除的commit之前的 pick 单词改为drop

    4.按下Esc(退出)键 命令行输入 :wq 保存文件退出

    5.使用“git push -f”提交到远程更改

    6.在使用 git rebase -i (commit-id) 过程中若撤销回退可以使用 git rebase --abort 撤回

    若在 git rebase后出现(xxx|REBASE-i)这种情况
    在这里插入图片描述
    原因:用git推送数据到仓库的时候会出现推送失败
    解决方案: 使用git rebase --abort 代码回退 回到git rebase之前的状态

    其他操作

    一. 当代码库远程迁移后,修改本地代码关联到远程地址
    1.迁移前先查看当前代码库的远程地址

    git remote -v 查看远程地址

    2.修改本地代码关联到的远程地址

    git remote set-url origin [远程地址]

    3.查看当前代码库的远程地址是否修改成功

    git remote -v 查看远程地址

    4.将本地的master分支推送到origin主机
    ①指定origin为默认主机 ,后面就可以不加任何参数使用git push

     git push -u origin master  

    ② 提交本地test分支 作为 远程的master分支 ,不指定默认主机

    git push origin test:master

    Git Reset 三种模式

    有时候,我们用Git的时候有可能commit提交代码后,发现这一次commit的内容是有错误的,那么有两种处理方法:
    1、修改错误内容,再次commit一次 2、使用git reset 命令撤销这一次错误的commit
    第一种方法比较直接,但会多次一次commit记录。
    而我个人更倾向第二种方法,错误的commit没必要保留下来。
    那么今天来说一下git reset。它的一句话概括

    git-reset - Reset current HEAD to the specified state
    

    意思就是可以让HEAD这个指针指向其他的地方。例如我们有一次commit不是不是很满意,需要回到上一次的Commit里面。那么这个时候就需要通过reset,把HEAD指针指向上一次的commit的点。
    它有三种模式,soft,mixed,hard,具体的使用方法下面这张图,展示的很全面了。

     
    git各个区域和命令关系

    这三个模式理解了,对于使用这个命令很有帮助。在理解这三个模式之前,需要略微知道一点Git的基本流程。正如上图,Git会有三个区域:

    • Working Tree 当前的工作区域
    • Index/Stage 暂存区域,和git stash命令暂存的地方不一样。使用git add xx,就可以将xx添加近Stage里面
    • Repository 提交的历史,即使用git commit提交后的结果
     
    文件存入Repository流程

    以下简单敘述一下把文件存入Repository流程:

    1. 刚开始 working tree 、 index 与 repository(HEAD)里面的內容都是一致的


       
      阶段1
    2. 当git管理的文件夹里面的内容出现改变后,此時 working tree 的內容就会跟 index 及 repository(HEAD)的不一致,而Git知道是哪些文件(Tracked File)被改动过,直接将文件状态设置为 modified (Unstaged files)。


       
      阶段2
    3. 当我們执行 git add 后,会将这些改变的文件內容加入 index 中 (Staged files),所以此时working tree跟index的內容是一致的,但他们与repository(HEAD)內容不一致。


       
      阶段3
    4. 接着执行 git commit 後,將Git索引中所有改变的文件內容提交至 Repository 中,建立出新的 commit 节点(HEAD)后, working tree 、 index 與与repository(HEAD)区域的内容 又会保持一致。


       
      阶段4

    实战演示

    reset --hard:重置stage区和工作目录:

    reset --hard 会在重置 HEAD 和branch的同时,重置stage区和工作目录里的内容。当你在 reset 后面加了 --hard参数时,你的stage区和工作目录里的内容会被完全重置为和HEAD的新位置相同的内容。换句话说,就是你的没有commit的修改会被全部擦掉。

    例如你在上次 commit 之后又对文件做了一些改动:把修改后的ganmes.txt文件addstage区,修改后的shopping list.txt保留在工作目录

    git status
    

     

     
    最初状态

    然后,你执行了reset并附上了--hard参数:
    git reset --hard HEAD^
    

    你的 HEAD 和当前 branch 切到上一条commit 的同时,你工作目录里的新改动和已经add到stage区的新改动也一起全都消失了:

    git status
    

     

     
    reset --hard head^之后

    可以看到,在 reset --hard 后,所有的改动都被擦掉了。

    reset --soft:保留工作目录,并把重置 HEAD 所带来的新的差异放进暂存区

    reset --soft 会在重置 HEAD 和 branch 时,保留工作目录和暂存区中的内容,并把重置 HEAD 所带来的新的差异放进暂存区。

    什么是「重置 HEAD 所带来的新的差异」?就是这里:

     

    由于 HEAD 从 4 移动到了 3,而且在 reset 的过程中工作目录和暂存区的内容没有被清理掉,所以 4 中的改动在 reset 后就也成了工作目录新增的「工作目录和 HEAD 的差异」。这就是上面一段中所说的「重置 HEAD 所带来的差异」。

    此模式下会保留 working tree工作目录的內容,不会改变到目前所有的git管理的文件夹的內容;也会
    保留 index暂存区的內容,让 index 暂存区与 working tree 工作目录的內容是一致的。就只有 repository 中的內容的变更需要与 reset 目标节点一致,因此原始节点与reset节点之间的差异变更集合会存在与index暂存区中(Staged files),所以我们可以直接执行 git commit 將 index暂存区中的內容提交至 repository 中。当我们想合并「当前节点」与「reset目标节点」之间不具太大意义的 commit 记录(可能是阶段性地频繁提交)時,可以考虑使用 Soft Reset 来让 commit 演进线图较为清晰点。

     
     

    所以在同样的情况下,还是老样子:把修改后的ganmes.txt文件addstage区,修改后的shopping list.txt保留在工作目录

    git status
    

     

     
    最初状态

    假设此时当前 commit 的改动内容是新增了 laughters.txt 文件:
    git show --stat
    
     
    git show --stat

    如果这时你执行:

    git reset --soft HEAD^
    

    那么除了 HEAD 和它所指向的 branch1 被移动到 HEAD^ 之外,原先 HEAD 处 commit 的改动(也就是那个 laughters.txt 文件)也会被放进暂存区:

    git status
    

     

     
    使用git reset --soft HEAD^后

    这就是--soft 和 --hard 的区别:--hard 会清空工作目录和暂存区的改动,*而 --soft则会保留工作目录的内容,并把因为保留工作目录内容所带来的新的文件差异放进暂存区

    reset 不加参数(mixed):保留工作目录,并清空暂存区

    reset 如果不加参数,那么默认使用 --mixed 参数。它的行为是:保留工作目录,并且清空暂存区。也就是说,工作目录的修改、暂存区的内容以及由 reset 所导致的新的文件差异,都会被放进工作目录。简而言之,就是「把所有差异都混合(mixed)放在工作目录中」。

    还以同样的情况为例:

    git status
    
     
    最初状态

    修改了 的games.txt 和 shopping list.txt,并把 games.txt 放进了暂存区。

    git show --stat
    
     
    git show --stat

    最新的 commit 中新增了 laughters.txt 文件。

    这时如果你执行无参数reset或者带--mixed参数:

    git reset HEAD^
    git reset --mixed HEAD^
    

    工作目录的内容和 --soft 一样会被保留,但和 --soft 的区别在于,它会把暂存区清空,并把原节点和reset节点的差异的文件放在工作目录,总而言之就是,工作目录的修改、暂存区的内容以及由 reset 所导致的新的文件差异,都会被放进工作目录

    git status
    
     
    git reset HEAD^之后

    总结

    reset 的本质:移动 HEAD 以及它所指向的 branch

    实质上,reset 这个指令虽然可以用来撤销 commit ,但它的实质行为并不是撤销,而是移动 HEAD ,并且「捎带」上 HEAD 所指向的 branch(如果有的话)。也就是说,reset 这个指令的行为其实和它的字面意思 "reset"(重置)十分相符:它是用来重置 HEAD 以及它所指向的 branch 的位置的。

    而 reset --hard HEAD^ 之所以起到了撤销 commit 的效果,是因为它把 HEAD 和它所指向的 branch 一起移动到了当前 commit 的父 commit 上,从而起到了「撤销」的效果:

     
    git reset

    Git 的历史只能往回看,不能向未来看,所以把 HEAD 和 branch 往回移动,就能起到撤回 commit 的效果

    所以同理,reset --hard 不仅可以撤销提交,还可以用来把 HEAD 和 branch 移动到其他的任何地方。

    git reset --hard branch2

    reset三种模式区别和使用场景

    区别:

    1. --hard:重置位置的同时,直接将 working Tree工作目录、 index 暂存区及 repository 都重置成目标Reset节点的內容,所以效果看起来等同于清空暂存区和工作区。

    2. --soft:重置位置的同时,保留working Tree工作目录index暂存区的内容,只让repository中的内容和 reset 目标节点保持一致,因此原节点和reset节点之间的【差异变更集】会放入index暂存区中(Staged files)。所以效果看起来就是工作目录的内容不变,暂存区原有的内容也不变,只是原节点和Reset节点之间的所有差异都会放到暂存区中。

    3. --mixed(默认):重置位置的同时,只保留Working Tree工作目录的內容,但会将 Index暂存区 和 Repository 中的內容更改和reset目标节点一致,因此原节点和Reset节点之间的【差异变更集】会放入Working Tree工作目录中。所以效果看起来就是原节点和Reset节点之间的所有差异都会放到工作目录中。

    使用场景:

    1. --hard:(1) 要放弃目前本地的所有改变時,即去掉所有add到暂存区的文件和工作区的文件,可以执行 git reset -hard HEAD 来强制恢复git管理的文件夹的內容及状态;(2) 真的想抛弃目标节点后的所有commit可能觉得目标节点到原节点之间的commit提交都是错了,之前所有的commit有问题)。

    2. --soft:原节点和reset节点之间的【差异变更集】会放入index暂存区中(Staged files),所以假如我们之前工作目录没有改过任何文件,也没add到暂存区,那么使用reset --soft后,我们可以直接执行 git commit 將 index暂存区中的內容提交至 repository 中。为什么要这样呢?这样做的使用场景是:假如我们想合并「当前节点」与「reset目标节点」之间不具太大意义的 commit 记录(可能是阶段性地频繁提交,就是开发一个功能的时候,改或者增加一个文件的时候就commit,这样做导致一个完整的功能可能会好多个commit点,这时假如你需要把这些commit整合成一个commit的时候)時,可以考虑使用reset --soft来让 commit 演进线图较为清晰。总而言之,可以使用--soft合并commit节点

    3. --mixed(默认):(1)使用完reset --mixed后,我們可以直接执行 git add 将這些改变果的文件內容加入 index 暂存区中,再执行 git commit 将 Index暂存区 中的內容提交至Repository中,这样一样可以达到合并commit节点的效果(与上面--soft合并commit节点差不多,只是多了git add添加到暂存区的操作);(2)移除所有Index暂存区中准备要提交的文件(Staged files),我们可以执行 git reset HEAD 来 Unstage 所有已列入 Index暂存区 的待提交的文件。(有时候发现add错文件到暂存区,就可以使用命令)。(3)commit提交某些错误代码,或者没有必要的文件也被commit上去,不想再修改错误再commit(因为会留下一个错误commit点),可以回退到正确的commit点上,然后所有原节点和reset节点之间差异会返回工作目录,假如有个没必要的文件的话就可以直接删除了,再commit上去就OK了

    假如手贱,又想回退撤销的版本呢?

    请看另外一篇文章:TODO

    参考文章:

    https://dotblogs.com.tw/wasichris/2016/04/29/225157
    https://www.domon.cn/2018/09/06/Git-reset-used-in-coding/
    https://juejin.im/book/5a124b29f265da431d3c472e/section/5a14529bf265da43310d7351(掘金小册)



    作者:carway
    链接:https://www.jianshu.com/p/c2ec5f06cf1a
    来源:简书
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

     reset
     git reset [--soft | --mixed | --hard
     上面常见三种类型

    --mixed
      会保留源码,只是将git commit和index 信息回退到了某个版本.

      git reset 默认是 --mixed 模式
      git reset --mixed  等价于  git reset

    --soft
      保留源码,只回退到commit 信息到某个版本.不涉及index的回退,如果还需要提交,直接commit即可.

    --hard
      源码也会回退到某个版本,commit和index 都回回退到某个版本.(注意,这种方式是改变本地代码仓库源码)

  • 相关阅读:
    破衣服的回忆
    underscorejs 源码走读笔记
    关于书籍《区块链以太坊DApp开发实战》的内容告示
    从区块链技术研发者的角度,说说我的区块链从业经历和对它的理解
    简介 以太坊 2.0 核心 之 共识机制的改变
    一般电商应用的订单队列架构思想
    详细讲解:零知识证明 之 ZCash 完整的匿名交易流程
    HyperLogLog 算法的原理讲解以及 Redis 是如何应用它的
    由 System.arraycopy 引发的巩固:对象引用 与 对象 的区别
    如何独立开发一个网络请求框架
  • 原文地址:https://www.cnblogs.com/xuwc/p/14130185.html
Copyright © 2011-2022 走看看