用了以後, 樹可以非常清晰, 某種程度上便於追踪, 但是 push --force
就多多了,
不用呢, 合併沒有遠端倉庫被修改的麻煩, 可是追蹤又不清晰...
怎麼取捨? 團隊裡一般怎麼取捨?
滿天的星座2017-04-25 09:04:57
git rebase
是對commit history的改寫。當你要改寫的commit history還沒有被提交到遠程repo的時候,也就是說,還沒有與他人共享之前,commit history是你私人所有的,那麼想怎麼改寫都可以。
而一旦被提交到遠端後,這時如果再改寫history,那麼勢必和他人的history長的就不一樣了。 git push
的时候,git会比较commit history,如果不一致,commit动作会被拒绝,唯一的办法就是带上-f
参数,强制要求commit,这时git会以committer的history覆写远程repo,从而完成代码的提交。虽然代码提交上去了,但是这样可能会造成别人工作成果的丢失,所以使用-f
參數要慎重。
樓主遇到的問題,就是改寫了公有的commit history造成的。 要解決這個問題,就要從提交流程上做規範。
舉個正確流程的栗子:
假設樓主的team中有兩個developer:tom和jerry,他們共同使用一個遠程repo,並各自clone到自己的機器上,為了簡化描述,這裡假設只有一個branch:master
。
這時tom機器的repo有兩個branchmaster
, origin/master
, origin/master
而jerry的機器上也是有兩個branchmaster
, origin/master
, origin/master
均如下圖
tom和jerry分別各自開發自己的新feature,不斷有新的commit提交到他們各自私有的commit history中,所以他們的master指針不斷的向前推移,分別指向不同的commit。而又由於他們都沒有git fetch
和git push
,所以他们的origin/master
都維持不變。
jerry的repo如下
tom的repo如下,注意T1
和上图的J1
,分別是兩個不同的commit
這時Tom先把他的commit提交的遠端repo中,那麼他本機origin/master
指針則會前進,和origin/master
指针则会前进,和master
指針保持一致,如下
遠端repo如下
現在jerry也想把他的commit提交到遠端repo上去,運行git push
,毫无意外的失败了,所以他git fetch
了一下,把远程repo,也就是之前tom提交的T1
給拉到了他本機repo中,如下
commit history出現了分叉,要想把tom之前提交的內容包含到自己的工作中來,有一個方法就是git merge
,它會自動生成一個commit,既包含tom的提交,也包含jerry的提交,這樣就把兩個分岔的commit重新合併在一起。但是這個自動產生的commit會有兩個parent,review程式碼的時候必須比較兩次,很不方便。
jerry為了確保commit history的線性,決定採用另一種方法,就是git rebase
。jerry的提交J1
这时还没有被提交到远程repo上去,也就是他完全私有的一个commit,所以使用git rebase
改写J1
的history完全沒有問題,改寫之後,如下
注意J1
被改写到T1
后面了,变成了J1`
git push
後,本機repo
而遠端repo
異常的輕鬆,一條直線,沒有-f
所以,在不用-f
的前提下,想维持树的整洁,方法就是:在git push
之前,先git fetch
,再git rebase
的前提下,想維持樹的整潔,方法就是:在
git fetch
,再git rebase
。
git fetch origin master
git rebase origin/master
git push
強烈建議閱讀PHPz2017-04-25 09:04:57
本地分支和遠端分支的綁定(tracking),加上 rebase 策略:
[branch "master"]
remote = origin
merge = refs/heads/master
rebase = true
這樣一來,更新程式碼(pull
)的時候就會自動套用 rebase 而不是產生 merge commit,除非有其他情況產生,例如三方合併造成了衝突需要人共去幹預。大部分時候還是很聰明的,只要團隊裡的習慣都很好,那麼可以保持一個非常乾淨漂亮的樹形。
其實想讓樹狀結構漂亮些清晰些是有很多辦法的,但首先要取決於團隊用的是什麼樣的 Git Model,對症下藥即可。在這裡就無法一言以蔽之了。
另外,樓上說得對,慎用 push -f
!
我想大声告诉你2017-04-25 09:04:57
這應該是一個git workflow的問題,我們團隊也一直在使用rebase保證commit資訊的整潔,但不會用到push -f
這樣的操作。
關於git workflow就是一個見仁見智的問題了,下面幾篇文章你可以看下,再找出一套適合自己團隊的就可以了,不過最重要的是要確保團隊的每個人都熟悉git,防止犯愚蠢的錯誤。
如果使用github來團隊合作的話,用好pull request,它可以解決push -f
這種愚蠢問題!
阿神2017-04-25 09:04:57
每個人提交前,都應該把自己的修改rebase到伺服器的最新程式碼之上,遵守這個規則就不會有任何問題。如果你需要force push,表示你做反了,把伺服器程式碼rebase到你本地分支之上才會需要force push,這是錯誤的用法。
PHP中文网2017-04-25 09:04:57
建議參考Pro Git 中關於rebase 的章節http://git-scm.com/book/zh/Git-%E5%88%86%E6%94%AF-%E5%88%86%E6%94% AF%E7%9A%84%E8%A1%8D%E5%90%88
衍合的風險
呃,奇妙的衍合也並非完美無缺,要用它得遵守一條準則:一旦分支中的提交對象發佈到公共倉庫,就千萬不要對該分支進行衍合操作。
如果你遵循這條金科玉律,就不會出差錯。否則,人民會仇恨你,你的朋友和家人也會嘲笑你,唾棄你。
就我而言。如果 rebase 完後,需要使用 push -f
的話,一定代表該 rebase 操作是不合適。除非你是有意在修改提交歷史。
伊谢尔伦2017-04-25 09:04:57
樓上的答案都很正,個人認為,除非某個分支只有你自己搞,你怎麼rebase都是沒有問題的,但是如果你在master或者develop這種分支上來rebase,估計團隊裡每個人都想拍死你,尤其是對git不熟悉的隊友,手足無措是非常正常的表現。
rebase之後push -f的情況只有一個,就是題主像我一樣有強迫症,害怕電腦宕機、系統崩潰這種蛋疼的事情(悲慘的血淚史),完成一個特性commit之後迅速push到遠程只屬於你的分支上,每天為了拿到develop的新特性,才在自己的分支上rebase develop,重複執行push的操作,這個個人認為是沒有問題的,畢竟你只影響了你自己(而你知道這是對的)。