「小技巧」使用Git從其他分支merge個別文件

  • 2019 年 10 月 3 日
  • 筆記

小明發現在實際項目開發過程中,總會遇到各種各樣的情況,比如一個大型的項目或版本迭代可能不是一次上線,可能會分好幾次上線,這時候就會涉及創建多個分支,分別開發。

項目背景

產品經理:我們本次開發三個功能,列表頁功能、詳情頁功能、系統消息功能,分兩次上線,先上列表功能,再上詳情頁和系統消息。

小明:好的吧。

緊接着,小明就將本次需求分為2個分支,分別為A、B。

  • A:開發列表頁功能
  • B:開發詳情頁功能、系統消息功能

原計劃:產品經理說先上列表功能,那小明就先開發A分支,列表功能很快開發完成(厲害吧)。

計劃有變:風雲變幻,第二天小明按照計劃開發B分支,開發到一半,產品經理突然說目前的系統消息功能(位於B分支)比較緊急,需要和列表功能(位於A分支)一起上線,當時小明就懵逼了。趕緊暫停開發詳情頁(位於B分支,雖然已經開發了一部分),轉戰系統消息功能的開發。當系統消息功能開發完成之後,就需要考慮將系統消息功能(位於B分支)和列表功能(位於A分支)放在一個分支上提測(開發一部分的詳情頁功能暫先不需要合併)的問題,這時候分支合併就要派上用場了。

分支合併

說起分支合併,大家第一個想到的命令肯定是git merge ,因為這是分支合併的常用命令。

使用git merge 合併分支會將兩個分支的所有內容進行比較合併,因此我們如果想合併兩個分支中的一部分,顯然直接使用這個命令是行不通的。

So what happens next ? 嘿嘿,有兩種方案可供我們選擇:

強制合併

從其他分支merge指定文件到當前分支,git checkout是個合適的工具。

語法如下:

git checkout source_branch <path>...

我們使用git checkout 將B分支上的系統消息功能添加到A分支上

$ git branch    * A      B    $ git checkout B message.html message.css message.js other.js    $ git status  # On branch A  # Changes to be committed:  #   (use "git reset HEAD <file>..." to unstage)  #  #    new file:   message.css  #    new file:   message.html  #    new file:   message.js  #    modified:   other.js  #

合併完成

但是……

注意:在使用git checkout某文件到當前分支時,會將當前分支的對應文件強行覆蓋

因此,合併A分支上沒有存在的文件沒問題,但是如果合併A分支上原先就存在的文件(比如兩個分支上都對other.js進行過修改),位於分支A上的文件other.js就會被checkout(分支B)過來的other.js覆蓋,導致分支A上之前開發的列表功能付之東流,這樣做肯定是優雅的!

那如何避免同一個文件不強制覆蓋,有沒有更好的解決方案呢(調一下味口)?我們一起來看一下第二種方案。

智能合併

思路:曲線救國,我們通過git merge 強大的分支合併功能來完成此次無縫合併。

  1. 首先使用git checkout根據A分支創建一個A_temp分支(避免影響A分支)
$ git checkout -b A_temp  Switched to a new branch 'A_temp'
  1. 然後將B分支合併到A_temp分支,此時兩個都經修改過的文件會跑出衝突,我們只需解決衝突即可。
$ git merge B  Updating 1f73596..04627b5  Fast-forward   message.css                     | 0   message.html                    | 0   message.js                      | 0   other.js                        | 1 +   4 files changed, 1 insertion(+)   create mode 100644 message.css   create mode 100644 message.html   create mode 100644 message.js
  1. 再次切換到A分支,並使用git checkout 將A_temp分支上的系統消息功能相關文件或文件夾覆蓋到A分支,此時可以大膽的覆蓋!因為我們已經在第二步處理過衝突問題。
  $ git checkout A  Switched to branch 'A'    $ git checkout A_temp message.html message.css message.js other.js    $ git status  # On branch A  # Changes to be committed:  #   (use "git reset HEAD <file>..." to unstage)  #  #    new file:   message.css  #    new file:   message.html  #    new file:   message.js  #    modified:   other.js  #
  1. 最後,有強迫症的患者可以卸磨殺驢,把剛剛根據分支A創建的A_temp刪除。

    $ git branch -d A_temp

OK,到此分支合併就完結了,現在我們就可以自信地召喚產品經理(我們公司產品兼測試)測試這兩個功能。

擴展

另外給大家介紹一下git merge 使用的小技巧

舉例:要把master分支合併到dev分支

git checkout dev // 切換到dev分支  git merge master --no-ff // 使用--no-ff

默認使用merge命令是ff,即 fast-forward,這種方式從Git 合併歷史中是無法查看到是哪幾個提交對象在一起實現了一個功能。

--no-ff 標記會在分支合併的時候,創建一個新的提交對象,可以避免丟失master分支的歷史信息,並且把所有的功能疊加在一起提交上去。兩者的區別如下圖所示,大家可以自己體驗一下兩者的區別。

兩者的區別

以上就是小明工作中使用git合併總結的經驗,希望能幫助到大家,僅供參考,有錯誤請指出,謝謝!

歡迎關注微信公眾號」程序員小明」,獲取更多資源。