Alan Tsai 的學習筆記


學而不思則罔,思而不學則殆,不思不學則“網貸” 記錄軟體開發的點點滴滴 著重於微軟技術、網頁開發、DevOps、C#, Asp .net Mvc、Azure、AI、Chatbot、Docker、Data Science

[git]如何快速清理已經合並(merged)的分支(branch) - local及remote

2019-04-12 星期五
[git]如何快速清理已經合並(merged)的分支(branch) - local及remote.jpg
圖片來源:https://pixabay.com/en/despair-alone-being-alone-archetype-513528/

分支(branch)可以説是git的殺手鐧功能,透過建立分支就像使用多重影分身之術一樣,可能同時進行不同分支的開發,最後可以透過合并(merge)把所有的修改整合在一起。

不過開啓大量分支有一個缺點,那就是當合并成功之後,怎麽清理不需要的分支

這篇就來看看怎麽快速清理掉這些無用的"分身"。

問題描述

由於git屬於分散式的版控,因此如果有push到遠端(remote)的分支,在遠端以及local同時都會有這個分支。

這個時候當把分支合并之後,由於做合并動作的地方可能不同,因此在不同地方可能會遺留不需要的分支,這個時候如果不清理乾净在看log的時候很痛苦。

那總共有可能有哪些情況呢?

1. 當分支存在遠端已經合并並且被砍掉
這種情況是當在遠端裡面的分支被砍掉,由於不是從你的local發起,因此local還會殘留這些已經被合并的分支。
2. 當分支在遠端已經合并,但是還沒砍掉
有可能有些已經push到遠端的分支已經被合并了,但是做合并的人忘記把分支刪掉
3. 當local的分支已經合并但是忘記刪掉
有些分支是自己local建立的,並且已經合并了。這個時候如果忘記砍掉可能就會殘留在log裡面。

下圖是上面提到的三個情況的發生情景圖,左邊是遠端的repo branch (azure DevOps),右邊則是local的repo (TortioseGit)

TortoiseGitProc_2019-04-12_06-42-00.png
情景情況圖

針對這3種情況怎麽快速清理這些分支呢?

解決方式 - TL;DR

這邊針對每一個情況的做法快速説明:

這邊主要針對的是用Windows PowerShell的指令,因此以下都是直接在PowerShell執行
以下指令假設目前在要檢查的分支。舉例來説,以上圖問題的情景,目前正在master
1. 當分支存在遠端已經合并並且被砍掉
git pull --prune
git branch -d $(git branch --merged | Select-String "master", "develop" -NotMatch | %{$_.ToString().Trim()})
2. 當分支在遠端已經合并,但是還沒砍掉
git push origin --delete $(git branch -r --merged | Select-String "origin/HEAD", "origin/master", "origin/develop" -NotMatch | %{$_.ToString().Trim().Replace("origin/", "")})
git branch -d $(git branch --merged | Select-String "master", "develop" -NotMatch | %{$_.ToString().Trim()})
3. 當local的分支已經合并但是忘記刪掉
git branch -d $(git branch --merged | Select-String "master", "develop" -NotMatch | %{$_.ToString().Trim()})

當上面都執行完了之後,最後得到的結果如下圖,是不是乾净很多啦:

TortoiseGitProc_2019-04-12_08-20-21.png
merge過的branch都清理乾净了

如果對於上面指令的分解有興趣,在往下看吧。

指令分解

其實上面3種情景在做的事情拆開來講是兩個部分:

  1. 遠端的相關tracking砍掉
  2. local的相關tracking砍掉

如果是情景1和2,由於牽涉到了遠端,因此第一個指令有點不同,但是第二個指令3個情景都是一樣,都是在把local相關tracking處理乾净。

因此,先從處理localtracking的指令:git branch -d $(git branch --merged | Select-String "master", "develop" -NotMatch | %{$_.ToString().Trim()})介紹起。

把local已經合并的分支砍掉指令説明

完整的指令是:git branch -d $(git branch --merged | Select-String "master", "develop" -NotMatch | %{$_.ToString().Trim()})

先從裡面的$(git branch --merged | Select-String "master", "develop" -NotMatch | %{$_.ToString().Trim()})介紹起。

這一段的目的是:取得所有已經被合并的分支但是過濾掉master或者develop分支

分解來説:

git branch --merged

這個是git内建的一個指令,取得所有以目前所在分支來説,已經被合并過的分支。因此,任何還沒有在當下分支所包含的分支不會出現。

不過這個指令有個討厭的地方是,它會包含目前分支。換句話説,我們在master執行,因此裡面包含master

爲了解決這個問題,使用了powershell的pipe做處理,也就是下一段。

Select-String "master", "develop" -NotMatch

Selete-String這一段的目的是要把部分我們不要被刪掉的分支給過濾掉。

這邊用了master以及develop因爲大部分這兩個分支是永遠存在的。

如果有分支也想過濾掉,那麽直接在加入在develop後面即可。

Select-String 其實底層跑的是Regular Expression,所以結果不是文字而已,因此有了下一個pipe

%{$_.ToString().Trim()}
這個部分目的很簡單,就是把所有在Select-String得到的,要轉換成爲string。

到目前爲止,已經取得了所有已經被合并的分支,不過排除掉了master以及develop,這個時候就可以把這些分支砍了。

powershell_2019-04-12_20-45-10.png
範例,呼叫指令取得的清單

因此在最外圍的指令為:git branch -d,也就是内建砍掉分支的指令。

瞭解了如何處理local指令之後,接下來就是看看遠端指令怎麽處理。

遠端指令之當遠端分支已經合并並且刪除

這個是情景1的情況,也就是當有人把遠端分支合并了,並且有把分支也一起砍掉了。

這個時候,其實就是清理兩個東西:

  1. 清理local對於遠端分支的track
  2. 清理local對應遠端分支在本地的branch

第二點同上面清理local分支方法一樣,不過第一點,怎麽清除local對於遠端分支的track branch呢?

git的pull指令已經有提供:git pull --prune

這個指令將會把所有遠端已經被刪掉的分支,把local有對應track的遠端分支也刪掉。

感覺有點繞口,換句話説,假設origin遠端有個分支branch1,local會有一個分支稱之爲:origin/branch1。當執行完了git pull --prune那麽這個分支會自動清理。

遠端指令之當遠端分支已經合并但是沒有被刪除

這種情況就是,做合并的人忘記把分支砍掉!!!

當遇到這個情況的時候,第一件事情請譴責合并的人XD,怎麽可以留垃圾在repo裡面。

當然,如果有做pull request的話就可以避免這種事情發生 - 關於pull request近期會介紹,敬請期待。

這個時候,也是兩個動作:

  1. 清理掉local有track遠端的分支 - 這次由於遠端還沒砍掉,因此要把遠端的記錄也砍了
  2. 清理本段對應遠端分支在本地的branch

清理掉local的指令是:git push origin --delete $(git branch -r --merged | Select-String "origin/HEAD", "origin/master", "origin/develop" -NotMatch | %{$_.ToString().Trim().Replace("origin/", "")})

這個和砍掉本地的分支指令很像,一樣,從裡面的拆解起來,裡面那段是找到所有remote已經合并過的branch

git branch -r --merged

這個指令可以取得從local repo裡面,track remote 分支的有沒有已經被合并過了。

由於也會包含常見的develop和master branch,因此要過濾這兩個,因此有了pipe

Select-String "origin/HEAD", "origin/master", "origin/develop" -NotMatch
這邊蠻好理解,忽略掉常見要保留的,這邊有一個特殊HEAD也不太需要動到。
%{$_.ToString().Trim().Replace("origin/", "")}
這邊基本上是要把結果回傳成爲一個string,不過由於結果包含了remote的prefix - 常見是origin/,這個時候要把這個部分拿掉,因爲等一下刪除不需要包含origin。
powershell_2019-04-12_20-46-13.png
取得所有remote已經合并的分支清單指令的範例

有了要刪除的清單之後,就呼叫:git push origin --delete

這個指令會把origin上面,對應剛剛那些branch都給砍了。

如果實際執行這個指令,powershell可能會出現紅字,但是實際上還是有執行成功。

出現紅字好像是傳入方法有點不太正確,如果以後有找到原因再來調整語法。

砍掉local分支方法就不用説啦。

結語

這篇介紹了如何快速清理已經合并完的分支的方式。

涵蓋了3種不同的情景,相信做完之後,整個log就會清爽很多。

保持乾净的log,到時候要看commit訊息的字也不會被擠掉,可以提升很多工作效率,以及減少“啊咋”的感覺。

如果有不同的清理方式,也歡迎和我分享哦。


如果文章對您有幫助,就請我喝杯飲料吧
街口支付QR Code
街口支付QR Code
街口支付QR Code
支付寶QR Code
街口支付QR Code
微信支付QR Code
2019-04-12 星期五
comments powered by Disqus