Git subtree 要不要使用 –squash 參數

關於 Git Subtree 的一些使用細節,有的小夥伴可能不是很清楚,小編髮現網上有一篇將要不要加 --squash 參數的文章講的挺好的,因此這裏和大家分享下。

原文地址:
http://www.fwolf.com/blog/post/246

問題的產生

subtree 處理多層包含是沒有問題的,因爲包含進項目之後,別人根本看不出這是一個 subtree, 所以它本質上還只是管理本地 repo 的一種方法。

使用 Git subtree 新建或更新子項目的時候,可以選用 --squash 參數, 它的作用就是把 subtree 子項目的更新記錄進行合併,再合併到主項目中。

所以,在使用 --squash 參數的情況下, subtree add 或者 pull 操作的結果對應兩個 commit, 一個是 Squash 了子項目的歷史記錄, 一個是 Merge 到主項目中。

這種做法下,主項目的歷史記錄看起來還是比較整齊的。但在子項目有更新,需要 subtree pull 的時候,卻經常需要處理衝突。嚴重的,在每次 subtree pull 的時候都需要重複處理同樣的衝突,非常煩人。

如果不使用 --squash 參數,子項目更新的時候,subtree pull 很順利, 能夠自動處理已解決過的衝突,缺點就是子項目的更新記錄“污染”了主項目的。

原因分析

簡單說,subtree add/pull 操作中,需要用到 merge,而 merge 順利進行的前提, 是要有相同的 parent commit。對照上面的情況:

使用 --squash 參數,原子項目歷史記錄被合併後就消失了,相當於一個“新”的提交。下次再進行 add/pull 時,新添加的內容找不到“上一次的修改”, 於是在更新 subtree 內文件的時候,就會提示衝突,需要手工解決。

不使用 --squash 參數,原子項目的歷史複製到了父項目中, 下次再進行 add/pull 時,新增的 commit 能夠找到“上一次的修改”, 那麼他會像在子項目中逐個 am patch 那樣更新 subtree 下的內容, 不會提示衝突。

注:我使用的 Git subtree 是 PPA 上的一箇舊版本,或許新版已經解決了上面的問題。

解決問題

是否使用 squash 都是可以的, 但需要在開始階段作出選擇,並一直堅持下去 。如果一會兒用一會兒不用,得到的不是兩者的優點,而是兩者的缺點之和。

出於個人偏好,我既希望能夠比較順利的更新子項目, 又不希望子項目的歷史記錄直接合並在主項目中。

StackOverflow 上有人提到了一種做法 , 就是另外建立一個分支進行 –no-squash 的 subtree 更新, 這樣就保留了子項目的歷史記錄,沒有煩人的反覆衝突問題;然後在合併到主分支(比如 master)時合併提交( git merge --squash ), 這樣主項目的主分支上只會體現一個 commit, 比直接 git subtree add/pull --squash 還要簡潔。

這種做法也有缺點,但在能夠接受的範圍內:

  • 新開分支的歷史記錄比較亂,無視吧
  • 新開分支與 master 分支不同步,記着每次在新開分支上做 subtree 操作之前 要 merge master

在新開分支上進行 subtree split 操作是沒有問題的。merge master 以後,subtree push 操作也沒有大問題, 也許剛開始會出現 push 被 reject 的狀況。

在這種情況下,可以先在本地 split 一份,比如 git subtree split -P extlib/magpierss -b test --rejoin , 然後切換到這個 test 分支,可以看到之所以被 reject , 是因爲主項目的那個合併提交也被 split 出來了。這裏會麻煩一些,需要通過 rebase 操作,把這些合併的提交刪掉, 換成合並內容包含的每個提交(用 pick HASH)。成功之後,可以在這個分支直接 push 到 子項目:git push remote_of_subtree
branch_on_local:branch_on_remote , 注意後面是指定將本地的哪個分支 push 進 remote 的哪個分支。這次 push 會很順利。接下來再做一次正常的 subtree pull 就可以了, 下次再進行 subtree split 操作時, split 出來的臨時分支和 remote 是一致的。

通過上面 push 的例子可以看出,爲了 split 和 push 順利, 即使用了 subtree 分支, 如果能在 master 分支中保存的項目歷史記錄還是有好處的。同時,我們還可以參考這個來決定 subtree 使用策略:

  • subtree 裏面放外圍項目,只接收更新,不發送更新, 那麼無論是用 squash 還是用 subtree 分支都不麻煩。
  • 將一個大項目拆分成若干小項目, 那麼最好不要用 squash,並且活用 subtree, 最好是所有提交都在主項目中作, 然後 subtree split 出子項目來發布, 子項目原則上不直接修改,即和上一條相反, 只向子項目發送更新,不從子項目接收更新。Symfony2 使用的就是這種做法。

總體上都有些麻煩,subtree 分支算不上是完美解決方法,但看起來好歹清爽了很多。

推薦閱讀:線上遠程京東技術三面+HR面,五月中旬成功就職京東,月薪30K

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章