Alan Tsai 的學習筆記


學而不思則罔,思而不學則殆,不思不學則“網貸” 為現任微軟最有價值專家 (MVP)、微軟認證講師 (MCT) 、Blogger、Youtuber:記錄軟體開發的點點滴滴 著重於微軟技術、C#、ASP .NET、Azure、DevOps、Docker、AI、Chatbot、Data Science

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

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

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

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

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

3 個類型未清理的分支呈現的樣子

如何快速清理已經合併的遠端(remote))以及本地(local)git 分支

有三種情況的分支是已經合併應該要被清理,但是還沒

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

針對每個處理方式可以執行如下:

  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. git branch -d $(git branch --merged | Select-String "master", "develop" -NotMatch | %{$_.ToString().Trim()})

適用於:Windows 使用 Powershell

問題描述

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

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

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

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

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

3 個類型未清理的分支呈現的樣子
情景情況圖

針對這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
台灣 Pay QR Code
台灣 Pay QR Code
Line Pay 一卡通 QR Code
Line Pay 一卡通 QR Code
街口支付QR Code
支付寶QR Code
街口支付QR Code
微信支付QR Code
2019-04-12 Friday
comments powered by Disqus