Safely clean up your local branches
Tags: github, git, go
Published: 2021-11-07 02:18:21

If you squash-merge a branch, you can't delete it in the usual way, `git branch -d`, because there is no history of merging into the default branch.
In the figure below, squash-merge the commit on your topic branch, D, and it's merged into your default branch as a new commit, E. Then the git history becomes a child of B, and it loses its relevance to the topic branch.
{% gist https://gist.github.com/seachicken/e2dd353eaa9cae2f18d5584b57e63326 %}

To delete a topic branch that has lost its merge history, you must forcibly delete with `git branch -D`, and you are always worried that you might accidentally delete another branch you are working on.

To solve this problem, I created a tool called [gh poi](https://github.com/seachicken/gh-poi) ("poi" means "feel free to throw it away" in Japanese).

## What tools?
`gh poi` is an extension that runs as a subcommand of the [GitHub CLI](https://github.com/cli/cli), which is officially provided by GitHub.
{% gist https://gist.github.com/seachicken/f72e024e5ae216097516a19f710a0612 %}
GitHub CLI v2.0.0 (released August 2021) and later versions allow you to develop and install extensions.
By providing it as an extension, you don't need to issue an access token to GitHub for each tool and can use it easily.

## Deletion strategy
As mentioned earlier, squash-merge branches can only be deleted by forcibly delete. Since `gh poi` also executes forced deletion internally, it is important to correctly determine the branch to delete.

### Deletion flow
1. Use [gh repo view](https://cli.github.com/manual/gh_repo_view) to get the remote repository name 
1. Use the `git` command to get a list of commit hashes for the branches that exist in the current directory
1. Use [gh api](https://cli.github.com/manual/gh_api) to search for all the pull requests associated with the repository name and commit hash mentioned above
1. **Determine deletion** branches and execute based on search results

### How to determine deletion
The GitHub API is used to check the pull requests associated with the head commit hash in each local branch, and if the status of the pull request is merged, the local work is considered complete and can be deleted. Since it uses the GitHub API, the best feature of it is that it can determine the deletion of any merge method including "Squash and merge".
In some cases, a pull request is closed and a new pull request is created. In this case, there will be multiple pull requests related to the branch, but if there is at least one pull request that has been merged and all other related branches are closed, it is determined that the branch can be deleted.
If there are still open pull requests, they are not included in the deletion list because they may continue to be worked on locally. We can easily run `gh poi` at any time to clean up the working environment.

In addition, if there is a forked repository in the first step, it also gets the name of the upstream repository, so it can make the same deletion decision when we merged the pull request to the forked repository. This is useful when contributing to OSS.
{% gist https://gist.github.com/seachicken/4ffed87cb9c598a5827d796a3dad508c %}

---

I found a few ways to delete squash-merge branches, but I couldn't find a tool that worked with GitHub and could delete them cleanly as expected, so I decided to make my own.
If you are interested in this project, please also register for ⭐️ Star from [gh-poi](https://github.com/seachicken/gh-poi).
Thanks for reading ☕️