引言
最近我在学习 Git,其中有一章节讲到了Git 集成使用的禁忌,恰巧在工作中也遇到了类似的问题,我利用这篇文章记录一下相关知识和实践。读完这篇文章,可以明白在集成分支和私有分支上可以做什么,不可以做什么。
集成分支使用的禁忌
禁止向集成分支执行修改历史的操作
场景
以 master 分支为例,master 分支是一个集成分支,我在 master 分支上开发,我提交了一个节点并推送到了远程,然后我发现有一些内容忘记提交了,我采用 --amend 的方式向该节点增加了一些内容,然后强行推送到远程,这时报错了,我以为是远程有别的提交,我就拉取远程代码并与本地的代码进行合并,合并后向远程推送还是无法推送成功。
解释出现该现象的原因
当我第一次提交节点并推送到远程之后,情况是这样的:
本地:
a --- b (master,origin/master)
远程:
a --- b (origin/master)
然后我发现有内容我忘记提交了,我就采用 --amend 的方式向该节点增加了一些内容。但是由于禁止强行推送内容到 master,所以这里报错了。
本地:
a --- b' (master,origin/master)
远程:
a --- b (origin/master)
我当时没有理解到这一层,还以为是远程 master 上有别人的新提交,所以我拉取了远程的代码到本地并进行了合并操作,之后的示意图是这样的,这样更没有办法向远程推送了。
本地:
a --- b' --- c (master)
\ /
-- b ---- (origin/master)
远程:
a --- b (origin/master)
总结起来出现该问题的原因是:
- 不了解 master 分支上强行推送代码是不被接受的。
- 向集成分支强行推送了代码。
- 当推送不上去代码的时候没有看本地和远程的提交历史,直接拉取合并了代码。
注:
查看本地分支提交图
git log --oneline --graph -n 5
查看远程分支提交图
- 查看远程的分支列表
git branch -r
- 选择其中一个用 log 进行查看
git log --graph --oneline --decorate origin/feature-xyz
- 如果选择查看远程分支的且本地分支没有的提交
git log origin/master ^master --graph --oneline
我以上的场景是在 master 上进行开发,强行推送是根本就不会被接受的,那我如果是在某个非 master 的集成分支上强行推送呢?注意,也是不行的,即使能够推上去,也是不能强行推送的。
那为什么不能强行推送呢?强行推送会带来哪些不好的结果呢?
强行推送带来的直接后果是会改变远程分支的提交历史,而远程分支的提交历史一旦改变,其他同事在拉取代码的时候会造成不便:
- 如果合并的话会产生分叉,提交历史不清晰,而且合并时可能会产生冲突。
- 如果不合并还需要进行 rebase 操作。
比如远程由于我的强行推送,变成了 a---b---c'---d
同事本地是 a---b---c---e
同事如果不想产生分叉的话还需要 rebase 这个远程分支,
同事的本地分支就会变成 a---b---c'---d---c'---e'
再来回顾一下 rebase 的操作,比如此场景下的 rebase
- 找出本地提交和远程的分叉点,这里是 b
- 暂存本地提交 c 和 e
- 将暂存的本地提交 c 和 e 依次应用到远程最新的 commit 的后面,最终本地分支变成了:
a---b---c'---d---c'---e'
规律总结与最佳实践
- 公共分支和集成分支禁止改写历史,不能使用--amend、rebase、push -f,如果想要修复已有的提交,必须要新增提交。
- 私有分支为了保持提交历史的简洁和线性,可以使用 --amend 和 rebase,在确保远程分支没有被其他人使用的情况下可以 push -f
参考
- [玩转 Git 三剑客]time.geekbang.org/course/intr…