分支(branch)可以説是git的殺手鐧功能,透過建立分支就像使用多重影分身之術一樣,可能同時進行不同分支的開發,最後可以透過合并(merge)把所有的修改整合在一起。
不過開啓大量分支有一個缺點,那就是當合并成功之後,怎麽清理不需要的分支。
這篇就來看看怎麽快速清理掉這些無用的"分身"。
問題描述
由於git屬於分散式的版控,因此如果有push到遠端(remote)的分支,在遠端以及local同時都會有這個分支。
這個時候當把分支合并之後,由於做合并動作的地方可能不同,因此在不同地方可能會遺留不需要的分支,這個時候如果不清理乾净在看log的時候很痛苦。
那總共有可能有哪些情況呢?
- 1. 當分支存在遠端已經合并並且被砍掉
- 這種情況是當在遠端裡面的分支被砍掉,由於不是從你的local發起,因此local還會殘留這些已經被合并的分支。
- 2. 當分支在遠端已經合并,但是還沒砍掉
- 有可能有些已經push到遠端的分支已經被合并了,但是做合并的人忘記把分支刪掉。
- 3. 當local的分支已經合并但是忘記刪掉
- 有些分支是自己local建立的,並且已經合并了。這個時候如果忘記砍掉可能就會殘留在log裡面。
下圖是上面提到的三個情況的發生情景圖,左邊是遠端的repo branch (azure DevOps),右邊則是local的repo (TortioseGit)
針對這3種情況怎麽快速清理這些分支呢?
解決方式 - TL;DR
這邊針對每一個情況的做法快速説明:
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()})
當上面都執行完了之後,最後得到的結果如下圖,是不是乾净很多啦:
如果對於上面指令的分解有興趣,在往下看吧。
指令分解
其實上面3種情景在做的事情拆開來講是兩個部分:
- 把遠端的相關tracking砍掉
- 把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
,這個時候就可以把這些分支砍了。
因此在最外圍的指令為:git branch -d
,也就是内建砍掉分支的指令。
瞭解了如何處理local指令之後,接下來就是看看遠端指令怎麽處理。
遠端指令之當遠端分支已經合并並且刪除
這個是情景1的情況,也就是當有人把遠端分支合并了,並且有把分支也一起砍掉了。
這個時候,其實就是清理兩個東西:
- 清理local對於遠端分支的track
- 清理local對應遠端分支在本地的branch
第二點同上面清理local分支方法一樣,不過第一點,怎麽清除local對於遠端分支的track branch呢?
git的pull指令已經有提供:git pull --prune
這個指令將會把所有遠端已經被刪掉的分支,把local有對應track的遠端分支也刪掉。
感覺有點繞口,換句話説,假設origin
遠端有個分支branch1
,local會有一個分支稱之爲:origin/branch1
。當執行完了git pull --prune
那麽這個分支會自動清理。
遠端指令之當遠端分支已經合并但是沒有被刪除
這種情況就是,做合并的人忘記把分支砍掉!!!
當遇到這個情況的時候,第一件事情請譴責合并的人XD,怎麽可以留垃圾在repo裡面。
這個時候,也是兩個動作:
- 清理掉local有track遠端的分支 - 這次由於遠端還沒砍掉,因此要把遠端的記錄也砍了
- 清理本段對應遠端分支在本地的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。
有了要刪除的清單之後,就呼叫:git push origin --delete
這個指令會把origin上面,對應剛剛那些branch都給砍了。
如果實際執行這個指令,powershell可能會出現紅字,但是實際上還是有執行成功。
出現紅字好像是傳入方法有點不太正確,如果以後有找到原因再來調整語法。
砍掉local分支方法就不用説啦。
結語
這篇介紹了如何快速清理已經合并完的分支的方式。
涵蓋了3種不同的情景,相信做完之後,整個log就會清爽很多。
保持乾净的log,到時候要看commit訊息的字也不會被擠掉,可以提升很多工作效率,以及減少“啊咋”的感覺。
如果有不同的清理方式,也歡迎和我分享哦。