git命令的骚操作 --每天进步一点点

879 阅读7分钟

前言

我们不说那些 git push, git merge, git reset 等等,这些基操,这里主要讲一下 git rebase, git cherry-pick, git reflog, git stash 四个可能会用到的操作。

git rebase

两个作用

作用一:合并多次提交记录

一个小功能更改,提交 几十次 ,项目充满了无用的 commit 纪录。

简介

简要概括为:可以对某一段线性提交历史进行编辑、删除、复制、粘贴;因此,合理使用rebase命令可以使我们的提交历史干净、简洁!

基本用法

这里介绍合并提交:

rebase合并提交.png

  1. 命令

    git rebase -i  [startpoint]  [endpoint]
    
    • -i的意思是--interactive,即弹出交互式的界面让用户编辑完成合并操作。
    • [startpoint] [endpoint]则指定了一个编辑区间。(一个前开后闭的区间)

    或者

    git rebase -i HEAD~3 
    
    • 最新的三个commit

  2. 然后进入vi 编辑模式

    rebase-step1.png

    上面的是本次rebase操作包含的所有提交,下面注释的是git命令说明。

    pick:保留该commit(缩写:p)

    reword:保留该commit,但我需要修改该commit的注释(缩写:r)

    edit:保留该commit, 但我要停下来修改该提交(不仅仅修改注释)(缩写:e)

    squash:将该commit和前一个commit合并(缩写:s)

    fixup:将该commit和前一个commit合并,但我不要保留该提交的注释信息(缩写:f)

    exec:执行shell命令(缩写:x)

    drop:我要丢弃该commit(缩写:d)

  3. 修改2、3的第一个单词为s,输入:wq or x 保存退出。

    rebase-step2.png

  4. 有冲突解决冲突。没有则会出现一个 commit message 编辑页面。

    rebase-step3.png

    修改 commit message ,然后 输入:wq or x 保存退出。

    rebase-step4.png

  5. 查看结果

    git log
    
  6. 异常退出vi窗口,想回去:

    git rebase --edit-todo
    
  7. 放弃此次压缩:

    git rebase --abort
    

当然,你可以使用其他命令比如:d(删除),修改这几次的提交。

作用二:分支合并(变基)

master 分支切出一个 dev 分支,进行开发,你的同事在master上完成一次提交,这时两个分支情况:

分支.png

我们想要同步 master 分支的改动,首先想到了 merge,还有一个命令就是rebase,那这两个的区别是什么呢?

merge 和 rebase 的区别

两张图就可以看出:

merge:

merge.png

  1. 新增一个新的 merge commit,然后将两个分支的历史联系在一起。
  2. 使用 merge 是很好的方式,因为它是一种非破坏性的操作,对现有分支不会以任何方式被更改。

rebase:

rebase分支.png

  1. rebase 会将整个 dev 分支移动到 master 分支的顶端,从而有效地整合了所有 master 分支上的提交。

  2. rebase 通过为原始分支中的每个提交创建全新的 commits 来重写项目历史记录,特点是仍然会在dev分支上形成线性提交。

Git rebase并不会删除老的提交,也就是说你在对某个分支执行了rebase操作之后,老的提交仍然会存放在.git文件夹的objects目录下。

git rebase 做了什么
  1. git 会把 dev 分支里面的每个 commit 取消掉;

  2. 把上面的操作临时保存成 patch 文件,存在 .git/rebase 目录下;

  3. dev 分支更新到最新的 master 分支;

  4. 把上面保存的 patch 文件应用到 dev 分支上。

基本用法
  1. 命令:

    git rebase master  #将master最新的commit作为基
    
  2. 解决冲突:

    rebasemerge的另一个区别是rebase 的冲突是一个一个解决,如果有十个冲突,先解决第一个,然后用命令:

    # 解决冲突
    git add xxx
    git rebase --continue
    

    继续后才会出现第二个冲突。

  3. 在任何时候,我们都可以用 --abort 参数来终止 rebase 的行动,并且分支会回到 rebase 开始前的状态。

    git rebase —abort
    
总结
  1. 融合代码到公共分支的时使用git merge,而不用git rebase

  2. 融合代码到个人分支的时候使用git rebase,可以不污染分支的提交记录,形成简洁的线性提交历史记录。

作用三:将某一段commit粘贴到另一个分支上

这个建议使用git cherry-pick,我也没实践过。

git cherry-pick

作用:挑选指定 commit 来合并。

将某个分支的部分提交(某几个提交)转移到另一个分支,原先分支提交不变。

好处

举个栗子:

dev 上改了提交1个更改,然后这个更改也想用到 master 分支上面。但又不需要全部提交。

基本用法

转移一个提交

  1. 命令:

    
    git cherry-pick <commitHash>
    
    

    master 分支执行,指定 dev 分支的一个提交的 commitHash,就可以将这个提交应用到 master 分支,产生一个新的提交,两个的哈希值不一样,相当于在两个分支上做一样的修改,然后分别提交。

  2. 看图秒懂:

    cherry-pick.png

    master 分支上 git cherry-pick Y,然后 master 上会有一个 Y'

  3. 参数不一定是哈希值,也可以是分支名:

    
    git cherry-pick dev
    
    

    表示将 dev 分支的最近一次提交,转移到当前分支。

转移多个提交

  1. 多个不连续的

    
    git cherry-pick <A> <B>
    
    

    转移 AB 两个提交。

  2. 多个连续的(不包含 A

    
    git cherry-pick <A>..<B>
    
    

    转移从 AB 的所有提交。

  3. 多个连续的(包含 A

    
    git cherry-pick <A>^..<B>
    
    

转移到另一个代码库

cherry-pick 的奥义就是,只要是在一个 .git 仓库管理下的本地代码,任何提交都可以被应用到任何可访问的本地分支,哪怕是跨代码库。

常用配置项

  1. n, –no-commit

    只更新工作区和暂存区。不产生新的提交

  2. -x

    在提交信息末尾追加一行(cherry picked from commit…)方便以后查到这个提交是如何产生的。

  3. m parent-number, –mainline parent-number

    • 如果原始分支是一个合并节点,那么 cherry-pick 默认会失败,因为不知道应该采用哪个分支的代码变动。

    • -m 配置项告诉 git 应该采用哪个分支分变动,parent-number 代表原始提交的父分支编号。

    
    git cherry-pick -m 1 <A>
    
    

    一般1号父分支是接受变动分支,2号父分支是作为变动来源的分支。

git reflog

作用

  1. git reflog 可以查看所有分支的 所有操作记录 (包括(包括 checkoutreset 的操作),包括已经被删除的 commit 记录。

  2. 用来恢复本地错误操作。

基本用法

  1. git reflog 显示所有操作。

    image.png

    回退到某一步:git reset --hard HEAD@{1} 或者用前面的id

  2. git reflog 分支名 显示某个分支的引用日志

与 git log 的区别

  1. git log 命令可以显示所有提交过的版本信息。git reflog 查看所有分支的 所有操作记录

  2. git log 不能察看已经删除了的 commit 记录。

git stash

作用

保存当前的工作进度至栈中。会分别对暂存区和工作区的状态进行保存(未提交前)

场景:

  1. 在一个分支开发,有一个紧急的bug,不想提交现在的更改,stash 存起来,改完bug后又切回该分支,从栈中取出来继续开发。

  2. 本来应该在 feat 分支上开发,但是却在 dev 分支上开发了,可以暂存起来,切到想要开发的分支,然后取出来。

注意

没有在git 版本控制中的文件,是不能被git stash 存起来的

基本用法

  1. git stash 保存当前的工作空间。但是提交信息是上次 commit 的信息。

  2. git stash save "save message" 保存;添加备注。

  3. git stash list 显示保存进度的列表。也就意味着,git stash 命令可以多次执行。

  4. git stash pop 恢复最新保存的工作进度。

    • 默认会把工作区和暂存区的改动都恢复到工作区。

    • 恢复进度后,会删除栈中的当前进度。

  5. git stash pop --index 恢复最新的进度到工作区和暂存区。(尝试将原来暂存区的改动还恢复到暂存区)。

  6. git stash pop stash@{1} 恢复指定的进度到工作区。

  7. git stash show stash@{1} 显示具体某一个做了哪些改动。直接 show 显示全部。

  8. git stash apply 除了不删除恢复的进度之外,其余和 git stash pop 命令一样。

  9. git stash drop stash@{1} 删除一个存储的进度。如果不指定id,则默认删除最新的存储进度。

  10. git stash clear 删除所有存储的进度。