{"id":7421,"date":"2016-07-28T14:43:53","date_gmt":"2016-07-28T05:43:53","guid":{"rendered":"http:\/\/www.skyarch.net\/blog\/?p=7421"},"modified":"2016-07-28T14:43:53","modified_gmt":"2016-07-28T05:43:53","slug":"git-flow-cleaning-your-local-branches","status":"publish","type":"post","link":"https:\/\/www.skyarch.net\/blog\/en\/git-flow-cleaning-your-local-branches\/","title":{"rendered":"Git Flow &#8211; Cleaning your Local Branches"},"content":{"rendered":"<p><strong>Git Flow<\/strong> indeed is the one of the most popular <a href=\"https:\/\/www.atlassian.com\/git\/tutorials\/comparing-workflows\/forking-workflow\" target=\"_blank\">Git Branching Model\/ Strategy\/Workflow<\/a> in use today.<br \/>\nYou can read more about Git Flow from the creator himself's post, \"<a href=\"http:\/\/nvie.com\/posts\/a-successful-git-branching-model\/\" target=\"_blank\">A successful Git branching model<\/a>\".<\/p>\n<p>Git Flow is very helpful for quite matured projects (traditional) rather than the infant ones (fast-phased or continuous), IMHO. And for the matured ones, Git Flow has been proven to work very well.<\/p>\n<p>The strategy's flow is a little slow-phased on the part\u00a0of releasing branches (features) into master\/production. And when a project hits a lot of feature tickets\/requests the repository tends to clog up, local and remote. And when those branches\u00a0are merged and closed from the origin, you will encounter the frustration of trying to remove those humongous number of merged branches from your local repository. And Git does not have, yet, the single command we want to delete all of those at the same time. Now, many of us searched the internet for answers, including myself, and got disappointed. \ud83d\ude41<\/p>\n<p>My answer?\u00a0I created a script to do just that. \ud83d\ude42<\/p>\n<h3>Steps how I came up with the Script<\/h3>\n<ol>\n<li>Since <code>git<\/code> does not have a command to print us all the deleted branches, I tried to go backwards by printing all remote branches; and local branches, and then loop on the list of remote branches and delete them from the list of local branches.<br \/>\nTo get the remote branches, use<\/p>\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\">\r\n$ git branch -r --no-merged\r\n<\/pre>\n<p>This would print something like,<\/p>\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\">\r\n$ git branch -r --no-merged\r\n  origin\/feature\/some-feature\r\n  origin\/feature\/another-one\r\n<\/pre>\n<p>Now, I only want the branch name so I can easily strip my local branches list with it, and create a list (array) of it. \u00a0I used this piped command.<\/p>\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\">\r\nIFS=&quot; &quot; read -r -a remoteBranches &lt;&lt;&lt; $(git branch -r --no-merged | sed 's\/\\\/\/ \/' | awk '{print $2;}' | sed -e ':a' -e 'N' -e '$!ba' -e 's\/\\n\/ \/g')\r\n<\/pre>\n<\/li>\n<li>Create a list\/array (space-delimited string) of local branches.\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\">\r\nlocalBranches=$(git branch | sed -e ':a' -e 'N' -e '$!ba' -e 's\/\\n  \/ \/g')\r\n# this command: sed -e ':a' -e 'N' -e '$!ba' -e 's\/\\n\/ \/g'\r\n# strips all the newline and the 2 spaces before each line of the git branch result\r\n<\/pre>\n<\/li>\n<li>One by one strip the branches in <code>remoteBranches<\/code>from the <code>localBranches<\/code>\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\">\r\n# loop and delete one by one\r\ndeleted=$localBranches\r\nfor branch in ${remoteBranches&#x5B;@]}; do\r\n    deleted=$(sed &quot;s!${branch}!!&quot; &lt;&lt;&lt; ${deleted})\r\ndone\r\n<\/pre>\n<\/li>\n<li>And now delete the local branches. From what's left of your local branches list after stripping all branches from remote, those branches are already \"not existing\" on your remote.\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\">\r\ngit branch -dl ${deleted}\r\n<\/pre>\n<\/li>\n<\/ol>\n<p>To sum it all up, here is the complete script:<\/p>\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\">\r\n#!\/bin\/bash\r\n\r\nprefix=&quot;feature\/richmond\/&quot;\r\n# only delete my own branches\r\n\r\nif &#x5B; &quot;$1&quot; != &quot;&quot; ]; then\r\n\tprefix=$1\r\n\t# or specify a prefix as argument\r\nfi\r\n\r\ncurrentBranch=$(git branch | grep &quot;*&quot; | awk '{print $2;}')\r\ngit checkout master\r\n\r\nIFS=&quot; &quot; read -r -a branches &lt;&lt;&lt; $(git branch -r --no-merged | grep ${prefix} | sed 's\/\\\/\/ \/' | awk '{print $2;}' | sed -e ':a' -e 'N' -e '$!ba' -e 's\/\\n\/ \/g')\r\n# get all existing branches in remote\r\n\r\nlocalBranches=$(git branch | grep ${prefix} | sed -e ':a' -e 'N' -e '$!ba' -e 's\/\\n  \/ \/g')\r\n# get all local branches\r\n\r\ndeleted=$localBranches\r\nfor branch in ${branches&#x5B;@]}; do\r\n\t# loop and delete one by one\r\n    deleted=$(sed &quot;s!${branch}!!&quot; &lt;&lt;&lt; ${deleted})\r\ndone\r\n\r\nif &#x5B; &quot;$deleted&quot; == &quot;&quot; ]; then\r\n\techo &quot;Nothing to delete, you local is clean.&quot;\r\nelse\r\n\tgit branch -dl ${deleted}\r\nfi\r\ngit checkout $currentBranch\r\n# checkout where you last checked out\r\n<\/pre>\n<p>Or you can also <a href=\"https:\/\/gist.github.com\/richmondwang\/61abbd8db51a2da1dcfa\" target=\"_blank\">checkout the Gist<\/a> i created.<\/p>\n<p>I added a prefix as I only want my branches to be deleted from my local.<br \/>\n<em style=\"font-size: 12px;\">This script is working with <code>git version ~1.7<\/code><\/em><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Git Flow indeed is the one of the most popular Git Branching Model\/ Strategy\/Workflow in use today. You can re&#8230;<\/p>\n","protected":false},"author":1,"featured_media":7457,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_locale":"en_US","_original_post":"7421","footnotes":""},"categories":[9],"tags":[137,134,136,135,138],"class_list":{"0":"post-7421","1":"post","2":"type-post","3":"status-publish","4":"format-standard","5":"has-post-thumbnail","7":"category-dev","8":"tag-delete-branch","9":"tag-git","10":"tag-git-branching","11":"tag-git-flow","12":"tag-scripting","13":"en-US"},"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/www.skyarch.net\/blog\/wp-json\/wp\/v2\/posts\/7421","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.skyarch.net\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.skyarch.net\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.skyarch.net\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.skyarch.net\/blog\/wp-json\/wp\/v2\/comments?post=7421"}],"version-history":[{"count":29,"href":"https:\/\/www.skyarch.net\/blog\/wp-json\/wp\/v2\/posts\/7421\/revisions"}],"predecessor-version":[{"id":7705,"href":"https:\/\/www.skyarch.net\/blog\/wp-json\/wp\/v2\/posts\/7421\/revisions\/7705"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.skyarch.net\/blog\/wp-json\/wp\/v2\/media\/7457"}],"wp:attachment":[{"href":"https:\/\/www.skyarch.net\/blog\/wp-json\/wp\/v2\/media?parent=7421"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.skyarch.net\/blog\/wp-json\/wp\/v2\/categories?post=7421"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.skyarch.net\/blog\/wp-json\/wp\/v2\/tags?post=7421"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}