bfchengnuo / MyRecord

平时充电做的笔记,一个程序猿的自我修养.
https://bfchengnuo.com/MyRecord/
33 stars 8 forks source link

Git中的merge和rebase #48

Closed bfchengnuo closed 4 years ago

bfchengnuo commented 4 years ago

虽然用 Git 的时间不短了,但是要么是自己一个人玩,要么就是非常简单的用,感觉根本没有用出真正的效率来,今天看到了有人在说 merge 和 rebase,脑袋中有点印象,按道理这俩应该用的是很频繁的才对。

借此机会做一下笔记,预感以后肯定会用到。

bfchengnuo commented 4 years ago

git pull 是 git fetch + git merge FETCH_HEAD 的缩写。所以,默认情况下,git pull 就是先 fetch,然后执行 merge 操作,如果加 –rebase 参数,就是使用 git rebase 代替 git merge。

merge 和 rebase

merge 是合并的意思,rebase是复位基底的意思。

现在我们有这样的两个分支:test 和 master,提交如下:

       D---E test
      /
 A---B---C---F master

在 master 执行 git merge test,然后会得到如下结果:

       D--------E
      /          \
 A---B---C---F----G   test, master

在 master 执行 git rebase test,然后得到如下结果:

A---B---D---E---C'---F' test, master

merge 操作会生成一个新的节点,之前的提交分开显示。而 rebase 操作不会生成新的节点,是将两个分支融合成一个线性的提交。


marge 特点:自动创建一个新的 commit;如果合并的时候遇到冲突,仅需要修改后重新 commit。 优点:记录了真实的 commit 情况,包括每个分支的详情; 缺点:因为每次 merge 会自动产生一个 merge commit,所以在使用一些 git 的 GUI tools,特别是 commit 比较频繁时,看到分支很杂乱。

rebase 特点:会合并之前的 commit 历史。 优点:得到更简洁的项目历史,去掉了 merge commit; 缺点:如果合并出现代码问题不容易定位,因为 re-write 了 history;

发生冲突时

在我们操作过程中。merge 操作遇到冲突的时候,当前 merge 不能继续进行下去。手动修改冲突内容后,add 修改,commit 就可以了。

而 rebase 操作的话,会中断 rebase,同时会提示去解决冲突。解决冲突后,将修改 add 后执行 git rebase –continue 继续操作(不要顺手直接 commit 了啊!),或者 git rebase –skip 忽略冲突。

参考

https://gist.github.com/68681395/9d2789f38fb62e60b9fa0d0c4a7d4511

bfchengnuo commented 4 years ago

使用规范

如果使用 rebase 将所有 master 的 commit 移动到你的 feature 的顶端。 然后问题是:其他人还在 original master 上开发,由于你使用了 rebase 移动了 master,git 会认为主分支的历史与其他人的有分歧,会产生冲突。

所以在执行 git rebase 之前问问自己,会有其他人看这个分支么? if YES 不要采用这种带有破坏性的修改 commit 历史的 rebase 命令; if NO ok,随你便,可以使用 rebase


在本地随便你怎么搞,而一旦被提交到远程后,这时如果再改写 history,那么势必和他人的 history 长的就不一样了。 git push 的时候,git 会比较 commit history,如果不一致,commit 动作会被拒绝,唯一的办法就是带上 -f 参数,强制要求 commit,这时 git 会以 committer 的 history 覆写远程 repo,从而完成代码的提交。 虽然代码提交上去了,但是这样可能会造成别人工作成果的丢失,所以使用 -f 参数要慎重。

所以,在不用 -f 的前提下,想维持树的整洁,方法就是:在 git push 之前,先 git fetch,再 git rebase。

除非只有自己一个人用,不然用 push --force 的都该去死。

参考:https://segmentfault.com/q/1010000000430041