git rebase

分支合并

我们先在 master 分支的基础上新建一个 dev 分支, 并做一个 commit:
在这里插入图片描述
这时候另外一个开发人员发现 master 上的代码有一个问题,对 master 的代码做了一个 fix,使得 master 的 head 向前推进了一步:
在这里插入图片描述
如果我们想将 master 的 Fix 改动应用到 dev 分支上,要如何做呢?
$(dev) git merge master
在这里插入图片描述
dev 上 多出来的这个 commit(绿色的那个节点), 就是我们的 merge 信息。
有时候我们并不想要 git 记录这个 merge 信息,因为让 git 的历史记录变得很繁琐,要如何做呢?可以使用 rebase !
我们先回到 master 提交了 fix 之后的 git 状态:

在这里插入图片描述
$ (dev) git rebase master
在这里插入图片描述
比较下 merge 和 rebase 之后的状态图,我们可以发现 masste 的 fix 被接到 dev 的后面,并且没有多出一个 merge 信息。

什么时候用rebase和merge选择

在合并代码时,选择 git rebase master 还是 git merge --no-ff master 取决于团队的工作流程以及你对提交历史的需求。两者的主要区别在于提交历史的处理方式:

  1. git rebase master
    使用 rebase 是将你的分支上的提交“平铺”在 master 分支的最新提交之上,最终提交历史是线性的。
git checkout feature
git rebase master

特点

  • 线性历史:提交历史将是线性的,更加简洁。
  • 重写历史rebase 会重新写入你分支上的提交,修改提交的父节点,因此它会改变提交 ID。
  • 避免额外的合并提交:只包含分支上的提交,不会创建额外的合并提交。

适用场景

  • 在将 feature 分支合并到 master 分支之前,通过 rebase 来保持提交历史的整洁。
  • 适用于代码库的风格要求提交历史线性、简洁的团队。
  • 注意:如果其他开发者也在使用该分支,使用 rebase 可能会导致冲突,因为 rebase 会重写提交历史。
  1. git merge --no-ff master
    merge --no-ff 命令进行的是普通合并,将 master 分支的内容合并到当前分支,并创建一个新的合并提交来记录这次合并。
git checkout feature
git merge --no-ff master

特点

  • 保留分支历史:保留了分支点和合并点的提交信息,可以看到每个分支的开发过程。
  • 不会重写历史:与 rebase 不同,merge 不会更改提交 ID。
  • 创建合并提交--no-ff 强制创建一个合并提交,即使 feature 分支可以直接快速前进(fast-forward)。

适用场景

  • 适用于需要保留分支信息的大型项目,通过合并提交可以清楚看到不同的功能或问题修复分支。
  • 当项目团队希望使用“合并提交”来记录分支合并时。
  • 团队工作流程鼓励保留所有分支信息,以便于回溯和查看分支变更记录。
什么时候使用哪个?
  • 使用 git rebase master:如果你想让提交历史看起来更简洁,并且你是唯一使用该分支的开发人员。
  • 使用 git merge --no-ff master:如果你希望保留分支的分叉和合并点,以更清晰地展示开发过程,尤其是团队开发或代码审核中,可以更容易看到分支的来源和合并点。

总结

  • rebase:适用于想要平滑、简洁的提交历史。通常在个人开发分支上使用,并最终 rebase 到主分支后合并。
  • merge --no-ff:适用于希望保留分支合并信息,提供清晰的合并记录,适合团队合作的大项目。

git rebase -i 是 Git 中的交互式变基(interactive rebase)命令,允许你在重写提交历史时进行细粒度的控制。它常用于合并提交、修改提交信息、删除提交、重新排序提交等。以下是 git rebase -i 的详细用法和步骤:

合并多个commit为一个commit

当我们在本地仓库中提交了多次,在我们把本地提交push到公共仓库中之前,为了让提交记录更简洁明了,我们希望把如下分支B、C、D三个提交记录合并为一个完整的提交,然后再push到公共仓库。
在这里插入图片描述
现在我们在测试分支上添加了四次提交,我们的目标是把最后三个提交合并为一个提交:
在这里插入图片描述
这里我们使用命令:

  git rebase -i  [startpoint]  [endpoint]

其中-i的意思是–interactive,即弹出交互式的界面让用户编辑完成合并操作,[startpoint] [endpoint]则指定了一个编辑区间,如果不指定[endpoint],则该区间的终点默认是当前分支HEAD所指向的commit(注:该区间指定的是一个前开后闭的区间)。

默认参数

  • git rebase -i 后面没有参数时,相当于隐式使用 git rebase -i <upstream>,其中 <upstream> 是当前分支与其父分支的分叉点。
  • 这个行为通常用于整理或修改当前分支上的所有提交,而不影响父分支上的提交历史。

在查看到了log日志后,我们运行以下命令:

git rebase -i 36224db

git rebase -i HEAD~3 

然后我们会看到如下界面:
在这里插入图片描述
上面未被注释的部分列出的是我们本次rebase操作包含的所有提交,下面注释部分是git为我们提供的命令说明。每一个commit id 前面的pick表示指令类型,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)

根据我们的需求,我们将commit内容编辑如下:
在这里插入图片描述
然后是注释修改界面:
在这里插入图片描述
编辑完保存即可完成commit的合并了:
在这里插入图片描述

解决冲突

在变基过程中,你可能会遇到合并冲突。Git 会提示你哪些文件有冲突,你需要手动解决冲突,解决完成后执行以下命令继续变基:

git add <resolved-files>
git rebase --continue

如果想中止变基操作,可以使用:

git rebase --abort

官网:https://git-scm.com/docs/git-rebase

上一篇:【Linux进程信号】Linux信号机制深度解析:保存与处理技巧-????1. 信号的保存


下一篇:linux环境下C程序的编译过程以及makefile的简单使用