Git教程十九:分支管理之Rebase
在上一節我們看到了,多人在同一個分支上協作時,很容易出現衝突。即使沒有衝突,後push的童鞋不得不先pull,在本地合併,然後才能push成功。
每次合併再push後,分支變成了這樣:
$ git log --graph --pretty=oneline --abbrev-commit
* d1be385 (HEAD -> master, origin/master) init hello
* e5e69f1 Merge branch 'dev'
|\
| * 57c53ab (origin/dev, dev) fix env conflict
| |\
| | * 7a5e5dd add env
| * | 7bd91f1 add new env
| |/
* | 12a631b merged bug fix 101
|\ \
| * | 4c805e2 fix bug 101
|/ /
* | e1e9c68 merge with no-ff
|\ \
| |/
| * f52c633 add merge
|/
* cf810e4 conflict fixed
總之看上去很亂,有強迫症的童鞋會問:為什麼Git的提交歷史不能是一條幹淨的直線?
其實是可以做到的!
Git有一種稱為rebase的操作,有人把它翻譯成“變基”。
先不要隨意展開想象。我們還是從實際問題出發,看看怎麼把分叉的提交變成直線。
在和遠端分支同步後,我們對hello.py這個檔案做了兩次提交。用git log命令檢視:
$ git log --graph --pretty=oneline --abbrev-commit
* 582d922 (HEAD -> master) add author
* 8875536 add comment
* d1be385 (origin/master) init hello
* e5e69f1 Merge branch 'dev'
|\
| * 57c53ab (origin/dev, dev) fix env conflict
| |\
| | * 7a5e5dd add env
| * | 7bd91f1 add new env
...
注意到Git用(HEAD -> master)和(origin/master)標識出當前分支的HEAD和遠端origin的位置分別是582d922 add author和d1be385 init hello,本地分支比遠端分支快兩個提交。
現在我們嘗試推送本地分支:
$ git push origin master
To github.com:michaelliao/learngit.git
! [rejected] master -> master (fetch first)
error: failed to push some refs to 'git@github.com:michaelliao/learngit.git'
hint: Updates were rejected because the remote contains work that you do
hint: not have locally. This is usually caused by another repository pushing
hint: to the same ref. You may want to first integrate the remote changes
hint: (e.g., 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.
很不幸,失敗了,這說明有人先於我們推送了遠端分支。按照經驗,先pull一下:
$ git pull
remote: Counting objects: 3, done.
remote: Compressing objects: 100% (1/1), done.
remote: Total 3 (delta 1), reused 3 (delta 1), pack-reused 0
Unpacking objects: 100% (3/3), done.
From github.com:michaelliao/learngit
d1be385..f005ed4 master -> origin/master
* [new tag] v1.0 -> v1.0
Auto-merging hello.py
Merge made by the 'recursive' strategy.
hello.py | 1 +
1 file changed, 1 insertion(+)
再用git status看看狀態:
$ git status
On branch master
Your branch is ahead of 'origin/master' by 3 commits.
(use "git push" to publish your local commits)
nothing to commit, working tree clean
加上剛才合併的提交,現在我們本地分支比遠端分支超前3個提交。
用git log看看:
$ git log --graph --pretty=oneline --abbrev-commit
* e0ea545 (HEAD -> master) Merge branch 'master' of github.com:michaelliao/learngit
|\
| * f005ed4 (origin/master) set exit=1
* | 582d922 add author
* | 8875536 add comment
|/
* d1be385 init hello
...
對強迫症童鞋來說,現在事情有點不對頭,提交歷史分叉了。如果現在把本地分支push到遠端,有沒有問題?
有!
什麼問題?
不好看!
有沒有解決方法?
有!
這個時候,rebase就派上了用場。我們輸入命令git rebase試試:
$ git rebase
First, rewinding head to replay your work on top of it...
Applying: add comment
Using index info to reconstruct a base tree...
M hello.py
Falling back to patching base and 3-way merge...
Auto-merging hello.py
Applying: add author
Using index info to reconstruct a base tree...
M hello.py
Falling back to patching base and 3-way merge...
Auto-merging hello.py
輸出了一大堆操作,到底是啥效果?再用git log看看:
$ git log --graph --pretty=oneline --abbrev-commit
* 7e61ed4 (HEAD -> master) add author
* 3611cfe add comment
* f005ed4 (origin/master) set exit=1
* d1be385 init hello
...
原本分叉的提交現在變成一條直線了!這種神奇的操作是怎麼實現的?其實原理非常簡單。我們注意觀察,發現Git把我們本地的提交“挪動”了位置,放到了f005ed4 (origin/master) set exit=1之後,這樣,整個提交歷史就成了一條直線。rebase操作前後,最終的提交內容是一致的,但是,我們本地的commit修改內容已經變化了,它們的修改不再基於d1be385 init hell,而是基於f005ed4 (origin/master) set exit=1,但最後的提交7e61ed4內容是一致的。
這就是rebase操作的特點:把分叉的提交歷史“整理”成一條直線,看上去更直觀。缺點是本地的分叉提交已經被修改過了。
最後,通過push操作把本地分支推送到遠端:
Mac:~/learngit michael$ git push origin master
Counting objects: 6, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (5/5), done.
Writing objects: 100% (6/6), 576 bytes | 576.00 KiB/s, done.
Total 6 (delta 2), reused 0 (delta 0)
remote: Resolving deltas: 100% (2/2), completed with 1 local object.
To github.com:michaelliao/learngit.git
f005ed4..7e61ed4 master -> master
再用git log看看效果:
$ git log --graph --pretty=oneline --abbrev-commit
* 7e61ed4 (HEAD -> master, origin/master) add author
* 3611cfe add comment
* f005ed4 set exit=1
* d1be385 init hello
...
遠端分支的提交歷史也是一條直線。
小結
rebase操作可以把本地未push的分叉提交歷史整理成直線;
rebase的目的是使得我們在檢視歷史提交的變化時更容易,因為分叉的提交需要三方對比。
相關文章
- git分支管理--rebase&merge詳解Git
- git學習之git rebaseGit
- git 入門教程之分支管理Git
- git rebase master 分支出現一堆 ^MGitAST
- 合併分支:Git merge 和 rebase 的區別Git
- git 中 rebase 是什麼樣的操作,應該從哪個分支rebase到哪個分支Git
- Git 分支管理Git
- Git merge和rebase分支合併命令的區別Git
- Git基礎命令之git rebase命令Git
- git-分支管理Git
- Git——分支管理(2)Git
- [Git]rebaseGit
- git rebaseGit
- Git -- RebaseGit
- Git 分支管理規範Git
- git分支基本管理規範Git
- git rebase 和 git mergeGit
- Git——rebase命令Git
- git rebase -iGit
- git rebase 流程Git
- git rebase masterGitAST
- git分支管理及git commit message規範GitMIT
- Git 系列教程(14)- 遠端分支Git
- GIT分支管理規劃說明Git
- git 基本操作|分支管理|gitlib使用Git
- Git分支管理,運維知道嗎?Git運維
- 如何理解git rebase?Git
- git rebase的使用Git
- [Git] Git整理(四) git rebase 的使用Git
- git 入門教程之分支策略Git
- Git(12)-- Git 分支 - 分支簡介Git
- Git rebase 與 Git merge 的使用Git
- Git三大特色之Branch(分支)Git
- 一種新的Git分支管理策略Git
- 【Git】程式碼許可權&分支管理Git
- 【第七篇】- Git 分支管理Git
- git 入門教程之分支總覽Git
- git分支Git