rebase in git

相信对于很多使用git的用户来说, rebase 和 merge像两个恶梦一样, 到底应该是从哪个branch rebase/merge 到哪个branch? rebase和merge又有什么区别?

我先回答一下第一问题:
如果你想把feature branch rebase/merge到master branch. 你得从feature branch rebase onto / merge into 到 master branch.
具体做法是先checkout feature branch, 然后执行: git rebase/merge master.

然后我们讲一下rebase的使用方法, 关于merge请见我的另一篇博客https://blog.csdn.net/seamanj/article/details/104057987

好了, 下面我会把每一步的操作以及tree的结构给贴出来:

假设我们有两个branch:master 和 feature,


我们先在master提交一个commit名为master1, 树结构长这样

D:\Workspace\GIT_TEST>git log --graph --decorate --oneline --all
* 7add0d0 (HEAD -> master, origin/master) master1
* 1531f85 initial commit

在这里插入图片描述


然后我们需要开发另一个feature功能, 这时我们建立一个feature branch 并checkout, 在feature branch上面我们提交两个commit, feature1, feature2

D:\Workspace\GIT_TEST>git log --graph --decorate --oneline --all
* 0adde55 (HEAD -> feature, origin/feature) feature2
* 7e427bf feature1
* 7add0d0 (origin/master, master) master1
* 1531f85 initial commit

在这里插入图片描述


同时, 在我们开发feature的同时, 假设有人在master上面做了新的commit: master2

D:\Workspace\GIT_TEST>git log --graph --decorate --oneline --all
* 386e693 (origin/master) master2
| * 0adde55 (origin/feature, feature) feature2
| * 7e427bf feature1
|/
* 7add0d0 (HEAD -> master) master1
* 1531f85 initial commit

在这里插入图片描述


现在我们需要把feature branch rebase(onto)到master branch 上面去. 我们需要在master branch 上面先做pull, 把别人在master上面的修改先pull下来

D:\Workspace\GIT_TEST>git log --graph --decorate --oneline --all
* 386e693 (HEAD -> master, origin/master) master2
| * 0adde55 (origin/feature, feature) feature2
| * 7e427bf feature1
|/
* 7add0d0 master1
* 1531f85 initial commit

在这里插入图片描述
然后跳到feature branch, 执行git rebase master

D:\Workspace\GIT_TEST>git checkout feature
Switched to branch 'feature'
Your branch is up to date with 'origin/feature'.

D:\Workspace\GIT_TEST>git rebase master
First, rewinding head to replay your work on top of it...
Applying: feature1
Applying: feature2

D:\Workspace\GIT_TEST>git log --graph --decorate --oneline --all
* 848d675 (HEAD -> feature) feature2
* 3b1fa65 feature1
* 386e693 (origin/master, master) master2
| * 0adde55 (origin/feature) feature2
| * 7e427bf feature1
|/
* 7add0d0 master1
* 1531f85 initial commit

在这里插入图片描述
最后我们需要跳回到master branch, 执行git rebase feature, 使得master指针指向最前面

> D:\Workspace\GIT_TEST>git checkout master
Switched to branch 'master'
Your branch is up to date with 'origin/master'.

D:\Workspace\GIT_TEST>git rebase feature
First, rewinding head to replay your work on top of it...
Fast-forwarded master to feature.

D:\Workspace\GIT_TEST>git log --graph --decorate --oneline --all
* 848d675 (HEAD -> master, feature) feature2
* 3b1fa65 feature1
* 386e693 (origin/master) master2
| * 0adde55 (origin/feature) feature2
| * 7e427bf feature1
|/
* 7add0d0 master1
* 1531f85 initial commit

在这里插入图片描述


最后我们将master branch push 到远程端

D:\Workspace\GIT_TEST>git push
Enumerating objects: 5, done.
Counting objects: 100% (5/5), done.
Delta compression using up to 12 threads
Compressing objects: 100% (4/4), done.
Writing objects: 100% (4/4), 431 bytes | 431.00 KiB/s, done.
Total 4 (delta 1), reused 0 (delta 0)
To https://gitlab.com/seamanj/git_rebase_test.git
   386e693..848d675  master -> master

D:\Workspace\GIT_TEST>git log --graph --decorate --oneline --all
* 848d675 (HEAD -> master, origin/master, feature) feature2
* 3b1fa65 feature1
* 386e693 master2
| * 0adde55 (origin/feature) feature2
| * 7e427bf feature1
|/
* 7add0d0 master1
* 1531f85 initial commit

在这里插入图片描述


okay, 现在 master branch上面完事了, 现在本地的feature 指针已经跑到master branch上面去了, 而远程的feature 指针还在原处不动. 那feature branch怎么收场呢?
具体可以参考 :https://stackoverflow.com/questions/42861353/git-pull-after-git-rebase

大概有三种结尾方式

  1. 如果现在你要pull远程的feature指针的话, 会创造一个新的merge. 然而这并没有任何意义, 也会导致大量的冲突(因为rebase已经合并过一次了)
  2. reset 本地的feature 指针 到远程的feature 指针, 这时本地的指针会指向远程的指针, 但是好像还是没有任何意义, 因为功能已经合并到master上面去了, 这时候继续在上面开发, 无论以后再次rebase或merge到master 都会造成大量的冲突(feature1, feature2会冲突)
  3. 通过 git push -f 强行push本地指针到远程指针, 这时远程指针也会跟着跳到master branch上面来, 而原来的feature branch就不复存在了.这种方法比有意义, 因为我可以随时从feature rebase 到 master顶端(先爬到顶端), 然后开发feature 3, feature 4 等等(然后生枝), 又可以继续rebase/merge到master(然后将枝移到顶端).

下面我们来试一下第3种方式

我们先跳到feature branch, 然后通过 git push 将本地push到远端

D:\Workspace\GIT_TEST>git checkout feature
Switched to branch 'feature'
Your branch and 'origin/feature' have diverged,
and have 3 and 2 different commits each, respectively.
  (use "git pull" to merge the remote branch into yours)

D:\Workspace\GIT_TEST>git push
To https://gitlab.com/seamanj/git_rebase_test.git
 ! [rejected]        feature -> feature (non-fast-forward)
error: failed to push some refs to 'https://gitlab.com/seamanj/git_rebase_test.git'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Integrate the remote changes (e.g.
hint: 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.

这时会提示错误, 这是因为本地的feature指针跳到master branch上面来了. 在原来的feature branch上, 本地的feature指针落后远程2步, 而在master branch上, 本地的feature指针领先远程3步

这时我们只有通过git push -f 霸王硬上弓了

D:\Workspace\GIT_TEST>git push -f
Total 0 (delta 0), reused 0 (delta 0)
remote:
remote: To create a merge request for feature, visit:
remote:   https://gitlab.com/seamanj/git_rebase_test/-/merge_requests/new?merge_request%5Bsource_branch%5D=feature
remote:
To https://gitlab.com/seamanj/git_rebase_test.git
 + 0adde55...848d675 feature -> feature (forced update)

D:\Workspace\GIT_TEST>git log --graph --decorate --oneline --all
* 848d675 (HEAD -> feature, origin/master, origin/feature, master) feature2
* 3b1fa65 feature1
* 386e693 master2
* 7add0d0 master1
* 1531f85 initial commit

在这里插入图片描述
舒服了


然后我们继续在feature branch开发feature 3

D:\Workspace\GIT_TEST>git log --graph --decorate --oneline --all
* 466f0cc (HEAD -> feature, origin/feature) feature3
* 848d675 (origin/master, master) feature2
* 3b1fa65 feature1
* 386e693 master2
* 7add0d0 master1
* 1531f85 initial commit

在这里插入图片描述


与此同时, 其他人在master branch上继续开发master3

D:\Workspace\GIT_TEST>git log --graph --decorate --oneline --all
* f9bc42e (HEAD -> master, origin/master) master3
| * 466f0cc (origin/feature, feature) feature3
|/
* 848d675 feature2
* 3b1fa65 feature1
* 386e693 master2
* 7add0d0 master1
* 1531f85 initial commit

在这里插入图片描述
这样的分叉, 是否曾经相似, 至此, 我们可以继续选择rebase或者merge而不必担心feature1, feature2所带来的冲突了, 但是记住原来的feature branch已经不见了


参考资料:

rebase视频详解及动画过程: https://www.youtube.com/watch?v=f1wnYdLEpgI
rebase 和 merge 优缺点以及如何选择:https://dzone.com/articles/git-merge-vs-rebase

发布了755 篇原创文章 · 获赞 195 · 访问量 104万+

猜你喜欢

转载自blog.csdn.net/seamanj/article/details/105086200