Git之git reset、git reflog、git revert、git rebase、cherry-pick高级指令

179 阅读6分钟
  • git 日常指令相关

  • 小知识

    • 常用的HEAD数组标位是怎样的?=》都是从数字0开始整数增长倒叙。
      • 比如a -> b -> c -> d -> e对应的HEAD就是4 -> 3 -> 2 -> 1 -> 0
      • ^代表一步,n个^代表n步
        • HEAD^回退一个版本到d
        • HEAD^^回退两个版本到c
        • HEAD^^回退三个版本到b
      • ~n也是代表n的意思
        • HEAD~1回退一个版本到d
        • HEAD~2回退两个版本到c
        • HEAD~3回退三个版本到b
  • git reflog

    • 定义:显示所有分支的所有操作记录【一定是ref 操作记录】
    • 对比:git log 只能显示当前分支的有效commit记录,比如reset了,reset前的就不会显示;而git reflog则会显示所有的操作记录,记录完整的操作流程,他会把整个commit 链和reset这个行为都会记下来
    • 使用场景:
      • 现在有五个提交a -> b -> c -> d -> e,现在执行git reset --hard HEAD~3后,显示a -> b,突然要求在找回c,执行git reflog找到c的哈希hashxx,然后在执行git reset --hard hashxx即可
      • 多个分支来回切换时,导致代码丢失或者合并错误等异常
      • 案例:
          程序员 A 在本地进行了三次 commit 'demo1''demo2''demo3'
          程序员 A 不小心进行了回滚 git reset --hard 'commit1',回滚到第一次提交
          程序员 A 又修改了文件并进行了 commit, 'demo4'
        ---- 
          问:如何找回被 reset 的两次 commit,并合并最新的一次 commit 'demo4'
        ----
          git reflog 可以查看所有分支的所有操作记录(包括已经被删除的 commit 记录和 reset 的操作) 恢复步骤
          git reflog 
          git reset  --hard  demo3_hash
          git cherry-pick 能够把另一个分支的一个或多个提交复制到当前分支 恢复步骤
          git cherry-pick  hash 
      
  • git reset

    • 定义:回退
      • 常用参数
        • --mixed 重置索引,但不重置工作树,更改后的文件标记为未提交(add)的状态【即回退到工作区】,默认操作。
        • --soft 回退后a分支修改的代码被保留并标记为add的状态(git status 是绿色的状态)【即回退到暂存区】。
        • --hard 重置索引和工作树,并且a分支修改的所有文件和中间的提交,没提交的代码都被丢弃了,【最常用,最直接,但是也是最有风险,一旦丢失,只能借助git reflog】
    • 使用场景:
      • 主要应用场景还是本地仓库,该提交还没有推到远程,如果已经推到远程,就只能强推上去,有一定的风险
      • 现在有五个提交a -> b -> c -> d -> e,现在执行git reset --hard HEAD^3或者git reset --hard hashc这样即可回退到c【切记最后时改代码还没有推到远程,只在本地仓库】
  • git revert

    • 定义:通过产生一条新的记录,同时保留已经有的历史commit记录,基于逆向操作,产生新的commit记录,达到剪切回退的效果
    • 语法:
      • 1、git revert [--[no-]edit] [-n] [-m parent-number] [-s] [-S[<keyid>]] <commit>
        • -e--edit】【可以不写,默认参数】不建议,会自动回退,自动commit产生新的commitId
        • -n--no-commit】建议,会自动回退,不自动commit产生新的commitId,回退完以后需要自己手动处理文件,手动处理如何commit
      • 2、git revert (--continue | --skip | --abort | --quit)
        • continue 继续操作
        • quit 停止操作,常用于pick失败后的操作
        • abort 停止操作,回到未操作前的状态
    • 常用细分指令:
      • git revert -n xxx 不要默认的后退且生成新的一条commitId
    • 使用场景:
      • 针对线上版本的回退,可以保留历史记录
        • 1、git revert -n xxx 回退到xxx【如果有冲突,需要先解决冲突】
        • 2、解决完冲突以后,可以重新commit,重新push / 也可以 git revert --continue 【拉起vim,填写日志,可以不处理,使用默认日志即可】,然后在git push
        • 3、在处理过程中如发现任何问题,可使用 "git revert --abort" 取消本次回滚行为。
    • 注意:revert是用来去除某次提交的,并不是用来回退到某次提交!!!那么怎么使用revert 回退到某次提交?
      • Answer:我们需要用一个区间来实现某种能力,给予revert一个区间,revert 可以接收一个区间x..y 【revert的行为操作默认不包括x,包括y】 - EX: 现在dev分支有五个提交a -> b -> c -> d -> e - 1、需要剔除c,实现:git revert -n head~2 或者 git revert -n c - 2、需要剔除b到d,实现:git revert -n head~4..head~1 或者 git revert -n e..b // 【这e是不被包含的】 - 3、需要剔除到d【即d保留,d以前的删除】,实现:git revert -n head~3..head~0 或者 git revert -n dev~3..dev // 【dev~3即d是不被包含的】
  • git rebase

    • 定义:合并修改,并重写commitId
      • git rebase会重写commitId,这个是最致命的
        • 所以能不用,就尽量不要用、尤其在公共的分支简直是车祸
        • 主干分支master是打死不能用的
        • 如果非要用,一定要指定最小范围git rebase -i xxx或者git rebase -i HEAD~xxx
      • git rebase为什么是重写commitId,原因就是为了创建更线性的提交,所以重写了commitId,从而实现
      • 交互式命令git rebase -i xxx,更直接的去操作重写
    • 常用细分指令:
      • git rebase -i xxx【修改pick为drop或者删除这一条】【可以罗列xxx之前,drop掉自己不要的或者删掉自己不要的】
      • git rebase -i xxx【修改pick为squash】合并commitId
    • 使用场景:
      • 在连续多次commit中去掉其中的某一次提交git rebase -i xxx【修改pick为drop或者删除这一条,保存:wq即可】
      • 将连续多次提交合并为一个提交git rebase -i xxx【修改pick为squash】合并commitId,保存:wq即可
  • git cherry-pick

    • 定义:将一个分支中的部分的提交合并到其他分支
    • 常用指令:
      • git cherry-pick <commitHash> 将另一个分支的某一条提交合并到当前分支
      • 多指令操作
        git cherry-pick <hashA> <hashB>     // 合并两个提交
        git cherry-pick <hashA>..<hashB>    // 合并从A到B两个提交中到所有提交,但不包含A  【左开】
        git cherry-pick <hashA>^..<hashB>   // 合并从A到B两个提交中到所有提交,包含A  【左闭】
      
      • 当执行了cherry-pick 命令如果有冲突,就会报冲突错误
        git cherry-pick --continue  // 1. 解决完冲突以后,继续下一个 cherry-pick
        git cherry-pick --abort   // 2. 不解决冲突,放弃合并,回到操作以前
        git cherry-pick --quit   // 3. 不解决冲突,放弃合并,且保持现有情况,不回到操作以前  
      
    • 使用场景: 1、想要合并某些内容,但又不想包含整个分支。这时用cherry-pick来合并单次提交
  • @后续持续更补中......