16

学会git-rebase看这一篇就可以了

 3 years ago
source link: https://segmentfault.com/a/1190000030688343
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

前言

哈喽,everybody,不知不觉8天的小长假也接近了尾声,玩耍了这么多天,今天也要收一收心,开始学习了呦~。明天就要上班啦,今天姐姐突然问我git-rebase指令是干什么的,怎么用?其实我是不想给他讲的,但是还是没有逃过姐姐的软磨硬泡,那么我们就一起来看一看什么是git-rebase吧!!!

缘起

话说,我和姐姐的缘分是在那一个月黑风高的晚上,啪,姐姐一巴掌打在了我的脸上并说了一句:能不能讲重点~~~。哈哈,不开玩笑了,直接说重点吧。我们先来看一个场景,我查看了一下我github上的个人仓库, commit 提交次数很多,提交内容如下:

6JZbqym.png!mobile

这么多的提交,有很多没有规范的命名,因为是自己使用,就随便开整了,这确实不好,还有一些没有必要的提交,其实是可以合并到一起的,这样会导致如下问题:

  • 造成分支污染,项目中充满了许多 commit 记录,当出现紧急问题需要回滚代码时,就只能一条条的查看了。
  • 代码 review 不方便,当你要做 code review 时,一个很小的功能却提交了很多次,看起来就不是很方便了。

这一篇文章我们先不讲 git 提交规范,我们先来解决一下如何合并多次提交记录。

rebase作用一:合并提交记录

通过上面的场景,我们可以引申出 git-rebase 的第一个作用:合并提交记录。现在我们想合并最近5次的提交记录,执行:

$ git rebase -i HEAD~2

执行该指令后会自动弹出 vim 编辑模式:

pick e2c71c6 update readme
pick 3d2c660 wip: merge`

# Rebase 5f47a82..3d2c660 onto 5f47a82 (2 commands)
#
# Commands:
# p, pick <commit> = use commit
# r, reword <commit> = use commit, but edit the commit message
# e, edit <commit> = use commit, but stop for amending
# s, squash <commit> = use commit, but meld into previous commit
# f, fixup <commit> = like "squash", but discard this commit's log message
# x, exec <command> = run command (the rest of the line) using shell
# b, break = stop here (continue rebase later with 'git rebase --continue')
# d, drop <commit> = remove commit
# l, label <label> = label current HEAD with a name
# t, reset <label> = reset HEAD to a label
# m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]
# .       create a merge commit using the original merge commit's
# .       message (or the oneline, if no original merge commit was
# .       specified). Use -c <commit> to reword the commit message.
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#
# Note that empty commits are commented out

从这里我们可以看出前面5行是我们要合并的记录,不过前面都带了一个相同的指令: pick ,这是什么指令呢,不要慌,这不,下面已经给出了 commands :

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

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

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

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

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

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

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

label:用名称标记当前HEAD(缩写:l)

reset:将HEAD重置为标签(缩写:t)

merge:创建一个合并分支并使用原版分支的commit的注释(缩写:m)

根据这些指令,我们可以进行修改,如下:

pick e2c71c6 update readme
s 3d2c660 wip: merge`

修改好后,我们点击保存退出,就会进入注释界面:

# This is a combination of 2 commits.
# This is the 1st commit message:

update readme

# This is the commit message #2:

wip: merge`

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# Date:      Thu Sep 17 22:03:52 2020 +0800
#
# interactive rebase in progress; onto 5f47a82
# Last commands done (2 commands done):
#    pick e2c71c6 update readme
#    squash 3d2c660 wip: merge`
# No commands remaining.
# You are currently rebasing branch 'master' on '5f47a82'.
#
# Changes to be committed:
#       new file:   hash/.idea/.gitignore
#       new file:   hash/.idea/hash.iml
#       new file:   hash/.idea/misc.xml
#       new file:   hash/.idea/modules.xml
#       new file:   hash/.idea/vcs.xml
#       new file:   hash/go.mod
#       new file:   hash/hash/main.go
#       modified:   snowFlake/Readme.md

上面把每一次的提交的 meassage 都列出了,因为我们要合并这两次的 commit ,所以提交注释可以修改成一条,最终编辑如下:

# This is a combination of 2 commits.
# This is the 1st commit message:

fix: merge update and wip: merge`

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# Date:      Thu Sep 17 22:03:52 2020 +0800
#
# interactive rebase in progress; onto 5f47a82
# Last commands done (2 commands done):
#    pick e2c71c6 update readme
#    squash 3d2c660 wip: merge`
# No commands remaining.
# You are currently rebasing branch 'master' on '5f47a82'.
#
# Changes to be committed:
#       new file:   hash/.idea/.gitignore
#       new file:   hash/.idea/hash.iml
#       new file:   hash/.idea/misc.xml
#       new file:   hash/.idea/modules.xml
#       new file:   hash/.idea/vcs.xml
#       new file:   hash/go.mod
#       new file:   hash/hash/main.go
#       modified:   snowFlake/Readme.md

编辑好后,保存退出就可以了。这样就完成了一次合并 commit 。我们来验证一下:

$ git log
15ace34 (HEAD -> master) fix: merge update and wip: merge`
5f47a82 update snowFlake code

从这里我们可以看到,两次提交变成了一次,减少了无用的提交信息。

作用二:分支合并

这个作用我们使用的很少,但是还是要知道,下面我们一起来看一下使用场景。

假设我们现在有一个新项目,现在我们要从 master 分支切出来一个 dev 分支,进行开发:

$ git checkout -b dev

这时候,你的同事完成了一次 hotfix ,并合并入了 master 分支,此时 master 已经领先于你的 dev 分支了:

Bvimmmi.png!mobile

同事修复完事后,在群里通知了一声,正好是你需要的部分,所以我们现在要同步 master 分支的改动,使用 merge 进行合并:

$ git merge master

MZNf63u.png!mobile

图中绿色的点就是我们合并之后的结果,执行 git log 就会在记录里发现一些 merge 的信息,但是我们觉得这样污染了 commit 记录,想要保持一份干净的 commit ,怎么办呢?这时候, git rebase 就派上用场了。

所以现在我们来试一试使用 git rebase ,我们先回退到同事 hotfix 后合并 master 的步骤,我现在不使用 merge 进行合并了,直接使用 rebase 指令

$ git rebase master

这时, git 会把 dev 分支里面的每个 commit 取消掉,然后把上面的操作临时保存成 patch 文件,存在 .git/rebase 目录下;然后,把 dev 分支更新到最新的 master 分支;最后,把上面保存的 patch 文件应用到 dev 分支上;

J3MZZzZ.png!mobile

commit 记录我们可以看出来, dev 分支是基于 hotfix 合并后的 master ,自然而然的成为了最领先的分支,而且没有 mergecommit 记录,是不是感觉很舒服了。

我们在使用 rebase 合并分支时,也会出现 conflict ,在这种情况下, git 会停止 rebase 并会让你去解决冲突。在解决完冲突后,用 git add 命令去更新这些内容。然后再次执行 git rebase --continue ,这样 git 会继续应用余下的 patch 补丁文件。

假如我们现在不想在执行这次 rebase 操作了,都可以通过 --abort 回到开始前状态:

git rebase --abort

rebase 是存在危险的操作 - 慎用

我们现在使用 rebase 操作看起来是完美的,但是他也是存在一定危险的,下面我们就一起来看一看。

现在假设我们在 dev 分支进行开发,执行了 rebase 操作后,在提交代码到远程之前,是这样的:

zqMbieY.png!mobile

提交 dev 分支到远程代码仓库后,就变成了这样:

V7nEVfy.png!mobile

而此时你的同事也在 dev 上开发,他的分支依然还是以前的 dev ,并没有进行同步 master

6RFFN3Y.png!mobile

那么当他 pull 远程 master 的时候,就会有丢失提交纪录。这就是为什么我们经常听到有人说 git rebase 是一个危险命令,因为它改变了历史,我们应该谨慎使用。

不过,如果你的分支上需要 rebase 的所有 commits 历史还没有被 push 过,就可以安全地使用 git-rebase 来操作。

总结

asong 的细心讲解下,姐姐完全搞懂了怎么使用 git rebase ,我们来看一下姐姐的总结:

  • 当我们在一个过时的分支上面开发的时候,执行 rebase 以此同步 master 分支最新变动;
  • 假如我们要启动一个放置了很久的并行工作,现在有时间来继续这件事情,很显然这个分支已经落后了。这时候需要在最新的基准上面开始工作,所以 rebase 是最合适的选择。
  • git-rebase 很完美,解决了我们的两个问题:

    commit
    merge
    
  • 使用 rebase 操作要注意一个问题,如果你的分支上需要 rebase 的所有 commits 历史还没有被 push 过,就可以安全地使用 git-rebase 来操作。

看来姐姐是真的学会了,那你们呢?

没有学会不要紧,亲自试验一下才能更好的理解呦~~~。

好啦这一篇文章到这里就结束了,我们下期见。

结尾给大家发一个小福利吧,最近我在看[微服务架构设计模式]这一本书,讲的很好,自己也收集了一本PDF,有需要的小伙可以到自行下载。获取方式:关注公众号:[Golang梦工厂],后台回复:[微服务],即可获取。

我翻译了一份GIN中文文档,会定期进行维护,有需要的小伙伴后台回复[gin]即可下载。

我是asong,一名普普通通的程序猿,让我一起慢慢变强吧。我自己建了一个 golang 交流群,有需要的小伙伴加我 vx ,我拉你入群。欢迎各位的关注,我们下期见~~~

J7BZRv.jpg!mobile


Recommend

  • 8

    在我们日常工作中,代码写着写着就出现下列的一些臭味。但是还好我们有SOLID这把‘尺子’, 可以拿着它不断去衡量我们写的代码,除去代码臭味。这就是我们要学习SOLID原则的原因所在。 设计的臭味 僵化性 具有联动性,...

  • 20
    • segmentfault.com 4 years ago
    • Cache

    Git 看这一篇就够了

    上一篇讲 Git 的文章发出来没想到效果特别好,很多读者都要求继续深入的写。 那今天齐姐简单讲下 Git 的实现原理,知其所以然才能知其然;并且梳理了日常最常用的 12 个命令,分为三大类分享给你。 本文的结构如下:

  • 6
    • www.androidchina.net 3 years ago
    • Cache

    一篇文章,教你学会Git

    在日常工作中,经常会用到Git操作。但是对于新人来讲,刚上来对Git很陌生,操作起来也很懵逼。本篇文章主要针对刚开始接触Git的新人,理解Git的基本原理,掌握常用的一些命令。 一、Git工作流程 以上包括一些简单而...

  • 37

    原文链接 前言 嗨,everybody,我是asong,这是我的第十二篇文章,今天给大家介绍一下雪花算法。介绍雪花算法是次要的,因为大家都太熟悉了,主...

  • 74
    • segmentfault.com 6 years ago
    • Cache

    了解NodeJS看这一篇就够了

    了解NodeJS看这一篇就够了

  • 82
    • 微信 mp.weixin.qq.com 6 years ago
    • Cache

    关于Jvm知识看这一篇就够了

  • 95
    • 微信 mp.weixin.qq.com 6 years ago
    • Cache

    关于 JVM 知识看这一篇就够了

    关于 JVM 知识看这一篇就够了

  • 72

    介绍Kotlin编程语言的基础知识,以及如何在Android开发中使用Kotlin

  • 81
    • 掘金 juejin.im 6 years ago
    • Cache

    RxJava2 只看这一篇文章就够了

    本文由 玉刚说写作平台 提供写作赞助 原作者:ZedeChan 版权声明:本文版权归微信公众号 玉刚说 所有,未经许可,不得以任何形式转载 0. 简介 RxJava 其实就是提供一套异步编程的 API,这套 API 是基于观察者模式的,而且是链式调用的,所以

  • 56

    营销文案写作十五字诀:懂策略、说人话、吸眼球、有人味、促销售。 一、营销文案写作十五字诀:懂策略 首先我们要问:什么是策略? 其实,策略是一个抽象、难以理解、没有统一标准的词汇。原本是不应该拿来作为通俗理论来阐述,因为这增加了读者的阅读与理解的障碍...

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK