When working on a git repository, I often have to manually delete old local branches that I don't use anymore. That's not really a huge waste of time but still that something I have to do quite often so I decided to automate that.
First let's talk about how I end up having many useless local git branches. In fact that's something quite usual and directly linked with the way I work with git but chances are that you are having the same issue.
At work I am working in a small teams of developers, we host our git repositories in Azure DevOps and we try to respect the following practices in our daily development:
- having a main branch (master) on which nobody can commit directly
- always create a short-lived branch (also called feature branch) when developing a new feature of the application
- only merge a feature branch on the main branch through an Azure DevOps pull request
- the PR triggers a pipeline that ensures the code build correctly, follow some conventions (with a Sonar analysis for instance) and that unit tests pass
- the PR can only be completed after a code review of at least one member of the team
These practices allow us to keep a good quality in our code base, not to mess with our git repositories and ensure the main branch always build.
However, each week we are creating a lot of branches that need to be deleted as once merged we no longer need to have them. When a pull request is approved and we decide to complete it, Azure DevOps takes care of automatically merging the associated feature branch into master and deleting it from the repository. Once that done, I can do a
git fetch --prune on my laptop to have the feature branch removed from the remote of my local repository (by the way, I recommend you to directly set the fetch command to prune by default in your git config 👌). Nevertheless, this does not delete the local version of the feature branch thus our problem: over the time if we do not think of deleting all these outdated branches, they become too many and we don't even know which branch should be kept or not.
As my outdated branches are already removed from my remote (thanks to
git fetch --prune) it should not be too complicated to use some git commands to guess which branches are not useful anymore. But as it's Azure DevOps which took care of merging them (sometimes with a squash) I cannot use the
git branch --merged command.
If I take my blog repository as an example I have a bunch of branches: some that could be useful (articles I have started to write but did not finish yet and I don't know if I will one day 😋) and some that are already merged into my master branch through a PR.
git branch -vl (which lists in a verbose way the local git branches) gives us an interesting view as it shows the branches for which the remote has been deleted specifying a
[gone] for them. These branches correspond to the outdated branches we want to delete.
We know how to identify the outdated branches but we need a command to delete them which is the
git branch -D command. Now we only need a script to associate output and input of these two commands in order to automate the deletion.
You can find on Stackoverflow some posts like this one that show different solutions using bash that work perfectly but I thought it would be interesting to try to script that using another shell. Indeed I recently started to use a shell called nushell which is a pretty powerful yet simple cross-platform shell. It is still in preview at the time of writing but if you have not heard of it I suggest you to read the introduction post of Jonathan Turner.
Enough of talking, let's script.To start with, we can use the nu lines command to create a table from the lines of the
git branch -vl output (we added an extra
*/* argument as we are only interested in posts branches).
Then we can split the different lines into columns that we can name with the
split-column command. We use spaces to correctly split a line and the option
--collapse-empty to remove the empty columns.
We then just have to filter the table to get only the lines with the Status
And the final script:
git branch -vl '*/*' | lines | split-column " " BranchName Hash Status --collapse-empty | where Status == '[gone]' | git branch -D $it.BranchName
We can integrate this script to our git commands by creating a git alias. Let's say I want to create the alias
bcl for branch clean up, we only need to add the following to our
[alias] bcl = !nu \"D:\\gitalias_bcl.nu\"
gitalias_bcl.nu is the nu script file we created earlier (it's located here in the
D:// drive but can be created anywhere).
Now we can simply do a
git bcl to clean our outdated local git branches.
That's it, nothing revolutionary but that was the opportunity to automate the boring task of deleting outdated local branches while playing with nushell.